[英]How to use DI(AutoFac) with a Service Layer
我有一個使用 3 層模式的 MVC 應用程序:DAL <-> 服務 <-> UI,我正在嘗試添加 AutoFac 來測試我的 MVC 控制器和服務。
幾個問題:
1) 如何使用 AutoFac 告訴我的服務層使用特定上下文? 目前我正在使用builder.Register(c => c.Resolve<IRepo>()).As<Repo>();
但這會將 IRepo 暴露給 UI,這將允許他們繞過服務層驗證和業務規則。
2) 除了構造函數標識要使用的上下文之外,Repo 和 MockRepo 是相同的。 它在那里是因為 UI 沒有對 DAL 的引用,所以我無法傳入 IDataContext。 有沒有辦法刪除冗余代碼/類並仍然能夠使用 DI?
/* DAL */
public interface IDataContext
{
T GetById<T>(int Id);
}
// Entity Framework context
public class EFContext : DbContext, IDataContext
{
public EFContext() : base("MyConnectionString")
{...}
public T GetById<T>(int Id)
{...}
}
// In-memory context for testing
public class MockContext : IDataContext
{
public MockContext()
{...}
public T GetById<T>(int Id)
{...}
}
/* Service */
public interface IRepo
{
T GetById<T>(int id);
}
// Entity Framework Repo
public class Repo
{
private IRepo _repo;
public Repo()
{
_repo = new EFContext();
}
public T GetById<T>(int Id)
{
return _repo.GetById<T>(Id);
}
}
// In-memory Repo
public class MockRepo : RepoBase
{
private IRepo _repo;
public MockRepo()
{
_repo = new MockContext();
}
public T GetById<T>(int Id)
{
return _repo.GetById<T>(Id);
}
}
// Service to be used in the UI
public class StudentService
{
public StudentService(IRepo repo)
{
_repo = repo;
}
public void ExpelStudent(int studentId)
{
var student = _repo.GetById(studentId);
...
_repo.Save();
}
}
根據您的評論,您將按以下方式構建項目。
解決方案項目(參考鏈):
因此,您將主要項目與所有其他 .dll 相關聯。 除了充當數據層的中介外,服務層不關心任何事情,因此是依賴關系。 那么你的數據層不應該關心你的域模型之外的任何東西。
除非您執行 Clean Architecture / Onion Architecture,在其中松散地加載 .dll 而不是存儲硬引用。
有了上面的結構,你就有了一個基本的基礎,除非你這樣做了。
public class SampleContext : ISampleRepository
{
public IEnumerable<SampleModel> GetAllSamples() => dbConnection.ExecuteQuery(query); // Dapper syntax, but you get the idea
// Implement Dispose
}
public interface ISampleRepository : IDispose
{
IEnumerable<SampleModel> GetAllSamples();
}
然后你建立你的工廠。
public class SampleFactory : ISampleFactory
{
public ISampleRepository CreateSample() => new SampleContext();
}
public interface ISampleFactory
{
ISampleRepository CreateSample();
}
關鍵是,如果您使用 DI 容器,則框架希望將 DI 框架與相關配置一起注冊到全局文件中。 這存在於您的頂級結構中。 因此,如果沒有容器,您的服務層可以簡單地完成。
public class SampleService
{
public IEnumerable<SampleModel> GetAllSamplesFromDb()
{
using(var context = new SampleFactory().CreateSample())
return context.GetAllSamples();
}
}
沒有依賴注入,但這需要服務層對關聯哪個工廠有一些具體的了解。 所以每種方法都會創建一個工廠,這可能是多余的。
因此,您的 DI 框架容器將使上述服務如下所示。
public class SampleService
{
private ISampleFactory factory;
public SampleService(ISampleFactory factory) => this.factory = factory;
public IEnumerable<SampleModel> GetAllSamplesFromDb()
{
using(var context = factory.CreateSample())
return context.GetAllSamples();
{
}
因此,在 DI 容器的配置中,您將按照這些行注冊一些內容。
builder.RegisterType<SampleFactory>().As<ISampleFactory>();
var container = builder.Build();
現在,我對 Autofac 不是很熟悉,因為我在 Core 中使用了 Unity、Ninject 或 default。 但是你會告訴頂部解決方案中的容器,所以你可以像我顯示的那樣引用。
希望這對你有幫助。 但是您需要稍微比較我的語法以確保使用正確的 Autofac 語法進行注冊。 但是結構和一般概念應該是一樣的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.