4
votes

I have a simple question regarding the OWIN pipeline. I pretty much understand the whole concept of this specification, but there is something that i haven't totally digested.

According to several online posts, there is the OWIN pipeline which consist of several developer-defined modules (or middleware components) and which is constucted by the owin Host. Then there is the server which will listen to requests and pass them over = through the pipeline of OWIN components.

The point that i don't totally understand is why do we need to have a pipeline. So for example, lets imagine that in thes StartUp class we have something like:

public class Startup
{
   public void Configuration(IAppBuilder app)
   {
      app.Use<CustomMiddleware>(new CustomComponent());
      var config = new HubConfiguration { EnableCrossDomain = true };
      app.MapHubs(config);
      string exeFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
      string webFolder = Path.Combine(exeFolder, "Web");
      app.UseStaticFiles(webFolder);
   }
}

In the above example we ask the OWIN Host to construct a pipeline of three OWIN middleware components. From what i understand, the server will forward the request (probably wrapped in a Dictionary) to the first component in that pipeline, which in turn will do some task and pass it over to the next component and so forth.

I wonder why would we need to get all the components involved in each request; For example, if we ask for a static html page only, why not only bother the component that deals with static files; i mean why such a request need the participation of the Web Api for example.

3
The way OWIN is used by Katana is a single long pipeline of middleware, with each middleware examining the request and deciding whether to handle it or pass it on to the next middleware. Middleware can also pass it to the next middleware in the pipe and do something else afterwards. This can be inefficient if you have lots of middleware, and every middleware needs to know which requests to process. There is also an OWIN Framework NuGet that addresses these issues. - bikeman868

3 Answers

3
votes

I think i've cleared that out. It turns out that the request doesn't have to move through the whole pipeline. It is the responsibility of each component in the pipeline to decide if they can deal with the request or if they want to forward it to the next node;

2
votes

You are correct in your answer that middlewares may opt out of handling the request. Many Katana middleware implementations favor a "soft 404" approach in which the middleware will interpret a 404 to mean "try the next middleware". The first middleware to complete the Task will halt further propagation and complete the response message. You can optimize the path by inserting middlewares in the most likely order for performance or common use.

1
votes

The middleware component are executed in order, and it usually makes sense to run through all the components in the pipeline, until one of them decides to cut the pipeline by not calling the next one.

This is possible because each middleware component has a reference to the next one, and the environment, a dictionary of objects, whose key is a string, who gives acces to all the necessary things to check the request, create the response, and do many other things. (using a dictionary is clever, because it's easy to add any kind of information, or executable code, which isn't known beforehand).

Each component can do the following things, but all of them are optional:

  • execute code before calling the next component (usually checking and modifying the environment dictionary)
  • call the next middleware component of the pipeline (which will do the same)
  • execute some code after the next component finishes executing
  • throw an exception (intentionally or because of un unhandled error)

The pipeline execution will finish on one of this cases:

  • a middleware component doesn't call the next one
  • a middleware component throws an exception

NOTE: each "Middleware component" is an implementation of the Application Delegate

Having a bunch of components makes sense, if they're are registered in the right order. A pipeline could look something like this:

  • authentication
  • authorization
  • caching
  • execution of some kind of API or HTML generation

Each component has enough information to execute the code its responsible for. For example:

  • authentication will alwasy be executed, and set in the dictionay the information of the principal. Then it will cal lthe next one: authorization component
  • depending on the request, and the result of the authenticacion, the authorization component will decide if the principal has permissions for executing the request, and call the next component (caching), or reject the request
  • the caching can also decide if it can return cached results, or has to call the next component
  • the last component will execute, and will probably create the response, and it will not call any other component. The call stack will be run in reverse order, giving each component the possibility to do some estra work. For example the caching component could cache the response, and the next ones (authorization and authentication) will simply return without executing any extra code.

As each component has all the request, response, context and any other desired information, they all have enough information to decide if they have to do something, modify the dictonay, cal lthe next one or retunr...

So, as you can see, registering a lot of middleware components doesn't require all them to be executed for each request, but it sometimes make sense.

OTOH executing a middleware component can be really cheap. For example, authentication could simply execute the next component if the request doesn't require authorization. And the same with the cahing component, which could simply call the next component if caching is not reuired.

So even if a component it's in the pipeline it can have a cheap execution, or it can even not run at all depending on the request.

In your particular question of static files, and Web API, one of the components will be resgitered before the other. The first one, whichever is, will execute and create the response, or simply call the next one, depending on the request. E.g. if the static files is registered before the other one, if a file is requested the static file will create the response, and will not call the Web API. If the request isn't for a file, it will do nothing but calling the next componente: the Web API component.