私の問題を解決するためにStackOverflowを見回しました。私はこれが独特の問題だとは思わないが、良い解決策を見つけることができていない。名前付きUnity登録の種類を条件付きでインスタンス化する方法
私のWPFアプリケーションでは、私のビューモデルで、いくつかのデータを返すためにいくつかのサービスを呼び出す必要があります。これらのサービスは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:私のシナリオでどのように表示されるのかを教えてください。それが助けになるだろう。ありがとう。 –