簡體   English   中英

如何在服務層中使用 DI(AutoFac)

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM