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);
Related
I Need to initiate the password reset from my web api. I have identity server application and web api applications separately. I use OIDC client to communicate with identity server. With this client I can only call signin, signout and some standard methods.
What I need is to generate password reset token and get the reset token in API.
I have tried to include 'Microsoft.Extensions.Identity.Core' in my webapi core layer which have all the entities. But I get
Unable to resolve service for type
Microsoft.AspNetCore.Identity.IUserStore1[Application.Core.Entities.User]
while attempting to activate 'Microsoft.AspNetCore.Identity.UserManager
code
private readonly UserManager<User> _userManager;
public AccountController(UserManager<User> userManager)
{
_userManager = userManager;
}
private async Task<string> GeneratePasswordResetLinkAsync(User user)
{
string token = await _userManager.GeneratePasswordResetTokenAsync(user);
return token;
}
I've also tried adding below code in startup Injection
services.AddScoped<UserManager<User>, UserManager<User>>();
What is the proper way of injecting UserManager in my web api ?
You need to configure asp.net core identity in the Startup class of you web api. Unfortunately you can not simply call services.AddIdentity(... in ConfigureServices because behind the scenes a cookie-based authentication scheme is registered and set as the default challenge scheme, as you can see in the code here for asp.net core 2.2
or here for asp.et core 3.1.
Thus the solution I end up with is to copy & update AddIdentity method like this:
For ASP.NET CORE 2.2:
public static IdentityBuilder AddIdentityForWebApi<TUser, TRole>(
this IServiceCollection services,
Action<IdentityOptions> setupAction)
where TUser : class
where TRole : class
{
// Hosting doesn't add IHttpContextAccessor by default
services.AddHttpContextAccessor();
// Identity services
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
services.TryAddScoped<UserManager<TUser>>();
services.TryAddScoped<SignInManager<TUser>>();
services.TryAddScoped<RoleManager<TRole>>();
if (setupAction != null)
{
services.Configure(setupAction);
}
return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
}
For ASP.NET CORE 3.1:
static IdentityBuilder AddIdentityForWebApi<TUser, TRole>(
this IServiceCollection services,
Action<IdentityOptions> setupAction)
where TUser : class
where TRole : class
{
// Hosting doesn't add IHttpContextAccessor by default
services.AddHttpContextAccessor();
// Identity services
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<TUser>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
services.TryAddScoped<IUserConfirmation<TUser>, DefaultUserConfirmation<TUser>>();
services.TryAddScoped<UserManager<TUser>>();
services.TryAddScoped<SignInManager<TUser>>();
services.TryAddScoped<RoleManager<TRole>>();
if (setupAction != null)
{
services.Configure(setupAction);
}
return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
}
Then you should call AddIdentityForWebApi in the Startup of your web api application.
This will register the UserManager and it will now be injected in your controller's constructor.
Then you should configure Data Protection API (DPAPI) properly so that the token generated by your web api (when you call _userManager.GeneratePasswordResetTokenAsync... from your question) could be unprotected by your identity server application.
So I set the "DPAPI application name" across the two applications, in both ConfigureServices methods:
services.AddDataProtection()
.dataProtectionBuilder.SetApplicationName("YOUR_DPAPI_APPLICATION_NAME");
For production, in a web farm environment, you will have to share the DPAPI keys. Depending on your situation you have several options.
Please refer to the official documentation for more details on how to configure DPAPI.
I have tested on Kestrel running Windows, I am not sure about IIS.
The injection code does not look correct. Try changing it to
services.AddScoped<UserManager<Application.Core.Entities.User>>();
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'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
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.
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.