简体   繁体   中英

Entity Framework Context Factory And Cyclic References

I try to create a factory for entity framework contexts.

1. Goal

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);
    }
}

2. Given

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 .

3. Problem

DataService <-- DependencyInjection
^ ^
| |
DataAccess --------------

  • If I place the ContextFactory in the assembly DependencyInjection (because I need Unity) I can't use it in the DataService .
  • If I place the ContextFactory in the assembly DataAccess , I can't use Unity in the factory

What 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:

  1. Create an assembly with public interfaces
  2. Create an assembly with internal implementations of interfaces
  3. Confugure Unity-container in assembly 2
  4. Expose Unity-container configuration with UnityContainerExtension class

Example

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:

  1. Your interfaces are public and separated from implementation
  2. Implementation is internal and can be used only via interface
  3. You expose configured container from assembly

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM