I try to create a factory for entity framework contexts.
In a PersonDataService (in the assembly DataService) I want to have the following method:
public void GetPerson(int id)
{
using(var context = this.contextFactory.Create<IPersonContext>())
{
var personRepository = this.repositoryFactory.Create<IPersonRepository>(context);
return personRepository.Get(id);
}
}
In our project, there is an assembly called DependencyInjection where we setup all of our unity config so this assembly has references to alot of projects including the assembly DataAccess where entity framework is.
The ContextFactory should look something like this:
public class ContextFactory : IContextFactory
{
public T Create<T>() where T : IDbContext
{
return UnityConfig.GetConfiguredContainer().Resolve<T>();
}
}
The assembly DependencyInjection also has a reference of the assembly DataService.
DataService <-- DependencyInjection
^ ^
| |
DataAccess --------------
ContextFactory
in the assembly DependencyInjection (because I need Unity) I can't use it in the DataService.ContextFactory
in the assembly DataAccess, I can't use Unity in the factoryWhat is the best way to resolve this cyclic reference problem?
Thanks in advance
Edit: The reason I want to introduce the ContextFactory
is, that I want to use an InMemoryContext in my acceptance test and to be able to setup a fake of the ContextFactory
to return this InMemoryContext when a call to Create<T>
happens
Ok, I think, problem is in decision to have one assembly for container configuration. I don't see a lot of benefits.
As a solution, I can advice you to use following project structure:
Assemply 1:
public interface ISecurityService
{
SignInStatus SignIn(string email, string password, bool isPersistent);
void SignOut();
}
Assembly 2:
internal sealed class SecurityService : ISecurityService
{
private readonly SignInManager<User, long> _signInManager;
public SecurityService(SignInManager<User, long> signInManager)
{
_signInManager = signInManager;
_signInManager.UserManager.UserValidator = new UserValidator<User, long>(_signInManager.UserManager)
{
AllowOnlyAlphanumericUserNames = false
};
}
public SignInStatus SignIn(string email, string password, bool isPersistent)
{
var status = _signInManager.PasswordSignIn(email, password, isPersistent, shouldLockout: false);
return status;
}
public void SignOut()
{
_signInManager.AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie,
DefaultAuthenticationTypes.TwoFactorCookie);
}
}
public sealed class ApplicationExtension : UnityContainerExtension
{
protected override void Initialize()
{
Container.RegisterType<IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));
Container.RegisterType<IPrincipal>(new InjectionFactory(c => HttpContext.Current.User));
Container.RegisterType<ISecurityService, SecurityService>(new PerRequestLifetimeManager());
}
}
Assembly 3:
public class UnityConfig
{
public static void RegisterTypes(IUnityContainer container)
{
var container = new UnityContainer();
container.AddExtension(new ApplicationExtension());
//use container
}
}
Advantages: