Skip to main content

Centralized model validation both for MVC/WebApi and SPA client-side validation using FluentValidation

Validation is one of the crucial parts of any application. It has to validate on both client side and server side requests.

What are target features or implementation from this article?

  • Model validation for any given model.
  • Centralized/One code for validation on both server-side and client-side.
  • Automatic validation of model without writing any extra codes on/under actions for validation.
  •  NO EXTRA/ANY codes on client-side to validate any form.
  • Compatible with SPA.
  • Can be compatible with any client-side validation framework/library. Like Angular Reactive form validation or any jquery validation libraries.

Tools used in the implementation?

  • FluentValidation: I feel DataAnnotation validation are excellent and simple to use, but in case of complex validation or writing any custom validations are always tricker and need to write a lot of codes to achieve whereas FluentValidations are simple even in case of complex validation. Generally, we need to validate incoming input against database values, which are straight-forward in FluentValidation. Also, it is not bound to be used only with MVC it can implement at any layers or any front-end, and on the entry point, it just need initialization. Also, the Fluent approach is similar to Entity Framework Fluent mapping so an identical pattern.
  • jquery-validation: In case of MVC and as long as cshtml/Views are used it is effortless to implement client-side validation since it is automatically taken care by auto-generated unobtrusive validation under rendered HTML. No work at all there unless some remote validations are required. In case of SPA, it gets hugely affected since rendering engines are on client-side and Microsoft Unobtrusive validation won't play a role.

    jquery-validation works based on JSON data, we would be getting rules and messages from server side and applying validation on the form through centralized code implementation. So, one code would take care of everything.
  • MVC and ActionFilterAttribute: The filter to generate validation rules based on JS validation library, validate model when posted on the server and remote validation for given field if it needs any check against database/server side codes.
Now, it is time to look into coding I have already pushed changes in GitHub repository https://github.com/viku85/CustomSpaApp. Also, this article could be treated as a continuation of SPA architecture that I had done in my last blog article https://vikutech.blogspot.in/2017/10/custom-spa-engine-similar-to-mvc-pattern-by-using-typescript.html.

Composing Fluent validation for the view model

Let's first directly begin with composing fluent validation and later look into Filter implementation. The validation is straightforward but a bit of enhancement through RuleSet and implementation of a little wrapper on base class BaseValidation.

 /// <summary>  
 /// Fluent validation for <see cref="ContactViewModel"/> view model.  
 /// </summary>  
 /// <seealso cref="BaseValidation{ContactViewModel}" />  
 public class ContactViewModelValidation  
   : BaseValidation<ContactViewModel>  
 {  
   /// <summary>  
   /// Initializes a new instance of the <see cref="ContactViewModelValidation"/> class.  
   /// </summary>  
   public ContactViewModelValidation()  
   {  
     RuleFor(model => model.Name)  
       .NotEmpty()  
       .Length(3, 100);  
     RuleFor(model => model.Email)  
       .NotEmpty()  
       .EmailAddress();  
     RuleFor(model => model.Message)  
       .NotEmpty()  
       .Length(5, 2000);  
     RuleFor(model => model.Subject)  
       .NotEmpty();  
     RuleSet(OperationRequest.Insert, () =>  
     {  
       RuleFor(model => model.Message)  
               .Must((model, field, token) =>  
             {  
               // TODO: Check against database if Email and message already exists.  
               return false;  
             }).WithMessage("Your information is already submitted.")  
             ;//.When(model => !String.IsNullOrEmpty(model.Message) && String.IsNullOrEmpty(model.Email));  
     });  
   }  
 }  

The above looks pretty simplified, and names say it all. The little twist is, it can hold validation rules for any addition, update or deletion of a model. An example can be seen from above through RuleSet of Insert through OperationRequest.Insert enum.

The above code includes Common rules for any CRUD operation which would be shared in all operations.

Here is code for OperationRequest enum and Base class from above.

Enum
   /// <summary>  
   /// Operation request  
   /// </summary>  
   public enum OperationRequest  
   {  
     /// <summary>  
     /// The insert request  
     /// </summary>  
     Insert,  
     /// <summary>  
     /// The update request  
     /// </summary>  
     Update,  
     /// <summary>  
     /// The delete request  
     /// </summary>  
     Delete  
   }  


Base Class
 /// <summary>  
 /// Base validation for all Fluent validations.  
 /// </summary>  
 /// <typeparam name="TModel">The type of the model.</typeparam>  
 /// <seealso cref="AbstractValidator{TModel}" />  
 public class BaseValidation<TModel>  
   : AbstractValidator<TModel>  
 {  
   /// <summary>  
   /// Defines a RuleSet that can be used to group together several validators.  
   /// </summary>  
   /// <param name="ruleSetName">The name of the ruleset.</param>  
   /// <param name="action">Action that encapsulates the rules in the ruleset.</param>  
   protected void RuleSet(OperationRequest ruleSetName, Action action)  
   {  
     RuleSet(ruleSetName.ToString(), action);  
   }  
 }  

Above two items are simple enough, after this, we just need to register it in MVC service collection for dependency injection.

We are not going to register in-built fluent validation on assembly level instead register on DI and use it on our custom smart filter for validation of actions and generation of JSON for client-side validation.

 /// <summary>  
 /// Extension to Register all Fluent validations.  
 /// </summary>  
 public static class ExtensionRegisterValidation  
 {  
   /// <summary>  
   /// Adds FluentValidation for the application.  
   /// </summary>  
   /// <param name="services">The services.</param>  
   /// <returns>The Service collection.</returns>  
   public static IServiceCollection AddFluentValidation(this IServiceCollection services)  
   {  
     services.AddScoped<IValidator<ContactViewModel>, ContactViewModelValidation>();  
     return services;  
   }  
 }  

Startup.cs
 services.AddFluentValidation();  

That completes FluentValidation part.

Filter to auto-trigger FluentValidation and generation of client-side validation rules along with support of remote validation

I have already explained three responsibilities of same, let's look in detail:
  • Model validation for action. We discussed four modes of  FluentValidation including Common for all kind of CRUD operation using OperationRequest seen earlier. If you see GetValidationRule function it retrieves RuleSet for FluentValidation. Common RuleSet is named as Default under FluentValidation. While creating Fluent Validator, we can specify an array of RuleSets. The function generates RuleSet based on Action name in MVC/WebApi so that we do not have to put Validate filter by specifying RuleSets manually. Do modify based on your need as of current implementation it pulls from action name containing add, create, insert, delete, update. So, action name like CreateCustomer, AddCustomer, UpdateCustomerAsync would be automatically resolved.
  • Remote validation: In this, an AJAX call would be made for a field to validate on the server side. The trick is, it would request the same URL with query string validate with property name to validate. From code level, you can see some condition with validate checks are done for the same reason. A JsonResult is sent from this. An example:
    Remote Validation
    AJAX/Remote validation for Message field.
  • Validation Rules and messages: This is a static data served when a form is rendered, this would contain necessary information about validations for fields used in the form. This, JSON generation is achieved through JqueryValidatorProvider class implementation, and the result is this:
Validation Rules for the entire form generated from JqueryValidatorProvider 

Codes of Action filter attribute

 /// <summary>  
 /// Validation filter for model state validation.  
 /// </summary>  
 /// <seealso cref="ActionFilterAttribute" />  
 public sealed partial class ValidationResponseFilterAttribute  
   : ActionFilterAttribute  
 {  
   /// <summary>  
   /// Action execution on any controller.  
   /// </summary>  
   /// <param name="context">Action context.</param>  
   public override void OnActionExecuting(ActionExecutingContext context)  
   {  
     if (context == null)  
     {  
       return;  
     }  
     var model = GetTheActionArgument(context);  
     if (model == null && context.HttpContext.Request.Query.TryGetValue("validate", out var _))  
     {  
       context.Result = new JsonResult(string.Empty);  
       return;  
     }  
     if (model == null)  
     {  
       return;  
     }  
     var validator = context.HttpContext.RequestServices  
       .GetService(typeof(IValidator<>)  
       .MakeGenericType(model.ModelType)) as IValidator;  
     // In case of no validator and URL requested for validation rule  
     if (validator == null && context.HttpContext.Request.Query.Keys.Any(val => val == "validation"))  
     {  
       context.Result = new EmptyResult();  
       return;  
     }  
     if (validator == null)  
     {  
       return;  
     }  
     if (context.HttpContext.Request.Query.TryGetValue("validation", out var clientRuleRequest))  
     {  
       switch (clientRuleRequest)  
       {  
         default:  
           context.Result = new JqueryValidatorProvider(validator).GetValidationRules();  
           break;  
       }  
       return;  
     }  
     model.ExecuteOnModel((modelValue) =>  
     {  
       var validationResult =  
         validator.Validate(new ValidationContext(  
           modelValue,  
           new PropertyChain(),  
           new RulesetValidatorSelector(GetValidationRule(context))));  
       validationResult.AddToModelState(context.ModelState, null);  
     });  
     // If requested for Ajax validation.  
     if (context.HttpContext.Request.Query.TryGetValue("validate", out var modelProperty))  
     {  
       context.Result = new JsonResult(context.ModelState.ToDictionary(  
               kvp => kvp.Key,  
               kvp => kvp.Value.Errors.Select(e => e.ErrorMessage).Humanize()));  
       return;  
     }  
     if (!context.ModelState.IsValid)  
     {  
       context.Result = new BadRequestObjectResult(context.ModelState);  
     }  
   }  
   /// <summary>  
   /// Gets the action argument.  
   /// </summary>  
   /// <param name="actionContext">The action context.</param>  
   /// <returns>Object type and object.</returns>  
   private static ModelDefination GetTheActionArgument(ActionExecutingContext actionContext)  
   {  
     return (from arg in actionContext.ActionArguments.Values  
         let typ = arg?.GetType()  
         where typ != null && !typ.IsPrimitive && !typ.IsValueType && typ != typeof(string)  
         //&& typ != typeof(Kendo.Mvc.UI.DataSourceRequest) TODO: Note could exclude any other types  
         select new ModelDefination(arg)).FirstOrDefault();  
   }  
   /// <summary>  
   /// Gets the validation rule set names for Fluent validation.  
   /// </summary>  
   /// <param name="actionContext">The action context.</param>  
   /// <returns>Validation rules for Fluent mapping</returns>  
   private static string[] GetValidationRule(ActionExecutingContext actionContext)  
   {  
     var ruleSetNames = new List<string>(2) { "default" };  
     if (actionContext.ActionDescriptor is ControllerActionDescriptor descriptor)  
     {  
       if (descriptor.ActionName.Contains(nameof(OperationRequest.Delete)))  
       {  
         ruleSetNames.Add(OperationRequest.Delete.ToString());  
       }  
       else if (descriptor.ActionName.Contains("Create") ||  
         descriptor.ActionName.Contains("Add") ||  
         descriptor.ActionName.Contains(nameof(OperationRequest.Insert)))  
       {  
         ruleSetNames.Add(OperationRequest.Insert.ToString());  
       }  
       else if (descriptor.ActionName.Contains(nameof(OperationRequest.Update)))  
       {  
         ruleSetNames.Add(OperationRequest.Update.ToString());  
       }  
     }  
     return ruleSetNames.ToArray();  
   }  
 }  

JqueryValidatorProvider

This class is responsible for generating JSON for general form validation. This is done by looking into FluentValidation models meta information and ultimately creating JSON which helps in form validation.
The implementation could be changed based on your choice of the client-side validator, and server-side codes would accordingly change.
 /// <summary>  
 /// jQuery.Validator rules provider.  
 /// </summary>  
 public class JqueryValidatorProvider  
 {  
   /// <summary>  
   /// The validator  
   /// </summary>  
   private readonly IValidator Validator;  
   /// <summary>  
   /// Initializes a new instance of the <see cref="JqueryValidatorProvider"/> class.  
   /// </summary>  
   /// <param name="validator">The validator.</param>  
   public JqueryValidatorProvider(IValidator validator)  
   {  
     Validator = validator;  
   }  
   /// <summary>  
   /// Gets the validation rules based on jQuery.validator.  
   /// </summary>  
   /// <returns>Result along with rules.</returns>  
   public IActionResult GetValidationRules()  
   {  
     if (Validator == null)  
     {  
       return new EmptyResult();  
     }  
     var validationObject = new Dictionary<string, object>();  
     var errorObject = new Dictionary<string, Dictionary<string, string>>();  
     var validatorDescriptor = Validator.CreateDescriptor();  
     foreach (var valida in validatorDescriptor.GetMembersWithValidators())  
     {  
       var validations = new Dictionary<string, object>();  
       var errors = new Dictionary<string, string>();  
       foreach (var propertyValidator in valida)  
       {  
         var validatorAdded = false;  
         Action<string, object, Action<MessageFormatter, Action<Func<string, string>>>> add = (validationType, value, format) =>  
         {  
           validatorAdded = true;  
           var formatter = new MessageFormatter();  
           formatter.AppendPropertyName(valida.Key.Humanize());  
           var template = propertyValidator.ErrorMessageSource.GetString(null);  
           format?.Invoke(formatter, (d) => { template = d?.Invoke(template); });  
           validations.SafeAdd(validationType, value);  
           errors.SafeAdd(validationType, formatter.BuildMessage(template));  
         };  
         if (propertyValidator is NotNullValidator  
           || propertyValidator is NotEmptyValidator)  
         {  
           add("required", true, null);  
         }  
         if (propertyValidator is EmailValidator)  
         {  
           add("email", true, null);  
         }  
         if (propertyValidator is LengthValidator lengthValidator)  
         {  
           if (lengthValidator.Max > 0)  
           {  
             add(  
               "maxlength",  
               lengthValidator.Max,  
             (formatter, template) =>  
             {  
               formatter.AppendArgument("MinLength", lengthValidator.Min);  
               formatter.AppendArgument("MaxLength", lengthValidator.Max);  
               template?.Invoke((tem) => !tem.Contains("TotalLength") ? tem :  
                   tem.Split(".")?.FirstOrDefault());  
             });  
           }  
           add(  
             "minlength",  
             lengthValidator.Min,  
             (formatter, template) =>  
             {  
               formatter.AppendArgument("MinLength", lengthValidator.Min);  
               formatter.AppendArgument("MaxLength", lengthValidator.Max);  
               template?.Invoke((tem) => !tem.Contains("TotalLength") ? tem :  
               tem.Split(".")?.FirstOrDefault());  
             });  
         }  
         if (propertyValidator is RegularExpressionValidator expressionValidator)  
         {  
           add("regex", expressionValidator.Expression, null);  
         }  
         if (!validatorAdded)  
         {  
           add("remote", valida.Key, null);  
         }  
       }  
       validations.IfNotEmpty(() => validationObject.Add(valida.Key, validations));  
       errors.IfNotEmpty(() => errorObject.Add(valida.Key, errors));  
     }  
     return new JsonResult(new  
     {  
       rules = validationObject,  
       messages = errorObject  
     });  
   }  
 }  

From codes, remote validation would only enable when it did not fall in any category of validation.
That's an end of server-side codes. Client-side codes are relatively simple.

Client-side codes for validation

The client-side validation is entirely dependent on jquery-validation plugin since it is our choice for client-side validation.

FormValidation.ts
 import { injectable } from "inversify";  
 import { HttpRequestResponse } from './../RequestResponse/HttpRequestResponse';  
 @injectable()  
 class FormValidation {  
   private AppendError(form: JQuery<HTMLFormElement> | JQuery<HTMLElement>,  
     error: JQuery<HTMLElement>, element: JQuery<HTMLElement>) {  
     let errorSelector = $(`#${$(element).attr("id")}Error`);  
     errorSelector = errorSelector.length ? errorSelector : $(`#${$(element).attr("id")}-error`);  
     if (errorSelector.length) {  
       errorSelector.removeClass('field-validation-valid').addClass('field-validation-error');  
       errorSelector.text(error.text());  
     }  
     else {  
       $(element)  
         .parent().after(  
         `<div id='${$(element).attr('name')}Holder' class="field-validation-error"></div>`);  
       $(`#${(element).attr('name')}Holder`).append(error);  
     }  
   }  
   ParseModelStateError(data: JQuery.jqXHR<any>, eachErrorCallback: (message: string, propName: string) => void) {  
     if (data == undefined || data.responseJSON == undefined) {  
       return;  
     }  
     var message = '';  
     var propStrings = Object.keys(data.responseJSON);  
     $.each(propStrings, (errIndex, propString) => {  
       var propErrors = data.responseJSON[propString];  
       $.each(propErrors, (errMsgIndex, propError) => {  
         message += propError;  
       });  
       message += '\n';  
       eachErrorCallback(message, propString);  
       message = '';  
     });  
   }  
   private RemoteValidation(elementName: string,  
     form: JQuery<HTMLFormElement> | JQuery<HTMLElement>) {  
     let getData = () => {  
       let serializedData = {};  
       $(form).serializeArray()  
         .map((key) => { serializedData[key.name] = key.value; });  
       return JSON.stringify(serializedData);  
     }  
     let remote: JQueryAjaxSettings = {  
       url: `${form.attr('action')}?validate=${elementName}`,  
       type: "post",  
       async: true,  
       contentType: 'application/json',  
       beforeSend: (xhr, setting) => {  
         setting.data = getData();  
       },  
       dataFilter: (response) => {  
         if ($.parseJSON(response) == true) {  
           return response;  
         }  
         var data = $.parseJSON(response);  
         var validator: any = $(form).validate();  
         validator.invalid[elementName] = data[elementName] != undefined;  
         return JSON.stringify(data[elementName] != undefined ? data[elementName] : true);  
       }  
     };  
     return remote;  
   }  
   RegisterJqueryValidation(formSelector: string) {  
     let form = $(formSelector);  
     $.ajax({  
       url: form.attr('action') + '?validation=jquery',  
       data: '{}',  
       contentType: 'application/json',  
       method: 'post',  
       success: (validationRule: JQueryValidation.ValidationOptions) => {  
         if (validationRule != undefined && validationRule.rules != undefined) {  
           validationRule.errorPlacement = (error, element) =>  
             this.AppendError(form, error, element);  
           validationRule.success = (label, input) =>  
             label.empty();  
           $.each(validationRule.rules, (prop: any) => {  
             if (validationRule.rules[prop].hasOwnProperty('remote')) {  
               validationRule.rules[prop].remote = () => this.RemoteValidation(prop, form);  
             }  
           });  
           $.validator.setDefaults({ ignore: '' });  
           var validator = form.validate(validationRule);  
         }  
       }  
     });  
   }  
 }  
 export { FormValidation }  

Usage

Form.ts was explained in the earlier blog post, but please refer to Form.ts in case of any confusion. The function RegisterJqueryValidation would take care of everything.

 this.Validation.RegisterJqueryValidation(this.ContactViewOption.FormSelector);  
 this.EventHelper.RegisterClickEvent(  
   this.ContactViewOption.SubmitButtonSelector,  
   (evt, selector) => {  
     this.FormHelper.SubmitForm({  
       Source: {  
         ButtonEvent: evt  
       },  
       OnPostSuccessResult: (data) => {  
         console.log('Submitted successfully.');  
       }  
     });  
   });  




Popular posts from this blog

Handling JSON DateTime format on Asp.Net Core

This is a very simple trick to handle JSON date format on AspNet Core by global settings. This can be applicable for the older version as well.

In a newer version by default, .Net depends upon Newtonsoft to process any JSON data. Newtonsoft depends upon Newtonsoft.Json.Converters.IsoDateTimeConverter class for processing date which in turns adds timezone for JSON data format.

There is a global setting available for same that can be adjusted according to requirement. So, for example, we want to set default formatting to US format, we just need this code.


services.AddMvc() .AddJsonOptions(options => { options.SerializerSettings.DateTimeZoneHandling = "MM/dd/yyyy HH:mm:ss"; });



Elegantly dealing with TimeZones in MVC Core / WebApi

In any new application handling TimeZone/DateTime is mostly least priority and generally, if someone is concerned then it would be handled by using DateTime.UtcNow on codes while creating current dates and converting incoming Date to UTC to save on servers.
Basically, the process is followed by saving DateTime to UTC format in a database and keep converting data to native format based on user region or single region in the application's presentation layer.
The above is tedious work and have to be followed religiously. If any developer misses out the manual conversion, then that area of code/view would not work.
With newer frameworks, there are flexible ways to deal/intercept incoming or outgoing calls to simplify conversion of TimeZones.
These are steps/process to achieve it. 1. Central code for storing user's state about TimeZone. Also, central code for conversion logic based on TimeZones. 2. Dependency injection for the above class to be able to use globally. 3. Creating Mo…

LDAP with ASP.Net Identity Core in MVC with project.json

Lightweight Directory Access Protocol (LDAP), the name itself explain it. An application protocol used over an IP network to access the distributed directory information service.

The first and foremost thing is to add references for consuming LDAP. This has to be done by adding reference from Global Assembly Cache (GAC) into project.json

"frameworks": { "net461": { "frameworkAssemblies": { "System.DirectoryServices": "4.0.0.0", "System.DirectoryServices.AccountManagement": "4.0.0.0" } } },
These System.DirectoryServices and System.DirectoryServices.AccountManagement references are used to consume LDAP functionality.

It is always better to have an abstraction for irrelevant items in consuming part. For an example, the application does not need to know about PrincipalContext or any other dependent items from those two references to make it extensible. So, we can begin with some bas…

Architecture solution composting Repository Pattern, Unit Of Work, Dependency Injection, Factory Pattern and others

Project architecture is like garden, we plant the things in certain order and eventually they grow in similar manner. If things are planted well then they will all look(work) great and easier to manage. If they grow as cumbersome it would difficult to maintain and with time more problems would be happening in maintenance.

There is no any fixed or known approach to decide project architecture and specially with Agile Methodology. In Agile Methodology, we cannot predict how our end products will look like similarly we cannot say a certain architecture will fit well for entire development lifespan for project. So, the best thing is to modify the architecture as per our application growth. I understand that it sounds good but will be far more problematic with actual development. If it is left as it is then more problems will arise with time. Just think about moving plant vs a full grown tree.

Coming to technical side, In this article, I will be explaining about the various techniques tha…

Unit Of Work injection through Asp.Net Core Dependency Injection

This article is not directly related to UnitOfWork but leveraging Asp.Net Core Dependency Injection to consume Unit Of Work.

In one of the previous article about project architecture, I was not very satisfied with the approach for Unit Of Work implementation for initialization of repository even if with some advantage.

Here is old code for UnitOfWork.

public sealed partial class MyProjectUnitOfWork : UnitOfWork<DbContext>, IMyProjectUnitOfWork { public MyProjectUnitOfWork(IContextFactory<DbContext> contextFactory) : base(contextFactory) { } /// <summary> /// BookRepository holder /// </summary> private MyProject.DB.Repository.BookRepository _bookRepository; /// <summary> /// Gets the BookRepository repository. /// </summary> /// <value> /// The BookRepository repository. /// </value> MyProject.Interface.Repository.IBoo…

Kendo MVC Grid DataSourceRequest with AutoMapper

Kendo Grid does not work directly with AutoMapper but could be managed by simple trick using mapping through ToDataSourceResult. The solution works fine until different filters are applied.
The problems occurs because passed filters refer to view model properties where as database model properties are required after AutoMapper is implemented.
So, the plan is to intercept DataSourceRequest  and modify names based on database model. To do that we are going to create implementation of CustomModelBinderAttribute to catch calls and have our own implementation of DataSourceRequestAttribute from Kendo MVC. I will be using same source code from Kendo but will replace column names for different criteria for sort, filters, group etc.
Let's first look into how that will be implemented.
public ActionResult GetRoles([MyDataSourceRequest(GridId.RolesUserGrid)] DataSourceRequest request) { if (request == null) { throw new ArgumentNullException("reque…

OpenId Authentication with AspNet Identity Core

This is a very simple trick to make AspNet Identity work with OpenId Authentication. More of all both approach is completely separate to each other, there is no any connecting point.

I am using Microsoft.AspNetCore.Authentication.OpenIdConnect package to configure but it should work with any other.

Configuring under Startup.cs with IAppBuilder
app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme, LoginPath = new PathString("/Account/Login"), CookieName = "MyProjectName", }) .UseIdentity() .UseOpenIdConnectAuthentication(new OpenIdConnectOptions { ClientId = "<AzureAdClientId>", Authority = String.Format("https://login.microsoftonline.com/{0}", "<AzureAdTenant>"), ResponseType = OpenIdConnectResponseType.IdToken, PostLogoutRedirectUri = "<my website url>", Au…

Configuring Ninject, Asp.Net Identity UserManager, DataProtectorTokenProvider with Owin

It can be bit tricky to configure both Ninject and Asp.Net Identity UserManager if some value is expected from DI to configure UserManager. We will look into configuring both and also use OwinContext to get UserManager.

As usual, all configuration need to be done on Startup.cs. It is just a convention but can be used with different name, the important thing is to decorate class with following attribute to make it Owin start-up:

[assembly: OwinStartup(typeof(MyProject.Web.Startup))]
Ninject configuration

Configuring Ninject kernel through method which would be used to register under Owin.

Startup.cs
public IKernel CreateKernel() { var kernel = new StandardKernel(); try { //kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); // TODO: Put any other injection which are required. return kernel; } catch { kernel.Dispose(); throw; }…

Global exception handling and custom logging in AspNet Core with MongoDB

In this, we would be looking into logging and global exception handling in the AspNet Core application with proper registration of logger and global exception handling.

Custom logging
The first step is to create a data model that we want to save into DB.

Error log Data model
These are few properties to do logging which could be extended or reduced based on need.

public class ErrorLog { /// <summary> /// Gets or sets the Error log identifier. /// </summary> /// <value> /// The Error log identifier. /// </value> [BsonRepresentation(BsonType.ObjectId)] public ObjectId Id { get; set; /// <summary> /// Gets or sets the date. /// </summary> /// <value> /// The date. /// </value> public DateTime Date { get; set; } /// <summary> /// Gets or sets the thread. /// </summary> /// <v…

T4, Generating interface automatically based on provided classes

With new techniques and patterns interface plays a key role in application architecture. Interface makes application extendable like defining file upload interface and implementing based on file system, Azure Blob storage, Amazon S3. At starting we might be implementing based on Azure Blob but later we might move to Windows based file system and so on.

Ideally we create interface based on need and start implementing actual default implementation class. Many a times at starting of implementation there is one to one mapping between Interface and Class. Like from above example File upload interface and the initial or default class implementation that we design and with time it will get extended.
In this article, we will try to create interface based on default class implementation. This is not at all recommended in Test Driven Design (TDD) where we test the application before actual code implementation but I feel sometimes and in some situations it is okay do that and test straight afte…