Search code examples
asp.net-coremiddleware

Configuring options for middleware


Looking on different libraries and even Microsoft code I've noticed two different ways of configuring options in code:

in ConfigureServices it can be done when registering DependencyInjection:

services.AddMvc(options => { });

or in Configure

app.UseStaticFiles(
     new StaticFileOptions
     {
        ServeUnknownFileTypes = true
     });

I tried to find out, which way use for which purpose and still don't know, assuming that creating your own middleware and registering both DI and usage.


Solution

  • Interesting issue you have found.

    Looking into the source code i have found the following:

    All the middleware registrations are an overload of this UseMiddleware function, which is an overload of IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);.

    In these overloads you can specify hard your own parameters for the middle-ware. Say you have a few strings in the constructor, the DI container will not be able to resolve this.

    If the parameters aren't set though, it does fallback to the IServiceProvider to resolve the specific type. see extension class: Microsoft.Extensions.Internal.ActivatorUtilities (inside: Microsoft.AspNetCore.Http.Abstractions.dll)

    Tips

    As for best practice think about the following (my opinion though):

    • Try to avoid using simple types in constructor but use an Options class.
    • for IOptions use services.Configure<>() as here you can specify options from a ConfigSection => appsettings.
    • As for Services: be aware that middleware is a singleton! so adding a transient Service, will only be resolved once for this middleware!

    I think best practise is to: Register Middleware AND its dependencies as singletons in IOC on startup. then resolve it yourself and add it yourself with the method App.Use([yourDelegate]).

    The advantage of this method is it is easilier understandable than use the hidden microsoft code + Microsoft recently published an upgrade to the DI container to check if the scopes of your registrations match properly (and warn you if not).

    This tool basically does: it checks if a dependency of a service has a smaller scope then the service itself: say service is scope: Singleton and the dependency is scope Transient. this means that if Singleton is resolved Transient is also resolved for this singleton and thus not resolved again on next usage of this singleton. (so its a hidden singleton usage).