seesharper / LightInject

An ultra lightweight IoC container
http://www.lightinject.net
MIT License
618 stars 121 forks source link

OWIN support #90

Closed iremezoff closed 9 years ago

iremezoff commented 10 years ago

Hello again! Please, talk me about OWIN support in Lightinject: how can I get OwinRequest per every request because there is no HttpContext since app don't have to be on IIS. Currently I don't have through request storage for IOwinRequest/HttpRequestMessage. I saw your code into OWIN initial commit but it is alternative for LightInjectHttpModule from WebAPI integration. First thought is creating subcontainer per scope and register Func or Lazy component but I afraid it may be expensive operation per request

seesharper commented 10 years ago

Actually you don't need to do anything to make this work as Web API handles scoping for us. I have however, updated the Web API documentation to show how to set up a self hosted Web API using LightInject.

http://www.lightinject.net/#webapi

Best regards

Bernhard Richter

iremezoff commented 10 years ago

I'v seen that link but how can I get essential object of request per scope? Early I could use HttpContext but now I can't get that object on components except controllers and filters. It seems similar question were here https://github.com/seesharper/LightInject/issues/83. If it isn't responsibility of IoC let me know and I will be digging further. Thanks!

seesharper commented 10 years ago

I probably don't understand what you are trying to do here. Is is that you need a place to store arbitrary values per request or is it that you need access to the the HttpActionContext from within controllers?

Best regards Bernhard Richter

iremezoff commented 10 years ago

I need the second variant. I want to have access to HttpRequestMessage (from HttpActionContext) in my PerScope registered components from container

seesharper commented 10 years ago

Now I finally understand :) I will look into it

Best regards Bernhard Richter

seesharper commented 10 years ago

I have updated the documentation with information about how to achieve what you need.

http://www.lightinject.net/#webapi

Best regards Bernhard Richter

iremezoff commented 10 years ago

Thanks a lot! Excellent solution!

iremezoff commented 10 years ago

Bernhard, I'v tried your solution and gotten error when I was trying to get PerScope-component (line 66). Code is in gist: https://gist.github.com/iremezoff/a941adf5a4c9fa56609b Have any idea? Thanks!

ps: used packages: microsoft.owin.security.oauth, microsoft.owin.host.systemweb, microsoft.owi.security and so on.

seesharper commented 10 years ago

Could you provide the exception and the stack trace ?

On Tuesday, July 8, 2014, iremezoff notifications@github.com wrote:

Bernhard, I'v tried your solution and gotten error when I was trying to get PerScope-component. Code is in gist: https://gist.github.com/iremezoff/a941adf5a4c9fa56609b Have any idea? Thanks!

— Reply to this email directly or view it on GitHub https://github.com/seesharper/LightInject/issues/90#issuecomment-48326561 .

iremezoff commented 10 years ago

Yes, sure! Exception: InvalidOperationException

Message: Attempt to create a scoped instance without a current scope.

Stack: at LightInject.PerScopeLifetime.GetInstance(Func`1 createInstance, Scope scope) in c:\Users\bri\Documents\GitHub\LightInject\NuGet\Build\Net45\LightInject\LightInject.cs:line 4654 at DynamicMethod(Object[] ) at LightInject.ServiceContainer.GetInstance(Type serviceType) in c:\Users\bri\Documents\GitHub\LightInject\NuGet\Build\Net45\LightInject\LightInject.cs:line 2350 at LightInject.ServiceContainer.GetInstance[TService]() in c:\Users\bri\Documents\GitHub\LightInject\NuGet\Build\Net45\LightInject\LightInject.cs:line 2400 at DynamicMethod(IServiceFactory ) at OWINDemo.Provier.GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) in c:\Users\remezovis\Documents\Visual Studio 2012\Projects\OWINDemo\OwinDemoWeb\Startup.cs:line 66 at Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerHandler.d__3a.MoveNext()

seesharper commented 10 years ago

Okay, and what do I do to make it fail. What is the url I need to access once I get this up and running?

On Tue, Jul 8, 2014 at 2:30 PM, iremezoff notifications@github.com wrote:

Yes, sure! Exception: InvalidOperationException

Message: Attempt to create a scoped instance without a current scope.

Stack: at LightInject.PerScopeLifetime.GetInstance(Func`1 createInstance, Scope scope) in c:\Users\bri\Documents\GitHub\LightInject\NuGet\Build\Net45\LightInject\LightInject.cs:line 4654 at DynamicMethod(Object[] ) at LightInject.ServiceContainer.GetInstance(Type serviceType) in c:\Users\bri\Documents\GitHub\LightInject\NuGet\Build\Net45\LightInject\LightInject.cs:line 2350 at LightInject.ServiceContainer.GetInstanceTService in c:\Users\bri\Documents\GitHub\LightInject\NuGet\Build\Net45\LightInject\LightInject.cs:line 2400 at DynamicMethod(IServiceFactory ) at OWINDemo.Provier.GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) in c:\Users\remezovis\Documents\Visual Studio 2012\Projects\OWINDemo\OwinDemoWeb\Startup.cs:line 66 at Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerHandler.d__3a.MoveNext()

— Reply to this email directly or view it on GitHub https://github.com/seesharper/LightInject/issues/90#issuecomment-48329482 .

iremezoff commented 10 years ago

post http://localhost:/token on IIS Express or http://localhost:/token on "Big" IIS Body should be follow: grant_type=password

seesharper commented 10 years ago

Now we are talking about dependency injection in OWIN middleware components which is quite a different story that we started out with. Or at least what I understood from it :)

The problem here is that this sort of happens prior to the scope being created by Web API so that is why LightInject complains about a missing scope.

You can take a look here and see how AutoFac has implemented a workaround for this.

http://alexmg.com/owin-support-for-the-web-api-2-and-mvc-5-integrations-in-autofac/

As the game is about to change for the whole ASP.Net stack with ASP.vNext, this is something I was hoping to avoid as it adds a great deal of complexity to the framework.

ASP.vNext adds dependency injection for the whole stack, WebAPI, Mvc and SignalR in such a way that we can rely on a single abstraction of the container.

You could propably do something like this

internal class LightInjectMiddleware : OwinMiddleware
{
    private readonly IServiceContainer container;

    public LightInjectMiddleware(OwinMiddleware next, IServiceContainer container)
        : base(next)
    {
        this.container = container;
    }

    public async override Task Invoke(IOwinContext context)
    {
        using (container.BeginScope())
        {                
            await Next.Invoke(context);
        }
    }
}

internal static class LightInjectOwinExtensions
{
    public static void UseLightInject(this IAppBuilder appBuilder, IServiceContainer container)
    {
        appBuilder.Use<LightInjectMiddleware>(container);
    }
}

public void Configuration(IAppBuilder app) { var config = new HttpConfiguration();

        var container = new ServiceContainer();
        container.ScopeManagerProvider = new PerLogicalCallContextScopeManagerProvider();
        container.Register<IFoo, Foo>(new PerScopeLifetime());
        container.EnableWebApi(config);
        container.RegisterApiControllers();
        app.UseLightInject(container);
        app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
        {
            // for demo purposes
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromHours(8),
            Provider = new Provier(
                config.DependencyResolver.GetService(typeof(Func<IFoo>)) as Func<IFoo>)
        });

        // token consumption
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

        app.UseWebApi(config);
    }

This would ensure that a scope is started, but Web API will probably start a new scope for the controllers and hence create a nested scope.

Before going down this path I think it would be wise to consider how important DI is in regard to middleware components.

Best regards

Bernhard Richter

On Tue, Jul 8, 2014 at 3:11 PM, iremezoff notifications@github.com wrote:

post http://localhost:/token on IIS Express or http://localhost:/token on "Big" IIS Body should be follow: grant_type=password

— Reply to this email directly or view it on GitHub https://github.com/seesharper/LightInject/issues/90#issuecomment-48333416 .

iremezoff commented 10 years ago

Have I understood right that it is worth waiting for in vNext only? ) Regardless, thank you very much for help and detailed answer! It works now with your simple middleware!

iremezoff commented 10 years ago

Bernhard, hello!

I have new problem with OWIN hosting and PerLogicalCallContextScopeManagerProvider. I don't use async/await, but using framework version is 4.5. And periodically (the more load the more often) I get follow exception: Message: Attempt to create a scoped instance without a current scope.;

This exception is thrown in the end of handling of http request.

Have any idea? What additional info do I have to leave else?

seesharper commented 10 years ago

This is probably related to this https://github.com/seesharper/LightInject/issues/97

I will take a look at it and create a new version of LightInject.WebApi

Best regards

Bernhard Richter

On Wed, Aug 6, 2014 at 8:28 AM, iremezoff notifications@github.com wrote:

Bernhard, hello!

I have new problem with OWIN hosting and PerLogicalCallContextScopeManagerProvider. I don't use async/await, but using framework version is 4.5. And periodically (the more load the more often) I throw follow exception: Message: Attempt to create a scoped instance without a current scope.;

This exception is thrown in the end of handling of http request.

Have any idea? What additional info do I have to leave else?

— Reply to this email directly or view it on GitHub https://github.com/seesharper/LightInject/issues/90#issuecomment-51298295 .