Monday, January 5, 2015

OWIN middleware!

As mentioned, I've followed Scott Allen's pluralsight.com MVC5 trainings to build a .NET Framework 4.5.1 OWIN-flavored console application like so:

using System;
using Microsoft.Owin.Hosting;
namespace MyKatana
{
   class Program
   {
      static void Main(string[] args)
      {
         string uri = "http://localhost:8080";
         using (WebApp.Start<Startup>(uri))
         {
            Console.WriteLine("Started!");
            Console.ReadKey();
            Console.WriteLine("Stopping!");
         }
      }
   }
}

 
 

Also, as mentioned here, there is a Startup class in the mix. Recently, I altered it (from what is at the link I provide) as seen here:

using MyKatana.Middleware;
using Owin;
namespace MyKatana
{
   public class Startup
   {
      public void Configuration(IAppBuilder app)
      {
         app.Use<HelloWorldComponent>();
      }
   }
}

 
 

I did this to bring in a component, a piece of middleware that is! In Mr. Allen's video he first builds a piece of middleware like so to show off a common shape:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MyKatana.Middleware
{
   public class HelloWorldComponent
   {
      private Func<IDictionary<string, object>, Task> _next;
      
      public HelloWorldComponent(Func<IDictionary<string, object>, Task> next)
      {
         _next = next;
      }
      
      public async Task Invoke(IDictionary<string, object> environment)
      {
         await _next(environment);
      }
   }
}

 
 

A Func<IDictionary<string, object>, Task> must be taken at the constructor of a componet for it to behave well (or at all really) in the OWIN context, and thus there is a need to write a custom constructor with the signature seen here for each component. We also need an Invoke method. It is important to note that using the await keyword in lieu of a return requires one to also use the async keyword. Mr. Allen suggested that the await/async shape to the Invoke method is the norm. It is not however mandatory, as he went on to refactor what is above to what is below.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace MyKatana.Middleware
{
   public class HelloWorldComponent
   {
      private Func<IDictionary<string, object>, Task> _next;
      
      public HelloWorldComponent(Func<IDictionary<string, object>, Task> next)
      {
         _next = next;
      }
      
      public Task Invoke(IDictionary<string, object> environment)
      {
         Stream response = environment["owin.ResponseBody"] as Stream;
         using (StreamWriter writer = new StreamWriter(response))
         {
            return writer.WriteAsync("Hello World!");
         }
      }
   }
}

 
 

We take off async in taking off await! Alright, clearly this piece is intended to the very last in a sequence of steps while the prior shape (which did nothing) was more friendly to being somewhere upstream of a last step. How can we use both shapes and still write a line of copy to the browser?

using MyKatana.Middleware;
using Owin;
namespace MyKatana
{
   public class Startup
   {
      public void Configuration(IAppBuilder app)
      {
         app.Use<HelloComponent>().Use<WorldComponent>();
      }
   }
}

 
 

We will run the HelloComponent before the WorldComponent and it looks like so:

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace MyKatana.Middleware
{
   public class HelloComponent
   {
      private Func<IDictionary<string, object>, Task> _next;
      
      public HelloComponent(Func<IDictionary<string, object>, Task> next)
      {
         _next = next;
      }
      
      public async Task Invoke(IDictionary<string, object> environment)
      {
         Stream response = environment["owin.ResponseBody"] as Stream;
         using (StreamWriter writer = new StreamWriter(response))
         {
            writer.Write("Hello: ");
         }
         await _next(environment);
      }
   }
}

 
 

environment["owin.ResponseBody"] = response; ...was just before the last line of code above is my first pass at this. It turns out I didn't need it after after given that I am altering a reference type however. WorldComponent is just a mild revamp of HelloWorldComponent. It looks like this:

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace MyKatana.Middleware
{
   public class WorldComponent
   {
      private Func<IDictionary<string, object>, Task> _next;
      
      public WorldComponent(Func<IDictionary<string, object>, Task> next)
      {
         _next = next;
      }
      
      public Task Invoke(IDictionary<string, object> environment)
      {
         Stream response = environment["owin.ResponseBody"] as Stream;
         using (StreamWriter writer = new StreamWriter(response))
         {
            return writer.WriteAsync("World!!!");
         }
      }
   }
}

 
 

After I did this, I turned around and mused that HelloComponent didn't really need to interface with owin.ResponseBody the way the last step in the chain (WorldComponent) must. I ended up refactoring it like so:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MyKatana.Middleware
{
   public class HelloComponent
   {
      private Func<IDictionary<string, object>, Task> _next;
      
      public HelloComponent(Func<IDictionary<string, object>, Task> next)
      {
         _next = next;
      }
      
      public async Task Invoke(IDictionary<string, object> environment)
      {
         environment["htmlspool"] = "Hello: ";
         await _next(environment);
      }
   }
}

 
 

This makes WorldComponent change up to accomodate.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace MyKatana.Middleware
{
   public class WorldComponent
   {
      private Func<IDictionary<string, object>, Task> _next;
      
      public WorldComponent(Func<IDictionary<string, object>, Task> next)
      {
         _next = next;
      }
      
      public Task Invoke(IDictionary<string, object> environment)
      {
         string htmlspool = environment["htmlspool"] as String;
         Stream response = environment["owin.ResponseBody"] as Stream;
         using (StreamWriter writer = new StreamWriter(response))
         {
            return writer.WriteAsync(htmlspool + "World!!!");
         }
      }
   }
}

 
 

Another part of Mr. Allen's training involves making an AppFunc using statement not unlike a using directive. Here is what one of those looks like:

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace MyKatana.Middleware
{
   using AppFunc = Func<IDictionary<string, object>, Task>;
   
   public class WorldComponent
   {
      AppFunc _next;
      
      public WorldComponent(AppFunc next)
      {
         _next = next;
      }
      
      public Task Invoke(IDictionary<string, object> environment)
      {
         string htmlspool = environment["htmlspool"] as String;
         Stream response = environment["owin.ResponseBody"] as Stream;
         using (StreamWriter writer = new StreamWriter(response))
         {
            return writer.WriteAsync(htmlspool + "World!!!");
         }
      }
   }
}

 
 

At the very end I decided to fall back to using a .Run instead of a .Use to implement the last step in my process. I did so like this:

using MyKatana.Middleware;
using Owin;
namespace MyKatana
{
   public class Startup
   {
      public void Configuration(IAppBuilder app)
      {
         app.Use<HelloComponent>().Run(environment =>
         {
            return environment.Response.WriteAsync("World!!!");
         });
      }
   }
}

 
 

That meant that it now made sense to revert the HelloComponent class to its initial shape:

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace MyKatana.Middleware
{
   public class HelloComponent
   {
      private Func<IDictionary<string, object>, Task> _next;
      
      public HelloComponent(Func<IDictionary<string, object>, Task> next)
      {
         _next = next;
      }
      
      public async Task Invoke(IDictionary<string, object> environment)
      {
         Stream response = environment["owin.ResponseBody"] as Stream;
         using (StreamWriter writer = new StreamWriter(response))
         {
            writer.Write("Hello: ");
         }
         await _next(environment);
      }
   }
}

 
 

install-package Microsoft.AspNet.WebApi.OwinSelfHost ...may be run to bring in the Web API! I added it in a new a step in my component chain like so:

using System.Web.Http;
using MyKatana.Middleware;
using Owin;
namespace MyKatana
{
   public class Startup
   {
      public void Configuration(IAppBuilder app)
      {
         HttpConfiguration config = new HttpConfiguration();
         config.Routes.MapHttpRoute(
            "MyRoutingRule",
            "api/{controller}/{id}",
            new {id = RouteParameter.Optional});
         app.UseWebApi(config).Use<HelloComponent>().Run(environment =>
         {
            return environment.Response.WriteAsync("World!!!");
         });
      }
   }
}

 
 

Now the app will continue to just serve up "Hello: World!!!" unless a legitimate ApiController route is hit at which point behavior differs! http://localhost:8080/api/whatever/ is such a route thanks to this controller:

using System;
using System.Web.Http;
using MyKatana.Objects;
namespace MyKatana.Controllers
{
   public class WhateverController : ApiController
   {
      public Whatever Get()
      {
         return new Whatever()
         {
            MeaningOfEverything = 42
         };
      }
   }
}

 
 

It will cough up an instance of this object:

namespace MyKatana.Objects
{
   public class Whatever
   {
      public int MeaningOfEverything { get; set; }
   }
}

No comments:

Post a Comment