Pazartesi, 27 Ağustos 2018 / Published in Uncategorized

Improving .NET Core Kestrel performance using a Linux-specific transport

By

Tom Deseyn
July 24, 2018
August 9, 2018

 
+9

rating,

11

votes

Loading…

ASP.NET Core is the web framework for .NET Core. Performance is a key feature. The stack is heavily optimized and continuously benchmarked. Kestrel is the name of the HTTP server. In this blog post, we’ll replace Kestrel’s networking layer with a Linux-specific implementation and benchmark it against the default out-of-the-box implementations. The TechEmpower web framework benchmarks are used to compare the network layer performance.

Transport abstraction

Kestrel supports replacing the network implementation thanks to the Transport abstraction. ASP.NET Core 1.x uses libuv for its network implementation. libuv is the asynchronous I/O library that underpins Node.js. The use of libuv predates .NET Core, when cross-platform ASP.NET was called ASP.NET 5. Then scope broadened to the cross-platform .NET implementation that we know now as .NET Core. As part of .NET Core, a network implementation became available (using the Socket class). ASP.NET Core 2.0 introduced the Transport abstraction in Kestrel to make it possible to change from the libuv to a Socket-based implementation. For version 2.1, many optimizations were made to the Socket implementation and the Sockets transport has become the default in Kestrel.

The Transport abstraction allows other network implementations to be plugged in. For example, you could leverage the Windows RIO socket API or user-space network stacks. In this blog post, we’ll look at a Linux-specific transport. The implementation can be used as a direct replacement for the libuv/Sockets transport. It doesn’t need privileged capabilities and it works in constrained containers, for example, when running on Red Hat OpenShift.

For future versions, Kestrel aims to become more usable as a basis for non-HTTP servers. The Transport and related abstractions will still change as part of that project.

Benchmark introduction

Microsoft is continuously benchmarking the ASP.NET Core stack. The results can be seen at https://aka.ms/aspnet/benchmarks. The benchmarks include scenarios from the TechEmpower web framework benchmarks.

It is easy to get lost watching the benchmark results, so let me give a short overview of the TechEmpower benchmarks.

There are a number of scenarios (also called test types). The Fortunes test type is the most interesting, because it includes using an object-relational mapper (ORM) and a database. This is a common use-case in a web application/service. Previous versions of ASP.NET Core did not perform well in this scenario. ASP.NET Core 2.1 improved it significantly thanks to optimizations in the stack and also in the PostgreSQL driver.

The other scenarios are less representative of a typical application. They stress particular aspects of the stack. They may be interesting to look at if they match your use-case closely. For framework developers, they help identify opportunities to optimize the stack further.

For example, consider the Plaintext scenario. This scenario involves a client sending 16 requests back-to-back (pipelined) for which the server knows the response without needing to perform I/O operations or computation. This is not representative of a typical request, but it is a good stress test for parsing HTTP requests.

Each implementation has a class. For example, ASP.NET Core Plaintext has a platform, micro, and full implementation. The full implementation is using the MVC middleware. The micro implementation is implemented at the pipeline level, and the platform implementation is directly building on top of Kestrel. While the platform class provides an idea of how powerful the engine is, it is not an API that is used to program against by application developers.

The benchmark results include a Latency tab. Some implementations achieve a very high number of requests per second but at a considerable latency cost.

Linux transport

Similar to the other implementations, the Linux transport makes use of non-blocking sockets and epoll. Like .NET Core’s Socket, the eventloop is implemented in managed (C#) code. This is different from the libuv loop, which is part of the native libuv library.

Two Linux-specific features are used: SO_REUSEPORT lets the kernel load-balance accepted connections over a number of threads, and the Linux AIO API is used to batch send and receive calls.

Benchmark

For our benchmark, we’ll use the JSON and Plaintext scenarios at the micro class. For the JSON benchmark, the web server responds with a simple JSON object that is serialized for each request. This means that for each request, our web server will do a tiny amount of useful work which makes the transport weigh through. For the Plaintext scenario, the server responds with a fixed string. Due to the pipelining (per 16 requests), only 1/16 of the requests need to do network I/O.

Each transport has a number of settings. Both the libuv and Linux transport have a property to set the number of threads for receiving/sending messages. The Sockets transport performs sends and receives on the ThreadPool. It has an IOQueueCount setting that we’ll set instead.

The graphs below show the HTTP requests per second (RPS) for varying ThreadCount/IOQueueCount settings.

We can see that each transport is initially limited by the number of allocated threads. The actual handling happens on the ThreadPool, which is not fully loaded yet. We see Sockets has a higher RPS because it is also using the ThreadPool for network sends/receives. We can’t compare it with the other transports because it is constrained in a different way (it can use more threads for transporting).

Linux vs libuv
Plaintext +15%
JSON +20%

Transport is CPU-constrained

When we increase the ThreadCount sufficiently, the transport is no longer the limiting factor. Now the constraint becomes either the CPU or network bandwidth.

The TechEmpower Round 16 benchmark hit the network bandwidth for the Plaintext scenario. If you look at the benchmark results, you see the top results are all about the same value. These benchmarks indicate underutilized CPU.

For our benchmark, the CPU is fully loaded. The processor is busy sending/receiving and handling the requests. The difference we see between the scenarios is due to the different workload per network request. For Plaintext, we receive 16 pipelined HTTP requests with a single network request. For JSON, there is an HTTP request per network request. This makes the transport weigh through much more in the JSON scenario compared to the Plaintext scenario.

libuv vs Sockets Linux vs libuv Linux vs Sockets
Plaintext +9% +0% +9%
Json +17% +10% +28%

App is CPU-constrained

Using the Linux transport

The Kestrel Linux transport is an experimental implementation. You can try it by using the 2.1.0-preview1 package published on myget.org. If you try this package, you can use this GitHub issue to give feedback and to be informed of (security) issues. Based on your feedback, we’ll see if it makes sense to maintain a supported 2.1 version published on nuget.org.

Do this to add the myget feed to a NuGet.Config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
	<add key="rh" value="https://www.myget.org/F/redhat-dotnet/api/v3/index.json" />
  </packageSources>
</configuration>

And add a package reference in your csproj file:

<PackageReference Include="RedHat.AspNetCore.Server.Kestrel.Transport.Linux" Version="2.1.0-preview1" />

Then we call UseLinuxTransport when creating the WebHost in Program.cs:

public static IWebHost BuildWebHost(string[] args) =>
        	WebHost.CreateDefaultBuilder(args)
            	.UseLinuxTransport()
            	.UseStartup()
            	.Build();

It is safe to call UseLinuxTransport on non-Linux platforms. The method will change the transport only when the application runs on a Linux system.

Conclusion

In this blog post, you’ve learned about Kestrel and how its Transport abstraction supports replacing the network implementation. We took a closer look at TechEmpower benchmarks and explored how CPU and network limits affect benchmark results. We’ve see that a Linux-specific transport can give a measurable gain compared to the default out-of-the-box implementations.

For information about running .NET Core on Red Hat Enterprise Linux and OpenShift, see the .NET Core Getting Started Guide.

Related

Pazartesi, 27 Ağustos 2018 / Published in Uncategorized

With the release of ASP.NET Core, there are several templates in the DotNet CLI. One of those templates is an Angular template that scaffolds a single page application built with Angular and ASP.NET Core. The problem with that template is that it scaffolds an Angular 4.2.5 project and Angular released Angular 6 in May of 2018!

In this post, not only will I show you how to build a base CRUD app with ASP.NET Core 2.1 and Angular, but I will show you how to update the Angular project to the latest and greatest, which is Angular 6 as of this writing! Let’s get right to it!

Update the DotNet CLI Angular Project to Angular 6

The project that the DotNet CLI for Core 2.1 scaffolds is using Angular 4.2.5, which will work. But if you’re looking to use Angular version 6, there are a few steps you’ll need to complete to get there.

Update the DotNet CLI Template Packages

Start by updating the SPA project templates:

dotnet new --install Microsoft.DotNet.Web.Spa.ProjectTemplates::2.1.0

Then run:

dotnet new --install Microsoft.AspNetCore.SpaTemplates::2.1.0-preview1-final

Scaffold an Angular App

Now you can scaffold a new project:

dotnet new angular -o dotnet-angular-crud-example

If you then open the app with VS Code, you can allow VS Code to add the .vscode folder that will allow you to run the application with a press of the F5 key. But the closest that gets you is Angular v5.2.0.

Upgrade to Angular 6

To update Angular to the latest version (v6.0.9 as of this writing) switch to the ClientApp directory and run:

This will update the package.json file; then you need to run:

If you get a message about @angular/cli you can update it by running:

You may now see some vulnerabilities in your NPM packages. To fix them run:

You may have to run this several times as some of the fixes introduce new vulnerabilities. I was only able to get my vulnerability list down to 6. I still have one low and five moderate vulnerabilities. You could hunt them each down and fix them manually.

Now you should be able to run the app by pressing the F5 key and see the example app running as before.

You may be presented with a warning page talking about security. This is because the new Angular app runs on port 5001 under TLS, and there is no certificate. You could create a certificate, or just go to advanced settings and tell the browser to proceed anyway. This is the much easier option and it doesn’t warn you every time.

Create and Okta Application and API Token

Dealing with user authentication in web apps is a massive pain for every developer. This is where Okta shines: it helps you secure your web applications with minimal effort.

Why Okta?

At Okta, our goal is to make identity management a lot easier, more secure, and more scalable than what you’re used to. Okta is a cloud service that allows developers to create, edit, and securely store user accounts and user account data, and connect them with one or multiple applications. Our API enables you to:

Add Okta to Your ASP.NET Core + Angular App

To get started, you’ll need to create an OpenID Connect application in Okta. Sign up for a forever-free developer account (or log in if you already have one).

Once you’ve logged in and landed on the dashboard page, copy down the Org URL pictured below. You will need this later.

Then create a new application by browsing to the Applications tab and clicking Add Application, and from the first page of the wizard choose Single-Page App.

On the settings page, enter the following values:

  • Name: AngularCrudApp
  • Base URIs: http://localhost:5000
  • Login redirect URIs: http://localhost:5000/implicit/callback

You can leave the other values unchanged, and click Done.

Now that your application has been created copy down the Client ID and Client secret values on the following page, you’ll need them soon.

Finally, create a new authentication token. This will allow your app to talk to Okta to retrieve user information, among other things. To do this, click the API tab at the top of the page followed by the Create Token button. Give your token a name, in this case, “Crud API” would be a good name, then click Create Token. Copy down this token value as you will need it soon.

Add Okta to Your Angular Application

You’ll need a couple of dependencies to set up Okta in your Angular app, so run:

npm install @okta/okta-angular rxjs-compat@6 --save

This installs Okta’s Angular SDK and the rxjs compatibility library for rxjs 6. Since the Angular SDK is still using rxjs 5 internally, this package provides backward compatibility for it.

Now you’ll want to store the configuration information in your Angular application.

In the ClientApp/src/app/app.module.ts file, you’ll need to import some Okta modules and components and configure Okta as your identity provider. First, import the OktaAuthModule and the OktaCallbackComponent.

import { OktaAuthModule, OktaCallbackComponent } from '@okta/okta-angular';

Then, right below the import statements, add a config variable that will hold your Okta configuration, replacing you okta domain and client id as needed.

const config = {
  issuer: 'https://{yourOktaDomain}/oauth/default',
  redirectUri: 'http://localhost:5000/implicit/callback',
  clientId: '{clientId}'
};

To the imports property of the main @NgModule add the OktaAuthModule.

OktaAuthModule.initAuth(config);

finally, add the OktaCallbackComponent as the handler for the callback path in the routing.

{ path: 'implicit/callback', component: OktaCallbackComponent }

Ultimately, your app.module.ts file will look like:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { OktaAuthModule, OktaCallbackComponent } from '@okta/okta-angular';

import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';
import { ProfileComponent } from './profile/profile.component';

const config = {
  issuer: 'https://{yourOktaDomain}/oauth/default',
  redirectUri: 'http://localhost:5000/implicit/callback',
  clientId: '{clientId}'
};

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    CounterComponent,
    FetchDataComponent,
    ProfileComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full' },
      { path: 'counter', component: CounterComponent },
      { path: 'fetch-data', component: FetchDataComponent },
      { path: 'implicit/callback', component: OktaCallbackComponent }
    ]),
    OktaAuthModule.initAuth(config)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

In the ClientApp/src/app/nav-menu/nav-menu.component.ts file, add the navigation for the login and logout functionality. Change the component code so that it looks like:

import { Component } from '@angular/core';
import { OktaAuthService } from '@okta/okta-angular';

@Component({
  selector: 'app-nav-menu',
  templateUrl: './nav-menu.component.html',
  styleUrls: ['./nav-menu.component.css']
})
export class NavMenuComponent {
  isExpanded = false;
  isAuthenticated: boolean;

  constructor(public oktaAuth: OktaAuthService) {
    this.oktaAuth.$authenticationState.subscribe(
      (isAuthenticated: boolean) => (this.isAuthenticated = isAuthenticated)
    );
  }

  async ngOnInit() {
    this.isAuthenticated = await this.oktaAuth.isAuthenticated();
  }

  login() {
    this.oktaAuth.loginRedirect('/profile');
  }

  logout() {
    this.oktaAuth.logout('/');
  }

  collapse() {
    this.isExpanded = false;
  }

  toggle() {
    this.isExpanded = !this.isExpanded;
  }
}

Then add login and logout buttons to the component’s template. To the navbar-nav unordered list element, add a new list item:

<li>
    <button *ngIf="!isAuthenticated" (click)="login()"> Login </button>
    <button *ngIf="isAuthenticated" (click)="logout()"> Logout </button>
</li>

Finally, add a profile page to the Angular application. You can take advantage of the Angular CLI here, by changing into the ClientApp/src/app folder and running:

This uses the Angular CLI (ng) and tells it to generate (g) a new component (c) called profile. The CLI will generate all the files needed with the base templates in each.

In the profile directory, open the profile component and paste in the following code replacing all that is there.

import { Component, OnInit } from '@angular/core';
import { OktaAuthService } from '@okta/okta-angular';

@Component({
  selector: 'app-profile',
  templateUrl: './profile.component.html',
  styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
  user: any;
  constructor(private oktaAuth: OktaAuthService) {}

  async ngOnInit() {
    this.user = await this.oktaAuth.getUser();
  }
}

This profile component code gets the user using the OktaAuthService provided by the Angular SDK and puts it into a component-level variable to use in the template.

In the profile.component.html file, paste the following code in replacing what’s currently there.

<h1>
  Welcome {{user ? user.email : null}}!
</h1>

You’ll need a way for users to navigate to the profile page, so add it to the nav menu and routing. In the nav-menu component, add a new list item.

<li #ngIf='isAuthenticated' [routerLinkActive]='["link-active"]'>
    <a [routerLink]='["/profile"]' (click)='collapse()'>
        <span class='glyphicon glyphicon-user'></span> Profile
    </a>
</li>

The *ngIf will make sure the navigation only shows if the user is logged in.

Then add a protected route to the app.module.ts file for the profile page. First, add the OktaAuthGuard component to the imports from the @okta/okta-angular package to protect the route so that your import statement now looks like this.

import {
  OktaAuthModule,
  OktaCallbackComponent,
  OktaAuthGuard
} from '@okta/okta-angular';

then add the protected route to the profile page.

{ path: 'profile', component: ProfileComponent, canActivate: [OktaAuthGuard] },

Now you can fire up the application (with F5) and see the application, login, view the profile page and logout.

Add Authentication to the ASP.NET Core API

For the ASP.NET Core application, the best thing to do is set up a file in your home folder to store the configuration. Okta’s SDK will pick the settings up for you, and you’ll never accidentally check them into source control!

In your home directory, create an .okta folder and add a file called okta.yaml. Your home folder will depend on your operating system. For *nix variants like Linux or macOS it is:

for Windows environments it is:

%userprofile%\.okta\okta.yaml

YAML is just a file format for configuration. The okta.yaml file looks like:

okta:
  client:
    orgUrl: "https://{yourOktaDomain}"
    token: "{yourApiToken}"

In the ConfigureServices() method before the services.AddMvc() line, add:

services.AddAuthentication(sharedOptions =>
{
  sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
  options.Authority = "https://{yourOktaDomain}/oauth2/default";
  options.Audience = "api://default";
});

And in the Configure() method before the app.UseMvc() line add:

That’s it! Now your ASP.NET Core app will take that bearer token, get the user’s information from Okta add them to the User object so you can get the currently requesting user’s data.

Set Up The ASP.NET Core API Database

You can use just about any database with DotNet Core and EntityFramework, but for the tutorial you’ll use EntityFramework’s in-memory database, a small database kept in memory. It is a great way to do development and then switch to the production database is as easy as changing the configuration!

In the ConfigureService() method of Startup.cs, add one line right after the services.AddMvc() set up.

services.AddDbContext<RestaurantRatingContext>(options => options.UseInMemoryDatabase("RestaurantRatingDb"));

You’ll also need to create the RestaurantRatingContext that you just referred to there. I put mine in the Models folder for ease of use.

using Microsoft.EntityFrameworkCore;

namespace okta_dotnetcore_react_example.Data
{
  public class RestaurantRatingContext : DbContext
  {
    public RestaurantRatingContext(DbContextOptions<RestaurantRatingContext> options) :
      base(options)
    { }

    public DbSet<RestaurantRating> Sessions { get; set; }
  }
}

While you’re in the Models folder, go ahead and create the model for the restaurant rating in a file called RestaurantRating.cs.

using System.ComponentModel.DataAnnotations;

namespace okta_dotnetcore_react_example.Data
{
  public class RestaurantRating
  {
    [Key]
    public int ID { get; set; }
    public string UserID { get; set; }
    public string RestarauntName { get; set; }
    public string RestaurantType { get; set; }
    public int Rating { get; set; }
  }
}

Now, create a controller to handle all the requests for creating, reading, updating, and deleting restaurant ratings. In the Controllers folder, create a file called RestaurantRatingController.cs.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace dotnet_angular_crud_example.Controllers
{
  [Authorize]
  [Route("/api/[controller]")]
  public class RestaurantRatingController : Controller
  {

  }
}

The Authorize attribute on the controller will ensure that only logged in users can work with restaurant ratings. Now, you just need to add the actions that will handle the CRUD operations, so that your final controller looks like this:

using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using okta_dotnetcore_react_example.Data;

namespace dotnet_angular_crud_example.Controllers
{
  [Authorize]
  [Route("/api/[controller]")]
  public class RestaurantRatingController : Controller
  {
    private readonly RestaurantRatingContext context;

    public RestaurantRatingController(RestaurantRatingContext context)
    {
      this.context = context;
    }

    [HttpGet]
    public async Task<ActionResult> GetAsync()
    {
      var userId = this.GetUserId();
      var ratings = await context.RestaurantRatings
        .Where(rr => rr.UserID == userId).ToListAsync();
      return Ok(ratings);
    }

    [HttpGet("{id}")]
    public async Task<ActionResult> GetByIdAsync(int id)
    {
      var userId = this.GetUserId();
      var rating = await context.RestaurantRatings
        .SingleOrDefaultAsync<RestaurantRating>(rr => rr.ID == id);
      if (rating.UserID != userId)
      {
        return Unauthorized();
      }
      else
      {
        return Ok(rating);
      }
    }

    [HttpPost]
    public async Task<ActionResult> PostAsync([FromBody] RestaurantRating rating)
    {
      var userId = this.GetUserId();
      if (rating.ID > 0)
      {
        var savedRating = await context.RestaurantRatings
          .SingleOrDefaultAsync<RestaurantRating>(rr => rr.ID == rating.ID);

        if (savedRating == null)
        {
          return NotFound(rating);
        }

        if (savedRating.UserID != userId)
        {
          return Unauthorized();
        }

        savedRating.RestaurantName = rating.RestaurantName;
        savedRating.RestaurantType = rating.RestaurantType;
        savedRating.Rating = rating.Rating;
        await context.SaveChangesAsync();
        return Ok(rating);
      }
      else
      {
        rating.UserID = userId;
        await context.AddAsync<RestaurantRating>(rating);
        await context.SaveChangesAsync();
        return CreatedAtAction("GetByIdAsync", rating);
      }

    }

    [HttpDelete("{id}")]
    public async Task<ActionResult> DeleteAsync(int id)
    {
      var ratingToDelete = new RestaurantRating { ID = id };
      context.RestaurantRatings.Attach(ratingToDelete);
      context.Entry(ratingToDelete).State = EntityState.Deleted;
      await context.SaveChangesAsync();
      return Ok();
    }

    private string GetUserId()
    {
      return User.Claims.SingleOrDefault(u => u.Type == "uid")?.Value;
    }
  }
}

There are a couple of things of note here:

First, all of the controller actions are asynchronous. This will help prevent performance bottlenecks. I am also using some ActionResult helper methods like Ok() and NotFound(). These are super helpful in making sure the right HTTP status is set in the return headers. You may also notice a rather odd helper being returned in the PostAsync() method called CreatedAtAction(). Not only does this helper send the right HTTP status, but it adds a URL for getting the newly created resource in proper ReST form!

Second, I created a method for getting the logged in user’s ID from their claims. This makes things a bit more readable and maintainable.

Add Ratings From the Angular 6 App

Now that your API is ready to save all the ratings to the database, you need to create the user interface that will allow users to enter their restaurant ratings.

In this case, just about everything can happen in the profile page. Part of the beauty of a single page app is that all of the CRUD operations for a single resource can be handled on a single page and the interface feels intuitive.

Start by creating a TypeScript object that will define the RestaurantRating type. In the src/app folder, create a file called RestaurantRating.ts and add the following contents:

export class RestaurantRating {
  id: number;
  userId: string;
  restaurantName: string;
  restaurantType: string;
  rating: number;
}

The type creates a class with all the properties needed for a restaurant rating. Then add an Angular service that will be the main point of interaction with the API.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { RestaurantRating } from './RestaurantRating';

@Injectable({
  providedIn: 'root'
})
export class RestaurantRatingsService {
  apiUrl = '/api/restaurantrating';

  constructor(private http: HttpClient) {}

  getAll(): Observable<Array<RestaurantRating>> {
    return this.http.get<Array<RestaurantRating>>(this.apiUrl);
  }

  addOrUpdate(rating: RestaurantRating): Observable<RestaurantRating> {
    return this.http.post<RestaurantRating>(this.apiUrl, rating);
  }

  delete(id: number): Observable<any> {
    return this.http.delete<RestaurantRating>(`${this.apiUrl}/${id}`);
  }
}

This is the service you’ll call from the Angular application to interact with the ASP.NET Core Web API. It uses the RestaurantRating type to enforce typing in the calls to the API and uses the HttpClient from Angular’s @angular/common/http package to make HTTP calls, and returns observables from the rxjs package.

The next step is to inject this new service into the profile component, so you’ll need to import it and the RestaurantRating type:

import { RestaurantRatingsService } from '../shared/restaurant-ratings.service';
import { RestaurantRating } from '../shared/RestaurantRating';

The constructor of the profile component also changes to take in the rating service you just created:

constructor(
    private oktaAuth: OktaAuthService,
    private ratingService: RestaurantRatingsService
  ) {}

Add to the ngOnInit() method a call to the service that gets all restaurant ratings. First, you’ll need a value in the component to put them in once they’ve been returned from the API, so add to the profile.component.ts:

ratings: Array<RestaurantRating> = [];

Then change the ngOnInit() so that it looks like:

  async ngOnInit() {
    this.user = await this.oktaAuth.getUser();
    await this.ratingService
      .getAll()
      .subscribe(ratings => (this.ratings = ratings));
  }

Finally, add the HTML to the component’s template to display all the ratings:

<ul class="list-group" *ngIf="ratings.length">
  <li class="list-group-item" *ngFor="let rating of ratings">
    {{rating.restaurantName}} is a type of {{rating.restaurantType}} with a rating of {{rating.rating}}
  </li>
</ul>

This is all well and good, but there still is no way to add ratings. So for now, there will never be any ratings in the list. Fix that by adding the “Create” and “Update” parts of the CRUD flow.

In the profile.component.ts add a new method below the ngOnInit() function:

async addUpdateRating() {
  await this.ratingService
    .addOrUpdate(this.currentRating)
    .subscribe(rating => {
      if (!this.currentRating.id) {
        this.ratings.push(rating);
      }
      this.currentRating = new RestaurantRating();
    });
}

This method will handle adding and updating the ratings. It will subscribe to the service call, and if the currentRating property has an ID, it will push the “new” rating onto the ratings array. You’ll need a currentRating property to allow the user to select a rating for editing, so add it to the component class.

currentRating: RestaurantRating = new RestaurantRating();

As well as a way to select a rating into the currentRating property. So below the addUpdateRating() function add:

selectRating(rating: RestaurantRating) {
  this.currentRating = rating;
}

You’ll need a form for users to fill out to add and edit ratings, so add to the component’s HTML template below the ul:

<form class="form-inline">
  <label class="sr-only" for="restaurantName">Restaurant</label>
  <input type="text" class="form-control" [(ngModel)]="currentRating.restaurantName" name="restaurantName" placeholder="Restaurant Name">

  <label class="sr-only" for="restaurantType">Restaurant Type</label>
  <input type="text" class="form-control" [(ngModel)]="currentRating.restaurantType" name="restaurantType" placeholder="Restaurant Type">

  <label class="sr-only" for="rating">Rating</label>
  <input type="number" class="form-control" [(ngModel)]="currentRating.rating" name="rating" placeholder="Rating (1-10)">

  <button type="submit" class="btn btn-primary" (click)="addUpdateRating()">Rate It!</button>
</form>

You’ll also need something for the user to click on to select a rating to edit, so add to the rating list in the template:

<ul class="list-group" *ngIf="ratings.length">
  <li class="list-group-item" *ngFor="let rating of ratings">
    <button (click)="selectRating(rating)" class="btn btn-default btn-xs">
      <i class="glyphicon glyphicon-pencil"></i>
    </button>
    {{rating.restaurantName}} is a type of {{rating.restaurantType}} with a rating of {{rating.rating}}
  </li>
</ul>

Now the user can add and edit ratings, as well as the ability to view a list of the ratings they’ve entered. All that is left is a way to delete ratings from the list (and database). To do this, add a method in the profile.component.ts file.

async deleteRating(rating: RestaurantRating) {
  await this.ratingService.delete(rating.id).subscribe(response => {
    var idx = this.ratings.indexOf(rating);
    this.ratings.splice(idx, 1);
  });
}

The only other thing is a user interface element for the user to click on to delete a rating. Inside the li for ratings add:

<button (click)="deleteRating(rating)" class="btn btn-danger btn-xs">
  <i class="glyphicon glyphicon-remove"></i>
</button>

In the end, the final profile.component.ts code is:

import { Component, OnInit } from '@angular/core';
import { OktaAuthService } from '@okta/okta-angular';
import { RestaurantRatingsService } from '../shared/restaurant-ratings.service';
import { RestaurantRating } from '../shared/RestaurantRating';

@Component({
  selector: 'app-profile',
  templateUrl: './profile.component.html',
  styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
  user: any;
  ratings: Array<RestaurantRating> = [];
  currentRating: RestaurantRating = new RestaurantRating();

  constructor(
    private oktaAuth: OktaAuthService,
    private ratingService: RestaurantRatingsService
  ) {}

  async ngOnInit() {
    this.user = await this.oktaAuth.getUser();
    await this.ratingService
      .getAll()
      .subscribe(ratings => (this.ratings = ratings));
  }

  async addUpdateRating() {
    await this.ratingService
      .addOrUpdate(this.currentRating)
      .subscribe(rating => {
        if (!this.currentRating.id) {
          this.ratings.push(rating);
        }
        this.currentRating = new RestaurantRating();
      });
  }

  async deleteRating(rating: RestaurantRating) {
    await this.ratingService.delete(rating.id).subscribe(response => {
      var idx = this.ratings.indexOf(rating);
      this.ratings.splice(idx, 1);
    });
  }

  selectRating(rating: RestaurantRating) {
    this.currentRating = rating;
  }
}

The completed ‘profile.component.html` file contents are:

<h1>
  Welcome {{user ? user.name : null}}!
</h1>
<ul class="list-group" *ngIf="ratings.length">
  <li class="list-group-item" *ngFor="let rating of ratings">
    <button (click)="deleteRating(rating)" class="btn btn-danger btn-xs">
      <i class="glyphicon glyphicon-remove"></i>
    </button>
    <button (click)="selectRating(rating)" class="btn btn-default btn-xs">
      <i class="glyphicon glyphicon-pencil"></i>
    </button>
    {{rating.restaurantName}} is a type of {{rating.restaurantType}} with a rating of {{rating.rating}}
  </li>
</ul>
<form class="form-inline">
  <label class="sr-only" for="restaurantName">Restaurant</label>
  <input type="text" class="form-control" [(ngModel)]="currentRating.restaurantName" name="restaurantName" placeholder="Restaurant Name">

  <label class="sr-only" for="restaurantType">Restaurant Type</label>
  <input type="text" class="form-control" [(ngModel)]="currentRating.restaurantType" name="restaurantType" placeholder="Restaurant Type">

  <label class="sr-only" for="rating">Rating</label>
  <input type="number" class="form-control" [(ngModel)]="currentRating.rating" name="rating" placeholder="Rating (1-10)">

  <button type="submit" class="btn btn-primary" (click)="addUpdateRating()">Rate It!</button>
</form>

That’s it! You should be able to fire up the application and Create, Read, Update, and Delete restaurant ratings in your new application, once you’ve logged in of course.

Learn More CRUD!

Check out our other CRUD posts on the Okta developer blog:

As always, if you have any comments or concerns, feel free to leave a comment below. Don’t forget to follow us on Twitter and on Facebook!

Pazartesi, 27 Ağustos 2018 / Published in Uncategorized

Previous posts in the series:

You’ve implemented some of your performance critical code using the new platform intrinsics API. The code is now running 10x or even 100x faster than before, and you might think that it can’t get any faster. This post will show you some less obvious (but almost universally applicable) techniques for improving the performance even further.

The code

This time we are going to analyze the function that calculates the sum of an array of integers:

public static int Sum(int[] source)
{
  const int VectorSizeInInts = 8;

  fixed (int* ptr = &source[0])
  {
    var pos = 0;
    var sum = Avx.SetZeroVector256<int>();

    for (; pos <= source.Length - VectorSizeInInts; pos += VectorSizeInInts)
    {
      var current = Avx.LoadVector256(ptr + pos);
      sum = Avx2.Add(current, sum);
    }

    var temp = stackalloc int[VectorSizeInInts];
    Avx.Store(temp, sum);

    var final = Sum(temp, VectorSizeInInts);
    final += Sum(ptr + pos, source.Length - pos);

    return final;
  }
}

Nothing fancy here—it just follows the pattern that we see very often when dealing with vectorized code. Let’s see how well it performs.

Benchmarking, take one

We will measure how long it takes to sum an array of 32K integers. Our benchmarking setup is going to be very simple:

public class SumBenchmark
{
  private const int Length = 32 * 1024;
  private int[] data;

  [GlobalSetup]
  public void GlobalSetup()
  {
    data = Enumerable.Range(0, Length).ToArray();
  }

  [Benchmark]
  public int Sum() => FastMath.Sum(data);
}

This benchmark produces the following numbers on my machine:

Method Mean Error StdDev
Sum 2.264 us 0.0352 us 0.0329 us

The results look fantastic, beating the naive implementation by one order of magnitude (if you are interested in the exact numbers, take a look here).

You want to be sure that there are no variations, so you run the benchmark several times to increase your confidence in the results, but you get pretty much the same numbers on each run. Is it time to call it a day? Not just yet: even though the SumBenchmark class looks completely reasonable, it contains one very subtle flaw.

Benchmarking, take two

Let’s modify our benchmarking code slightly:

[GlobalSetup]
public void GlobalSetup()
{
  data1 = Enumerable.Range(0, Length).ToArray();
  data2 = Enumerable.Range(0, Length).ToArray();
}

[Benchmark(Baseline = true)]
public int Sum1() => FastMath.Sum(data1);

[Benchmark]
public int Sum2() => FastMath.Sum(data2);

You would probably expect both Sum1 and Sum2 to have the identical performance characteristics. After all, we are calling the same function on two arrays with the exact same contents. But if you run the benchmark, you will see that Sum2 actually performs 13% worse!

Method Mean Error StdDev Scaled
Sum1 2.283 us 0.0211 us 0.0198 us 1.00
Sum2 2.589 us 0.0241 us 0.0214 us 1.13

What is going on here?

Alignment

When working with most of AVX instructions, you initially have to load the data from the memory into 32-byte registers. The CPU does that in the most efficient way when the data is aligned in memory on a 32-byte boundary. How does that apply to our situation?

In one of the runs of the modified benchmark, the data1 array was located at the address 0x19aa99ce0, while the data2 was placed at 0x19aab9d18. The first number is divisible by 32; the second one is not. That was not just a coincidence: each time I ran the benchmark, the first allocation ended up on a properly aligned address, but the second one didn’t (I guess that the heap segments are aligned, which would mean that the first allocated object in the program would also be aligned, but I didn’t bother to check that hypothesis, so it might be terribly wrong).

Dealing with an alignment is burdensome, which is why the LoadVector256 function works with any memory location—it just works slower when the location is unaligned. There is also another variant of Load function, called LoadAlignedVector256, which works the same in the aligned case (it’s not any faster), but throws an exception if the input is not aligned on a 32-byte boundary. It’s useful mostly as a signal that its input is expected to be aligned.

There are no guarantees that our input array is always going to be correctly aligned, so you might think that we can’t do anything about the performance in the unaligned case. Luckily, we don’t have to start processing the array from the first element—instead we can find the first aligned element, and proceed from there (that means we have to calculate the sum of previous elements manually). To do that, we just have to round up the address of our array to the nearest multiple of 32:

var aligned = (int*)(((ulong)ptr + 31UL) & ~31UL);
var pos = (int)(aligned - ptr);
var final = Sum(ptr, pos);

The rest of the code remains the same (we can also replace the call to LoadVector256 with the call to LoadAlignedVector256 in order to catch potential bugs in our code more easily). We can now expect the best-case performance on any input, but we still have to confirm that in practice:

Method Alignment Mean Error StdDev Scaled
Sum 8 2.508 us 0.0353 us 0.0313 us 1.00
SumAligned 8 2.260 us 0.0106 us 0.0082 us 0.90
           
Sum 32 2.254 us 0.0187 us 0.0166 us 1.00
SumAligned 32 2.264 us 0.0256 us 0.0227 us 1.00

We are indeed getting the expected 10% performance improvement on unaligned arrays! Nothing spectacular, but we are not stopping there.

Pipelining

I’ve already talked briefly about pipelining in the second post of this series, so you might want to take a look at it if you want to refresh your memory. Now let’s see if it’s possible to apply it somehow in our Sum function. Here’s what the documentation for the _mm256_loadu_si256 intrinsic says (the page for the _mm256_load_si256 is almost the same):

The properties we are interested in are latency and throughput. We can see that the instruction has a latency of 1, which means it takes one CPU cycle to complete. What is more interesting is that it has a throughput of 0.25 (except on Ivy Bridge, where its throughput is 0.5), which is just another way of saying that we can issue four instructions in the same cycle! It means that if we changed our code to process four 32-byte blocks of input at the same time, we could expect at least some performance improvement. Here’s the modified version of the code:

const int VectorSizeInInts = 8;
const int BlockSizeInInts = 32;

for (; pos <= source.Length - BlockSizeInInts; pos += BlockSizeInInts)
{
  var block0 = Avx.LoadVector256(ptr + pos + 0 * VectorSizeInInts);
  var block1 = Avx.LoadVector256(ptr + pos + 1 * VectorSizeInInts);
  var block2 = Avx.LoadVector256(ptr + pos + 2 * VectorSizeInInts);
  var block3 = Avx.LoadVector256(ptr + pos + 3 * VectorSizeInInts);

  sum = Avx2.Add(block0, sum);
  sum = Avx2.Add(block1, sum);
  sum = Avx2.Add(block2, sum);
  sum = Avx2.Add(block3, sum);
}

for (; pos <= source.Length - VectorSizeInInts; pos += VectorSizeInInts)
{
  var current = Avx.LoadVector256(ptr + pos);
  sum = Avx2.Add(current, sum);
}

Notice that after the first loop is completed, we might still have several vector-sized blocks of data remaining, so we have to run the original loop to process the rest. We are ready to run the benchmark again:

Method Alignment Mean Error StdDev Scaled
Sum 8 2.556 us 0.0144 us 0.0121 us 1.00
SumPipelined 8 2.116 us 0.0189 us 0.0168 us 0.83
           
Sum 32 2.264 us 0.0127 us 0.0113 us 1.00
SumPipelined 32 1.654 us 0.0133 us 0.0124 us 0.73

The results are looking great! The next obvious step is to combine both alignment and pipelining in the same function.

Combined solution

Here’s the complete source code of the ultimate version of the Sum function:

public static int SumAlignedPipelined(int[] source)
{
  const ulong AlignmentMask = 31UL;
  const int VectorSizeInInts = 8;
  const int BlockSizeInInts = 32;

  fixed (int* ptr = &source[0])
  {
    var aligned = (int*)(((ulong)ptr + AlignmentMask) & ~AlignmentMask);
    var pos = (int)(aligned - ptr);
    var sum = Avx.SetZeroVector256<int>();
    var final = Sum(ptr, pos);

    for (; pos <= source.Length - BlockSizeInInts; pos += BlockSizeInInts)
    {
      var block0 = Avx.LoadAlignedVector256(ptr + pos + 0 * VectorSizeInInts);
      var block1 = Avx.LoadAlignedVector256(ptr + pos + 1 * VectorSizeInInts);
      var block2 = Avx.LoadAlignedVector256(ptr + pos + 2 * VectorSizeInInts);
      var block3 = Avx.LoadAlignedVector256(ptr + pos + 3 * VectorSizeInInts);

      sum = Avx2.Add(block0, sum);
      sum = Avx2.Add(block1, sum);
      sum = Avx2.Add(block2, sum);
      sum = Avx2.Add(block3, sum);
    }

    for (; pos <= source.Length - VectorSizeInInts; pos += VectorSizeInInts)
    {
      var current = Avx.LoadAlignedVector256(ptr + pos);
      sum = Avx2.Add(current, sum);
    }

    var temp = stackalloc int[VectorSizeInInts];
    Avx.Store(temp, sum);

    final += Sum(temp, VectorSizeInInts);
    final += Sum(ptr + pos, source.Length - pos);

    return final;
  }
}

And here are the final results:

Method Alignment Mean Error StdDev Scaled
Sum 8 2.501 us 0.0284 us 0.0251 us 1.00
SumAligned 8 2.271 us 0.0257 us 0.0241 us 0.91
SumPipelined 8 2.103 us 0.0276 us 0.0258 us 0.84
SumAlignedPipelined 8 1.645 us 0.0126 us 0.0118 us 0.66
           
Sum 32 2.255 us 0.0243 us 0.0227 us 1.00
SumAligned 32 2.277 us 0.0288 us 0.0269 us 1.01
SumPipelined 32 1.661 us 0.0219 us 0.0205 us 0.74
SumAlignedPipelined 32 1.653 us 0.0063 us 0.0056 us 0.73

The SumAlignedPipelined shows a noticeable improvement over the initial Sum: we are getting a 27% boost in performance if the data is 32-byte aligned, and 34% if it’s not.

Conclusion

You’ve seen how some very simple techniques can help you speed up your intrinsics code with almost no effort. The complete C# implementation of these performance exercises can be found in my alignment and pipelining GitHub repository.

Pazartesi, 27 Ağustos 2018 / Published in Uncategorized

The first preview of ASP.NET Core 2.2 is due (very) soon and it will be our first chance to test the changes and new features which are expected to be released by the end of this year.

ASP.NET Core 2.2 marks the next minor release of the ASP.NET Core framework, following on from the ASP.NET Core 2.1 release at the end of May. With these minor releases, the team are able to provide new features to us quickly and iterate on an already great product. ASP.NET Core 2.2 will be a “Current” release for those wanting to take advantage of the latest features more quickly. For some, the “current” releases may not be suitable as while offering newer features they do not offer the same long support commitment as long-term support (LTS). If you choose the “current” release train then you need to keep updating as new “current” releases are available (See the ASP.NET Core support policy for more details).

I’ve been watching the features planned for ASP.NET Core 2.2 since version 2.1 shipped. There are quite a few things which look pretty interesting. Today I want to take an early look at a new feature whose final name is  Endpoint Routing. You may also see this referred to by its former name “Dispatcher”.

Update 18-08-2018: James Newton-King who works on the ASP.NET team, has confirmed that the name for this feature with be Endpoint routing.

NOTE: This post is based on reading and watching some limited early coverage of Dispatcher (Global Routing) from the ASP.NET team over the last few months. I’ve also spent a small amount of time looking at the source code and some early samples to form the content below. As a result, there are things I may not have 100% correct! This post is written prior to the first preview of ASP.NET Core 2.2 and as a result, some of this could change before the final release of ASP.NET Core 2.2. If you’re reading this in the future, treat it with some caution and keep an eye out for more recent posts where I will cover using the released versions of the feature. If you’re reading this in the past, I’m pleased to see that time travel is now a thing!!

Update 18-08-2018: After feedback from James Newton-King who works on the ASP.NET team, I understand that in the 2.2 timeframe the only supported way to use Endpoint Routing will be via MVC.

What is Endpoint Routing (the feature formerly known as Dispatcher)?

The current routing story with ASP.NET Core 2.1 MVC is that we define routes within MVC using either convention-based routing which uses a RouteBuilder when we register MVC into the middleware pipeline or via Route Attributes on our action methods. Personally, I tend towards the attribute approach for the APIs I build.

When a request reaches MVC, the route information is used to determine which Controller and Action should be invoked to handle the request, based on the URL path. At this point, MVC can invoke that action which will then return the response. If a suitable route is not found then a 404 is returned instead.

One issue with this approach to routing is that as the request flows through the middleware chain, all other middleware has no idea of where that request is eventually going to be handled.

With the Endpoint Routing feature, routing decisions can occur earlier into the pipeline so that incoming requests can be mapped to their eventual endpoint before MVC is even invoked. This gives other middleware an opportunity to make more reasoned choices and process requests armed with the knowledge of which Endpoint will eventually handle the request.

Implemented as middleware the URL matching can now be registered to run very early in the application middleware pipeline. After which, a set of known Endpoints will be registered. When a request is passed through the pipeline, other middleware will be able to inspect the final matched Endpoint and view/update its associated metadata.

In addition, Endpoint Routing looks like it should allow developers to build ASP.NET Core applications that don’t use MVC, but which can still rely on routing to handle requests. Developers can provide their own EndpointDataSource, complete with a set of route patterns and the corresponding RequestDelegates to be invoked for matches. There are opportunities here for some very lightweight APIs to be built without the sometimes unnecessary additional overhead of MVC.

Note: Based on the feedback from James Newton-King this feature is expected to work with MVC as the support way to use it in 2.2. For the 3.0 timeframe a public API for non MVC use is expected to be ready.

The original ASP.NET Core 2.2 features announcement (where the feature is known as “Dispatcher”) included a good example of where this Endpoint Routing concept can be useful. CORS is currently implemented as both a feature of MVC and as middleware. This is necessary as some requests will be handled outside of MVC, such as serving static files. However, to apply CORS for requests which do reach MVC, the policy can’t be applied until the MVC routing selects the controller and action for the request. Global Routing will enable CORS to be implemented more consistently since the routing and Endpoints will be known up front when a request is matched through the middleware.

Endpoint Routing is also integrated with the latest ASP.NET Core 2.2 MVC functionality, allowing MVC to work on top of this new Endpoint Routing feature. MVC in ASP.NET Core 2.2 includes code changes to support building up a list of available Endpoints for Endpoint Routing, using the existing MVC route provider.

I plan to dive into all of this more deeply in future posts. I’m currently spending a fair bit of time in the Microsoft.AspNetCore.Routing source code understanding the building blocks and Types involved.

A Small Sample

I’ll end with a basic example of what the services and middleware pipeline for an ASP.NET Core 2.2 application using Endpoint Routing could look like. In this case, there’s no MVC involved (this is based on the current RoutingSample from the Routing repository).

Update 18-08-2018: After feedback from James Newton-King who works on the ASP.NET team, I understand that in the 2.2 timeframe the only supported way to use Endpoint Routing will be via MVC.

Inside the Startup class, we must register the routing services in the ConfigureServices method as follows…

This sample manually adds a DefaultEndpointDataSource with a single Endpoint which is not necessary if you wish to use the MVC routes. MVC will populate Endpoints for you.

Once registered we can add Endpoint Routing to the pipeline as middleware in the Configure method…

The first middleware, UseEndpointRouting is responsible for inspecting the incoming request and matching it to an Endpoint. The matched Endpoint is set in the HttpContext.Features collection. At this point, all other middleware can retrieve the Endpoint from the Features collection as necessary.

Since we’re not using MVC in this sample we need something to invoke the matched RequestDelegate for the Endpoint. UseEndpoint registers the middleware which does exactly that.

Summary

Hopefully, this has been a useful primer of what to expect with the Endpoint Routing feature in ASP.NET Core 2.2. I expect this to be available in the first preview of ASP.NET Core 2.2 (perhaps due by the end of the month). I have started building up some fairly extensive notes as I explore the code and I hope to put together some follow up posts demonstrating more concrete samples once the previews are formally available (and at which point the API surface is less likely to change). I may also produce a deeper dive into how this all functions internally as its quite interesting code to explore.

Pazartesi, 27 Ağustos 2018 / Published in Uncategorized

In the year 2008, Microsoft released the first version of MVC i.e. Model, View and Controller for the web programming framework. It was the one of biggest revolutionary released by the Microsoft in the recent past. Because, before this era, web developers mainly developed by using web forms which are mainly maintained by the control of the HTML templates including CSS and Scripting languages as required. The concept of web forms is very simple and easy for the web developers, especially for the beginners. But, in the case of MVC the concept is a little harder. Because in the technology, web developers need to take the full responsibility related to all web content in their applications.

In MVC, developers normally do not use any web content for their applications. Because, Microsoft introduced three helper objects (HtmlHelper, UrlHelper and AjaxHelper) for generating web control in the application. This helper objects basically simply and shorten the work of developer for designing any application of web interface. In MVC pattern, all the code of Razor views (include server-side) starts with @ sign. In this way, MVC framework always have a clear separation between the server-side code and client-side code.

WHY TAG HELPERS?

Microsoft introduced a new feature in the MVC Razor engine with the release of ASP.NET Core which is known as Tag Helpers. This feature helps web developers to use their old conventional HTML tags in their web applications for designing presentation layer. With the help of Tag Helpers, developers can design their presentation layer using HTML tag while they still can write business logic in the C# the code at server-side which will run in web server.

So, with the help of Tag Helpers which one is the Microsoft’s new features in ASP.NET CORE, developers can replace the Razor cryptic syntax with @ symbol with a more natural looking HTML-like syntax. So, the first question always arises that “Why we need Tag Helpers?”. The simple answer is that Tag Helpers actually reduce the coding amount in HTML which we need to write and also create an abstracted layer between our UI and server-side code. We can extend the existing HTML tag elements or can create custom elements just like HTML elements with the help of Tag Helpers. Actually, we can write server-side code in the Razor files to create new elements or rendering HTML elements. So, we can define the customs elements name, attribute or parent name just like the HTML elements by using Tag Helpers. But, we need to remember that Tag Helpers does not replace the HTML helpers, so we can use both of them side by side as per our requirement. In the below example, we can clearly see the difference between the two helper methods

// HTML Helpers
@Html.ActionLink("Click", "Controller1", "CheckData", { @class="my-css-classname", data_my_attr="my-attribute"}) 

//Tag Helpers
<a asp-controller="Controller1" asp-action="CheckData" class="my-css-classname" my-attr="my-attribute">Click</a>

In the above sample code of HTML, it is clear to see that how much similar to HTML the tag helper syntax looks like. In fact, when we use data attribute in HTML that is also optional in this case.

TAG HELPERS ADVANTAGES

Now, we need to understand why Tag Helpers is important or what are the advantages of its over the HTML Helper objects. So that, can compares of these two different helper objects. So, before going to in deep discussion about Tag Helpers, let’s discuss the main advantages of Tag Helpers over HTML Helpers objects

  1. Tag Helpers use server-side binding without any server-side code.

  2. This helper objects is very much use full when HTML developers do the UI designing who does not have any idea or concept about Razor syntax.

  3. It provides us an experience of working on basic HTML environments.the

  4. It Support rich intellisence environment support for create a markup between HTML and Razor

BUILT-IN TAG HELPERS

Microsoft provides many build-in Tag Helpers objects to boost our development. In the below table, there are a list of available built-it Tag Helpers in ASP.NET Core.

Tag Helpers About Descriptions
Anchor Tag Helpers

The Anchor Tag Helpers extend the standard HTML anchor tag (<a>..</a>) where it provide some new attribute. By standard convention, the attribute name must be start with asp-. This helper objects contains the below attributes –

  1. asp-controller – This attribute assign the controller name which is used for generating the URL.

  2. asp-action – This attribute is used to specify the controller action method name. If no value assign against this attribute name, then default asp-action value in the controller will execute to render the view.

  3. asp-route-{value} – This attribute actually enables a wildcard-based route prefix. Any value specified in the {value} placeholder is actually interpreting as a route parameter.

  4. asp-route – This attribute is used for creating a direct URL linking to an actual route value.

  5. asp-all-route-data – It support to create a dictionary of key-value pairs. The Key is the parameter name and value is the parameter value.

  6. asp-fragment – This attribute specify an URL fragment section to append the URL.

  7. asp-area – This attribute name actually set the area name used in the actual route.

  8. asp-protocol – This attribute is used to specify the protocol value like https in the URL.

  9. asp-host – It is used to specify the host name in the URL.

  10. asp-page – This attribute is need to be used with the Razor Pages.

<a asp-controller="Student" asp-action="Index" 
asp-route-id="@Model.Id"> StudentId: @Model.StudentId </a> >Student List</a>
Cache Tag Helpers

This Tag Helper objects provides the ability to catch the application content within the ASP.NET core cache provider. This helper objects basically increase the performance of the application. The default cached date time is set to twenty minutes by the Razor engine. The attributes of this Tag Helpers –

  1. enabled – This attribute decides that content within the Cache Tag Helper is cached or not. The default value is true.

  2. expires-on – This attribute is used to set the absolute expiration date for the cached data.

  3. expires-after – This attribute set the length of time from the first request to the cached content.

  4. expires-sliding – This attribute set the time span of the cached entity so that after that time that entity can be deleted if not accessed.

 <cache enabled="true">
 Last Cached Time: @DateTime.Now
</cache>
Distributed Cache Tag Helpers

This Tag Helper objects provides the ability to catch the application content within the ASP.NET core distributed cache provider. This helper objects basically increase the performance of the application. So, his Helpers objects and Cache Tag Helpers inherits from the same base class. So, for this reason, all attribute available under cache tag helpers will also available Distributed Cache Tag Helpers. Except for this attribute, it contains one new attribute as below –

  1. name -> This attribute provide the key of each instance of the cache entirely in the cache provider.
 <distributed-cache name="unique-cache-1">
 Time Inside Cache Tag Helper: @DateTime.Now
</distributed-cache>
Environment Tag Helpers

This Tag Helpers renders the enclosed HTML content based on the current hosting environment conditionally. This helper objects contains single attribute named name. This attribute accept string type value and value can be assigned as a comma separation method.

 <environment names="Testing,Release">
<strong>Application Environemt is Staging or Production</strong>
</environment>
Form Tag Helper

This Tag Helpers methods helps us to working with Form and HTML elements within a Form. The Form Tag Helpers can do –

  1. It can generate the same form action attribute which we normally used for MVC Controller to provide action name.
  2. Generate a hidden token to present cross origin forgery.
 <form asp-controller="Demo" asp-action="Save " method="post">
………………………………
</form>
Image Tag Helper

The Image Tag Helpers basically extend the <img> tag of the HTML. It always required an src tag as well as a Boolean attribute named asp- append-version. If we need to provide static image source from a hosted web server, then a cache bursting string is added into the query parameter as the image source. This process ensures us that if file changes then the related changes need to done mandatorily for the web server changes.

Input Tag Helper

This Tag Helpers is used for HTML input element to display model data in our Razor view. This helper objects do the following –

  1. asp-for attribute normally populate id and name of the specified html attribute for the display expression name.
  2. It can assign attribute value based on the model data to the HTML attribute
  3. It support HTML 5 based validation attributes related the model data annotations
 @model Login
<form asp-controller="Demo" asp-action="Register" method="post">
Provide Email: <input asp-for="Email" /> 
Provide Password: <input asp-for="Password" />
<button type="submit">SignUp</button>
</form>
Label Tag Helper

This Tag Helper basically extend the label tag of the HTML. It populates the caption of the label and attribute against the expression name. This Helper Object provide the advantages like –

  1. We automatically retrieve the label description from the Display attribute.
  2. It reduced the code volume of the markup.
  3. It also can be used as strong types for the model property.
 <form asp-controller="Demo" asp-action="Register" method="post">
<label asp-for="Email">Email Address</label>
<input asp-for="Email" /> 
</form>
Select Tag Helper

This Tag Helpers populate <select> tag of HTML and also associated option elements for the properties of the error. The asp-for attribute of this tag helps is used to mention the model property name of the select element. Similarly, asp-items specify the option element.

<select asp-for="Country" asp-items="Model.Countries"></select>

Text Area Tag Helpers

This Tag Helper is similar type of Input Tag Helper. Only different is that this tag helpers is application on <textarea> tag.

Validation Message Tag Helper

It is used to show the validation message in our view model.

Validation Summery Tag Helper

It is used to display validation summery messages.

CUSTOM TAG HELPERS

In ASP.NET Core, there are several built-in Tag Helpers objects available. But in spite of that, we can create a custom Tag Helpers and that can be included in the ASP.NET Core. We can add a custom tag helper in our MVC Core projects very easily. We can create separate projects for this custom tag helpers or can create in the same projects There are 3 easy steps need to perform for create a custom tag helper –

Step 1

First, we need to decide, which tag we need to target for create the custom tag helpers and then we need to create a class for the tag helpers. So, I want to create our first tag helper named "hello-world", so for that I need to add a class named HelloWorldTagHelper. Also, we need to remember that your tag helper class must be inherited from the TagHelper class.

Step 2

For perform the operations, we need to override the Process or ProcessAsync. In this method, we get two parameters as input –

1. TagHelperContext – The Tag Helpers receive information about the HTML element which they are transforming through an instances of the TagHelperContext class. It mainly contains 3 values –

  1. AllAttributes – It is a dictionary of property which we can use in our Tag Helpers.
  2. Items – It returns a dictionary which is used to co-ordinate between tag helpers.
  3. UniqueId – This property returns a unique id or identifier for the HTML element which has been transformed.

2.TagHelperOutput – This parameter is basically being the output of our tag helper declaration. It start describing the HTML elements as it view in the Razor engine and can be modified through the below properties as mentioned.

  1. TagName – It provide the root name of the tag element.

  2. Attributes – Provides a dictionary of items for the output attributes.

  3. PreElement – It returns TagHelperContext object which is used in the view before the output element.

  4. PostElement – It returns TagHelperContext object which is used in the view after the output element.

  5. PreContent – It returns TagHelperContext object which is used in the view before the output element con.

  6. PostContent – It returns TagHelperContext object which is used in the view after the output element con.

  7. TagMode – This property mention that either tag is SelfClosing, StartTagAndEndTag or StartTagOnly Tag.

  8. SupressOutput() – Execution of this method basically prevents the elements being including in the view.

namespace CustomTagHelper.TagHelpers 
 { 
 using Microsoft.AspNetCore.Razor.TagHelpers; 
 using System.Text; 
 
 [HtmlTargetElement("hello-world")] 
 public class HelloWorldTagHelper : TagHelper 
 { 
 public string Name { get; set; } 
 public override void Process(TagHelperContext context, TagHelperOutput output) 
 { 
 output.TagName = "CustumTagHelper"; 
 output.TagMode = TagMode.StartTagAndEndTag; 
 
 var strSb = new StringBuilder(); 
 strSb.AppendFormat("<span>Hello! My Name is {0}</span>", this.Name); 
 
 output.PreContent.SetHtmlContent(strSb.ToString()); 
 } 
 } 
 }

3.Use the tag in your view and pass the required attribute

SUMMARY

With the tag helper, we can extend the existing element or create new elements. We can developer custom reusable attribute or elements with the help of Tag Helpers. It also maintains the MVC naming conventions. But the most important thing is that Tag helpers can contain presentation logic. Business logic must remain in models or business service class. They can also be used as objects in strongly typed views. Also, it needs to remember that they’re no new way to create web controls. Tag Helpers does not contain any event model or view state. Tag Helpers give us more flexibility over the content in a great maintainable fashion.

Pazartesi, 27 Ağustos 2018 / Published in Uncategorized

Use the new HttpClientFactory to create HttpClient objects in ASP.NET Core. Learn how to create Named or Typed HttpClient instances.

With .NET Core 2.1 the HttpClientFactory is introduced. The HttpClientFactory is a factory class which helps with managing HttpClient instances. Managing your own HttpClient correctly was not so easy. The HttpClientFactory gives you a number of options for easy management of your HttpClient instances. In this post I’ll explain how to use the HttpClientFactory in your ASP.NET Core application.

HttpClient The HttpClient enables you to send HTTP requests and receive HTTP responses. The HttpClient is intended to be instantiated once for each uri and reused throughout the life of the application. It implements IDisposable, which seduces many developers to put it in an using block.

“Although HttpClient does indirectly implement the IDisposable interface, the standard usage of HttpClient is not to dispose of it after every request. The HttpClient object is intended to live for as long as your application needs to make HTTP requests. Having an object exist across multiple requests enables a place for setting DefaultRequestHeaders and prevents you from having to re-specify things like CredentialCache and CookieContainer on every request as was necessary with HttpWebRequest.” — From the book ‘Designing Evolvable Web APIs with ASP.NET’

HttpClient is probably the only IDisposible that should not be put into an using block. When creating unneeded HttpClient object, it can lead to a SocketException caused by open TCP/IP connections. When disposed is called, the connection will stay open for a 240 second to correctly handle the network traffic. A good explanation can be found here: You’re using HttpClient wrong and it is destabilizing your software.

However, when you try to solve it with a static member, a new problem will be introduced. It is not possible to do blue-green deployments caused by the behavior of the HttpClient. It will only renew its DNS when the connection is lost. Read Singleton HttpClient? Beware of this serious behaviour and how to fix it for more information on this.

Then in ASP.NET Core 2.1 the HttpClientFactory is introduced that manages the life cycle of the HttpClient instances. This will make developing good software so much easier. All life cycle management is done by the factory class and it also adds a very nice way to configure your HttpClients in your Startup. You are able to choose to use create an empty one with the factory class, Named Clients or Typed Clients.

Create a HttpClient The simple way to get a HttpClient object is to just create one with the HttpClientFactory. The first thing to do is add it to your services configuration in StartUp: services.AddHttpClient();. Next, you can use dependency injection to inject the HttpClientFactory into your class. Call the CreateClient method on the factory to create a new HttpClient.

    public class MyApiWrapper
    {
        private readonly IHttpClientFactory _httpClientFactory;

        public MyApiWrapper(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }

        public Task PingResult()
        {
            var client = _httpClientFactory.CreateClient();
            client.BaseAddress = new Uri("https://mycustomapiuri/");
            client.DefaultRequestHeaders.Add("Accept", "application/json");
            return client.GetStringAsync("/ping");
        }
    }

As you can see in the code, the HttpClient has no configuration yet. When you configure the object, it will create a HttpClientHandler under the hood. This object is pooled within the HttpClientFactory.

Named Clients The second option to get a HttpClient with the HttpClientFactory is by using Named Clients. The HttpClientFactory is injected into your classes like before. By passing a name into the CreateClient method, you can get the Named client. The Named clients are pre-configured in the startup method:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("MyCustomAPI", client =>
    {
        client.BaseAddress = new Uri("https://mycustomapiuri/");
        client.DefaultRequestHeaders.Add("Accept", "application/json");
    });
    (...)
}

Then the HttpClient is accessable by its name ‘MyCustomAPI’:

    public class MyApiWrapper
    {
        private readonly IHttpClientFactory _httpClientFactory;

        public MyApiWrapper(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }

        public Task PingResult()
        {
            var client = _httpClientFactory.CreateClient("MyCustomAPI");
            return client.GetStringAsync("/ping");
        }
    }

Named clients give you more control over how the clients you are using in your program are configured. This makes your life already a lot easier.

Typed Clients Typed Clients are even better as the Named Clients. They are strongly typed and do not need the HttpClientFactory to be injected. The Type Clients can be injected directly into your classes. In startup you can configure them like:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient(client =>
    {
        client.BaseAddress = new Uri("https://mycustomapiuri/");
        client.DefaultRequestHeaders.Add("Accept", "application/json");
    });
    (...)
}

The HttpClient is configured when the in ConfigureServices and then used in a implementation like:

    public class MyCustomClient
    {
        private readonly HttpClient _httpClient;

        public MyApiWrapper(HttpClient httpClient)
        {
            _httpClient = httpClient;
        }

        public Task PingResult()
        {
             return _httpClient.GetStringAsync("/ping");
        }
    }

The MyCustomClient implementation encapsulates the HttpClient by exposing only the functional methods. This hides all implementation details from the actual user of the class.

    public class MyApiWrapper
    {
        private readonly MyCustomClient _customClient;

        public MyApiWrapper(MyCustomClient customClient)
        {
            _customClient = customClient;
        }

        public Task PingResult()
        {
            return customClient.PingResult();
        }
    }

Related posts Background processing Schedule services Headless services Using scoped services

Finally By the introduction of the HttpClientFactory, the usage of the HttpClient is a lot easier. Beside what I have shown in this post, is very easy to add extra functionality to Named or Typed client, for example a retry policy or circuit breaker. Probably nice content for a later post.

Pazartesi, 27 Ağustos 2018 / Published in Uncategorized

[link VIDEO]

Introduction

In this article, we will see how to create a simple CRUD application for ASP.NET Core Blazor using Entity Framework and Web API. Blazor is a new framework introduced by Microsoft. I love to work with Blazor as this makes our SPA full stack application development in a more simple way and yes, now, we can use only one language, C#. Before Blazor, we were using ASP.NET Core with the combination of Angular or ReactJS. Now, with the help of Blazor support, we can create our own SPA application directly with C# Code.

If you start your SPA application development using Blazor, surely, you will love it and it is so simple and fun to work with Blazor. The only drawback now we have is that because Blazor is a newly introduced framework, it’s still in the experimental phase. Once we get the complete version, it will be more fun to work with application development.

In this article, we will see about creating a CRUD Web Application using ASP.NET Core Blazor.

  • C: (Create): Insert new Student Details into the database using ASP.NET Core, Blazor, EF and Web API.
  • R: (Read): Select Student Details from the database using ASP.NET Core, Blazor, EF and Web API.
  • U: (Update): Update Student Details to the database using ASP.NET Core, Blazor, EF and Web API
  • D: (Delete): Delete Student Details from the database using ASP.NET Core, Blazor, EF and Web API.

We will be using Web API and EF to perform our CRUD operations. Web API has the following four methods as Get/Post/Put and Delete, where:

  • Get is to request for the data. (Select)
  • Post is to create a data. (Insert)
  • Put is to update the data. (Update)
  • Delete is to delete data. (Delete)

Prerequisites Make sure, you have installed all the prerequisites on your computer. If not, then download and install them all, one by one. Note that since Blazor is a new framework we must have installed the preview of Visual Studio 2017 (15.7) or above.

Step 1 – Create a database and a table

We will be using our SQL Server database for our WEB API and EF. First, we create a database named StudentsDB and a table as StudentMaster. Here is the SQL script to create a database table and sample record insert query in our table. Run the query given below in your local SQL Server to create a database and a table to be used in our project. 

  1. USE MASTER       
  2. GO       
  3.        
  4. <span–< 1) Check for the Database Exists .If the database is exist then drop and create new DB       
  5. IF EXISTS (SELECT [nameFROM sys.databases WHERE [name] = ‘StudentsDB’ )       
  6. DROP DATABASE StudentsDB       
  7. GO       
  8.        
  9. CREATE DATABASE StudentsDB       
  10. GO       
  11.        
  12. USE StudentsDB       
  13. GO       
  14.        
  15.        
  16. <span–< 1) //////////// StudentMasters       
  17.        
  18. IF EXISTS ( SELECT [nameFROM sys.tables WHERE [name] = ‘StudentMasters’ )       
  19. DROP TABLE StudentMasters       
  20. GO       
  21.        
  22. CREATE TABLE [dbo].[StudentMasters](       
  23.         [StdID] INT IDENTITY PRIMARY KEY,       
  24.         [StdName] [varchar](100) NOT NULL,          
  25.         [Email]  [varchar](100) NOT NULL,          
  26.         [Phone]  [varchar](20) NOT NULL,          
  27.         [Address]  [varchar](200) NOT NULL       
  28. )       
  29.        
  30. <span–< insert sample data to Student Master table       
  31. INSERT INTO [StudentMasters]   ([StdName],[Email],[Phone],[Address])       
  32.      VALUES (‘Shanu’,‘syedshanumcain@gmail.com’,‘01030550007’,‘Madurai,India’)       
  33.        
  34. INSERT INTO [StudentMasters]   ([StdName],[Email],[Phone],[Address])       
  35.      VALUES (‘Afraz’,‘Afraz@afrazmail.com’,‘01030550006’,‘Madurai,India’)       
  36.             
  37. INSERT INTO [StudentMasters]   ([StdName],[Email],[Phone],[Address])       
  38.      VALUES (‘Afreen’,‘Afreen@afreenmail.com’,‘01030550005’,‘Madurai,India’)       
  39.             
  40.      select * from [StudentMasters]     

Step 2 – Create ASP.NET Core Blazor Application

After installing all the prerequisites listed above and ASP.NET Core Blazor Language Services, click Start >> Programs >> Visual Studio 2017 >> Visual Studio 2017 on your desktop. Click New >> Project. Select Web >> ASP.NET Core Angular Web Application. Enter your project name and click OK.

Select Blazor (ASP.NET Core hosted) and click ok

After creating ASP.NET Core Blazor Application, wait for a few seconds. You will see the below structure in solution explorer.

What is new in ASP.NET Core Blazor solution?

When we create our new ASP.NET Core Blazor application we can see there will be 3 projects that will be automatically created in the Solution Explorer.

Client Project

The first project created as a Client project is our Solutionname.Client and here, we can see our solution name as “BlazorASPCORE”. This project will be mainly focused on all the client-side views. Here, we will be adding all our page views to be displayed at the client side in the browser.

We can see a few sample pages have been already added here and we can also see a shared folder like our MVC application where we will be having the Shared folder and Layout page for the Master page. Here, in Blazor, we have the MainLayout which will be working like the Master page and NavMenu for the left side menu display.

Server Project

As the name indicates, this project will be used as a Server project. This project is mainly used to create all our Controllers and WEB API Controllers to perform all business logic and perform CRUD operation using WEB API’s. In our demo application, we will be adding a Web API in this Server project and all the WEB API in our Client application. This Server project will be work like getting/set the data from Database and from our Client project we bind or send the result to this server to perform the CRUD operation in the database.

Shared Project

As the name indicating this project work like a shred project. This project works as a Model for our Server project and for the Client project. The Model declared in this Shared project will be used in both the Server and in the Client project. We also install all the packages needed for our project here; for example, to use the Entity Framework, we install all the packages in this Shared project.

Run to test the application

When we run the application, we can see that the left side has navigation and the right side contains the data. We can see as the default sample pages and menus will be displayed in our Blazor web site. We can use the pages or remove it and start with our own page.

Now let’s see how to add new page perform the CRUD operation for maintaining student details.

Using Entity Framework

To use the Entity Framework in our Blazor application we need to install the below packages

Install the Packages

Go to Tools and then select -> NuGet Package Manager -> Package Manager Console.

You can see the Console at the bottom of the VS 2017 IDE and on the right side of the combo box on the console, select the Default project as your shared project” Select Shared”.

  • You can see the PM> and copy and paste the below line to install the Database Provider package. This package is used to set the database provider as SQL Server.

Install-Package Microsoft.EntityFrameworkCore.SqlServer

We can see as the package is installed in our Shared folder.

Install the Entity Framework –

  • You can see the PM> and copy and paste the below line to install the EF package.

Install-Package Microsoft.EntityFrameworkCore.Tools

To Create DB Context and set the DB Connection string

  • You can see the PM> and copy and paste the below line set the Connection string and create DB Context. This is an important part as we give our SQL Server name, Database Name and SQL server UID and SQL Server Password to connect to our database for performing the CRUD operation. We also give our SQL Table name to create the Model class in our Shared project.
  1. Scaffold-DbContext "Server= YourSqlServerName;Database=StudentsDB;user id= YourSqlUID;password= YourSqlPassword;Trusted_Connection=True;MultipleActiveResultSets=true" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables StudentMasters  

Press enter create a connection string, Model Class, and Database Context.

We can see StudentMasters Model class and StudentsDBContext class has been created in our Shared project. We will be using this Model and DBContext in our Server project to create our Web API to perform the CRUD operations. 

Creating Web API for CRUD operation

To create our WEB API Controller, right-click Controllers folder. Click Add New Controller.

Here we will be using Scaffold method to create our WEB API .We select API Controller with actions, using Entity Framework.

Select our Model and DatabaseContext from the Shared project.

Select our StudentMasters Model from the Shared Project for performing the CRUD operation.

Select the Data Context Class as our StudentsDBContext from the Shared project. Our Controller name will be automatically added if you need you can change it and click the ADD.

Our WEB API with Get/Post/Put and Delete method for performing the CRUD operation will be automatically created and we no need to write any code in Web API now as we have used the Scaffold method for all the actions and methods add with code.

To test Get Method, we can run our project and copy the GET method API path. Here, we can see our API path to get api/StudentMasters/ Run the program and paste API path to test our output.

Now we will bind all this WEB API Json result in out View page from our Client project

Working with Client Project

First, we need to add the new Razor view page

Add Razor View

To add the Razor view page right click the Pages folder from the Client project. Click on Add >> New Item

Select Razor View >> Enter your page name,Here we have given the name as Students.chtml

In Razor view Page we have 3 parts of code as first is the Import part where we import all the references and models for using in the view, HTML design and data bind part and finally we have the function part to call all the web API to bind in our HTML page and also to perform client-side business logic to be displayed in View page.

Import part

First, we import all the needed support files and references in our Razor View page.Here we have first imported our Model class to be used in our view and also imported HTTPClient for calling the Web API to perform the CRUD operations.

  1. @using BLAZORASPCORE.Shared  
  2. @using BLAZORASPCORE.Shared.Models  
  3. @page "/Students"  
  4. @using Microsoft.AspNetCore.Blazor.Browser.Interop  
  5. @inject HttpClient Http  

HTML design and data Bind part

Next, we design our Student details page to display the student details from the database and created a form to Insert and update the Student details we also have Delete button to delete the student records from the database.

For binding in Blazor we use the bind="@stds.StdId" and to call the method using onclick="@AddNewStudent"

Function Part

function part to call all the web API to bind in our HTML page and also to perform client-side business logic to be displayed in View page.In this Function we create a separate function for Add, Edit and Delete the student details and call the Web API Get,Post,Put and Delete method to perform the CRUD operations and in HTML we call all the function and bind the results.

  1. @functions {  
  2.     StudentMasters[] student;  
  3.   
  4.     StudentMasters stds = new StudentMasters();  
  5.     string ids = "0";  
  6.     bool showAddrow = false;  
  7.     protected override async Task OnInitAsync()  
  8.     {  
  9.         student = await Http.GetJsonAsync<StudentMasters[]>("/api/StudentMasters/");  
  10.     }  
  11.   
  12.     void AddNewStudent()  
  13.     {  
  14.         stds = new StudentMasters();  
  15.     }  
  16.     // Add New Student Details Method  
  17.     protected async Task AddStudent()  
  18.     {  
  19.         if (stds.StdId == 0)  
  20.   
  21.         {  
  22.             await Http.SendJsonAsync(HttpMethod.Post, "/api/StudentMasters/", stds);  
  23.   
  24.         }  
  25.         else  
  26.         {  
  27.             await Http.SendJsonAsync(HttpMethod.Put, "/api/StudentMasters/" + stds.StdId, stds);  
  28.         }  
  29.         stds = new StudentMasters();  
  30.         student = await Http.GetJsonAsync<StudentMasters[]>("/api/StudentMasters/");  
  31.     }  
  32.     // Edit Method  
  33.     protected async Task EditStudent(int studentID)  
  34.     {  
  35.         ids = studentID.ToString();  
  36.         stds = await Http.GetJsonAsync<StudentMasters>("/api/StudentMasters/" + Convert.ToInt32(studentID));  
  37.     }  
  38.     // Delte Method  
  39.     protected async Task DeleteStudent(int studentID)  
  40.     {  
  41.         ids = studentID.ToString();  
  42.         await Http.DeleteAsync("/api/StudentMasters/" + Convert.ToInt32(studentID));  
  43.   
  44.         // await Http.DeleteAsync("/api/StudentMasters/Delete/" + Convert.ToInt32(studentID));  
  45.   
  46.         student = await Http.GetJsonAsync<StudentMasters[]>("/api/StudentMasters/");  
  47.     }  
  48.   
  49. }   

Navigation Menu

Now we need to add this newly added Students Razor page to our left Navigation. For adding this Open the Shared Folder and open the NavMenu.cshtml page and add the menu.

  1. <li class="nav-item px-3">  
  2.             <NavLink class="nav-link" href="/Students">  
  3.                 <span class="oi oi-list-rich" aria-hidden="true"></span> Students Details  
  4.             </NavLink>  
  5.         </li>  

Build and Run the application

Conclusion

Note that when creating the DBContext and setting the connection string, don’t forget to add your SQL connection string. Hope you all like this article. In the next article, we will see more examples to work with Blazor. It’s really very cool and awesome to work with Blazor.

Pazartesi, 27 Ağustos 2018 / Published in Uncategorized

Mithun Pattankar describes using Angular 6 inside ASP.NET MVC 5 using Angular CLI in Visual Studio 2017.

Pazartesi, 27 Ağustos 2018 / Published in Uncategorized
  • When a user requests a page from the server, first, it will check the cache memory and see if the page is present in cache or not. 
  • If the page is found in the Cache, the third step is to check its expiration time. If it’s already expired, then again it will go for regenerating the page.
  • If it’s not expired, then the cached content is provided to the user.
  • On the other hand, if the page or content is not found in this case, it will go with the manual process and generate the the page and store that in Cache Memory and then forwarded that to its client.

This is how the entire caching process works.

Here we will learn the Azure Redis Cache provided by the Redis Cache. Azure Redis Cache is based on the popular open-source Redis cache. It gives you access to a secure, dedicated Redis cache, managed by Microsoft, and accessible from any application within Azure.

To work with Azure Redis Cache we have to create a Redis cache in the Azure Portal. Please follow the following steps to create a Redis cache in the portal.

 

Why Caching is Fast??

 

A cache is a small storage area that is closer to the application needing it than the original source.

Accessing this cache is typically faster than accessing a typically stored in memory or on disk.

A memory cache is normally faster to read from than a disk cache, but a memory cache typically does not survive system restarts.

 

 This is very much similar to a library(considered as a DB) and searching a book from this vast memory will be very difficult.so once any item is searched putting that in study table will be searched easily next time.

To use Azure Redis Cache Log in to your Azure portal with your UserId and Password. Once you are logged in it will forward you to the Dashbord.

From the Search menu, search for Database in the Portal as shown below.

Once you select the Database option, under that you can search for Redis Cache as shown in the below picture.

 

Select the Redis Cache and create and create a new Redis Cache in the Portal.

While creating Redis cache on the basic of Pricing tier, you will find 3 options:

  • Basic – Single node. Multiple sizes up to 53 GB. 
  • Standard – Two-node Primary/Replica. Multiple sizes up to 53 GB. 99.9% SLA.
  • Premium – Two-node Primary/Replica with up to 10 shards. Multiple sizes from 6 GB to 530 GB. All Standard tier features and more including support for Redis cluster,  Redis persistence, and Azure Virtual Network. 99.9% SLA.

Here I have shown the Premium One with Redis Cluster in the below image.

 

Once you create your Cache just pin it to the Dashbord, so that it will be easy to work on it. So in this way you are able to create a Redis Cache in the Azure Portal. Now let’s create a Client MVC application will  use this cache to store and retrieve the data to boost the performance.

 

So Open Visual Studio and create a new MVC project as shown below.

 

Once you create the project, go to NuGet Package and search for Stack Exchange Redis and include that in the project as shown below.

Once that is completed, you will find the references in Reference folder.

Here is my solution Explorer with all the settings.

 

Now go to the Azure Portal and check the access key for the Redis Cache

Once you get the connection string and Key, copy it and take it to the Configfile of your application.

  1. <appSettings>  
  2.   <add key="webpages:Version" value="3.0.0.0" />  
  3.   <add key="webpages:Enabled" value="false" />  
  4.   <add key="ClientValidationEnabled" value="true" />  
  5.   <add key="UnobtrusiveJavaScriptEnabled" value="true" />  
  6.   <add key="RedisCachekey" value="Debendra.redis.cache.windows.net:6980,password=###########KtWeHK9IRK3kmb7uIsdeben&&&&=,ssl=True,abortConnect=False" />  
  7. </appSettings>  

Note

Here I have tempered my password. In the below section I have pasted the connection string; the database for this application is hosted in webAPP in the Azure.

  1. <connectionStrings>  
  2.    <add name="Connect" connectionString="Server=tcp:debendra.database.windows.net,1433;Initial Catalog=EmployeeDetails;User ID=Debendra;Password=Password#####;" providerName="System.Data.SqlClient"/>  
  3.  </connectionStrings>  

Now create an Employee Model to define properties for CRUD operations.

  1. namespace RedisCache.Models  
  2. {  
  3.     public class Employee  
  4.     {  
  5.         public int Id { getset; }  
  6.         public string Name { getset; }  
  7.         public string Address { getset; }  
  8.         public string Company { getset; }  
  9.         public string MobileNo { getset; }  
  10.     }  
  11. }  

As I will work in the CodeFirst Approach, here I have defined my DBContex class as follows.

  1. public class DebendraContext:DbContext  
  2.     {  
  3.         public DebendraContext():base("Connect")  
  4.         {  
  5.   
  6.         }  
  7.         public DbSet<Employee> Employee { getset; }  
  8.   
  9.     }  

Now Create an Index controller and read the connection string and Redis Cache connection value in that.

Now Create an Action Method to add some Employee Data in the same Index Controller.

  1. [HttpPost]  
  2.        public ActionResult AddEmployee(Employee model)  
  3.        {  
  4.            mydbcontext = new DebendraContext();  
  5.            mydbcontext.Employee.Add(model);  
  6.            mydbcontext.SaveChanges();  
  7.   
  8.            return View();  
  9.        }  
  10.        [HttpGet]  
  11.        public ActionResult AddEmployee()  
  12.        {  
  13.             
  14.            return View();  
  15.        }  

Create the  Add Employee View. Here is the attached view code.

  1. @model RedisCache.Models.Employee  
  2.   
  3. @{  
  4.     Layout = null;  
  5. }  
  6.   
  7. <!DOCTYPE html>  
  8.   
  9. <html>  
  10. <head>  
  11.     <meta name="viewport" content="width=device-width" />  
  12.     <title>AddEmployee</title>  
  13. </head>  
  14. <body>  
  15.     @Scripts.Render("~/bundles/jquery")  
  16.     @Scripts.Render("~/bundles/jqueryval")  
  17.       
  18.       
  19.     @using (Html.BeginForm())   
  20.     {  
  21.         @Html.AntiForgeryToken()  
  22.           
  23.         <div class="form-horizontal">  
  24.             <h4>Employee</h4>  
  25.             <hr />  
  26.             @Html.ValidationSummary(true, "", new { @class = "text-danger" })  
  27.             <div class="form-group">  
  28.                 @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })  
  29.                 <div class="col-md-10">  
  30.                     @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })  
  31.                     @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })  
  32.                 </div>  
  33.             </div>  
  34.       
  35.             <div class="form-group">  
  36.                 @Html.LabelFor(model => model.Address, htmlAttributes: new { @class = "control-label col-md-2" })  
  37.                 <div class="col-md-10">  
  38.                     @Html.EditorFor(model => model.Address, new { htmlAttributes = new { @class = "form-control" } })  
  39.                     @Html.ValidationMessageFor(model => model.Address, "", new { @class = "text-danger" })  
  40.                 </div>  
  41.             </div>  
  42.       
  43.             <div class="form-group">  
  44.                 @Html.LabelFor(model => model.Company, htmlAttributes: new { @class = "control-label col-md-2" })  
  45.                 <div class="col-md-10">  
  46.                     @Html.EditorFor(model => model.Company, new { htmlAttributes = new { @class = "form-control" } })  
  47.                     @Html.ValidationMessageFor(model => model.Company, "", new { @class = "text-danger" })  
  48.                 </div>  
  49.             </div>  
  50.       
  51.             <div class="form-group">  
  52.                 @Html.LabelFor(model => model.MobileNo, htmlAttributes: new { @class = "control-label col-md-2" })  
  53.                 <div class="col-md-10">  
  54.                     @Html.EditorFor(model => model.MobileNo, new { htmlAttributes = new { @class = "form-control" } })  
  55.                     @Html.ValidationMessageFor(model => model.MobileNo, "", new { @class = "text-danger" })  
  56.                 </div>  
  57.             </div>  
  58.       
  59.             <div class="form-group">  
  60.                 <div class="col-md-offset-2 col-md-10">  
  61.                     <input type="submit" value="Create" class="btn btn-default" />  
  62.                 </div>  
  63.             </div>  
  64.         </div>  
  65.     }  
  66.       
  67.     <div>  
  68.         @Html.ActionLink("Back to List", "Index")  
  69.     </div>  
  70. </body>  
  71. </html>  

Now run the application to add some employee details to the Database, which will later be cached and shown.

Here I have saved some data in the DataBase in Azure.

Now here is the Main logic to retrieve the data from DataBase and put it in Cache.

  1. public ActionResult Index()  
  2.       {  
  3.             var connect = ConnectionMultiplexer.Connect(cacheConnectionstring);  
  4.             mydbcontext = new DebendraContext();  
  5.             IDatabase Rediscache = connect.GetDatabase();  
  6.             if (string.IsNullOrEmpty(Rediscache.StringGet("EmployeeDetails")))  
  7.             {  
  8.               var liemp = mydbcontext.Employee.ToList();  
  9.              var emplist= JsonConvert.SerializeObject(liemp);  
  10.   
  11.               Rediscache.StringSet("EmployeeDetails", emplist, TimeSpan.FromMinutes(2));  
  12.                 return View(liemp);  
  13.   
  14.             }  
  15.             else  
  16.             {  
  17.                   
  18.                 var detail = JsonConvert.DeserializeObject<List<Employee>>(Rediscache.StringGet("EmployeeDetails"));  
  19.                 return View(detail);  
  20.   
  21.             }  
  22.            
  23.         }  

CODE EXPLANATION

  1. As you know we have installed StackExchange.Redisfor using the Redis Cache in our client application.
  2. The central object in StackExchange.Redis is the ConnectionMultiplexer class in the StackExchange.
  3. The connection to the Azure Redis Cache is managed by the ConnectionMultiplexer class.
  4. This class should be shared and reused throughout your client application, and does not need to be created on a per operation basis.
  5. In these examples abortConnect is set to false, which means that the call succeeds even if a connection to the Azure Redis Cache is not established.  
    1. <appSettings>      
    2.   <add key="RedisCachekey" value="Debendra.redis.cache.windows.net:6980,password=###########KtWeHK9IRK3kmb7uIsdeben&&&&=,ssl=True,abortConnect=False" />      
    3. </appSettings>  
  6. One key feature of ConnectionMultiplexer class is that it automatically restores connectivity to the cache once the network issue or other causes are resolved.

  7. Accessing a redis database is as simple as:

    1. IDatabase db = redis.GetDatabase();   
  8. Once you have the IDatabase, it is simply a case of using the redis API. Note that all methods have both synchronous and asynchronous implementations.
  9. Here I  have used two methods to store and retrieve data using StringGet and StringSet.
  10. Add and retrieve objects from the cache.

    1. // If key1 exists, it is overwritten.    
    2. Rediscache .StringSet("key1""value1");    
    3.     
    4. string value = Rediscache .StringGet("key1");    

    Where Rediscache is the object of IDatabase.

  11. Here we are definging the expiration time  while setting the data. 

    1. Rediscache.StringSet("EmployeeDetails", emplist, TimeSpan.FromMinutes(2));   

Now just run the Index method and check how it works: 

For the first time the Rediscache.StringGet("EmployeeDetails"

)

will be null. Go  inside the If statement, fetch the data, and set it the to the cache object. This object is valid for two minutes. If you make any request within that time period it will go to the else part and just fetch the data from the cache without regenerating again .

So let’s request it again. 

 

NOTE

The second request is within two minutes, otherwise it will go  inside the If statement again. Here is the complete Flow.

So we can avoid a lot of  time using Caching.

You can also set rules to get email alerts when a particular threshold is reached for your cached object.

Similarly you can monitor your cache health here as follows.

Conclusion


In this way we can work on Azure Redis Cache  and keep our web application maximized.

Please let me know if  you have any doubts or if I made any mistakes so I can modify and learn from that.

Pazartesi, 27 Ağustos 2018 / Published in Uncategorized

Introduction

Let’s have a quick review of ASP.NET MVC Architecture. So when the request arrives at our application MVC Framework hands off that request to an action in a controller, this action most of the time returns a view which is then parsed by razor view engine and then eventually HTML markup is returned to the client. So in this approach html markup is generated on the server and then return to the client.

There is an alternative way to generate the HTML markup, we can generate it on the client. So instead of our action returning HTML markup, they can return raw data.

What is the benefit of this approach?

There are numbers of benefits of generating markup on the client.

  • It requires fewer server resources (it potentially improves the scalability of the application because each client will be responsible for generating their own views)
  • Raw Data often requires less bandwidth than HTML markup. So the data potentially arrives faster at the client. And this can improve the perceived performance of the application.
  • This approach supports the broad range of clients like mobile and tablet apps.

These apps are simply called endpoints get the data and generate the view locally. We call these endpoints Data Services (Web APIs) because they just return data, not markup.

Web APIs are not just limited to cross devices, it also widely used in our Web Applications to add the new features like many popular websites like youtube, facebook and twitter expose public data services which we can consume in our web applications. We can merge their data with the data in our application and provide new experiences to the new user. These are the benefits.

These data services are just not only to get the data, we’ve services to modify the data like adding the customer etc. The framework we use to build these data services is called web APIs. This framework was developed after ASP.Net MVC but it follows the same architecture and principals of ASP.NET MVC so it has routings, controllers, actions, action result and so on. There are also few minor differences that we’ll see here. In .Net Core, Microsoft has merged these both frameworks (ASP.NET MVC & ASP.NET Web API) into a single framework.

Restful Convention

So you know what is http services and what is web api. Here we’ll develop an application which supports few different kinds of requests.

GET                               /api/customers               (to get the list of customers)

GET                               /api/customers/1             (to get the single customer)

POST                             /api/ customers              (to add the customer and add the customer data in request body)

Don’t confuse about GET and POST request of the data, we use get a request to get the list of the resource or data. And we use post request to create the new one.

Now to update the student we use PUT request.

PUT                               /api/customers/1

So the id of the customer is in the url and the actual data or properties to update will be in the request body. And finally to delete the student.

Delete                             /api/customers/1

We send HttpDelete request to the endpoint. So what you see here, in terms of request types and endpoints is a standard convention referred to ask REST (Representational State Transfer)

Building An API

This class derives from ApiController as opposed to Controller. If you’re working with any existing project then just add a new folder in controllers folder and add the api controller here. And add these actions but before defining the actions in apis, this is my Customer model class

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

    [Required]
    [StringLength(255)]
    public string Name { get; set; }

    public bool IsSubscribedToNewsLetter { get; set; }

    [Display(Name = "Date of Birth")]
    public DateTime? Birthdate { get; set; }

    [Display(Name = "Membership Type")]
    public byte MembershipTypeId { get; set; }

    // it allows us to navigate from 1 type to another
    public MembershipType MembershipType { get; set; }
}

And here is my DbContext class

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    public DbSet<Customer> Customers { get; set; }
    public DbSet<MembershipType> MembershipTypes { get; set; }
}

Now it would be easy for you to write actions for Api.

public IEnumerable<Customer> GetCustomers()
{
}

Because we’re returning a list of objects. This action by convention will respond to

// Get                              /api/customers

So this is the convention built into ASP.Net Web API. Now in this action we gonna use our context to get the customers from the database.

namespace MyAPI.Controllers.Api
{
    public class CustomersController : ApiController
    {
        private readonly ApplicationDbContext _context;

        public CustomersController()
        {
            _context = new ApplicationDbContext();
        }

        // GET /api/customers
        public IEnumerable<Customer> GetCustomers()
        {
            return _context.Customers.ToList();
        }
    }
}

If the resource isn’t found, we return not found httpresponse otherwise we return the object.

// POST /api/customers
[HttpPost]
public Customer CreateCustomer(Customer customer)
{
}

So this is the customer argument will be in the request body and ASP.NET Web API Framework will automatically initialize this. Now we should mark this action with HttpPost because we’re creating the resource. And if we’re following the naming convention then we don’t even need to place the action verb on the action.

// POST /api/customers
public Customer PostCustomer(Customer customer)
{
}

But originally it isn’t so good approach, Let’s suppose you refactor the code in future and rename your action then surely your code will break. So always prefer to use Http verbs on the top of action.

Now let’s insert the customer object into the database with post request of api action.

// POST /api/customers
[HttpPost]
public Customer CreateCustomer(Customer customer)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    _context.Customers.Add(customer);
    _context.SaveChanges();

    return customer;
}

Another action let’s suppose we want to update the record.

// PUT /api/customers/1
[HttpPut]
public void UpdateCustomer(int id, Customer customer)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);

    // Might be user sends invalid id.
    if (custmr == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    custmr.Birthdate = customer.Birthdate;
    custmr.IsSubscribedToNewsLetter = customer.IsSubscribedToNewsLetter;
    custmr.Name = customer.Name;
    custmr.MembershipTypeId = customer.MembershipTypeId;

    _context.SaveChanges();
}

Here in this scenario, different people have different opinions to return the void or the object. And if we make the delete action of Api,

// Delete /api/customers/1
[HttpDelete]
public void DeleteCustomer(int id)
{
    var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);

    // Might be user sends invalid id.
    if (custmr == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    _context.Customers.Remove(custmr);
    // Now the object is marked as removed in memory

    // Now it is done
    _context.SaveChanges();
}

This is how we use restful convention to build the api.

Testing the API

If we run the application and request the api controller, we can see the list of customers in XML based language.

<a href="http://localhost:53212/api/customers">http://localhost:53212/api/customers</a>

So ASP.NET Web API has what we call media formatter. So what we return from an action (in our case the list of customer will be formatted based on what the client asks) let me explain what I mean and what I’m trying to say.

Inspect the browser on above screen and refresh the page, here you’ll see the customer request.

Here look at Content Type, if you don’t set the content type header in our request by default the server assumes application/xml.

Note: General is the Request Header, Response Headers is our Response Header here. As you can see in Request Header, we don’t have any content type. Now let me show you the best to test the api and get the data in json.

Install Postman Desktop App in your machine. And copy the browser link with localhost port number and paste it into the postman.

And here we put the url of the request with localhost and here the response comes back in json.

And if we click on the Header tab, here we’ll see our request header content type is application/json

Most of the time we’ll be using json because it is native for javascript code and much faster than xml. XML media format is largely used in large organizations like government because they’re behind the modern technology. Json format is more lightweight because it doesn’t have redundant opening and closing tabs like xml.

Little Confusion:

Sometimes when you’re working with Apis or with postman, mostly people confuse about the interface of Postman because they have not ever used postman before. It is very simple just keep in mind,

So if you’re working with request and trying to change some information of request then focus on request header and if you’re monitoring the response then watch the results in response headers. As they’re looking same and sometimes when the scroll down the request header vanishes. So don’t confuse about the things.

Now let’s insert a customer in the database with Api Post Action.

Select the Post request from the dropdown and in request body tab. You can insert the customer with key value pairs on clicking form-data. But most of the time we use json format. So click on raw and write the json here.

Don’t put Id property in json because it is hard and fast rule when we insert the data in database, the id is automatically generated on the server.

Now click on Send Button and here I’ve successfully inserted the data with Post api action and gets the response.

Here the above block is request block and the below block is response block. You might face some kind of error here like this.

If you read the error message ‘The request entity’s media type ‘text/plain’ is not supported for this resource’. This is the error message.

Now to resolve this error. Click on Header tab and add the value for content-type (‘application/json’)

And here the values has been added. Look the status code for request is 200 OK and we can see the response body below.

Now let’s update the customer entity.

And look it has been updated.

Now let’s delete one record similarly, just select Delete in dropdown and specify the id with forward slash in the url and click on Send button. It will be automatically deleted.

Best Practice:

The best practice is when you build the api and before consuming it in application. It would be better to test the api through Postman.

Data Transfer Objects (DTO)

So now we’ve build this api but there are couple of issues with this design. Our api receives or returns Customer object. Now you might be thinking what’s wrong with this approach? Actually Customer object is part of the domain model of our application. It is considered implementation details which can change frequently as we implement new features in our applications and these changes potentially grab existing clients that are dependent on the customer object i.e. if we rename or remove our property this can impact the client that are dependent upon the property. So basically we make the contract of the api as stable as possible. And here we use DTOs.

DTO is the plain data structure and is used to transfer data from the client on server or vice versa that’s why we called it data transfer object. By creating DTOs, we reduces the chances of our APIs breaking as we refactor our domain model. Ofcourse we should remember that changing these DTOs that can be costly. So the most important thing is our api should not receive or return the Customer model class object.

Another issue by using domain object here in API is we’re opening the security holes in our application. A hacker can easily pass additional data in json and they will be mapped to our domain object. What if one of this property should not be updated, a hacker can easily bypass this but if we use DTO we can simply exclude the properties that can be updated. So add a new folder in your project with name DTOs and Add the class CustomerDTO and copy all the properties of Customer domain model class with their data annotation attributes and paste it in CustomerDTO. Now remove the navigation properties from CustomerDTO because it is creating the dependency to MembershipType domain model class.

namespace MyAPI.DTOs
{
    public class CustomerDTO
    {
        public int Id { get; set; }

        [Required]
        [StringLength(255)]

        public string Name { get; set; }

        public bool IsSubscribedToNewsLetter { get; set; }

        public DateTime? Birthdate { get; set; }

        public byte MembershipTypeId { get; set; }
    }
}

Now the next thing is we want to use to CustomerDTO in our api instead of Customer domain class object. So to reduce a lot of code to bind the properties one by one, we use Automapper.

Automapper

Install the automapper package from Package Manager Console.

PM > Install-Package Automapper -version:4.1

Now add the new class in App_Start (MappingProfile.cs) and inherit it from Profile.

using AutoMapper;

namespace MyAPI.App_Start
{
    public class MappingProfile : Profile
    {
    }
}

Now create the constructor and add the mapping configuration between 2 types.

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        Mapper.CreateMap<Customer, CustomerDTO>();
        Mapper.CreateMap<CustomerDTO, Customer>();
    }
}

The first argument of the CreateMap is the Source and the second one is destination. When we use the CreateMap method, automapper automatically uses the reflection to scan these types. It finds their properties and maps them based on their names. This is why we called automapper (a convention based mapping tool) because it uses the property names as the convention to map objects. So here is mapping profiles, now we need to load it when the application started.

Now open the Global.asax.cs file and write the code for Application_Start()

protected void Application_Start()
{
    Mapper.Initialize(c => c.AddProfile<MappingProfile>());
    GlobalConfiguration.Configure(WebApiConfig.Register);
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

Now open CustomerController of Api. And let’s start changes here.

// GET /api/customers
public IEnumerable<CustomerDTO> GetCustomers()
{
    return _context.Customers.ToList();
}

Now we want to return CustomerDTO type instead of Customer object. Now we need to map this Customer object to CustomerDTO. So we use linq extension method.

// GET /api/customers
public IEnumerable<CustomerDTO> GetCustomers()
{
    return _context.Customers.ToList()
    .Select(Mapper.Map<Customer, CustomerDTO>);
}

Mapper.Map<Customer, CustomerDTO>

This delegates does the mapping. As we can see we’re not placing function call small brackets because we’re not calling the function here. We just reference it here. Mapping function automatically calls, when it executes.

// GET /api/customers/1
public Customer GetCustomer(int id)
{
    var customer = _context.Customers.SingleOrDefault(x => x.Id == id);

    // This is part of the RESTful Convention
    if (customer == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    return customer;
}

In this function, as we are returning one object so we don’t use Select extension method. Here we directly use mapper

// GET /api/customers/1
public CustomerDTO GetCustomer(int id)
{
    var customer = _context.Customers.SingleOrDefault(x => x.Id == id);

    // This is part of the RESTful Convention
    if (customer == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    return Mapper.Map<Customer, CustomerDTO>(customer);
}

Now come on the next CreateCustomer action,

// POST /api/customers
[HttpPost]
public CustomerDTO CreateCustomer(CustomerDTO customerDto)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    var customer = Mapper.Map<CustomerDTO, Customer>(customerDto);
    _context.Customers.Add(customer);
    _context.SaveChanges();

    // Here we make our CustomerDto completely fill, because after
    // adding customer to Customer table (id is assigned to it)
    // & Now we assigned this id to customerDto
    customerDto.Id = customer.Id;

    return customerDto;
}

This is how we works with Dtos and Automapper.

Now let’s update the UpdateCustomer action api method.

// PUT /api/customers/1
[HttpPut]
public void UpdateCustomer(int id, CustomerDTO customerDto)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);

    // Might be user sends invalid id.
    if (custmr == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    Mapper.Map<CustomerDTO, Customer>(customerDto, custmr);
    //custmr.Birthdate = customerDto.Birthdate;
    //custmr.IsSubscribedToNewsLetter = customerDto.IsSubscribedToNewsLetter;
    //custmr.Name = customerDto.Name;
    //custmr.MembershipTypeId = customerDto.MembershipTypeId;

    _context.SaveChanges();
}

So this is how we map objects using Automapper. Now automapper has a few features that you may find useful in certain situations i.e. if your property names don’t match, you can override the default convention or you can exclude some of its properties from mapping or you may wanna create custom mapping classes. If you want to learn more, you can learn from Automapper documentation.

IHttpActionResult

Alright look at this CreateCustomer action method

// POST /api/customers
[HttpPost]
public CustomerDTO CreateCustomer(CustomerDTO customerDto)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    var customer = Mapper.Map<CustomerDTO, Customer>(customerDto);
    _context.Customers.Add(customer);
    _context.SaveChanges();

    // Here we make our CustomerDto completely fill, because after
    // adding customerDto to Customer table (id is assigned to it)
    // & Now we assigned this id to customerDto
    customerDto.Id = customer.Id;

    return customerDto;
}

Here we’re simply returning CustomerDto which would eventually result in response like this

But in restful convention when we create a resource, the status code should be 201 or created. So we need more control over the response return from an action and to make this happen, instead of returning CustomerDto we return IHttpActionResult. This interface is similar to ActionResult we’ve in MVC framework so it is implemented by few different classes and here in ApiController, we’ve bunch of methods to create an instance of one of the classes that implement IHttpActionResult interface.

Now here if the model is not valid instead of throwing an exception, use the helper method BadRequest()

// POST /api/customers
[HttpPost]
public IHttpActionResult CreateCustomer(CustomerDTO customerDto)
{
    if (!ModelState.IsValid)
        return BadRequest();

    var customer = Mapper.Map<CustomerDTO, Customer>(customerDto);
    _context.Customers.Add(customer);
    _context.SaveChanges();

    // Here we make our CustomerDto completely fill, because after
    // adding customerDto to Customer table (id is assigned to it)
    // & Now we assigned this id to customerDto
    customerDto.Id = customer.Id;

    return Created(new Uri(Request.RequestUri + "/" + customer.Id),
        customerDto);
}

As we can see if the ModelState is not valid, it is returning BadRequest and if customer has been added then we return the Uri with this resource id in Created() with the object we’ve finally created the new one.

Look here we created one more resource and now the status is 201 Created. And if we look the location tab

That’s the uri of newly created customer. This is part of the restful convention. So in Web Apis, we preferred to use IHttpActionResult as the returntype of your actions.

Now let’s make changes in the rest of the actions in this Web Api. And here is the complete code of our Api

public class CustomersController : ApiController
{
    private readonly ApplicationDbContext _context;

    public CustomersController()
    {
        _context = new ApplicationDbContext();
    }

    // GET /api/customers
    public IHttpActionResult GetCustomers()
    {
        return Ok(_context.Customers.ToList()
            .Select(Mapper.Map<Customer, CustomerDTO>));
    }

    // GET /api/customers/1
    public IHttpActionResult GetCustomer(int id)
    {
        var customer = _context.Customers.SingleOrDefault(x => x.Id == id);

        // This is part of the RESTful Convention
        if (customer == null)
            return NotFound();

        return Ok(Mapper.Map<Customer, CustomerDTO>(customer));
    }

    // POST /api/customers
    [HttpPost]
    public IHttpActionResult CreateCustomer(CustomerDTO customerDto)
    {
        if (!ModelState.IsValid)
            return BadRequest();

        var customer = Mapper.Map<CustomerDTO, Customer>(customerDto);
        _context.Customers.Add(customer);
        _context.SaveChanges();

        // Here we make our CustomerDto completely fill, because after
        // adding customerDto to Customer table (id is assigned to it)
        // & Now we assigned this id to customerDto
        customerDto.Id = customer.Id;

        return Created(new Uri(Request.RequestUri + "/" + customer.Id),
            customerDto);
    }
    
    // PUT /api/customers/1
    [HttpPut]
    public IHttpActionResult UpdateCustomer(int id, CustomerDTO customerDto)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest();
        }
 
        var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);
 
        // Might be user sends invalid id.
        if (custmr == null)
        {
            return NotFound();
        }
 
        Mapper.Map<customerdto, customer="">(customerDto, custmr);
 
        _context.SaveChanges();
        return Ok(custmr);
    }
    
    // Delete /api/customers/1
    [HttpDelete]
    public IHttpActionResult DeleteCustomer(int id)
    {
        var custmr = _context.Customers.SingleOrDefault(x => x.Id == id);
 
        // Might be user sends invalid id.
        if (custmr == null)
        {
            return NotFound();
        }
 
        _context.Customers.Remove(custmr);
        // Now the object is marked as removed in memory
 
        // Now it is done
        _context.SaveChanges();
 
        return Ok(custmr);
    }
}</customerdto,>

Let me mention this point here, as you can see we’ve 2 parameters in UpdateCustomer. If the parameter is primitive type like we’ve int id then we’ll place this parameter in route url or with query string. And if we want to initialize our complex type like here we’ve CustomerDTO then we’ll always initialize it from request body in postman. So don’t be confuse about this thing here.

Now let’s update and delete the json object through postman. If you focus on the UpdateCustomer action parameter, here we’ve 1st parameter has record id and the 2nd parameter is the Customer domain model class object.

Look it is working with Id in request header because our entity is complete here.

But if we don’t provide the id in the request header, we’ll get the error.

And the exceptionMessage is “The property ‘Id’ is part of the object’s key information and cannot be modified.” Actually this exception happens on this line,

Mapper.Map<CustomerDTO, Customer>(customerDto, custmr);

Because customerDto doesn’t contain the Id but custmr (which is the object variable of Customer model class) has an Id property. And here we need to tell Automapper to ignore Id during mapping to customerDto to custmr. So, come on to the Mapping Profile

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        Mapper.CreateMap<Customer, CustomerDTO>();
        Mapper.CreateMap<CustomerDTO, Customer>()
            .ForMember(c => c.Id, opt => opt.Ignore());
    }
}

And look it is working now,

Consuming the Web API

After proper testing of the api, now it is the time of consuming the api. Most important thing is which I would like to mention here. Now our api is ready, you can consume this api in any client. Here we’re showing you the sample of consuming with Visual Studio application. If you’ve build this api with us then you can consume it in php, python, in any framework application with the help of jquery ajax. Now we’ll use jquery to call our api. Look this screen, here I’m showing some customers.

Now what we want is to delete the row on clicking the delete button. So if you get the idea how we’re rendering the items on the screen, obviously using foreach loop. So on Delete anchor tag click we want record id as well to pass this id to the web api Delete action and on success remove the row.

@foreach (var customer in Model)
{
    <tr>
        <td>@Html.ActionLink(customer.Name, "Edit", "Customers", new { id = customer.Id }, null)</td>
        @if (customer.Birthdate != null)
        {
            <td>
                @customer.Birthdate
            </td>
        }
        else
        {
            <td>Not Available</td>
        }
        <td>
            <button data-customer-id="@customer.Id" class="btn btn-link js-delete">Delete</button>
        </td>
    </tr>
}

This is the html. Now I want to call my api through ajax.

@section scripts{
    
        $(document).ready(function() {
            $('#customers .js-delete').on('click',
                function () {
                    var button = $(this);
                    if (confirm('Are you sure you want to delete this client?')) {
                        $.ajax({
                            url: '/api/customers/' + button.attr('data-customer-id'),
                            method: 'DELETE',
                            success: function() {
                                button.parents('tr').remove();
                            }
                        })
                    }
                });
        });
    
}

This is how we work with ajax and apis. Now you might be thinking here I’m just passing the id to the customers api and targeting Delete action and on success event I’m removing the row directly. You might think this scenario in different way, because every developer has its own taste.

You might think like first we delete the record with Delete method and then get all the records from GetCustomers() method of Web Api and then render all these items through each loop of jquery. But this scenario takes too much time and effort. Look when I click on the Delete anchor tag and show the result in inspect browser, the status is 200 ok. It means everything is working fine, our code (Delete action) is working as we expects. So we don’t any need to again verify the items how much items we’ve in the database and render it through each loop.

Just make your scenario simple, and remove the record as I do here.

Conclusion

So the conclusion is always follow the Restful convention when you’re working with Web Apis. Web Apis are very lightweight than SOAP based web services. They are cross platform. Restful Http verbs helps in the application a lot to insert, delete, update, get the records. Here we see how we use the postman and there are 2 different panes like request header and response header. Most of the time developers confuse about how to use Web Api actions with jquery ajax. Here we also consume the action as well.

 

TOP