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.