Search code examples
owinkatana

How to add middleware to Owin without IAppBuilder


I'm currently building a library that contains several OWIN-middlewares. These middlewares should be executed in a certain order. In one of the first releases of OWIN, there was the IAppBuilder interface. However the IAppBuilder is not part of OWIN anymore, but part of Microsoft.Owin. I don't want to force my user(s) to have a dependency on Microsoft.Owin.

What is the preferred way of adding middlewares to the OWIN-pipeline without using Microsoft.Owin?


Solution

  • It took some time, but I think I figured it out.

    First the definitions as specified by Owin:

    public delegate Task AppFunc(IDictionary<string, object> environment);
    
    public delegate AppFunc MidFunc(AppFunc next);
    
    public delegate MidFunc MidFactory(IDictionary<string, object> startupProperties);
    
    public delegate void BuildFunc(MidFactory midFactory);
    

    I use delegate here to avoid the generics madness.

    To go from IAppBuilder to BuildFunc:

    public static BuildFunc UseOwin(this IAppBuilder builder)
    {
        return middleware => builder.Use(middleware(builder.Properties));
    }
    

    In order to build a pipeline using BuildFunc, you can create an extension on BuildFunc:

    public static BuildFunc UseMyFramework(this BuildFunc buildFunc)
    {
        buildFunc(startupProperties => BuildPipeline(startupProperties));
    
        return buildFunc;
    }
    

    It is a good practice to return the BuildFunc for chaining.

    Building the pipeline is nothing more than linking the MidFuncs together and optionally end with the actual AppFunc:

    public static MidFunc BuildPipeline(IDictionary<string, object> startupProperties)
    {
        return next => LogMiddleware(AuthenticateMiddleware(MyApplication));
    
        // Or this if you don't supply your own AppFunc
        return next => LogMiddleware(AuthenticateMiddleware(next));
    }
    
    public static AppFunc LogMiddleware(AppFunc next)
    {
        AppFunc middleware = async environment =>
        {
            // Log request
    
            await next(environment);
        };
    
        return middleware;
    }
    
    public static AppFunc AuthenticateMiddleware(AppFunc next)
    {
        AppFunc middleware = async environment =>
        {
            // authenticate request
    
            await next(environment);
        };
    
        return middleware;
    }
    
    public static async Task MyApplication(IDictionary<string, object> environment)
    {
        await Task.CompletedTask;
    }
    

    You still need to connect the Owin implementation to your framework. I use Microsoft.Owin for this:

    app.UseOwin().UseMyFramework()