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.');  
       }  
     });  
   });  




Comments

  1. Thanks for sharing this! Very useful for people searching for premium wellness experiences. Choosing the best spa in Adyar can make a big difference.

    ReplyDelete

Post a Comment

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 ...

Trim text in MVC Core through Model Binder

Trimming text can be done on client side codes, but I believe it is most suitable on MVC Model Binder since it would be at one place on infrastructure level which would be free from any manual intervention of developer. This would allow every post request to be processed and converted to a trimmed string. Let us start by creating Model binder using Microsoft.AspNetCore.Mvc.ModelBinding; using System; using System.Threading.Tasks; public class TrimmingModelBinder : IModelBinder { private readonly IModelBinder FallbackBinder; public TrimmingModelBinder(IModelBinder fallbackBinder) { FallbackBinder = fallbackBinder ?? throw new ArgumentNullException(nameof(fallbackBinder)); } public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } var valueProviderResult = bindingContext.ValueProvider.GetValue(bin...

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> ...

A wrapper implementation for Kendo Grid usage

A wrapper implementation for any heavily used item is always a good practice. Whatever is not written by us and used at a lot of places should be wrapped within specific functionality to keep it future proof and easily changeable. This also encourages DRY principle to keep our common setting at a central place. Kendo UI items are enormous in configuration, one of an issue I find people keep repeating codes for Kendo Grid configuration. They have built very flexible system to have any configuration, but in most of the cases, we do not need all of those complicated configuration. We would try to see a simpler configuration of same. The actual core implementation is bit complex, but we do not have to bother about it once done since the focus is just on usage only. I recommend doing this practice for as simple as jQuery events, form handling or as simple as any notification system. This just won't make things simple but makes codes much more manageable, easy understand, read or open f...

Using Redis distributed cache in dotnet core with helper extension methods

Redis cache is out process cache provider for a distributed environment. It is popular in Azure Cloud solution, but it also has a standalone application to operate upon in case of small enterprises application. How to install Redis Cache on a local machine? Redis can be used as a local cache server too on our local machines. At first install, Chocolatey https://chocolatey.org/ , to make installation of Redis easy. Also, the version under Chocolatey supports more commands and compatible with Official Cache package from Microsoft. After Chocolatey installation hit choco install redis-64 . Once the installation is done, we can start the server by running redis-server . Distributed Cache package and registration dotnet core provides IDistributedCache interface which can be overrided with our own implementation. That is one of the beauties of dotnet core, having DI implementation at heart of framework. There is already nuget package available to override IDistributedCache i...

Data seed for the application with EF, MongoDB or any other ORM.

Most of ORMs has moved to Code first approach where everything is derived/initialized from codes rather than DB side. In this situation, it is better to set data through codes only. We would be looking through simple technique where we would be Seeding data through Codes. I would be using UnitOfWork and Repository pattern for implementing Data Seeding technique. This can be applied to any data source MongoDB, EF, or any other ORM or DB. Things we would be doing. - Creating a base class for easy usage. - Interface for Seed function for any future enhancements. - Individual seed classes. - Configuration to call all seeds. - AspNet core configuration to Seed data through Seed configuration. Creating a base class for easy usage public abstract class BaseSeed<TModel> where TModel : class { protected readonly IMyProjectUnitOfWork MyProjectUnitOfWork; public BaseSeed(IMyProjectUnitOfWork MyProjectUnitOfWork) { ...

main method return value

Mainly we used to write "static void main" for entry point in console application. Placement of void denotes return type. In main function we could have "int" too but what does it really mean. "int main" signifies return type as integer. The return type of main function tells about execution status of application. Even if we have specified void as return type then it would be marked as successful program execution. If we mark int as return type then we are able to control the execution status. Now, what is the benefit of making main function as int. Windows OS saves result in  %ERRORLEVEL% environment variable of OS. If we create batch file and execute application through it then we will able to get status and based on result we can trigger something else through batch file. Let's suppose we have created program called TEST.EXE. Batch file script: @echo off REM Execute main program REM TEST.EXE @if  "%ERRORLEVEL%" == "0...

Channel, ChannelReader and ChannelWriter to manage data streams in multi-threading environment

I came across Channel class while working with SignalR which looks really interesting. By looking into NuGet packages ( https://www.nuget.org/packages/System.Threading.Channels ), it seems just 4 months old. The Channel class provides infrastructure to have multiple reads and write simuletensely through it's Reader and Writer properties. This is where it is handy in case of SignalR where data streaming needs to be done but is not just limited to that but wherever something needs to be read/write/combination of both in a multi-threading environment. In my case with SignalR, I had to stream stock data at a regular interval of time. public ChannelReader<StockData> StreamStock() { var channel = Channel.CreateUnbounded<StockData>(); _stockManager.OnStockData = stockData => { channel.Writer.TryWrite(stockData); }; return channel.Reader; } The SignalR keeps return type of ChannelReader<StockData> open so that whatev...

Dependency Injection through XML configuration and XML transformation through SlowCheetah

Dependency Injection (DI) is a design pattern to change definition by substituting object without changing code for the application. The most popular DI type is to construct classes based on certain interface and pass actual object on constructor level. What are we trying to do? We will be looking into a way to achieve dependency injection through XML configuration based on  build selection . The implemented classes derived through interface will get switched based on build selection. Where to use it? I really hate making dependencies with something specific which can be changed later on. In my case, Azure environment. I believe Azure is more like a platform where we can host the application rather then integrating the application with Azure. What if client decided to switch to other hosting environment, in that case we got to change every piece of code wherever Azure SDKs are referred. The above one is merely an example. We can use this approach on many other item as wel...