How to integrate Autofac with WepApi 2 and Owin? - c#

I am using this package to integrate Autofac with my WebApi Owin application:
https://www.nuget.org/packages/Autofac.WebApi2.Owin
And following this post:
http://alexmg.com/owin-support-for-the-web-api-2-and-mvc-5-integrations-in-autofac/
My code in Startup.cs looks like this:
var config = new HttpConfiguration();
IContainer container = EngineContext.InitializeEngine();
var dependencyResolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = dependencyResolver;
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
WebApiConfig.Register(config);
app.UseWebApi(config);
However whichever way I spin it, rearrange the code or whatever, Autofac is just not able to resolve anything. Before Owin I had my Global.asax method working just fine:
protected void Application_Start()
{
IContainer container = EngineContext.InitializeEngine();
var dependencyResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver;
GlobalConfiguration.Configure(WebApiConfig.Register);
}
What am I missing?
Thanks

Ok,
I figured it out.
The Autofac Owin integration actually creates an Owin liftimescope, which is available through the whole Owin pipeline, thus available to middleware and extends this lifetimescope to the HttpRequestMessage. This is the lifetimescope marked with the AutofacWebRequest tag.
So all the previous WebApi integration code still needs to be performed on application startup. I have included:
var dependencyResolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = dependencyResolver;
but missed:
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
in the EngineContext.Initialize method, which does all the registrations via the builder.
Here you can find more information on how to integrate Autofac with the WebApi, which obviously needs to be done also in the case of Owin:
https://code.google.com/p/autofac/wiki/WebApiIntegration
I hope this is useful!

Related

Constructor injection of InstancePerRequest to service resolves new instance

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.

WebForms Project with Mvc Area and Autofac IoC

I have a WebForms project with an Mvc Area.
I have two methods in the Application_Start of the Global.asax.cs to register services with Autofac Dependency Injection respectively;
private void WebFormsContainer()
{
var webFormsContainer = new ContainerBuilder();
webFormsContainer.RegisterAssemblyTypes(typeof(CompanyService).Assembly)
.Where(s => s.Name.EndsWith("Service"))
.AsImplementedInterfaces().InstancePerRequest();
_containerProvider = new ContainerProvider(webFormsContainer.Build());
}
and also,
private void MvcContainer()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterAssemblyTypes(typeof(CompanyService).Assembly)
.Where(s => s.Name.EndsWith("Service"))
.AsImplementedInterfaces().InstancePerRequest();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
The WebForms injection appears to work but when I try the Mvc part of the app I get the error;
No parameterless constructor defined for this object.
Question is how do I set up Autofac for MVC areas in a Webforms app?
I had previously tried the answer from this post;
Autofac, MVC (with ActionFilters), Web.Forms - dependency resolution conflict but I must have attempted incorrectly because I have retried it and got it to work.

Autofac - Make sure that the controller has a parameterless public constructor

I know it's been asked and answered before - the reason I'm asking is because (I think) I tried all suggested solutions to this problem but still can't resolve it.
I have an ASP.NET Web API 2.0 project. I have Autofac, Autofac.Mvc5 and Autofac.WebApi2 dependencies installed. When I try to call an API controller I get the following error:
An error occurred when trying to create a controller of type 'MyController'. Make sure that the controller has a parameterless public constructor.
In my Global.asax I have a call to IocConfig.Config() which I have placed inside App_Start:
public static class IocConfig
{
public static void Config()
{
var builder = new ContainerBuilder();
builder.RegisterType<MyLogger>().As<IMyLogger>();
builder.RegisterApiControllers(Assembly.GetCallingAssembly());
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
WebApiApplication.Container = builder.Build();
DependencyResolver.SetResolver(
new AutofacDependencyResolver(WebApiApplication.Container));
GlobalConfiguration.Configuration.DependencyResolver =
new AutofacWebApiDependencyResolver(WebApiApplication.Container);
}
}
And this is the constructor for MyController:
public MyController(IMyLogger logger)
When I try to call it I get the specified error about the constructor. What am I missing?
I encountered this error as well and the root cause was that one of the Controller's dependencies wasn't registered correctly in Autofac.
The InnerException has the detail (in my case it was an Autofac.Core.DependencyResolutionException) and the ExceptionMessage included the detail of this dependency. Along the lines of:
"An error occurred during the activation of a particular registration... Cannot resolve parameter 'XXXX'
Check this answer.
It helps me configure correct ContainerBuilder() for WebApi controllers.
If you are looking here a solution for such error you should check your DependencyResolver Configuration first.
I faced the same issue and the problem was that I was using Autofac code samples for ContainerBuilder() object for MVC controllers and not API.
My code for register both type of controllers (MVC and Api):
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly()); //Register MVC Controllers
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); //Register WebApi Controllers
builder.RegisterType<Type>().As<IType>();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); //Set the MVC DependencyResolver
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver((IContainer)container); //Set the WebApi DependencyResolver
Assembly.GetCallingAssembly() will return the calling assembly, not the assembly where your types is defined.
Assembly.GetCallingAssembly Method
Returns the Assembly of the method that invoked the currently executing method.
In order to make it works, you should use typeof(IocConfig).Assembly or Assembly.GetExecutingAssembly
You might be missing calling configuration from WebApiConfig.cs file:
IocConfigurator.ConfigureDependencyInjection(config);
ConfigureDependencyInjection can be like this:
public static void ConfigureDependencyInjection(HttpConfiguration config)
{
var builder = new ContainerBuilder();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// OPTIONAL: Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
// OPTIONAL: Register the Autofac model binder provider.
builder.RegisterWebApiModelBinderProvider();
// Set the dependency resolver to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
I think you are missing registering autofac at app start code.
Use this:
protected void Application_Start()
{
IocConfig.Config();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
For more details, refer this blog http://www.codeproject.com/Articles/808894/IoC-in-ASP-NET-MVC-using-Autofac
Open you ServiceModule File
Register the Interface and service name those are mentioned in controller.
Example are as below:-
builder.RegisterType().As();

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.

Parameterless constructor error. (upgrade to autofac 3)

In application_start() I have the following code.
When the Account Controller get's created I get the parameterless constructor error.
AccountController does not have a parameterless constructor. It seems that autofac is no longer configured?
Account Controller Expects the following.
public AccountController(IFlexMembershipProvider membership, IFlexOAuthProvider openAuth)
I am not sure why autofac is not injecting the dependences?
var builder = new ContainerBuilder();
builder.RegisterType<DataContext>()
.As<IRepository>()
.As<DbContext>().InstancePerLifetimeScope();
builder.RegisterType<FlexMembershipProvider>().As<IFlexMembershipProvider>();
builder.RegisterType<FlexMembershipProvider>().As<IFlexOAuthProvider>();
builder.RegisterType<FlexRoleProvider>().As<IFlexRoleProvider>();
builder.RegisterType<UserStorage>().As<IFlexUserStore>().InstancePerLifetimeScope();
builder.RegisterType<RoleStorage>().As<IFlexRoleStore>().InstancePerLifetimeScope();
builder.RegisterType<DefaultSecurityEncoder>().As<ISecurityEncoder>().SingleInstance();
builder.RegisterType<AspnetEnvironment>().As<IApplicationEnvironment>();
builder.RegisterType<InvestorService>().As<IInvestorService>();
builder.RegisterType<InvestmentService>().As<IInvestmentService>();
builder.RegisterType<BrokerService>().As<IBrokerService>().As<IListService<Broker>>();
builder.RegisterType<PortfolioManagerService>().As<IListService<PortfolioManager>>();
builder.RegisterModelBinderProvider();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
You need to register the assembly that contains your controllers before calling the .Build method:
builder.RegisterControllers(typeof(MvcApplication).Assembly);
var container = builder.Build();
In this example I assumed that your application class is called MvcApplication and took its assembly. If your controllers are defined in a different assembly you should specify this assembly.
The documentation of AutoFac has an example that you could have gone through.
Try add this before calling builder.Build method:
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(x => !(x.IsValueType) && !(x.IsAssignableFrom(typeof(string)))));

Categories