Skip to content

Instantly share code, notes, and snippets.

@tugberkugurlu
Last active August 29, 2015 13:56
Show Gist options
  • Save tugberkugurlu/9054704 to your computer and use it in GitHub Desktop.
Save tugberkugurlu/9054704 to your computer and use it in GitHub Desktop.

I have an IFoo instance which I need to use as per request instance. Here is how my startup class look like:

public void Configuration(IAppBuilder app)
{
    HttpConfiguration config = new HttpConfiguration();
    config.Routes.MapHttpRoute("DefaultHttpRoute", "api/{controller}");

    app.Use<RandomTextMiddleware>()
       .UseWebApi(config);
}

RandomTextMiddleware is a pass-through middleware and I need an instance of IFoo implementation there. I also need an instance of IFoo implementation inside my Web API pipeline.

How would you solve this problem so that I have the same instance of IFoo implementation inside the RandomTextMiddleware and the Web API pipeline per HTTP request?

@tugberkugurlu
Copy link
Author

@panesofglass conserve resources. An HTTP request has a lifetime. It starts and goes through the pipeline I created and it ends at the end. If an instance can be used throughout the whole pipeline for that individual request, why on earth must I need to create different instances of that object? It's just a waste.

@tugberkugurlu
Copy link
Author

@darrelmiller

Consider for a moment that you want to add a piece of caching middleware. If your request/response pipeline is using state that is not part of the HTTP message then chances are the caching middleware is not going to cache that additional state. When a request comes in and gets a cache hit, the response will be missing the additional state.

Why should that effect the state? Assume that RandomTextMiddleware is my caching middleware and inside that middleware I need to go to my ETagStore (redis, mongodb, etc.) to check the ETag. Shouldn't I have a way of resolving that dependency? Should my middleware have a deep knowladge of creating that store instance? I don't think so.

@darrelmiller
Copy link

Just one other thing. Consider the TRACE HTTP method. The point of the HTTP trace method is to allow you to send a request to an origin server and instead of the origin server processing the request, it returns the request as a message/http response so that you can see exactly what the middleware did to the request before it reached the origin server. This is an amazing debugging tool that is terribly underused. If you allow middleware and applications to act on state that is not part of the HTTP message then the value of TRACE is lost.

@panesofglass
Copy link

Katana offers several points where you can register and re-use components: IAppBuilder.Properties and environment dictionary. Like Darrel, I disagree that leveraging those is always a good idea. If you are writing a middleware for your specific application, then knock yourself out. If you are trying to write a middleware that works for anyone in any application, then you won't be able to depend on this re-use.

I'll always go back to the original purpose of OWIN: separate app framework from server. ASP.NET WebForms and MVC violate this, which makes them difficult to host elsewhere. Web API, Nancy, etc. all do this very well. Middleware are unspecified in the OWIN spec, but since frameworks all work differently, I don't know how you could expect a middleware to use a specific mechanism or instance and be re-usable.

@panesofglass
Copy link

Also, I don't know of a library/framework agnostic dependency injection mechanism. So if you use Autofac in your middleware but I use StructureMap in my app that uses your middleware, then I have yet another dependency issue. Your middleware just created another problem for my app.

@beyond-code-github
Copy link

If we keep OWIN clean in this way, then I believe there is a need for an 'interoperable pipeline' that can provide the ability for adding middleware-like components that work within the context of an app, but independantly of framework. This is something that Superscribe aims to provide.

@tugberkugurlu
Copy link
Author

@panesofglass

I don't know how you could expect a middleware to use a specific mechanism or instance and be re-usable.

Here is an example: OAuthAuthorizationServerMiddleware (UseOAuthAuthorizationServer).

ILogger logger = app.CreateLogger<MyOAuthAuthorizationServerProvider>();
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions 
{
    TokenEndpointPath = new PathString("/token"),
    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(10),
    Provider = new MyOAuthAuthorizationServerProvider(logger)
});

Here is my provider:

public class MyOAuthAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    private const string ClientContextKey = "my:oauth:client";
    private readonly ILogger _logger;

    public MyOAuthAuthorizationServerProvider(ILogger logger)
    {
        _logger = logger;
    }

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        string clientId;
        string clientSecret;

        if (context.TryGetBasicCredentials(out clientId, out clientSecret))
        {
            IServiceProvider requestContainer = context.OwinContext.Environment.GetRequestContainer();
            IClientManager clientManager = requestContainer.GetService<IClientManager>();
            Client client = await clientManager.GetVerfiedClientAsync(clientId, clientSecret);

            if (client != null)
            {
                context.OwinContext.Set<Client>(ClientContextKey, client);
                context.Validated(clientId);
                return;
            }
        }

        context.Rejected();
    }

    // ...
}

Noticed requestContainer.GetService<IClientManager>()? OAuthAuthorizationServerMiddleware is still reusable and I'm able to use my DI implementation on top of OWIN environment, w/o any coupling at all.

@tugberkugurlu
Copy link
Author

@panesofglass

Also, I don't know of a library/framework agnostic dependency injection mechanism. So if you use Autofac in your middleware but I use StructureMap in my app that uses your middleware, then I have yet another dependency issue. Your middleware just created another problem for my app.

Again, you won't be tied to a specific IoC container, we will just bound to IServiceProvider. Please review the following readme file and the source code: https://github.com/DotNetDoodle/DotNetDoodle.Owin.Dependencies#readme

I guess there is a misunderstanding between what I wanted to do and what I expressed.

@darrelmiller
Copy link

The HTTP request has a much longer lifetime than the time it spends in your Owin pipeline. The HTTP Request is created by the client, it passes through the local client proxy cache, it goes through corporate proxies, through your ISPs public caching infrastructure, through your reverse proxy. Owin middleware is just another intermediary in that huge pipeline that extends from client to origin server. It just happens to run in the same process as your application. The fact that you can share state between owin middleware doesn't mean you should.

Maybe tomorrow, you will need to load balance your application servers and it makes more sense to run that piece of middleware on the reverse proxy rather than running an instance on each app server. If you have coupling between your middleware, that is going to make it harder to move.

@darrelmiller
Copy link

Why not just inject IClientManager into the MyOAuthAuthorizationServerProvider constructor at application startup time?

@tugberkugurlu
Copy link
Author

Why not just inject IClientManager into the MyOAuthAuthorizationServerProvider constructor at application startup time?

Simple, it's not thread safe. It should be constructed per each request.

@tugberkugurlu
Copy link
Author

@yreynhout
Copy link

Factory, anyone?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment