Wednesday, 12 June 2019

Create a simple Retry Policy by using Polly in any fault.

Polly a .NET fault-handling wrapper that allows developers to express policies in thread safe manner.
Policies could be made over:

  • Retry
  • Circuit Breaker
  • Timeout
  • Bulkhead Isolation
  • Fallback.

More: <https://github.com/App-vNext/Polly

Simple Demo:

using Polly;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
 
namespace PollyRetry
{
 
    class Program
    {
        static void Main(string[] args)
        {
            HttpRequestDemo();
            Console.WriteLine("Done!");
            Console.ReadLine();
        }
 
        private static void HttpRequestDemo()
        {
 
 
            HttpStatusCode[] httpStatusCodesWorthRetrying = {
                HttpStatusCode.RequestTimeout, // 408
                HttpStatusCode.InternalServerError, // 500
                HttpStatusCode.BadGateway, // 502
                HttpStatusCode.ServiceUnavailable, // 503
                HttpStatusCode.GatewayTimeout, // 504
                HttpStatusCode.NotFound // 404
            };
 
            var httpRetryPolicy = Policy.HandleResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
            .OrResult(r => r.StatusCode == HttpStatusCode.BadGateway)
            .WaitAndRetry(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (extime) =>
            {
                Console.WriteLine($"Unable to complete operation after {time.TotalSeconds:n1}s ({ex.Result.StatusCode})");
            });
 
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:51976/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                var response = httpRetryPolicy.ExecuteAndCapture(() =>
                {
                    return client.GetAsync("api/order").Result;
                }).FinalHandledResult;
 
                if (response != null && response.IsSuccessStatusCode)
                {
                    Console.WriteLine("Got valid response from API");
                }
            }
 
 
        }
    }
}


We can also create multiple policy to handle multiple faults, like server is down and we are unable to establish connection with the service. In that case at initial call above code will produce exception. So, I made some changes in code, created two policies and wrapped first one with 2nd once.

using Polly;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
 
namespace PollyRetry
{
 
    class Program
    {
        static async System.Threading.Tasks.Task Main(string[] args)
        {
            await HttpRequestDemoAsync();
            Console.WriteLine("Done!");
            Console.ReadLine();
        }
 
        private static async System.Threading.Tasks.Task HttpRequestDemoAsync()
        {
 
            int retryCount = 5;
 
            HttpStatusCode[] httpStatusCodesWorthRetrying = {
                HttpStatusCode.RequestTimeout, // 408
                HttpStatusCode.InternalServerError, // 500
                HttpStatusCode.BadGateway, // 502
                HttpStatusCode.ServiceUnavailable, // 503
                HttpStatusCode.GatewayTimeout, // 504
                HttpStatusCode.NotFound // 404
            };
 
 
            var httpRetryPolicy = Policy.HandleResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
            .OrResult(r => r.StatusCode == HttpStatusCode.BadGateway)
            .WaitAndRetryAsync(retryCountretryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (exceptioncalculatedWaitDuration) =>
            {
                Console.WriteLine($"Unable to complete operation after {calculatedWaitDuration.TotalSeconds:n1}s ({exception.Result.StatusCode})");
            });
 
            var exceptionPolicy = Policy
            .Handle<Exception>()
            .WaitAndRetryAsync(retryCountretryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (exceptioncalculatedWaitDuration) =>
            {
                Console.WriteLine($"Error while performing operation after {calculatedWaitDuration.TotalSeconds:n1}{exception.Message}");
            })
            .WrapAsync(httpRetryPolicy);
 
 
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:51976/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                var response = (await exceptionPolicy.ExecuteAndCaptureAsync(() =>
                {
                    return client.GetAsync("api/order");
                })).FinalHandledResult;
 
                if (response != null && response.IsSuccessStatusCode)
                {
                    Console.WriteLine("Got valid response from API");
                }
            }
        }
    }
}

Now you can see variation in fault message

In case of DotNetCore we can use Microsoft.Extensions.Http.Polly.

Thursday, 30 May 2019

Distributed Microservice Architecture with Rabbitmq and DotNetCore

When we say distributed, suddenly 3rd parties message broker comes in our mind like Azure Service Bus or RabbitMQ. Let explore RabbitMQ and its implementation in DotnetCore.

RabbitMQ is a message broker: it accepts and forwards messages. It use AMQP Advanced Message Queuing Protocol.

Key Points:

  • Message: a package for information, usually composed of two parts; headers, containing metadata, and a body, containing a binary package containing the actual message itself
  • Producer: Whoever creates and sends a message.
  • Consumer: Whoever receives and reads a message
  • Queue: A communication channel that enqueues messages for later retrieval by one or more consumers.
  • Exchange: A queue aggregator that routes messages to queues based on some predefined logic


Run RabbitMq through docker:
docker run -d --hostname my-rabbit --name some-rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3-management

Then go to http://localhost:15672 and use following credentials.
Username:guest
Password:guest

Advantage of using it?
Checkout https://www.rabbitmq.com/features.html

How it can fit in to distributed micro service architecture?
Micro soft itself described in one of his GitHub implementation. With this design.
https://github.com/dotnet-architecture/eShopOnContainers

I don’t want to use RabbitMq Dotnet Client, any supplements?
EasyNetQ is more popular then other, check it out http://easynetq.com/

Any simple running demo of above design?
Yes, https://github.com/rajkrs/EasyNetQDotNetCore

Tuesday, 23 April 2019

Custom Model Binding through header in DotNetCore

Now the day with Asp.net core we have facility to bind object through exact binding by using attributes [FromHeader], [FromQuery], [FromRoute], [FromForm], [FromBody] and [FromServices] etc.

In this post we are focusing on FromHeader in which we have one constrain that it doesn't not resolve Complex Type.
But we can overcome from this constrain by using ModelBinder by using which we can customize Binder in asp.net core.

Scenario
Let's suppose that we have a Complex Model

public class UserLogin
{
    public int UserId { getset; }
    public string Password { getset; }
    public DateTime? RequestTime { getset; }
}

Now we want to make a get call where we are putting JSON value from Header with key RequestModel.

Now what we are expecting that, from RequestModel header key Model should resolve there in controller where we are using FromHeader attribute.
But unfortunately it is null.

To resolve this problem we can have 2 quick solution.
1. Create Custom Binder that implement IModelBinder, and use additional hint everywhere, when binding required from header.
2. Create a Custom Binder from IModelBinder and Custom provider from IModelBinderProvider, point Binder to Provider and Use provider in ConfigureServices globally so without adding additional hint model will be resolve.  
Note: In this example we just resolve only one header key RequestModel.

Solution 1:
Create a simple HeaderComplexModelBinder.cs
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Newtonsoft.Json;
using R6.Core.Constants;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
 
namespace R6.Service.Filter
{
    [ExcludeFromCodeCoverageAttribute]
    public class R6ModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
 
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
 
            var headerKey = bindingContext.ModelMetadata.BinderModelName;//Resolve Name from FormHeader(Name = "Key")
            if (string.IsNullOrEmpty(headerKey))
            {
                headerKey = Constant.CUSTOM_HEADER_NAME;
            }
            var headerValue = bindingContext.HttpContext.Request.Headers[headerKey].FirstOrDefault();
            var modelType = bindingContext.ModelMetadata.ModelType;
 
            if (!string.IsNullOrEmpty(headerValue))
            {
                bindingContext.Model = JsonConvert.DeserializeObject(headerValuemodelType);
                bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
            }
            return Task.CompletedTask;
        }
    }
}

And change action like this, and you found resolved Model.
[ModelBinder(typeof(HeaderComplexModelBinder))] UserLogin userLogin
Solution 2:
We need to keep HeaderComplexModelBinder.cs and create an additional HeaderComplexModelBinderProvider.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System;
using System.Linq;
 
namespace CoreApp.WebApi
{
    public class HeaderComplexModelBinderProvider : IModelBinderProvider
    {
 
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
 
            if (context.Metadata.IsComplexType)
            {
                var x = context.Metadata as Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadata;
                var headerAttributex.Attributes.Attributes.Where(a => a.GetType() == typeof(FromHeaderAttribute)).FirstOrDefault();
                if (headerAttribute != null)
                {
                    return new BinderTypeModelBinder(typeof(HeaderComplexModelBinder));
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }
    }
}

And add provider inside MVC service as option in ConfigureServices.
services.AddMvcCore(options =>
{
options.ModelBinderProviders.Insert(0, new HeaderComplexModelBinderProvider());
}

Now make your action very simple like this and you found resolved Model. :-)


Thursday, 4 April 2019

apidoc vs swagger for node app

While developing node services, we might need to expose our Api documents based on requirement. In that case we think of picking right documentation tool because there are many 3rd parties tools available for it. I have created sample POC by using 2 popular documentation tools
a. Swagger and
b. Apidocjs

Here is my finding regarding both:

  • Popularity: By comparing stats,  swagger-ui is more popular then apidocjs.
  • Consistency: If we already using swagger for our Dotnetcore service, then implementing swagger tool will consist more from Info and UI prospective.
  • Implementation complexity: apidocjs and swagger both required documentation content on implemented method as customize comment data. In addition they allow to write documentation data in separate resource file as .js and .json. If we already have swagger.json created by DotnetCore we can reuse more than 80% specification.
  •  Maintenance: For apidocjs will have to modify documentation for each affected method/endpoints if service changed. In swagger we can limit changes. But by implementing apidocjs we can isolate the layer.
  • Other benefits: Because swagger use plain .json that could be parsed through programing language, thus we can get advantage of various other 3rd parties in order to create http client and more. 
  • Future: Due to popularity of swagger, apidocjs provide information about apidoc-swagger converter so we can switch apidoc to swagger anytime.

Steps of using Swagger in to node app

1. Install following packages in your node app by running cmd commands:
npm install swagger-ui-express --save-dev
npm install window --save-dev

2. Add following snippet in app.ts
app.use('/images', express.static(__dirname + '/Images'));

//Use Swagger documentation
const Window = require('window');
var swaggerUi = require('swagger-ui-express'),
    swaggerDocument = require('./src/app/swagger');//When swagger.json available in app

const { document } = new Window();
var swaggerUi = require('swagger-ui-express');
const swaggerOption = {
    customCss: `.swagger-ui .topbar {
              background-color: #007298;
              }
              .topbar-wrapper span {
              visibility: hidden;
              }
              .topbar-wrapper img {
              content: url('../images/logo.png');
              width: 100px;
              height: 30px;
              }`,
    //swaggerUrl: '//www.dotnetapi.com/v1/swagger.json'), // When we need to add json from URL
    swaggerOptions: {
        defaultModelExpandDepth: 0,
        defaultModelsExpandDepth: -1,
        supportedSubmitMethods: ["patch"],
        validatorUrl: null,
        defaultModelRendering: [],
        deepLinking: false,
        onComplete: function (swaggerApi, swaggerUi) {
            document.title = 'Api Docs';
        },
    }
};
app.use('/api_docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, swaggerOption));

Monday, 4 March 2019

How to increase Unit Test code coverage in DotNetCore?

Hey let me tell you, if you are analyzing unit test coverage in Visual Studio and the scores is not good, this post is for you. Here I will tell you how to analyze the code coverage in visual studio?

First of all you would require Visual Studio Enterprise or else you can try Visual Studio 2019 Preview. In Visual studio Professional code coverage option not given.

Write some code and create unit test and verify it through
Test > Window > Test Explorer or try shortcut (Ctrl+E, T)

In the same Test tab you could find the Analyze Code Coverage Option.



After clicking on it you get complete code coverage details.
Now If you see your coverage score is poor, even if you have written unit test for you projects, don't worry. You project might include some core component or utility that you don't want to comes in coverage. Might be there are many private methods been declared that you want to exclude or some time you have also declared some constructor that you want to exclude.

I would recommend you to use [ExcludeFromCodeCoverageAttribute] attribute  that comes under
Namespace System.Diagnostics.CodeAnalysis, under the Assembly System.Diagnostics.Tools. You can
Apply this attribute on methods or on class to exclude.

If you want to test your private methods then you can try [Unit Testing for Private Methods in DotNet C#]

Some time you also need to refactor the code in such a way that code coverage will increase like:
Avoid return in mid of the implementation.





Wednesday, 13 February 2019

DotnetCore Web API model validation message from resource file.

It's so simple you just need to add resource file ValidationMessage.resx under the project as I have added. After adding it you will found that corresponding ValidationMessage.Designer.resx is not available inside resource folder.


So you need to set Custom Tool property for the .resx file as ResXFileCodeGenerator, as soon as we add it, will find ValidationMessage.Designer.resx.


After enabling it and writing appropriate model with validation attribute with ErrorMessageResourceName = "Password", ErrorMessageResourceType = typeof(ValidationMessage) you may found your required 
ModelValidationState Error message from your resource file.


using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using CoreApp.WebApi.Resources;
 
namespace CoreApp.WebApi.Models
{
    public class UserLogin
    {
        [DisplayName("LoginId")]
        public int UserId { getset; }
 
        [Required(ErrorMessageResourceName = "Password", ErrorMessageResourceType = typeof(ValidationMessage)), MinLength(4), MaxLength(10)]
        public string Password { getset; }
        public DateTime? RequestTime { getset; }
 
    }
}



Note:
Personally I fall in a situation in which I was using services.AddMvcCore() and with this model validation with  DataAnnotations was not working. So after searching out found that we need to use
services.AddDataAnnotations() Extensions in order to enable DataAnnotaions validation. And that worked for DotNetCore Web API model validations.

services.AddMvcCore().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonFormatters()
.AddDataAnnotations()
.AddXmlSerializerFormatters();

Thursday, 7 February 2019

Custom Model Validation Response Globally in DotNetCore

We can validate model globally and can can have custom response globally by using ActionFilter where we can just validate context.ModelState.IsValid or not and based on that we can have custom response there. The advantage of using this filter is that we can set it for few controllers where as if we looking for to apply globally for each controller in dotnet core, now we can change the ApiBehavior using ApiBehaviorOptions. The below code is for creation for extension of IServiceCollection and then simple use inside ConfigureServices();

services.UseCoreAppCustomModelValidation();

Extension:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
 
namespace CoreApp.ModelStateValidation
{
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection UseCoreAppCustomModelValidation(this IServiceCollection services)
        {
            _ = services.Configure((Action<ApiBehaviorOptions>)(apiBehaviorOptions =>
                    apiBehaviorOptions.InvalidModelStateResponseFactory = actionContext =>
                    {
                        var message = GetModelStateErrorWithException(actionContext);
 
                        return new BadRequestObjectResult(new
                        {
                            Code = 400,
                            Status = 0,
                            Messages = message
                        });
                    }));
            return services;
        }
 
        private static ExpandoObject GetModelStateFriendlyError(ActionContext actionContext)
        {
            var modelType = actionContext.ActionDescriptor.Parameters.FirstOrDefault()?.ParameterType; //Get model type  
                                                                                                       //p => p.BindingInfo.BindingSource.Id.Equals("Body", StringComparison.InvariantCultureIgnoreCase)
 
            var expandoObj = new ExpandoObject();
            var expandoObjCollection = (ICollection<KeyValuePair<stringobject>>)expandoObj//Cannot convert IEnumrable to ExpandoObject  
 
            var dictionary = actionContext.ModelState.ToDictionary(k => k.Key, v => v.Value)
                .Where(v => v.Value.ValidationState == ModelValidationState.Invalid)
                .ToDictionary(
                k =>
                {
                    if (modelType != null)
                    {
                        var property = modelType.GetProperties().FirstOrDefault(p => p.Name.Equals(k.Key, StringComparison.InvariantCultureIgnoreCase));
                        if (property != null)
                        {
                            //Try to get the attribute  
                            var displayName = property.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault()?.DisplayName;
                            return displayName ?? property.Name;
                        }
                    }
                    return k.Key; //Nothing found, return original validation key  
                },
                v => v.Value.Errors.Select(e => e.ErrorMessage).ToList() as object); //Box String collection
 
            foreach (var keyValuePair in dictionary)
            {
                expandoObjCollection.Add(keyValuePair);
            }
 
            return expandoObj;
        }
 
        private static List<stringGetModelStateErrorWithException(ActionContext actionContext)
        {
            List<stringerrorMessages = new List<string>();
            foreach (var error in actionContext.ModelState)
            {
                string message = error.Value.Errors != null && error.Value.Errors.Count() > 0 ?
                                    error.Value.Errors[0].Exception != null ?
                                            error.Key + " : " + error.Value.Errors[0].Exception.Message   //More weight-age is given to exception, so in case of one, use the exception message
                                    : error.Value.Errors[0].ErrorMessage != null ?
                                            error.Key + " : " + error.Value.Errors[0].ErrorMessage //Otherwise use error message
                                    : string.Empty
                            : string.Empty;
 
                if (!string.IsNullOrWhiteSpace(message))
                {
                    errorMessages.Add(message);
                }
            }
            return errorMessages;
        }
 
        private static List<stringGetModelStateError(ActionContext actionContext)
        {
            return actionContext.ModelState.Values.SelectMany(x => x.Errors)
                            .Select(x => x.ErrorMessage).ToList();
        }
    }
}