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.
Related
I'm currently working on a Xamarin.Forms application using Prism and Unity as my IoC container.
I'm also attempting to add the business logic framework CSLA to my application.
There is a Xamarin sample provided here:
https://github.com/MarimerLLC/csla/blob/main/Samples/XamarinExample/XamarinExample/XamarinExample/App.xaml.cs
In particular, everything seems to be wired up using this piece of code:
public App()
{
InitializeComponent();
var services = new ServiceCollection();
services.AddCsla();
services.AddTransient(typeof(DataAccess.IPersonDal), typeof(DataAccess.PersonDal));
serviceProvider = services.BuildServiceProvider();
ApplicationContext = serviceProvider.GetRequiredService<ApplicationContext>();
MainPage = new AppShell();
}
I'm trying to figure out how to fit that sort of code / registration into the Prism framework with Unity as the IoC container. Is this a time when I'd need to use the extensions? I saw those, but I was still coming up a little short on understanding what I should be doing.
I feel like there's a fundamental misunderstanding on my part of what I should be trying to achieve here, so any guidance on what direction I should be going in would be great.
You have to dig into AddCsla() and replicate all the registrations that are done in there.
The rest is easy:
services.AddTransient(typeof(DataAccess.IPersonDal), typeof(DataAccess.PersonDal));
ApplicationContext = serviceProvider.GetRequiredService<ApplicationContext>();
is trivial to translate to Unity
unityContainer.RegisterType<DataAccess.IPersonDal, DataAccess.PersonDal>();
ApplicationContext = unityContainer.Resolve<ApplicationContext>();
or Prism's "abstraction layer"
containerRegistry.Register<DataAccess.IPersonDal, DataAccess.PersonDal>();
ApplicationContext = containerRegistry.Resolve<ApplicationContext>();
I think this may be what I'm looking for:
protected override IContainerExtension CreateContainerExtension() {
var containerExtension = base.CreateContainerExtension();
var services = new ServiceCollection();
services.AddCsla();
var serviceProvider = ((UnityContainerExtension)containerExtension).Instance.BuildServiceProvider(services);
ApplicationContext = serviceProvider.GetRequiredService<ApplicationContext>();
return containerExtension;
}
Basically, it seems that I can override the container creation in my app.cs. From there I can call whatever methods I'd like against the ServiceCollection, build the container using the extension (in this case Unity) and return that container to the application.
Testing this in code I can see that I'm now able to inject the IDataPortalFactory into my view model along with the IServiceProvider, and the IServiceProvider is of type Unity.Microsoft.DependencyInjection.ServiceProvider.
public MainPageViewModel(
INavigationService navigationService,
IServiceProvider serviceProvider,
IDataPortalFactory dataPortalFactory,
ITestClassFactory testClassFactory)
: base(navigationService) {
Title = "Main Page";
this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
this.dataPortalFactory = dataPortalFactory ?? throw new ArgumentNullException(nameof(dataPortalFactory));
this.testClassFactory = testClassFactory ?? throw new ArgumentNullException(nameof(testClassFactory));
}
So, if I'm getting IDataPortalFactory in my view model, I'm assuming my call to AddCsla() worked, and if the IServiceProvider is considered to be a Unity service provider, I must have successfully replaced the Service Provider implementation.
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
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);
I try to separate one of my API projects into three different layers.
The API
Data access(repos + uow)
Data Entities
The API is using Asp.net Identity 2.0 with code from a sample I installed, just enough to work with OAuth Authorization.
However, When I do this separation, sometimes I get an error telling me that I need to reference the third layer(entities) from my first layer. And I can't figure out why. That would break the whole purpose of the separation, right?
For example, when I try to replace this line(from the API layer in Startup.Auth.cs, ConfigureAuth method)
app.CreatePerOwinContext(ApplicationDbContext.Create);
With
app.CreatePerOwinContext(uow.CreateDbContext())
A method that returns a new instance of the ApplicationDbContext.
I would expect that context to be returned from my second layer, where my UnitOfWork is(which in turn gets the ApplicationDbContext from the data layer).
Could someone please explain how this works?
To solve your issue you need to start use Interfaces and any DI-framework. Here I can provide you with the code if you want to start using AutoFac (https://code.google.com/p/autofac/wiki/WebApiIntegration).
When you installed AutoFac to your solution through Nuget. Add this part of code in your Global.asax.cs file.
protected void Application_Start()
{
...
SetupAutoFac();
...
}
private static void SetupAutoFac()
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
var container = builder.Setup();
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
Create this part of code in your BLL-layer:
public static class AutoFacConfiguration
{
public static IContainer Setup(this ContainerBuilder builder)
{
REGISTER ALL YOUR SERVICES AND UOW HERE
return builder.Build();
}
}
After this you can inject every services Interface to your ApiControllers, and the the WebAPi will only have a reference to your BLL-layer or to the layer where you put all your interfaces.
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).