Understanding Azure Durable Functions

In this post I would like to share a simple Azure Durable Function which will perform Simple Return Value along with some Timer Delays.

Function Replays

As you are aware Functions undergo multiple Replays which may require aligning your code as well. 

context.IsReplaying property says whether it is a replay.

The Code

The code ensures there is a 2 minute delay between sections.

namespace DurableFunctionTest
{
     public static class Function1
     {
         [FunctionName(“Function1_HttpStart”)]
         public static async Task<HttpResponseMessage> HttpStart(
             [HttpTrigger(AuthorizationLevel.Anonymous, “get”, “post”)]HttpRequestMessage req,
             [OrchestrationClient]DurableOrchestrationClient starter,
             ILogger log)
         {
             // Function input comes from the request content.
             string instanceId = await starter.StartNewAsync(“Function1”, null);

            log.LogInformation($”Started orchestration with ID = ‘{instanceId}’.”);

            return starter.CreateCheckStatusResponse(req, instanceId);
         }

        [FunctionName(“Function1”)]
         public static async Task<List<string>> RunOrchestrator(
             [OrchestrationTrigger] DurableOrchestrationContext context)
         {
             var outputs = new List<string>();

            outputs.Add(await context.CallActivityAsync<string>(“Function1_Hello”, “London”));

            return outputs;
         }

        [FunctionName(“Function1_Hello”)]
         public static string SayHello([ActivityTrigger] string name, ILogger log)
         {
             log.LogInformation($”step 1 {DateTime.Now.ToLongTimeString()}”);
             Thread.Sleep(2 * 60 * 1000); // 2min

            log.LogInformation($”step 2 {DateTime.Now.ToLongTimeString()}”);
            Thread.Sleep(2 * 60 * 1000); // 2min

            log.LogInformation($”step 3 {DateTime.Now.ToLongTimeString()}”);
             Thread.Sleep(2 * 60 * 1000); // 2min

            log.LogInformation($”step 4 {DateTime.Now.ToLongTimeString()}”);
             Thread.Sleep(2 * 60 * 1000); // 2min

            return $”Hello {name} !”;
         }
     }
}

The Output

2/10/2020 6:38:10 PM] 352ff6a310684f6eba4274bb81a54220: Function ‘Function1_Hello (Activity)’ started. IsReplay: False. Input: (40 bytes). State: Started. HubName: DurableFunctionsHub. AppName: . SlotName: . ExtensionVersion: 1.8.2. SequenceNumber: 9.
[2/10/2020 6:38:10 PM] Executing ‘Function1_Hello’ (Reason=”, Id=7f616c57-f299-4f9c-91ec-75feaa180893)
[2/10/2020 6:38:10 PM] step 1 1:38:10 PM
[2/10/2020 6:38:13 PM] Host lock lease acquired by instance ID ‘000000000000000000000000FE3C5631’.
[2/10/2020 6:40:08 PM] step 2 1:40:08 PM
[2/10/2020 6:40:10 PM] step 2 1:40:10 PM
[2/10/2020 6:40:10 PM] step 2 1:40:10 PM
[2/10/2020 6:42:08 PM] step 3 1:42:08 PM
[2/10/2020 6:42:10 PM] step 3 1:42:10 PM
[2/10/2020 6:42:10 PM] step 3 1:42:10 PM
[2/10/2020 6:44:08 PM] step 4 1:44:08 PM
[2/10/2020 6:44:10 PM] step 4 1:44:10 PM
[2/10/2020 6:44:10 PM] step 4 1:44:10 PM
[2/10/2020 6:46:08 PM] Executed ‘Function1_Hello’ (Succeeded, Id=02c78620-a573-4ffa-9f62-0aac2333ceaf)

The Inference

As you can see, although the Function replayed multiple times, but the restart was not loosing any time, it was accurate enough to replay from the past exit point.

Notes

Break your code into multiple chunks

Ensure transactions are protecting the Atomicity.

Azure Migrate, Azure Site Recovery, Azure Database Migration Service & Disaster Recovery

For migrating on-premise applications to Azure, following tools are available to help you:

  1. Azure Migrate
  2. Azure Site Recovery
  3. Azure Database Migration Service

Planning Phase

Before migrating to Azure, you will have to do a Planning on your existing applications, technologies, hosting methodologies & their corresponding equivalent in Azure.

Azure Migrate

Azure Migrate is a free service which will help in discover, assess & migrate on-premise systems to Azure.

Azure Migrate can do the Assessment with following steps:

  • Configure Appliance on Server
  • Run Agents on each VM
  • Create Assessment

Azure Site Recovery

Azure Site Recovery is a Disaster Recovery strategy which can also be used to Migrate On-Premises VM to Azure.

Database Migration Service

Database Migration Service helps to asses the Compatibility of source database against destination Azure database & Also migrate the data.

Disaster Recovery

Business Continuity and Disaster Recovery is Essential to prevent Revenue Loss & Maintaining SLAs of businesses.  Azure provides Disaster Recovery through Azure Site Recovery strategy.

For the same, one has to understand RTO & RPO during a disaster:

  • Recovery Time Objective (RTO) is maximum time business can survive until service restoration
  • Recovery Point Objective (RPO) is maximum data business can loose until service restoration

Azure Site Recovery is an important tool for Disaster Recovery & Business Continuity.  ASR will replicate workloads from primary site to secondary site during a disaster.  Replication can happen:

  • From VM to Azure
  • From Azure Region to another Azure region

Note

Failover is the process of switching service from primary to secondary during disaster. 

Failback is the process of switching service back to primary when it is recovered.

HADR – High Availability Disaster Recovery

BCDR – Business Continuity Disaster Recovery

Azure Active Directory–How to protect a Web Application without Code

In this post I would be demonstrating how to protect a web site without any code changes.

Advantages

  • High Protection Web Site will not serve any html, js, css files without Authentication  (MSAL protection causes few MSAL JS to be served to do authentication – this may be restricted by Information Security groups of Enterprise class customers)
  • Same Code can be deployed multiple places as the Authentication pieces being decoupled

Create Web Application

Create a web application of ASP.NET or Angular.

Publish to Azure

Publish to Azure so that an App Service is created.

Set the Authentication

image

Test the Application

Now you can test the application & the login prompt happens.

Note

In the background the App Service is adding Redirect URL

https://working-angular-webapi.azurewebsites.net/.auth/login/aad/callback

Client Side Applications

For client side applications, you can always refer the following URL to get the current ID Token for the Authenticated User.  It can also be used as Access Token as the Audience is same as Client ID.

https://working-angular-webapi.azurewebsites.net/.auth/me


Summary

In this post we have seen how to do No Code protection of web application using Azure Active Directory.

Azure AD Search using C#

In this post I would like to give a Sample to Search on Azure Active Directory using Filter.

Pre-Requisites

Following are the pre-requisites:

  • Create AD > App Registration & Client Credentials
  • Assign Directory.Read.All “application” permission & Provide Admin Consent

The Code

private async static void SerachAzureAD(string search)
        {
                string clientID = “YOUR-CLIENT-ID”;
                string clientSecret = “YOUR-CLIENT-SECRET”;
                string tenantID = “YOUR-AD-TENANT-ID”;

               string graphApiResource = “https://graph.microsoft.com”;
                Uri microsoftLogin = new Uri(“https://login.microsoftonline.com/”);

               string authority = new Uri(microsoftLogin, tenantID).AbsoluteUri;
                AuthenticationContext authenticationContext = new AuthenticationContext(authority);
                ClientCredential clientCredential = new ClientCredential(clientID, clientSecret);

               // Picks up the bearer token.
                AuthenticationResult authenticationResult = authenticationContext.AcquireTokenAsync(graphApiResource, clientCredential).Result;

               GraphServiceClient graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(
                async (requestMessage) =>
                {
                    requestMessage.Headers.Authorization = new AuthenticationHeaderValue(“bearer”, authenticationResult.AccessToken);
                }));

               string filter = $”startswith(displayName, ‘{search}’) or startswith(givenName, ‘{search}’) or startswith(surname, ‘{search}’) or startswith(mail, ‘{search}’) or startswith(userPrincipalName, ‘{search}’)”;
                //$”$filter=displayName EQ {search}”;

               IGraphServiceUsersCollectionPage users = graphClient.Users.Request()
                    .Filter(filter)
                    .GetAsync().Result;

               Console.WriteLine(“Searching..”);

               while (users.Count > 0)
                {
                    foreach (var user in users.CurrentPage)
                    {
                        Console.WriteLine(user.DisplayName);
                    }

                   if (users.NextPageRequest != null)
                    {
                        users = await users.NextPageRequest
                            .GetAsync();
                    }
                    else
                    {
                        break;
                    }
                }

        }

Result

image

Summary

In this post we have seen how to do Azure Active Directory Search using C# & Search Filters.

Azure Active Directory Error – Code: Authorization_RequestDenied

While working with Azure Active Directory, I encountered following error on code below:

            string clientID = “970a3de9-6714-4a1e-81b7aaaa”;
             string clientSecret = “I0ieHQ3.8DCQ3HX.RkVEbc:u_dddd”; .
                 string tenantID = “0f0a4aac-8998-4f49-8a17-eeeee”;

            string resourceID = “https://graph.microsoft.com”;
             Uri loginURI = new Uri(“https://login.microsoftonline.com/”);

            // Bearer Token
             string authority = new Uri(loginURI, tenantID).AbsoluteUri;
             AuthenticationContext authenticationContext = new AuthenticationContext(authority);
             ClientCredential clientCredential = new ClientCredential(clientID, clientSecret);
             AuthenticationResult authenticationResult = authenticationContext.AcquireTokenAsync(resourceID, clientCredential).Result;

             IGraphServiceUsersCollectionPage users = new GraphServiceClient(new DelegateAuthenticationProvider(
                 async (requestMessage) =>
                 {
                     requestMessage.Headers.Authorization = new AuthenticationHeaderValue(“Bearer”, authenticationResult.AccessToken);
                 })).Users.Request().GetAsync().Result;

Error displayed below

["System.AggregateException: One or more errors occurred.

(Code: Authorization_RequestDenied\r\nMessage: Insufficient privileges to complete the operation.

Inner error:AdditionalData:\r\n\trequest-id: 22ffcc47-67bd-4ad6-9558-66581d8b0734

---> Microsoft.Graph.ServiceException: Code: Authorization_RequestDenied

Message: Insufficient privileges to complete the operation.\r\nInner error:

AdditionalData:\r\n\trequest-id: 22ffcc47-67bd-4ad6-9558-66581d8b0734\r\n\tdate: 2020-01-07T16:52:11\r\nClientRequestId: 22ffcc47-67bd-4ad6-9558-66581d8b0734\r\n\r\n at Microsoft.Graph.HttpProvider.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)\r\n at Microsoft.Graph.BaseRequest.SendRequestAsync(Object serializableObject, CancellationToken cancellationToken, HttpCompletionOption completionOption)\r\n at Microsoft.Graph.BaseRequest.SendAsync[T](Object serializableObject, CancellationToken cancellationToken, HttpCompletionOption completionOption)\r\n at Microsoft.Graph.GraphServiceUsersCollectionRequest.GetAsync(CancellationToken cancellationToken)\r\n --- End of inner exception stack trace ---\r\n at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)\r\n at AzureADPassPOC.Controllers.ValuesController.Get() in C:\\Programs\\AzureADPassPOC\\AzureADPassPOC\\Controllers\\ValuesController.cs:line 45\r\n---> (Inner Exception #0) Status Code: Forbidden\r\nMicrosoft.Graph.ServiceException: Code: Authorization_RequestDenied\r\nMessage: Insufficient privileges to complete the operation.\r\nInner error:\r\n\tAdditionalData:\r\n\trequest-id: 22ffcc47-67bd-4ad6-9558-66581d8b0734\r\n\tdate: 2020-01-07T16:52:11\r\nClientRequestId: 22ffcc47-67bd-4ad6-9558-66581d8b0734\r\n\r\n at Microsoft.Graph.HttpProvider.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)\r\n at Microsoft.Graph.BaseRequest.SendRequestAsync(Object serializableObject, CancellationToken cancellationToken, HttpCompletionOption completionOption)\r\n at Microsoft.Graph.BaseRequest.SendAsync[T](Object serializableObject, CancellationToken cancellationToken, HttpCompletionOption completionOption)\r\n at Microsoft.Graph.GraphServiceUsersCollectionRequest.GetAsync(CancellationToken cancellationToken)<---\r\n"]

Solution

Enable Directory.ReadAll permission on Graph

Open Portal > Active Directory > App Registration > API Permissions blade

image

Choose Application Permissions > Graph API > Directory.ReadAll

image

image

Save changes & Run the code again.

The error should disappear.

Data Classification & Storage

Application Data can be classified into 3 ways:

  • Structured
  • Semi-Structured
  • Unstructured

Structured Data

Relational Data with Columns & Data Types.

Example: Financial Statements

Apt for SQL Server

Semi-Structured Data

Dynamic Columns with No pre-defined Data Types.

Example: Product Catalog

Apt for Cosmos DB

Unstructured Data

Files such as Images & Videos

Apt for BLOB Storage.

More Parameters

Following are more parameters which determine the storage of data.

Data Location

The location where data is stored like East-US, West-Europe etc..  In case of Data Compliance rules which demand Data should not cross country-boundaries more stringent location choice is required.

Data Redundancy

Data Redundancy ensures data will be copied to alternative location.  This is useful on disaster recovery scenarios.

VNETs

In case if the Data contains Proprietary Information – we can enforce restricted VNET (Virtual Network) Only access to the data.

Data Encryption

Data Encryption can be applied on Rest & Transit.  Encryption on Rest is supported by TDE (Transparent Data Encryption) of Azure SQL and Encryption by CosmosDB, Storage Accounts etc.  Encryption on Transit is provided by HTTPS enable.

Storage Accounts

Storage Accounts allows grouping of data management through blobs, files, tables & queues

Create VNET & VNET Peering in Azure using CLI

In this post we can learn how to create 2 VNET & enable VNET Peering between both.

Azure VNET

Azure VNET allows private network within Azure.  VNET should specify an Address Space.  VNET creates Subnets which are Segments within the Address Space.

VNET Peering

It is possible for 2 VNETs to communicate with each other using VNET Peering.  VNET Peering bypasses Internet, Public IP Addresses & Communicate with the Local Azure Network which is faster & higher bandwidth without any encryption.  Thus the VNET Peering is faster & safer too.

VNET allows Resources (eg: VMs) communicate with each other as if they are in the same network.

VNET can be configured across regions & subscriptions too.

image

Create VNET

Open Azure CLI command interface & Run the following commands.

az login

az network vnet create –resource-group “jp_azure” –name VNET1 –address-prefix 10.1.0.0/16 –subnet-name Apps –subnet-prefix 10.1.1.0/24 –location eastUS

az network vnet create –resource-group “jp_azure” –name VNET2 –address-prefix 10.1.0.0/16 –subnet-name Apps –subnet-prefix 10.1.1.0/24 –location eastUS

az network vnet list –output table

Create VMs

Now we can create VM in each of the VNETs.

az vm create \ –resource-group “jp_azure” \ –no-wait \ –name VM1 \ –location northeurope \ –vnet-name VNET1 \ –subnet Apps \ –image win2016datacenter \ –admin-username admin \ –admin-password administrator1!

az vm create \ –resource-group “jp_azure” \ –no-wait \ –name VM2 \ –location northeurope \ –vnet-name VNET2 \ –subnet Apps \ –image win2016datacenter \ –admin-username admin \ –admin-password administrator1!

Create VNET Peering

Now we can create VNET Peering using the following commands.

az network vnet peering create \ –name VNET1-TO-VNET2 \ –remote-vnet VNET1 \ –resource-group JP-Resource \ –vnet-name VNET2 \ –allow-vnet-access

Following is for reciprocal connection.

az network vnet peering create \ –name VNET2-TO-VNET1 \ –remote-vnet VNET2 \ –resource-group JP_azure \ –vnet-name VNET1 \ –allow-vnet-access

Testing

Login to the VM1 using Public IP and Ping to the VM2 using Private IP.  If the connection succeeded it means the VNET Peering was created successfully.

Summary

In this post we have explored how to create 2 VNET & enable VNET Peering between both.