4

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.

ppoliani
  • 4,792
  • 3
  • 34
  • 62
  • 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 Jan 15 '17 at 06:37

3 Answers3

3

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;

ppoliani
  • 4,792
  • 3
  • 34
  • 62
2

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.

panesofglass
  • 267
  • 3
  • 10
  • This is totally wrong, each middleware component can decide to call the next component on the pipeline or return without calling it. The only way to stop the chain is this one, or throwing an exception. If a middleware component retunrs a 404 and doesn't call the next component in the chain, the pipeline will finish it execution. By the way, the middleware is executed before and after the call to the next component in the pipeline. – JotaBe Mar 14 '15 at 17:11
  • 1
    @JotaBe, this is not "totally wrong." You described the pattern of pure OWIN, but Katana, which I pointedly called out above, does in fact use the concept of "soft 404s" in their libraries. For one example in Web API, see http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http.Owin/HttpMessageHandlerAdapter.cs and look for `IsSoftNotFound`. It's true this is a pattern and not part of OWIN. – panesofglass Mar 16 '15 at 15:33
  • Please, see the code of Katana project at http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin/OwinMiddleware.cs I don't know if you'll be able to find that pattern in any of the many OWIN middleware components in the project. To strat with you can see the abstract `OwinMiddleware` class, and any of its implementaions: no cue of `IsSoftNotFound` or something similar there. You are looking of a very particular implementation, not the general Katana middleware component. – JotaBe Mar 16 '15 at 20:53
  • You are correct again. I've updated my answer to reflect my intended meaning more accurately. – panesofglass Mar 17 '15 at 22:41
1

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.

JotaBe
  • 38,030
  • 8
  • 98
  • 117
  • Middleware components are not implementations of Application Delegates. They are intended to be chainable wrappers around an Application Delegate that, when applied, produce a new Application Delegate. using Env = IDictionary; using AppFunc = Func; using MidFunc = Func; – panesofglass Mar 16 '15 at 15:36
  • Please, don't read it so literally. See the abstract implementation of OWIN middleware int the link in my comment to your answer. That's an OWIN component. The pattern is a constructor that receive a reference to the next middleware component, and an `Invoke` method that implements the `AppFunc` delegate. That'sthe base abstrac `OwinMiddleware` class from wihi most Katana OWIN middleware directly inherit. – JotaBe Mar 16 '15 at 21:01
  • "Component" is not part of the OWIN terminology. I think you mean middleware, and there, you are correct. (To be fair, we are still working out the details of the middleware spec, which you can find [here](https://github.com/openrasta/owin.spec/blob/master/spec/middleware-1.0.0-draft.1.md).) – panesofglass Mar 17 '15 at 22:43
  • I've not created the term "OWIN middleware component". If you google for it you'll see this term, or its acronym OMC, in quite a lot of places. By the way, you're not a lawyer, are you? ;) I agree to use terms correctly, but not in such an sctrict way. Andm, lo and behold, the Abstract of the middleware spec document linked in your answer ends with these words: "resuable OWIN middleware *components*" – JotaBe Mar 18 '15 at 09:22
  • Interesting. I missed that piece in the middleware spec. Nice catch. :) And no, I'm not a lawyer. – panesofglass Mar 18 '15 at 21:05