Code Monkey home page Code Monkey logo

autofac.owin's Introduction

Autofac character Autofac logo

Autofac is an IoC container for Microsoft .NET. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity. This is achieved by treating regular .NET classes as components.

Build status codecov NuGet

Autofac on Stack Overflow Join the chat at https://gitter.im/autofac/autofac

Get Packages

You can get Autofac by grabbing the latest NuGet package. There are several application integration and extended functionality packages to choose from. If you're feeling adventurous, continuous integration builds are on MyGet.

Release notes are available on GitHub.

Get Help

Need help with Autofac? We have a documentation site as well as API documentation. We're ready to answer your questions on Stack Overflow or check out the discussion forum.

Get Started

Our Getting Started tutorial walks you through integrating Autofac with a simple application and gives you some starting points for learning more.

Super-duper quick start:

Register components with a ContainerBuilder and then build the component container.

var builder = new ContainerBuilder();

builder.Register(c => new TaskController(c.Resolve<ITaskRepository>()));
builder.RegisterType<TaskController>();
builder.RegisterInstance(new TaskController());
builder.RegisterAssemblyTypes(controllerAssembly);

var container = builder.Build();

Resolve services from a lifetime scope - either the container or a nested scope:

var taskController = container.Resolve<TaskController>();

There is a growing number of application integration libraries that make using Autofac with your application a snap. Support for several popular frameworks is also available through the "Extras" packages.

Intrigued? Check out our Getting Started walkthrough!

Project

Autofac is licensed under the MIT license, so you can comfortably use it in commercial applications (we still love contributions though).

File issues in the repo with the associated feature/code.

Sponsors

Autofac is supported by AWS. Thanks for your contribution!

Contributing / Pull Requests

Refer to the Contributor Guide for setting up and building Autofac source.

You can also open this repository right now in VS Code.

autofac.owin's People

Contributors

alexmg avatar alistairjevans avatar alsami avatar pengweiqhca avatar shiftkey avatar srogovtsev avatar tillig avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

autofac.owin's Issues

Is the dispose of the lifetime made too soon?

I'm trying to access the AutofacLifetimeScope inside the context.Response.OnSendingHeaders event.
This event may only run a bit late on the request execution, but shouldn't it be considered still request execution?

A bit of context:
Microsoft.Owin.Security.OAuth only calls the Create providers of the codes and tokens during this event. As of now, my only solution is to create transient services and pass delegates to create the service instances on those providers so I can save the tokens and codes.

Anyway, I'm trying to change that in order to use the "normal" context per request so I don't have to open up multiple connections.

Here's an example of an owin middleware with the issue replication:

public class SimpleMiddleware : OwinMiddleware
{
    private static readonly PathString Path = new PathString("/test");

    public SimpleMiddleware(OwinMiddleware next) : base(next)
    {
    }

    public async override Task Invoke(IOwinContext context)
    {
        if (!context.Request.Path.Equals(Path))
        {
            await Next.Invoke(context);
            return;
        }

        context.Response.OnSendingHeaders(o =>
        {
            //scope here is already disposed
            var scopeOnHeaders = context.GetAutofacLifetimeScope();
            var serviceOnHeaders = scopeOnHeaders.Resolve<PluggableComponent>();
            context.Response.Headers.Add("Echo", new[] { serviceOnHeaders.Echo() });
        }, this);

        //scope here is fine
        var scope = context.GetAutofacLifetimeScope();
        var service = scope.Resolve<PluggableComponent>();

        var responseData = new { Date = DateTime.Now, Echo = service.Echo() };

        context.Response.StatusCode = (int)HttpStatusCode.OK;
        context.Response.ContentType = "application/json";
        context.Response.Write(JsonConvert.SerializeObject(responseData));
    }

}

Memory Leak Due to ThreadLocalStorage / ConcurrentBag / LifetimeScope Behavior in Owin

Bug Description

I would love to give a concise description of exactly what this bug is, but I don't fully understand it myself so I will instead try to explain as much of what I know about the issue and hope someone can fill in the gaps.

A web application using the Owin integration has memory leaks if it is under consistent stress which does not allow the request processing threads to exit.

LifetimeScopes are created for each request and are disposed properly when the request ends, but the LifetimeScope references are maintained and as a result garbage collection never cleans up the LifetimeScopes.

Here's a sample reference tree for one such LifetimeScope:
image

Rough outline of what happens to cause this issue:

  • Autofac.Owin creates a LifetimeScope in the Owin pipeline and registers the OwinContext as an IOwinContext in this LifetimeScope. This OwinContext has an Environment key which tracks the LifetimeScope (something like "autofac:OwinLifetimeScope:")
  • The ComponentRegistration for this OwinContext is somehow tracked in a ConcurrentBag, which apparently uses ThreadLocal as some kind of backing store
  • The ThreadLocals have a strong GC handle tracking them, so they do not get cleaned up by the GC unless the thread exits. This does not happen if the web application is consistently busy.
  • Since the ThreadLocals don't get GC'ed, neither does the ComponentRegistration, the ComponentRegistrations references the OwinContext, the OwinContext references the LifetimeScope, and the LifetimeScope never gets garbage collected.

I believe the ConcurrentBag which tracks the ComponentRegistrations is coming from somewhere within the Autofac 6.0 pipeline but I am not sure where.

Steps to Reproduce

I have attached a sample application (see below), this is just a simple Web API .NET Framework application to which I added the Owin pipeline and Autofac Owin integration.

To reproduce, just spam the application (using F5 in a browser works for me) and then take a memory dump. Don't wait too long between spamming and taking the dump or the threads will exit and the GC will clean up the ThreadLocal stuff and eventually clear out the LifetimeScopes. Inside of the memory dump, search for all instances of LifetimeScope and see that there are many hanging around and are all rooted in ConcurrentBags / ThreadLocals.

If you consistently ping the sample site for an extended period of time, you will see the number of LifetimeScopes in the memory dump continue to grow.

Expected Behavior

Under high load, the LifetimeScopes which are created by the Autofac.Owin integration should be cleaned up and released for garbage collection when the request ends.

Dependency Versions

Autofac 6.0
Autofac.Owin 6.0

Additional Info

I was able to work around this problem by specifically removing the OwinContext.Environment key "autofac:OwinLifetimeScope:" which removes the reference to the LifetimeScope and allows it to be garbage collected. This smells like a hack to me.
This can be found in NonAutofacMiddleware.cs inside of the sample application.

Sample Application

MemoryLeakSample.zip

If you want to see the results in memory from running requests for an extended amount of time, I wrote a small console app to just repeatedly ping the site:

static void Main(string[] args)
{
    var address = "https://localhost:44387/";
    while (true)
    {
        Console.WriteLine($"Pinging {address} at {DateTime.Now}");
        var client = new HttpClient();
        var response = client.GetAsync(address).ConfigureAwait(false).GetAwaiter().GetResult();
        response.EnsureSuccessStatusCode();

        Thread.Sleep(300);
    }
}

Include the latest stable version of Microsoft.Owin (4.0.0) in dependencies

Hello!

Microsoft have just released an update of all Microsoft.Owin.* NuGet packages from 4.0.0-preview1 to 4.0.0 stable. But I can't update update to stable due to Autofac dependency (Microsoft.Owin < 4.0.0, so strictly less).

My app works fine with a current Autofac.Owin package and a preview from Microsoft, and from what I've seen they didn't introduce breaking changes in 4.0.0, so please consider validating and including 4.0.0 stable in your NuGet package dependencies.

Thanks.

OwinLifetimeScopeKey configurable

Is there any way we can make the OwinLifetimeScopeKey configurable and/or allow for some sort of prefix?

We have a scenario where 2 different copies of Autofac are being used in the same OWIN pipeline. Given that they're using the same key for storing per-request data in the OWIN environment then we get cross-over behavior and undesirable results. Obviously the MiddlewareRegisteredKey would also be affected by this.

I can provide more contextual information if desired. Thanks.

Allow DI for IAppBuilder.Run

Now, after we got rid of one unpleasantry, let's move to another one.

Terminal call.

app
  .UseBasicAuthentication()
  .Use(AuthenticatedOnly)
  .Run(container.Resolve<Uploader>().InvokeAsync);

I want to be able to specify end-of-pipeline delegate (unfortunately, only delegates are allowed) without explicitly resolving the dependencies needed inside.

Option 1

app.Run<Uploader>((uploader, owinContext) => uploader.InvokeAsync(owinContext));

Which should be more or less equivalent to

app.Run(owinContext =>
  owinContext.GetAutofacLifetimeScope().Resolve<Uploader>().InvokeAsync(owinContext)
  );

Option 2

Task UploadAsync(IOwinContext, Dependency1, Dependency2);

app.Run(UploadAsync);

Equivalent to

app.Run(owinContext => {
  var lifetimeScope = owinContext.GetAutofacLifetimeScope();
  return UploadAsync(
    owinContext,
    lifetimeScope.Resolve<Dependency1>(),
    lifetimeScope.Resolve<Dependency2>()
    );
  });

This one is actually beautiful from the user point of view - if you not take into account the necessity to provide for 15 variants of Func<Task,IOwinContext,Dependency1,...,DependencyN>.

I could do either - or both - if you deem this appropriate.

External creation of ILifetimeScope

I have a particular configuration (i.e., hosting OWIN in plain vanilla asp.net application in IIS) that requires me to "inject" ILifetimeScope from outside OWIN middleware instead of creating it inside. So what I want to have is:

  1. asp.net's Application_BeginRequest creates a per-request lifetime scope and saves it to HttpRequest properties
  2. OWIN injector middleware, instead of creating its own lifetime scope, calls external "factory", which simply extracts lifetime scope from HttpRequest properties
  3. further OWIN pipeline proceeds as before
  4. because lifetime scope was created externally, OWIN injector middleware does not dispose it
  5. asp.net's Application_EndRequest gets lifetime scope from HttpRequest properties and disposes it

Is this a feasible approach? I can provide a create a pull-request for this quite quickly and I don't think this would be a breaking change.

Nuget package cannot be installed against latest version of Autofac.

Version 7.0.0 of Autofac was published on March 7, 2023 but it looks like Autofac.Owin is setup with an upper bound on the verions of Autofac to be less than version 7.0.0. Attemptiong to install gives the following error:

Unable to resolve dependencies. 'Autofac 7.0.0' is not compatible with 'Autofac.Owin 7.0.0 constraint: Autofac (>= 6.0.0 && < 7.0.0)'.

Autofac - SingleInstance get's instantiated for every API request

Describe the Bug

I'm working on an ASP.NET (not Core, but based on .NET Framework) WebAPI project. It uses Autofac for DI. I need to implement a Singleton/SingleInstance via Autofac. But the class gets instantiated for every API request. What I want is an object that exists for the entire runtime of the application and is always the same. Independent of any API request.
The controller requests the object in the constructor and Autofac properly delivers an instance of the object, but it's always a new one.
The only exception was, when I started the SingleInstance with AutoActivate it was created, then the first request got the same instance, but every following one received a new instance.

I already asked this on StackOverflow, but got no answer, so I hoped I'll find a response here. I'm thankful for any suggestions.

The class in question is named ScriptExecutionHost. It requests only a string as a parameter and two other singletons. See below for details.

Steps to Reproduce

Here is the relevant code:

Startup.cs

        public void Configuration(IAppBuilder app)
        {

            var container = ContainerConfig.Configure();
            var config = GetHttpConfiguration(container);

            app.UseAutofacMiddleware(container);
            app.UseAutofacLifetimeScopeInjector(container);
            app.UseCors(CorsOptions.AllowAll);
            ConfigureOAuth(app);

#if TESTSYSTEM || DEBUG
            Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
            SwaggerConfig.Register(config);
#endif

            var physicalFileSystem = new PhysicalFileSystem("./app");
            // Make ./app the default root of the static files in our Web Application.
            app.UseFileServer(new FileServerOptions
            {
                RequestPath = new PathString(string.Empty),
                EnableDirectoryBrowsing = true,
                EnableDefaultFiles = true,
                FileSystem = physicalFileSystem,
                StaticFileOptions = { FileSystem = physicalFileSystem, ServeUnknownFileTypes = true },
                DefaultFilesOptions = { DefaultFileNames = new[] { "index.html" } }
            });

            app.UseStageMarker(PipelineStage.MapHandler);

            app.UseAutofacWebApi(config);
            app.UseWebApi(config);
        }

        private static HttpConfiguration GetHttpConfiguration(IContainer container)
        {
            // Create HttpConfiguration instance
            var config = new HttpConfiguration
            {
                DependencyResolver = new AutofacWebApiDependencyResolver(container)
            };
            config.Formatters.Remove(config.Formatters.XmlFormatter);

            // tell the application to treat dates as UTC
            config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling =
                DateTimeZoneHandling.Utc;
            config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling =
                ReferenceLoopHandling.Ignore;
            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
                new CamelCasePropertyNamesContractResolver();

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                "DefaultApi",
                "api/{controller}/{id}",
                new { id = RouteParameter.Optional }
            );
            return config;
        }

        private static void ConfigureOAuth(IAppBuilder app)
        {
            var oAuthServerOptions = new OAuthAuthorizationServerOptions
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = new AuthorizationServerProvider()
            };

            // Token Generation
            app.UseOAuthAuthorizationServer(oAuthServerOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }

ContainerConfig.Configure()

        public static IContainer Configure()
        {
            var builder = new ContainerBuilder();

            // Register your Web API controllers.
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            // Register Credentials Service
            builder.Register(_ => new CredentialsService(CredentialManagerConfiguration.LoadFromWebConfig()))
                .As<CredentialsService>().SingleInstance();

            // Register our DatabaseContext
            builder.RegisterType<DatabaseContext>().AsSelf().InstancePerRequest();

            // Register the CredentialManagerConfiguration using the web.config
            builder.Register(_ => CredentialManagerConfiguration.LoadFromWebConfig()).AsSelf().SingleInstance();
            // Register the EmailConfiguration using the web.config
            builder.Register(_ => EmailConfiguration.LoadFromWebConfig()).AsSelf().SingleInstance();

            // Register the EmailClient using the EmailConfiguration from the web.config
            builder.RegisterType<EmailRepo>().As<IEmailRepo>().SingleInstance();

            // Register the UnitOfWork using the DatabaseContext, FileTemplates and EmailClient
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().AsSelf()
                .WithParameter("templateFileFolder", _fileTemplateBaseDirectory)
                .WithParameter("downloadDir", _fileDownloadBaseDirectory)
                .InstancePerRequest();

            builder.RegisterType<ScriptExecutionHost>().AsSelf().WithParameter("fileDownloadBaseDirectory", _fileDownloadBaseDirectory).SingleInstance().AutoActivate();

            // OPTIONAL: Register the Autofac model binder provider.
            builder.RegisterWebApiModelBinderProvider();

            return builder.Build();
        }

The relevant controllers constructor

        public ScriptsController(IUnitOfWork unitOfWork, ScriptExecutionHost scriptExecutionHost) : base(unitOfWork)
        {
            _unitOfWork = unitOfWork;
            _adService = new ActiveDirectoryService(new ActiveDirectoryConfiguration());
            _scripExecutionHost = scriptExecutionHost;
        }

The ScriptExecutionHost constructor

 public class ScriptExecutionHost : IRegisteredObject
    {
...
       public ScriptExecutionHost(string fileDownloadBaseDirectory, CredentialManagerConfiguration credentialManagerConfiguration, IEmailRepo emailRepo)
        {
            // Register ourself to the hosting environment to be able to shut down gracefully
            // This is necessary to ensure we can finish our work before the application pool is recycled
            HostingEnvironment.RegisterObject(this);

            _fileDownloadBaseDirectory = fileDownloadBaseDirectory;
            _credentialManagerConfiguration = credentialManagerConfiguration;
            _emailRepo = emailRepo;

            _logger.Debug("ScriptExecutionHost initialized.");
            _logger.Debug("File download base directory: {0}", _fileDownloadBaseDirectory);

// I used this to check if Autofac truly creates a new instance of this class every time.
            initTime = DateTime.Now;
        }

Expected Behavior

I excpect a SingleInstance to generate a singleton type object, that only exists once for the entire lifetime of the application.

Dependency Versions

Autofac: 7.0.1
Autofac.Owin: 7.1.0
Autofac.WebApi2: 6.1.1
Autofac.WebApi2.Owin: 6.2.1
CsvHelper: 30.0.1
Microsoft.AspNet.WebApi: 5.2.9
Microsoft.AspNet.WebApi.Client: 5.2.9
Microsoft.AspNet.WebApi.Core: 5.2.9
Microsoft.AspNet.WebApi.Cors: 5.2.9
Microsoft.AspNet.WebApi.Owin: 5.2.9
Microsoft.AspNet.WebApi.WebHost: 5.2.9
Microsoft.CodeDom.Providers.DotNetCompilerPlatform: 4.1.0
Microsoft.IdentityModel.JsonWebTokens: 6.30.0
Microsoft.IdentityModel.Logging: 6.30.0
Microsoft.IdentityModel.Tokens: 6.30.0
Microsoft.Owin: 4.2.2
Microsoft.Owin.Cors: 4.2.2
Microsoft.Owin.FileSystems: 4.2.2
Microsoft.Owin.Host.SystemWeb: 4.2.2
Microsoft.Owin.Security: 4.2.2
Microsoft.Owin.Security.Jwt: 4.2.2
Microsoft.Owin.Security.OAuth: 4.2.2
Microsoft.Owin.StaticFiles: 4.2.2
Microsoft.Web.Infrastructure: 2.0.0
Newtonsoft.Json: 13.0.3
NLog: 5.1.4
NLog.Web: 5.2.3
Owin: 1.0.0
Swashbuckle: 5.6.0
System.IdentityModel.Tokens.Jwt: 6.30.0

owin autofac middleware and controller lifetime not same one

Describe the Bug

owin one request autofac middleware and controller lifetime not same one

UnitOfWorkManagerMiddleware

Dingtalk_20220824103418

TemplateService
Dingtalk_20220824103612

Steps to Reproduce

Startup.css

 /// <summary>
    /// 
    /// </summary>
    public class Startup
    {
        /// <summary>
        /// 
        /// </summary>
        public Startup()
        {
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="app"></param>
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();


            config.MapHttpAttributeRoutes();
           
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
            config.Formatters.JsonFormatter.MediaTypeMappings.Add(new QueryStringMapping("datatype", "json", "application/json"));
            config.Formatters.JsonFormatter.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings()
            {
                NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore 
            };

            ConfigureAutofac(app, config);
            app.UseWebApi(config);
        }



        /// <summary>
        /// 
        /// </summary>
        /// <param name="appBuilder"></param>
        /// <param name="config"></param>
        private static void ConfigureAutofac(IAppBuilder appBuilder, HttpConfiguration config)
        {
            var builder = new ContainerBuilder();

            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            #region SingleInstance

            var assemblyCore = Assembly.Load("Api");
            var assemblyCommon = Assembly.Load("Common");
            builder.RegisterAssemblyTypes(assemblyCore, assemblyCommon)
            .Where(t => t.GetCustomAttribute<SingleInstanceAttribute>() != null)
            .SingleInstance();

            builder.RegisterAssemblyTypes(assemblyCore, assemblyCommon)
            .Where(t => t.GetCustomAttribute<SingleInstanceAttribute>() != null)
            .AsImplementedInterfaces()
            .SingleInstance();
            #endregion

            #region Repository
            var assemblyRepository = Assembly.Load("Repository");
            builder.RegisterAssemblyTypes(assemblyRepository)
            .AsImplementedInterfaces()
            .InstancePerRequest();
            #endregion

            #region Service
            var assemblyServices = Assembly.Load("Services");
            builder.RegisterAssemblyTypes(assemblyServices)
            .AsImplementedInterfaces()
            .InstancePerRequest();
            #endregion

            builder.RegisterType<UnitOfWorkManagerMiddleware>().InstancePerRequest();


            var container = builder.Build();

            config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

            appBuilder.UseAutofacMiddleware(container);

        }
    }

Middleware

/// <summary>
    /// 
    /// </summary>
    public class UnitOfWorkManagerMiddleware : OwinMiddleware
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="next"></param>
        /// <param name="unitOfWorkManager"></param>
        public UnitOfWorkManagerMiddleware(OwinMiddleware next, UnitOfWorkManagerCloud unitOfWorkManager, ITemplateRepository _templateRepository, ITemplateRepository _templateRepository2) : base(next)
        {
        }


        public override async Task Invoke(IOwinContext context)
        {
            try
            {
                await Next.Invoke(context);
            }
            finally
            {
                TransactionalAttribute.SetUnitOfWorkManager(null);
            }
        }
    }

Repository

    public class TemplateRepository : ITemplateRepository
    {
        readonly string aa = Guid.NewGuid().ToString();


        public TemplateRepository(UnitOfWorkManagerCloud uowm) : base(uowm)
        {
        }
    }

    public interface ITemplateRepository : IRepositoryCloud<TemplateEntity>
    {
    }
public class TemplateService : ITemplateService
    {
        private readonly ITemplateRepository _templateRepository;
        private readonly ITemplateRepository _templateRepository2;

        private readonly UnitOfWorkManagerCloud _uowm;

        public TemplateService(ITemplateRepository templateRepository,ITemplateRepository templateRepository2, UnitOfWorkManagerCloud uowm)
        {
            _templateRepository = templateRepository;
            _templateRepository2 = templateRepository2;

            _uowm = uowm;
            //TransactionalAttribute.SetUnitOfWorkManager(uowm);
        }
}
public class UnitOfWorkManagerCloud
    {
        readonly string aa = Guid.NewGuid().ToString();
        public UnitOfWorkManagerCloud()
        {
        }
    }

Expected Behavior

owin autofac middleware and controller lifetime

same one

Exception with Stack Trace

Put the exception with stack trace here.

Dependency Versions

Autofac: 6.4.0.0
Autofac.Integration.Owin: 7.0.0.0
Autofac.Integration.WebApi:6.1.1.0

Additional Info

Sample
WindowsFormsApp7.zip

Middleware registration order is inverted during resolve

Describe the Bug

If you look at the OWIN self hosting example you can see the expected output to respect the registration order of the middleware. However, when you execute the example, the middleware is executed in the opposite order:

Inside the 'Invoke' method of the 'SecondMiddleware' middleware.
Inside the 'Invoke' method of the 'FirstMiddleware' middleware.
Inside the 'OnActionExecutingAsync' method of the custom action filter.
Inside the 'Get' method of the 'TestController' controller.
Inside the 'OnActionExecutedAsync' method of the custom action filter.
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Date: Wed, 24 Nov 2021 16:21:09 GMT
  Server: Microsoft-HTTPAPI/2.0
  Content-Length: 15
  Content-Type: application/json; charset=utf-8
}
"Hello, world!"

(Issue based on this StackOverflow question.)

Steps to Reproduce

  1. Clone the Examples repo.
  2. cd src/WebApiExample.OwinSelfHost
  3. dotnet run

Expected Behavior

As documented, the middleware should execute in the order registered.

Dependency Versions

  • Autofac: 6.0.0
  • Autofac.Owin: 6.0.0
  • Autofac.WebApi2: 6.0.0
  • Autofac.WebApi2.Owin: 6.0.0

Additional Info

The logic for resolving the set of middleware items looks like it's been stable for six years. However, I recall we had to change some internals in Autofac to handle resolving IEnumerable<T> in registration order and it involved doing things like this which reverse the order in which registrations are returned when enumerating them manually.

I'm guessing that due to that reversal in core Autofac, we also need to reverse the order in which the manual enumeration of registered middleware is handled. We probably should also add a unit test to make sure we don't regress this.

7.0.0 introduced memory leak due to async disposal issue in main Autofac

I want to file this here just so that the people Googling for the symptoms will be able to find it and see the resolution

Describe the Bug

After upgrading to Autofac.Owin 7.0.0 we've observed a sizeable memory leak due to a lot of held System.Threading.ThreadLocal+LinkedSlotVolatile<System.Collections.Concurrent.ConcurrentBag+ThreadLocalList<Autofac.Core.IComponentRegistration>>

Steps to Reproduce

  • Setup a regular OWIN integration: app.UseAutofacLifetimeScopeInjector(_container)
  • See autofac/Autofac#1252

Expected Behavior

  • no memory leak

Dependency Versions

Autofac: 6.4.0
Autofac.Owin: 7.0.0

Additional Info

So, to fix this, we simply need to wait for new core release, and then simply bump the required dependency version.

Put the registration into middlewares

Basically, I can build the container in the Startup.Configuration method and then add the Autofac middleware into the IAppBuilder.

public void Configuration(IAppBuilder application)
{
        var container = BuildContainer();
        app.UseAutofacMiddleware(container);
}

I can also put the registrations into custom middlewares and register different dependencies in different middlewares based on some arguments. For example:

public class HttpClientRegistrationMiddleware : OwinMiddleware
{
    private HttpClientRegistrationOptions options;

    public HttpClientRegistrationMiddleware(OwinMiddleware next, HttpClientRegistrationOptions options) : base(next)
    {
        this.options = options;
    }

    public override async Task Invoke(IOwinContext context)
    {
        if (context.GetAutofacLifetimeScope() != null)
        {
            await Next.Invoke(context);
        }
        else
        {
            var builder = context.Get<ContainerBuilder>(nameof(ContainerBuilder));
            builder.Register(c => options.Handler == null ? new HttpClient() : new HttpClient(options.Handler)).SingleInstance();
            await Next.Invoke(context);
        }        
    }
}

Is it a good practice? Are there any pitfalls about it?
Thank you.

Autofac.Owin 4.2.0 seems to require Microsoft.Owin 3.0.0

I'm using Autofac.Owin to get DI features using IAppBuilder.
I created a simple DebugMiddleware which I try to resolve from Autofac container by calling the UseMiddlewareFromContainer method.

Here's a simple code snippet:

public void Configuration(IAppBuilder application)
{
        this.RegisterDependencies(); // creating Container here
        application.UseMiddlewareFromContainer<DebuggingMiddleware>(); 
}

DebugMiddleware is a simple OwinMiddleware class that doesn't have any dependencies other than Microsoft.Owin.

The problem is that the Configuration method is not even fired on startup and the app crashes with the exception:

System.IO.FileLoadException
Could not load file or assembly 'Microsoft.Owin, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

I looked up in the source code of Autofac.Owin, the packages.config containts a reference to Microsoft.Owin 3.0.0 even though there's >=3.0.0 on Nuget. Can this be a problem?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.