patterncsharpMinor
MembershipProvider with Entity Framework and IoC
Viewed 0 times
iocwithmembershipproviderandframeworkentity
Problem
I am using Castle Windsor as my IoC container and I registered it as a
With the Entity Framework I have this
In Castle Windsor it is registered as per web request:
Because I don't have control over creating the
I wrote this as a solution:
And I registered like this:
Now I can create a
```
public class MyMembershipProvider : MembershipProvider
{
IDoInContext db;
public MyMembershipProvider()
: this(DependencyResolver.Current.GetService>())
{ }
public MyMembershipProvider(IDoInContext db)
{
this.db = db;
}
public override bool ValidateUser(string username, string password)
{
bool result = false;
db.DoInContext(x => {
var encodedPassword = encodePassword(password);
result = x.Users.Any(y => y.Login == username &&
y.Password == encodedPassword);
}
DependencyResolver to let the MVC framework know about it. With the Entity Framework I have this
DbContext:public class MyDbContext : DbContext
{
public DbSet Users { get; set; }
}In Castle Windsor it is registered as per web request:
container.Register(
Component.For()
.ImplementedBy()
.LifestylePerWebRequest()
);Because I don't have control over creating the
MyMembershipProvider object, this object is created once per web application so it is not possible to inject DbContext directly, because it will be disposed when the web request ends.I wrote this as a solution:
public interface IDoInContext
{
void DoInContext(Action action);
}
public class DoInMyDbContext : IDoInContext
{
IKernel _kernel;
public DoInMyDbContext(IKernel kernel)
{
_kernel = kernel;
}
public void DoInContext(Action action)
{
var context = _kernel.Resolve();
action(context);
_kernel.ReleaseComponent(context);
}
}And I registered like this:
container.Register(
Component.For>()
.ImplementedBy()
.LifestyleSingleton()
);Now I can create a
MyMembershipProvider which will be able to interact with the current and correct DbContext every time it needs:```
public class MyMembershipProvider : MembershipProvider
{
IDoInContext db;
public MyMembershipProvider()
: this(DependencyResolver.Current.GetService>())
{ }
public MyMembershipProvider(IDoInContext db)
{
this.db = db;
}
public override bool ValidateUser(string username, string password)
{
bool result = false;
db.DoInContext(x => {
var encodedPassword = encodePassword(password);
result = x.Users.Any(y => y.Login == username &&
y.Password == encodedPassword);
}
Solution
The preferred method of doing this is to use a factory dependency that creates the DbContext for you. So instead of the DbContext as the dependency you have a ContextFactory as the dependency and its consumers can get and manage a local DbContext by calling
If you insist on having your context injected directly, I believe it would be much better to have your MembershipProvider be registered per web request (even though you don't have control over creating it, you still have to register it right?). It shouldn't be a bottleneck. From a design and testing perspective this is much preferred to having a hard dependency on a service locator. How will you test the class by itself? Would you be incorporating your service locator into your tests?
contextFactory.CreateContext();If you insist on having your context injected directly, I believe it would be much better to have your MembershipProvider be registered per web request (even though you don't have control over creating it, you still have to register it right?). It shouldn't be a bottleneck. From a design and testing perspective this is much preferred to having a hard dependency on a service locator. How will you test the class by itself? Would you be incorporating your service locator into your tests?
Context
StackExchange Code Review Q#20735, answer score: 2
Revisions (0)
No revisions yet.