Autofac with MVC4: controller does not have a default constructor - asp.net

I've been working with Autofac in MVC3 and love it. Now I am trying to implement it with MVC4.
I installed the pre-release versions of Autofac MVC4 and Autofac WebApi through the Package Manager Console (Install-Package Autofac.Mvc4 -Pre and Install-Package Autofac.WebApi -Pre)
I adjusted my IoC container as following:
private static void SetAutofacContainer()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerHttpRequest().InstancePerApiRequest();
builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerHttpRequest().InstancePerApiRequest();
builder.RegisterType<RepositoryWrapper>().As<RepositoryWrapper>().InstancePerHttpRequest().InstancePerApiRequest();
builder.RegisterType<ServiceWrapper>().As<ServiceWrapper>().InstancePerHttpRequest().InstancePerApiRequest();
// Repositories
builder.RegisterAssemblyTypes(typeof(UserRepository).Assembly).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces().InstancePerHttpRequest().InstancePerApiRequest();
// Services
builder.RegisterAssemblyTypes(typeof(UserService).Assembly).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerHttpRequest().InstancePerApiRequest();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
When I run the application (by accessing the API controller) I get the exception:
"Controllers.UserController' does not have a default constructor"
The controller looks like this:
namespace Controllers
{
[Authorize]
public class UserController : ApiController
{
private ServiceWrapper _services;
public UserController(ServiceWrapper services)
{
_services = services;
}
// GET api/user/{userrequest}
public IQueryable<User> Get(UserRequest request)
{
if (ModelState.IsValid)
{
'...
}
}
}
Am I missing something? Did I not set it up right? Any help would be greatly appreciated!
Update
My API controller are within a separate project in the same solution. If I place the API controller in my main MVC project, it works. Could someone please enlighten me on how to get Autofac to register the API controllers in my API project?

With the RegisterApiControllers method you tell Autofac where (in which assembly) it should look for your ApiControllers
So the following call:
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
Registers the ApiControllers from the current assembly (project).
If you have ApiControllers also in a different project you need to use it like this:
builder.RegisterApiControllers(typeof(UserController).Assembly);
Which means: register all the ApiController form the assembly (project) where the UserController lives. So you only need one RegisterApiControllers per assembly even if you have multiple ApiController in an assembly (project).

Related

Assigning all controllers with one register In DI Container

I have a fairly simple question, I am testing Autofac DI container under .net core 2.0 now for example i have a controller
public class ValuesController : Controller
{
private readonly ITestModel _testModel;
public ValuesController(ITestModel testModel)
{
_testModel = testModel;
}
}
And registered DI in startup:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var builder = new ContainerBuilder();
builder.RegisterType<TestModel>().As<ITestModel>();
builder.Populate(services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
It works fine, but I've been wondering, what about if ill have twenty of those controllers and some 20 more logic classes with constructor with parameters with some interface do i need to register them in same manner, It would get really ugly in no time. So my question is, is it possible to register all controllers and classes that has only interfaces as parameters at once in this environment??
As the in comment was said, assembly scanning but with all referenced(filtered by interface of course), assembles did work as planned.
builder
.RegisterAssemblyTypes(typeof(HomeController).Assembly)
.AssignableTo<Controller>()
.InstancePerLifetimeScope()
.PropertiesAutowired();
Be sure to reference a Controller in your project (HomeController in this case)
ref

How to pass IOptions to an ASP.NET 5 middle-ware service?

I have started playing around with ASP.NET 5 vNext and I am struggling passing the options from config.json into a middle-ware service that is used by my WebApi controller.
Here is a snippet with my middle-ware service:
public class MyService : IMyService
{
public MyService(IOptions<MyOptions> settings)
{
var o = settings.Options;
}
}
Here is my WebApi controller that is using the middle-ware service:
public class MyController : Controller
{
private IMyService _myService;
public TestController(IMyService service)
{
_myService = service;
}
}
In Startup.cs I am reading the options:
services.AddOptions();
services.Configure<MyOptions>(Configuration);
What I am struggling with is how to register an instance to IMyService so that it would be passed to the constructor of the controller (how can I get a hold of the IOptions)?
services.AddInstance<IMyService>(new MyService(XXXXX));
As suggested below I did try to use both
services.AddTransient<MyService>();
and
services.AddSingleton<MyService>();
But in both cases I am seeing the following error:
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type
'MyApp.Services.IMyService' while attempting to activate
'MyApp.Controllers.TestController'.
Microsoft.Framework.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider
sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
Thanks for your help!
Don't register it as an Instance. Instead just add it as Scoped/Transient/Singleton depending on your requirements and let Dependency Injection do its magic;
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddScoped<IMyService, MyService>();
For example, you can to add to Startup.cs that code:
public void ConfigureServices(IServiceCollection services)
{
var builder = new ConfigurationBuilder("[path to file with configuration]");
builder.AddJsonFile("config.json");
var config = builder.Build();
services.AddOptions();
services.Configure<MyOptions>(config);
//services.AddSingleton<IMyService, MyService>();
services.AddTransient<IMyService, MyService>();
}
I can assure you that you can use Singleton or Transient.
If you're interested, you can find more info here https://github.com/aspnet/Docs/issues/24.
And additionally, currently Autofac creates DI for ASP.NET 5 on
http://alexmg.com/autofac-4-0-alpha-1-for-asp-net-5-0-beta-3/

ASP.NET 5 (VNext) Autofac Instance per Request

I'm playing around with ASP.NET vNext and I'd like to utilize InstancePerRequest for some of my registrations, e.g MyDbContext would be one example.
I've got Autofac running using InstancePerLifetimeScope for these dependencies. Which works....
But as soon as I change over to use InstancePerRequest I get this common error:
DependencyResolutionException: No scope with a Tag matching
'AutofacWebRequest' is visible from the scope in which the instance
was requested. This generally indicates that a component registered as
per-HTTP request is being requested by a SingleInstance() component
(or a similar scenario.) Under the web integration always request
dependencies from the DependencyResolver.Current or
ILifetimeScopeProvider.RequestLifetime, never from the container
itself.
I've read the Autofac help docs around this.... but I'm not sure how to set up the "request lifetime scope" which is causing this exception.
Has anyone set up an ASP.NET 5 web app integrating Autofac including InstancePerRequest?
You have two options as far as I know and both of them will give you the instance per request.
Assuming you have the below class to register:
public class Foo : IDisposable
{
public Foo()
{
Console.WriteLine("created");
}
public void Dispose()
{
Console.WriteLine("disposed");
}
}
Register with IServiceCollection
You can register the instance as scoped on IServiceCollection and build the Autofac container based on this.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddScoped<Foo, Foo>();
#if DNX451
// Create the autofac container
var builder = new ContainerBuilder();
// Create the container and use the default application services as a fallback
AutofacRegistration.Populate(builder, services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
#endif
return services.BuildServiceProvider();
}
Register on Autofac Builder
You can register the type on Autofac builder as instance per lifetime scope and this will give you the instance per request lifetime:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
#if DNX451
// Create the autofac container
var builder = new ContainerBuilder();
// Create the container and use the default application services as a fallback
AutofacRegistration.Populate(builder, services);
builder.RegisterType<Foo>().As<Foo>().InstancePerLifetimeScope();
var container = builder.Build();
return container.Resolve<IServiceProvider>();
#endif
return services.BuildServiceProvider();
}
As said, the result will be the same for both:
For more info per request instances on ASP.NET 5: Middlewares and Per Request Dependency Injection

Autofac OWIN TestServer and HttpContext

I am trying to setup Integration tests with my IIS Hosted WebAPI 2.2 application. I use Autofac for DI and I am using the new ASP.net Identity stack which uses OWIN. I am running into an issue with Autofac where the HttpContext class is always null. Here is how I am setting up my base integration test class-
[TestClass]
public class TestBase
{
private SimpleLifetimeScopeProvider _scopeProvider;
private IDependencyResolver _originalResolver;
private HttpConfiguration _configuration;
public TestServer Server { get; private set; }
[TestInitialize]
public void Setup()
{
Server = TestServer.Create(app =>
{
//config webpai
_configuration = new HttpConfiguration();
WebApiConfig.Register(_configuration);
// Build the container.
var container = App_Start.IocConfig.RegisterDependencies(_configuration);
_scopeProvider = new SimpleLifetimeScopeProvider(container);
//set the mvc dep resolver
var mvcResolver = new AutofacDependencyResolver(container, _scopeProvider);
_originalResolver = DependencyResolver.Current;
DependencyResolver.SetResolver(mvcResolver);
//set the webapi dep resolvers
_configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(_configuration);
app.UseAutofacMvc();
});
}
[TestCleanup]
public void Cleanup()
{
// Clean up the fake 'request' scope.
_configuration.Dispose();
DependencyResolver.SetResolver(_originalResolver);
_scopeProvider.EndLifetimeScope();
Server.Dispose();
}
}
When a simple test starts, I get an ArgumentNullException "Value cannot be null" httpContext. Which if I track down into the autofac code, I think it is coming from this extension method -
public static class AutofacMvcAppBuilderExtensions
{
internal static Func<HttpContextBase> CurrentHttpContext = () => new HttpContextWrapper(HttpContext.Current);
/// <summary>
/// Extends the Autofac lifetime scope added from the OWIN pipeline through to the MVC request lifetime scope.
/// </summary>
/// <param name="app">The application builder.</param>
/// <returns>The application builder.</returns>
[SecuritySafeCritical]
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
public static IAppBuilder UseAutofacMvc(this IAppBuilder app)
{
return app.Use(async (context, next) =>
{
var lifetimeScope = context.GetAutofacLifetimeScope();
var httpContext = CurrentHttpContext();
if (lifetimeScope != null && httpContext != null)
httpContext.Items[typeof(ILifetimeScope)] = lifetimeScope;
await next();
});
}
}
loacted in the Core/Source/Autofac.Integration.Mvc.Owin/AutofacMvcAppBuilderExtensions.cs file. Is there a problem with my setup, or a proper way to use Autofac in integration tests with a WebApi application using IIS Host and OWIN Middleware?
It appears you already asked this as an issue over on the Autofac project. I'll copy/paste the answer here (though in the future it'd probably be better to go with one or the other and not both).
Part of the awesomeness of OWIN-only apps is that you don't need HttpContext anymore. Nothing is tied to that; instead, it's all HttpContextBase and things that are separate from the legacy IIS. Like, in Web API, the current context is always shipped around with the HttpRequestMessage - there's no global static HttpContext.Current because that's legacy stuff.
Thus, when you run unit tests with an OWIN test host, you can expect there to not be an HttpContext.Current. It's decoupled from all that.
MVC can't run as OWIN-only because the libraries are tightly coupled to the legacy IIS/ASP.NET stack. Trying to test MVC stuff using an OWIN-only test server is going to give you trouble like this. That will change with the new ASP.NET 5.0 coming out with the new Visual Studio.
If you need to test MVC in an integrated way, there isn't a way to do that with OWIN right now. You have to fire up IIS Express.
Finally, I do see that you're missing the Web API middleware for OWIN (the actual Microsoft Web API middleware). That might give you other problems down the line.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(_configuration);
app.UseAutofacMvc();
// You're missing this:
app.UseWebApi(config);

How to plug my Autofac container into ASP. NET Identity 2.1

I have been looking into the new features of the new version of ASP.NET Identity 2.1 and one of its enhancements is the new IoC features integrated into the OWIN Middleware.
One of the sentences that I looked in the examples is this one:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
This sentence receives a function delegate which returns a new instance of a manager implementation provided on the examples:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
I personally dont like this implementation because I am not able to use a container to inject any dependency that I want for these managers.
Also there is an "IdentityFactoryOptions" and a "IOwinContext" that are "magically" injected to the function which Im not able to pull out into my IoC container.
Do anyone have a better workaround on this implementation?
I'm starting from an out-of-the-box MVC5 installation and using AutoFac as an IoC container. It sounds like I am trying to acheive a similar goal as you, so let me explain what I've done. As a disclaimer, I am fairly new to using IoC and to Identity.
I believe the IOwinContext is unnecessary in a role as an IoC if you are using your own - I switched over to registering my ApplicationUserManager with AutoFac. To achieve this I had to:
Remove CreatePerOwinContext lines from Startup.Auth since I'll register ApplicationDbContext and ApplicationUserManager in AutoFac.
//app.CreatePerOwinContext(ApplicationDbContext.Create);
//app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
Modify the ApplicationUserManager constructor arguments and included everything from the Create function.
public ApplicationUserManager(IUserStore<ApplicationUser> store, IdentityFactoryOptions<ApplicationUserManager> options)
: base(store)
{
//all the code from the 'Create' function here, using `this` for `manager`
}
Set the AccountController to have a single constructor taking an ApplicationUserManager as an argument and scrapped the UserManager property that grabs the ApplicationUserManager from the OwinContext.
private ApplicationUserManager _userManager; //every thing that needs the old UserManager property references this now
public AccountController(ApplicationUserManager userManager)
{
_userManager = userManager;
}
Register everything with AutoFac, including an instance of IdentityFactoryOptions.
var x = new ApplicationDbContext();
builder.Register<ApplicationDbContext>(c => x);
builder.Register<UserStore<ApplicationUser>>(c => new UserStore<ApplicationUser>(x)).AsImplementedInterfaces();
builder.Register<IdentityFactoryOptions<ApplicationUserManager>>(c => new IdentityFactoryOptions<ApplicationUserManager>()
{
DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ApplicationName")
});
builder.RegisterType<ApplicationUserManager>();
That's the rough summary. I may have missed a couple of other tweaks I had to do along the way.
Ben's answer gets the general idea right, but it manually instantiates the DbContext and uses this instance when registering the rest of the types. IMO, that's a bad idea (one shouldn't use the same eternal db context for ALL requests).
Derek's comment is a big improvement, but it doesn't pass the database context to the user store, resulting in errors such as "The entity type ApplicationUser is not part of the model for the current context.".
I've included my code below, for reference - it's really similar to Derek's.
builder.RegisterType<MyApplicationContext>().AsSelf().InstancePerRequest()
//...
builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
builder.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerRequest();
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<MyApplicationContext>())).AsImplementedInterfaces().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("Application​")
});
For reference here's how you can wire everything up using Unity:
var container = new UnityContainer();
container.RegisterType<MyDbContext>(new InjectionConstructor("ConnectionStringName"));
container.RegisterType<IAuthenticationManager>(
new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
new InjectionConstructor(typeof(MyDbContext)));
container.RegisterType<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>(
new InjectionConstructor(typeof(MyDbContext)));
container.RegisterType<IdentityFactoryOptions<ApplicationUserManager>>(new InjectionFactory(x =>
new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ApplicationName")
}));
container.RegisterType<ApplicationSignInManager>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Now detailed for MVC5 Owin integration on Autofac Docs:
"
Do all the stuff for standard MVC integration - register controllers, set the dependency resolver, etc.
Set up your app with the base Autofac OWIN integration.
Add a reference to the Autofac.Mvc5.Owin NuGet package.
In your application startup class, register the Autofac MVC middleware after registering the base Autofac middleware.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// STANDARD MVC SETUP:
// Register your MVC controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly);
// Run other optional steps, like registering model binders,
// web abstractions, etc., then set the dependency resolver
// to be Autofac.
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// OWIN MVC SETUP:
// Register the Autofac middleware FIRST, then the Autofac MVC middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
}
"
I also have RoleManager wrapper so added:
builder.RegisterType<RoleStore<IdentityRole>>().As<IRoleStore<IdentityRole, string>>();
as per SO answer
I managed the workaround by using autofac service locator:
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
Yes, it is not good enough, but in the mean time, we could use object same scope as declared in autofac registration process.

Resources