Common features in ASP.NET Core 2.1 WebApi: Validation

 

Introduction

Validating user input is a common scenario in a Web-based application. For production applications, developers often end up spending a lot more time and code on this task than we would like. In building the ASP.NET Core Web API with FluentValidation, it was important to try and make the task of validating input a lot easer than it has been in the past.

FluentValidation is  popular .NET library for building strongly-typed validation rules.

Configuring the project

Step 1: Download FluentValidation.AspNetCore Nuget package

PM> Install-Package FluentValidation.AspNetCore -Version 8.0.100

 

Step 2: Add FluentValidation in Startup.cs

public void ConfigureServices(IServiceCollection services) 
{ 
   // mvc + validating
   services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddFluentValidation();
}

Creating a validator

FluentValidation ships with several built-in validators. In ths next example will see how to use two of them:

  • NotNull
  • NotEmpty

We will see how to build a custom validator as well with the RuleBuilder Must.

Step 1: Create a model you want to validate

Example of User model:

public class User
{
   public string Gender { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public string SIN { get; set; }
}

Step 2: Create your validator

Note that your validator must inherit from the abstract class named AbstractValidator

public class UserValidator : AbstractValidator<User>
{
   public UserValidator()
   {
      // Rules here
   }
}

Step 3: Create your rules

In this example we will ensure that FirstName, LastName and SIN are not null and not empty, we will also ensure that SIN number is a valid SIN with this algorithm:

public static class Utilities
{
   public static bool IsValidSIN(int sin)
   {
      if (sin < 0 || sin > 999999998) return false;

      int checksum = 0;
      for (int i = 4; i != 0; i--)
      {
         checksum += sin % 10;
         sin /= 10;

         int addend = 2 * (sin % 10); if (addend >= 10) addend -= 9;
         checksum += addend;
         sin /= 10;
      }
         return (checksum + sin) % 10 == 0;
   }
}

Implementation of rules:

public class UserValidator : AbstractValidator<User>
{
   public UserValidator()
   {
      RuleFor(x => x.FirstName)
      .NotNull()
      .NotEmpty()
      .WithMessage("FirstName is mandatory.");

      RuleFor(x => x.LastName)
      .NotNull()
      .NotEmpty()
      .WithMessage("LastName is mandatory.");

      RuleFor(x => x.SIN)
      .NotNull()
      .NotEmpty()
      .WithMessage("SIN is mandatory.")
      .Must((o, list, context) =>
      {
         if (null != o.SIN)
         {
            context.MessageFormatter.AppendArgument("SIN", o.SIN);
            return Utilities.IsValidSIN(int.Parse(o.SIN));
         }
         return true;
      })
     .WithMessage("SIN ({SIN}) is not valid.");
   } 
}

Step 4: Declare your rules as a singleton service in Startup.cs

public void ConfigureServices(IServiceCollection services) 
{ 
   // Validators
   services.AddSingleton<IValidator<User>, UserValidator>();
   // mvc + validating
   services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddFluentValidation();
}

Step 5: Manage your validation errors in Startup.cs

ASP.NET Core 2.1 allows you to override the default behavior of ModelState management (ApiBehaviorOptions), you have now an alternative to MVC Attributes:

public void ConfigureServices(IServiceCollection services) 
{ 
   // Validators
   services.AddSingleton<IValidator<User>, UserValidator>();
   // mvc + validating
   services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddFluentValidation();

    // override modelstate
    services.Configure<ApiBehaviorOptions>(options =>
    {
       options.InvalidModelStateResponseFactory = (context) =>
       {
          var errors = context.ModelState.Values.SelectMany(x => x.Errors.Select(p => p.ErrorMessage)).ToList();
          var result = new
          {
             Code = "00009",
             Message = "Validation errors",
             Errors = errors
          };
          return new BadRequestObjectResult(result);
       };
    });
}

When a validation fails, this piece of code is performed (ModelState is false)

Is this example, I manage what I do with errors and how I display errors to the client, simply an object that contains an error code, a message, and a list of validation errors encountered.

Here we are! Let’s see how it works now

Using a validator

It’s really easy to use a validator after it’s creation.

You just need to create your action that takes in parameter your model to validate.

Because the validation service added in your configuration, FluentValidation will automatically detect your model when you use it into an action and fire the validator !

Step 1: Create an action that uses your model to validate

[Route("api/[controller]")]
[ApiController]
public class DemoValidationController : ControllerBase
{
   [HttpPost]
   public IActionResult Post(User user)
   {
      return NoContent();
   }
}

Step 2: Test your action with POSTMAN

Conclusion

This was an example of implementing validation in an ASP.NET Core WebAPI 🙂

The complete source code can be found here.

Using OpenIdConnect with Azure AD, Angular5 and WebAPI Core: Introduction

Introduction

 

 

Azure Active Directory (Azure AD) is Microsoft’s multi-tenant, cloud based directory and identity management service. Azure AD combines core directory services, advanced identity governance, and application access management. Azure AD also offers a rich, standards-based platform that enables developers to deliver access control to their applications, based on centralized policy and rules.

OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner. OpenID Connect allows clients of all types, including Web-based, mobile, and JavaScript clients, to request and receive information about authenticated sessions and end-users. The specification suite is extensible, allowing participants to use optional features such as encryption of identity data, discovery of OpenID Providers, and session management, when it makes sense for them.

Five scenarios supported by Azure AD:

In this serie of articles article we will demystify Single Page Application (SPA) scenario:

 

This scenario is named Implicit flow in opposition to basic flow in a full back end web application

  1. The user navigates to the web application.
  2. The application returns the JavaScript front end (presentation layer) to the browser.
  3. The user initiates sign in, for example by clicking a sign in link. The browser sends a GET to the Azure AD authorization endpoint to request an ID token. This request includes the application ID and reply URL in the query parameters.
  4. Azure AD validates the Reply URL against the registered Reply URL that was configured in the Azure Portal.
  5. The user signs in on the sign-in page.
  6. If authentication is successful, Azure AD creates an ID token and returns it as a URL fragment (#) to the application’s Reply URL. For a production application, this Reply URL should be HTTPS. The returned token includes claims about the user and Azure AD that are required by the application to validate the token.
  7. The JavaScript client code running in the browser extracts the token from the response to use in securing calls to the application’s web API back end.
  8. The browser calls the application’s web API back end with the access token in the authorization header.

Using OpenIdConnect with Azure AD, Angular5 and WebAPI Core: WebAPI configuration

 

Installing required packages

There is only one required package to achieve our Web Api protection with a JWT.

Install https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer/

PM> Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 2.0.1

Configure your Web API in Startup.cs:

using System;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace WebApiJwtBearer
{
   public class Startup
   {
      public Startup(IConfiguration configuration)
      {
         Configuration = configuration;
      }

      public IConfiguration Configuration { get; }

     //This method gets called by the runtime. Use this method to add services to the container.
     public void ConfigureServices(IServiceCollection services)
     {
        services.AddAuthentication(options =>
        {
           options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
           options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(options =>
        {
           options.Authority = "https://login.microsoftonline.com/136544d9-038e-4646-afff-10accb370679"; <- tenantId
           options.Audience = "257b6c36-1168-4aac-be93-6f2cd81cec43"; <- clientId
           options.TokenValidationParameters.ValidateLifetime = true;
           options.TokenValidationParameters.ClockSkew = TimeSpan.Zero;
       });

       services.AddAuthorization();

       services.AddMvc();
    }

    //This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
       if (env.IsDevelopment())
       {
          app.UseDeveloperExceptionPage();
       }

      app.UseAuthentication();

      app.UseCors(builder => builder
      .AllowAnyOrigin()
      .AllowAnyMethod()
      .AllowCredentials()
      .AllowAnyHeader());
      app.UseMvc();
   }
 }
}

Now you should be done 🙂

Let’s see what happen if we test it :

 

Nice isn’t it? 🙂