Common features in ASP.NET Core 2.2 WebApi: Mapping

 

Introduction

The data mapping is a very likely need to transform objects into other objects (similar or not) as the application layers interact with each other (dto -> domain objects and vice versa).
There are different ways to proceed. It is possible to create services, create classic static classes or extension methods.

In this article we will talk about AutoMapper.

AutoMapper is convention-based object-object mapper.

AutoMapper uses a fluent configuration API to define an object-object mapping strategy. AutoMapper uses a convention-based matching algorithm to match up source to destination values. AutoMapper is geared towards model projection scenarios to flatten complex object models to DTOs and other simple objects, whose design is better suited for serialization, communication, messaging, or simply an anti-corruption layer between the domain and application layer.

Installation

Download this package:

PM> Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

This package will install everything you need, AutoMapper itself and necessary dll to use AutoMapper with Injection Dependency in ASP.NET Core.

Configuring Startup.cs 

Pretty simple at this step.

We just need to add AutoMapper at the ServiceCollection like this:

public void ConfigureServices(IServiceCollection services)
{
   // Automapper
   services.AddAutoMapper();
}

Then we just need to write AutoMapper profiles and thees profiles will be loaded when the application starts. No need to register them in the Startup.cs.

Create profiles

Profiles are a collection of mapping strategy. Each strategy is defined with method CreateMap<TSource,TDestination>.

In the next sample we will use two objects that are differents and that need a precise mapping strategy (UserEntity to map in a User dto):

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

As we can see, their signature is not the same, Id needs to be mapped to SIN, and Gender needs to be casted to a string.

Let’s see how we can achieve this:

public class MyMappingProfiles : Profile
{
   public MyMappingProfiles()
   {
      CreateMap<UserEntity, User>()
      .ForMember(dest => dest.Gender, source => source.MapFrom(src => src.Gender.ToString()))
      .ForMember(dest => dest.FirstName, source => source.MapFrom(src => src.FirstName.ToUpper()))
      .ForMember(dest => dest.LastName, source => source.MapFrom(src => src.LastName.ToUpper()))
      .ForMember(dest => dest.SIN, source => source.MapFrom(src => src.Id));
   }
}

The important thing here is to inherit from Profile class. When the application starts, every classes that inherit from a Profile class will be registered by AutoMapper and the mapping strategy will be enabled.

How to use a mapping strategy ? Let’s go to the next section!

Using a mapping strategy

Let’s create a Controller and inject in the constructor the interface IMapper as follow:

[Route("api/[controller]")]
[ApiController]
public class DemoMappingController : ControllerBase
{
   private IMapper _mapper;

   public DemoMappingController(IMapper mapper)
   {
      _mapper = mapper;
   }

   [HttpGet("getuser")]
   public ActionResult<User> Get()
   { 
      var entity = new UserEntity
      {
         Gender = Gender.Mister,
         FirstName = "Anthony",
         LastName = "Giretti",
         Id = "123456789"
      };

   return Ok(_mapper.Map<User>(entity));
}

Because the Nuget package we installed (AutoMapper +  Injection Dependency extensions for AutoMapper) we are able to use AutoMapper by calling the interface IMapper.

In order to execute the mapping let’s call the map method like this: _mapper.Map<TDestination>(objectToMap)

Demo!

Conclusion

With Automapper you can map one object to another throughout your application with just a little configuration.

This example was really simple. AutoMapper can really handle more complex mappings.

I leave you the opportunity to deepen the subject hoping that this article convinced you to use AutoMapper 🙂

Common features in ASP.NET Core 2.2 WebApi: Caching

 

Introduction

In the previous article we talked about the answers to probable interrogations that we could have on the performances of a Web API by helping us with the metrics collected with MiniProfiler.
We will now see a feature allowing us to optimize the performance of our Web API: data caching.

In this article we will see four ways to cache our data:

  • In-memory cache with IMemoryCache provided by Microsoft.Extensions.Caching.Memory assembly
  • Response cache with ResponseCacheAttribute provided by Microsoft.AspNetCore.Mvc assembly
  • Global Response cache with the default Response Caching Middleware provided by Microsoft.AspNetCore.ResponseCaching assembly (won’t be described in this article)
  • Global Response cache with a custom Response Caching Middleware provided by Microsoft.AspNetCore.ResponseCaching assembly

Installation

Download this package:

PM> Install-Package Microsoft.AspNetCore.ResponseCaching

This package is required only for the global cache with middleware

The two others are provided by the default package installed when you create a new app: Microsoft.AspNetCore.App

Configuring Startup.cs 

It’s really simple to configure and activate cache, let’s see how it works (No configuration is required to activate Response cache by MVC Attribute):

First let’s add In-memory cache and Response Caching Middleware

in ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
   // cache in memory
   services.AddMemoryCache();
   // caching response for middlewares
   services.AddResponseCaching();
}

AddResponseCaching() is required if you need to use the default Response Caching Middleware AND a custom middleware

Now let’s activate the default Response Caching Middleware:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
   // caching response for middlewares
   app.UseResponseCaching();
}

No particular activation is required for In-memory cache (IMemoryCache)

Using cache in the Web API

Let’s implement a sample of each case described in introduction:

public class DemoCachingController : ControllerBase
{
   private readonly IMemoryCache _cache;

   public DemoCachingController(IMemoryCache cache)
   {
      _cache = cache;
   }

   // GET: api/DemoCaching/memorycache
   [HttpGet("memorycache")]
   public string Get()
   {
      var cacheEntry = _cache.GetOrCreate("MyCacheKey", entry =>
      {
         entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
         return LongTimeOperation();
      });
      return cacheEntry;
   }

   // GET: api/DemoCaching/responsecache
   [HttpGet("responsecache")]
   [ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any)]
   public string Get2()
   {
      return LongTimeOperation();
   }

   // GET: api/DemoCaching/globalcache
   [HttpGet("globalcache")]
    public string Get3()
    {
       return LongTimeOperation();
    }

    private string LongTimeOperation()
    {
       Thread.Sleep(5000);
       return "Long time operation done!";
    }
}

In-memory cache with IMemoryCache

This use case represents a cache stored in the memory of the web server and works natively with ASP.NET Core dependency injection.

In this sample we use the method GetOrCreate that creates an entry in the server memory the first time we use it with a specific entry “MyCacheKey”, The operation result that needs to be cached is executed this time.

The second time the operation is called, GetOrCreate  method will check in the memory if an entry with the “MyCacheKey” exists, and will load it from memory. The operation that provides the result is not executed.

For the cache expiracy I recommand to use AbsoluteExpirationRelativeToNow option because the cache will expire after a precise time (up to you for the duration), instead of SlidingExpiration that expires after a precise duration if the cache has not been used. By this way you will ensure your data will be up to date after a certain moment.

Response cache with ResponseCacheAttribute

This case represents a cache stored on the server or / and on the client browser.

This attribute can be used to avoid any cache as well.

There are not so much properties:

  • Duration that indicates the time of expiracy in seconds
  • Location allow to choose where to cache your response (Any for client + browser, Client for the browser only, None to avoid any caching)
  • NoStore overrides most of the other properties. When this property is set to true, the Cache-Control header is set to no-store. If Location is set to None: Cache-Control is set to no-store,no-cache. Pragma is set to no-cache. If NoStore is false and Location is None, Cache-Control and Pragma are set to no-cache.
  • VaryByHeader stores cache for one / several header, example: VaryByHeader = “User-Agent” will cache the same data or clients that have the same User Agent.
  • VaryByQueryKeys is special, when you  want to use it, enabling the middleware for response caching is required (services.AddResponseCaching() and app.UseResponseCaching()). This option allow you to cache by one  / several QueryString key. (http://localhost:xxxxx/api/?param1=value1&param2=value2).

In the code sample above, I cache my action for 1 minute on the client and the server.

This way to cache can be used for error pages for example because the default Response Caching Middleware ignores HTTP status other than 200 (OK).

Response cache with a custom Response Caching Middleware

This way to cache allow you to cache gobally any HTTP responses.

The good news is that you can setup in the middleware QueryString keys you want to apply cache like the ReponseCacheAttribute by playing with IResponseCachingFeature Interface.

Example of a custom Response Caching Middleware:

This middleware caches all HTTP responses during 10 seconds if the URL contains the QueryString “Param1”.

public class CachingMiddleware
{
   private readonly RequestDelegate _next;

   public CachingMiddleware(RequestDelegate next)
   {
      _next = next;
   }

   public async Task Invoke(HttpContext context)
   {
      // Sample of global cache for any request that contains in QueryString "Param1"
      // Note that the middleware ignores requests doesn't return 200 (OK)
      context.Response.GetTypedHeaders().CacheControl =
      new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
      {
         Public = true,
         MaxAge = TimeSpan.FromSeconds(10)
      };
      var responseCachingFeature = context.Features.Get<IResponseCachingFeature>();
      if (responseCachingFeature != null)
      {
         responseCachingFeature.VaryByQueryKeys = new[] { "Param1" };
      }
      await _next(context);
   } 
}

Demo

Let’s use Postman for the demos:

Demo with IMemoryCache

First call

Second call

Demo with ResponseCacheAttribute

First call

Second call

Demo with a custom Response Caching Middleware

First call

Second call

Note that to make everything working with Postman, just ensure to disable “Send no-cache header”

Conclusion

You saw how to use cache with 3 differents manners.

Keep in mind caching can significantly improve the performance and scalability of an ASP.NET Core app.

There is also another one manner you can use not described in this article: Distributed cache, this is a different cache because this cache is shared by multiple app servers, typically maintained as an external service to the app servers that access it. I will talk about this kind of cache in another article.

Hope you enjoyed this article 🙂

Common features in ASP.NET Core 2.2 WebApi: Profiling

 

Introduction

It is quite natural to wonder about the performance of a newly developed Web API.
There are for example tools like Application Insights in Visual Studio and Azure which allow to monitor your applications, There is another Stackify Prefix tool which is free and which allows to trace Http requests. This tool is described here: https://www.carlrippon.com/scalable-and-performant-asp-net-core-web-apis-profiling-and-monitoring/

In this article we will explore the integration of MiniProfiler into an ASP.NET Core 2.2 Web API, a free tool that allows you to finely profile any code protion in ASP.NET and ASP.NET Core applications.

Bonus! We will also see how MiniProfiler can be easily integrated to Swagger!

Installation

Download this package:

PM> Install-Package MiniProfiler.AspNetCore.Mvc

Configuring Startup.cs 

It’s pretty simple to configure and activate MiniProfiler.

First let’s add MiniProfiler in ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
   // profiling
   services.AddMiniProfiler(options =>
      options.RouteBasePath = "/profiler"
   );
}

Now let’s activate the middleware that enable MiniProfiler:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
   // profiling, url to see last profile check: http://localhost:xxxxx/profiler/results
   app.UseMiniProfiler();
}

Setup your portion of code you want to profile

public class DemoProfilingController : ControllerBase
{
   // GET: api/DemoProfiling
   // url to see last profile check: http://localhost:xxxxx/profiler/results
   // profile available in swagger page too
   [HttpGet]
   public IEnumerable<string> Get()
   {
      string url1 = string.Empty;
      string url2 = string.Empty;
      using (MiniProfiler.Current.Step("Get method"))
      {
         using (MiniProfiler.Current.Step("Prepare data"))
         {
            using (MiniProfiler.Current.CustomTiming("SQL", "SELECT * FROM Config"))
            {
               // Simulate a SQL call
               Thread.Sleep(500);
               url1 = "https://google.com";
               url2 = "https://stackoverflow.com/";
            }
         }
         using (MiniProfiler.Current.Step("Use data for http call"))
         {
            using (MiniProfiler.Current.CustomTiming("HTTP", "GET " + url1))
            {
               var client = new WebClient();
               var reply = client.DownloadString(url1);
            }

            using (MiniProfiler.Current.CustomTiming("HTTP", "GET " + url2))
            {
               var client = new WebClient();
               var reply = client.DownloadString(url2);
            }
         }
      }
      return new string[] { "value1", "value2" }; 
   }
}

MiniProfiler.Current.Step() is the most common way to define section of code to be profiled.

This method takes in parameter a string that describes the name of the code section.

The same method can be nested with the previous indefinitely (code in bold above).

MiniProfiler.Current.CustomTiming() helps to categorize finely the portion of code profiled, like the exact command executed and in what category the profile is set for.

In our example we categorize the profiled code in “HTTP” and “SQL”.

Demo

Let’s take a look on the result after the execution of our code (http://localhost:xxxxx/api/Demoprofiling)

As we set it up in the Startup.cs let’s call the route that display profiling results:

As we can see each steps appear clearly with their respective portions of code.

Each category (HTTP and SQL) have their own statistics,  an easy to see which part of the application takes time and causes or not performance issues.

This page shows only the latest request.

It’s for sure possible to log into a database or in a file via a logger the statistics. (I will provide an example of implementation soon).

Bonus: Integration with Swagger

As I promised earlier here is hiw we can integrate MiniProfiler with Swagger.

In order to achieve this we have to modify the index.html page of  Swagger.

Download the index page:

The default index.html is downloadable here:

https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/src/Swashbuckle.AspNetCore.SwaggerUI/index.html

Let’s setup Swagger’s custom page:

In your Startup.cs file, modify options of UseSwaggerUI middleware to add IndexStream option:

app.UseSwaggerUI(c =>
{
   c.RoutePrefix = "api-doc";
   c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
   // this custom html has miniprofiler integration
   c.IndexStream = () => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("WebApiDemo.SwaggerIndex.html");
});

Then name your html file as you desire, in our example: SwaggerIndex.html, WebApiDemo is the namespace where the file is located.

At the top of the file, add this script:

<script async="async" id="mini-profiler" src="/profiler/includes.min.js?v=4.0.138+gcc91adf599" 
        data-version="4.0.138+gcc91adf599" data-path="/profiler/" 
        data-current-id="4ec7c742-49d4-4eaf-8281-3c1e0efa748a" data-ids="" data-position="Left" 
        data-authorized="true" data-max-traces="15" data-toggle-shortcut="Alt+P" 
        data-trivial-milliseconds="2.0" data-ignored-duplicate-execute-types="Open,OpenAsync,Close,CloseAsync">
</script>

To make everything working don’t forget to set in the HTML file properties  “Build Action” to “Embedded resource”.

Now let’s execute again the same code like previously and see the Swagger page:

The statistics are now provided in a little box on the top left of the screen.

Awesome isn’t it ? 😉

Conclusion

Now you know how to profile your Web APIs easily. MiniProfiler is simple to implement and it’s easy to understand metrics.

If you want to monitor each request with all wanted metrics, I suggest you to store your metrics in a database and build a WebApp with the data stored.

Promise I will come back soon with a database storage implementation 🙂