<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Sanjay Bhagia&apos;s Blog</title><description>The personal blog of Sanjay Bhagia</description><link>https://sanjaybhagia.com/</link><item><title>We all should be bit more like dogs</title><link>https://sanjaybhagia.com/blog/we-all-should-be-bit-more-like-dogs/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/we-all-should-be-bit-more-like-dogs/</guid><description>We can learn valuable lesson on life from dogs. They are calm, satisfied with very little, don&apos;t overthink, masters of solitude, quick to forgive, unmatched excitement, make you move, what you see is what you get.</description><pubDate>Fri, 29 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dogs. They are adorable. They are cute and cuddly and bring so much joy to our lives.&lt;/p&gt;
&lt;p&gt;Take my dog, Chihu - oh, I adore her. I love spending time with her.&lt;/p&gt;
&lt;p&gt;I’m not writing this to convince you to get a dog for yourself. What I’m proposing, however, is that we should all be more like dogs!
Yes, I know, it’s unusual but hear me out.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Calmness&lt;/strong&gt;
Dogs are calm (&lt;em&gt;for the most part)&lt;/em&gt;. They bring a sense of stillness in you when they are around. There is a certain peace you feel in their presence. Right now, when I&apos;m writing this, she sits beside me, calm and composed. Such a positive energy
&lt;br /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Satisfaction with very little&lt;/strong&gt;
They are happy with very little. You give them their food, spoil them with a few treats and spend some time with them, and they couldn’t be happier! Who would have thought a tiny piece of carrot could be so satisfying?&lt;/p&gt;
&lt;p&gt;It doesn’t take much for them to feel happy and content; it shouldn’t take much for us, either.
&lt;br /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No overthinking&lt;/strong&gt;
They don’t complicate their lives with overthinking. It&apos;s like they have cracked the code that overthinking doesn&apos;t lead to anything good. Why do we tend to overcomplicate everything in our lives?
&lt;br /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Masters of solitude&lt;/strong&gt;
They are good at handling boredom and staying with themselves. Something we have lost to the modern world! When was the last time you sat with yourself and did nothing? Give it a try; you might find a new person within you.
&lt;br /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Quick to forgive&lt;/strong&gt;
They don’t hold grudges.
They do something stupid; you get mad at them, they get bit scared. But they will quietly sneak into your lap after few minutes. Matter resolved!
Almost a zen-like quality that we can learn from them.
&lt;br /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Unmatched excitement&lt;/strong&gt;
They are the most excited to see you when you are coming home. Every single time, without a fail!
This sense of excitement on little things and appreciation of what you have got, something we can learn from these voiceless creatures.
&lt;br /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Make you move&lt;/strong&gt;
They help you move. Yes, you have to take your dog out for some physical work, good for them and good for you. Maybe, maybe you can reach your daily steps goal in the process.
&lt;br /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;What you see is what you get&lt;/strong&gt;
I haven&apos;t seen dogs pretending to be someone they are not. They are what they are. They emote how they feel. You can see through them.
I understand we can&apos;t always be like that, but what if we try a little bit more to be ourselves and more authentic?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, wouldn&apos;t incorporating or amplifying these dog-like qualities enhance your daily life? It has certainly helped me. You be the judge of it.&lt;/p&gt;
&lt;p&gt;Do you have a dog? What do you like about them? Share your stories in the comments below.&lt;/p&gt;
&lt;p&gt;Remember, sometimes the greatest lessons come from the most unexpected teachers.&lt;/p&gt;
&lt;p&gt;Until next time.&lt;/p&gt;
</content:encoded></item><item><title>Handling Order Processing with Azure API Management and Service Bus Topics</title><link>https://sanjaybhagia.com/blog/handling-order-processing-with-azure-api-servicebus-topics/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/handling-order-processing-with-azure-api-servicebus-topics/</guid><description>Learn how to securely send messages to Azure Service Bus Topics directly from Azure API Management using the policies.</description><pubDate>Tue, 10 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Scenario&lt;/h1&gt;
&lt;p&gt;Imagine we are are a dropshipping supplier for e-commerce stores around the world. Clients receive orders from their end-customers and forward them to our backend to process and deliver them. We are going to automate the process of receiving orders by exposing APIs. In order to distribute the load, we are providing the endpoints to receive orders based on the geography. For example, we have an endpoint to receive orders from Sydney, Australia etc.&lt;/p&gt;
&lt;p&gt;Here is the high level architecture of the system we are going to design in this blog post.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/apim-sb-topic.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We will use Azure API Management to expose the endpoints and make use of Azure APIM policies to send the orders to Azure Service Bus Topics. Service Bus Topic will have different subscriptions to receive orders for different geographies. At the end, we will have multiple consumers (in the form of Azure functions) to process the messages from the Service Bus Topic for respective subscriptions.
This architecture, allows us to scale the processing of orders based on geography. We can have multiple consumers to process the messages from the Service Bus Topic to distribute the load.&lt;/p&gt;
&lt;p&gt;Before we dive into the details, let&apos;s understand the components we are going to use in this demo.&lt;/p&gt;
&lt;h1&gt;Service Bus Topic&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview&quot; target=&quot;blank&quot;&gt;Azure Service Bus&lt;/a&gt; is a fully-managed enterprise integration message broker. It provides reliable message delivery between applications and services, even when one or more of the endpoints are offline. Service Bus supports a variety of messaging patterns, including publish/subscribe, request/response, and message queuing. It also provides features such as message batching, dead-lettering, and message deferral. Service Bus can be used to decouple applications and services, enabling them to scale independently and evolve over time.&lt;/p&gt;
&lt;p&gt;One of the core components of Azure Service Bus is the &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-queues-topics-subscriptions#topics-and-subscriptions&quot; target=&quot;blank&quot;&gt;Topic&lt;/a&gt;, which can be used for publish/subscribe scenarios. Messages are sent to a topic and delivered to one or more associated subscriptions.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/azure-sb-topic-highlevel.png&quot; alt=&quot;Alt text&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;API Management&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/api-management/api-management-key-concepts&quot; target=&quot;blank&quot;&gt;Azure API Management (APIM)&lt;/a&gt; is a fully managed service that enables customers to publish, secure, transform, maintain, and monitor APIs.
It provides a unified experience across the entire API lifecycle, enabling developers to create APIs and app developers to consume them easily.&lt;/p&gt;
&lt;h2&gt;API Management Policies&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-policies&quot; target=&quot;blank&quot;&gt;Azure API Management policies&lt;/a&gt; are a set of rules that are executed by the API Gateway when a request is made to an API. These policies can be used to modify the request or response, enforce security, or perform other actions. Policies can be defined at the API level, the operation level, or the product level. Azure API Management provides a rich set of built-in policies and also allows you to define custom policies using XML and C# (policy expressions).&lt;/p&gt;
&lt;p&gt;When integrating APIM with Azure Service Bus Topic, the idea is to allow APIM to publish messages to the Service Bus Topic by using one of the built-in policies. This makes is very easy for us to send messages to the Service Bus without having to write any code.&lt;/p&gt;
&lt;h1&gt;Provision the Infrastructure&lt;/h1&gt;
&lt;p&gt;Let&apos;s walk through the steps to provision the required infrastructure. I&apos;m using Azure CLI (&lt;code&gt;az cli&lt;/code&gt;) to provision the resources. You can use the Azure Portal, ARM templates, or PowerShell to do the same.&lt;/p&gt;
&lt;h2&gt;Set the account&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# Login &amp;amp; set appropriate subscription
az login
az account show
az account set --subscription &amp;lt;subscription-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create a resource group&lt;/h2&gt;
&lt;p&gt;We will create all of the resources in a single resource group.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Define a variable which we will use later
resourceGroupName=azecommstore

# Create the resource group
az group create --name $resourceGroupName --location australiaeast
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create Azure API Management Service&lt;/h2&gt;
&lt;p&gt;Here, we will provision the consumption tier of Azure APIM, create the API, and set up a operation (endpoint) that will receive requests from clients.&lt;/p&gt;
&lt;p&gt;For this demo, I&apos;m leveraging system-assigned &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview&quot; target=&quot;blank&quot;&gt;managed identity&lt;/a&gt; to establish secure communication between APIM and Service Bus.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--enable-managed-identity&lt;/code&gt; flag is going to create a System Assigned Managed identity for the APIM. You could create the user-assigned managed identity and use that as well. In fact, I would recommend that. However, there is no support for creating user-assigned managed identity using Azure CLI, you would have to use ARM templates, PowerShell, or the Portal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Define variable, which we will use later
apimName=azecommstoreapimae

# Create APIM instance with managed identity enabled
az apim create --name $apimName --resource-group $resourceGroupName --location australiaeast --publisher-name Sanjay --publisher-email admin@gmail.com --sku-name Consumption --enable-managed-identity true
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create API&lt;/h3&gt;
&lt;p&gt;Now that we have the APIM instance ready, let&apos;s create an API that will receive orders for us.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;az apim api create --service-name $apiName -g $resourceGroupName --api-id Orders --path &apos;/orders&apos; --display-name &apos;Orders&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create API Operation&lt;/h3&gt;
&lt;p&gt;Once we have the API, let&apos;s create a POST operation that will receive the request from the client and send the message to the Service Bus Topic.&lt;/p&gt;
&lt;p&gt;I&apos;m creating a generic endpoint here (e.g., /process/{geography}), so that we can have as many URLs for geographies (e.g., /process/sydney, /process/melbourne etc.) without defining separate operations.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;az apim api operation create --resource-group $resourceGroupName --service-name $apimName --api-id Orders --url-template &quot;/process/{geography}&quot; --method &quot;POST&quot; --display-name &apos;Process Orders&apos; --description &apos;Process Orders for E-Store&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create Service Bus Resources&lt;/h2&gt;
&lt;p&gt;Here, we will create the Azure Service Bus namespace, topic, and subscription. We will also create a rule on the subscription to filter messages based on the &lt;code&gt;originUrl&lt;/code&gt; header (&lt;em&gt;will explain a bit later about this&lt;/em&gt;). This will allow us to route the messages to different subscriptions based on the originUrl header.&lt;/p&gt;
&lt;h3&gt;Namespace&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# Define variable, which we will use later
serviceBusNamespace=azsbnsorders

# Create a namespace with standard SKU
az servicebus namespace create --name $serviceBusNamespace --resource-group $resourceGroupName --location australiaeast --sku Standard
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Service Bus Topic&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;az servicebus topic create --name orders --resource-group $resourceGroupName --enable-partitioning false --namespace $serviceBusNamespace
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Service Bus Topic Subscription&lt;/h3&gt;
&lt;p&gt;We can create multiple subscriptions to forward messages as they come to our topic. I&apos;m creating a subscription for processing orders coming for Sydney.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;az servicebus topic subscription create --name sydneyorders --resource-group $resourceGroupName --namespace-name $serviceBusNamespace --topic-name orders
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Service Bus Topic Subscription Rule&lt;/h3&gt;
&lt;p&gt;The way we route messages to subscriptions is via &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/service-bus-messaging/topic-filters&quot; target=&quot;blank&quot;&gt;filters&lt;/a&gt;. Here, we are creating a &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/service-bus-messaging/topic-filters#sql-filters&quot;&gt;SqlFilter&lt;/a&gt; based on the &lt;code&gt;originUrl&lt;/code&gt; custom property that will be coming with incoming messages to this topic.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;az servicebus topic subscription rule create --resource-group $resourceGroupName --namespace-name $serviceBusNamespace --topic-name orders --subscription-name sydneyorders --name processorders --filter-sql-expression &quot;originUrl=&apos;/orders/process/sydney&apos;&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/apim-sb-topic-sqlfilter.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/apim-sb-topic-filter-definition.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Assign Permissions to Service Bus Namespace&lt;/h3&gt;
&lt;p&gt;In order for APIM to send messages to the Service Bus Topic, we need to assign the &lt;code&gt;Azure Service Bus Data Sender&lt;/code&gt; role for APIM instance (&lt;em&gt;system-assigned managed identity we created earlier at the time of provisioning the APIM instance&lt;/em&gt;) on service bus namespace.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Get the subscription id
subscriptionId=$(az account show --query id --output tsv)

# Get the objectId of the APIM instance (system-assigned managed identity)
assigneeId=$(az apim show --name $apimName --resource-group $resourceGroupName --query &apos;identity.principalId&apos; --out tsv)

# Finally, assign the permissions on Azure Service Bus namespace
az role assignment create --role &quot;Azure Service Bus Data Sender&quot; --assignee $assigneeId --scope /subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.ServiceBus/namespaces/$serviceBusNamespace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the sake of simplicity, I&apos;m setting the permissions on the entire namespace. However, you can be very specific (e.g., set the permissions on the topic or subscription level) by changing the scope of the role assignment.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--scope /subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.ServiceBus/namespaces/$serviceBusNamespace/topics/$service_bus_topic/subscriptions/$service_bus_subscription
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Set Policies in APIM&lt;/h2&gt;
&lt;p&gt;This is where the magic happens. We are leveraging Azure APIM policies to receive requests, extract information from incoming requests, and send messages to the Service Bus Topic. We are using the managed identity to get the access token from Azure AD and then using that access token to send the message to the Service Bus Topic.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For the purposes of demonstration, this endpoint is not secured. We haven&apos;t set up any authentication or authorization. In a real-world scenario, you would want to secure this endpoint. You can configure the setting on the API level or you can validate the incoming request within the policy itself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here, we are simply setting the backend URL to the service bus namespace.&lt;/p&gt;
&lt;p&gt;Navigate to APIM -&amp;gt; APIs -&amp;gt; Orders -&amp;gt; Process Orders -&amp;gt; Inbound processing -&amp;gt; Policy Code editor.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/apim-set-policies-I.png&quot; alt=&quot;Set APIM Policy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Copy and paste the following policy and click &lt;code&gt;Save&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;policies&amp;gt;
     &amp;lt;inbound&amp;gt;
        &amp;lt;base /&amp;gt;
        &amp;lt;!--Azure Service Bus--&amp;gt;
        &amp;lt;!-- Set the backend URL to Service Bus Namespace--&amp;gt;
        &amp;lt;rewrite-uri template=&quot;orders/messages&quot; /&amp;gt;
        &amp;lt;set-backend-service base-url=&quot;https://azsbnsorders.servicebus.windows.net&quot; /&amp;gt;
        &amp;lt;!-- Custom Headers are sent as &apos;Custom Properties&apos; on service bus messages --&amp;gt;
        &amp;lt;set-header name=&quot;originUrl&quot; exists-action=&quot;override&quot;&amp;gt;
            &amp;lt;value&amp;gt;@(context.Request.Headers.GetValueOrDefault(&quot;X-Original-URL&quot;, &quot;&quot;))&amp;lt;/value&amp;gt;
        &amp;lt;/set-header&amp;gt;
        &amp;lt;authentication-managed-identity resource=&quot;https://servicebus.azure.net&quot; output-token-variable-name=&quot;msi-access-token&quot; ignore-error=&quot;false&quot; /&amp;gt;
        &amp;lt;set-header name=&quot;Authorization&quot; exists-action=&quot;override&quot;&amp;gt;
            &amp;lt;value&amp;gt;@((string)context.Variables[&quot;msi-access-token&quot;])&amp;lt;/value&amp;gt;
        &amp;lt;/set-header&amp;gt;
    &amp;lt;/inbound&amp;gt;
    &amp;lt;backend&amp;gt;
        &amp;lt;base /&amp;gt;
    &amp;lt;/backend&amp;gt;
    &amp;lt;outbound&amp;gt;
        &amp;lt;base /&amp;gt;
    &amp;lt;/outbound&amp;gt;
    &amp;lt;on-error&amp;gt;
        &amp;lt;base /&amp;gt;
    &amp;lt;/on-error&amp;gt;
&amp;lt;/policies&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/apim-set-policies-II.png&quot; alt=&quot;Set APIM Policy&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Test the API&lt;/h1&gt;
&lt;p&gt;Now, we have everything in place. Let&apos;s test the API. We will use Postman to test the API.&lt;/p&gt;
&lt;p&gt;Let&apos;s issue a simple request from Postman to the endpoint&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://azecommstoreapimae.azure-api.net/orders/process/sydney
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/apim-request-postman.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As we can see, the request is successful and we received a &lt;code&gt;201 Created&lt;/code&gt; response!&lt;/p&gt;
&lt;h2&gt;Curl Command&lt;/h2&gt;
&lt;p&gt;For reference, here is the CURL request&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl --location &apos;https://azecommstoreapimae.azure-api.net/orders/process/sydney&apos; \
--header &apos;Content-Type: application/json&apos; \
--data &apos;{
    &quot;key&quot;: &quot;value&quot;
}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s validate the message from the Portal.&lt;/p&gt;
&lt;h2&gt;Azure Service Bus - Portal&lt;/h2&gt;
&lt;p&gt;As we can see, we did indeed receive the message in our subscription within the Service Bus Topic. Upon further inspection, we can see that the message was sent to the &lt;code&gt;sydneyorders&lt;/code&gt; subscription and the &lt;code&gt;processorders&lt;/code&gt; rule was applied.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/apim-sb.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/apim-sb-topic-message-body.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/apim-sb-topic-message-properties.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;From this point, you can very well create an Azure function to receive messages from this topic and subscription.&lt;/p&gt;
&lt;h2&gt;Bonus - Azure Function App&lt;/h2&gt;
&lt;p&gt;Now, we are ready to write our code to process the orders. But first, let&apos;s spin up an azure function. We need a storage account and Azure Function app first.&lt;/p&gt;
&lt;h2&gt;Storage Account&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;az storage account create --name azecommstorestorage --resource-group $resourceGroupName --location australiaeast --sku Standard_LRS
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Azure Function&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;az functionapp create --resource-group $resourceGroupName --consumption-plan-location australiaeast --name sydneyordersprocessor --storage-account azecommstorestorage --runtime dotnet-isolated --functions-version 4 --os-type Linux
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Write and Test Code&lt;/h2&gt;
&lt;p&gt;You can use &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-csharp?tabs=macos%2Cazure-cli#install-the-azure-functions-core-tools&quot; target=&quot;blank&quot;&gt;Azure Function Core Tools&lt;/a&gt; or your favorite IDE to create a function app.
Here is the simple function I have created. It simply logs the message it receives.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

public class ServiceBusTopicListeners
{
    private ILogger _logger;
    public ServiceBusTopicListeners(IServiceProvider serviceProvider)
    {
        var loggerFactory = serviceProvider.GetRequiredService&amp;lt;ILoggerFactory&amp;gt;();
        _logger = loggerFactory.CreateLogger(this.GetType());
    }
    [Function(nameof(ProcessOrders))]
    public async Task ProcessOrders([ServiceBusTrigger(&quot;orders&quot;,
        subscriptionName: &quot;sydneyorders&quot;, 
        Connection = &quot;servicebus_cs&quot;, IsSessionsEnabled = false)] 
        string message, FunctionContext context)
    {
        _logger.LogInformation($&quot;Received message: {message}&quot;);   
    }    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we run this function locally in debug mode, and set the breakpoint, we see that message is received successfully.
&lt;img src=&quot;https://sanjaybhagia.com/images/apim-sb-topic-function-execution.png&quot; alt=&quot;Azure Function Local Debug&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Clean up the resources&lt;/h2&gt;
&lt;p&gt;Always a good idea to clean up the resources you are not using&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;az group delete --name $resourceGroupName
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Source Code&lt;/h2&gt;
&lt;p&gt;You can find the complete source code of this post on my &lt;a href=&quot;https://github.com/sanjaybhagia/ServiceBusTopicConsumer&quot; target=&quot;blank&quot;&gt;GitHub repo&lt;/a&gt;. Add the connection string of your Azure Service Bus namespace in &lt;code&gt;local.settings.json&lt;/code&gt; to test this out locally. I have also listed all az cli command in this blog post in one file &lt;a href=&quot;https://github.com/sanjaybhagia/ServiceBusTopicConsumer/blob/main/infra.sh&quot; target=&quot;blank&quot;&gt;infra.sh&lt;/a&gt; for your reference.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;In this blog post, we saw how we can leverage Azure API Management policies to send messages to Azure Service Bus Topic. We also saw how we can leverage Managed Identity to get the access token and use that to send messages to the Service Bus Topic. This approach makes it easy to send messages to the Service Bus Topic without having to write any code.&lt;/p&gt;
&lt;p&gt;Hope this was helpful.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Hands-on with Katonic.ai&apos;s Generative AI Platform</title><link>https://sanjaybhagia.com/blog/hands-on-with-katonic-generative-ai/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/hands-on-with-katonic-generative-ai/</guid><description>Exploring Katonic.ai&apos;s Generative AI Platform</description><pubDate>Wed, 27 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;OpenAI has taken the world by storm, and Generative AI is all the rage these days. It&apos;s not just OpenAI; many other companies are working on Generative AI and Large Language Models (LLMs). These models are rapidly changing how we interact with machines and build applications. From Copilots to Spotify&apos;s recent Voice Translation for podcasters, we are witnessing the sheer power of these models penetrating our daily lives.&lt;/p&gt;
&lt;p&gt;In this blog post, I&apos;m exploring one platform I have recently encountered that offers a no-code environment to create, deploy and manage such Large Language models. Let&apos;s dive in!&quot;&lt;/p&gt;
&lt;h1&gt;What is Generative AI?&lt;/h1&gt;
&lt;p&gt;In case you are not familiar with Generative AI, I asked our trusted friend ChatGPT and this what it had to say:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Generative AI is like a super smart robot that can make up new things, like stories, pictures, or even music. It learns from lots of other things people have made, and then it can create its own stuff that&apos;s brand new and sometimes really cool! It&apos;s like a creative friend who can make up fun games and drawings for you to enjoy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;What are Large Language Models (LLMs)&lt;/h1&gt;
&lt;p&gt;Large language models (LLMs) are a type of artificial intelligence model designed to understand and generate human-like text. They are built using deep learning, specifically a kind of neural network called a transformer.&lt;/p&gt;
&lt;p&gt;Large language models are like super-advanced text generators that can produce coherent and contextually relevant text based on the massive amount of data they&apos;ve been trained on.
Katonic.ai&lt;/p&gt;
&lt;h1&gt;Katonic.ai&lt;/h1&gt;
&lt;p&gt;Now that we are on the same page let&apos;s see what Katonica.ai is and what it brings to the table.&lt;/p&gt;
&lt;p&gt;Before discussing Katonic&apos;s Generative AI Platform, let&apos;s touch base on Katonica to set the context for the rest of the discussion.&lt;/p&gt;
&lt;h2&gt;What is Katonic.ai?&lt;/h2&gt;
&lt;p&gt;Katonic is a collection of cloud-native tools for all the stages of the Model Development Life Cycle (data exploration, feature preparation, model training/tuning, model serving, model testing, and model versioning). Katonic provides a unified UI and has tooling that allows these traditionally separate tools to work seamlessly together. An important part of this tooling is the pipeline system, which enables users to build integrated end-to-end pipelines that connect all components of their Model Development Life Cycle (MDLC).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-21.png&quot; alt=&quot;Create Project&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Katonic is for data scientists and engineers looking to build production-grade machine learning implementations. Katonic can run locally in your development environment or a production cluster. Often, pipelines will be developed locally and migrated once the pipelines are ready. Katonic provides a unified system—leveraging Kubernetes for containerisation and scalability for the portability and reusability of its pipelines (&lt;em&gt;&lt;a href=&quot;https://docs.katonic.ai&quot; target=&quot;_blank&quot;&gt;source&lt;/a&gt;&lt;/em&gt;)&lt;/p&gt;
&lt;h2&gt;Katonic Generative AI Platform&lt;/h2&gt;
&lt;p&gt;The Katonic Generative AI platform allows users to instantly deploy and manage their own Generative AI models. It offers categories like Chatbot, Classify, Extract, Summarize, and Generate, along with a Tuning Studio for creating customised prompts. The platform also provides a seamless deployment process, turning models into production-ready APIs with just a few clicks. Lastly, it offers a Playground where users can explore and interact with various Generative AI models.&lt;/p&gt;
&lt;p&gt;Katonic offers a no-code Generative AI Platform that is simple and intuitive, allowing for rapidly building powerful Enterprise-grade AI Applications without coding.&lt;/p&gt;
&lt;h1&gt;Why would I need to run my own LLMs if I can simply use something like ChatGPT?&lt;/h1&gt;
&lt;p&gt;It&apos;s a good question, so let me share a few thoughts about this.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data Security &amp;amp; Privacy&lt;/strong&gt;
If you have spent time in this space, you would be aware that this is one of the most talked about concerns. Large Language Models, by nature, are trained on large data sets. When we talk about enterprises or businesses where data is susceptible, we cannot hand it over to the model running in the public domain. Running a model in a controlled environment ensures our data doesn&apos;t leave our premises. Even if it leaves, we can anonymise or sanitise it such that no private information goes out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost&lt;/strong&gt;
Depending on your usage, running your model after the initial investment might be more cost-effective, as you won&apos;t be paying per API call.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Latency&lt;/strong&gt;
Running a local instance can result in lower latency since you don&apos;t need to make an API call over the internet. This is especially beneficial for real-time applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom Training&lt;/strong&gt;
You can fine-tune the model specifically for your domain or dataset, making it specialized for specific tasks or industries, which can improve its accuracy and relevance for specialized applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Others&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Pinning specific versions of the model&lt;/li&gt;
&lt;li&gt;Bypassing API rate limits while using third-party APIs&lt;/li&gt;
&lt;li&gt;Tight control of the deployment and uptime of the system&lt;/li&gt;
&lt;li&gt;Better control over integration with your line of business applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is not an exhaustive list, but you get the point. There is a place and good reason for running LLMs in your environment that you have complete control of.&lt;/p&gt;
&lt;h1&gt;Take it for a spin.&lt;/h1&gt;
&lt;p&gt;Enough talk, let&apos;s take this for a spin and see how can we use this platform.&lt;/p&gt;
&lt;p&gt;You will need a Katonic.ai account. You can create a free account &lt;a href=&quot;https://www.katonic.ai/signup.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. Once you log in, you land on this Generative AI page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-2.png&quot; alt=&quot;Create Project&quot; /&gt;&lt;/p&gt;
&lt;p&gt;UX is neat and intuitive; you won&apos;t need much guidance, but I&apos;ll walk you through here anyway.&lt;/p&gt;
&lt;h2&gt;Create a project&lt;/h2&gt;
&lt;p&gt;For demonstration purposes, I&apos;ll create a chatbot application trained on some of the blog posts I have written in the past. Once the chatbot is ready, we will ask a few questions to see how it performs.&lt;/p&gt;
&lt;p&gt;Alright, so hit the &lt;code&gt;+ Create a new Generative AI Project&lt;/code&gt; button.&lt;/p&gt;
&lt;h2&gt;Selecting project type&lt;/h2&gt;
&lt;p&gt;Fill-in the project name and description. The important thing is to pick the type of project we want to create. This makes it easy to choose because we should know our use case without getting too much into technicalities. I&apos;m picking up &lt;code&gt;Chat&lt;/code&gt; here.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-3.png&quot; alt=&quot;Select Type&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Add Data&lt;/h2&gt;
&lt;p&gt;The next screen is where we have to provide the source of data we want our chatbot to be trained on. We can either provide URLs or upload documents. I&apos;ll provide five links to the blog posts that I have written on Pulumi. (&lt;em&gt;5 is the limit for free project&lt;/em&gt;).
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-4.png&quot; alt=&quot;Add Data&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Customise&lt;/h2&gt;
&lt;p&gt;This is where things get interesting. Here we can tweak a number of settings.
First up is the language model we want to pick. In the free tier, we can only select &lt;code&gt;Pick the Best LLM&lt;/code&gt;. Katonica picks up the appropriate model based on the project type we selected earlier. But we could choose any other LLM model.
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-5.png&quot; alt=&quot;Customise Data LLM&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next up, we can customise the look and feel of our Chat application we will get in the end. And also if we want to make this application be available as public or private. This is pretty powerful, so you can be sure your enterprise applications are not accessible publicly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-6.png&quot; alt=&quot;Customise Data Look and Feel&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It is not enough to train the models on just the data; we want to control it so that it doesn&apos;t blurb out the answers in any way it pleases. We want to ensure our models don&apos;t include inappropriate information, especially if this is something we are using in a business context. For example, we want to filter our content of any abusive wording. Katonica allows us to tweak these things at this stage, and it&apos;ll ensure the generated responses respect the constraints we set up here.
Other than content filtration and restrictions, we can also define the personality our bot should have while answering the questions. This is your opportunity to get creative; if you have always wanted to sound like William Shakespeare, go ahead and tell the model!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-7.png&quot; alt=&quot;Customise Data Grounding&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Project Completion&lt;/h2&gt;
&lt;p&gt;Once we have provided our data and customised the model to our wishes, hit next. Click the Deploy button and let Katonica work its magic. It might take a few minutes for the model to be ready. Once it&apos;s ready, you&apos;ll see the green tick, and now you are ready to play with it. You can head over to &apos;Deploy&apos; tab from the left to see all your models.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-9.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Hit the &lt;code&gt;Try this &apos;Chatbot&apos;&lt;/code&gt; button to launch your very own  bot!&lt;/p&gt;
&lt;h2&gt;Testing&lt;/h2&gt;
&lt;p&gt;Here, we have our very own chatbot trained on some of my blog posts in all its glory! Notice, here I did bit of customisation (though I was a bit lazy and just changed the colour to orange; but you can change the logo, description, colour, etc., to make it your own).&lt;/p&gt;
&lt;p&gt;Alright, it&apos;s time to test it. Let me ask a few questions
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-10.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Not bad! It pulled relevant information from my blog posts. Let&apos;s try few more questions.
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-11.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-12.png&quot; alt=&quot;Project Deployed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, it picks up the content from the links I provided and gives me correct answers. It even returns the formatted results (bullet points) while answering. Since it&apos;s an LLM, you can converse with it as you please and it will return the results based on your input.&lt;/p&gt;
&lt;p&gt;Well, this was pretty sweet and quick. In a matter of minutes, I have my very own Large Language Model trained on my data with my defined constraints and personality, running as a web application - all without writing a single line of code! 🤯&lt;/p&gt;
&lt;h1&gt;Access the model via APIs&lt;/h1&gt;
&lt;p&gt;This is impressive, but this might not be something you are after. You may want to use the APIs to integrate the model into your application. That is a fair point, and Katonica&apos;s Generative AI platform provides access via APIs!
Let&apos;s see how we can use it.&lt;/p&gt;
&lt;h2&gt;Get API URL and Access Token&lt;/h2&gt;
&lt;p&gt;If you head over the Deploy screen or &apos;Generative AI&apos; tab, you will find your deployed chatbot model.&lt;/p&gt;
&lt;p&gt;Click on &lt;code&gt;API&lt;/code&gt;, and it&apos;ll open up a modal. Here, we can see two endpoints:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Model Prediction API endpoint&lt;/li&gt;
&lt;li&gt;Model Feedback API endpoint
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-13.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&apos;s create the API token before we click the first link, as we will need it for the next step.
Click &lt;code&gt;Create API token&lt;/code&gt;, provide the token name and click the &lt;code&gt;Create token&lt;/code&gt; button.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-27.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Copy this token, as you won&apos;t be able to see this again.
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-28.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now, select the &lt;code&gt;API usage docs&lt;/code&gt; tab and click the &lt;code&gt;View documentation&lt;/code&gt; button&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-29.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It should bring up the swagger page.&lt;/p&gt;
&lt;p&gt;Click &lt;code&gt;Authorize&lt;/code&gt; and paste the API token we copied earlier.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-14.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-15.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Use the API&lt;/h2&gt;
&lt;p&gt;Set the following payload as request body. This is the same question we asked earlier in the chatbot UI that was created for us.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
&quot;data&quot;: &quot;what are the supported secrets
  management providers? List them as bullet points&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Press the &lt;code&gt;Execute&lt;/code&gt; button and look at the response body. The same response we got earlier.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-16.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This is how easy it is to use the APIs for the project we created. With this, we are not restricted to using the UI that was created for us, but we can use the APIs within our existing applications to integrate the power of LLMs.&lt;/p&gt;
&lt;p&gt;You can also check the usage and monitor your application from the application card.&lt;/p&gt;
&lt;h1&gt;Playground&lt;/h1&gt;
&lt;p&gt;So far, we have covered how we can create a simple chatbot using the no-code approach of Katonica&apos;s Generative AI Platform. We trained the model based on our sample data by providing a few URLs, and we could ask questions. We also used the APIs to achieve the same result. This shows that you can use the APIs and integrate them within your application to talk to the model rather than using the UI provided by Katonica.&lt;/p&gt;
&lt;p&gt;Let&apos;s switch gears and explore some other interesting features that the platform has to offer.&lt;/p&gt;
&lt;p&gt;If you recall, while creating our chatbot early on, we let Katonica choose the best model for us.
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-5.png&quot; alt=&quot;Customise Data LLM&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And it&apos;s fine. Katonic picks up the model suitable for the type of application we want to build. It makes it very easy for us if we don&apos;t understand much about different models or how they function.&lt;/p&gt;
&lt;p&gt;However, if we want to gain more control over the type of LLM model we want to work with, Katonic makes it extremely easy for us to do so.&lt;/p&gt;
&lt;p&gt;Playground is a place where we can explore a variety of Generative AI models (60+ at the time of this writing available on the platform).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-17.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here, we can find models such as Stable Diffusion, code Llama, MusicGen and many others. You can navigate this list and filter based on categories for easier navigation.&lt;/p&gt;
&lt;p&gt;Let&apos;s explore stable-diffusion model here.
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-18.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-19.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As we can see, based on our input, &lt;strong&gt;an astronaut riding a horse on mars, hd, dramatic lightning&lt;/strong&gt;, it generates the image on the right.&lt;/p&gt;
&lt;p&gt;Besides the apparent input, we can change and control other parameters, such as image dimensions and other model-specific settings. Change the settings and see the difference in the output.&lt;/p&gt;
&lt;p&gt;Another important element on this page is the &apos;Model Card&apos;. For each model, you can find the details of what it does, how it works, and how you can use it, along with examples and other important information on the model. This is very handy as you can find all the necessary information at one place while you are testing any model.
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-20.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Tuning Studio&lt;/h1&gt;
&lt;p&gt;Another stellar feature, albeit an advanced one, is the Tuning Studio.
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-22.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here, you can easily manage all your custom prompts for various models you want to use for different applications. Katonica offers pre-created prompts that you can use as a foundation before customising them for your use cases.
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-23.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This is a good place to experiment with your prompts and tweak the parameters of the desired model (even try out different models to see which gives you the desired outcome). You can provide instructions to the model, give it some training data and test out the models.
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-24.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-25.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once you are finished with your prompts and happy with the results, you can save it!
&lt;img src=&quot;https://sanjaybhagia.com/images/kgai-26.png&quot; alt=&quot;API URL&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Tuning Studio also lets you manage your models so that you can manage them in one place.&lt;/p&gt;
&lt;h1&gt;Takeaway&lt;/h1&gt;
&lt;p&gt;I&apos;m impressed by the simplicity of the platform and yet how powerful it is to create, manage and operate. It makes it very convenient to develop models from a various options and deploy them in public or private environments. This becomes a one-stop shop for testing different models, both proprietary and open source. I can see how enterprises can easily train these models based on their data and deploy and manage them without compromising security.
We are going to see more and more capabilities coming in this space in the future but Katonica&apos;s no-code, private and secure platform definitely seems a great fit for companies to quickly leverage the power of LLMs within their line of offerings.&lt;/p&gt;
&lt;p&gt;You can read more about it on their official &lt;a href=&quot;https://docs.katonic.ai/UserGuide/katonic-generativeai-platform/Katonic%20Generative%20AI%20Overview&quot; target=&quot;_blank&quot;&gt;website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for sticking to the end. I hope you find this helpful.&lt;br /&gt;
Cheers&lt;/p&gt;
</content:encoded></item><item><title>Deploying IronPdf to Azure Functions via CI/CD using Azure DevOps</title><link>https://sanjaybhagia.com/blog/cicd-pipeline-irondpf-azure-functions/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/cicd-pipeline-irondpf-azure-functions/</guid><description>Guide to setup a CI/CD Pipeline (YAML) in Azure DevOps for running IronPdf in Azure Functions.</description><pubDate>Sun, 20 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;You can find the source code for the sample I am using in this blog post on my &lt;a href=&quot;https://github.com/sanjaybhagia/testironpdf&quot;&gt;GitHub&lt;/a&gt;. This contains the code for Azure Function along-with YML pipeline that I&apos;m going to discuss here.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Brief Introduction to IronPdf&lt;/h1&gt;
&lt;p&gt;IronPDF is the leading C# PDF library for generating &amp;amp; editing PDFs. Its user friendly API allows developers to rapidly deliver professional, high quality PDFs from HTML in .NET projects. Some of the key feature are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Convert web forms, local HTML pages, and other web pages to PDF with .NET&lt;/li&gt;
&lt;li&gt;Allow users to download documents, send them by email, or store them in the cloud.&lt;/li&gt;
&lt;li&gt;Produce invoices, quotes, reports, contracts, and other documents.&lt;/li&gt;
&lt;li&gt;Work with ASP.NET, ASP.NET Core, web forms, MVC, Web APIs on .NET Framework, and .NET Core.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can read more about it on their official &lt;a href=&quot;http://ironpdf.com&quot;&gt;website&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Setting the context&lt;/h1&gt;
&lt;p&gt;In this blogpost, I&apos;m going to focus on deploying your code that uses IronPdf to an Azure Function. I&apos;ll be using Azure Function on Windows, but you can find the guidance on Linux on their website as well.&lt;/p&gt;
&lt;p&gt;For the purpose of demonstration, I&apos;ve created a simple HTTP Triggered Azure Function that receives HTML string in request and returns the PDF File. I assume, the function app is already created.&lt;br /&gt;
Here is how the generated PDF looks like.
&lt;img src=&quot;https://sanjaybhagia.com/images/pdf-generated-by-ironpdf.png&quot; alt=&quot;Generated Pdf&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Deploying to Azure Function via Azure DevOps&lt;/h2&gt;
&lt;p&gt;Now we have a functioning code, let&apos;s deploy this to Azure via CI/CD pipeline using Azure DevOps&lt;/p&gt;
&lt;p&gt;The CI/CD pipeline is similar to any azure function pipeline, there is no major difference except choosing the right deployment method.&lt;/p&gt;
&lt;h2&gt;Choosing the Deployment method.&lt;/h2&gt;
&lt;p&gt;In Azure DevOps, for the &lt;code&gt;AzureFunctionApp@1&lt;/code&gt; task, there are the following supported methods.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;auto&lt;/li&gt;
&lt;li&gt;zipDeploy&lt;/li&gt;
&lt;li&gt;runFromPackage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;auto&lt;/code&gt; is the default method, when you add a task. But for IronPdf, &lt;code&gt;zipDeploy&lt;/code&gt; is the recommended mode&lt;/p&gt;
&lt;h2&gt;YML Snippet&lt;/h2&gt;
&lt;p&gt;Here is the yml snippet for this step:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;steps:
- task: AzureFunctionApp@1
  displayName: Azure functions app deploy
  inputs:
    azureSubscription: &amp;lt;subscription name&amp;gt;
    appType: functionApp
    appName: ironpdf-azurefunc-app 
    package: $(Pipeline.Workspace)/azurefunction/a.zip
    deploymentMethod: zipDeploy
    appSettings: &amp;gt;
      -FUNCTIONS_EXTENSION_VERSION &quot;~4&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only different is setting the &lt;code&gt;deploymentMethod&lt;/code&gt; to &lt;code&gt;zipDeploy&lt;/code&gt; instead of default &lt;code&gt;auto&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This will deploy the code from your solution in Azure Function.&lt;/p&gt;
&lt;p&gt;You can find the complete CI/CD pipeline in my GitHub repository &lt;a href=&quot;https://github.com/sanjaybhagia/testironpdf/blob/main/ironpdf-azurefunc-pipeline.yml&quot;&gt;here&lt;/a&gt;. You will need to adjust the settings to make it work for your environment such as subscription name etc.&lt;/p&gt;
&lt;h1&gt;Bonus: GitHub Action&lt;/h1&gt;
&lt;p&gt;If you prefer using GitHub, I have also included the action for your in my repository. You can find it &lt;a href=&quot;https://github.com/sanjaybhagia/testironpdf/blob/main/.github/workflows/azure-functions-app-dotnet.yml&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hope it helps.
Cheers&lt;/p&gt;
</content:encoded></item><item><title>The best investment I made in 2022</title><link>https://sanjaybhagia.com/blog/the-best-investment-i-made-in-2022/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/the-best-investment-i-made-in-2022/</guid><description>Find out how a simple $15 bullet journal transformed my life in 2022 and why you should give it a try.</description><pubDate>Mon, 06 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We all know that 2022 was a challenging year for many of us around the world. The stock markets struggled, inflation reached record highs, and the fear of a global recession loomed large. I was no exception and didn&apos;t fare well with financial investments last year. However, despite all the challenges, there is one thing that I did in 2022 that turned out to be the best investment for me. And it only cost me $15!&lt;/p&gt;
&lt;p&gt;It was a bullet journal.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/bullet-journal.jpg&quot; alt=&quot;Journal&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You may have heard about bullet journal before, but if you haven&apos;t, it&apos;s a simple journaling approach that can help you organize your life. You can read all you want about the bullet journal &lt;a href=&quot;https://bulletjournal.com/&quot;&gt;here&lt;/a&gt;. I started with a very basic approach, using it to plan my weekly tasks. Rather than planning each day, I found that planning each week worked better for me. I primarily use this approach to organize my personal life, not my work (for work, I use a similar weekly planning approach but on OneNote).&lt;/p&gt;
&lt;p&gt;At first, it may seem like a simple concept, but I have achieved much more by just planning my weeks over the last year than I ever have before. Here are some of the things I accomplished in 2022:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;More workouts. I have been much more consistent than I have ever been in my entire life.&lt;/li&gt;
&lt;li&gt;More running. In fact, I completed my very first &lt;a href=&quot;https://sydneyrunningfestival.com.au/&quot;&gt;10k run&lt;/a&gt; run back in September 2022.&lt;/li&gt;
&lt;li&gt;More walking. I completed my very first &lt;a href=&quot;https://www.7bridgeswalk.com.au/&quot;&gt;28k walk&lt;/a&gt; walk in October 2022, in addition to walking my dog almost every day.&lt;/li&gt;
&lt;li&gt;More socialization with friends.&lt;/li&gt;
&lt;li&gt;Hosted more events at my home.&lt;/li&gt;
&lt;li&gt;Published my very first &lt;a href=&quot;https://www.educative.io/courses/cloud-computing-fundamentals&quot;&gt;course&lt;/a&gt; on cloud computing fundamentals, yeah!&lt;/li&gt;
&lt;li&gt;More experiences, including trying out new restaurants, attending events, concerts, exhibitions, and outdoor activities.&lt;/li&gt;
&lt;li&gt;More done around the house, including fixing things and maintenance tasks.&lt;/li&gt;
&lt;li&gt;More certifications. I completed several certifications in 2021 and had to renew most of them in 2022, so with a little bit of planning, I managed to get them done.&lt;/li&gt;
&lt;li&gt;Increased my financial literacy by taking few courses to educate myself on the subject.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of this was achieved simply by putting down the tasks I intended to do each week in my bullet journal. No overthinking, no fancy productivity hacks, no over-the-top system to get things done. Just a simple list of activities that I planned to do each week.&lt;/p&gt;
&lt;p&gt;One of the best things about bullet journaling is that you can use any tool that works for you, whether it&apos;s an analog journal or a digital equivalent. What matters is the act of doing it.&lt;/p&gt;
&lt;p&gt;So, if you&apos;re not already using a bullet journal or a similar system, I highly encourage you to give it a try. You may be surprised at how much you can get done by being intentional about your tasks. Here&apos;s to the next year and all the things we&apos;ll achieve! 🥂&lt;/p&gt;
</content:encoded></item><item><title>Pulumi - State Management</title><link>https://sanjaybhagia.com/blog/pulumi-state-management/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/pulumi-state-management/</guid><description>How Pulumi tracks infrastructure state, and a walkthrough of replacing the hosted backend with your own Azure Blob Storage container.</description><pubDate>Mon, 01 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I am learning &lt;a href=&quot;https://www.pulumi.com/&quot;&gt;Pulumi&lt;/a&gt; and I&apos;ll be sharing my journey along the way here in the form of blog posts and code samples on my &lt;a href=&quot;https://github.com/sanjaybhagia/pulumi-examples&quot;&gt;GitHub&lt;/a&gt;. Join me on this journey if this topic interests you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Disclaimer: I have hands-on experience working with the Microsoft Azure Cloud platform not so much with others. So in here, I&apos;ll be looking at Pulumi from Azure&apos;s lens and most of my references and examples will be with Azure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you haven&apos;t read my previous blog posts around this topic, you can check them out here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/09/10/pulumi-what-and-why&quot;&gt;Pulumi - What and Why?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/09/21/pulumi-how-it-works&quot;&gt;Pulumi - How it works?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2021/01/15/pulumi-configuration-management&quot;&gt;Pulumi - Configuration Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2021/01/22/pulumi-secrets-management&quot;&gt;Pulumi - Secrets Management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blog post, I&apos;m going to explore and understand how Pulumi manages the state.&lt;/p&gt;
&lt;h2&gt;What is State?&lt;/h2&gt;
&lt;p&gt;Pulumi manages the state (in the form of a state file - a JSON file). This is the source of truth for Pulumi. Whenever you make any change in your program, Pulumi refers to that state and checks with resource providers to determine what action needs to be taken (update, delete, add or nothing). Each stack in Pulumi has it&apos;s own state file.&lt;/p&gt;
&lt;p&gt;Pulumi keeps this state file in a backend. By default, pulumi offers it&apos;s own free backend service (http://pulumi.com), it works seamlessly and offers a nice UI on top of it where you can see what&apos;s going on during the lifecycle of any program and stack. However, as mentioned earlier, we can take complete control of the state management. This is where, we can either keep the state locally or in any other backend such as Azure Storage (which we will explorer in here a bit later). You can read more about the advantages of using Pulumi&apos;s hosted backend &lt;a href=&quot;https://www.pulumi.com/docs/intro/concepts/state/#deciding-on-a-backend&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Using Azure Storage as a backend&lt;/h1&gt;
&lt;p&gt;You can use any backend (e.g., Local file system, AWS S3, Google Cloud Storage etc.) to manage your state but for this blogpost let&apos;s focus on Azure Blob Storage.&lt;/p&gt;
&lt;p&gt;For this, we need to first create a storage account and a container within that. You can perform all of the following operations via Azure Portal if you feel comfortable with that.&lt;/p&gt;
&lt;h2&gt;Create a resource group&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;az group create --name rg-pulumi-state-dev --location australiasoutheast&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Create Storage Account&lt;/h2&gt;
&lt;h3&gt;Create an account&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;$SA=$(az storage account create --name pulumiazstate --resource-group rg-pulumi-state-dev --location australiasoutheast --sku Standard_LRS --access-tier Hot --https-only true --kind StorageV2)&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Extract keys&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;$KEYS=$(az storage account keys list --account-name pulumiazstate --resource-group rg-pulumi-state-dev --output json)&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Set Environment Variables&lt;/h3&gt;
&lt;p&gt;We need to set &lt;code&gt;AZURE_STORAGE_ACCOUNT&lt;/code&gt; and &lt;code&gt;AZURE_STORAGE_KEY&lt;/code&gt; as environment variables so that the CLI can use them while performing other operations. You can set them manually or via script. Here is the PowerShell / CLI combination to set them.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[System.Environment]::SetEnvironmentVariable(&apos;AZURE_STORAGE_ACCOUNT&apos;,&apos;pulumiazstate&apos;)&lt;/code&gt;
&lt;code&gt;[System.Environment]::SetEnvironmentVariable(&apos;AZURE_STORAGE_KEY&apos;,$(echo $KEYS | jq -r .[0].value)&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Create a container in the storage account&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;az storage container create --name state&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;the command above uses the &apos;AZURE_STORAGE_KEY&apos; environment variable we defined earlier.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Head over to the Azure Portal to see the account and a container has been successfully created.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-backend-container.png&quot; alt=&quot;Container&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Set storage account as state backend&lt;/h2&gt;
&lt;p&gt;Now we have a storage account and a container ready, let&apos;s tell Pulumi to use that as a backend. Pulumi offers following command to do this:&lt;br /&gt;
&lt;code&gt;pulumi login azblob://&amp;lt;container-path&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;so go ahead and execute &lt;code&gt;pulumi login azblob://state&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Create a new stack&lt;/h2&gt;
&lt;p&gt;Create a new directory &lt;code&gt;mkdir azbackend&lt;/code&gt; and navigate &lt;code&gt;cd azbackend&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;From this point onward, the rest of the approach is similar to what we have done earlier. The only different being when you create a stack, you will be asked for a passphrase.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pulumi new&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-backend-new-stack.png&quot; alt=&quot;New Stack&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can use the Azure key vault to manage the encryption if you will. Refer to my previous &lt;a href=&quot;https://sanjaybhagia.com/2021/01/22/pulumi-secrets-management&quot;&gt;blogpost&lt;/a&gt; to see how that can be done.&lt;/p&gt;
&lt;p&gt;Now we have a stack created with our backend managed within Azure Blob Storage.
If you head over to the container we created earlier, you will see a folder for the stack we created &apos;dev&apos; and a JSON file.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-backend-state-blob.png&quot; alt=&quot;State&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This is the checkpoint file or state file Pulumi uses where it keeps track of the state of our infrastructure. You can see the file contents directly from within the portal in edit mode.&lt;/p&gt;
&lt;h2&gt;Preview the stack&lt;/h2&gt;
&lt;p&gt;If you go one step further and execute &lt;code&gt;pulumi preview&lt;/code&gt; you will find everything works as usual. Notice, the URL is now pointing to our blob instead of Pulumi&apos;s backend.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-backend-preview.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now, go ahead and execute &lt;code&gt;pulumi up&lt;/code&gt; and let it finish. If you check the state file now, you will see a lot more content in there.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-backend-up.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Logout&lt;/h2&gt;
&lt;p&gt;In order to work with external storage we used &lt;code&gt;pulumi login azblob://&amp;lt;container-path&amp;gt;&lt;/code&gt; earlier. If you would like to switch to a different backend or return to the default one, you can use
&lt;code&gt;pulumi logout&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This simply logs you out and you can start with &lt;code&gt;pulumi login&lt;/code&gt; again with the choice of your backend.&lt;/p&gt;
&lt;h1&gt;Interacting with the state via CLI&lt;/h1&gt;
&lt;p&gt;You can use some commands to interact with the state, such as:
&lt;code&gt;pulumi state&lt;/code&gt;
&lt;code&gt;pulumi state delete&lt;/code&gt;
&lt;code&gt;pulumi state unprotect&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you would like to export the sate you can use &lt;code&gt;pulumi stack export&lt;/code&gt; and &lt;code&gt;pulumi stack import&lt;/code&gt; allows you to import the existing state to your stack.&lt;/p&gt;
&lt;h1&gt;Things to be aware of&lt;/h1&gt;
&lt;p&gt;Pulumi&apos;s default hosted backend service offers quite a several things that make our life easier. So when we decide to user any external backend systems, we loose some nice features that are worth being aware of.&lt;/p&gt;
&lt;h2&gt;No UI&lt;/h2&gt;
&lt;p&gt;First and foremost, if you use any external backend, you can&apos;t use the nice UI that pulumi.com offers. Which means, you will have to read the JSON file if you want to make sense of what is going on.&lt;/p&gt;
&lt;h2&gt;Security&lt;/h2&gt;
&lt;p&gt;Since state file contains encryption keys etc, it is our responsibility to secure the access to the storage account. Be sure you follow the principle of least privilege when it comes to setting up backends.&lt;/p&gt;
&lt;h2&gt;Stack names&lt;/h2&gt;
&lt;p&gt;when we use Pulumi&apos;s backend service it creates stack names as fully qualified names (projectname/stackname). Pulumi handles that behind the scenes and we get a good experience of having a separation of the project name for stacks. When we are using any other backend, we don&apos;t get that. Stack name is simply the name we mention at the time of &lt;code&gt;pulumi new&lt;/code&gt;. So if we created a stack with &lt;code&gt;dev&lt;/code&gt; already, we won&apos;t be able to create another stack with the same name. This forces us to set the strategy of naming our stacks from the get-go. To put it simply, Pulumi used fully qualified names for naming stacks (organization/project/stack) where as any other backend uses just the stack name. It is up to us to introduce the hierarchy.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-backend-stack-names.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Pulumi provides a robust and free hosted service to manage the state and backend but at the same time we can complete control over that if we want. We can use a file system, AWS S3, Azure Blob Storage and Google Cloud Storage to manage the backend by ourselves. The tools pulumi provides (CLI etc.) work similarly irrespective of the backend you use. However, you need to be aware of few things you might have to manage on your own if you choose not to use Pulumi&apos;s hosted backend service.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Pulumi - Secrets Management</title><link>https://sanjaybhagia.com/blog/pulumi-secrets-management/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/pulumi-secrets-management/</guid><description>How Pulumi encrypts secrets in stack configuration, and using the passphrase and Azure Key Vault providers to manage your own encryption keys.</description><pubDate>Tue, 26 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I am learning &lt;a href=&quot;https://www.pulumi.com/&quot;&gt;Pulumi&lt;/a&gt; and I&apos;ll be sharing my journey along the way here in the form of blog posts and code samples on my &lt;a href=&quot;https://github.com/sanjaybhagia/pulumi-examples&quot;&gt;GitHub&lt;/a&gt;. Join me on this journey if this topic interests you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Disclaimer: I have hands-on experience working with Microsoft Azure Cloud platform not so much with others. So in here, I&apos;ll be looking at Pulumi from Azure&apos;s lens and most of my references and examples will be with Azure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you haven&apos;t read my previous blog posts around this topic, you can check them out here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/09/10/pulumi-what-and-why&quot;&gt;Pulumi - What and Why?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/09/21/pulumi-how-it-works&quot;&gt;Pulumi - How it works?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2021/01/15/pulumi-configuration-management&quot;&gt;Pulumi - Configuration Management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blog post, I&apos;m going to explore and understand how Pulumi manages secrets.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We will build on the &lt;a href=&quot;https://sanjaybhagia.com/pulumi-configuration-management&quot;&gt;Configuration Management&lt;/a&gt; blog post that I wrote earlier so please have a look if you haven&apos;t done so already.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Having sensitive information such as Passwords, API Keys, Tokens, ConnectionStrings etc. is quite common for any application. However keeping them in your source code in plaintext is never a good idea, let alone checking it in your source control.&lt;/p&gt;
&lt;p&gt;Pulumi&apos;s configuration system lets us add secrets to our configuration in a similar way we manage any other configuration. Pulumi offers multiple approaches to manage sensitive information and exposes a number of APIs and tools we can use to work with them seamlessly, so without further a do, let&apos;s explore how it all works.&lt;/p&gt;
&lt;h1&gt;Handling Secrets&lt;/h1&gt;
&lt;p&gt;First off, let&apos;s see how can we set secrets in our configuration.&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;pulumi config set&lt;/code&gt; with &lt;code&gt;--secret&lt;/code&gt; flag to set a secret&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pulumi config set --secret mySecretKey mySecretValue&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Check the config
&lt;code&gt;pulumi config&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To retrieve the secrets programmatically, the use of &lt;code&gt;RequireSecrets&lt;/code&gt; variant is recommended.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pulumi.Log.Info($&quot;mySecretKey: {config.RequireSecret(&quot;mySecretKey&quot;)}&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;see the value is masked&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-config-get-secret.jpg&quot; alt=&quot;Pulumi Config Get Secret&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If we look at the &lt;code&gt;Pulumi.dev.yaml&lt;/code&gt; file in VSCode, this is what we see:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config:
  azure:location: australiaeast
  hello-pulumi:data:
    active: true
    nums:
    - 1
    - 2
    - 3
  hello-pulumi:location: australiasoutheast
  hello-pulumi:mySecretKey:
    secure: AAABAFybCK/w34qectPQHPWSoivUhG7uI5//y7Xqc/6Cczh3k3Yi35zvrk+U
  hello-pulumi:resourcesName: pulumi

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at this, what we see is that the configuration we set as a secret is not stored in plaintext, it is in fact encrypted. By default, Pulumi uses &lt;strong&gt;per-stack&lt;/strong&gt; encryption key managed by the Pulumi Service to encrypt values.&lt;/p&gt;
&lt;p&gt;However, this might not be desirable in situations where you want to manage the state by yourself by using any external storage like S3 bucket, Azure Blob storage. Or you simply don&apos;t want Pulumi to manage the keys and would prefer keeping that control and management with you. For such scenarios, Pulumi supports multiple providers for secrets management.&lt;/p&gt;
&lt;p&gt;As of this writing, these are the supported providers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;default&lt;/li&gt;
&lt;li&gt;passphrase&lt;/li&gt;
&lt;li&gt;awskms&lt;/li&gt;
&lt;li&gt;azurekeyvault&lt;/li&gt;
&lt;li&gt;gcpkms&lt;/li&gt;
&lt;li&gt;hashivault&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We used &lt;code&gt;default&lt;/code&gt; provider in our examples above. &lt;code&gt;passphrase&lt;/code&gt; allows you to keep the encryption keys to yourself but still use Pulumi&apos;s backend service for state management OR you are self-managing the state storage (e.g., Azure Storage). The last option is where you are completely managing your own keys (bring your own key a.k.a BYOK)&lt;/p&gt;
&lt;h2&gt;Using Passphrase&lt;/h2&gt;
&lt;p&gt;Let&apos;s create a new stack in our codebase that we used in the previous blogpost (grab the core &lt;a href=&quot;https://github.com/sanjaybhagia/pulumi-examples/tree/d035014aa852ff2d68a8958d5036037a5cf50ae4/hello-pulumi&quot;&gt;here&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pulumi stack init passphrasestack --secrets-provider passphrase&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;or create a new project
&lt;code&gt;pulumi new azure-csharp --secrets-provider passphrase&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It&apos;ll ask for the passphrase. This is the passphrase that Pulumi is going to use to encrypt the configuration system.
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-stack-init-passphrase-1.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Looking at the project in VSCode, we can see a new file has been created
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-stack-init-passphrase-2.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s add two keys (one normal and one secret)
&lt;code&gt;pulumi config set normalKey normalValue&lt;/code&gt;
&lt;code&gt;pulumi config set --secret secretKey secretValue&lt;/code&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-stack-init-passphrase-3.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This is how our stack file looks like
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-stack-init-passphrase-4.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you pay attention, the secure value in &lt;code&gt;Pulumi.passphrasestack.yaml&lt;/code&gt; is different to what we had in &lt;code&gt;Pulumi.dev.yaml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Notice, we need to enter the passphrase every time we are performing any operations. This can be avoided by setting &lt;code&gt;PULUMI_CONFIG_PASSPHRASE&lt;/code&gt; in your environment variables (can be done on the local machine or in the CI system).&lt;/p&gt;
&lt;h2&gt;Using Azure Key Vault for encryption&lt;/h2&gt;
&lt;p&gt;This would be a similar approach for any other cloud-based provider but we are looking at Azure Key Vault here.
In order to use the Azure Key Vault for managing the encryption keys, the approach is same i.e., we set &lt;code&gt;--secret-provider&lt;/code&gt; to Azure Key Vault via the CLI&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ pulumi stack init &amp;lt;name&amp;gt; --secrets-provider=&quot;&amp;lt;provider&amp;gt;://&amp;lt;provider-settings&amp;gt;&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;e.g.,
&lt;code&gt;$ pulumi stack init &amp;lt;name&amp;gt; --secrets-provider=&quot;azurekeyvault://&amp;lt;keyvaultname&amp;gt;.vault.azure.net/keys/&amp;lt;key name&amp;gt;&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Before we could do this, we need to create the Key Vault and a Key in the vault that we need.&lt;/p&gt;
&lt;h3&gt;Create Azure Key Vault&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;az keyvault create --name pulumiazvault --resource-group rg-pulumi-dev --location australiasoutheast&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Create the Key in Vault&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;az keyvault key create --name pulumiencryptionkey --vault-name pulumiazvault&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Assign Access&lt;/h3&gt;
&lt;p&gt;When you create the vault and key from the CLI, a policy is created by default but it doesn&apos;t set &apos;encrypt&apos; and &apos;decrypt&apos; policy for us, so use this command to include that.&lt;/p&gt;
&lt;p&gt;Extract Object Id of your account (you can pull this from Azure AD or run the command below to extract it. Use your account here)&lt;br /&gt;
&lt;code&gt;az ad user show --id &amp;lt;your account name&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Look up for ObjectId of your account&lt;/p&gt;
&lt;p&gt;&lt;code&gt;az keyvault set-policy --name pulumiazvault --object-id &amp;lt;Object Id from above&amp;gt; --key-permissions encrypt decrypt get create delete list update import backup restore recover&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I prefer using Azure AD Application instead of any individual user account for such scenarios. In that case you will need the ObjectId of the application instead&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now we have the key vault with a key that we will use for encryption along with the right access policy set.
&lt;img src=&quot;https://sanjaybhagia.com/images/az-keyvault-with-key.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Set Environment Variables&lt;/h3&gt;
&lt;p&gt;You can set this if you want to use the credentials from the CLI (that you already have set up).
&lt;code&gt;AZURE_KEYVAULT_AUTH_VIA_CLI=true&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Checkout &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/developer/go/azure-sdk-authorization#use-environment-based-authentication&quot;&gt;Azure Environment Authentication&lt;/a&gt; if you wish to use other authentication mechanism such as Client Credentials, Username/Password etc.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I prefer using Client Credentials since I&apos;m using Azure AD Application approach&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Create a new stack&lt;/h3&gt;
&lt;p&gt;I&apos;m creating a new project for this scenario rather than using the previous one but you could very well create a new stack in the same project that uses Azure key Vault provider.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pulumi new azure-csharp --secrets-provider=&quot;azurekeyvault://pulumiazvault.vault.azure.net/keys/pulumiencryptionkey&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Pulumi.dev.yaml&lt;/code&gt; files looks like this after creating the new project. As you notice, we have the information about secrets provider and encryption key. From this point onward, Pulumi uses this information to encrypt the configuration system for us.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;secretsprovider: azurekeyvault://pulumiazvault.vault.azure.net/keys/pulumiencryptionkey
encryptedkey: N1JsSnFjWGpKUl9jY3U1SlRQd2J2WXd3TEw0XzQxeWExY2hTOEhtLTRKWkd3cTViblg3OWF4VHFTcDY4amo4RDc4RUxyT3poNC0tUEVSM0ppbUxfcUdiN1dOWm9Cb0VrNU5TODF6dUlMVEg3c2VVc1ItTVZfRjFBQWpmdGNiX29xYU1BdTN2d0NlMmtWUWFUWUc0NjNJMnh4eUNybzdJMzlXZHdXMVRpODh4TnZfdDM1R2pfdS1rS3VlQlh5cDI4OXZmMkxXaFFuNzNBckJaRU9vcnl5WmJPeUVXMHpJSzlIOEZXOG5WTnl6akFXYmxWYkkyYVB6c3BsUWpDOGw5OFRJNXFyV0JBSjAybHVkTE9UMGF6MllqSW4xbm9GVW1pODRsbVJZbEh6OThPLUdBemlhcWp4V1dKaE5vN0NDeEFZdFM2cXk3emozSDI0UHlGQllESTdR
config:
  azure:location: australiasoutheast

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rest of the things works the same as &lt;code&gt;default&lt;/code&gt; or &lt;code&gt;passphrase&lt;/code&gt; provider for encryption.&lt;/p&gt;
&lt;h1&gt;Switching Encryption providers&lt;/h1&gt;
&lt;p&gt;You change the secrets provider of any of your stack anytime via this command.
&lt;code&gt;pulumi stack change-secrets-provider &quot;&amp;lt;secrets-provider&amp;gt;&quot;&lt;/code&gt;
It&apos;s pretty straightforward, once the provider is changed, Pulumi will use the new secrets provider to encrypt configuration and state files.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Pulumi provides a robust mechanism for configuration management of your infrastructure. It provides support for handling secrets as well. You have the possibility to use external service providers for secrets management such as Azure Key Vault by using a familiar approach. The default option is secure and configurations and secrets are encrypted by the keys that Pulumi manages for us however we have the flexibility to take ownership of this and go to that extra mile for enhanced security or compliance reasons.&lt;/p&gt;
&lt;p&gt;You can find the source code for this blog post &lt;a href=&quot;https://github.com/sanjaybhagia/pulumi-examples/tree/950d6b4889999be548a21cccb9945ad5f9cd20a0/pulumi-azvault&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Pulumi - Configuration Management</title><link>https://sanjaybhagia.com/blog/pulumi-configuration-management/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/pulumi-configuration-management/</guid><description>How Pulumi&apos;s per-stack configuration works: setting and reading values via the CLI and C# code, namespaces, and structured config with --path.</description><pubDate>Fri, 15 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I am learning &lt;a href=&quot;https://www.pulumi.com/&quot;&gt;Pulumi&lt;/a&gt; and I&apos;ll be sharing my journey along the way here in the form of blog posts and code samples on my &lt;a href=&quot;https://github.com/sanjaybhagia/pulumi-examples&quot;&gt;GitHub&lt;/a&gt;. Join me on this journey if this topic interests you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Disclaimer: I have hands-on experience working with Microsoft Azure Cloud platform not so much with others. So in here, I&apos;ll be looking at Pulumi from Azure&apos;s lens and most of my references and examples will be with Azure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you haven&apos;t read my previous blog posts around this topic, you can check them out here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/09/10/pulumi-what-and-why&quot;&gt;Pulumi - What and Why?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/09/21/pulumi-how-it-works&quot;&gt;Pulumi - How it works?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blog post, I&apos;m going to explore and understand how configuration management works in Pulumi.&lt;/p&gt;
&lt;h1&gt;Understanding the Basics&lt;/h1&gt;
&lt;p&gt;In Pulumi each stack can be configured separately. By default, when using &lt;code&gt;pulumi new&lt;/code&gt; a stack is created at that time and the file is named as Pulumi.[stack name].yaml. However, you can create new stacks with &lt;code&gt;pulumi stack init&lt;/code&gt; command at any time. It&apos;s important to notice that with &lt;code&gt;pulumi stack init&lt;/code&gt; no new file is created, this is something we need to create manually.&lt;/p&gt;
&lt;p&gt;Stack configuration files are used to store stack variables and secrets (more on this in another blog post). We can interact with configuration management either via CLI or programmatically. Let&apos;s check them out.&lt;/p&gt;
&lt;h2&gt;Working with Configuration via CLI&lt;/h2&gt;
&lt;p&gt;Pulumi CLI provides &lt;code&gt;pulumi config&lt;/code&gt; to work with the configuration systems.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pulumi config set &amp;lt;key&amp;gt; [value]&lt;/code&gt;: sets a configuration entry &lt;code&gt;&amp;lt;key&amp;gt;&lt;/code&gt; to &lt;code&gt;[value]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pulumi config get &amp;lt;key&amp;gt;&lt;/code&gt;: gets an existing configuration value with the key &lt;code&gt;&amp;lt;key&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pulumi config&lt;/code&gt;: gets all configurations for the current stack. you can specify &lt;code&gt;-s &amp;lt;stack name&amp;gt;&lt;/code&gt; flag to retrieve configurations for a particular stack.&lt;/p&gt;
&lt;p&gt;Pulumi uses the project name as the default namespace and appends it as a prefix for key names. So &lt;code&gt;pulumi config set location australiasoutheast&lt;/code&gt; will end up adding an entry (key/value) to  Pulumi.dev.yaml file like this (where &lt;code&gt;hello-pulumi&lt;/code&gt; is the project name):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config:
  azure:location: australiaeast
  hello-pulumi:location: australiasoutheast
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This (namespace) makes it easier to segregate the configurations for different providers or components.&lt;/p&gt;
&lt;p&gt;So if we have to retrieve the key from the specific namespace, we can specify the full name by adding prefix while fetching e.g., &lt;code&gt;pulumi config get &apos;azure:location&apos;&lt;/code&gt; or &lt;code&gt;pulumi config get &apos;hello-pulumi:location&apos;&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Working with Configuration via Code&lt;/h2&gt;
&lt;p&gt;Working with configuration via code is also very straightforward. For C#, Pulumi exposes &lt;code&gt;Pulumi.Config&lt;/code&gt; type.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var config = new Pulumi.Config();
var resourcesName = config.Get(&quot;resourcesName&quot;);
var location = config.Require(&quot;location&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Pulumi.Config()&lt;/code&gt; takes the namespace name as an optional parameter. If you don&apos;t pass it uses the project name&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;Config.Get&lt;/code&gt; will return &lt;code&gt;null&lt;/code&gt; if the configuration value was is provided whereas &lt;code&gt;Config.Require&lt;/code&gt; raises an exception with a helpful error message to prevent the deployment from continuing until the variable has been set.&lt;/p&gt;
&lt;p&gt;Pulumi also exposes &lt;code&gt;Pulumi.Deployment.Instance&lt;/code&gt; that allows us to retrieve the project name and stack name etc. at runtime &lt;code&gt;Pulumi.Deployment.Instance.StackName&lt;/code&gt; and &lt;code&gt;Pulumi.Deployment.Instance.ProjectName&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Structured Configuration&lt;/h2&gt;
&lt;p&gt;Often we have structured configuration such as a JSON or YAML that we need to deal with in our applications. Pulumi works wonderfully well with that type of configuration as well.&lt;/p&gt;
&lt;p&gt;We use the same &lt;code&gt;pulumi config&lt;/code&gt; command to interact with the configuration system. The only difference with structured configuration is we need to pass &lt;code&gt;--path&lt;/code&gt; switch such as
&lt;code&gt;pulumi config set --path &apos;data.active&apos; true&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;So let&apos;s set some configuration using the CLI.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pulumi config set --path &apos;data.active&apos; true
pulumi config set --path &apos;data.nums[0]&apos; 1
pulumi config set --path &apos;data.nums[1]&apos; 2 
pulumi config set --path &apos;data.nums[2]&apos; 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This results in following configuration.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config:
  azure:location: australiaeast
  hello-pulumi:location: australiasoutheast
  hello-pulumi:data:
    active: true
    nums:
    - 1
    - 2
    - 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To retrieve the setting via the CLI, we use &lt;code&gt;pulumi config get --path &apos;data.nums[2]&lt;/code&gt; and it returns &lt;code&gt;3&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;For programmatic approach, Pulumi exposes &lt;code&gt;Config.GetObject&lt;/code&gt; and &lt;code&gt;Config.RequireObject&lt;/code&gt; for such functionality&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var config = new Pulumi.Config();
var data = config.RequireObject&amp;lt;JsonElement&amp;gt;(&quot;data&quot;);
Pulumi.Log.Info($&quot;Active: {data.GetProperty(&quot;active&quot;)}&quot;);
Pulumi.Log.Info($&quot;Nums[2] number?: {data.GetProperty(&quot;nums&quot;)[2]}&quot;);

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Get&lt;/code&gt; vs &lt;code&gt;Require&lt;/code&gt; works in a similar fashion we discussed previously.&lt;/p&gt;
&lt;h1&gt;Making changes to our program&lt;/h1&gt;
&lt;p&gt;In the previous blog post, we created a hello world pulumi program that created a resource group and a storage account for us (check out the source &lt;a href=&quot;https://github.com/sanjaybhagia/pulumi-examples/blob/524fc5c60b017b7564e2141b33f85e05c6310e30/hello-pulumi/MyStack.cs&quot;&gt;here&lt;/a&gt;). That time the resources were assigned unique names by Pulumi (this is the default behavior if we don&apos;t specify &lt;code&gt;Name&lt;/code&gt; property of any resource). Let&apos;s change that and assign names explicitly to the resource group and storage account.&lt;/p&gt;
&lt;p&gt;The naming convention I want to use is:&lt;br /&gt;
&lt;strong&gt;Resource Group&lt;/strong&gt;: &apos;rg-pulumi-dev&apos; (where &apos;dev&apos; is the environment that we pick from the stack name).&lt;br /&gt;
&lt;strong&gt;Storage Account&lt;/strong&gt;: &apos;strpulumidev&apos;&lt;/p&gt;
&lt;p&gt;In order to pick up the stack name at runtime, we can use &lt;code&gt;Deployment.Instance&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var stack = Deployment.Instance.StackName;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let&apos;s define a new property called &lt;code&gt;resourcesName&lt;/code&gt; by using the following command in our terminal:&lt;br /&gt;
&lt;code&gt;pulumi config set resourcesName pulumi&lt;/code&gt;&lt;br /&gt;
This adds a new key/value pair in our &lt;code&gt;dev&lt;/code&gt; stack. Once we have it, let&apos;s read that in our code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var resourcesName = config.Require(&quot;resourcesName&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lets use this information to construct the resource name at runtime&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var resourceGroupName = $&quot;rg-{resourcesName}-{stack}&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we expand our resource group resource declaration to this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var resourceGroup = new ResourceGroup(&quot;resourceGroup&quot;, new ResourceGroupArgs()
        {
            Name = resourceGroupName, //If we don&apos;t set this, Pulumi generates a random unique Id by itself
            Location = location
        });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repeat it for storage account.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Construct storage account name
var storageAccountName = $&quot;str{resourcesName}{stack}&quot;;
var storageAccount = new Account(&quot;storage&quot;, new AccountArgs
{
    ResourceGroupName = resourceGroup.Name,
    Name = storageAccountName,  //If we don&apos;t set this, Pulumi generates a random unique Id by itself
    AccountReplicationType = &quot;LRS&quot;,
    AccountTier = &quot;Standard&quot;,
    Tags =  {
        { &quot;Environment&quot;, &quot;Dev&quot; }
    }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when we do &lt;code&gt;pulumi preview&lt;/code&gt; we can see what Pulumi is going to create for us by checking state over at pulumi.com
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-state-config-changes.png&quot; alt=&quot;Pulumi Config Changes&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Pulumi provides a robust mechanism for configuration management of your infrastructure. You can interact with configs via the CLI and programming model with the same ease. There are a number of built-in utility functions within the SDK to make it easier to work with configurations. You can use the power of programming language to work with the configurations like you normally would in your application.&lt;/p&gt;
&lt;p&gt;You can check out the entire source code along with configuration file &lt;a href=&quot;https://github.com/sanjaybhagia/pulumi-examples/tree/d035014aa852ff2d68a8958d5036037a5cf50ae4/hello-pulumi&quot;&gt;here&lt;/a&gt; for reference.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Pulumi - How it works?</title><link>https://sanjaybhagia.com/blog/pulumi-how-it-works/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/pulumi-how-it-works/</guid><description>A look under the hood of Pulumi: the engine, language hosts, resource providers, stacks and state, plus a hello world program targeting Azure.</description><pubDate>Mon, 21 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I am learning &lt;a href=&quot;https://www.pulumi.com/&quot;&gt;Pulumi&lt;/a&gt; and I&apos;ll be sharing my journey along the way here in the form of blog posts and code samples on my &lt;a href=&quot;https://github.com/sanjaybhagia/pulumi-examples&quot;&gt;GitHub&lt;/a&gt;. Join me on this journey if this topic interests you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Disclaimer: I have hands-on experience working with Microsoft Azure Cloud platform not so much with others. So in here, I&apos;ll be looking at Pulumi from Azure&apos;s lens and most of my references and examples will be with Azure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you haven&apos;t read my previous blog posts around this topic, you can check them out here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/09/10/pulumi-what-and-why&quot;&gt;Pulumi - What and Why?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this blog post, I&apos;m going to explore and understand How Pulumi works. What are the underlying core concepts and toward the end, will add a &apos;Hello World&apos; to see in practice.&lt;/p&gt;
&lt;h1&gt;How Pulumi works?&lt;/h1&gt;
&lt;p&gt;So let&apos;s try to understand how Pulumi actually works.
Let&apos;s have a look at the Pulumi Engine Diagram that is take from their website.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-engine-block-diagram.png&quot; alt=&quot;Pulumi Engine Diagram&quot; /&gt;
&lt;em&gt;Pulumi Engine Diagram from Pulumi.com&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You write a &lt;em&gt;Pulumi Program&lt;/em&gt; which is executed by a &lt;em&gt;language host&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;You handover that &lt;em&gt;Program&lt;/em&gt; to the &lt;em&gt;Engine&lt;/em&gt; (using the Pulumi CLI)&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;engine&lt;/em&gt; compares the desired state of your infrastructure with the &lt;em&gt;stack&apos;s&lt;/em&gt; current state and figures out the needed changes&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;engine&lt;/em&gt; then uses &lt;em&gt;resource providers&lt;/em&gt; to manage the resources&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&apos;s try to understand these concepts a bit more.&lt;/p&gt;
&lt;h1&gt;Core Concepts&lt;/h1&gt;
&lt;h3&gt;Pulumi Programs&lt;/h3&gt;
&lt;p&gt;Pulumi programs are basically any program you written in any supported language of your choice (JavaScript, TypeScript, C#, Python, Go ... ). Pulumi provides SDKs for supported languages and you install the required packages (nuget, npm etc. ) to work with your providers besides the libraries you use for native languages&lt;/p&gt;
&lt;h3&gt;Desired State&lt;/h3&gt;
&lt;p&gt;State is at the core of all this. Pulumi manages the state (in the form of a state file). This is the source of truth for Pulumi. Whenever you make any change in your program, Pulumi refers to that state and check with the resource provider to determine what action needs to be taken (update, delete, add or nothing).&lt;/p&gt;
&lt;h3&gt;Backends&lt;/h3&gt;
&lt;p&gt;Pulumi provide two approaches to manage the state&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Pulumi Service backend (a free hosted service that Pulumi offers. https://pulumi.com )&lt;/li&gt;
&lt;li&gt;A self-managed backend, either stored locally on your filesystem or remotely using a cloud storage service
By default, Pulumi uses it&apos;s hosted service backend. This makes it almost trivial to get started and you have the flexibility to take the control yourself if you wish so.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Language hosts&lt;/h3&gt;
&lt;p&gt;Responsible for running a Pulumi program. Consists of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Language Executor&lt;br /&gt;
a binary that is used to launch the runtime (e.g., pulumi-language-dotnet.exe). Comes with the CLI. I installed Pulumi via Chocolatey so this is the location for this for me: C:\ProgramData\chocolatey\lib\pulumi\tools\Pulumi\bin&lt;/li&gt;
&lt;li&gt;Language Runtime&lt;br /&gt;
Responsible for preparing your program to be executed. The runtime observes the execution of a program and detect resource registrations, communicates the registration request to the deployment engine.
The runtime is distributed as a regular package. Here is the one for &lt;a href=&quot;https://www.nuget.org/packages/Pulumi/2.11.0-x.1600207064&quot;&gt;.NET&lt;/a&gt; on nuget, &lt;a href=&quot;https://www.npmjs.com/package/@pulumi/pulumi&quot;&gt;node&lt;/a&gt; on npm etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Deployment engine&lt;/h3&gt;
&lt;p&gt;The engine is responsible for achieving the desired state you have specified in your Pulumi program. Given the program from language host, it checks the local state, talks to resource providers and take all sorts of decisions to get you to the desired state.
You interact with the engine with the CLI.&lt;/p&gt;
&lt;h3&gt;Stacks&lt;/h3&gt;
&lt;p&gt;A stack is an isolated, independently configurable instance of a Pulumi program. You use them to represent various environments like dev, stage and prod (I use them like this so far). Or you can represent feature branches like feature-x-dev, feature-y-dev.&lt;/p&gt;
&lt;h3&gt;Resource Providers&lt;/h3&gt;
&lt;p&gt;This is how you talk to your target cloud platforms like Azure, AWS and other SaaS platforms. Consists of two parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Resource Plugin
Again, a binary that the deployment engine uses to manage a resource. You can manage plugins using &lt;code&gt;pulumi plugin&lt;/code&gt; from the CLI
You can find these in your user directory (for me it&apos;s at: C:\Users\sanja.pulumi\plugins - I&apos;m on Windows machine)&lt;/li&gt;
&lt;li&gt;SDK
Just like the language runtime, available as packages. These determine the type of resources any provider can manage.
For Azure, you have &lt;a href=&quot;https://www.nuget.org/packages/Pulumi.Azure&quot;&gt;this&lt;/a&gt; nuget package for C#&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Pulumi CLI&lt;/h3&gt;
&lt;p&gt;This is your gateway to the Pulumi world. You interact with Pulumi via CLI for all the operations you want to carry on.&lt;/p&gt;
&lt;h1&gt;Take Pulumi for a ride&lt;/h1&gt;
&lt;p&gt;Now we have got a fair understanding of how Pulumi works and what are various components involved. Let&apos;s change the gears and see it in action.&lt;/p&gt;
&lt;h2&gt;Setting up the environment&lt;/h2&gt;
&lt;p&gt;The first thing we need is to set the environment to work with Pulumi.
Pulumi has a really good &lt;a href=&quot;https://www.pulumi.com/docs/get-started/&quot;&gt;getting started&lt;/a&gt; guide. Here is the one for &lt;a href=&quot;https://www.pulumi.com/docs/get-started/azure/&quot;&gt;Azure&lt;/a&gt; specifically. So please follow the guide and install and configure your environment.
What you should have after the setup is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pulumi CLI Installed&lt;/li&gt;
&lt;li&gt;IDE of your choice (VS Code, VS etc.)&lt;/li&gt;
&lt;li&gt;Azure Subscription&lt;/li&gt;
&lt;li&gt;Pulumi Service Account (for state management) (https://pulumi.com)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am setting the environment on my local Windows 10 machine.
&lt;em&gt;You can install Pulumi CLI in a docker container if you wish.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Hello Pulumi&lt;/h2&gt;
&lt;p&gt;Now having our environment setup, let&apos;s start with the quintessential &lt;strong&gt;Hello world&lt;/strong&gt; application with Pulumi! And what&apos;s the Cloud equivalent of Hello World? Creating a resource group and a storage account - isn&apos;t it 😆 Let&apos;s do it!&lt;/p&gt;
&lt;h3&gt;Create a new project&lt;/h3&gt;
&lt;p&gt;Fire up your terminal and type the following command&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pulumi new
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is an interactive command. You will be asked to choose the template first:
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-new-1.png&quot; alt=&quot;Pick up the template&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next, set the project name, description, stack, location (you can simply enter to set recommended names or change the names).
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-new-2.png&quot; alt=&quot;Other metadata&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Pulumi then goes ahead and initializes the project for you.
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-new-3.png&quot; alt=&quot;Pulumi new Finish&quot; /&gt;&lt;/p&gt;
&lt;p&gt;or you can simply pass the arguments at the time of creation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pulumi new azure-csharp --stack dev --name hello-pulumi --description &quot;Minimal C# Pulumi Program&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s see what Pulumi has created for us.
Enter &lt;code&gt;code .&lt;/code&gt; in your terminal to open up the VS Code.&lt;/p&gt;
&lt;h4&gt;Projects&lt;/h4&gt;
&lt;p&gt;A &lt;em&gt;Pulumi project&lt;/em&gt; is any folder which contains a &lt;strong&gt;Pulumi.yaml&lt;/strong&gt; file. A project specifies which runtime to use, which determines where to look for the program that should be executed during deployments. Supported runtimes are nodejs, python, dotnet, and go.&lt;/p&gt;
&lt;p&gt;This is how my structure looks like:&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-project-1.png&quot; alt=&quot;Pulumi project&quot; /&gt;&lt;/p&gt;
&lt;p&gt;My YAML files looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  name: hello-pulumi
  runtime: dotnet
  description: A minimal Azure C# Pulumi program
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You also get a YAML file with your &apos;Stack&apos; name that contains some configurations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;MyStack.cs&lt;/strong&gt; file is actually the stack that contains our desired state which we want to achieve&lt;br /&gt;
&lt;strong&gt;Program.cs&lt;/strong&gt; file is just an entry point to execute the stacks&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;using Pulumi;
using Pulumi.Azure.Core;
using Pulumi.Azure.Storage;

class MyStack : Stack
{
    public MyStack()
    {
        // Create an Azure Resource Group
        var resourceGroup = new ResourceGroup(&quot;resourceGroup&quot;);

        // Create an Azure Storage Account
        var storageAccount = new Account(&quot;storage&quot;, new AccountArgs
        {
            ResourceGroupName = resourceGroup.Name,
            AccountReplicationType = &quot;LRS&quot;,
            AccountTier = &quot;Standard&quot;
        });

        // Export the connection string for the storage account
        this.ConnectionString = storageAccount.PrimaryConnectionString;
    }

    [Output]
    public Output&amp;lt;string&amp;gt; ConnectionString { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Stacks inherit from &lt;strong&gt;Stack&lt;/strong&gt; class.&lt;br /&gt;
In this program, we have defined a resource group and a storage account in that resource group. And finally we are exporting a connection string property (Output) once the storage account is provisioned. This will be output after the execution of the program.&lt;/p&gt;
&lt;h4&gt;Preview the changes&lt;/h4&gt;
&lt;p&gt;Once you are ready with the program, you can use the preview command&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pulumi preview
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells you what Pulumi is going to do when you actually deploy. This is a really good way to test the impact before actually deploying the program and allows for the faster feedback loop&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-preview.png&quot; alt=&quot;Pulumi preview&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As we discussed already, Pulumi offers a backend service for state management. If you follow the link (View Live) in the console, you will be able to see the state preview on the backend service.&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-state-preview.png&quot; alt=&quot;Pulumi State Preview&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It looks similar to what you already have on your console.&lt;/p&gt;
&lt;p&gt;Let&apos;s deploy the changes now.&lt;/p&gt;
&lt;h4&gt;Deploy the Changes&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;pulumi up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the way, &lt;code&gt;pulumi up&lt;/code&gt; also does &lt;code&gt;preview&lt;/code&gt; before and gives you the opportunity to go ahead of reject the deployment.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-up-1.png&quot; alt=&quot;Pulumi up&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Go ahead and select &apos;yes&apos; and let Pulumi deploy the changes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-up-2.png&quot; alt=&quot;Pulumi up&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, after successful deployment, you have a &apos;View Live&apos; link taking you to the Pulumi backend service and &apos;ConnectionString&apos; of the storage account as output.&lt;/p&gt;
&lt;h4&gt;Reviewing the Changes&lt;/h4&gt;
&lt;p&gt;Now that we have deployed the resource successfully let&apos;s check Pulumi&apos;s state by following the URL&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-up-state.png&quot; alt=&quot;Pulumi up&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now, just move your cursor in Changes windows on Pulumi you will see few buttons appearing on the top right. Click &apos;diff&apos; there. Here you will be able to see the log of what has been created/changed for you compared to the previous state.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-up-state-diff.png&quot; alt=&quot;Pulumi up&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Note, the name of the resource group here. In our Program, we simply specified the name as &apos;resourceGroup&apos;, this is not the real name, this way Pulumi generates a random unique name at the time of execution, that&apos;s why we get the random numbers after our specified name. If you want to specify the name of the resource you want, you will need to specify the &apos;name&apos; property explicitly for that resource.&lt;/p&gt;
&lt;h4&gt;Verify the deployment&lt;/h4&gt;
&lt;p&gt;So far, Pulumi is telling us everything looks great but let&apos;s verify it in Azure. Navigate to Azure Portal and search for the resource group name you noted earlier.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-resource-provisioned.png&quot; alt=&quot;Resource Provisioned&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So, it went fine after all. We have a resource group and a storage account within that resource group. All good&lt;/p&gt;
&lt;h4&gt;Update the program&lt;/h4&gt;
&lt;p&gt;Now, let&apos;s make a quick change by adding a tag in our Storage account resource. Add the following line after &apos;AccountTier&apos; property in your storage account resource.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; Tags = {
          { &quot;Environment&quot;, &quot;Dev&quot; }
        }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Back to your terminal, enter&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pulumi up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we have made a change after deploying the program earlier, Pulumi already has a state of our infrastructure. When you do Pulumi up now, Pulumi will compare the state it has for our stack and will tell you what changes it has detected and going to update.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-up-update-1.png&quot; alt=&quot;Pulumi Update&quot; /&gt;&lt;/p&gt;
&lt;p&gt;select &apos;yes&apos; to deploy the change&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-up-update-3.png&quot; alt=&quot;Pulumi Update&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, Pulumi successfully deployed our change. Follow the Pulumi link to preview the change. Notice, this URL is different to the previous one.
You will be able to see all the updates that have made on your stack on the backend service.&lt;/p&gt;
&lt;p&gt;Head back to the Azure portal and open the storage account again and see that our tag has been applied now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-resource-updated.png&quot; alt=&quot;Resource Updated&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;Destroy&lt;/h4&gt;
&lt;p&gt;If at this stage, you want to delete the state, it&apos;s as simple as executing the following command&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pulumi destroy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By this, we are telling Pulumi to just delete the stack.
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-destroy.png&quot; alt=&quot;Pulumi Destroy&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you head back to the Pulumi backend service and see the &apos;Activity&apos; of your stack (dev) you will be able to see all the changes that you have made to your state
&lt;img src=&quot;https://sanjaybhagia.com/images/pulumi-state-overview.png&quot; alt=&quot;Pulumi state overview&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;We discussed how Pulumi works, what are the core concepts while working with Pulumi. How to set up the environment and write your first Pulumi program. We also looked at the Pulumi&apos;s backend service (a free hosted state management service) to review the changes while you are working with your infrastructure.&lt;/p&gt;
&lt;h1&gt;Signing off&lt;/h1&gt;
&lt;p&gt;I hope this blog post helped you understand the core concepts involved while working with Pulumi and also gave your some idea of how it is to work with Pulumi.
Give it a go, it&apos;s very easy to get started working with Pulumi.
If you have any questions or feedback, feel free to drop the comment.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Pulumi - What and Why?</title><link>https://sanjaybhagia.com/blog/pulumi-what-and-why/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/pulumi-what-and-why/</guid><description>An introduction to Pulumi and why writing infrastructure as code in a real programming language beats DSLs like ARM templates and HCL.</description><pubDate>Thu, 10 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I am learning &lt;a href=&quot;https://www.pulumi.com/&quot;&gt;Pulumi&lt;/a&gt; and I&apos;ll be sharing my journey along the way here in the form of blog posts and code samples on my &lt;a href=&quot;https://github.com/sanjaybhagia/pulumi-examples&quot;&gt;GitHub&lt;/a&gt;. Join me in this journey if this topic interest you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Disclaimer: I have hands-on experience working with Microsoft Azure Cloud platform not so much with others. So in here I&apos;ll be looking at Pulumi from Azure&apos;s lens and most of my references and examples will be with Azure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Context&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Infrastructure_as_code&quot;&gt;Infrastructure as Code (IaC)&lt;/a&gt; is the process of managing and provisioning computer data centres through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools. It&apos;s the practice of treating your infrastructure like you would treat your code. Meaning, you can check in the definition files in a source control system, review it, version it and it produces the same environment every time it is used.&lt;/p&gt;
&lt;p&gt;Infrastructure provisioning predates cloud. We used to provision our on-premises infrastructure before cloud became the thing and there are plenty of tools for that. With cloud comes the opportunity and challenge of managing large scale distributed systems, service based architectures and cloud native applications. If you are building apps on Cloud, you need to have automation and have the ability to quickly span up and tear down the environment in a short amount of time and with confidence. This is where the whole infrastructure as code approach shines. This gives you the superpowers to run any workload in cloud whilst taking advantage of core cloud tenants like speed, elasticity, cost-effectiveness.&lt;/p&gt;
&lt;p&gt;Almost every cloud provider has a way to provision infrastructure. For this, they have their own &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-specific_language&quot;&gt;domain specific language (DSL)&lt;/a&gt; and often written in &lt;a href=&quot;https://en.wikipedia.org/wiki/YAML&quot;&gt;JSON&lt;/a&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/YAML&quot;&gt;YAML&lt;/a&gt; format - called templates. For Azure, its &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/overview&quot;&gt;ARM (Azure Resource Manager)&lt;/a&gt;, for Amazon its &lt;a href=&quot;https://aws.amazon.com/cloudformation/&quot;&gt;CloudFormation&lt;/a&gt;, Google its &lt;a href=&quot;https://web.archive.org/web/20210108202514/https://cloud.google.com/deployment-manager/docs&quot;&gt;Cloud Development Manager&lt;/a&gt; etc. Now they are very powerful in a sense that you can &lt;em&gt;declaratively&lt;/em&gt; provision your complex cloud resources without knowing the details of the underlying workings - the cloud platform takes in your JSON/YAML files and do the magic for you. This has helped the entire Industry a lot in adaption of cloud platforms, irrespective of which platform you are operating on. However, there are certain challenges associated with this.&lt;/p&gt;
&lt;p&gt;With declarative approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You need to know and learn the DSL for each and every cloud platform you are working with or you need to type in YAML files (I know right !),&lt;/li&gt;
&lt;li&gt;You rely on the (not so great) tooling around it&lt;/li&gt;
&lt;li&gt;Templates get very difficult to manage and go out of control very quickly&lt;/li&gt;
&lt;li&gt;Lack of local development loop. You have to actually call-in cloud APIs (actually deploy them) to be sure the templates you have authored are correct and will work.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now take a notch up, let&apos;s say you are going to work across cloud platforms, i.e., &lt;em&gt;n &amp;gt; 1&lt;/em&gt;. We can discuss whether it&apos;s a good idea or not but it&apos;s becoming a reality. Even if your application doesn&apos;t work in multi-cloud scenario but you are most likely using other SaaS applications or services for example, using Cloudflare for managing CDN for your web application running in Azure. This adds further challenges to the list previously mentioned:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You need to write infrastructure in different language for &lt;em&gt;n&lt;/em&gt; number of cloud platforms you are working with&lt;/li&gt;
&lt;li&gt;Each has its own set of associated tools you might need to deal with&lt;/li&gt;
&lt;li&gt;Most likely, your infrastructure code will be placed in different locations not in a single coherent place &lt;em&gt;(not necessarily but likely)&lt;/em&gt;&lt;br /&gt;
etc. etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;...here enters &lt;a href=&quot;https://www.hashicorp.com/products/terraform/&quot;&gt;Terraform&lt;/a&gt; !&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Terraform solved this challenge of dealing with multi-cloud scenario. It&apos;s a very popular tool in IaC space today and I would say almost becoming the &lt;em&gt;de facto&lt;/em&gt; standard when it comes to provisioning infrastructure in cloud these days. It&apos;s &lt;a href=&quot;https://www.terraform.io&quot;&gt;free&lt;/a&gt; and &lt;a href=&quot;https://github.com/hashicorp/terraform&quot;&gt;open source&lt;/a&gt;. However, Terraform introduces another DSL which is called HCL (HashiCorp Configuration Language). It is a declarative language where you define the resources you would like to provision in a cloud platform. It works cross platforms and you need to know only HCL to work against any platform of your choice. There is a great ecosystem and community around Terraform which is great. Even though Terraform is fantastic but now you need to understand yet another language.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;...now we are entering the realm of &lt;a href=&quot;https://www.pulumi.com/&quot;&gt;Pulumi&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Pulumi takes a step further and expands on this problem and provides us a way to really use &lt;em&gt;any&lt;/em&gt; proper programming language of our choice and write the infrastructure provisioning code like we write any other code as developers and operations people.&lt;/p&gt;
&lt;h2&gt;What is Pulumi?&lt;/h2&gt;
&lt;p&gt;What Pulumi brings on the table is you can use the programming language of your choice to write the infrastructure for any cloud - &lt;strong&gt;&quot;Any Code, Any Cloud&quot;&lt;/strong&gt;&lt;br /&gt;
Pulumi is a Modern Infrastructure as Code with which you can create, deploy and manage infrastructure on any cloud using familiar programming languages and tools.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As of this writing, Pulumi supports these programming languages: Go, Python, JavaScript, TypeScript, C#, F# and Visual Basic (.NET Core)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&apos;s also &lt;a href=&quot;https://www.pulumi.com/pricing/#community-edition&quot;&gt;free&lt;/a&gt; and &lt;a href=&quot;https://github.com/pulumi&quot;&gt;open source&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Why Pulumi?&lt;/h2&gt;
&lt;p&gt;By leveraging familiar programming languages for infrastructure as code, Pulumi makes you more productive, and enables sharing and reuse of common patterns. A single delivery workflow across any cloud helps developers and operators work better together.&lt;/p&gt;
&lt;p&gt;Some reasons I think Pulumi is great:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Programming model&lt;/strong&gt; - You can write your infrastructure like you write your code in a programming language and tools of your choice
This is &lt;strong&gt;HUGE&lt;/strong&gt;. Having the flexibility to provision your infrastructure with your preferred programming language is a big productivity boost. On top of that you can bring in the same software development practices and principles like composition, abstraction, testability etc. for your infrastructure and use the favourite tools you are accustomed to, such as IDEs etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Familiar tools&lt;/strong&gt;&lt;br /&gt;
IDEs, refactoring, testing tools, package management etc.
Improves productivity from the get go&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration Management&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testability&lt;/strong&gt;&lt;br /&gt;
With the power of programming language you can actually test your infrastructure like you would for your code. No one is stopping you to bring back the &lt;a href=&quot;https://dhh.dk/2014/tdd-is-dead-long-live-testing.html&quot;&gt;TDD from dead&lt;/a&gt;, if you will ;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster feedback loop&lt;/strong&gt;
With programming language, testability and ability to preview the plans before you actually update/apply your changes comes very handy while writing the infrastructure code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi cloud support&lt;/strong&gt;&lt;br /&gt;
Pulumi allows you to provision resources in multiple clouds and SaaS services. Even though you will be writing separate code for targeting to different clouds (providers) but you can have all of them in a single solution/project at one place. On top of that, you can have your entire end-to-end across clouds and SaaS infrastructure in a single place that you can check in your source code repository in GitHub.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Governance&lt;/strong&gt;&lt;br /&gt;
Besides providing infrastructure as code capabilities, Pulumi has introduced the support for Policy as code. You can write the policies for governance (which could be managed separately by security team, independent of the DevOps team) that can be executed while running Pulumi programs. It&apos;s not tied to cloud vendors (like Azure Policies), rather they are Pulumi specific but that can be run across clouds to enable same set of policies in multi-cloud scenarios.&lt;br /&gt;
Pulumi provides:
&lt;ul&gt;
&lt;li&gt;Policy as code&lt;/li&gt;
&lt;li&gt;Secret Management&lt;/li&gt;
&lt;li&gt;Enforce standards&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adapting existing infrastructure&lt;/strong&gt;
You can bring in your terraform files to Pulumi (they provide a tool for this) or you can adapt existing environment from your already deployed resources in the cloud&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State management&lt;/strong&gt;&lt;br /&gt;
Besides providing the flexibility to completely manage the state ourselves (just like Terraform), Pulumi offers a free app.pulumi.com service that takes control of state management concerns for you.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validating your code before you actually provision the resources&lt;/strong&gt;&lt;br /&gt;
The ability to preview the changes you are making before you actually deploy the code helps in the faster feedback loop when you are writing the code.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Other tools in similar space&lt;/h2&gt;
&lt;p&gt;While looking at Pulumi I came across some other tools in this space that are doing similar things but there are still quite a few differences. I think Pulumi is far ahead of them - at least as of now.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://compositionalit.github.io/farmer/&quot;&gt;Farmer&lt;/a&gt;&lt;br /&gt;
&lt;em&gt;this lets you write the code in F# and generates ARM templates at the end&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hashicorp.com/blog/cdk-for-terraform-enabling-python-and-typescript-support/&quot;&gt;CDK for Terraform&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What do I think about this&lt;/h2&gt;
&lt;p&gt;I am coming from a development background, so don&apos;t consider myself an Ops guy per se but let&apos;s be real. If you are working in cloud, the boundaries are getting blurred faster than we realise. If you are developing, the chances are you will be deploying the applications yourself. And having the mindset of operability of your applications you develop pushes you to build great software. It&apos;s a great learning experience in and of itself.&lt;/p&gt;
&lt;p&gt;I think this space is going to get a lot of traction and will be adapted widely as we can already see the competitors getting into this space (referring to CDK). Even though it seems this is targeted more toward developers than operations people but the platform already support quite popular languages like Python and Go that are widely used in Ops world. Moreover, for Microsoft workloads, since we already have the support for .NET it&apos;s perhaps just a matter of time before PowerShell support is added. Another reason I see is the level of confidence this provides with the whole testability story that Pulumi enables. It allows us the flexibility to try out the infrastructure with confidence right from our local development machines and that only leads to the robust infrastructure. I&apos;m excited about this if you ask me !&lt;/p&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Alright, this was a bit of an introduction to what Pulumi is and why it makes sense to me. As I&apos;m learning more about Pulumi, I&apos;ll be sharing my learnings along the way. Thanks for sticking around.&lt;/p&gt;
&lt;p&gt;Let me know if you have fiddled with Pulumi yet and how do you find it?&lt;/p&gt;
&lt;p&gt;Until next time&lt;br /&gt;
Ciao&lt;/p&gt;
</content:encoded></item><item><title>Passing AZ-220: Microsoft Azure IoT Developer Exam</title><link>https://sanjaybhagia.com/blog/passing-azure-iot-220-exam/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/passing-azure-iot-220-exam/</guid><description>How I prepared for and passed the AZ-220 Azure IoT Developer exam, with study material, labs, online proctoring tips and my impressions.</description><pubDate>Sat, 05 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently passed the &lt;strong&gt;AZ 220: Microsoft Azure IoT Developer&lt;/strong&gt; exam and thought to share my impressions and some reference material that might of use if you are pursuing this exam.&lt;/p&gt;
&lt;h2&gt;The Exam&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Candidates for this exam should have subject matter expertise developing cloud and edge components of an Azure IoT solution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You implement designs for Azure IoT solutions including device topology, connectivity, debugging, and security, as well as solutions to manage, monitor, and transform IoT-related data pipelines. You also deploy Azure IoT Edge components and configure device networking on the edge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This exam is targeted at Developers who will be building IoT solutions using Microsoft services and technologies.&lt;/p&gt;
&lt;p&gt;You can read more about the exam &lt;a href=&quot;https://docs.microsoft.com/en-us/learn/certifications/exams/az-220&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Skills measured&lt;/h2&gt;
&lt;p&gt;Following are the skills you will be measured on. For detailed description, &lt;a href=&quot;https://web.archive.org/web/20230108202921/https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE4nBeC&quot;&gt;check this out&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement the IoT solution infrastructure (15-20%)&lt;/li&gt;
&lt;li&gt;Provision and manage devices (20-25%)&lt;/li&gt;
&lt;li&gt;Implement Edge (15-20%)&lt;/li&gt;
&lt;li&gt;Process and manage data (15-20%)&lt;/li&gt;
&lt;li&gt;Monitor, troubleshoot, and optimize IoT solutions (15-20%)&lt;/li&gt;
&lt;li&gt;Implement security (15-20%)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The exam frequently undergo changes so keep an eye on upcoming changes. You will find this on the exam page&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Study Process&lt;/h2&gt;
&lt;p&gt;The study process varies from person to person, so there is no one approach. This is what I used for this exam.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go through MS Learn Learning Paths and Modules&lt;/li&gt;
&lt;li&gt;Hands-on Labs on GitHub for Azure IoT&lt;/li&gt;
&lt;li&gt;Practice Exam (Mock)&lt;/li&gt;
&lt;li&gt;Go back and cover the gaps&lt;/li&gt;
&lt;li&gt;Repeat&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Services&lt;/h2&gt;
&lt;p&gt;These are some of the Azure services that are relevant for this exam.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Azure IoT Hub&lt;/li&gt;
&lt;li&gt;Device Provisioning Service&lt;/li&gt;
&lt;li&gt;Azure IoT Central&lt;/li&gt;
&lt;li&gt;Azure IoT Edge&lt;/li&gt;
&lt;li&gt;Time Series Insights&lt;/li&gt;
&lt;li&gt;Azure Stream Analytics&lt;/li&gt;
&lt;li&gt;Azure Blob Storage&lt;/li&gt;
&lt;li&gt;Power BI&lt;/li&gt;
&lt;li&gt;Azure Event Hubs&lt;/li&gt;
&lt;li&gt;Azure Service Bus&lt;/li&gt;
&lt;li&gt;Azure Functions / Logic Apps&lt;/li&gt;
&lt;li&gt;Azure Monitor / Log Analytics&lt;/li&gt;
&lt;li&gt;Azure Cosmos DB&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Study Material&lt;/h2&gt;
&lt;p&gt;This is what I used as study material for this exam.&lt;/p&gt;
&lt;h3&gt;Study Notes&lt;/h3&gt;
&lt;p&gt;A good starting point, gives you links to respective sections based on exam structure. Great time saver and you have links to all relevant areas and topics.&lt;/p&gt;
&lt;p&gt;Please check &lt;a href=&quot;https://sanjaybhagia.com/assets/220-studynotes&quot;&gt;this&lt;/a&gt; out.&lt;/p&gt;
&lt;h3&gt;Labs&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20201223224138/https://microsoftlearning.github.io/AZ-220-Microsoft-Azure-IoT-Developer/&quot;&gt;Hands-on labs&lt;/a&gt; related to various topics for Azure IoT that are relevant for the exam.&lt;/p&gt;
&lt;h3&gt;MS Learn&lt;/h3&gt;
&lt;p&gt;There are few &lt;a href=&quot;https://docs.microsoft.com/en-us/learn/browse/?terms=iot&amp;amp;resource_type=learning%20path&quot;&gt;learning paths&lt;/a&gt; on MS Learn that are really good. I started off with these.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/learn/paths/introduction-to-azure-iot/&quot;&gt;Introduction to Azure IoT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/learn/paths/securely-connect-iot-devices/&quot;&gt;Securely connect IoT devices to the cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/learn/paths/build-intelligent-edge-with-azure-iot-edge/&quot;&gt;Build the intelligent edge with Azure IoT Edge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/learn/paths/develop-iot-solutions-with-azure-iot-central/&quot;&gt;Develop IoT solutions with Azure IoT Central&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/learn/paths/implement-data-streaming-with-asa/&quot;&gt;Implement a Data Streaming Solution with Azure Streaming Analytics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/learn/modules/remotely-monitor-devices-with-azure-iot-hub/&quot;&gt;Remotely monitor and control devices with Azure IoT Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/learn/modules/automate-iot-devices-management-with-azure-iot-hub/&quot;&gt;Automate IoT devices management with Azure IoT Hub&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Microsoft Docs&lt;/h3&gt;
&lt;p&gt;Microsoft Docs are an invaluable resource anything Azure. There is tons of great documentation about any area and great in-depth knowledge in there. If you have found Study notes already, most of them will have links to MS Docs for relevant topics anyways.
However, do dig into different topics as you are going through MS Learn paths or doing the labs to solidify the understanding.
Here is the landing page for &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/iot-fundamentals/&quot;&gt;Azure IoT Docs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Courses on A Cloud Guru&lt;/h3&gt;
&lt;p&gt;I came to know about these courses quite late in my preparation so I didn&apos;t use them but they look good and could be a starting point for you, so do check them out.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://acloud.guru/learn/9f9c3d86-77bb-4719-bfa3-c046bc92a880?_ga=2.174232555.893703794.1598229047-690054353.1597628021&quot;&gt;Azure IoT Solution Infrastructure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://acloud.guru/learn/c5836783-9f6e-433e-aed0-589bdabbef0f?_ga=2.204652249.893703794.1598229047-690054353.1597628021&quot;&gt;Provisioning and Managing Devices in Azure IoT &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Skills Assessment&lt;/h2&gt;
&lt;p&gt;As you are studying, fill-in &lt;a href=&quot;https://github.com/Build5Nines/exam-assessments/blob/master/Assessments/Exam-Msft-AZ-220-Self-Assessment-Build5Nines.xlsx&quot;&gt;this spreadsheet&lt;/a&gt;. It&apos;ll give you the overview of where you stand at any given point. You can use to track your progress and work on weak areas as you go about the studies.&lt;/p&gt;
&lt;h2&gt;Exam Experience - From Home&lt;/h2&gt;
&lt;p&gt;Due to COVID, most of us are stuck at our homes and to be honest, going to the physical centre sounds a bit risky at this time. Good thing is we have the possibility to give exams remotely and I&apos;ve been using this for my last few exams.
The overall experience has been positive (except once). So here are some tips:&lt;/p&gt;
&lt;h5&gt;Booking / Scheduling and Re-schedule&lt;/h5&gt;
&lt;p&gt;You can do this on Pearson VUE online. I have noticed, you can reschedule without any extra fees currently so it&apos;s quite flexible in that regards.&lt;/p&gt;
&lt;h5&gt;Set-up&lt;/h5&gt;
&lt;p&gt;Make sure you run the system test before booking online. You need to be sure the system you have is fit for the test. The utility you will be downloading from Pearson&apos;s website will test it for you.&lt;/p&gt;
&lt;h5&gt;Environment&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;One of the requirements is to have a clean space with closed door where no one can enter the room during the exam.&lt;/li&gt;
&lt;li&gt;You will be monitored continuously via webcam&lt;/li&gt;
&lt;li&gt;You won&apos;t be allowed to leave for any reason during the exam&lt;/li&gt;
&lt;li&gt;Make sure you have a comfortable environment where you are giving the exam. Put the heater or fan (depending where you are)&lt;/li&gt;
&lt;li&gt;You can keep water in a transparent glass or bottle&lt;/li&gt;
&lt;li&gt;No phone at arms length. You can keep it far away (you might receive call from proctor during the exam if any issue arises)&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Day of the exam&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Start 15-30 minutes before the exam time so you have enough time to set up&lt;/li&gt;
&lt;li&gt;You will be running the ID check (take a picture of your identity, your space and a selfie) and system check before the exam.&lt;/li&gt;
&lt;li&gt;Then you simply wait for the proctor to start your exam.&lt;/li&gt;
&lt;li&gt;They might call you (via phone or chat) to ask few questions or make some changes&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Exam Tips &amp;amp; Tricks&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Book the exam in advance (4-6) - give yourself a deadline and work toward it&lt;/li&gt;
&lt;li&gt;Practice, Practice, Practice and some more
&lt;ul&gt;
&lt;li&gt;Can&apos;t emphasize it enough. Do the hands-on labs, run the labs and demos. Try out. Explore. Get comfortable with the areas you are targeting.&lt;/li&gt;
&lt;li&gt;It&apos;s of no use to just pass the exam if you don&apos;t have any hands-on knowledge. Even if you haven&apos;t done any real life project and want to learn about any new area, do the labs and get the hands-on experience. There are plenty of resources available for any technology you want to get into. Put some hours in.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Know your Azure IoT
&lt;ul&gt;
&lt;li&gt;Pricing Tiers of IoT Hub&lt;/li&gt;
&lt;li&gt;JSON structure of various components like Digital Twins, Module Twins, Device Deployment etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Clean your resources once you are done with the labs (to save cost)&lt;/li&gt;
&lt;li&gt;MS Learn modules provide you the Sandbox environment - use them as it&apos;ll save you cost&lt;/li&gt;
&lt;li&gt;Some resources are bit more expensive than others i.e., Azure Time Series Insights (make sure you delete them after you are done)&lt;/li&gt;
&lt;li&gt;Take notes&lt;br /&gt;
When you are reading documentation or watching video content, take notes along the way. This will be helpful when you want to revise before the exam. You will save plenty of time with these notes.&lt;/li&gt;
&lt;li&gt;Mix it a bit
Studying for the exam can get boring, so make sure you mix it up a bit.
If you are reading, add in bunch of videos along the way so you are consuming a mixed content during your preparation. You will loose the focus and end-up wasting a lot of time. Mix up various types of contents and hands-on on regular basis&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;My Exam and Impressions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I got 57 questions in my exam
&lt;ul&gt;
&lt;li&gt;42 questions (multiple choice types - radio / check boxes / drag &amp;amp; drop etc.)&lt;/li&gt;
&lt;li&gt;Set of questions (5 - can’t go back to review)&lt;/li&gt;
&lt;li&gt;2 case studies (5 questions each)&lt;/li&gt;
&lt;li&gt;power&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Time was not an issue. You get ~3 hours for this exam and even though there were quite a lot of questions but I easily managed the time&lt;/li&gt;
&lt;li&gt;For me case studies were at the end which I find good since you end up spending quite a bit of time on case studies and I find them better to have toward the end (unlike other exams which started with a case study)&lt;/li&gt;
&lt;li&gt;I can&apos;t list the exact questions I received but there were quite a number of questions with Azure CLI commands, IoT Edge and around security.&lt;/li&gt;
&lt;li&gt;What helped me solidify the knowledge was doing hands-on (the labs that I have listed above and MS Learn modules), I did the more than once. Also for each services (like IoT Hub, IoT Central, Device Provisioning service),familiarize yourself in the Azure Portal. Just just checkout various options you have for these services.&lt;/li&gt;
&lt;li&gt;Since I needed to provision resource a number of time (saving cost etc.), I tried to provision them from Portal, Azure CLI, Cloud Shell to just get the feel of different approaches)&lt;/li&gt;
&lt;li&gt;I didn&apos;t spend too much time on PowerShell though.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hope you find this guide helpful and wish you all the best.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Capture your favourite quotes from physical books - Part 2</title><link>https://sanjaybhagia.com/blog/capture-quotes-from-books-2/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/capture-quotes-from-books-2/</guid><description>Part 2: Writing an Azure Function that appends OCR-detected quotes from the Logic App to a text file in blob storage.</description><pubDate>Tue, 25 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a two part series blogpost:&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/08/24/capture-quotes-from-books&quot;&gt;Part 1: Setting up the logic app to retrieve text from an image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/08/25/capture-quotes-from-books-2&quot;&gt;Part 2: Pushing the detected text to a text file in blob storage (this)&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my previous blogpost, we created the logic app where we could upload a picture to a folder in OneDrive and Computer Vision API detected the text from that image. Please read through that &lt;a href=&quot;capture-quotes-from-books&quot;&gt;post&lt;/a&gt;  if you haven&apos;t already before continuing this one. Let&apos;s take it a bit further in this blogpost.&lt;/p&gt;
&lt;h2&gt;Save detected text to a text file&lt;/h2&gt;
&lt;p&gt;Currently, there is no action for &apos;Append&apos; operation on blob storage. This is bit of a bummer if you ask me! So we need to write a bit of a code to achieve this. I know I said, I want this to be easy but such is life, you got to to write some code somewhere you didn&apos;t anticipate.
I&apos;m going to pick up the Azure Function with C#, you can use whatever language you are comfortable with.&lt;/p&gt;
&lt;h2&gt;Create Azure Function app&lt;/h2&gt;
&lt;p&gt;You can pick any IDE you prefer, I&apos;m going to work with Visual Studio (VSCode is amazing as well, if you prefer that)&lt;/p&gt;
&lt;p&gt;I won&apos;t go into detail of how create and publish functions as it has already been written about. You can follow this &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-develop-vs&quot;&gt;link&lt;/a&gt; to create Azure Functions and Publish them to Azure. If you prefer VS Code check &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-vs-code?pivots=programming-language-csharp&quot;&gt;this&lt;/a&gt; out.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Once you have created the Functions project, Delete the &apos;Function1.cs&apos; file and add a new Function (Right Click Project -&amp;gt; Add -&amp;gt; New azure function -&amp;gt; Select &apos;Azure Function&apos; and name it AddQuotetoFile)&lt;/li&gt;
&lt;li&gt;Select &apos;Http trigger&apos; and press &apos;OK&apos;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Moving on to the actual code. Here are some details:&lt;br /&gt;
The Function expects the following payload (request)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;blobName&quot;: &quot;testfile.txt&quot;,
    &quot;containerName&quot;: &quot;ocr-images&quot;,
    &quot;text&quot;: &quot;Here is the quote from the book&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;blobName&lt;/strong&gt;: the name of the blob that we need to append the text to (if it - doesn&apos;t exist already, it&apos;ll be created the first time)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;containerName&lt;/strong&gt;: the blob storage container where the file should exist&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;text&lt;/strong&gt;: the actual text we want to write to the file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this function, when it&apos;s triggered, we want to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Parse the HTTP request body&lt;/li&gt;
&lt;li&gt;Make sure we have all the information we need&lt;/li&gt;
&lt;li&gt;Grab reference to the blob container (create if it doesn&apos;t exist)&lt;/li&gt;
&lt;li&gt;Grab reference to the blob (create if it doesn&apos;t exist)&lt;/li&gt;
&lt;li&gt;Append the text at the end of the file&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is how my main function looks like. Please check out my &lt;a href=&quot;https://github.com/sanjaybhagia/capture-quotes-books&quot;&gt;GitHub repository&lt;/a&gt; for the entire solution.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static class AddQuotetoFile
    {
        [FunctionName(&quot;AddQuotetoFile&quot;)]
        public static async Task&amp;lt;IActionResult&amp;gt; Run(
            [HttpTrigger(AuthorizationLevel.Function,&quot;post&quot;, Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation(&quot;C# HTTP trigger function processed a request.&quot;);

            // Expects JSON body:
            // {
            //      &quot;blobName&quot;: &quot;[Blob name here]&quot;,
            //      &quot;containerName&quot;: &quot;[Container name here]&quot;,
            //      &quot;text&quot;: &quot;\&quot;Column A\&quot;,&quot;Column B\&quot;,\\n,\&quot;A1\&quot;,\&quot;B1\&quot;,\\n,\&quot;A2\&quot;,\&quot;B2\&quot;&quot;
            // }

            var connectionString = System.Environment.GetEnvironmentVariable(&quot;StorageConnectionString&quot;);

            // StorageConnectionString configured as app setting.

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);

            var blobName = data?.blobName;
            var containerName = data?.containerName;
            var text = data?.text;

            if (blobName == null)
            {
                return new BadRequestObjectResult(&quot;blobName is required.&quot;);
            }

            if (containerName == null)
            {
                return new BadRequestObjectResult(&quot;containerName is required.&quot;);
            }

            if (text == null)
            {
                return new BadRequestObjectResult(&quot;text is required.&quot;);
            }

            var storageAccount = CloudStorageAccount.Parse(connectionString);
            var blobClient = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference(containerName.ToString());

            await container.CreateIfNotExistsAsync();

            
            var appendBlob = container.GetAppendBlobReference(blobName.ToString());

            if ((await appendBlob.ExistsAsync()) == false)
            {
                await appendBlob.CreateOrReplaceAsync();
            }

            StringBuilder lineToAdd = new StringBuilder();
            lineToAdd.AppendLine(text.ToString());
            await appendBlob.AppendTextAsync(lineToAdd.ToString());

            return new OkResult();
        }
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice in the code snippet, we are referencing &apos;StorageConnectionString&apos; environment variable. This is the connection string of a storage account where the file is being created/appended. For this, we need to create a storage account.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Head over to the portal&lt;/li&gt;
&lt;li&gt;Create a resource for Storage Account
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-storageaccount-create.png&quot; alt=&quot;StorageAccountCreate&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Press &apos;Review + create&apos; to create the account&lt;/li&gt;
&lt;li&gt;Head over to the resource once it&apos;s created&lt;/li&gt;
&lt;li&gt;Select &apos;Access keys&apos; under Settings&lt;/li&gt;
&lt;li&gt;Copy the Key1 connection string&lt;/li&gt;
&lt;li&gt;Back to Visual Studio, open your &apos;local.settings.json&apos; file and set a property &apos;StorageConnectionString&apos; under Values&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;IsEncrypted&quot;: false,
  &quot;Values&quot;: {
    &quot;AzureWebJobsStorage&quot;: &quot;UseDevelopmentStorage=true&quot;,
    &quot;FUNCTIONS_WORKER_RUNTIME&quot;: &quot;dotnet&quot;,
    &quot;StorageConnectionString&quot;: &quot;&amp;lt;your connection string goes here&amp;gt;&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Make sure the you can Build the function correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, if you want to test the function locally, hit F5 to debug the solution, you can make a HTTP request via Postman (or any other tools) to ensure the function is working as expected. Drop a file in a container in the storage account you created and construct the HTTP request and hit your local function endpoint (you can use simulator to pick the file from instead of using Storage Account in Azure, if you have it setup).&lt;/p&gt;
&lt;p&gt;Once you have established the function works correctly, it&apos;s time to publish the function.
We all know &lt;em&gt;&quot;&lt;strong&gt;Friends don&apos;t let friend right-click and publish&lt;/strong&gt;&quot;&lt;/em&gt; - but it&apos;s OK for this demonstration, so don&apos;t feel bad and go ahead - yes Right click the solution and hit Publish. Follow the links that I mentioned earlier (&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-develop-vs&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-vs-code?pivots=programming-language-csharp&quot;&gt;here&lt;/a&gt;) for the instructions on how to run locally and publish from Visual Studio and Visual Studio Code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Once the publishing is successful, we would like to add the application setting.&lt;/li&gt;
&lt;li&gt;Navigate to the Azure portal and open the function app resource that we just published&lt;/li&gt;
&lt;li&gt;Head over to &apos;Configuration&apos; under Settings&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-functionsapp-add-settings.png&quot; alt=&quot;FunctionAppAdSettings&quot; /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Add a new application setting
&lt;ul&gt;
&lt;li&gt;Name: StorageConnectionString&lt;/li&gt;
&lt;li&gt;Value: &quot;the connection string of storage account you put in local.settings.json file earlier&quot;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-functionsapp-add-settings-done.png&quot; alt=&quot;FunctionAppAdSettingsDone&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Make sure to click save to persist the setting, otherwise you will loose it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we are ready with the setup. You can test this at point via Postman as you did earlier. The only change would be to pick up the URL of the function from Azure instead of localhost. Still in your Function in the Portal -&amp;gt; Select &apos;Functions&apos; -&amp;gt; Select your function (&apos;AddQuotetoFile) -&amp;gt; click on &apos;Get Function Url&apos; and copy the URL.&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-function-url.png&quot; alt=&quot;FunctionUrl&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Update the logic app to trigger Azure Function&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Head over to the Azure Portal, Navigate to the Logic App we created in &lt;a href=&quot;capture-quotes-from-books&quot;&gt;Part 1&lt;/a&gt;. Select &apos;Logic app designer&apos; under &apos;Development tools&apos;&lt;/li&gt;
&lt;li&gt;Click &apos;+ New step&apos; to add an action&lt;/li&gt;
&lt;li&gt;Search &apos;Compose&apos; -&amp;gt; Select &apos;Data Operations&apos; and then &apos;Compose&apos; action.&lt;/li&gt;
&lt;li&gt;Under Inputs, add this JSON&lt;pre&gt;&lt;code&gt;{
  &quot;blobName&quot;: &quot;quotes.txt&quot;,
  &quot;containerName&quot;: &quot;quotescontainer&quot;,
  &quot;text&quot;: @{body(&apos;Optical_Character_Recognition_(OCR)_to_Text&apos;)?[&apos;text&apos;]}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-compose-action.png&quot; alt=&quot;ComposeAction&quot; /&gt;&lt;br /&gt;&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-compose-action-input.png&quot; alt=&quot;ComposeAction&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Add another action&lt;/li&gt;
&lt;li&gt;Search for &apos;Azure Functions&apos; -&amp;gt; Select &apos;Azure Functions&apos; and then &apos;AppendQuoteToFile&apos; action&lt;/li&gt;
&lt;li&gt;Set &apos;Request Body&apos; to compose outputs&lt;br /&gt;&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-function-action.png&quot; alt=&quot;FunctionAction&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Save the Logic App&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are almost done, time to test it out now.
Upload another image in your OneDrive folder &apos;ocr-images&apos; and watch the run history again.
Here is my successful run:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-run-stage2.png&quot; alt=&quot;Stage2Run&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-run-stage2-2.png&quot; alt=&quot;Stage2Run-2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s open up the storage account to see if the text was written successfully.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select the storage account -&amp;gt; Containers -&amp;gt; quotescontainer&lt;/li&gt;
&lt;li&gt;click on the file &apos;quotes.txt&apos; (notice the Blob type is &apos;Append blob&apos;)&lt;/li&gt;
&lt;li&gt;From the pop-up press &apos;Download&apos; and open it in any editor and inspect the contents
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-storage-file-open.png&quot; alt=&quot;result-1&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I uploaded yet another file in my OneDrive. Download the quotes.txt file again and look at the contents. You will see another line has been appended.
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-storage-file-open-2.png&quot; alt=&quot;result-2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here are all the resources we ended up creating for this solution
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-resources.png&quot; alt=&quot;resources&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We are finally done! Now when you take a picture of any quote and upload it to your OneDrive, Logic app will be triggered and appends the quote into a text file in your blob storage.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In case you followed along and provisioned the resources and  you don&apos;t intend to use the solution, you can delete the resource group here.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This turned out to be a much longer blogpost than I anticipated, so thanks for tagging along.&lt;br /&gt;
Let me know if you found this useful and if you have any suggestions to improve this further.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Capture your favourite quotes from physical books</title><link>https://sanjaybhagia.com/blog/capture-quotes-from-books/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/capture-quotes-from-books/</guid><description>Building an Azure Logic App that picks up book photos from OneDrive and extracts the quotes with the Computer Vision OCR API.</description><pubDate>Mon, 24 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a two part series blogpost:&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/08/24/capture-quotes-from-books&quot;&gt;Part 1: Setting up the logic app to retrieve text from an image (this)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sanjaybhagia.com/2020/08/25/capture-quotes-from-books-2&quot;&gt;Part 2: Pushing the detected text to a text file in blob storage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I like reading books. Though I love technology but certain books are best suited for physical form and I&apos;m quite open about it - whatever works. One of the good things about digital books is they make it quite trivial to highlight or take notes of our favourite quotes or sections. When it comes to physical books, there are all kind of (manual) techniques you can use to take notes. While underlying few quotes in a book I was reading the other day, I thought wouldn&apos;t it be nice if I take a picture and the quote is written to a text file somewhere as a collection for me which I can refer to later on? Of course, I didn&apos;t just put down the book right away since I was enjoying it so I carried on - I know not so easy to do.&lt;/p&gt;
&lt;p&gt;Once done with the reading, I set out to create a solution for this. I work with Microsoft Azure in my day to day job so it was an obvious choice for me. I went about picking up the services that could help me easily put different pieces together to solve the challenge at hand.&lt;/p&gt;
&lt;p&gt;This is what I came up with.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/capturequotes.drawio.png&quot; alt=&quot;architecture diagram&quot; title=&quot;Archietcture Diagram&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So the flow is:&lt;/strong&gt; I will take a picture of any quote with my phone, upload it to a certain folder in my OneDrive. The Logic app gets triggered if there is a new file in that folder, reads the contents of the file, passes that image to the Cognitive API (OCR to Text) that returns the detected text, we then call an azure function that appends the quote to a text file in my blob storage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rationale&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OneDrive (Personal): I already use it, it&apos;s my private drive, have secured access from anywhere and from my device&lt;/li&gt;
&lt;li&gt;Logic Apps: Helps me orchestrate the flow without writing much code and I can use built-in connectors to access OneDrive, Cognitive services, blob storage etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-au/azure/cognitive-services/computer-vision/&quot;&gt;Computer Vision API&lt;/a&gt;: Makes it almost trivial to detect text from the images and works quite well with Logic Apps&lt;/li&gt;
&lt;li&gt;Azure Functions: Though I shouldn&apos;t have used this but this is to append the text in blob storage since there is no built-in connector for this currently.&lt;/li&gt;
&lt;li&gt;Blob Storage: I could potentially store this file anywhere else but storage account is quite handy in this scenario (supports append blobs natively).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the high level architecture in place, let&apos;s dig into the implementation.&lt;/p&gt;
&lt;h2&gt;Create Logic App&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Head over to the Azure Portal and create a logic app.&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-create-logicapp.png&quot; alt=&quot;CreateLogicApp&quot; /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Once the resource is created, go to that resource.&lt;/li&gt;
&lt;li&gt;Select &apos;Blank Logic App&apos; from templates&lt;/li&gt;
&lt;li&gt;Search for &apos;OneDrive&apos; connector and select &apos;When a file is created&apos; from Triggers&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-onedrive-filecreated.png&quot; alt=&quot;FileCreated&quot; /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Sign in to your OneDrive account and select the folder where you will be placing your images from mobile.
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-onedrive-signin.png&quot; alt=&quot;OneDriveSignIn&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Set the frequency at which you want OneDrive connector to look for new files (during development, select smaller window and when you are ready to use it, increase it so you don&apos;t end-up polling OneDrive too often)
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-onedrive-setfrequency.png&quot; alt=&quot;OneDriveSetFrequency&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Click &apos;New Step&apos; to add the next action.&lt;/li&gt;
&lt;li&gt;Search for &apos;Cognitive&apos; and select &apos;Computer Vision API&apos; and then search for &apos;ocr&apos;.&lt;/li&gt;
&lt;li&gt;Select &apos;Optical Character Recognition (OCR) to Text&apos; from the list&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-computervision-ocr-text.png&quot; alt=&quot;ComputerVisionOcr&quot; /&gt;&lt;/li&gt;
&lt;li&gt;To fill this information we need a Computer vision resource.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create Computer Vision resource&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Open another tab/window and go to Azure Portal (portal.azure.com)&lt;/li&gt;
&lt;li&gt;Create a new resource of type &apos;Computer Vision&apos;. Select &apos;F0&apos; pricing tier (it&apos;s free - though you can have only one free resource in a subscription)
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-computervision-create.png&quot; alt=&quot;ComputerVisionCreateResource&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Once the resource is created, navigate to that resource (by selecting &apos;Go to resource&apos; or search for it from the search bar at the top)&lt;/li&gt;
&lt;li&gt;Head over to &apos;Keys and Endpoint&apos; under &apos;Resource  Management&apos; section&lt;/li&gt;
&lt;li&gt;Copy &apos;Key1&apos; and &apos;Endpoint&apos; (in notepad or anywhere else you prefer)
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-computervision-keys.png&quot; alt=&quot;ComputerVisionKeys&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Update Logic App with Computer Vision Action&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Head back to the Logic App now&lt;/li&gt;
&lt;li&gt;Enter connection name &apos;computervisionconnection&apos;&lt;/li&gt;
&lt;li&gt;Enter value of &apos;Key1&apos; from computer vision API in &apos;Account Key&apos; field&lt;/li&gt;
&lt;li&gt;Set &apos;Site Url&apos; to the &apos;Endpoint&apos; you coped from computer vision&lt;/li&gt;
&lt;li&gt;Click &apos;Create&apos; button to create the connection&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-computervision-connection.png&quot; alt=&quot;ComputerVisionConnection&quot; /&gt;&lt;/li&gt;
&lt;li&gt;For &apos;Image Source&apos; - select &apos;Image Content&apos; from the dropdown.&lt;/li&gt;
&lt;li&gt;For &apos;Image Content&apos; - set it to File Content from previous step (by selecting the dynamic content. Put a cursor in - Image Content field and a pop up will show up, select the value from there) &lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-computervision-action-setcontent.png&quot; alt=&quot;ComputerVisionActionSetContent&quot; /&gt;&lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-computervision-action.png&quot; alt=&quot;ComputerVisionAction&quot; /&gt;&lt;/li&gt;
&lt;li&gt;This is how the logic app looks so far &lt;br /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-logicapp-stagei.png&quot; alt=&quot;LogicAppStageI&quot; /&gt;&lt;/li&gt;
&lt;li&gt;At this point, we have a logic app that will be triggered if there is a new file in OneDrive under &apos;/ocr-images&apos; folder and the text is translated using Computer Vision API. It&apos;s time to test&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Test the app&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Save the app. Upload a picture of some text in your folder in OneDrive. Check the run history of the logic app and select the last run.&lt;/li&gt;
&lt;li&gt;I have uploaded this picture
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-test-pic-1.jpg&quot; alt=&quot;TestPicture1&quot; /&gt;&lt;/li&gt;
&lt;li&gt;Here is how it looks for me.
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-logicapp-runhistory.png&quot; alt=&quot;LogicAppRunHistory&quot; /&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/translate-quotes-logicapp-stagei-success.png&quot; alt=&quot;LogicAppRunHistory&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check the text in &apos;Body&apos; and you will see that it matches the text we had in the image. That&apos;s pretty rad, isn&apos;t it?&lt;/p&gt;
&lt;p&gt;We are pretty much done here. But I would like to take this further. I would like the text to be stored in a text file that sits in my blob storage. I want the text to be appended every time the logic app runs so I have my quotes in one file on new line. This will be covered in part II of the series, so stay tuned.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Migrating from WordPress to Wyam</title><link>https://sanjaybhagia.com/blog/migrating-blog-from-wordpress-to-wyam/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/migrating-blog-from-wordpress-to-wyam/</guid><description>Notes on moving my blog from WordPress to the Wyam static site generator, hosted on Netlify with an Azure DevOps pipeline for deployment.</description><pubDate>Sat, 05 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I had been hosting my blog on SiteGround for a number of years now. It&apos;s been good so far, no complaints but I had been wanting to try out the static content generation engines for a while. One major reason for this is that my content is mostly static and don&apos;t really require a server side for anything as such (ok, few things but nothing that can&apos;t be achieved on client-side).&lt;/p&gt;
&lt;p&gt;I had looked at few options in the past but never really set out to do this. What pushed me to make this move was that, during last month, I got an email that some malicious code has been detected on my website! SiteGround did a really good job to make my website &lt;em&gt;unavailable&lt;/em&gt; and notified me so that I could investigate, clean it up and put it back. It was a fairly smooth process but it got me thinking, this shouldn&apos;t have happened at first place. I don&apos;t really need the overhead of dealing with server side code at all. I could have drastically reduced the attack surface just by serving the static content. So, this was the tipping point for me.&lt;/p&gt;
&lt;p&gt;I have been following static content generation solutions and was aware of this space and few options like Jekyll &amp;amp; Wyam etc. I decided to go with Wyam for now (&lt;em&gt;it&apos;s built on top of .NET Core&lt;/em&gt;) but any other engine will do. My motivation to go with Wyam was influenced by a number of people I follow in the tech community and the fact it&apos;s running on .NET which, for me, is good opportunity to understand and learn how things are working behind the scenes to make such application work.&lt;/p&gt;
&lt;h3&gt;This is how my migration process looked like:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Installed &lt;a href=&quot;https://wordpress.org/plugins/jekyll-exporter/&quot;&gt;Jekyll Exporter&lt;/a&gt; plugin on my wordpress site and exported the content in markdown format&lt;/li&gt;
&lt;li&gt;Pretty much followed &lt;a href=&quot;https://erikonarheim.com/posts/using-wyam-blog&quot;&gt;this blog&lt;/a&gt; to do the heavy lifting, so won&apos;t repeat myself again as it has already been written quite a lot. Here is &lt;a href=&quot;https://salvoz.com/posts/2018-01-01-static-content.html&quot;&gt;another good blogpost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Some decisions that I made though:
&lt;ul&gt;
&lt;li&gt;Went with CleanBlog theme but made some changes (css, fonts etc.) to suit the design I liked.&lt;/li&gt;
&lt;li&gt;The exported content is not really proper markdown but I am OK with it. It would have taken significant effort to clean it up otherwise.&lt;/li&gt;
&lt;li&gt;Decided to put images along with the content for now. I will look further if there is any better approach like hosting images into Azure Blob storage.&lt;/li&gt;
&lt;li&gt;Even though I had disqus comment system enabled on my wordpress, I encountered a bit of a trouble getting it right because the out-of-the-box wyam URLs were different than my previous and during testing I ended up creating different disqus threads for my posts and it messed it up. I needed to remove those threads from disqus to be able to re-use with my previous URLs. You can read more about this &lt;a href=&quot;https://mycyberuniverse.com/how-delete-discussion-threads-incorrect-url-disqus.html&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Configured the URLs to be same as my previous URLs (includes day in the post path besides the default year and month). I found this way simpler rather than doing the redirections etc.&lt;/li&gt;
&lt;li&gt;Added support for Google Analytics (&lt;em&gt;might get rid of this going forward with some other solutions but good for now&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Release Management:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;I have hosted the source code (aka, markdown pages and assets) on GitHub&lt;/li&gt;
&lt;li&gt;Setup &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; account to host the site (I could have hosted it directly on GitHub but wanted to try out Netlify as I was hearing so many good things about it lately,rightfully so. It was a delightful experience with Netlify.)&lt;/li&gt;
&lt;li&gt;I setup Azure DevOps pipeline (via yml) to push the content to Netlify&lt;/li&gt;
&lt;li&gt;I found this a lot easier and simpler without going to any other approach (Cake or PS). I&apos;m tempted to use &lt;a href=&quot;https://github.com/features/actions&quot;&gt;Github Actions&lt;/a&gt; for this part however.&lt;/li&gt;
&lt;li&gt;Whenever I push anything into my &apos;&lt;em&gt;master&lt;/em&gt;&apos; branch, the pipeline is triggered and content is pushed over to Netlify.
&lt;ul&gt;
&lt;li&gt;One nice thing about Netlify is that, it allows you to preview your changes before you want to Publish it, which is nice (there are other options to create proper staging environment etc. but for me this was sufficient)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Here is my new tech stack:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wyam.io/&quot;&gt;Wyam&lt;/a&gt; - Static Content Generator&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.github.com/&quot;&gt;GitHub&lt;/a&gt; - hosting the content&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; - hosting the blog&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cloudflare.com/&quot;&gt;Cloudflare&lt;/a&gt; - Caching, DNS and Certificate management (via Lets Encrypt)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.azure.com/&quot;&gt;Azure DevOps&lt;/a&gt; - CI/CD&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://analytics.google.com&quot;&gt;Google Analytics&lt;/a&gt; - Traffic Analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&apos;s about it. With this setup, After pushing everything I redirected my domain from SiteGround to Netlify site (from cloudflare) and bam new blog is alive!&lt;/p&gt;
&lt;p&gt;Now, I want to list some things that I like, did not like and what I will add / improve going forward.&lt;/p&gt;
&lt;h4&gt;Things I like:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;The entire blog is served as static resource (html, images, css etc.), nothing is running server side (as of now at least)&lt;/li&gt;
&lt;li&gt;Wyam is pretty awesome and seem to work really well. I do look forward to learning more about this.&lt;/li&gt;
&lt;li&gt;I am able to write my posts totally in markdown on my local machine (without any internet connectivity with amazing VSCode)&lt;/li&gt;
&lt;li&gt;Site is much faster!&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Things I am &lt;em&gt;less&lt;/em&gt; satisfied with:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Wordpress took care of a lot of things out-of-the-box for me such as search, image compression, contact form and various other plugins (pretty for any need you can think of) and I will have to add a number of these features to my site which I find important. But I was fully aware of these trade-offs.&lt;/li&gt;
&lt;li&gt;I don&apos;t understand Wyam 100% yet as there is some learning curve and Wyam&apos;s own tooling (no intellisense for example) makes it a bit difficult to compose config file.&lt;/li&gt;
&lt;li&gt;I need to think of image compression or use better solution to reduce the size of served content.&lt;/li&gt;
&lt;li&gt;Had some issues with setting up Images compression with Wyam (apparently there are some issues around this)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Things I will add/improve going forward:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Add Search capability on my site as I think it&apos;s very important feature (and one that I use quite often no matter where I&apos;m as a user)&lt;/li&gt;
&lt;li&gt;Better support for serving smaller images (or even replace the ones that I already have with smaller size)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Contact form&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Might replace Disqus with GitHub issues (found out this &lt;a href=&quot;https://utteranc.es/&quot;&gt;Utterance&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another thing I found interesting is site performance. Up until now, I didn&apos;t pay much attention to this aspect since it&apos;s not a heavy site but as I recently moved to Australia, I started noticing how slow internet speed affects your mood :wink:, I decided to improve this aspect of my site. By following the approach for my new blog (without doing much optimization, I already gained a huge improvement), see it yourself:&lt;/p&gt;
&lt;p&gt;This is my site on wordpress earlier (see both mobile and desktop speeds):&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://sanjaybhagia.com/images/old-mobile.png&quot; /&gt;
  &lt;img src=&quot;https://sanjaybhagia.com/images/old-desktop.png&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;And here is my new blog (again, mobile vs desktop):&lt;/p&gt;
&lt;p&gt;
  &lt;img src=&quot;https://sanjaybhagia.com/images/new-mobile.png&quot; /&gt;
  &lt;img src=&quot;https://sanjaybhagia.com/images/new-desktop.png&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;That&apos;s quite impressive already!!. I have yet to optimize images (which should push me even further). I can make some optimizations in time to improve it even further. I used &lt;a href=&quot;https://developers.google.com/speed/pagespeed/insights/&quot;&gt;Google&apos;s PageSpeed Insights&lt;/a&gt; to measure this.&lt;/p&gt;
&lt;p&gt;That&apos;s it for now. I will keep posting my learnings and finding as I go along.&lt;/p&gt;
&lt;p&gt;Feel free to drop any suggestions if you have been the same path already, I would very much appreciate that.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Microsoft OpenHack DevOps - Stockholm</title><link>https://sanjaybhagia.com/blog/microsoft-openhack-devops-stockholm/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/microsoft-openhack-devops-stockholm/</guid><description>My experience at Microsoft&apos;s three-day OpenHack DevOps hackathon in Stockholm, solving Azure DevOps and Kubernetes challenges hands-on.</description><pubDate>Mon, 11 Feb 2019 00:00:00 GMT</pubDate><content:encoded>
&lt;p&gt;Last week I participated in OpenHack DevOps organized by Microsoft in Stockholm. It was a three day event from 5th - 7th February 2019. The hackathon was focused on Azure DevOps. The format of the event was of-course like a hackathon. &lt;/p&gt;


&lt;p&gt;Participants were divided into teams (4-6 each). The content was set as challenges (total 9). Every team (or two) had a coach - someone from Microsoft - who was helping and guiding during the challenges. We, as teams, were supposed to find our way out to solve the challenges. There was no one way, we were free to take our decisions and paths as deemed fit.&lt;/p&gt;


&lt;p&gt;Here is the schedule and agenda for the event if you are curious: &lt;a href=&quot;https://www.microsoftevents.com/profile/form/index.cfm?PKformID=0x5473274abcd&quot; target=&quot;_blank&quot;&gt;Microsoft OpenHack DevOps&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;What I really liked about this event was that we were focused on a task at hand. It was a hands-on rather than attending any tech talk about a specific topic. The tasks were set, challenges were well organized, the environment was prepared, code was almost prepared (with some changes) so that we can focus on learning how we can use Azure DevOps as a tool to ensure zero down-time for production ready application. Kubernetes was chosen as an orchestration framework.&lt;/p&gt;


&lt;figure&gt;&lt;blockquote&gt;&lt;p&gt; Microsoft OpenHack is a developer focused event where a wide variety of participants (Open) learn through hands-on experimentation (Hack) using challenges based on real-world customer engagements designed to mimic the developer journey. &lt;/p&gt;&lt;/blockquote&gt;&lt;/figure&gt;


&lt;p&gt;For every challenge the links to documentation and resources were provided to understand relevant topics and areas at hand.&lt;/p&gt;


&lt;p&gt;Besides the actual work, it was a great opportunity to network and discuss broader topics with fellow participants and Microsoft employees. They also had what they called the &lt;strong&gt;envisioning &lt;/strong&gt;sessions which were basically to discuss with Microsoft guys one-on-one the challenges one is facing at his or her work.&lt;/p&gt;


&lt;p&gt;Overall, I think it was a great learning experience with great focus on getting things done. I will definitely keep an eye on such events in the future. By the way, if you happen to be in Stockholm in April there is an upcoming &lt;a href=&quot;https://www.microsoft.com/sv-se/ignite-the-tour/stockholm&quot; target=&quot;_blank&quot;&gt;Microsoft Ignite Tour&lt;/a&gt; that you must checkout.&lt;/p&gt;


&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Using Postman for Integration Tests</title><link>https://sanjaybhagia.com/blog/using-postman-for-integration-tests/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/using-postman-for-integration-tests/</guid><description>How I use Postman collections, tests and environment variables to run integration tests against my APIs before every release.</description><pubDate>Tue, 11 Dec 2018 00:00:00 GMT</pubDate><content:encoded>
&lt;p&gt;In my recent project, I&apos;m providing some integration services (APIs) that are used by the web application to fetch data from source systems. This is a legacy project that I inherited. To be honest, this was a PoC and we all know how PoCs are developed and very often continue to be used in production. That is why I have been rewriting/refactoring this codebase (&lt;a href=&quot;https://twitter.com/bhagiasanjay/status/1054740627978641410&quot;&gt;I even tweeted about this a while ago&lt;/a&gt;) in every sprint to improve the code quality and cleaning up a lot of code. Since I don&apos;t have a proper code coverage for all the source code, I&apos;m always concerned when I&apos;m continuously developing and refactoring this codebase. I&apos;m often concerned (rightfully so) that I&apos;ll break my API and will eventually bring down the system due to some stupid mistake.  But until I can have a good enough code coverage I want to be confident that I&apos;m not breaking my APIs whenever I&apos;m pushing a new release to production. Now I&apos;ve taken quite a lot of steps over past few months (from having proper CI/CD pipeline to having slots support to have the availability for new releases etc) to clean up the codebase and continue to have my services up-and-running, one thing I&apos;m particularly excited about is Postman.&lt;/p&gt;


&lt;p&gt;If you are involved in RESTful API development, chances are you are already aware of Postman or atleast have heard of it. But in case this is the first time you heard about the tool, I&apos;ll give you a very quick intro about it. &lt;/p&gt;


&lt;blockquote&gt;
&lt;p&gt;&quot;Postman mkes API Development Simple&quot;
&lt;a href=&quot;&apos;https://www.getpostman.com&apos;&quot;&gt;&lt;em&gt;Postman website&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;Postman is a powerful HTTP client for testing web services. It makes API development faster, easier and better. You can read more about it on their official &lt;a href=&quot;https://www.getpostman.com&quot;&gt;website&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;I&apos;ve been using postman during my development (testing APIs etc) but for last few weeks, I&apos;ve started to write integration tests for my APIs so that whenever I&apos;m making any changes or creating a new release (for any environment), I can quickly run the collection and make sure everything is still functioning as expected. &lt;/p&gt;


&lt;p&gt;This is not a replacement for having a proper unit test (with good enough code coverage) but I find it very useful to quickly verify that I haven&apos;t broken the core functionality of my solution. &lt;/p&gt;


&lt;p&gt;Here are some features I&apos;m using with Postman for my integration tests&lt;/p&gt;


&lt;ul&gt;&lt;li&gt;Test automation&lt;ul&gt;&lt;li&gt;Collections&lt;ul&gt;&lt;li&gt;One big collection to run tests for all services in one go&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Separate collections for each service (API) with calls of each operation that API exposes/supports&lt;/li&gt;&lt;li&gt;Extended tests to cover different scenarios&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Debugging&lt;ul&gt;&lt;li&gt; Pre-script and tests for individual calls&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Environment variables - to have the possibility to test the APIs towards any environment that I want to test &lt;/li&gt;&lt;/ul&gt;


&lt;p&gt;Even though I&apos;ve used quite a few features so far but it doesn&apos;t end here. Here is what I have planned to take advantage of other features as I go along. &lt;br /&gt;&lt;/p&gt;


&lt;ul&gt;&lt;li&gt;Integrating postman in my CI/CD (newman) so that I can auto swap my slots for the web application if everything is green&lt;/li&gt;&lt;li&gt;Mocking&lt;/li&gt;&lt;li&gt;Continue to extend my tests cases to increase coverage&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;


&lt;p&gt;How are you using Postman in your projects? Have you found anything intersting/useful that you would like to share?&lt;/p&gt;


&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Accessing WCF Service via Azure Service Bus Relay with .NET Core</title><link>https://sanjaybhagia.com/blog/accessing-wcf-service-via-azure-service-bus-relay-with-net-core/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/accessing-wcf-service-via-azure-service-bus-relay-with-net-core/</guid><description>Calling an on-premises WCF service from a .NET Core web app through Azure Service Bus Relay by crafting the SOAP request and relay token by hand.</description><pubDate>Wed, 28 Nov 2018 00:00:00 GMT</pubDate><content:encoded>
&lt;p&gt;&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://github.com/sanjaybhagia/wcfservice-servicebusrelay-netcore&quot; target=&quot;_blank&quot;&gt;Check out my GitHub repository if you want to dig into the source code directly.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&lt;/p&gt;


&lt;p&gt;WCF (Windows Communication Foundation) has served us for a long time when it comes to talking to many LOB systems (SAP etc.). You might have love or hate (&lt;em&gt;though if I have to guess, it would be on hate side&lt;/em&gt;) relationship with WCF but it works and at times we don&apos;t have any other choice. If you happen to be in a situation where you are talking to legacy systems via WCF, you most likely have a built an API layer on top of it to serve your clients. &lt;/p&gt;


&lt;p&gt;I was recently looking to consume WCF services using .NET Core &lt;em&gt;(with the intention that I can migrate my web application to .NET Core)&lt;/em&gt;. Very quickly I came up to this &lt;a href=&quot;https://github.com/dotnet/wcf&quot; target=&quot;_blank&quot;&gt;GitHub repository&lt;/a&gt; which was awesome. However, this .NET Core implementation is not in parity with the full framework yet.  I tested it and it worked just fine with standard bindings (http etc). &lt;a href=&quot;https://twitter.com/spboyer&quot; target=&quot;_blank&quot;&gt;Shane Boyer&lt;/a&gt; has a good &lt;a href=&quot;http://tattoocoder.com/asp-net-core-getting-clean-with-soap/&quot; target=&quot;_blank&quot;&gt;blog post&lt;/a&gt; on this topic if you want to see how to use this.&lt;/p&gt;


&lt;p&gt;As far as my needs (this particular scenario) are concerned, I couldn&apos;t get it to work for my setup. This is how the setup looks for me. &lt;/p&gt;


&lt;p&gt;The web application (hosted in Azure Web App) talks to WCF Service (running on-premises, hosted in IIS) via Azure Service Bus Relay (in Azure)&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-21.png&quot; alt=&quot;&quot; /&gt;&lt;/figure&gt;


&lt;p&gt;So basically, there is no equivalent to basicHttpRelayBinding in .NET Core implementation yet and this is something my WCF service has to enable communication via Azure Service Bus Relay. &lt;/p&gt;


&lt;p&gt;After discussing with a friend of mine, I got a suggestion to try it out with SOAP instead and it seems to work fine! I know it sounds a bit ironic that on the one hand I&apos;m moving to the latest (and greatest) framework for my web application but at the same time, I&apos;m going one step back and using SOAP protocol to make it work - well such is life. I would very much appreciate if anyone can point me to the better solution. but until then, let&apos;s continue forward.&lt;/p&gt;


&lt;p&gt;So, in this blog post, I will go through how did I manage to call WCF service from my .NET Core Web Application. Again, &lt;a href=&quot;https://github.com/sanjaybhagia/wcfservice-servicebusrelay-netcore&quot; target=&quot;_blank&quot;&gt;here is the entire source code&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;&lt;a href=&quot;https://github.com/sanjaybhagia/wcfservice-servicebusrelay-netcore&quot; target=&quot;_blank&quot;&gt;&lt;/a&gt;So this is what I&apos;m going to do: &lt;/p&gt;


&lt;ul&gt;&lt;li&gt;Create Azure Service Bus Relay (&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/service-bus-relay/service-bus-dotnet-hybrid-app-using-service-bus-relay&quot; target=&quot;_blank&quot;&gt;read here how to create this&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Create a WCF Service (with Azure Service Bus Relay Binding) and publish this locally to run it on IIS&lt;/li&gt;&lt;li&gt;ASP.NET Core Web Application calling to WCF Service using HTTP Post SOAP request.&lt;/li&gt;&lt;/ul&gt;


&lt;p&gt;Follow the link I have provided above to create the service bus relay. Let&apos;s start with WCF Service. Here is the &lt;a href=&quot;https://github.com/sanjaybhagia/wcfservice-servicebusrelay-netcore/tree/master/WcfService&quot; target=&quot;_blank&quot;&gt;sample WCF project&lt;/a&gt; I build for this demo.  It&apos;s a very basic WCF service which has Azure Service Bus Relay binding besides standard HTTP binding (check out the &lt;a href=&quot;https://github.com/sanjaybhagia/wcfservice-servicebusrelay-netcore/blob/master/WcfService/WcfService/Web.config&quot; target=&quot;_blank&quot;&gt;web.config&lt;/a&gt; for binding details). I have deployed this in IIS on my local machine. You can clone the repository and add the details of your relay if you want to try it out yourself. It exposes the following contract, which I&apos;m interested in.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;[ServiceContract]
    public interface ICustomerService
    {
        [OperationContract]
        string GetCustomerData(string customerId);
    }&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;When you browse this service from IIS you should see the service like this. At this point, a Service Bus WCF listener should also be registered in your namespace (you can check it in Azure Portal)&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-14.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;WCF Service deployed in IIS with Azure Service Relay Binding&lt;/figcaption&gt;&lt;/figure&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-18.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;WCF Relay Registered from WCF Service&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;Now, let&apos;s start with the web application. I have created a vanilla ASP.NET Core Web API project (2.1). You can grab the &lt;a href=&quot;https://github.com/sanjaybhagia/wcfservice-servicebusrelay-netcore/tree/master/WebApplication&quot; target=&quot;_blank&quot;&gt;source code from here &lt;/a&gt;(and clone it if you want to try it out yourself). &lt;em&gt;Make sure you update settings in appsettings.json file for Azure Service Bus Relay. If you wish you publish this to Azure Web app - add these settings as Application Settings&lt;/em&gt;&lt;/p&gt;


&lt;p&gt;After creating the project, I added following NuGet package&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;Nuget Packages: &lt;/strong&gt;&lt;/p&gt;


&lt;ul&gt;&lt;li&gt;Microsoft.Azure.ServiceBus&lt;/li&gt;&lt;/ul&gt;


&lt;p&gt;In &lt;strong&gt;ValuesController&lt;/strong&gt;, I have created a &lt;em&gt;GetCustomerData&lt;/em&gt; method that takes in &lt;em&gt;customerId&lt;/em&gt; as a string.  In here, I&apos;ll make a call to WCF Service and return the response I receive from the service (&lt;em&gt;the WCF service returns a dummy response&lt;/em&gt;)&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;[HttpGet(&quot;{customerId}&quot;)]
public async Task&amp;lt;string&amp;gt; GetCustomerData(string customerId)&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then moving forwards,  I generate the token for Azur Service Bus Relay:&lt;/p&gt;


&lt;figure&gt;&lt;a href=&quot;https://github.com/sanjaybhagia/wcfservice-servicebusrelay-netcore/blob/master/WebApplication/WebApplication/Controllers/ValuesController.cs&quot;&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-17.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Generating Token for Service Bus Relay&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;With this information, I construct the HTTP Post request like this:&lt;/p&gt;






&lt;p&gt;We are basically making an HTTP Post Request to the Service Bus Relay endpoint over SOAP. For this, we need to set up a few headers&lt;/p&gt;


&lt;ul&gt;&lt;li&gt;ServiceBusAuthorization - &lt;em&gt;Relay Token retrieved earlier&lt;/em&gt;&lt;/li&gt;&lt;li&gt;SOAPAction - &lt;em&gt;The Operation you want to call from WCF Service&lt;/em&gt;&lt;/li&gt;&lt;li&gt;Accept header - &lt;em&gt;text/&lt;/em&gt;xml&lt;/li&gt;&lt;/ul&gt;


&lt;p&gt;Lastly, we need to set the body for the request - since this is a SOAP call, we need a SOAP message.&lt;/p&gt;


&lt;figure&gt;&lt;a href=&quot;https://github.com/sanjaybhagia/wcfservice-servicebusrelay-netcore/blob/master/WebApplication/WebApplication/Controllers/ValuesController.cs&quot;&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-16.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;SOAP message body&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;Press F5 and run the web application, pass in cusotmerId parameter and you should get a response from the service:&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-15.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Successful response from WCF Service&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;Have you tried to consume WCF Service from .NET Core application? How did it go for you? I would love to hear from you and would appreciate if you could suggest a better way of doing this as of today? I guess I don&apos;t need to tell you that I don&apos;t like using SOAP :)&lt;/p&gt;


&lt;p&gt;Cheers.&lt;/p&gt;
</content:encoded></item><item><title>Accessing Azure Analysis Services Models using .NET Core</title><link>https://sanjaybhagia.com/blog/accessing-azure-analysis-services-models-using-net-core/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/accessing-azure-analysis-services-models-using-net-core/</guid><description>Querying an Azure Analysis Services model from .NET Core using ADOMD.NET with a service principal and token-based authentication via ADAL.NET.</description><pubDate>Mon, 12 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update (2020-07-25):&lt;/strong&gt;&lt;/em&gt; Microsoft recently &lt;a href=&quot;https://azure.microsoft.com/en-us/updates/net-core-support-for-azure-analysis-services-client-libraries-is-in-preview/&quot;&gt;announced&lt;/a&gt; the .NET Core support for Azure Analysis Services client libraries in preview (&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.AnalysisServices.NetCore.retail.amd64&quot;&gt;AMO&lt;/a&gt; and &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.AnalysisServices.AdomdClient.NetCore.retail.amd64&quot;&gt;ADOMD.NET&lt;/a&gt;). You can use these packages instead of the Unofficial packages which I have based this blogpost on. These packages are still in preview though, so you can&apos;t (or shoudn&apos;t) use these in your production environment. I have added another console application project in my project which you can checkout &lt;a href=&quot;https://github.com/sanjaybhagia/azure-analysis-services-netcore-sample/tree/master/ConsoleApp/ConsoleAppOfficialLibs&quot;&gt;here&lt;/a&gt;. I just updated the reference to the nuget packge in &lt;a href=&quot;https://github.com/sanjaybhagia/azure-analysis-services-netcore-sample/blob/dd1a8f059551e78a7ad4da28b5a6a333dfa47938/ConsoleApp/ConsoleAppOfficialLibs/ConsoleAppOfficialLibs.csproj#L10&quot;&gt;.csproj&lt;/a&gt; file, nothing else. These libraries should work similar to the full .NET framework ones.&lt;/p&gt;
&lt;hr /&gt;

&lt;blockquote&gt;&lt;p&gt;Azure Analysis Services is a fully managed platform as a service (PaaS) that provides enterprise-grade data models in the cloud. Use advanced mashup and modeling features to combine data from multiple data sources, define metrics, and secure your data in a single, trusted tabular semantic data model. The data model provides an easier and faster way for users to browse massive amounts of data for ad-hoc data analysis.&lt;br /&gt;&lt;/p&gt;&lt;cite&gt;Refer to &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/analysis-services/analysis-services-overview&quot; target=&quot;_blank&quot;&gt;Microsoft official documentation&lt;/a&gt; to read more about Azure Analysis Services&lt;/cite&gt;&lt;/blockquote&gt;


&lt;p&gt;Programming against Analysis services is nothing new and we have been doing it for a long time with the full .NET framework, the most common approach is using ADOMD.Net. In this blog post, I will go through the process of getting the same task done with .NET Core.  For this sample, I&apos;m using .NET Core 2.1.&lt;/p&gt;


&lt;p&gt;&lt;a href=&quot;https://github.com/sanjaybhagia/azure-analysis-services-netcore-sample&quot; target=&quot;_blank&quot;&gt;Look at my GitHub repository for the entire source code for this blogpost&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;The important thing to note here is that there is no official nuget package from Microsoft for ADOMD.NET yet, but I found an unofficial package here (&lt;a href=&quot;https://github.com/bdebaere/Unofficial.Microsoft.AnalysisServices.AdomdClientNetCore&quot; target=&quot;_blank&quot;&gt;Unofficial.Microsoft.AnalysisServices.AdomdClientNetCore&lt;/a&gt;) and it seems to work for my quick test (you have to make a call if you want to use it in production or not). I couldn&apos;t find any official word on this anywhere I looked for.  &lt;em&gt;Besides this &lt;/em&gt;nuget&lt;em&gt; package for .net core rest of the stuff should work same in full framework (with official &lt;/em&gt;nuget&lt;em&gt; for ADOMD.NET)&lt;/em&gt;&lt;/p&gt;


&lt;p&gt;I have divided this into several steps so that it is easy to follow. So let&apos;s get started!&lt;/p&gt;


&lt;h2&gt;Step 1: Create Azure Analysis Service resource&lt;/h2&gt;


&lt;p&gt;The very first thing we need is the Analysis Server and model in Azure. Follow &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/analysis-services/analysis-services-create-server&quot; target=&quot;_blank&quot;&gt;this&lt;/a&gt; quick starter to create the server.&lt;/p&gt;


&lt;p&gt;Next is to create a model which we will use to query. You can create a model with sample data (adventure works) right from within your Analysis Server.&lt;/p&gt;


&lt;p&gt;Click &apos;Manage&apos; in the blade and click &apos;New Model&apos;. Select &apos;Sample data&apos; from the drop down and press &apos;Add&apos;. It should add the model for you. &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-3.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Create a model Analysis Services&lt;/figcaption&gt;&lt;/figure&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-2.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Model successfully created&lt;/figcaption&gt;&lt;/figure&gt;


&lt;h2&gt;Step 2: Create App Service Principal&lt;/h2&gt;


&lt;p&gt;There are many ways to access analysis services. Simplest is using a connection string that has usrename and password. But this is not recommended approach and works only with full .Net framework but not .Net Core (I was pointed by &lt;a href=&quot;https://github.com/bdebaere/Unofficial.Microsoft.AnalysisServices.AdomdClientNetCore/issues/1&quot; target=&quot;_blank&quot;&gt;bdebaere in his GitHub respo&lt;/a&gt; regarding this), so we want to authenticate with other OAuth flows. For this post, we will use token-based authentication. For this we will need an app principal (or Azure AD App)&lt;/p&gt;


&lt;ol&gt;&lt;li&gt;Sign in to &lt;a href=&quot;https://portal.azure.com/&quot; target=&quot;_blank&quot;&gt;Azure Portal&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Navigate to Azure Active Directory -&amp;gt; App Registrations and Click New application registration.&lt;/li&gt;&lt;li&gt;Register an app with the following settings:&lt;ul&gt;&lt;li&gt;Name: any name&lt;/li&gt;&lt;li&gt;Application type: Web app/API,&lt;/li&gt;&lt;li&gt;Sign-on URL:  https://westeurope.asazure.windows.net (&lt;em&gt;Not really important here, you can provide any valid url&lt;/em&gt;).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Once the app is created, navigate to &apos;Keys&apos; and add a new key&lt;ul&gt;&lt;li&gt;provide the description and select duration and press Save button&lt;/li&gt;&lt;li&gt;after that you will be able to see the key &lt;strong&gt;it will appear only once&lt;/strong&gt; so take note of this key and we will use this later on&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Also take note of the Application Id from the main page of the application&lt;/li&gt;&lt;/ol&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-5.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Setting access key for Azure AD App&lt;/figcaption&gt;&lt;/figure&gt;


&lt;h2&gt;Step 3: Assign your user as Service Admin in order to connect from SSMS&lt;/h2&gt;


&lt;p&gt;Registering an app is not enough. We need to assign access to this app on  Analysis Service Model (&lt;em&gt;adventureworks model that we created in previous step)&lt;/em&gt;. In order to give this access, we will need SQL Server Management Studio. &lt;/p&gt;


&lt;p&gt;Before we could use that, we need a way to connect to this analysis services instance via SSMS. For this, we need to set up our account as Service Admin. Navigate to the Analysis Services resource that we created in the first step. Click &apos;Analysis Services Admin&apos;. Normally your subscription account is set as the admin (this is what I will be using) but you are free to set up any account you wish appropriate. &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-6.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Setting Sevice Admin for Analysis Service&lt;/figcaption&gt;&lt;/figure&gt;


&lt;h2&gt;Step 4: Grant permissions to app principal on the model&lt;/h2&gt;


&lt;ol&gt;&lt;li&gt;Connect to Analysis Service using SSMS 2017 with your account that you assigned as Service Admin in the previous step&lt;ul&gt;&lt;li&gt;You will need the Server name (from Step 1)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Select the database model and click on Roles or add a new Role&lt;ul&gt;&lt;li&gt;Choose any name &lt;/li&gt;&lt;li&gt;Select &apos;Read&apos; database permission for the role &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Add the Service principal to any role in below format (search for the app name)&lt;/li&gt;&lt;/ol&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-9.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Connect to Azure Analysis Server with Service Admin account&lt;br /&gt;&lt;/figcaption&gt;&lt;/figure&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-13.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Adding App principal as a member in newly defined role&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;This will add user with following convention:  app:&amp;lt;appid&amp;gt;@&amp;lt;tenantid&amp;gt;&lt;/p&gt;


&lt;p&gt;&lt;em&gt;appid&lt;/em&gt;: is the application id for your app you created in the Step 2.&lt;/p&gt;


&lt;p&gt;&lt;em&gt;tenantid&lt;/em&gt; - is the id of your subscription (you can find this in Properties of your Azure Active Directory)&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;This didn&apos;t work for me when I tried &lt;/em&gt;&lt;/strong&gt;&lt;strong&gt;&lt;em&gt; to use Azure subscription with my personal account (hotmail&lt;/em&gt;&lt;/strong&gt;&lt;strong&gt;&lt;em&gt;) so I had to use my company account subscription to make this work. &lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;Step 5: Write the code to access data&lt;/h2&gt;


&lt;p&gt;Now we are all set up write our code that reads from the Model. Please refer to the entire source code in my &lt;a href=&quot;https://github.com/sanjaybhagia/azure-analysis-services-netcore-sample&quot; target=&quot;_blank&quot;&gt;GitHub respository&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Important method here &lt;em&gt;GetAccessToken.&lt;/em&gt; I&apos;m using ADAL.Net (nuget: &lt;em&gt;Microsoft.IdentityModel.Clients.ActiveDirectory&lt;/em&gt;) to grab the token for the service principal from Azure AD&lt;em&gt;.&lt;/em&gt; &lt;/p&gt;


&lt;figure&gt;&lt;a href=&quot;https://github.com/sanjaybhagia/azure-analysis-services-netcore-sample/blob/master/ConsoleApp/ConsoleApp/Program.cs&quot;&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-12.webp&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Method to acquire token from Azure AD to access analysis services&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;Once we have the token, we are good to access data from the model. Here I&apos;m using the unofficial NuGet package for ADOMD.NET that I mentioned previously.  The correct  Connection String format is: &lt;/p&gt;


&lt;p&gt;“&lt;strong&gt;Provider=MSOLAP;Data Source=&amp;lt;url of the Azure Analysis Server&amp;gt;;Initial Catalog=&amp;lt;modelname&amp;gt;;User ID=;Password=&amp;lt;access token here&amp;gt;;Persist Security Info=True;Impersonation Level=Impersonate&lt;/strong&gt;“&lt;/p&gt;


&lt;p&gt;User ID is left empty and Password is the access token which we get from Azure AD. &lt;/p&gt;


&lt;figure&gt;&lt;a href=&quot;https://github.com/sanjaybhagia/azure-analysis-services-netcore-sample/blob/master/ConsoleApp/ConsoleApp/Program.cs&quot;&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-11.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;figcaption&gt;Method to read data from Analysis Services Model &lt;em&gt;adventureworks&lt;/em&gt;&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;If you run this, you will see the output in the console&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-10.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Final output of the program&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;Have you tried to work with Azure Analysis services in .NET Core? How was your experience? I would be very interested in listening to your experience and challenges.&lt;/p&gt;


&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Are you keeping your secrets secret?</title><link>https://sanjaybhagia.com/blog/are-you-keeping-your-secrets-secret/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/are-you-keeping-your-secrets-secret/</guid><description>Two versions of an Azure web app reading from blob storage: one with the connection string in app settings, one keeping it safe in Key Vault.</description><pubDate>Thu, 25 Oct 2018 00:00:00 GMT</pubDate><content:encoded>
&lt;p&gt;&lt;strong&gt;As developers&lt;/strong&gt;, we are all guilty of leaking sensitive information of our applications and systems more than we would perhaps like to admit. Don&apos;t get me wrong, I&apos;m not talking about breaking the NDAs with our clients but about those little connection strings to our databases and keys to our storage accounts where we hold all our information that we want to protect from outside world. As developers, we understand that this information is sensitive and still we check-in those along with the rest of our code base which eventually ends up in our version control systems that are hosted in the cloud somewhere. And we firmly believe that this is going to be fine. This is akin to watching a dreadful accident on NEWS and saying this can&apos;t happen to us.&lt;/p&gt;


&lt;p&gt;&quot;The Cloud&quot; is all beautiful and powerful but with power comes responsibility. Among all people, we developers should be well aware and feel responsible &amp;amp; accountable for handling the sensitive information of our applications. We must ensure that it doesn&apos;t leak under any circumstances which can jeopardize our systems (and also our positions). And believe it or not cloud has made these things easier and we have all the tools we need to make it happen. It is not complicated anymore, you just need to be a bit thoughtful and set up the habit to do this when you are starting your project (or even better put these things if you end up in a project where this is lacking).&lt;/p&gt;


&lt;p&gt;Ok, enough talking let&apos;s get to the meat of this post. In this blog post, I will create a Web Application (hosted in Microsoft Azure) which lists URIs of blobs from a container in Storage Account (Microsoft Azure). For the sake of simplicity, I&apos;m creating the container and a dummy blob at the runtime. The Web app is a standard ASP.Net Core web app. I will present two implementations of this scenario.&lt;/p&gt;


&lt;p&gt;The first implementation would be with the connection string of a Storage account stored in Application Settings of the web application directly. In the second part, I will move that connection string from the web application and keep it somewhere safe and will fetch information from the Storage account as earlier. Both the applications are deployed using ARM Templates and completely automated (&lt;em&gt;You can create these resources manually if you so&lt;/em&gt; &lt;em&gt;wish&lt;/em&gt;).&lt;/p&gt;


&lt;h3&gt;&lt;strong&gt;Part I&lt;/strong&gt;&lt;/h3&gt;


&lt;p&gt;&lt;a href=&quot;https://github.com/sanjaybhagia/webappsecretsdemo/tree/master/WebAppsWithSecrets&quot; target=&quot;_blank&quot;&gt;Here&lt;/a&gt; is the source code for this part. I will refer to some bits and pieces of this below:&lt;/p&gt;


&lt;p&gt;Here is how the setup looks like: &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-25.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Web App reading from Storage Account directly using Connection String&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;If you look at the source code (&lt;a href=&quot;https://github.com/sanjaybhagia/webappsecretsdemo/tree/master/WebAppsWithSecrets&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;), in my &lt;em&gt;WebApWithSecrets&lt;/em&gt; solution, I have two projects:&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-26.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Solution structure - WebAppWithSecrets&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;&lt;strong&gt;deployment&lt;/strong&gt; project contains the ARM template for provisioning the resources. The ARM Template does the following&lt;/p&gt;


&lt;ul&gt;&lt;li&gt;provisions a Storage Account&lt;br /&gt;&lt;/li&gt;&lt;li&gt;provisions the web application&lt;/li&gt;&lt;li&gt;adds &apos;StorageAccountConnectionString&apos; as a Connection String in the Web Application&lt;/li&gt;&lt;/ul&gt;


&lt;p&gt;You have instructions to deploy this template in GitHub repository at the above URL (if you want to try it out yourself). Once the resources are provisioned, this is how my resource group looks like when I see it in Azure Portal.&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-38.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Three resources provisioned by ARM template in Azure subscription&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;If I navigate to my Web Application and look at the Application Settings, this is what I see: a connection string with the name &apos;StorageAccountConnectionString&apos; &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-31.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Connection String set in Web Application after deployment&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;Once the resources are provisioned and in place, we can push the code to our web application. You can push this in a variety of ways but for now, I will just right-click and publish (&lt;strong&gt;WebAppsWithSecrets&lt;/strong&gt; project (&lt;em&gt;don&apos;t do this in production&lt;/em&gt;). Once the code is pushed successfully, the web application will open up in my browser (otherwise navigate to the web application). This is how it looks for me (the red box is my custom code that lists the URIs):&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-32.png&quot; alt=&quot;&quot; /&gt;&lt;/figure&gt;


&lt;p&gt;At this point, the app is fully functional and there is nothing wrong here. If I navigate to &lt;a href=&quot;https://github.com/sanjaybhagia/webappsecretsdemo/blob/master/WebAppsWithSecrets/WebAppsWithSecrets/appsettings.json&quot; target=&quot;_blank&quot;&gt;appsettings.json&lt;/a&gt; file in my source code, I will find this: a connection string to my storage account which my code picks and fetches content from Storage Account (you will find the code to render these URIs in &lt;a href=&quot;https://github.com/sanjaybhagia/webappsecretsdemo/blob/master/WebAppsWithSecrets/WebAppsWithSecrets/Pages/Index.cshtml.cs&quot; target=&quot;_blank&quot;&gt;Index.cshtml.cs&lt;/a&gt; file)&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-33.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Connection String in appsettings.json in the solution&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;I have this details not only to me but this is now checked-in to my source control.&lt;/p&gt;


&lt;p&gt;We can all argue that it is not that bad after all since this is hosted in GitHub (or Azure DevOps or whatever the version control system you are using). These are secure systems and only our team members have access to them - so why bother? &lt;/p&gt;


&lt;p&gt;This all holds true until someone gets hold of your GitHub account or you haven&apos;t configured the permissions correctly and someone who shouldn&apos;t have the detail might get access. Put it simply, we are increasing the attack surface and we might have to deal with some unwanted situations later on. The good news is we don&apos;t necessary have to do it this way, there is a better alternative which I will demonstrate in next part.&lt;/p&gt;


&lt;h3&gt;&lt;strong&gt;Part II&lt;/strong&gt;&lt;/h3&gt;


&lt;p&gt;&lt;a href=&quot;https://github.com/sanjaybhagia/webappsecretsdemo/tree/master/WebAppsWithoutSecrets&quot; target=&quot;_blank&quot;&gt;Here&lt;/a&gt; is the source code for this part. I will refer to some bits and pieces of this below:&lt;/p&gt;


&lt;p&gt;The alternative approach could be that we keep such sensitive information in some sort of secured place or vault which is encrypted and secure which we can rely on and our application simply &lt;em&gt;asks&lt;/em&gt; for this information from that vault without ever knowing the details itself. We sort of want to delegate the responsibility of handling sensitive information of our application to some other party without us worrying about the implications. By doing this we not only simplify our lives but also gain much more benefits like it would be better to govern these secrets, we would be able to update the keys and connection strings and certificates without changing anything in our application. The good news is Microsoft Azure has exactly such offer called &apos;Azure KeyVault&apos;. You can read about this more &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/key-vault/key-vault-overview&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;This is how the redesign of our application looks like after introducing the Azure KeyVault: &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-35.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Solution design after introducing Azure Key Vault&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;The Web Application has information about the KeyVault only and delegates the responsibility of retrieving ConnectionString to Storage Account to the KeyVault.&lt;/p&gt;


&lt;p&gt;If you look at the source code (&lt;a href=&quot;https://github.com/sanjaybhagia/webappsecretsdemo/tree/master/WebAppsWithoutSecrets&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;). In &lt;em&gt;WebApWithourSecrets&lt;/em&gt; solution, I have two projects, same as before.&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-24.png&quot; alt=&quot;&quot; /&gt;&lt;/figure&gt;


&lt;p&gt;I have updated my ARM template for this. The template now does the following:&lt;/p&gt;


&lt;ul&gt;&lt;li&gt;provisions a Storage Account&lt;/li&gt;&lt;li&gt;provisions the KeyVault&lt;/li&gt;&lt;li&gt;provisions the web application&lt;/li&gt;&lt;li&gt;adds &apos;StorageAccountConnectionString&apos; as a &lt;em&gt;Secret&lt;/em&gt; in the KeyVault&lt;br /&gt;&lt;/li&gt;&lt;li&gt;sets the name of the KeyVault in application settings&lt;/li&gt;&lt;/ul&gt;


&lt;p&gt;There is one catch, however. You might ask, wait for a second here! Fine, I moved my storage account&apos;s connection string to the KeyVault but I still need details of the vault in my web application to read anything from it. Though I moved the secret of storage account my web application now holds even more sensitive information - all the secrets !! I feel you, I&apos;m with you. But don&apos;t worry, this is a solved problem. Microsoft quickly realized this and provided a very nice solution for this very problem. They introduced something called &apos;Managed Service Identity&apos; aka MSI (now being renamed to just Managed identities) a while back. You can read more about this &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; but in short, it abstracts this detail in such a way that you don&apos;t need to keep any ClientId/ClientSecret or Key of the vault in your web application. You simply enable Managed Identity in your web application (it creates an app principle which gets permissions to read from the Vault). &lt;a href=&quot;https://web.archive.org/web/20190326093706/https://blog.kloud.com.au/2018/04/13/demystifying-managed-service-identities-on-azure/&quot; target=&quot;_blank&quot;&gt;Here&lt;/a&gt; is a really good premier of MSI if you want to get a deeper understanding of the feature.&lt;/p&gt;


&lt;p&gt;If you navigate to &lt;a href=&quot;https://github.com/sanjaybhagia/webappsecretsdemo/blob/master/WebAppsWithoutSecrets/WebAppsWithoutSecrets/Program.cs&quot; target=&quot;_blank&quot;&gt;&lt;em&gt;Program.cs&lt;/em&gt;&lt;/a&gt; file in the solution, here is code that hooks up the KeyVault into our application (BuildWebHost method):&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;public static IWebHost BuildWebHost(string[] args) =&amp;gt;
     WebHost.CreateDefaultBuilder(args)
     //this is where KeyVault magic happens - we are setting up configurations from Azure KeyVault using Managed Service Identity
     //without specifiying any details of the Azure KeyVault itself (except the Url of the vault)
    .ConfigureAppConfiguration((context, config) =&amp;gt;
    {
       var builtConfig = config.Build();
       var keyVaultUrl = $&quot;https://{builtConfig[&quot;KeyVaultName&quot;]}.vault.azure.net&quot;;

       //this comes with .net core 2.1
       config.AddAzureKeyVault(keyVaultUrl);
                
       //if using 2.0, you should use this apporach
       //AzureServiceTokenProvider - this is the magic piece that makes it seamless to work with MSI
       //var azureServiceTokenProvider = new AzureServiceTokenProvider();
       //var keyVaultClient = new KeyVaultClient(
       //new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
       //config.AddAzureKeyVault(keyVaultUrl, keyVaultClient, new DefaultKeyVaultSecretManager());
       })
       .UseStartup&amp;lt;Startup&amp;gt;()
       .Build();&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;if you look closely, all information we have about the Azure KeyVault in our web application is the name (or URL if you will) of the KeyVault (&lt;em&gt;KeyVaultName&lt;/em&gt;) stored in our appsettings.json (or Application Settings in the published web app). Everything else is managed by MSI for us. &lt;br /&gt;&lt;/p&gt;


&lt;p&gt;In ARM template, we enable MSI for the web application with this property: &lt;/p&gt;


&lt;pre&gt;&lt;code&gt;&quot;identity&quot;: {
     &quot;type&quot;: &quot;SystemAssigned&quot;
   }	&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This enables this setting for the web application&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-23.png&quot; alt=&quot;&quot; /&gt;&lt;/figure&gt;


&lt;p&gt;So, as we did it Part I, let&apos;s deploy the template to provision new set of resources for us (You will find instructions in GitHub repository for this). Once resources are provisioned, this is how it looks for me in Azure Portal:&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-40.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Four resources provisioned by ARM template in Azure Account&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;If i navigate to the application settings of my web application, this is what I see: &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-37.png&quot; alt=&quot;&quot; /&gt;&lt;/figure&gt;


&lt;p&gt;Notice, there is no connection string as we had earlier, instead there is an App Settings &apos;KeyVaultName&apos; which contains the name of the vault. That&apos;s the only information this web application has. Let&apos;s deploy the code for the web application (like earlier, right-click and publish). After successfull deployment, this is what you should see: &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-22.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Web Application without Secrets after successful deployment&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;This looks exactly same as previous web application since we haven&apos;t changed the logic. The only thing that was changed in this web app was to read connection string from KeyVault. &lt;/p&gt;


&lt;p&gt;Now let&apos;s uncover some more details. If you navigate to the Azure KeyVault resource and then head over to &lt;em&gt;Secrets&lt;/em&gt;, you will see this: &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-41.png&quot; alt=&quot;&quot; /&gt;&lt;/figure&gt;


&lt;p&gt;If you pay attention, you don&apos;t see anything, instead, it tells you that &quot;&lt;em&gt;You are unauthorized to view these contents.&lt;/em&gt;&quot; But the web application lists the URIs just fine! Let&apos;s go to Access Policies tab, you will see that there is one policy created for a web application: &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-42.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Access Policy for Web Application&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;This was created by the &lt;a href=&quot;https://github.com/sanjaybhagia/webappsecretsdemo/blob/master/WebAppsWithoutSecrets/deployment/azuredeploy.json&quot; target=&quot;_blank&quot;&gt;ARM template&lt;/a&gt; after web application was provisioned. This is the section in ARM Template which defines this policy for the web application&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;&quot;accessPolicies&quot;: [
          {
            &quot;tenantId&quot;: &quot;[reference(concat(resourceId(&apos;Microsoft.Web/sites&apos;, variables(&apos;webAppName&apos;)), &apos;/providers/Microsoft.ManagedIdentity/Identities/default&apos;), &apos;2015-08-31-PREVIEW&apos;).tenantId]&quot;,
            &quot;objectId&quot;: &quot;[reference(concat(resourceId(&apos;Microsoft.Web/sites&apos;, variables(&apos;webAppName&apos;)), &apos;/providers/Microsoft.ManagedIdentity/Identities/default&apos;), &apos;2015-08-31-PREVIEW&apos;).principalId]&quot;,
            &quot;permissions&quot;: {
              &quot;keys&quot;: [ &quot;all&quot; ],
              &quot;secrets&quot;: [ &quot;all&quot; ]
            }
          }
        ],
        &quot;tenantId&quot;: null,
        &quot;tenantId&quot;: &quot;[reference(concat(resourceId(&apos;Microsoft.Web/sites&apos;, variables(&apos;webAppName&apos;)), &apos;/providers/Microsoft.ManagedIdentity/Identities/default&apos;), &apos;2015-08-31-PREVIEW&apos;).tenantId]&quot;,
        &quot;sku&quot;: {
          &quot;name&quot;: &quot;Standard&quot;,
          &quot;family&quot;: &quot;A&quot;
        }&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Since at the moment, the only allowed access is for the web application you are not able to see any secrets when you go to &lt;em&gt;Secrets&lt;/em&gt; tab. You can give access to your account if you want to see these secrets. &lt;em&gt;Remember to click Save button after adding the policy, otherwise settings will not be saved&lt;/em&gt;&lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-43.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Adding Access Policy in Azure Key Vault&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;now, when I navigate the Secrets again, i&apos;m able to see the Secrets. &lt;/p&gt;


&lt;figure&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/image-45.png&quot; alt=&quot;&quot; /&gt;&lt;figcaption&gt;Secrets visible after adding access policy for the logged in user in Azure Portal&lt;/figcaption&gt;&lt;/figure&gt;


&lt;p&gt;Remember: &lt;em&gt;If you want to use secrets from the KeyVault while development, you will have to assign access policy for your user in Azure KeyVault. Otherwise, you will get access denied exception. &lt;/em&gt;&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: &lt;/p&gt;


&lt;p&gt;So as we saw, it&apos;s fairly straightforward to keep sensitive information in Azure KeyVault and configure our Web Application to read these secrets from the Vault. Moreover,  Managed Service Identity feature further facilitates us to keep the information about KeyVault out of our web application. This can be applied to any scenarios - this is not necessarily bound to the web application only. You can keep connection strings, keys, certificates and all sorts of information you don&apos;t want to keep in your consumer application.&lt;/p&gt;


&lt;p&gt;So, how do you handle your secrets? What is your opinion on this topic? I would love to hear more from you, please leave your comments. &lt;/p&gt;


&lt;p&gt;Cheers&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Identifying the owner of personal sites in SharePoint</title><link>https://sanjaybhagia.com/blog/identifying-the-owner-of-personal-sites-in-sharepoint/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/identifying-the-owner-of-personal-sites-in-sharepoint/</guid><description>How to find the owner of a SharePoint personal site by mapping the PersonalSpace profile property to search and caching the result in the property bag.</description><pubDate>Thu, 22 Jan 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Scenario/Problem:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Recently I was faced with a situation where I wanted to know the owner of the Personal Site in SharePoint. While it’s fairly straightforward to identify the personal site by the WebTemplate property in the corresponding SPWeb object but there was no property that could simply pin-point the owner of the site itself. If you take a look at the User Profile (from User Profile Service in Central Administration), there is a property called “Personal Site” (internal name is PersonalSpace) that tells us the relative url of the personal site for the respective profile. It is set automatically by SharePoint after the personal site is successfully provisioned. Wouldn’t it be nice in if we simply have a property or attribute on SPWeb object that tells us just this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;However, it is not that difficult to achieve this. There could be many possible implementations but here I’m going to discuss one approach that I recently implemented.&lt;/p&gt;
&lt;p&gt;So based on the information I could get out of SharePoint, I first set the Personal Site property to be indexed so that it can be crawled by the search service. Then, I created a managed property called PersonalSite and map it to PersonalSpace property. This gives me the possibility to query the search engine like “PersonalSite:/person/adamb”. If this is targeted to People scope, you will get the user profile whose personal site is set to /personal/adamb. And its safe to assume that the value would be unique.&lt;/p&gt;
&lt;p&gt;Having set up the basics, now we can simply write a search query to give us the result we want.&lt;/p&gt;
&lt;p&gt;Moving ahead, we can store this value in the property bag of the SPWeb object of the personal site. And whenever we need this property, we can first check if the value is present in the property bag, if we already have it, we don’t need to make a query again to the search, otherwise we can make a search query and store the value in the property bag for the next time.&lt;/p&gt;
&lt;p&gt;Here is the code snippets for the above mentioned functionality. This code snippet doesn’t contain the creation of managed property but rest of the implementation.&lt;/p&gt;

&lt;p&gt;With this fairly simple implementation, we can grab the owner of the personal site and fetch his user profile to perform other required operations.&lt;/p&gt;
&lt;p&gt;Please feel free to share if you have any other alternative(s) to get this done.&lt;/p&gt;
&lt;p&gt;P.S: You will require to run the Full Crawl after creating the managed property with the correct mapping. Before this, you will not get any result back from the search query.&lt;/p&gt;
&lt;p&gt;Cheers !&lt;/p&gt;
</content:encoded></item><item><title>Deleting Managed Metadata Fields via PowerShell</title><link>https://sanjaybhagia.com/blog/deleting-managed-metadata-fields-via-powershell/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/deleting-managed-metadata-fields-via-powershell/</guid><description>PowerShell script to remove the hidden Note fields SharePoint leaves behind when deleting taxonomy fields, fixing duplicate field name errors.</description><pubDate>Thu, 08 Jan 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;
When you provision a Managed Metadata (Taxonomy) field in SharePoint, it creates a hidden field (of type Note) along with the main taxonomy field. What happens when you delete that field? You would expect the other one to be deleted as well, right? Not that easy :)&lt;/p&gt;
&lt;p&gt;SharePoint for some reason doesn’t delete that hidden field. So when you provision the field again with the same name, it simply increments the number for the hidden field. Let’s say your field is called MyTax1. The hidden field will be named MyTax1_0. Now if MyTax1_0 already exists, SharePoint will create MyTax1_1 and so on. This is applicable when you working from the interface with OOB functionality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;
What if you are provisioning taxonomy fields through code or PowerShell where you provision certain fields, associate them with the content types etc. Moreover, during the development/testing phase, you might need to delete those fields and re-provision them number of times before your code is production ready.
Well, if thats the case then most likely you will end with the following exception.&lt;/p&gt;
&lt;blockquote&gt;A duplicate field name dd93a2825ad24eef8e3e1cf4f2e96a40 was found&lt;/blockquote&gt;
Reason? The hidden field is not deleted yet and your code is trying to create the field with the same name.
&lt;p&gt;If you check it with &lt;a href=&quot;https://web.archive.org/web/20160108124745/http://spm.codeplex.com/&quot; target=&quot;_blank&quot;&gt;SharePoint Manager 2013&lt;/a&gt; you can see that this Guid is the internal name of the hidden taxonomy field&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;
In order to get around this issue, we need to make sure that hidden Note field is also removed. I wrote few lines of PowerShell script to delete those hidden fields as well. Here is the code snippet.&lt;/p&gt;


&lt;p&gt;Hope it helps. Cheers.&lt;/p&gt;
</content:encoded></item><item><title>Using HttpHandler to deal with cross-domain requests from AngularJS app for SharePoint on-premises</title><link>https://sanjaybhagia.com/blog/using-httphandler-to-deal-with-cross-domain-requests-from-angularjs-app-for-sharepoint-on-premises/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/using-httphandler-to-deal-with-cross-domain-requests-from-angularjs-app-for-sharepoint-on-premises/</guid><description>Using a custom HttpHandler to avoid cross-domain issues when an AngularJS app filters followed sites with the site feed feature in SharePoint on-prem.</description><pubDate>Sat, 16 Aug 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When you go to the newsfeed in your personal site (mysite newsfeed), you can write post and target it to different sites you are following or on your personal feed.&lt;/p&gt;
&lt;p&gt;Recently, I had to built the same functionality for one of the projects. The ideas was to build the UI using SharePoint’s REST APIs and AngularJS. I am not using Office365 so i still have SharePoint on-prem.&lt;/p&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/Screen-Shot-2014-08-14-at-10.37.17.png&quot; alt=&quot;&quot; /&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Its quite simple as you would expect to retrieve the list of sites a user is following. You simply call this REST endpoint “../_api/social.following/my/followed(types=4)” and you have the result, no brainer. But only when you dig into the results, you get to know that even though the list is correct but not every site returned has newsfeed enabled. As a result, you also get those sites that have no newsfeed and these are the sites you don’t want to display. So, how do you eliminate those?&lt;/p&gt;
&lt;p&gt;The problem is that there is no information in the JSON response that REST endpoint returns. The only option you have is to actually check for the SiteFeed feature on that web. So you get the site, open that web and see if this feature in enabled. Now this is all fine when you are on server side but if you are implementing your functionality using client side, you will end up dealing with cross-domain issues and you will get exception as it is treated as a cross-domain request by the browser.&lt;/p&gt;
&lt;p&gt;Now if you were dealing with Office365, this could have been resolved using Microsoft Azure’s ACS to authenticate your app with SharePoint and all would have worked just fine. But that’s not the case when you are building your client app using jQuery or Angular and using REST APIs in SharePoint on-prem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So, after struggling quite a bit to somehow deal with this, I ended up creating the HttpHandler in which I retrieved the list of sites the current user is following. Then I iterated through that collection to check for the Site Feed feature and return the collection of sites only with site feed feature enabled and continue to building my AngularJS app as I was before hitting this issue.&lt;/p&gt;
&lt;p&gt;I am not putting up the entire code or even complete code for my app here. I am adding some snippets demonstrating the solution. Here is the markup in my view. Its simply a drop down that lists the sites I’m following just like the one you get in SharePoint by default.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- Here is the markup in the view (html file) of my angularjs app. I am putting just the markup for rendering the dropdown with required results and eliminating rest of the code for demonstration purpose --&amp;gt;
&amp;lt;!-- here, vm.followedSites is the model that im setting in my controller and select element is bound to that model --&amp;gt;
 &amp;lt;div&amp;gt;
      &amp;lt;select ng-model=&quot;vm.selectedValue&quot; ng-options=&quot;value.Name for value in vm.followedSites&quot;&amp;gt;
          &amp;lt;option value=&quot;&quot;&amp;gt;everyone&amp;lt;/option&amp;gt;
      &amp;lt;/select&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is my controller that calls the handler to retrieve that data and set the model that my view is bound to.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* to simplify things, i am demonstrating the underlying method that is calling in the httphandler to get the desired result 
 this method is inside my controller 
 */
 
 function loadFollowedSites(currentUser) {
            //construct the URL for httphandler to get the sites with newsfeed activated
            var url = &quot;/_layouts/15/myapp/Handlers/ClientHandler.ashx?operation=getFollowedSitesWithNewsFeed&amp;amp;username=&quot;+ currentUser;
            
            //make request to the url and return the result back
            return $http.get(url).then(function (response) {
                return response.data;
            });
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, here is the code that retrieves the list of sites i’m following in my HttpHandler&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
Here is the code snippet from my HttpHandler
 
**/  
  public void ProcessRequest(HttpContext context)
  {
      context.Response.ContentType = &quot;application/json&quot;;
      context.Response.ContentEncoding = Encoding.UTF8;
      
      string operation = context.Request.QueryString[&quot;operation&quot;];
 
      if (!String.IsNullOrEmpty(operation))
      {
        /* Code removed */ 
        if (operation == &quot;getFollowedSitesWithNewsFeed&quot;)
        {
            string userName = (context.Request.QueryString[&quot;username&quot;] != null) ? context.Request.QueryString[&quot;username&quot;] : String.Empty;
            List&amp;lt;SPSocialActor&amp;gt; newsFeedFollowedSites = GetFollowedSitesWithNewsFeed(context, userName);
            context.Response.Write(JsonSerializer.Serialize(newsFeedFollowedSites));
        }
        
        /* code remoed */
      }
 
  }
  
  //Retrieves the list of all the sites that specific user is following that has SiteFeed web feature enabled
  private List&amp;lt;SPSocialActor&amp;gt; GetFollowedSitesWithNewsFeed(HttpContext cxt, string username)
  {
      List&amp;lt;SPSocialActor&amp;gt; followedSitesWithNewsFeed = new List&amp;lt;SPSocialActor&amp;gt;();            
      SPServiceContext context = SPServiceContext.GetContext(cxt);
      UserProfileManager profileManager = new UserProfileManager(context);
 
      if (profileManager.UserExists(username))
      {
          UserProfile userProfile = profileManager.GetUserProfile(username);
          SPSocialFollowingManager followingManager = new SPSocialFollowingManager(userProfile, context);
 
          SPSocialActor[] followedSites = followingManager.GetFollowed(SPSocialActorTypes.Sites);
 
          foreach (var actor in followedSites)
          {
              try
              {
                  using (SPSite site = new SPSite(actor.Uri.AbsoluteUri))
                  {
                      SPWeb rootWeb = site.RootWeb;
                      
                      //Check for SiteFeed feature (web)
                      Guid featureGuid = new Guid(&quot;15a572c6-e545-4d32-897a-bab6f5846e18&quot;);
                      if (rootWeb.Features[featureGuid] != null)
                      {
                          followedSitesWithNewsFeed.Add(actor);
                      }
                  }
              }
              catch 
              { 
                //Handle exception
              }
          }
      }
      else
      {
        //Log - user doesn&apos;t exist
      }            
      
      
      return followedSitesWithNewsFeed;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please let me know if there’s something I have missed or if there is any better way of doing this. I will really appreciate it.&lt;/p&gt;
&lt;p&gt;Thanks Cheers&lt;/p&gt;
</content:encoded></item><item><title>The specified program requires a new version of Windows. (Exception from HRESULT:0x8007047E)</title><link>https://sanjaybhagia.com/blog/the-specified-program-requires-a-new-version-of-windows-exception-from-hresult0x8007047e/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/the-specified-program-requires-a-new-version-of-windows-exception-from-hresult0x8007047e/</guid><description>Fixing the HRESULT 0x8007047E exception by dropping ModeratedList from schema.xml and enabling content approval in code instead.</description><pubDate>Sat, 23 Nov 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;:
I have a custom list definition based on which I want to create some lists and associate OOB approval workflow with them for content approval.&lt;/p&gt;
&lt;p&gt;In the schema.xml file for my custom list definition (&lt;em&gt;based documents library i.e., basetype=1&lt;/em&gt;), I set ModeratedList=“True” attribute among others (see in the code snippet below)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;List xmlns:ows=&quot;Microsoft SharePoint&quot; Title=&quot;TestList&quot; Direction=&quot;$Resources:Direction;&quot; Url=&quot;TestList&quot; BaseType=&quot;1&quot;
xmlns=&quot;http://schemas.microsoft.com/sharepoint/&quot; EnableContentTypes=&quot;TRUE&quot; EnableMinorVersions=&quot;TRUE&quot; VersioningEnabled=&quot;TRUE&quot; DraftVersionVisibility=&quot;2&quot; ModeratedList=&quot;TRUE”&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, I added a ListAdded event receiver that listens to my custom list definition,so whenever any list is created based on my custom list definition, the OOB approval workflow should be associated with the list.&lt;/p&gt;
&lt;p&gt;Here is the code snippet that associates the OOB approval workflow with the list&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
///
/// Associate OOB Approval workflow with the list
///
///
public static void AssociateApprovalWorklowWithList(SPList list)
{
  //variables
  Guid listId = list.ID;
  Guid webId = list.ParentWeb.ID;
  Guid siteId = list.ParentWeb.Site.ID;
  SPSite site = null;
  SPWeb web = null;

  try
  {
    site = new SPSite(siteId);
    web = site.OpenWeb(webId);
    bool allowUnsafeCurrent = web.AllowUnsafeUpdates;
    web.AllowUnsafeUpdates = true;
    list = web.Lists[listId];

    //Get Approval Workflow Template Base Id
    Guid workflowBaseId = new Guid(&quot;8ad4d8f0-93a7-4941-9657-cf3706f00&quot;+ web.Language.ToString(&quot;X&quot;));

    //If workflow is already associated, don&apos;t re-associate
    if (list.WorkflowAssociations.GetAssociationByBaseID(workflowBaseId) != null)
       return;

    //check if workflows feature is activated, if not activate the feature
    SPFeature workflowsFeature = web.Site.Features[WorkflowId];

    if (workflowsFeature == null)
      web.Site.Features.Add(WorkflowId);

    // Get workflow history and task list
    SPList historyList = EnsureHistoryList(web);
    SPList taskList = EnsureTasksList(web);
    string workflowAssociationName = string.Format(&quot;{0} - Approval&quot;, list.Title);
    SPWorkflowTemplate workflowTemplate = web.WorkflowTemplates.GetTemplateByBaseID(workflowBaseId);
    if (workflowTemplate == null)
    {
     //Log exception
     return;
    }

    workflowTemplate.AllowManual = false;

    // Create workflow association
    SPWorkflowAssociation workflowAssociation = SPWorkflowAssociation.CreateListAssociation(workflowTemplate,
    workflowAssociationName, taskList, historyList);

    var associationDataXml = XElement.Parse(workflowAssociation.AssociationData);
    // Add workflow association to my list
    list.WorkflowAssociations.Add(workflowAssociation);

    //Set workflow association data
    workflowAssociation.AssociationData = Add_Association_Data(web, associationDataXml);

    // Enable workflow
    if (!workflowAssociation.Enabled)
        workflowAssociation.Enabled = true;

    if (list.DraftVersionVisibility != DraftVisibilityType.Approver)
       list.DraftVersionVisibility = DraftVisibilityType.Approver;

    list.WorkflowAssociations.Update(workflowAssociation);
    list.DefaultContentApprovalWorkflowId = workflowAssociation.Id;
    list.Update();
    web.AllowUnsafeUpdates = allowUnsafeCurrent;
  }
  catch (Exception ex)
  {
    //Log Exception
  }
  finally
  {
    //Dispose the objects
    if (web != null)
       web.Dispose();
    if (site != null)
       site.Dispose();
   }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the explanation of retrieving the workflow template id (line#23), please refer to my previous post here &lt;a href=&quot;http://sanjaybhagia.com/2013/10/20/associating-oob-approval-workflow-with-custom-list-for-different-locale-lcids/&quot;&gt;Associating OOB Approval workflow with custom list for different Locale (LCIDs)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;
Once I have deployed the solution and everything is hooked up, I create the list based on my custom list definition and the process ends with the following exception:&lt;/p&gt;
&lt;img src=&quot;https://sanjaybhagia.com/images/pastedgraphic-1.png&quot; alt=&quot;PastedGraphic-1&quot; /&gt;
&lt;p&gt;&lt;span&gt;But when I go to the site, the list is created and workflow is associated properly. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;
&lt;span&gt;After narrowing down the problem, I removed the &lt;strong&gt;ModeratedList&lt;/strong&gt; attribute from List element in schema.xml file for custom list definition (shown in the first code snippet), enabled the content approval for the list in the code and redeployed the solution and everything worked !&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Here is the code for enabling content approval through code (add this in the function defined above after setting &lt;em&gt;DraftVersionVisibility&lt;/em&gt; property)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
  if(!list.EnableModeration)
    list.EnableModeration = true;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cheers&lt;/p&gt;
</content:encoded></item><item><title>Associating OOB Approval workflow with custom list for different Locale (LCIDs)</title><link>https://sanjaybhagia.com/blog/associating-oob-approval-workflow-with-custom-list-for-different-locale-lcids/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/associating-oob-approval-workflow-with-custom-list-for-different-locale-lcids/</guid><description>Why the OOB Approval workflow template BaseId differs per locale, and how to build the right GUID from the site&apos;s LCID in hex to associate it.</description><pubDate>Sun, 20 Oct 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; I have a custom web template that is used to provision the site. Among other things (branding etc), a custom documents library is provisioned whenever a new site is created (also based on my custom documents library template). Besides creating the custom library, I need to associate the OOB Approval workflow with the library that will be used as a publishing workflow. So if any user publishes the major version of the document it goes through the approval process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem/Limitation:&lt;/strong&gt; Associating the workflow with any list or library is fairly straight forward. Here are the steps:&lt;/p&gt;
&lt;ol&gt;
 	&lt;li&gt;Fetch the workflow template from parent web where list exist&lt;/li&gt;
 	&lt;li&gt;Get the target list&lt;/li&gt;
 	&lt;li&gt;Create the workflow association&lt;/li&gt;
 	&lt;li&gt;Check if workflow is already associated with the list&lt;/li&gt;
 	&lt;li&gt;If workflow is not associated, add the workflow association to the list&lt;/li&gt;
&lt;/ol&gt;
Here is the code snippet for performing this task.
&lt;pre&gt;&lt;code&gt;private void AssociateApprovalWorklowWithList(SPList list)
{
SPWeb web = list.ParentWeb;
SPSite site = web.Site;
try
{
bool allowUnsafeCurrent = web.AllowUnsafeUpdates;
web.AllowUnsafeUpdates = true;
&lt;p&gt;//Associate the approval workflow with libraries
//based on Custom Documents template only
if (list != null &amp;amp;&amp;amp; list.BaseTemplate.ToString() == &quot;10050&quot;)
{
//Get Approval Workflow Template Base Id
Guid workflowBaseId = new Guid(&quot;8ad4d8f0-93a7-4941-9657-cf3706f00409&quot;);&lt;/p&gt;
&lt;p&gt;//If workflow is already associated, don&apos;t re-associate
if (list.WorkflowAssociations.GetAssociationByBaseID(workflowBaseId) != null)
return;&lt;/p&gt;
&lt;p&gt;// Get workflow history and task list
SPList historyList = EnsureHistoryList(web);
SPList taskList = EnsureTasksList(web);&lt;/p&gt;
&lt;p&gt;//set the name of workflow association
string workflowAssociationName = string.Format(&quot;{0} - Approval&quot;, list.Title);&lt;/p&gt;
&lt;p&gt;//Get workflow template by Base Id
SPWorkflowTemplate workflowTemplate = web.WorkflowTemplates.GetTemplateByBaseID(workflowBaseId);
if (workflowTemplate == null)
{
//Log - no template found and return
return;
}&lt;/p&gt;
&lt;p&gt;// Create workflow association
SPWorkflowAssociation workflowAssociation =
SPWorkflowAssociation.CreateListAssociation(workflowTemplate, workflowAssociationName,
taskList, historyList);&lt;/p&gt;
&lt;p&gt;// Add workflow association to custom list
list.WorkflowAssociations.Add(workflowAssociation);&lt;/p&gt;
&lt;p&gt;workflowAssociation.AssociationData = String.Empty;&lt;/p&gt;
&lt;p&gt;//.. details omitted
list.WorkflowAssociations.Update(workflowAssociation);
list.DefaultContentApprovalWorkflowId = workflowAssociation.Id;
list.Update();&lt;/p&gt;
&lt;p&gt;web.AllowUnsafeUpdates = allowUnsafeCurrent;
}
}
catch (Exception ex)
{
//Log exception
}
finally
{
//Dispose objects
}
}&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
The above code snippet will work just fine. But there is a little problem.&lt;p&gt;&lt;/p&gt;
&lt;p&gt;What if the site is created on language other than English? One case ask, why would there be any problem as we are fetching the workflow template by Base Id. Well, it turned out that the Base Id is not the same across different languages, it varies. So it failed if site has different locale.&lt;/p&gt;
&lt;p&gt;There is also another method GetWorkflowTemplateByName but it didn&apos;t work out for me as well, even though I set the right culture.. So that means, we can not use both the methods.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Trying both the methods to get the template didn&apos;t work and I didn&apos;t get anything by googling it either. So the only way out of this problem was the following:&lt;/p&gt;
&lt;p&gt;Looking at the BaseIds of different sites, a pattern emerged. Let&apos;s examine the BaseIds from English and Swedish sites, as we saw previously&lt;/p&gt;
&lt;pre&gt;8ad4d8f0-93a7-4941-9657-cf3706f00409 (English, LCID: 1033)
8ad4d8f0-93a7-4941-9657-cf3706f0041D (Swedish, LCID: 1053)&lt;/pre&gt;
&lt;p&gt;If you look closely, almost entire Id is same except last three digits Let&apos;s take some more examples:&lt;/p&gt;
&lt;pre&gt;8ad4d8f0-93a7-4941-9657-cf3706f00415 (Polish, LCID: 1045)
8ad4d8f0-93a7-4941-9657-cf3706f00406 (Danish, LCID: 1030)&lt;/pre&gt;
&lt;p&gt;as you can see, only the last three digits vary from language to language.&lt;/p&gt;
&lt;p&gt;Now take the LCID and convert it to hexadecimal representation (thanks to my colleague &lt;a href=&quot;https://twitter.com/mattein&quot;&gt;Matthias Einig&lt;/a&gt; for breaking this code ;) )&lt;/p&gt;
&lt;p&gt;Lets say,  for:&lt;/p&gt;
&lt;p&gt;LCID = 1033 =&amp;gt; hex = 409&lt;/p&gt;
&lt;p&gt;LCID = 1053 =&amp;gt; hex = 41d&lt;/p&gt;
&lt;p&gt;LCID = 1045 =&amp;gt; hex = 415&lt;/p&gt;
&lt;p&gt;So, it became clear that the last three digits that differ are basically the hexadecimal representation of LCID. Having identified this pattern, I simply converted the LCID to hex value and there we have it, the BaseId for approval workflow template for current language&lt;/p&gt;
&lt;p&gt;So,  if we change the line #15 in our code snippet above to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Guid workflowBaseId = new Guid(&quot;8ad4d8f0-93a7-4941-9657-cf3706f00&quot;+ web.Language.ToString(&quot;X&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this change, now no matter which locale the site has, it will construct the right workflow template id and will fetch the workflow template for association.&lt;/p&gt;
&lt;p&gt;Hope it helps some folks out there :)&lt;/p&gt;
</content:encoded></item><item><title>Updates are currently disabled in GET requests exception while provisioning multiple site collections</title><link>https://sanjaybhagia.com/blog/updates-are-currently-disabled-in-get-requests-exception-while-provisioning-multiple-site-collections/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/updates-are-currently-disabled-in-get-requests-exception-while-provisioning-multiple-site-collections/</guid><description>Why SharePoint throws &apos;Updates are currently disabled in GET requests&apos; when a timer job creates several site collections, and the HttpContext fix.</description><pubDate>Sun, 02 Jun 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Recently i was working with creating site provisioning in SharePoint 2010. For that I have a list where user submits the request for the site that needs to be created (along with some required metadata). Then I have scheduled the timer job that picks up items from that list (based on the status), iterates through the items and provisions the site.&lt;/p&gt;
&lt;p&gt;Here is the method in Timer Job that iterates through the items and creates site collections.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void ProvisionSite(String siteCollectionUrl)
{
   using (SPSite siteCollection = new SPSite(siteCollectionUrl))
   {
      SPList requestList = siteCollection.RootWeb.Lists.TryGetList(&quot;SiteRequests&quot;);
      if (requestList != null)
      {
        var query = new SPQuery();

        //Fetch the items that have Status=Requested
        query.Query = String.Format(&quot;{0}&quot;, &quot;Requested&quot;);

        SPListItemCollection items = list.GetItems(query);

        if (items != null &amp;amp;&amp;amp; items.Count &amp;gt; 0)
            ProcessRequest(items);
      }
   }
}

//Generates random 7-digit number
public static String GenerateSiteNumber()
{
  Random random = new Random();
  String siteNumber = random.Next(0000000, 9999999).ToString();
  return siteNumber;
}

public static void ProcessRequest(SPListItemCollection items)
{
   try
   {
      foreach (SPListItem item in items)
      {
        try
        {
           SPSite site = null;
           SPSecurity.RunWithElevatedPrivileges(delegate
           {
               SPWebApplication webApp = item.Web.Site.WebApplication;
               SPSiteCollection siteCollections = webApp.Sites;

              //Generate random number to use as site collection url
              String siteNumber = GenerateSiteNumber();
              String relativeUrl = &quot;/sites/&quot; + siteNumber;

              //Fail if site collection already exists
              if (SPSite.Exists(new Uri(&quot;http://sp2010demo/&quot; + relativeUrl)))
                   throw new Exception(&quot;Site already exists&quot;);

               using (SPSite newSite = siteCollections.Add(relativeUrl, &quot;My Site&quot; + siteNumber, &quot;Test Site collection&quot;, 1033, null, &quot;dc\spadmin&quot;, &quot;&quot;,       &quot;&quot;))
               {
                  site = newSite;
                  //.. code removed for clarity .....
               }
           });
        }
      }
   }
   catch
   { }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As provisioning is done by the timer job Context is null (i.e., HttpContext.Current will be null). In my solution, I am simply iterating through the list items and creating the site collections. First request always works fine, site is created successfully but I am getting an exception as soon as the site for the next item is being provisioned. The exception that I get is the following:&lt;/p&gt;
&lt;em&gt;&quot;Updates are currently disabled in GET requests. To enable updates in GET requests, change the property AllowUnsafeUpdates on SPWeb.&quot;&lt;/em&gt;
&lt;p&gt;Now apparently, this exception is thrown when you perform any GET operation on Web and you haven&apos;t set AllowUnsafeUpdates to &quot;True&quot; !! But I&apos;m just creating a site collection, so I don&apos;t have any SPWeb object where I should set this property ??&lt;/p&gt;
&lt;p&gt;After investigating a little further (and with the help of ILSpy) it turned out that after first site collection is created, HttpContext.Current is set to the context of this newly created site collection and for the next item, Context is already set to the previous site collection and exception is thrown at SiteCollection.Add() method. The Add() method basically checks if HttpContext is already set, if yes then it uses the context and in my case this is wrong!&lt;/p&gt;
&lt;strong&gt;Solution&lt;/strong&gt;
&lt;p&gt;The solution is quite easy to fix.&lt;/p&gt;
&lt;p&gt;After the completion of first iteration, set the HttpContext to null so that during the next request there is no context set.&lt;/p&gt;
&lt;p&gt;Here is the line of code (finally block) that I added to my previous method.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public static void ProcessRequest(SPListItemCollection items)
{
 try
 {
   foreach (SPListItem item in items)
   {
     try
     {
         //... code removed for clarity --
     }
     finally
     {
        //Reset the Context
        System.Web.HttpContext.Current = null;
     }
   }
 }
 catch
 { }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hope it helps.&lt;/p&gt;
</content:encoded></item><item><title>Incorrect values for User Fields while copying list items from one site collection to another</title><link>https://sanjaybhagia.com/blog/incorrect-values-for-user-fields-while-copying-list-items-from-one-site-collection-to-another/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/incorrect-values-for-user-fields-while-copying-list-items-from-one-site-collection-to-another/</guid><description>Fixing wrong user field values when copying SharePoint list items across site collections by remapping lookup ids with SPWeb.EnsureUser.</description><pubDate>Sat, 25 May 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Recently, I was writting a piece of code to copy list item from a list in one site collection to the list in another site collection. I did the shallow copy (copying field by field).
Both the lists were created using same List definition so they had same fields and content types etc.
The item was successfully copied but then I noticed that the values of user fields were not correct.&lt;/p&gt;
&lt;p&gt;Here is the pice of code that i used for copying the item&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
Public static void Main(string[] args)
{
    using (SPSite sourceSite = new SPSite(&quot;http://sp2010demo/sites/source&quot;))
    {
      using (SPWeb web = sourceSite .OpenWeb())
      {
          SPList sourceList= web.Lists.TryGetList(&quot;Source List&quot;);
          //fetch first item - for demonstration purpose
          SPListItem sourceItem = sourceList.Items[0];
          //instantiate destination site collection
          using (SPSite destinationSite = new SPSite(&quot;http://sp2010demo/sites/destination/&quot;))
          {
             var destinationList = destinationSite.RootWeb.Lists.TryGetList(&quot;DestinationList&quot;);
             if (destinationList != null)
             {
                //Add new item
                SPListItem destinationItem = destinationList.Items.Add();
                //copy item
                CopyListItem(sourceItem, destinationItem);
             }
          }
      }
   }
}

public static void CopyListItem(SPListItem sourceItem, SPListItem destinationItem)
{
        foreach (SPField field in sourceItem.Fields)
        { 
          //Filter out readonly and attachment fields
          if ((!field.ReadOnlyField) &amp;amp;amp;&amp;amp;amp; (field.InternalName != &quot;Attachments&quot;))
          {
                destinationItem[field.Title] = sourceItem[field.Title];
          }
        } 
        destinationItem.Update();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apparently, it looked just fine and i used the same piece of code to copy the list items from one list to another within the same site collection and it worked just perfect as it should !&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So, the problem was actually that when you move this item to a different site collection, users have to be present there in order for it to have the correct value.&lt;/p&gt;
&lt;p&gt;If you look at the internal representation of the user field it is basically a look up value and the value is represented something like this: &lt;strong&gt;1;#Sanjay Bhagia&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Where first number is the user id in User Information List in the site collection that can be accessed (only if you are admin) by navigating to the following url in your site &lt;strong&gt;_catalogs/users/simple.aspx&lt;/strong&gt; (e.g., http://sp2010demo/sites/source/_catalogs/users/simple.aspx).&lt;/p&gt;
&lt;p&gt;So lets do some investigation.&lt;/p&gt;
&lt;p&gt;I first open my source site collection i.e., http://sp2010demo/sites/source and navigate to my user information list by navigating to the following url http://sp2010demo/sites/source_catalogs/users/simple.aspx It shows all the users that have been added in my site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sanjaybhagia.com/images/userinfosourcesite1.jpg&quot;&gt;&lt;img alt=&quot;userinfosourcesite&quot; src=&quot;https://sanjaybhagia.com/images/userinfosourcesite1.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now, if you put the cursor on the user link, you can see the entire url in the status bar of your browser. At the end of the url you can see the querystring &lt;strong&gt;ID &lt;/strong&gt;that has value 1 in this example.&lt;/p&gt;
&lt;p&gt;Now lets navigate to the same user list in destination site collection by (http://sp2010demo/sites/destination/_catalog/users/simple.aspx).&lt;/p&gt;
&lt;p&gt;Note: In my environment, I already have my user added in both the site collections, that is why I&apos;m able to see my user at both the places but it is possible that you don&apos;t see any user at both the places. User will be added automatically if you have logged in with that user on that site&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sanjaybhagia.com/images/userinfodestination1.jpg&quot;&gt;&lt;img alt=&quot;userinfodestination&quot; src=&quot;https://sanjaybhagia.com/images/userinfodestination1.jpg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;By observing the url of the same user we can see that the user id for this user in destination site collection is &lt;strong&gt;10&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So if I&apos;m copying the list item that has user field and that field has my user added (i.e., Sanjay Bhagia) the representation of that user in my source site collection will be &lt;strong&gt;1;#Sanjay Bhagia&lt;/strong&gt; but the representation of the same user in my destination site collection will be &lt;strong&gt;10;#Sanjay Bhagia&lt;/strong&gt; !! Hence, the copied item will not display the proper user at the destination list item.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;
It is quite easy to fix this issue, I basically fetched the value from user field and called SPWeb.EnsureUser() method to make sure the user is added in the User Information List in my destination site collection and updated the LookupId attribute of the SPUser object.&lt;/p&gt;
&lt;p&gt;Here is the modified code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public static void CopyListItem(SPListItem sourceItem, SPListItem destinationItem)
{
    foreach (SPField field in sourceItem.Fields)
    {
        //Filter out readonly and attachment fields
	if ((!field.ReadOnlyField) &amp;amp;&amp;amp; (field.InternalName != &quot;Attachments&quot;))
        {
            //only for user type fields
            if (field.GetType() == typeof(SPFieldUser))
            {
               SPWeb destinationParentWeb = destinationItem.ParentList.ParentWeb;
               if (sourceItem[field.Title] != null)
               {
                 //for field can have multiple selection enabled otherwise you can user SPFieldUserValue class
                 SPFieldUserValueCollection users = new SPFieldUserValueCollection(sourceItem.ParentList.ParentWeb, sourceItem[field.Title].ToString());
                 foreach (SPFieldUserValue user in users)
                 {
                    //this LookupId is the number of user object in User Information List
                    user.LookupId = destinationParentWeb.EnsureUser(user.User.LoginName).ID;
                 }
                destinationItem[field.Title] = users;
               }
            }
            else
              destinationItem[field.Title] = sourceItem[field.Title];
                    }
        }
    destinationItem.Update();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So basically, I&apos;m making sure that user object in destination site collection has the correct look up id, that&apos;s it!&lt;/p&gt;
&lt;p&gt;Hope it helps.&lt;/p&gt;
</content:encoded></item><item><title>Creating loosely coupled and generic process steps implementation</title><link>https://sanjaybhagia.com/blog/creating-loosely-coupled-and-generic-process-steps-implementation/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/creating-loosely-coupled-and-generic-process-steps-implementation/</guid><description>Designing a loosely coupled process step framework in C# with Execute and RollBack methods for a SharePoint site provisioning workflow.</description><pubDate>Thu, 02 May 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, during one of the SharePoint implementations we came across the requirement to build the workflow for site provisioning engine that we are developing.&lt;/p&gt;
&lt;p&gt;One of the requirements of the process is to rollback everything that we create/modify if there is any problem/exception during the process. So for example, if we created the site collection and then in the next step process failed at setting up custom permissions, the process should be roll backed to the initial stage.&lt;/p&gt;
&lt;p&gt;Normally, this is no big deal to implement everything as a standard workflow and you write a piece of code for different activities of the workflow (or use standard workflow activities from Visual Studio toolbox) but then an idea came up why not write an implementation of the process steps independent of the workflow in a nice and loosely couple way that should take care of roll back in a much flexible and nicer and cleaner way !&lt;/p&gt;
&lt;p&gt;So in this post, I will try to describe the solution that I came up with and also implementation details.&lt;/p&gt;
&lt;p&gt;So here is the implementation details:&lt;/p&gt;
&lt;p&gt;First, I created an interface that contains the method declarations for Execute and RollBack methods&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public interface IProcessStep
{
   void Execute(ProcessStepProperties properties);

   void RollBack(ProcessStepProperties properties);
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you see in the code above, I&apos;m using parameter of type ProcessStepProperties. This is basically a custom class that I use as a data transfer object (DTO) across different steps and methods. It&apos;s basically a collection (dictionary in my implementation) that contain key/value pairs. Here is the implementation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public class ProcessStepProperties
{
   public Dictionary&amp;lt;String, Object&amp;gt; Keys = new Dictionary&amp;lt;String, Object&amp;gt;();

   public bool KeyExists(String key)
   {
     if (Keys.ContainsKey(key) &amp;amp;&amp;amp; Keys[key] != null)
        return true;
     return false;
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having interface ready, we write a class that defines one the process steps. This step is CreateSiteStep that creates the site collection. This class inherits from our interface IProcessStep and hence it provides the implementation of Execute and RollBack methods.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public class CreateSiteStep : IProcessStep
{
   //private method to check for preconditions for Execute method
   private bool PrequisitesPresent(ProcessStepProperties properties)
   {
      if (properties.KeyExists(&quot;SiteNumber&quot;) &amp;amp;&amp;amp; properties.KeyExists(&quot;Title&quot;) &amp;amp;&amp;amp; properties.KeyExists(&quot;TemplateName&quot;))
         return true;
      return false;
   }

   public void Execute(ProcessStepProperties properties)
   {
      //Check if preconditions are met
      if (PrequisitesPresent(properties))
      {
         //Create site collection
         CreateSiteFromRequest(properties);

         //Update the property bag
         var spSite = properties.Keys[&quot;SPSite&quot;] as SPSite;
         if (spSite != null)
         {
            properties.Keys[&quot;SiteUrl&quot;] = spSite.Url;
         }
      }

      //Write checkpoint for rollback
      TransactionLogger.Log(this);
   }

   public void RollBack(ProcessStepProperties properties)
   {
        // Add Logging information  - ULS or event logger if appropriate
        SPSite site = properties.Keys[&quot;SPSite&quot;] as SPSite;
        DeleteSite(site);
   }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now there are couple of things that need to be discussed in the above code.&lt;/p&gt;
&lt;p&gt;Firstly, as you see, I have created a private method to check pre-conditions before the Execute method is executed. This is totally upto the specific step to check if it requires any pre-conditions to be met or any values it requires before it proceeds.&lt;/p&gt;
&lt;p&gt;Secondly, as i mentioned above I&apos;m using ProcessProperties class (key/value collection) to transfer the state across methods and steps, I&apos;m updating (adding) the value in the collection right after Site collection has been created. In this way, the next step (or rollback) step will have the updated information that might be useful for further execution of the process.&lt;/p&gt;
&lt;p&gt;Thirdly and quite importantly there is a call to Log method of  TransactionLogger class.
&lt;strong&gt;TransactionLogger.Log(this);&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is very important. Again, TransactionLogger is my custom class that I&apos;m using to log in the information for steps that have successfully been completed. This serves the purpose of check point for me that i use to roll back when anything fails. I&apos;m using Stack as a data structure to push the steps (of type &lt;em&gt;IProcessStep&lt;/em&gt;) whenever any step is successfully executed and if there is any failure during the execution, i simply pop the steps and invoke RollBack method until stack is empty - hence everything is cleaned up in case of failover.&lt;/p&gt;
&lt;p&gt;Here is the implementation of TransactionLogger class.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public class TransactionLogger
{
  //to keep checkpoints
  private static readonly Stack TransactionStack = new Stack();

  //public property to check number of steps in the stack
  public static int LogCount
  {
      get { return TransactionStack.Count; }
  }

  private IProcessStep Pull()
  {
     return TransactionStack.Pop();
  }

  //Pushes the process step into the stack
  public static void Log(IProcessStep step)
  {
      TransactionStack.Push(step);
  }

  //Pops the step from stack and invoke rollback method for every step  until stack is empty
  public static void RollBack(ProcessStepProperties properties)
  {
      while (TransactionStack.Count &amp;gt; 0)
      {
          var step = TransactionStack.Pop();
          step.RollBack(properties);
      }
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, basically the idea is that in case of any failure everything is rolled back and in the implementation above, TransactionLogger class doesn&apos;t need to know the details about any ProcessStep class how to roll back because it is upto every step to roll back the things it has created. That is why TransactionLogger class adds IProcessStep object into the stack and that is our interface!
here is another class called SetSitePermissionGroupStep that basically adds custom permissions to the site collection that has been created in previous process step.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public class SetSitePermissionGroupStep : IProcessStep
{

   // .... code removed for clarity purpose ....

 public override void Execute(ProcessStepProperties properties)
 {
    if (PrequisitesPresent(properties))
    {
       AddAssociatedMemberGroups(properties, _key);
       TransactionLogger.Log(this);
    }
 }

 public override void RollBack(ProcessStepProperties properties)
 {
   //Roll back implementation
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, as a recap, we defined an interface called IProcessStep that contains the declaration of Execute and RollBack methods.&lt;/p&gt;
&lt;p&gt;Other classes (specific to process steps) inherit from IProcessStep and provide an implementation for Execute and RollBack methods. Execute method of every process step class also add check point after successful execution of the step using TransactionLogger.Log method.&lt;/p&gt;
&lt;p&gt;Now having all this setup we need some sort of controller class that could use this implementation. This could be used from within the workflow as well but in my demonstration I&apos;m using a class that implements the Queue and in that queue we can insert separate steps and then Process the queue in the end. Here is the implementation of my controller class.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public class TestProcessSteps
{
    private Queue _queue = new Queue();
    private ProcessStepProperties _properties = new ProcessStepProperties();

    public void Initialize(ProcessStepProperties properties)
    {
       _properties = properties;
    }
    public void Enqueue(IProcessStep step)
    {
       this._queue.Enqueue(step);
    }

    public void ProcessQueue()
    {
      try
      {
         while (_queue.Count &amp;gt; 0)
         {
            //pick item from the queue and invoke execute method
            var step = _queue.Dequeue();
            step.Execute(_properties);
         }
       }
       catch (Exception ex)
       {
          //roll back
          TransactionLogger.RollBack(_properties);
       }
    }
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you notice above, if anything fails (i.e, exception occurs), RollBack method is invoked from TransactionLogger class (that basically pops up items from the stack and invoke rollback method on respective step).&lt;/p&gt;
&lt;p&gt;Finally, here is how we test our implementation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
//Instantiate TestProcessStep class
TestProcessSteps testclient = new TestProcessSteps();

//setup properties
properties = InitializeProcessProperties(item);

//Invoke Initialize method on TestProcessSteps class (that basically initializes ProcessProperties)
testclient.Initialize(properties);

//Insert steps into Queue
testclient.Enqueue(new CreateSiteStep());
testclient.Enqueue(new SetSitePermissionGroupStep(&quot;MemberGroup&quot;));
testclient.Enqueue(new SetSitePermissionGroupStep(&quot;OwnerGroup&quot;));

//Process the Queue (that basically takes items from queue and invoke Execute methods on respective steps)
testclient.ProcessQueue();

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that during the enqueue, I&apos;m adding SetSitePermissionGroupStep step two times with different parameters - in this way you can actually define atomic steps also using the same class.&lt;/p&gt;
&lt;p&gt;Hope it gives the general idea about my thought behind the implementation. Don&apos;t hesitate to provide any feedback or issues if you find any in my solution.&lt;/p&gt;
&lt;p&gt;Thanks for taking time to read this long post :)&lt;/p&gt;</content:encoded></item><item><title>Consuming Content Type Hub in custom web templates</title><link>https://sanjaybhagia.com/blog/consuming-content-type-hub-in-custom-web-templates/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/consuming-content-type-hub-in-custom-web-templates/</guid><description>Why sites created from custom web templates can&apos;t consume the Content Type Hub, and how activating the hidden TaxonomyFieldAdded feature fixes it.</description><pubDate>Thu, 21 Mar 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Setting up content type hub in SharePoint 2010 is quite straightforward process. There are simple steps to follow and if followed in correct order you can get it working in no time. Content Type Hub relies on managed metadata service. Unless all web applications are sharing the same instance of managed metadata service application, they should be able to consume content types from the content type hub (a site collection marked as a hub and other web application are marked to consume from this location).&lt;/p&gt;
&lt;p&gt;However, if you are doing the customization and you have some custom Web Templates that you use to create sites and subsites. And in those sites, you want to consume content types from content type hub, you might get a little bump in the road during the setup.&lt;/p&gt;
&lt;p&gt;As I mentioned, Content Type Hub relies on Managed Matadata service, one feature TaxonomyFieldAdded (a hidden) feature is enabled on every site collection by default. This feature is not activated by default when you create web templates (please refer to this blog for further explanation of this: &lt;a href=&quot;http://blogs.msdn.com/b/chaks/archive/2011/09/04/web-templates-and-content-type-publishing.aspx&quot;&gt;Web Templates and Content Type Publishing&lt;/a&gt;). So if you navigate to the Site Settings for any site that is created from custom web template, you will not see any link for Term store management or Content Type Publishing&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://sanjaybhagia.com/images/sitesettings-featuredisabled.png&quot;&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/sitesettings-featuredisabled.png&quot; alt=&quot;sitesettings-featuredisabled&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
So for custom web templates, you are required to activate this feature.  Here is the PowerShell code for enabling this feature on a specific site collection.
&lt;pre&gt;&lt;code&gt;$snapin = Get-PSSnapin | Where-Object {$_.Name -eq &apos;Microsoft.SharePoint.Powershell&apos;}

if ($snapin -eq $null)
{
Write-Host &quot;Loading SharePoint Powershell Snapin&quot;
Add-PSSnapin &quot;Microsoft.SharePoint.Powershell&quot; -EA SilentlyContinue
}

#Enable &amp;lt;strong&amp;gt;TaxonomyFieldAdded &amp;lt;/strong&amp;gt;feature on site collection
Enable-SPFeature –Identity 73EF14B1-13A9-416b-A9B5-ECECA2B0604C –url &quot;http://portal.local.domain/sites/subsite1/&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once feature is activated, you will see the links in Site Settings appear !
&lt;a href=&quot;https://sanjaybhagia.com/images/sitesettings-featureenabled.png&quot;&gt;&lt;img src=&quot;https://sanjaybhagia.com/images/sitesettings-featureenabled.png&quot; alt=&quot;sitesettings-featureenabled&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now, you should be able to consume content types from content type hub as expected. You can activate this feature directly from your web template, add an entry for this feature in onet.xml file for your web template, in this way you don&apos;t have to enable this feature manually.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;/pre&amp;gt;
&amp;lt;SiteFeatures&amp;gt;
&amp;lt;!-- OOTB: Taxonomy --&amp;gt;
&amp;lt;Feature ID=&quot;73EF14B1-13A9-416b-A9B5-ECECA2B0604C&quot; /&amp;gt;
&amp;lt;/SiteFeatures&amp;gt;
&amp;lt;pre&amp;gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title>Paged Custom Search Query using KeywordQuery</title><link>https://sanjaybhagia.com/blog/paged-custom-search-query-using-keywordquery/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/paged-custom-search-query-using-keywordquery/</guid><description>Paging SharePoint KeywordQuery results with RowLimit and StartRow to stay under the 10000 row search limit and avoid HRESULT 0x80040E01 errors.</description><pubDate>Thu, 14 Mar 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;SharePoint Server Object Model provides two classes to perform custom search queries namely &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.search.query.fulltextsqlquery(v=office.14).aspx&quot;&gt;FullTextSqlQuery &lt;/a&gt;and &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.search.query.keywordquery(v=office.14).aspx&quot;&gt;KeywordQuery&lt;/a&gt;. Both of these classes inherit from a generic Query class (in  Microsoft.SharePoint.Search namespace).&lt;/p&gt;
&lt;p&gt;You can perform search operations using both of these classes depending on your needs as FullTextSqlQuery provides more sophisticated queries using Sql syntax whereas KeywordQuery class provides simpler syntax to do the search.&lt;/p&gt;
&lt;p&gt;However, the scenario I&apos;m explaining in this post is relevant to both of these classes but i will use KeywordQuery class to demonstrate.&lt;/p&gt;
&lt;p&gt;Scenario:&lt;/p&gt;
&lt;p&gt;I want to write a custom people search web part that takes in the keywords entered by user and performs the search.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I&apos;m using powershell to demonstrate here but this can be done in C# as well in similar fashion.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So, here is the function that performs the basic search&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
Function GetSearchResults([string]$siteCollectionUrl, [string]$keyword, [int]$sIndex, [int]$rLimit)
{
	#load the site and set the keyword query object
	$searchSite = Get-SPSite $siteCollectionUrl

	$keywordQuery = New-Object Microsoft.Office.Server.Search.Query.KeywordQuery $searchSite

	$keywordQuery.ResultTypes = [Microsoft.Office.Server.Search.Query.ResultType]::RelevantResults

  	#Write-Host &quot;Start Index &quot; $sIndex
	#Write-Host &quot;Row Limit &quot; $rLimit
	#Write-Host &quot;Keyword &quot; $keyword

	$keywordQuery.StartRow = $sIndex
	$keywordQuery.RowLimit = $rLimit
	$keywordQuery.HiddenConstraints = &quot;scope:People&quot;

	#Pass the query text - SharePoint
	$keywordQuery.QueryText = $keyword

	#query execution
	$results = $keywordQuery.Execute()
	return $results
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;KeywordQuery class has two properties (RowLimit and StartRow) that are of our interest here.
&lt;strong&gt;RowLimit&lt;/strong&gt; specifies the number of items that you want the search to return when you execute the query
and &lt;strong&gt;StartRow&lt;/strong&gt; gets or sets the first row of information from the search results. So basically with both of these properties you get the paged search result instead of getting entire data in one chunk !&lt;/p&gt;
&lt;p&gt;Now, one of the obvious reasons to do this performance. But there is one more reason as well. RowLimit (&lt;em&gt;default value is 50 if you don&apos;t specify it yourself&lt;/em&gt;), even though can accept maximum 32-bit integer value theoretically, is set to some hardcoded limit of 10000. It means that if you set RowLimit to anything greater that 10000 you will get an exception when you execute the query.&lt;/p&gt;
&lt;p&gt;The exception is something like this:&lt;/p&gt;
&lt;pre&gt;&quot;Exception from HRESULT: 0x80040E01&quot;&lt;/pre&gt;
&lt;p&gt;Here is the StackTrace from ULS log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Log Query: More Information: Row could not be inserted into the rowset without exceeding provider&apos;s maximum number of active rows.

SearchServiceApplication::Execute--Exception: System.Runtime.InteropServices.COMException (0x80040E01): Exception from HRESULT: 0x80040E01
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at Microsoft.Office.Server.Search.Query.KeywordQueryInternal.Execute()
at Microsoft.Office.Server.Search.Query.QueryInternal.Execute(QueryProperties properties)
at Microsoft.Office.Server.Search.Administration.SearchServiceApplication.Execute(QueryProperties properties)

SearchServiceApplicationProxy::Execute--Error occured: System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]:
Exception from HRESULT: 0x80040E01 (Fault Detail is equal to An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true,
whose value is: System.Runtime.InteropServices.COMException: Exception from HRESULT: 0x80040E01
at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at Microsoft.Office.Server.Search.Query.KeywordQueryInternal.Execute()
at Microsoft.Office.Server.Search.Query.QueryInternal.Execute(QueryProperties properties)
at Microsoft.Office.Server.Search.Administration.SearchServiceApplication.Execute(QueryProperties properties)
at SyncInvokeExecute(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp;amp; outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp;amp; rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp;amp; rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&amp;amp; rpc) ...).&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can determine this limit by this method in your environment.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Get the maximum results returned value set for KeywordQuery and FullTextQuery in current environment
Function GetMaxResultsReturned()
{
 # Get reference to Search Service Application
 $ssa = Get-SPEnterpriseSearchServiceApplication
 return $ssa.GetSetting(&apos;Config:qp_MaxResultsReturned&apos;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This value is configured at Search Service Application level. Now this could be different for your environment but default is 10000. So if you set RowLimit to anything greater than this value (&apos;Config:qp_MaxResultsReturned&apos;) you will get an exception.
You can modify this value if you want using this function&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Sets the maximum results returned value set for KeywordQuery and FullTextQuery in current environment
Function SetMaxResultsReturned($newLimit)
{
	$ssa = Get-SPEnterpriseSearchServiceApplication
	$ssa.UpdateSetting(&apos;Config:qp_MaxResultsReturned&apos;, $newLimit)
	$ssa.Update()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, in order to avoid this exception, you should query to retrieve results in chunks and then merge them. In this way you don&apos;t loose on performance and also you will get your results back without facing this exception.&lt;/p&gt;
&lt;p&gt;Following, I&apos;m calling the GetSearchResults function (defined above) to perform people search query by retrieving results in pages and merging them in a DataTable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
$startIndex = 0
$rowLimit = 50
$siteCollectionUrl = &quot;&amp;lt;Url of the site collection&amp;gt;&quot;
$searchKey = &quot;s*&quot;

$resultCollection = GetSearchResults $siteCollectionUrl $searchKey $startIndex $rowLimit
$hits = $resultCollection.TotalRows
Write-Host Total hits: $hits
$resultsDataTable = $resultCollection.Table

#Iterate through the rest of the pages to fetch items
while($resultCollection.TotalRows -gt $resultsDataTable.Rows.Count)
{
	$sIndex = $resultsDataTable.Rows.Count
	$resultCollection = GetSearchResults $searchKey $startIndex $rowLimit
        $resultsDataTable.Load($resultCollection, [System.Data.LoadOption]::PreserveChanges)
}

# display the results in table format for better view
$resultsDataTable | Format-Table -AutoSize -Property title , url
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hope it helps!&lt;/p&gt;
</content:encoded></item><item><title>Update Personal Site Property in User Profile</title><link>https://sanjaybhagia.com/blog/update-personal-site-property-in-user-profile/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/update-personal-site-property-in-user-profile/</guid><description>PowerShell script to relink the PersonalSpace user profile property when SharePoint loses the connection between users and their personal sites.</description><pubDate>Wed, 06 Mar 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;User Profile has one property called PersonalScope that stores the URL of the personal site of user (if mysite is enabled for users). When user creates personal site, this property is set. Recently we had some problem in our environment with user profile synchronization that removed some of the information for user profiles and Personal Site was one of them. The impact of this was that when affected users navigate to their personal site (&quot;My Content&quot;) they get the message that personal site hasn&apos;t been created yet. On checking the site collections for my site web application in Central Administration, the site collections for users were present. So it was just the linkage that was broken.&lt;/p&gt;
&lt;p&gt;It is as simple as updating the User Profile&apos;s Personal Site property with proper relative URL of the site collection, but if many users are affected then PowerShell is the way to go!&lt;/p&gt;
&lt;p&gt;Here is the scrip that i wrote to fix this linkage. I basically, went through all the site collections (in My Site Web Application) and fetched the user profile for every site and checked if Personal Site is null, simply update it with relative URL.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Add-PSSnapin &quot;Microsoft.SharePoint.PowerShell&quot;

#This function resets the link to personal site for users who have personal site created but the link has been removed from user profile
Function UpdatePersonalSiteLinks($webApplicationUrl)
{
   #Instantiate Web Application Object
   $webApplication = Get-SPWebApplication -Identity $webApplicationUrl
   
   #Create Service Context for User Profile Manager
   $context = Get-SPServiceContext $webApplication.Sites[0]

   #Get User Profile Manager instance
   $profileManager = new-object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
   [Microsoft.SharePoint.SPSecurity]::RunWithElevatedPrivileges(
   {
     #Iterate through site collection in My Site Host web application
     foreach($siteCol in $webApplication.Sites)
     {
          Write-Host &quot;Site: &quot; $siteCol.Url

          #Get the user profile for owner of the personal site
          $uProfile = $profileManager.GetUserProfile($siteCol.Owner.LoginName)

          #Check if user profile has reference to personal site
          if($uProfile.PersonalSite -eq $null)
          {
             #If link has been removed, update the user profile
             Write-Host -ForegroundColor Red &quot;Personal Site is not linked&quot;
             Write-Host -ForegroundColor Green &quot;Updating the link&quot; $siteCol.RootWeb.ServerRelativeUrl

             #update the property (&quot;PersonalSpace&quot;)
             $uProfile[&quot;PersonalSpace&quot;].Value = $siteCol.RootWeb.ServerRelativeUrl
             $uProfile.Commit()
          }
     }
   })
}

UpdatePersonalSiteLinks &quot;http://mysite.local.domain/&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is important to run this script under right context, otherwise it might fail (to fetch the personal sites or updating the user profiles). That is why i have used RunWithElevatedPrivileges, however this might not be sufficient in your environment. So be sure you execute this script with right user credentials.&lt;/p&gt;
</content:encoded></item><item><title>Update list items to trigger event handler through PowerShell</title><link>https://sanjaybhagia.com/blog/update-list-items-to-trigger-event-handler-through-powershell/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/update-list-items-to-trigger-event-handler-through-powershell/</guid><description>PowerShell script that updates every item in a SharePoint list to re-trigger its event handler and push taxonomy values back into user profiles.</description><pubDate>Mon, 25 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Scenario:
A SharePoint list has different content types associated with it and every content type has a field of type taxonomy (connected to managed metadata termstore). And that list has an event handler attached to it that is triggered on item add and item update. In that event handler, you push the change to user profile property (for respective user profile) that is also of type managed metadata. So basically when you add or update an item in the list, that value is written back in a user profile property.&lt;/p&gt;
&lt;p&gt;Now, under normal circumstances everything should work fine as event handler will kick in and write back the values to user property. However, if you have to delete the user profile or due to different reasons, the values in user profile is wiped off etc, you need to ensure that the data already inserted in the list is also present in the user profile.&lt;/p&gt;
&lt;p&gt;Solution:&lt;/p&gt;
&lt;p&gt;For such scenarios, what we need to do is trigger the event handler on every list item so that the value is written back to user profile property. PowerShell comes to our rescue in such situation!&lt;/p&gt;
&lt;p&gt;Here is the powerShell script for that&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
Function UpdateListItems($webAppUrl)
 {
  [Microsoft.SharePoint.SPSecurity]::RunWithElevatedPrivileges(
  {
     #Get Site Collections for respective web applications
     $sitecolls = Get-SPSite -WebApplication $webAppUrl

     Write-Host &quot;Total number of site collections: &quot; $sitecolls.Count

     #Iterate through every site collection to find the list at the root web
     foreach($siteCol in $sitecolls)
     {
        $site = Get-SPSite $siteCol.Url

        Write-Host &quot;Site Collection: &quot; $site.Url
        $rootSite = $site.RootWeb

        Write-Host $rootSite.Name

        #Retrieve the list
        $list = $rootSite.Lists[&quot;ListName&quot;]

        if($list -ne $null)
        {

         # Fetch list items only for required content type (If this needs to execute for every content type,
         # just remove the filter from following statement, just write $listItems = $list.Items)
         $listItems = $list.Items | ?{$_.ContentType.Name -eq &quot;ContentTypeName&quot;}

         foreach($item in $listItems)
         {
           Write-Host $item[&quot;Field&apos;s Dislay Name&quot;]

           #Update the item
           $item.Update()
         }
       }
     }
  })
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now once the function is defined, call it for execution.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
UpdateListItems &quot;http://mysite.mydomain.com&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing to notice in the script above is that we are using RunWithElevatedPrivileges. My Colleague &lt;a href=&quot;http://www.matthiaseinig.de/&quot;&gt;Matthias Einig&lt;/a&gt; has written an amazing &lt;a href=&quot;https://web.archive.org/web/20190824180710/http://www.matthiaseinig.de/2012/12/18/lost-in-impersonation/&quot;&gt;post&lt;/a&gt; on his blog regarding this, do check it out.&lt;/p&gt;
&lt;p&gt;Hope it helps.&lt;/p&gt;</content:encoded></item><item><title>Remove webpart from a page on Personal site using delegate control</title><link>https://sanjaybhagia.com/blog/remove-webpart-from-a-page-on-personal-site-using-delegate-control/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/remove-webpart-from-a-page-on-personal-site-using-delegate-control/</guid><description>Using a delegate control to remove the Recent Blog Posts web part from the default page when SharePoint provisions a user&apos;s personal site.</description><pubDate>Sat, 12 Jan 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Customizing Personal Sites (site collections for users in my site) could be little challenging at times. One reason being that personal site is provisioned automatically by SharePoint and there could be more than one point from which user can provision the site and there is no support to create your own web template or site definition, as we can do with every other type of site (&lt;em&gt;as per my knowledge&lt;/em&gt;). Creating your own web template provides great flexibility and easiness to provision sites  having your own settings and all but lacking this feature for personal sites provide us more challenges, even for small customizations at times. In a recent project, one of the customer&apos;s wish was to remove &quot;Recent Blog Posts&quot; web part from default page when user provisions the personal site.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: After trying out different approaches the final solution turned out to create a delegate control that removes the web part from the page when site is provisioned and having this delegate control added on the site collection through feature stappling.&lt;/p&gt;
So, here is what I did to fulfill this requirement.
&lt;ol&gt;
	&lt;li&gt;Create a delegate control&lt;/li&gt;
&lt;p&gt;Here is the element file for delegate control&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&amp;gt;

 &amp;lt;Control
 ControlAssembly=&quot;MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b848d3ec396f6039&quot;
 ControlClass=&quot;MyAssembly.RemoveWebPartsFromPersonalSiteDefaultPage&quot; Id=&quot;AdditionalPageHead&quot; Sequence=&quot;50&quot;

&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;li&amp;gt;Fetch the desired webpart and remove it&amp;lt;/li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/ol&gt;
and in the code behind file for this delegate control add the functionality to fetch and remove the desired webpart (I&apos;ve added this logic in Render method)
&lt;pre&gt;&lt;code&gt;

//... code removed

//Fetch Web Part title from SPCore resoruce file for current web language
 //It is important to fetch the localed based on current site&apos;s language not based on Browser locale or regional settings!
 var localizedRecentPostWebPartName = SPUtility.GetLocalizedString(&quot;$Resources:spscore,MySiteOnet_WebPart_Blog&quot;, &quot;spscore&quot;, SPContext.Current.Web.Language);

//remove the webpart
 RemoveWebPartsFromWebPartPage(SPContext.Current.Web, &quot;default.aspx&quot;, &quot;MiddleRightZone&quot;, localizedRecentPostWebPartName);

 //add page redirectino logic otherwise it will be an infinite loop
 // ... code removed

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is the definition of RemoveWebPartsFromWebPartPage method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;

//... code removed

using (SP.SPLimitedWebPartManager webpartManager = web.GetLimitedWebPartManager(webPartPage.Url, Web.PersonalizationScope.Shared))
{
  var collection = webpartManager.WebParts;
  List webParts = new List();

  foreach (WebPart webPart in collection)
  {
    if (fromZoneId == webpartManager.GetZoneID(webPart))
    {
      if (webPart.DisplayTitle == webPartTitle)
      {
          webParts.Add(webPart);
      }
    }
  }

 // delete the web parts
 foreach (WebPart webPart in webParts)
 {
   webpartManager.DeleteWebPart(webPart);
 }
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s it! that is the functionality that we need to remove the webpart. We created a delegate control that contains the code to remove the web part from desired page! Now comes the part where we need to execute this delegate. You can use different approaches depending on your requirement. For this demo, we create a simple site scoped feature and add this delegate as an item in that feature.&lt;/p&gt;
&lt;p&gt;Build your solution, create the package and deploy it. Activate the feature. Having this feature activated, as soon as user navigates to the default page, our delegate control will kick in and looks for the desired web part and removes it!&lt;/p&gt;
&lt;p&gt;Other approaches could be creating feature stappling mechanism that attaches our delegate control with desire web templates so that this control is attached to every site that is created.&lt;/p&gt;
Hope it helps!</content:encoded></item><item><title>Adding local variables on a page as a user control</title><link>https://sanjaybhagia.com/blog/adding-local-variables-on-a-page-as-a-user-control/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/adding-local-variables-on-a-page-as-a-user-control/</guid><description>Using a SharePoint user control to emit server-side values as inline JavaScript variables, available on page load without waiting for external scripts.</description><pubDate>Thu, 20 Dec 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Quite often you need to use both server side and client side approach to build SharePoint solution as both offer different level of flexibility and functionality. One of the benefits of using mixed approach is that you can utilize the strength of both approaches and solve the problems quite quickly and efficiently.&lt;/p&gt;
&lt;p&gt;In this post I&apos;m going to present a part of the solution where we had to cache one control during one of the recent projects.&lt;/p&gt;
&lt;p&gt;It is a very common practice that we write separate .js file for our client side scripting and than we can add these file either on a page or on a master page that we can use later on in our controls underneath. This works totally fine but the only thing we need to be careful about external files is that we need to wait for them to load before we can use anything inside these files. That is also fine but in some situations but there might be a little delay until file is loaded and that delay might be of quite a significance.&lt;/p&gt;
&lt;p&gt;To overcome this issue, we (Me and &lt;a href=&quot;http://maghansson.blogspot.com/&quot;&gt;Magnus Hansson&lt;/a&gt;, who is the mastermind of this solution) recently came up with an approach where we actually created a user control and in that user control, we added some script to set some local variables that we needed to use in on our page.&lt;/p&gt;
&lt;p&gt;Here is the markup of the user control (ascx control):&lt;/p&gt;
&lt;p&gt;Markup:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
var Local = window.Local || {};
   Local.Variables = function () {
     return {
        currentRootWebUrl : &apos;&amp;lt;asp:Literal runat=&quot;server&quot; id=&quot;litRootWebUrl&quot; /&amp;gt;&apos;,
        currentWebUrl : &apos;&amp;lt;asp:Literal runat=&quot;server&quot; id=&quot;litCurrentWebUrl&quot; /&amp;gt;&apos;,
        currentUser : &apos;&amp;lt;asp:Literal runat=&quot;server&quot; id=&quot;litCurrentUser&quot; /&amp;gt;&apos;,
        currentLCID : &apos;&amp;lt;asp:Literal runat=&quot;server&quot; id=&quot;litCurrentLCID&quot; /&amp;gt;&apos;
       }
} ();
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and in the CodeBehind(.cs) we set these asp controls embedded in script above:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
protected override void CreateChildControls()
{
      //Get current user&apos;s Web object and Root Web Object
      SPWeb currentWeb = SPContext.Current.Web;
      SPWeb currentRootWeb = currentWeb.Site.RootWeb;

      //Get Locale and user&apos;s login name
      litCurrentLCID.Text = SPContext.Current.Web.CurrencyLocaleID.ToString();
      litCurrentUser.Text = SPContext.Current.Web.CurrentUser.LoginName;
      litCurrentWebUrl.Text = currentWeb.Url;
      litRootWebUrl.Text = currentRootWeb.Url;

      base.CreateChildControls();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So what we have achieved so far is basically set of variables that are set from code behind in control. When executed, the output would be a JavaScript object named &quot;Local&quot; that has a public property called &quot;Variables&quot; that contains some more properties.&lt;/p&gt;
&lt;p&gt;Now in order to see this, we need to add this control either on application page or master page (or any where you find it appropriate in your case).&lt;/p&gt;
&lt;p&gt;We added in on Master Page as we needed to used this on a control inside master page. In order to add it on a master page, you can directly Register your user control on master page and then added reference to the control in header section or even create a delegate control to attach it with master page through feature.&lt;/p&gt;
&lt;p&gt;Once, control is added, navigate to your site and see the browser output. You should find this section rendered in the view source:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
var Local = window.Local || {};

Local.Variables = function () {

return {
    currentRootWebUrl : &apos;http://demo.local.com&apos;,
    currentWebUrl : &apos;http://demo.local.com/site/hr&apos;,
    currentUser : &apos;domain\\user1&apos;,
    currentLCID : &apos;1033&apos;
  }

} ();

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now as soon as DOM is loaded, you have your local variables present that you can use right away in your control further down in the DOM (or controls etc) without waiting for any other JavaScript file to load like following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
    var currentRootWebUrl = Local.Variables.currentRootWebUrl;
    var currentWebUrl = Local.Variables.currentWebUrl;
&lt;/code&gt;&lt;/pre&gt;</content:encoded></item><item><title>AllowEveryoneViewItems - Enable anonymous access to files in list</title><link>https://sanjaybhagia.com/blog/alloweveryoneviewitems-enable-anonymous-access-to-files-in-list/</link><guid isPermaLink="true">https://sanjaybhagia.com/blog/alloweveryoneviewitems-enable-anonymous-access-to-files-in-list/</guid><description>How the AllowEveryoneViewItems property makes documents and attachments in a SharePoint list anonymously accessible, set via PowerShell, XML or code.</description><pubDate>Wed, 12 Dec 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;SharePoint provides anonymous access to sites and document libraries etc but for that you have to set up the policy at web application level and then for specific site or document library as per your needs. But at times you don&apos;t want to allow anonymous access for entire web application or site collection but simply want to provide access to files within a specific document library without going through the trouble of configuring and managing permissions.&lt;/p&gt;
&lt;p&gt;If you want to access documents within a document library or files in a list (as an attachment) there is one quick and easy way to do that.&lt;/p&gt;
&lt;p&gt;There is a list property called &lt;em&gt;AllowEveryoneViewItems&lt;/em&gt; that makes all documents within a document library anonymously accessible without dealing with permissions. There is no option in UI to set this up so you have to either do it through code, declaratively (list definition element.xml) or Powershell (depending on your situation and need).&lt;/p&gt;
Here is the PowerShell code for setting this property on any list or library
&lt;pre&gt;&lt;code&gt;
$web = Get-SPWeb -Identity &quot;[site url]&quot;
$list = $web.Lists.TryGetList(&quot;[list title]&quot;);
$list.AllowEveryoneViewItems = $true
$list.Update()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is how you define in list definition xml:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;!--?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?--&amp;gt;

	&amp;lt;ListTemplate
		Name=&quot;[list name]&quot;
		DisplayName=&quot;[list display name]&quot;
		Description=&quot;[list description]&quot;
		Type=&quot;10000&quot;
		BaseType=&quot;0&quot;
		Default=&quot;True&quot;
		VersioningEnabled=&quot;TRUE&quot;
		Hidden=&quot;FALSE&quot;
                AllowEveryoneViewItems=&quot;TRUE&quot;
		HiddenList=&quot;FALSE&quot; /&amp;gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is how you can do it using code&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
using (SPSite site = new SPSite(&quot;[site collection url]&quot;))
{
   using (SPWeb web = site.OpenWeb())
   {
       SPList list = rootWeb.Lists.TryGetList(&quot;[list title]&quot;);
       if (list != null)
       {
          if (!list.AllowEveryoneViewItems)
          {
             list.AllowEveryoneViewItems = true;
             list.Update();
          }
       }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is important to note here that this property does not apply to all list items, but only to documents in document libraries or to attachments in list items. So you have to access this file directly for it to work ! (reference: &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splist.alloweveryoneviewitems.aspx&quot; target=&quot;_blank&quot;&gt;SPList.AllowEveryoneViewItems property&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Here is the code snippet for accessing the file directly using HttpWebRequest&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
var fileContent = String.Empty;
//construct path to the navigation file
string fileUrl = &quot;[full url of the file]&quot;;

//create webrequest to fetch this file!
var httpRequest = (HttpWebRequest)WebRequest.Create(fileUrl);
using (var webResponse = (HttpWebResponse)httpRequest.GetResponse())
{
   if (webResponse.StatusCode == HttpStatusCode.OK)
   {
      using (var responseStream = new StreamReader(webResponse.GetResponseStream()))
      {
          //if we get the response, read the content from file as string
          fileContent = responseStream.ReadToEnd();
      }
   }
}
&lt;/code&gt;&lt;/pre&gt;</content:encoded></item></channel></rss>