Wednesday, January 13, 2016

Owin Appfuncs and Midfuncs

I received some questions about Owin appfuncs and midfuncs, because they are not the easies thing to wrap your head around.

They have the following (rather ugly) definition:

using AppFunc = System.Func<System.Collections.Generic.Dictionary<string, object>, System.Threading.Tasks.Task>;
using MidFunc = System.Func<System.Func<System.Collections.Generic.Dictionary<string, object>, System.Threading.Tasks.Task>, System.Func<System.Collections.Generic.Dictionary<string, object>, System.Threading.Tasks.Task>>

Wow.. that’s easy to understand right? So what’s going on here?

What’s an appfunc?

An appfunc is basically a function that, when invoked with a http request, implements part of a webapplication and thus returns an http response. It can be anything ranging from a function that returns just an http statuscode to a complete webapplication.

A slightly more readable way to think of an appfunc is:

delegate Task AppFunc(Dictionary<string, object> environment);

It’s a function (that executes asynchronously, so it returns a task) that takes a dictionary as a parameter. That dictionary will contain keys that describe both the incoming webrequest as the outgoing response, such as RequestUrl, StatusCode, ResponseStream, etc..

Why do you need a midfunc then?

Owin is designed to make pluggable components into a pipeline. The Midfunc allows you to compose functions (and components) together.

 

A (simplified) example.

public delegate void SimplifiedAppFunc(string url, ref string response);

        /// <summary>
        /// Simplified example of an appfunc that returns helloworld only if you go to the url helloworld.html
        /// </summary>
        /// <param name="url"></param>
        /// <param name="response"></param>
        public static void HelloWorld(string url, ref string response)
        {
            if (url == "helloworld.html")
            {
                response = "<Hello> <World/> </Hello>";
            }
        }

This code is a simplified version of an appfunc. When invoked with the right webrequest, it will return a hello world response.

Now if you want to implement a component, for example request logging, you could do the following:

/// <summary>
        /// Static (non flexible) example of composing functions together to build an appliation
        /// 
        /// Here the LogREquest is limited to calling ONLY the hello world function
        /// </summary>
        /// <param name="url"></param>
        /// <param name="response"></param>
        public static void LogRequest(string url, ref string response)
        {
            Logger.Log("Received request to ", url);

            HelloWorld(url, ref response);

            Logger.Log("Completed request to ", url, "Response was ", response);
        }

        public static void InvokeStaticAppFunc()
        {
            SimplifiedAppFunc appfunc = LogRequest;

            string response = null;
            appfunc("helloworld.html", ref response);

            Console.WriteLine("static appfunc response: " + response);
        }

 

When you call this mini ‘webapplication’, it will log all requests and if the request happens to be for helloworld.html, it will return the hello world page.

But this is hardly a flexible approach, because the LogRequest function now directly calls the helloworld application. To make this component flexible, you’ll need a midfunc:

public delegate SimplifiedAppFunc SimplifiedMidFunc(SimplifiedAppFunc appfunc);

        public static SimplifiedAppFunc LogRequest(SimplifiedAppFunc next)
        {
            return (string url, ref string response) =>
            {

                Logger.Log("Received request to ", url);

                next(url, ref response);

                Logger.Log("Completed request to ", url, "Response was ", response);
            };
        }

 

Now the logrequest function takes an appfunc (which is a mini webapplication), and then extends it with it’s own functionality (in this case request logging). It doesn’t execute it itself, but it returns a new function. Yes, this is functional programming in action here.

Note how you can execute logic both before and after the next() function is called. That means you could do something to intercept / modify the request and / or something to intercept / do something with the response.

Now you have to combine these together when executing:

public static void InvokeComposedAppFunc()
        {
            string response = null;

            SimplifiedAppFunc application = HelloWorld;
            
            // create the function log request. Inject the function Hello world application. 
            SimplifiedAppFunc appfunc = LogRequest(application);

            appfunc("helloworld.html", ref response);

            Console.WriteLine("composed appfunc response: " + response);
        }

When you invoke the logrequest midfunc, with another appfunc (helloworld) as a parameter, you get back a new appfunc. That appfunc is now again a mini webapplication that, when you invoke it, does logging AND returns a helloworld.

Now back to owin appfunc and midfunc

Now if you think about it like this, owin isn’t as scary anymore:

public static Task HelloWorld(Dictionary<string, object> environment)
        {
            string responseText = "Hello World";
            byte[] responseBytes = Encoding.UTF8.GetBytes(responseText);

            // See http://owin.org/spec/owin-1.0.0.html for standard environment keys.
            Stream responseStream = (Stream)environment["owin.ResponseBody"];
            IDictionary<string, string[]> responseHeaders =
                (IDictionary<string, string[]>)environment["owin.ResponseHeaders"];

            responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) };
            responseHeaders["Content-Type"] = new string[] { "text/plain" };

            return Task.Factory.FromAsync(responseStream.BeginWrite, responseStream.EndWrite, responseBytes, 0, responseBytes.Length, null);
            // 4.5: return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length);
        }

        public static AppFunc LogRequest(AppFunc next)
        {
            return async (env) =>
            {
                Logger.Log("received request", env["RequestUrl"]);
                await next(env);
                Logger.Log("completed request", env["RequestUrl"], env["StatusCode"]);
            };
        }

        public static async Task InvokeOwin()
        {
            AppFunc application = HelloWorld;
            MidFunc logRequest = LogRequest;

            AppFunc composedApp = logRequest(application);

            var environent = new Dictionary<string, object>()
            {

            };
            await composedApp(environent);
        }

 

But why not an interface?

Owin components can be built so that they depend ONLY on the .net framework and nothing else. This helps to maximize the pluggability of owin components. Because else, if your component depends on owin 1.0 and mine depends on owin 2.0, they can’t work together anymore.

But it looks so ugly.

That’s where AppBuilder, and OwinContext come to the rescue. You can use these classes (as an internal implementation detail) to make working with appfuncs and the environment dictionary a bit less scary.

Plenty of examples on how this would help:

// Note: By default all requests go through this OWIN pipeline. Alternatively you can turn this off by adding an appSetting owin:AutomaticAppStartup with value “false”. 
    // With this turned off you can still have OWIN apps listening on specific routes by adding routes in global.asax file using MapOwinPath or MapOwinRoute extensions on RouteTable.Routes
    public class Startup
    {
        // Invoked once at startup to configure your application.
        public void Configuration(IAppBuilder app)
        {
            app.Run(Invoke);
        }

        // Invoked once per request.
        public Task Invoke(IOwinContext context)
        {
            context.Response.ContentType = "text/plain";
            return context.Response.WriteAsync("Hello World");
        }
    }

Hope this helps understanding appfuncs and midfuncs a bit.

Happy funcing (without a k of course)

3 comments:

  1. Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a .Net developer learn from Dot Net Training in Chennai. or learn thru ASP.NET Essential Training Online . Nowadays Dot Net has tons of job opportunities on various vertical industry.

    ReplyDelete