I am a newbie in ASP.NET, and currently learning ASP.NET Identity. I know it\'s built on top of OWIN implementation by Microsoft, and I am also still learning that too. So,
you may use typeof
to get the name like this:
HttpContext.GetOwinContext().Get<ApplicationDbContext>(typeof(ApplicationDbContext).ToString());
CreatePerOwinContext registers a static callback which your application will use to get back a new instance of a specified type.
This callback will be called once per request and will store the object/objects in OwinContext so that you will be able to use them throughout the application.
Let's say you have defined your own implementation of IdentityDbContext:
public class ApplicationDatabaseContext : IdentityDbContext<MyApplicationUser, MyRole, Guid, MyUserLogin, MyUserRole, MyUserClaim>
{
public ApplicationDatabaseContext() : base("<connection string>")
{
}
public static ApplicationDatabaseContext Create()
{
return new ApplicationDatabaseContext();
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Customize your table creation here.
#region USERS - INFOS
modelBuilder.Entity<UserInfo>()
.Property(p => p.FirstName)
.HasColumnType("varchar")
.HasMaxLength(70);
modelBuilder.Entity<UserInfo>()
.Property(p => p.LastName)
.HasColumnType("varchar")
.HasMaxLength(70);
modelBuilder.Entity<UserInfo>()
.Property(p => p.Address)
.HasColumnType("varchar")
.HasMaxLength(100);
modelBuilder.Entity<UserInfo>()
.Property(p => p.City)
.HasColumnType("varchar")
.HasMaxLength(100);
modelBuilder.Entity<UserInfo>()
.ToTable("UsersInfo");
#endregion
}
public DbSet<UserInfo> UsersInfo { get; set; }
}
and your implementation of UserManager:
public class ApplicationUserManager : UserManager<MyApplicationUser, Guid>
{
public ApplicationUserManager(IUserStore<MyApplicationUser, Guid> store) : base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new MyUserStore(context.Get<ApplicationDatabaseContext>()));
manager.UserValidator = new UserValidator<MyApplicationUser, Guid>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
manager.PasswordValidator = new PasswordValidator()
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
// RequireDigit = true,
RequireLowercase = false,
RequireUppercase = false,
};
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<MyApplicationUser, Guid>(dataProtectionProvider.Create("PasswordReset"));
}
return (manager);
}
}
In your Owin Startup you will register the callback:
// IAppBuilder app
app.CreatePerOwinContext<ApplicationDatabaseContext>(ApplicationDatabaseContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
which will call the static method:
public static ApplicationDatabaseContext Create()
{
return new ApplicationDatabaseContext();
}
and
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
...
}
Now you will be able to access your database context and user manager in a simple straightforward way:
ApplicationDatabaseContext dbContext = context.OwinContext.Get<ApplicationDatabaseContext>();
ApplicationUserManager userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
In your ApiController (if you're using WebApi):
IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
ApplicationUserManager applicationUserManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
What is the real purpose of the method? In what case it should be applied?
To answer your question more directly, this is useless.
Get
, it takes you nowhere helpful.What should you do instead then?
Personally, I'm a fan of using OO for this, remember OO? Pepperidge farm remembers. With OO, you remain in control, you can debug, log, and you can extend.
public class BaseApiController : ApiController
{
private AppDbContext _db = null;
protected AppDbContext db
{
get
{
if (_db == null)
{
_db = AppDbContext.Create(); //Hey look a proper factory that you can extend with other overloads! And I can debug this line - neat!
}
return _db;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_db != null)
_db.Dispose();
}
}
}
All this could be a waste of time, if someone finds some documentation why Microsoft engineers put this in, they might have a good reason why, but I doubt it, so let's upvote this answer in the meantime.
UPDATE 1
Here's the why, why it's there for Microsoft: https://blogs.msdn.microsoft.com/webdev/2014/02/12/per-request-lifetime-management-for-usermanager-class-in-asp-net-identity/
Basically, the UserManager and all them are built for this kind of structure. The Security checks occur in the pipeline, so why not have a singleton linked to the request, to reduce waste? Because it's hidden.
I would still recommend creating your own instance of the db context on a baseclass, it makes it much cleaner to use. If you really want, you can have a property in your baseclass which retrieves the singleton from the OwinContext.
How much time do we waste trying to work out these fancy APIs, and Authorise attributes and the like, when all we want to do is:
public void DoSomething()
{
DemandAuthenticated();
DemandAuthorised(typeof(somethingClass), "DoSomething");
}
Clearly, I prefer verbose code you can see.
Update 2
EF contexts should not be held as singletons, and certainly not through any IoC or repository pattern.
Generally, yes IoC can be good in situations. But specifically for a dbContext? No.
1) EF DB contexts are a unit of work, they should be short-lived. If you keep them running for a long time, the object cache will slow down queries, and updates/inserts to the underlying database get slower. It's designed to have short lifetime. 2) Also, EF contexts are already loosely coupled. You can change the RDBMS behind a context in the connection string, you can even use memory-only. 3) EF has LINQ which is very flexible, expressive, and type safe. 4) Database is not a business-level service for IoC it's a tool that services use to communicate with the database. Perhaps, You might have some kind of service IEmail that is accessed via IoC. But it should access the internal database using a new EF context that is disposed promptly after completion of queries. 5) Given 1-4 above, we certainly don't want any intermediate Interface layers (Service or Repository) to spoil all the benefits of using EF in the first place.