Saturday 15 September 2018

Create Azure Durable Functions which includes Orchestrator Function and Activity Function - Part 2

In this post we are going to see the implementation of  Durable Function which includes Orchestrtor Function and Activity Function

Please click on the below link for the Azure Durable Function source code
AzureDurableFunctions Source Code


We will take a scenario, inside the Orchsetrator Function, we will call two Activity Function, one Activity function returns the books list and second activity will save the books list to the Azure Table Storage.

1. Create a New Project
2. Select cloud in the left pane
3. Select Azure Functions in the right pane.
4. Give Azure Function name as "BookFunction" and click ok.



5. Select the HttpTrigger from the menu
6. Click ok




7. Install the following nuget package in the solution

Microsoft.Azure.WebJobs.Extensions.DurableTask




8. Change the input parameter for the function. add the OrchestrationClient Attribute with     
    DurableOrchestrationClient

[OrchestrationClient]DurableOrchestrationClient starter,



9. TestFunction.cs
******************


public static class TestFunction
    {
        [FunctionName("TestFunction")]
        public static async Task<HttpResponseMessage> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post",
                         Route = null)]HttpRequestMessage req,
            [OrchestrationClient]DurableOrchestrationClient starter,
            TraceWriter log)
        {
            log.Info("C# HTTP trigger function processed a request.");
            // Function input comes from the request content.
            string instanceId = await starter.StartNewAsync("Orchestrator", "TedTalk");

            log.Info($"Started orchestration with ID = '{instanceId}'.");
               
            return starter.CreateCheckStatusResponse(req, instanceId);
        }       
        

    }


Let we start the Program for Azure Durable Functions. From the above code you can see that we are calling a durable function Orchestrator  await starter.StartNewAsync("Orchestrator""TedTalk");


10. Add another Function named it as OrchestratorFunction , It is decorated by [OrchestrationTrigger] with DurableOrchestrationContext, Now if you see inside the function we are calling two Activity function named "GetAllData" and "SaveData"

OrchestratorFunction.cs
*********************************


    public class OrchestratorFunction
    {
        [FunctionName("Orchestrator")]
        public static async Task<string> RunOrchestrator([OrchestrationTrigger]
                 DurableOrchestrationContext context)
        {
            var name = context.GetInput<string>();

            // retrieves the list of data by invoking a separate Activity Function.
            var books = await context.CallActivityAsync<List<Book>>("GetAllData", name);
            if (books.Count > 0)
            {
                //Saving the retrieved data to table
                await context.CallActivityAsync("SaveData", books);
            }
            return context.InstanceId;
        }

    }



11. Add another Function named it as ActivityFunction, It is decorated by [ActivityTrigger] with DurableActivityContext, Now create two functions inside the file one is for "GetAllData" another one is for "SaveData", This two activity functions are called inside orchestration function.

GetAllData: This activity function will return the list of books
SaveData: This activity function will save the books list to Azure Table Storage.




ActivityFunction.cs
******************************


public static class ActivityFunction
    {
        private static CloudStorageAccount account = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("AzureWebJobsStorage",                                    EnvironmentVariableTarget.Process));

        
        [FunctionName("GetAllData")]
        public static async Task<List<Book>> GetAllData( 
                            [ActivityTrigger]DurableActivityContext context)
        {
            // retrieves the book name from the Orchestrator function
            var organizationName = context.GetInput<string>();

            return new List<Book> { new Book{ Id = 1, Name = "C#" }, 
                                    new Book{ Id = 2, Name = "Java" } };
        }



        [FunctionName("SaveData")]
        public static async Task SaveData([ActivityTrigger]DurableActivityContext context)
        {
            // retrieves a list of books from the Orchestrator function
            var books = context.GetInput<List<Book>>();

            // create a table storage client
            var client = account.CreateCloudTableClient();
            var table = client.GetTableReference("Books");

            await table.CreateIfNotExistsAsync();

            TableBatchOperation tableBatchOperations = new TableBatchOperation();

            for(int i=0; i<books.Count; i++)
            {
                tableBatchOperations.Add(TableOperation.InsertOrMerge(
                    new BookRepository(books[i].Id)
                    {
                        Name = books[i].Name
                    }));
            }

            await table.ExecuteBatchAsync(tableBatchOperations);

        }
    }

    public class BookRepository: TableEntity
    {
        public BookRepository(int id)
        {
            PartitionKey = "TechnicalBooks";
            RowKey = id.ToString();
        }

        public string Name { set; get; }
    }

    public class Book
    {
        public int Id { get; set; }

        public string Name { get; set; }


    }


Now change values in the local.settins.json for AzureWebJobsStorage to connect the azure table storage.

{
    "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "AzureWebJobsDashboard": "UseDevelopmentStorage=true"
  }

}



12. Now run the application, it will results in display the window like below




13. In the console Windows you can see the http url to hit the function, copy that url and paste that in browser. Now Orchestrator Function will be hit and two Activity Functions will be executed.




14. You see the Azure table storage , you can see the data populated from activity function.




Full source code:
*******************
Please click on the below link for the Azure Durable Function source code

AzureDurableFunctions Source Code


From this post you can learn how to use the Azure Durable Functions which includes Orchestrator Function and Activity Function.

Create Azure Durable Functions which includes Orchestrator Function and Activity Function - Part 1

In this post we are going to see how to create a Azure Durable Functions that includes the Orchestrator Function and Activity Function.

Azure Durable Functions is a new model based on Serverless platform Azure Functions. It allows you to write the workflow as code. It introduces more concepts that make developing complex workflow easy.

Azure Functions allows you to pay for what you use. A Serverless function is a unit of work which consists of a method from a static class.


public static class TestFunction
{
    [FunctionName("FirstFunction")]
    public void FirstFunction()
    {
       
    }

}


Orchestrator Function:
**********************************
An Orchestrator is an Azure function with specific behavior attached to them. it automatically set the checkpoint during its execution. Orchestrator Function is a function with an OrchestrationTrigger  on a DurableOrchestrationContext parameter.


[FunctionName("Orchestrator")]
public static async Task Orchestrator([OrchestrationTrigger] DurableOrchestrationContext context)
{
    return context.InstanceId;

}


It is invoked by DurableOrchestrationClient decorated by OrchestrationClient Attribute injected with in the ordinary function with any trigger.

[FunctionName("TimerTrigger")]
public static void TimerTrigger([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, [OrchestrationClient]DurableOrchestrationClient starter)
{
    // Function input comes from the request content.
    string instanceId = await starter.StartNewAsync("Orchestrator", null);
    /* ... */

}


Activity Function
************************
Not every function will be used with an orchestrator function, only ActivityFunction which are decorated by ActivityTrigger with DurableActivityContext parameter can be used inside Orchestration Function

[FunctionName("Activity1")]
public static async Task<string> Activity([ActivityTrigger] DurableActivityContext context)
{
    /* ... */

}


Calling the Activity function "Activity1" inside the Orchestrator Function

[FunctionName("Orchestrator")]
public static async Task Orchestrator([OrchestrationTrigger] DurableOrchestrationContext context)
{
    await context.CallActivityAsync<string>("Activity1", name);
    return context.InstanceId;

}




From this post you can learn more about Azure Durable Function which includes Orchestrator Function and Activity Function. we will see the implementation of this Durable Function in the Part 2 of this post

































Intercept the HttpRequest for create a custom authentication using AuthenticationMiddleware Owin in WebApi


In this post we are going to see how to intercept HttpRequest for create a custom authentication using AuthenticationMiddleware owin in WebApi. For this we will take scenario like Pin based token authentication. For example users have to send the following header in each request for validate

Header Name: x-token-auth

This header must contain a value of pin token, that must be greater than 10000 for authorize, if it is less then we will state it as unauthorized.

Sample:
*********
x-token-auth: token|50000

In my previous post we did same kind of authentication using OwinMiddleware, Now we are going to do that using AuthenticationMiddleware Link for the previous post Create custom authentication using Owin Middleware


Steps to follow:
****************

  1. Create a class PinBasedAuthenticationOptions derive from AuthenticationOptions
  2. Create a middleware derive from AuthenticationMiddleware<PinBasedAuthenticationOptions>
  3. Create a Handler derive from AuthenticationHandler<PinBasedAuthenticationOptions>
  4. Create a another middleware derive from OwinMiddleware.
  5. Create a extension method which is used to map the middleware in the HttpRequest.
  6. Call the extension method in the startup.cs

Step 1:
********
Create a class PinBasedAuthenticationOptions derive from AuthenticationOptions and set the authentication type as PinBased_Token

public class PinBasedAuthenticationOptions : AuthenticationOptions
{
  internal const string Authentication_Type = "PinBased_Token";       

  public PinBasedAuthenticationOptions() : base(Authentication_Type)
  {
  }
}



Step 2:
********
Create a middleware derive from AuthenticationMiddleware<PinBasedAuthenticationOptions> we have to create a second parameter in the constructor which takes input param as PinBasedAuthenticationOptions and that constructor should be public.


    public class PinBasedMiddleware :                 
             AuthenticationMiddleware<PinBasedAuthenticationOptions>
    {
       public PinBasedMiddleware(OwinMiddleware next, PinBasedAuthenticationOptions options)           : base(next, options)
        {
        }

        protected override AuthenticationHandler<PinBasedAuthenticationOptions>                      CreateHandler()
        {
            return new PinAuthenticationHandler();
        }
    }



Step 3:
********
Create a Handler derive from AuthenticationHandler<PinBasedAuthenticationOptions>, Here in this handler we are checking the Request headers for the PinBased token if it is authorized then populate the ClaimsIdentity in the AuthenticationTicket, This will internally populate the user object in the Request.


public class PinAuthenticationHandler : AuthenticationHandler<PinBasedAuthenticationOptions>
    {
        public PinAuthenticationHandler()
        {
        }

        protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
        {           
            AuthenticationProperties properties = new AuthenticationProperties();
            var authenticationResult = new AuthenticationTicket(null, properties);
            bool authorised =  IsAuthorised(Request.Headers);
            if(authorised)
            {
                IEnumerable<Claim> claimCollection = new List<Claim>
                {
                    new Claim(ClaimTypes.NameIdentifier,"123456"),
                    new Claim(ClaimTypes.Country, "India"),
                    new Claim(ClaimTypes.Gender,"Male"),
                    new Claim(ClaimTypes.Email,"test@gmail.com"),
                    new Claim(ClaimTypes.Role, "SA"),
                    new Claim(ClaimTypes.Sid,Guid.NewGuid().ToString())
                };
      ClaimsIdentity claimsIdentity = new ClaimsIdentity(claimCollection,"Pin_Based");
      authenticationResult = new AuthenticationTicket(claimsIdentity, properties);                
            }
            return await Task.Run(() => authenticationResult);           
        }


        private bool IsAuthorised(IHeaderDictionary requestHeaders)
        {
          string []pinValues;
          bool pinHeaderPresent = requestHeaders.TryGetValue("x-token-auth", out pinValues);
            if (pinHeaderPresent)
            {
                string[] valuesInHeader = pinValues.ToList()[0].Split(new char[] { '|' }, 
                                              StringSplitOptions.RemoveEmptyEntries);
                if (valuesInHeader.Length == 2)
                {
                    int pin;
                    if (int.TryParse(valuesInHeader[1], out pin))
                    {
                        if (pin >= 10000)
                        {
                            return true;
                        }
                    }
                }
            }

            return false;
        }

    }




Step 4:
********
Create a another middleware derive from OwinMiddleware.In this middleware we are checking whether user object in the request is populated or not, if it is not populated then we are setting the StatusCode for response as UnAuthorized.

    public class PinBasedPostAuthenticationMiddleware : OwinMiddleware
    {
        public PinBasedPostAuthenticationMiddleware(OwinMiddleware next) : base(next)
        {
        }

        public override async Task Invoke(IOwinContext context)
        {
            if (context.Request.User == null)
            {
                context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            }
            else
            {
                await Next.Invoke(context);
            }
        }
    }


Step 5:
********
Create a extension method which is used to map the middleware in the HttpRequest. Here in this extension method we are using the middleware based on the pipeline stage, so middleware will run stage by stage , one by one.


    public static class PinAuthenticationExtension
    {
        public static void UsePinBasedAuthentication(this IAppBuilder builder)
        {
            builder.MapWhen((context) => true, (app) =>
               {
                   app.Use<PinBasedMiddleware>(new PinBasedAuthenticationOptions());
                   app.UseStageMarker(PipelineStage.Authenticate);

                   app.Use<PinBasedPostAuthenticationMiddleware>();
                   app.UseStageMarker(PipelineStage.PostAuthenticate);
               });            
        }
         }


Step 6:
********
Call the extension method in the startup.cs

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UsePinBasedAuthentication();
        }       
    }



Controller:
***********
public class ValuesController : ApiController
    {
        // GET api/values
        public IHttpActionResult Get()
        {           
            var data = new string[] { "value1""value2" };
            return Ok(data);
        }

        // GET api/values/5
        public string Get(int id)
        {
            var data = "Rajesh";
            return data;
        }

        // POST api/values
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
        }
       
    }


Output:
**********

Make a call to the endpoint with pin value less than 10000 using postman will result in UnAuthorized






Make a call to the endpoint with pin value greater than 10000 using postman will result in success authentication




From this post you can learn how to intercept the HttpRequest for create a custom authentication using AuthenticationMiddleware Owin in WebApi