我已经浏览了StackOverflow以解决我的问题。虽然我不认为这是一个独特的问题,但我一直无法找到一个好的解决方案。如何有条件地实例化一个命名的Unity注册类型
在我的WPF应用程序中,在我的viewmodels中,我需要调用一些服务来返回一些数据。这些服务被注入UnitOfWork,后者又被注入了DbContext。这个注入UnitOfWork的dbcontext应该根据一些标准而有所不同。
我在正确地做IoC容器注册并在运行时注入正确的DbContext时遇到了问题。所以,如果有人可以填写空白(在统一注册以及它的用法)。我在下面的代码中有一些内联注释,在这里我遇到了麻烦并且需要帮助。谢谢。
如果有人能以正确的方式替换我的注册码,并教育我如何在我的WPF ViewModel类中使用它,那真是太棒了!谢谢。
最后一个注意事项:如果您在此代码中发现编码错误,请不要开始想知道如何编译?这里的代码不是我真正的代码。为了简化事情,我只是写了起来。但它确实非常类似于我的真实应用程序代码。
public interface IDBContext{}
public interface IUnitOfWork{}
public interface ISomeEntityService{}
public interface IRepository<T> where T : class
{ T GetSingle(Expression<Func<T, bool>> predicate); }
public class DBContext1 : IDBContext
{
public DBContext1(connString) : base(connString){}
}
public class DBContext2 : IDBContext
{
public DBContext2(connString) : base(connString){}
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDBContext context;
private readonly IDbSet<T> dbSet;
public Repository(IDBContext ctx)
{
context = ctx;
dbSet = ((DbContext)context).Set<T>();
}
public T GetSingle(Expression<Func<T, bool>> predicate)
{
return ((DbContext)context).Set<T>().SingleOrDefault(predicate);
}
}
public class UnitOfWork : IUnitOfWork
{
IDBContext ctx;
private Dictionary<string, dynamic> repositories;
public UnitOfWork(IDBContext context)
{
ctx = context;
}
public IRepository<T> Repository<T>() where T : class
{
if (repositories == null)
repositories = new Dictionary<string, dynamic>();
var type = nameof(T);
if (repositories.ContainsKey(type))
return (IRepository<T>)repositories[type];
var repositoryType = typeof(Repository<>);
repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(T)), ctx));
return repositories[type];
}
public int SaveChanges()
{
return ctx.SaveChanges();
}
}
public class MyUnityBootstrapper : UnityBootstrapper
{
protected override void ConfigureContainer()
{
Container.RegisterType<IDBContext, DBContext1>("Context1");
Container.RegisterType<IDBContext, DBContext2>("Context2");
Container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
Container.RegisterType<IUnitOfWork, UnitOfWork>();
}
}
public class SomeEntityService : ISomeEntityService
{
private IUnitOfWork uow;
public ConsumerService(IUnitOfWork _uow)
{ uow = _uow; }
public SomeEntity GetSomeData(int id)
{
return uow.Repository<SomeEntity>().GetSingle(x => x.Id == id);
}
}
public class SomeViewModel : BindableBase
{
private readonly ISomeEntityService someService;
public SomeViewModel(ISomeEntityService _someService)
{
// when I call someService, I want to make sure it is using either
// DBContext1 or DBContext2 based on some condition I can set here.
// This is where I am totally stuck.
someService = _someService;
}
// get the repository instance with an id of 1000
someService.GetSomeData(1000);
}
/*
I could do something like this. But I am afraid, I am violating
two of the best practices recommendations.
1. I am creating a dependency to my IoC Container here.
2. I am using the container as a Service Locator
*/
public class SomeViewModel : BindableBase
{
private readonly ISomeEntityService someService;
public SomeViewModel()
{
var container = SomeHowGetTheContainer();
/*
1. Call Container.Resolve<IDBContext>(with the required context);
2. Use the retrieved context to inject into the UnitOfWork
3. Use the retrieved UnitOfWork to inject into the service
But that would be like throwing everything about best practices to the wind!
*/
someService = container.Resolve<ISomeEntityService>(/*do some magic here to get the right context*/)
}
// get the repository instance with an id of 1000
someService.GetSomeData(1000);
}
我会在抽象工厂实现中隐藏对容器的调用。工厂依赖容器是可以的。 – Haukinger
@Haukinger:在我的场景中,您可以请包括一些代码来告诉我如何?这将有所帮助。谢谢。 –