Constructor injection of InstancePerRequest to service resolves new instance - c#

I register a service FooRequest as InstancePerRequest in ASP.NET MVC & OWIN:
builder.RegisterType<FooRequest>().AsSelf().InstancePerRequest();
After that I resolve FooRequest in two locations. First is global.asax Application_BeginRequest():
protected void Application_BeginRequest(object sender, EventArgs e)
{
var fooRequest = DependencyResolver.Current.GetService<FooRequest>();
}
A second time in another services constructer. The other service has InstancePerLifetimeScope:
public class FooService
{
public FooService(FooRequest fooRequest)
{
...
}
}
My problem is that those two resolves in different instances of FooService and the one used in constructor injection of service does not call Dispose[Async] on the end of the request.
What am I doing wrong?
Btw. using DependencyResolver.Current.GetService<FooRequest>() outside the constructor does resolve the proper instance of FooRequest in FooService.
Additional requested information
OWIN & Container configuration:
[assembly: OwinStartup(typeof(Project.Web.Startup))]
namespace Project.Web
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// REGISTER CONTROLLERS SO DEPENDENCIES ARE CONSTRUCTOR INJECTED
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterApiControllers(typeof(MvcApplication).Assembly);
// REGISTER DEPENDENCIES
builder.RegisterModule(new ProjectWebModule());
builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager> { DataProtectionProvider = app.GetDataProtectionProvider() });
// REGISTER FILTERS SO DEPENDENCIES ARE PROPERTY INJECTED
builder.RegisterFilterProvider();
// BUILD THE CONTAINER
var container = builder.Build();
// REPLACE THE MVC DEPENDENCY RESOLVER WITH AUTOFAC
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// REPLACE THE WEBAPI DEPENDENCY RESOLVER WITH AUTOFAC
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// REGISTER WITH OWIN
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
app.Use((context, next) =>
{
var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
httpContext.SetSessionStateBehavior(SessionStateBehavior.Required);
return next();
});
// STANDARD MVC SETUP
RouteConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); // immer nach RouteConfig.RegisterRoutes ausführen!
BundleConfig.RegisterBundles(BundleTable.Bundles);
// PLACE ConfigureAuth AFTER RegisterGlobalFilters
ConfigureAuth(app);
}
}
}
ProjectWebModule
namespace Project.Web.Autofac
{
public class ProjectWebModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<FooRequest>().AsSelf().InstancePerRequest();
builder.RegisterType<FooService>().AsSelf().InstancePerLifetimeScope();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
builder.Register(c =>
//register FakeHttpContext when HttpContext is not available
HttpContext.Current != null
? new HttpContextWrapper(HttpContext.Current) as HttpContextBase
: new FakeHttpContext("~/") as HttpContextBase)
.As<HttpContextBase>()
.InstancePerLifetimeScope()
.OnActivated(e =>
{
Toolbox.HttpContext = e.Instance;
});
builder.Register(c => c.Resolve<HttpContextBase>().Request)
.As<HttpRequestBase>()
.InstancePerLifetimeScope();
builder.Register(c => c.Resolve<HttpContextBase>().Response)
.As<HttpResponseBase>()
.InstancePerLifetimeScope();
builder.Register(c => c.Resolve<HttpContextBase>().Server)
.As<HttpServerUtilityBase>()
.InstancePerLifetimeScope();
builder.Register(c => c.Resolve<HttpContextBase>().Session)
.As<HttpSessionStateBase>()
.InstancePerLifetimeScope();
base.Load(builder);
}
}
}

I mention in the comments on the question that there's not enough info here to really tell, but here's my guess: you have a race condition.
As you know from the Autofac.Mvc.Owin README and the MVC/OWIN integration docs, ASP.NET MVC doesn't actually fully run in the OWIN pipeline. Trying to make the two work creates some weird issues that aren't of Autofac's creation. For example (again, from the Autofac docs):
Minor gotcha: MVC doesn’t run 100% in the OWIN pipeline. It still needs HttpContext.Current and some other non-OWIN things. At application startup, when MVC registers routes, it instantiates an IControllerFactory that ends up creating two request lifetime scopes. It only happens during app startup at route registration time, not once requests start getting handled, but it’s something to be aware of. This is an artifact of the two pipelines being mangled together. We looked into ways to try working around it but were unable to do so in a clean fashion.
But that also means there's a sort of order around when Application_BeginRequest handlers run that could cause oddness like what you're seeing. For example, the Autofac OWIN MVC integration tries to set up a request lifetime (if it's not already set up) when you put app.UseAutofacMvc() in the pipeline, but the ASP.NET MVC framework also tries to set up a request lifetime internally (using DependencyResolver.Current), so those things have to work together. It's not entirely impossible that your Application_BeginRequest handler is resolving from a different lifetime scope than what the MVC framework is trying to set up as the request lifetime, for example if the MVC framework hasn't had a chance to set it up before you've tried resolving from it.
I would recommend if you're trying to use OWIN with MVC, give in to OWIN and actually use OWIN middleware in the pipeline rather than event handlers in MVC. It'll remove the race condition for Application_BeginRequest and give you greater control over the order of operations. It'll also get you closer to where ASP.NET Core is so if/when it's time to migrate your application you won't have to deal with the event handlers that aren't there anymore.
Of course, again, this is totally a guess based on what I could gather from the question. Hopefully it helps.
Edit after new info was added to question: I think my guess is still correct, but it also looks like you're not setting up OWIN right for WebAPI, which could contribute to the problem. You shouldn't be using GlobalConfiguration. Also, again, MVC doesn't really run in OWIN, so you may see weirdness trying to get two app types (MVC, WebAPI) with two different pipelines to mash together. It's why they unified it in ASP.NET Core.

Related

SimpleInjector Container.Verify() with HTTP context-scoped dependency

I have the following basic SI registration in an ASP.NET WebApi project.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSimpleInjector(container, options =>
{
options
.AddAspNetCore()
.AddControllerActivation();
});
services.AddHttpContextAccessor();
services.AddScoped<Work>(services =>
{
var traceId = services.GetRequiredService<IHttpContextAccessor>().HttpContext.TraceIdentifier;
// ...
});
}
public void Configure(IApplicationBuilder app)
{
app.ApplicationServices.UseSimpleInjector(container);
// ...
container.Verify();
}
private readonly Container container = new Container();
The Problem
Container.Verify() attempts to resolve a Work instance, whose factory delegate successfully resolves an IHttpContextAccessor but its HttpContext is null because there is no current HTTP call on startup. Therefore the code dies with a null-reference exception.
I don't think there is anything we can do except guard against null but that goes against my taste in this context:
why would I do that when I know for a fact that this factory delegate should only be called during an HTTP call?
what exactly do I do if my HTTP-scoped dependency is null? Sure, return a fake BUT how do I detect that it's null for good reason and not because my web infrastructure is dying somehow?
I can't see a good solution. What do you do in this case?
I've wrote extensively about this problem in the past. Your HttpContext and its TraceIdentifier are runtime data and runtime data should be kept out of the construction of your object graphs. See for instance this article.
What the correct solution in your particular case is, is hard to say, because it depends on the details of what you are trying to construct, but the article gives some pointers.

Injecting a registered named service is not working as expected using Autofac 4.2.1

Background
Autofac 4.2.1(tried with the latest version of Autofac and the issue is still present) ,
WebApi project .netcore 2.2
Issue :
I have two instances of the same service, which I register to the ContainerBuilder with Name:
builder.RegisterType<ServiceOne>().Named<IService>("ServiceOne").SingleInstance();
builder.RegisterType<ServiceTwo>().Named<IService>("ServiceTwo").SingleInstance();
I then inject the named services to my controller classes as required:
builder.Register(c => new KeysController(c.ResolveNamed<IService>("ServiceOne")));
builder.Register(c => new ValuesController(c.ResolveNamed<IService>("ServiceTwo")));
Autofac is not able to resolve the IService for both of my controllers by name.
The Exception
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type
'AutoFacNaming.IService' while attempting to activate
'AutoFacNaming.Controllers.ValuesController'.
By default ASP.net core will not build controller from the container but only its parameters. You can change this by specifying AddControllersAsServices() when you register MVC with the service collection. Doing that will automatically register controller types into the IServiceCollection when the service provider factory calls builder.Populate(services).
public class Startup
{
// Omitting extra stuff so you can see the important part...
public void ConfigureServices(IServiceCollection services)
{
// Add controllers as services so they'll be resolved.
services.AddMvc().AddControllersAsServices();
}
public void ConfigureContainer(ContainerBuilder builder)
{
// If you want to set up a controller for, say, property injection
// you can override the controller registration after populating services.
builder.Register(c => new KeysController(c.ResolveNamed<IService>("ServiceOne")));
builder.Register(c => new ValuesController(c.ResolveNamed<IService>("ServiceTwo")));
}
}
You can read more about it in the Autofac documentation

Understanding Autofac middleware usage with ASP.NET Webforms, OWIN and ASP.NET Identity

I'm currently updating an old ASP.NET Webforms application that uses MembershipProvider and RoleProvider, to use the newer ASP.NET Identity classes. Additionally, I use Autofac for my dependency injection and for consistency I want to be able to use it with the new Identity classes.
ASP.NET Identity now relies on OWIN middleware and I have been successfully able to incorporate the OWIN middleware setup in my application by adding the following Startup.cs class:
internal partial class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
AutofacConfig.RegisterTypes(builder);
AutofacConfig.RegisterIdentityTypes(builder, app);
var container = builder.Build();
Global.SetContainer(container);
app.UseAutofacMiddleware(container);
ConfigureAuth(app);
}
}
I register the identity classes with Autofac like so:
internal static class AutofacConfig
{
public static void RegisterIdentityTypes(ContainerBuilder builder, IAppBuilder app)
{
builder.RegisterType<ApplicationUserStore>().As<IUserStore<ApplicationUser>>().InstancePerRequest();
builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
builder.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).InstancePerRequest();
builder.Register(c => app.GetDataProtectionProvider()).InstancePerRequest();
}
}
I can see when I navigate to my WebForms sign in page the following ApplicationSignInManager class is instantiated and its constructor parameters are also resolved so that suggests to me that Autofac is working correctly.
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
public ApplicationSignInManager(
ApplicationUserManager userManager,
IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
// userManager is valid
// authenticationManager is valid
}
}
When I click my sign in button on my WebForms sign in page the following method is called and the ApplicationSignInManager is instantiated via the Autofac property injection. This then calls down to the correct Identity class implementations.
public partial class SignIn : BasePage
{
// Autofac property injection
public ApplicationSignInManager ApplicationSignInManager { get; set; }
....
protected void SignInClick(object sender, EventArgs e)
{
// Validate the user password
var result = this.ApplicationSignInManager.PasswordSignIn(
this.email.Text,
this.password.Text,
this.remember.Checked,
true);
....
}
So all seems well but something doesn't seem right to me, I don't see where the OWIN and Autofac are connected, or even required. To add fuel to that fire if I remove the following line from Startup.cs...
app.UseAutofacMiddleware(container);
...everything still works as it should! Which can't be right, can it?
Many examples for MVC seems to suggest this is the correct way to get the Identity object (via the GetOwinContext() call):
protected void SignInClick(object sender, EventArgs e)
{
var signInManager = this.Context.GetOwinContext().GetUserManager<ApplicationSignInManager>();
// Validate the user password
var result = signInManager.PasswordSignIn(
this.email.Text,
this.password.Text,
this.remember.Checked,
true);
....
}
But on executing that code the 'signInManager' variable always is NULL.
Do I really need this line of code?
app.UseAutofacMiddleware(container);
Can anyone point me in the right direction?
Documentation states that
For a simple scenario, app.UseAutofacMiddleware(container); will handle both adding an Autofac lifetime to the OWIN request scope as well as adding middleware that is registered with Autofac into the pipeline.
See source to confirm.
Basically if you are injecting anything from Autofac into OWIN pipeline (i.e. middlewares), you need this line. But for your scenario it does not look like you do anything like that, so removing that line does not change anything for you.
As for resolving objects from OWIN pipeline, you don't really need to do that - you already resolve objects from Autofac. However, SecurityStampValidator still resolves ApplicationUserManager from OWIN, so you still need to register it with OWIN:
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
See this question/answer for reasons behind it.
I know this is pretty late to the game but I'm updating a legacy app and I ran into the "IAppBuilder does not contains a definition for 'UseAutofacMiddleware'" error and fixed it by adding the NuGet package Autofac.Owin.

Injecting a dependency into OWIN Middleware and per web-request with Simple Injector

I am trying to work out how to best inject all of my dependencies into the custom OWIN Middleware I have written for a Web API Application. A simple example would be the DbContext I am using. I have some middleware that needs to potentially query based on the request. The issue I have is that I want my DbContext to otherwise have a WebApiRequestLifestyle scope. My DbContext is registered as such:
container.Register<MobileDbContext>(Lifestyle.Scoped);
Obviously, this does not work:
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
Because I need the MobileDbContext in my Middleware using something like:
app.CreatePerOwinContext(() =>
{
return container.GetInstance<MobileDbContext>();
};
I tried a hybrid lifestyle, but that also didn't work because I don't think the Middleware is technically something that can fall under a "scoped" lifestyle. It is probably closer to a singleton, I would think.
Is there a better way to design my app to avoid this problem or address it with some sort of custom scoped lifestyle?
The documentation shows an example of how to wrap an OWIN request in a scope:
public void Configuration(IAppBuilder app) {
app.Use(async (context, next) => {
using (AsyncScopedLifedtyle.BeginScope (container)) {
await next();
}
});
}
What this does is wrapping an OWIN request in an execution context scope. All you have to do now is make the execution contest scope the default scoped lifestyle as follows:
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

MvcSiteMapProvider and Autofac issue with InstancePerRequest

I've installed nutget package MvcSiteMapProvider.MVC5.DI.Autofac.Modules.
I'm trying to register my DBContext as InstancePerRequest. This however fails with the error
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested.
If I change my DBContext to InstancePerLifetimeScope, all is well. The error is thrown in the file
DI\Autofac\Modules\MvcSiteMapProviderModule.cs Line: 195
Actually, if I try to register any of my own types with InstancePerRequest, I get this error. I'm new to Autofac so don't really understand a lot of the code in the nuget package forMvcSiteMapProvider Autofac. While I'm learning more about Autofac, hoping someone can point in the right direction as to how to get around this issue?
EDIT:
From Autofac docs, I'm getting the error because:
Code is running during application startup (e.g., in an ASP.NET Global.asax) that uses dependency resolution when there isn’t an active request yet.
According to MvcSiteMapProvider docs, this line is required though, so can I move this somewhere else?
// Setup global sitemap loader (required)
MvcSiteMapProvider.SiteMaps.Loader = container.Resolve<ISiteMapLoader>();
EDIT 2:
protected void Application_Start()
{
// BEGIN: Autofac Config
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterSource(new ViewRegistrationSource());
// Register context and unit of work here
IoC.Dependencies.Register.RegisterTypes(builder);
builder.RegisterModule(new MvcSiteMapProviderModule());
builder.RegisterModule(new MvcModule());
var container = builder.Build();
MvcSiteMapProvider.SiteMaps.Loader = container.Resolve<ISiteMapLoader>();
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// END: Autofac Config
Helpers.Log4NetManager.InitializeLog4Net();
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
}
You are registering your controllers twice with Autofac.
// This registers the all of the controllers in the application
builder.RegisterControllers(typeof(MvcApplication).Assembly);
// And so does this...
builder.RegisterModule(new MvcModule());
Contents of MvcModule:
public class MvcModule
: Module
{
protected override void Load(ContainerBuilder builder)
{
var currentAssembly = typeof(MvcModule).Assembly;
builder.RegisterAssemblyTypes(currentAssembly)
.Where(t => typeof(IController).IsAssignableFrom(t))
.AsImplementedInterfaces()
.AsSelf()
.InstancePerDependency();
}
}
UPDATE
From here:
The error pretty much says it all - something in your registrations has a dependency that is registered as InstancePerRequest and it's being resolved outside of a web request.
I am not sure that registering DBContext as InstancePerRequest is such a good idea. MvcSiteMapProvider loads before any request context is created, so if you are using dynamic node providers or custom ISiteMapNodeProvider implementations that access the database, it isn't going to work. A better choice would be to use InstancePerDependency which is not dependent upon HttpContext.
Instance Per Dependency
Also called ‘transient’ or ‘factory’ in other containers. Using per-dependency scope, a unique instance will be returned from each request for a service.

Categories