Unit Testing the HttpContext in Controllers

Introduction

When it comes to unit testing, it is common to use mocking to replace “external” services, that is, those that are not part of the subject under test. Not everything can be mocked, and, sometimes, when we instantiate non-POCO classes, such as controllers (ControllerBase), there are lots of things that are not instantiated by the framework and are left for us do to. Just think, for example, if you want to access request or quest string data or know if the user is logged in?

In this post I will talk about two things: the user identity and the request data.

The HttpContext

Inside of a controller action method, it is common to get information which actually comes from the the context (the HttpContext property):

All of these properties get routed to the HttpContext property, which is read-only. It turns out that this property is itself routed to the ControllerContext’s property’s own HttpContext, but the ControllerContext can be set:

var controller = new HomeController();
controller.ControllerContext = new ControllerContext();

So, if we want to set a controller’s HttpContext property, all we have to do is set the ControllerContext’s HttpContext:

controller.ControllerContext.HttpContext = new DefaultHttpContext();

The DefaultHttpContext class is the default implementation of the abstract HttpContext class that is included in ASP.NET Core.

Features

All of the .NET and ASP.NET Core is very modular and designed for extensibility, so it should come as no surprise that all of the HttpContext features are provided as features and it’s easy to provide implementations for them.

Features are accessible through the Features collection and can be set using as key one interface, which is generally a core interface that identifies that feature:

context.Request.Set<IFormFeature>(new FormCollection(request));

The DefaultHttpContext takes in one of its constructors a collection of features, from which it can extract its functionality.

Request Data

When we talk about the request we can be talking about:

  • Form data (including files)
  • The query string

Each is implemented by its own feature. So, if we want to mock form data, we would do something like this, leveraging the IFormFeature:

var request = new Dictionary { { “email”, “rjperes@hotmail.com” }, { “name”, “Ricardo Peres” } }; var formCollection = new FormCollection(request); var form = new FormFeature(formCollection);

var features = new FeatureCollection(); features.Set<IFormFeature>(form); var context = new DefaultHttpContext(features);

This allows us to write code like this, from inside the :

var email = HttpContext.Request["email"];

As for the query string, we would do it like this, using IQueryFeature:

var request = new Dictionary { { “id”, “12345” } }; var queryCollection = new QueryCollection(request); var query = new QueryFeature(queryCollection);

var features = new FeatureCollection(); features.Set<IQueryFeature>(form); var context = new DefaultHttpContext(features);

This code gives us the ability to do this:

var id = HttpContext.Request.Query["id"];

Response

What about sending responses, HTTP status codes and cookies? I’ve got you covered too! The feature contract for the response is IHttpResponseFeature and we add it like this:

var response = new HttpResponseFeature();

var features = new FeatureCollection(); features.Set<IHttpResponseFeature>(response); var context = new DefaultHttpContext(features);

var responseCookies = new ResponseCookiesFeature(context.Features);

Notice that the ResponseCookiesFeature is a little awkward, as it takes the feature collection in its constructor.

With this on, you can set the response status or some cookies on the response of your action:

Response.StatusCode = 400;
Response.Cookies.Append("foo", "bar");

User Identity

As for the user identity, it’s much simpler, we just need to create a ClaimsPrincipal with any claims that we want:

var context = new DefaultHttpContext(features)

{ User = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]

{

     new Claim(ClaimTypes.Name, “<username>”),

new Claim(ClaimTypes.Role, “<role>”)

    })) };

You can just pass any username and roles you want, and they will be made available to the controller’s User property.

Conclusion

As you can see, with a little bit of work, almost anything is possible in .NET Core, and, particularly, when it comes to unit tests! Stay tuned for more! Winking smile

Dynamic Routing in ASP.NET Core 3

ASP.NET Core 3 introduced a not so talked about feature which is dynamic routing. In a nutshell, it means that it is possible to decide at runtime the controller, action and route tokens that a request will be dispatched to. The idea is to map a route pattern to a dynamic route handler, like this:

app.UseEndpoints(endpoints =>
{
    endpoints.MapDynamicControllerRoute<SearchValueTransformer>("search/{**product}");
});

This maps a route of “/search/<anything>” to a class SearchValueTransformer, which is then responsible for supplying values for the controller and action.

This SeachValueTransformer class must inherit from DynamicRouteValueTransformer, this is the abstract base class for all dynamic route handling, and it only has one method to implement, TransformAsync. The example I am providing here is that of a service that receives some random query for a product on the URL and then decides to which controller it will be forwarded to. A sample implementation of this class would be:

class SearchValueTransformer : DynamicRouteValueTransformer { private readonly IProductLocator _productLocator; public SearchValueTransformer(IProductLocator productLocator) { this._productLocator = productLocator; } public override async ValueTask TransformAsync(

HttpContext httpContext, RouteValueDictionary values) { var productString = values[“product”] as string; var id = await this._productLocator.FindProduct(“product”, out var controller); values[“controller”] = controller; values[“action”] = “Get”; values[“id”] = id; return values; } }

As you can see, it takes an instance of an IProductLocator (I will get to that in a moment) in its constructor, which means that it supports dependency injection. The TransformAsync extracts a “product” parameter from the route – I am skipping validation because if we got here that’s because we matched the route – which it then uses to call the stored IProductLocator instance to retrieve the id and controller, which are then set as route parameters. The result route is then returned.

The SearchValueTransformer needs to be registered in the dependency injector too:

services.AddSingleton<SearchValueTransformer>();

The actual lifetime is irrelevant, here I am setting it as singleton because the SearchValueTransformer holds a single IProductLocator which is itself a singleton and nothing else.

As to the IProductLocator, here is it’s interface:

public interface IProductLocator
{
    Task<string> FindProduct(string product, out string controller);
}

The actual implementation, I leave it up to you, it must apply some logic to the product passed in the URL to decide which controller should be used for search it, and then return some reference and a controller responsible for returning information about it. This interface and its implementation must also be registered:

services.AddSingleton<IProductLocator, ProductLocator>();

And this is it. This may serve as a complement to static routing, other uses include translating route parts (controller, action) on the fly. As always, hope you find this useful!

Accessing the HttpContext from a DbContext

Sometimes it might be necessary to access the current HttpContext from inside a DbContext, namely, from inside the OnConfiguring or OnModelCreating methods. Why? Well, for once, because of multitenancy: we may want to be able to decide the connection string to use based on the requesting or the host’s domain, the current user or some other request parameter. Here the internal dependency injection (Instance) can’t help, because it cannot be used inside these methods.

The only option we have is to inject the IHttpContextAccessor class through our DbContext class’ constructor, and, from it, get hold of the HttpContext.

First we need to register the IHttpContextAccessor service in ConfigureServices:

services.AddHttpContextAccessor();

We also need to register our context for dependency injection:

services.AddDbContext<MyContext>();

A context registered this way needs to have a special constructor that has a parameter of type DbContextOptions (or DbContextOptions<MyContext>), in our case, we just need to add an extra parameter of type IHttpContextAccessor:

public class MyContext : DbContext
{
    public MyContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor) : base(options)
    {
        this.HttpContextAccessor = httpContextAccessor;
    }

    protected IHttpContextAccessor HttpContextAccessor { get; }
}

Finally, when you need to access the HttpContext, you just need to retrieve it from the IHttpContextAccessor:

protected internal override void OnConfiguring(DbContextOptionsBuilder builder)
{
    var httpContext = this.HttpContextAccessor.HttpContext;
    var tenantService = httpContext.RequestServices.GetService<ITenantService>();
    var connectionString = tenantService.GetConnectionString(httpContext);

    builder.UseSqlServer(connectionString);

    base.OnConfiguring(builder);
}

Here the hypothetical ITenantService provides a method GetConnectionString that returns a connection string for the current HttpContext, and we use it with the SQL Server provider.

Hope you find this useful! Winking smile

.NET Core Service Provider Gotchas and Less-Known Features

Introduction

In this post I’m going to talk about a few gotchas with the .NET Core’s built-in inversion of control (IoC) / service provider (SP)/dependency injection (DI) library. It is made available as the Microsoft.Extensions.DependencyInjection NuGet package.

I wrote another post some time ago, but this one supersedes it, in many ways.

Extension Methods

The single method exposed by the IServiceProvider interface, GetService, is not strongly typed. If you add a using statement for Microsoft.Extensions.DependencyInjection, you’ll get a few ones that are:

  • GetRequiredService<T>: tries to retrieve a service that is registered under the type of the generic template parameter and throws an exception if one cannot be found; if it is, it is cast to the template parameter;
  • GetService<T>: retrieves a service and casts it to the template parameter; if no service is found, null is returned;
  • GetServices<T>: returns all services registered as the template parameter type, cast appropriately.

Using a Different Service Provider

You are not forced to use the built-in service provider; you can use anyone you like, as long as it exposes an IServiceProvider implementation. You just need to return this implementation from the ConfigureServices method, which normally does not return anything:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
//return an implementation of IServiceProvider
}

Why would you want to do that, you may ask? Well, there are service providers out there that offer much more interesting features than Microsoft’s (for example, more lifetimes), and this has a reason: Microsoft kept his simple on purpose.

Multiple Registrations

You may not have realized that you can register any number of implementations for a given service, even with different lifetimes:

services.AddTransient<IService, ServiceA>();
services.AddScoped<IService, ServiceB>();

So, what happens when you ask for an implementation for IService? Well, you get the last one registered, in this case, ServiceB. However, you can ask for all the implementations, if you call GetServices<T>.

Registration Factories

You can specify how a service implementation is constructed when you register a service, and it can depend upon other services that are also registered in the service provider:

services.AddTransient<IService>(sp => new ServiceImpl(sp.GetRequiredService<IOtherService>));

Don’t worry about registration order: IOtherService will only be required once IService is retrieved.

Lifetime Dependencies

You cannot have a Singleton registration depend upon a Scoped service. This makes sense, if you think about it, as a singleton has a much longer lifetime than a scoped service.

Nested Scopes

You can create nested scopes at any time and retrieve services from them. If you are using the extension methods in the Microsoft.Extensions.DependencyInjection namespace, it’s as easy as this:

using (var scope = serviceProvider.CreateScope())
{
    var svc = scope.ServiceProvider.GetRequiredService<IService>();
}

The CreateScope method comes from the IServiceScopeFactory implementation that is registered automatically by the dependency injection implementation. See next for implications of this.

Why is this needed? Because of lifetime dependencies: using this approach you can instantiate a service marked as a singleton that takes as a parameter a scoped one, inside a scope.

Dispose Pattern

All services instantiated using the Scoped or Transient lifetimes that implement the IDisposable interface will have their Dispose methods called at the end of the request – or the nested scope (when it is disposed). The root service provider is only disposed with the app itself.

Scope Validation

The built-in service provider validates the registrations so that a singleton does not depend on a scoped registration. This has the effect of preventing retrieving services in the Configure method, through IApplicationBuilder.ApplicationServices, that are not transient or singletons.

If, however, you think you know what you’re doing, you can bypass this validation:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
//add services
return services.BuildServiceProvider(validateScopes: false);
}

As I said before, the other alternative is creating a scope and instantiating your singleton service inside the scope. This will always work.

Injecting Services

ASP.NET Core only supports constructor:

public HomeController(IService svc)
{
}

and parameter:

public IActionResult Index([FromServices] IService svc)
{
}

inheritance, but not property, in controllers and Razor Pages. You can achieve that through actions or conventions. Another option is to use the Service Locator pattern.

Service Locator

You can retrieve any registered services from HttpContext.RequestServices, so whenever you have a reference to an HttpContext, you’re good. From the Configure method, you can also retrieve services from IApplicationBuilder.ApplicationServices, but not scoped ones (read the previous topics). However, it is generally accepted that you should prefer constructor or parameter injection over the Service Locator approach.

Conclusion

Although the service provider that comes with .NET Core is OK for most scenarios, it is clearly insufficient for a number of others. These include:

  • Other lifetimes, such as, per resolve-context, per thread, etc;
  • Property injection;
  • Lazy<T> support;
  • Named registrations;
  • Automatic discovery and configuration of services;
  • Child containers.

You should consider a more featured DI library, and there are many out there, if you need any of these.

Integrating Managed Extensibility Framework with the .NET Service Provider

Introduction

It seems I’m in the mood for Managed Extensibility Framework: second post in a week about it! This time, I’m going to talk about how we can integrate it with the .NET Core’s service provider/dependency injection (DI) library (Microsoft.Extensions.DependencyInjection).

Mind you, this will apply to both ASP.NET Core and .NET Core console apps.

Locating Services

We’ve seen before how we can find all types that match a given interface:

public static class ContainerConfigurationExtensions     {         public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, SearchOption searchOption = SearchOption.TopDirectoryOnly)         {             return WithAssembliesInPath(configuration, path, null, searchOption);         }         public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, AttributedModelProvider conventions, SearchOption searchOption = SearchOption.TopDirectoryOnly)         {             var assemblyFiles = Directory                 .GetFiles(path, "*.dll", searchOption);             var assemblies = assemblyFiles                 .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath);             configuration = configuration.WithAssemblies(assemblies, conventions);             return configuration;         }     }

Service Registration

The next step is picking up all of the found types and registering them with the DI:

public static class ServiceCollectionExtensions     {         public static IServiceCollection AddFromAssembliesInPath<T>(this IServiceCollection services, ServiceLifetime lifetime, string path = null) where T : class         {             var factory = new ExportFactory<T, object>(() => new Tuple<T, Action>(Activator.CreateInstance<T>(), () => { }), new object());             var conventions = new ConventionBuilder();             var builder = conventions                 .ForTypesDerivedFrom<T>()                 .Export<T>();             if (lifetime == ServiceLifetime.Singleton)             {                 builder = builder.Shared();             }             path = path ?? AppContext.BaseDirectory;             var configuration = new ContainerConfiguration()                 .WithAssembliesInPath(path, conventions);             using (var container = configuration.CreateContainer())             {                 var svcs = container.GetExports<Lazy<T>>();                 foreach (var svc in svcs)                 {                     services.Add(new ServiceDescriptor(typeof(T), sp => svc.Value, lifetime));                 }             }             return services;         }         public static IServiceCollection AddSingletonFromAssembliesInPath<T>(this IServiceCollection services, string path = null) where T : class         {             return AddFromAssembliesInPath<T>(services, ServiceLifetime.Singleton, path);         }         public static IServiceCollection AddScopedFromAssembliesInPath<T>(this IServiceCollection services, string path = null) where T : class         {             return AddFromAssembliesInPath<T>(services, ServiceLifetime.Scoped, path);         }         public static IServiceCollection AddTransientFromAssembliesInPath<T>(this IServiceCollection services, string path = null) where T : class         {             return AddFromAssembliesInPath<T>(services, ServiceLifetime.Transient, path);         }     }

The AddFromAssembliesInPath extension method is what does all the work; it leverages the previous WithAssembliesInPath method to locate all types that match a given interface, in the assemblies inside a specific folder (which can be the current one). AddSingletonFromAssembliesInPath, AddScopedFromAssembliesInPath and AddTransientFromAssembliesInPath are merely here to make your life a (little bit) easier. Although MEF only supports singletons (Shared) and transient (Non-shared) lifetimes, with this approach

Notice how MEF let’s us resolve Lazy<T> instances besides T. This is pretty cool, as we can delay object instantiation to a later stage, when the object is actually needed. A word of caution: the instantiation will actually be done by MEF, not by the .NET Core DI, so you won’t have constructor injection.

Putting it all Together

So, armed with these two extension methods, we can add this to the ConfigureServices method of your ASP.NET Core app (or wherever you populate your service provider):

services.AddTransientFromAssembliesInPath<IPlugin>();

Here IPlugin is just some interface, nothing to do with the one described in the previous post. After this, you should be able to inject all of the actual implementations:

public class HomeController : Controller

{

public HomeController(IEnumerable<IPlugin> plugins) { … }

}

Dynamically Loading Middleware in ASP.NET Core

Introduction

The concept of middleware has been around since ASP.NET MVC (pre-Core) and OWIN. Essentially, a middleware component lives in a pipeline and handles requests and acts as a chain of responsibility, delegating to any subsequent middleware components registered in the pipeline after itself. The following image (taken from the Microsoft site) shows this.

Image result for asp.net core middleware

MVC itself is implemented as a middleware component, as is redirection, exception handling, buffering, etc.

A middleware component can be added in several ways, but in ASP.NET Core, it all goes down to the Use method in IApplicationBuilder. Lots of API-specific methods rely on it to add their own middleware.

For the time being, we’ll make use of the IMiddleware interface that comes with ASP.NET Core. It provides a simple contract that has no dependencies other than the common HTTP abstractions.

One common request is the ability to load and inject middleware components dynamically into the pipeline. Let’s see how we can

Managed Extensibility Framework

.NET Core has Managed Extensibility Framework (MEF), and I previously blogged about it. MEF offers an API that can be used to find and instantiate plugins from assemblies, which makes it an interesting candidate for the discovery and instantiation of such middleware components.

Image result for managed extensibility frameworkWe’ll use the System.Composition NuGet package. As in my previous post, we’ll iterate through all the assemblies in a given path (normally, the ASP.NET Core’s bin folder) and try to find all implementations of our target interface. After that we’ll register them all to the MEF configuration.

Implementation

Our target interface will be called IPlugin and it actually inherits from IMiddleware. If we so wish, we can add more members to it, for now, it really doesn’t matter:

public interface IPlugin : IMiddleware
{
}

The IMiddleware offers an InvokeAsync method that can be called asynchronously and takes the current context and a pointer to the next delegate (or middleware component).

I wrote the following extension method for IApplicationBuilder:

public static class ApplicationBuilderExtensions

{

public static IApplicationBuilder UsePlugins(this IApplicationBuilder app, string path = null)        {

     var conventions = new ConventionBuilder();

        conventions

           .ForTypesDerivedFrom<IPlugin>()

           .Export<IPlugin>()

           .Shared();

           path = path ?? AppContext.BaseDirectory;

            var configuration = new ContainerConfiguration()

            .WithAssembliesInPath(path, conventions);

            using (var container = configuration.CreateContainer())

            {

           var plugins = container

                .GetExports<IPlugin>()

                    .OrderBy(p => p.GetType().GetCustomAttributes<ExportMetadataAttribute>(true)

.SingleOrDefault(x => x.Name == “Order”)?.Value as IComparable ?? int.MaxValue); 

               foreach (var plugin in plugins)

                {

                    app.Use(async (ctx, next) =>

                    {

                    await plugin.InvokeAsync(ctx, null);

                        await next();

                    });

                }

          }

          return app;

    }

}

We define a convention that for each type found that implements IPlugin we register it as shared, meaning, as a singleton.

As you can see, if the path parameter is not supplied, it will default to AppContext.BaseDirectory.

We can add to the plugin/middleware implementation an ExportMetadataAttribute with an Order value to specify the order by which our plugins will be loaded, more on this in a moment.

The WithAssembliesInPath extension method comes from my previous post but I’ll add it here for your convenience:

public static class ContainerConfigurationExtensions
{     public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, SearchOption searchOption = SearchOption.TopDirectoryOnly)     {      return WithAssembliesInPath(configuration, path, null, searchOption);     }     public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path, AttributedModelProvider conventions, SearchOption searchOption = SearchOption.TopDirectoryOnly)     {         var assemblyFiles = Directory          .GetFiles(path, "*.dll", searchOption);         var assemblies = assemblyFiles             .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath);         configuration = configuration.WithAssemblies(assemblies, conventions);         return configuration;     }
}

If you want to search all assemblies in nested directories, you need to pass SearchOption.AllDirectories as the searchOption parameter, but this, of course, will have a performance penalty if you have a deep directory structure.

Putting it All Together

So, let’s write a few classes that implement the IPlugin interface and therefore are suitable to be used as middleware components:

[Export(typeof(IPlugin))] [ExportMetadata(“Order”, 1)] public class MyPlugin1 : IPlugin {     public async Task InvokeAsync(HttpContext context, RequestDelegate next)     {         //do something here

//this is needed because this can be the last middleware in the pipeline (next = null)         if (next != null)         {             await next(context);         }

//do something here     } }

Notice how we applied an ExportMetadataAttribute to the class with an Order value; this is not needed and if not supplied, it will default to the highest integer (int.MaxValue), which means it will load after all other plugins. These classes need to be public and have a public parameterless constructor. You can retrieve any registered services from the HttpContext’s RequestServices property.

Now, all we need to do is add a couple of assemblies to the web application’s bin path (or some other path that is passed to UsePlugins) and call this extension method inside Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

{

//rest goes here

app.UsePlugins(/*path: “some path”*/);

//rest goes here

}

And here you have it: ASP.NET Core will find middleware from any assemblies that it can find on the given path.

Hope you find this useful! Winking smile

Succinctly Books Index

This page lists all the books I wrote or reviewed for Syncfusion’s Succinctly series.

Books I wrote:

Books I reviewed:

ASP.NET Core Pitfalls – Session Storage

Previous versions of ASP.NET featured several ways to persist sessions:

  • InProc: sessions would be stored on the server’s process memory
  • SQL Server: sessions would be serialized and stored in a SQL Server database; other vendors offered similar functionality
  • State Server: sessions would be serialized and stored on an instance of the ASP.NET State Service
  • Custom: we had to implement our own persistence mechanism

InProc was probably the most commonly used; it was the fastest, as the items in the session weren’t serialized, but on the other side they would not survive server crashes. Using this approach things usually worked well, because the session object merely provided a reference to the items stored in memory, so manipulating these items didn’t mandate that the session be explicitly saved.

In ASP.NET Core, all of this is gone. By default, sessions are still stored in memory but one can also use one of the available distributed cache mechanisms. The main difference, however, is that even when the session objects are stored in memory, they still need to be serialized and deserialized prior to persisting or retrieving them. It is no longer possible to just store a pointer to a memory object and keep manipulating it transparently; the object to be stored needs to be converted into a byte array first. You can use any serializer you want.

If we think about it seriously, it was probably a good decision: I’ve seen applications where a lot of data was being stored on the session using InProc mode, but then there was a need to switch to another mode to improve scalability, and the application would just stop working, as the objects being stored weren’t serializable. This time, we need to carefully think about it beforehand.

ASP.NET Core Pitfalls – Redirect to Action Keeps Route Parameters

When you redirect after a POST – following the famous Post-Redirect-Get pattern – but your previous view was constructed using a route parameter, then it will be sent to the redirect action as well.

For example, say you are responding to a request for /Filter/Smartphone, where Smartphone is a route parameter, you POST it to some controller action and at the end you redirect to the Index action using the RedirectToAction method:

return this.RedirectToAction(nameof(Index));

The browser will issue the GET request for Index but keeps the Smartphone route parameter, which is not good.

The solution is to pass a routeValues parameter to RedirectToAction that doesn’t contain any of the possible route parameters. One way to do it would be to create a dictionay with all action parameters nullified:

return this.RedirectToAction(nameof(Index), MethodBase.GetCurrentMethod().GetParameters().ToDictionary(x => x.Name, x => (object) null));

The solution to have this done automatically lies in the MethodBase.GetCurrentMethod() method. This way, you are sure to avoid any unwanted route parameters on your next request.

In case you are wondering, passing null, a dictionary without entries or object won’t work, the only other way is to pass an anonymous value with the parameters explicitly set to null.