簡體   English   中英

從ASP.NET MVC中的參數解析依賴項

[英]Resolving dependencies from parameters in asp.net mvc

這里是接口和類(例如):

public IReportGenerator
{
    string Build();
}

public interface IPersonReportGenerator : IReportGenerator

public class PersonReportGenerator : IPersonReportGenerator 
{
  private readonly int _personId;
  private readonly IPersonDb _personDb;

  public PersonReportGenerator(IPersonDb personDb, int personId)
  {
    _personDb = personDb;
    _personId = personId;
  }

  public string Build()
  {
    // get data with _personId;
    return "Person Report";
  }
}

public interface ICarReportGenerator : IReportGenerator

public class CarReportGenerator : ICarReportGenerator 
{
  private readonly guid _make;
  private readonly guid _model;
  private readonly ICarDb _cardDb;

  public CarReportGenerator (ICarDb cardDb, guid make, guid model)
  {
    _cardDb = cardDb;
    _make = make;
    _model = model;
  }

  public string Builder()
  {
    // get data with _make and _model;
    return "Car Report";
  }
}

消耗者:

// MVC ActionResult to encapsulate the response for a report
public class ReportResult : ActionResult
{
  public ReportResult(IReportGenerator rg)
  {
  }
}

這就是我注冊這些的方式:

containerBuilder cb;

cb.RegisterType<PersonReportGenerator >()
  .As<IPersonReportGenerator >();

cb.RegisterType<CarReportGenerator>()
  .As<ICarReportGenerator>();

現在在我的動作結果中..而且很丑:

public ActionResult GetReport(int personId)
{
  var report = 
    ((AutoFacDependencyResolver)DependencyResolver.Current)
    .ApplicationContainer.Resolve<PersonReportGenerator>(
      new NamedParameter("personId", personId)
    );

  return new ReportResult(report);
}

有沒有更干凈的方法可以使用MVC / Autofac解決此類依賴關系?

如果您不能更改此界面:

public interface IPersonReportGenerator : IReportGenerator

public IReportGenerator
{
    string Build();
}

然后,這就產生了一個問題。 根據定義,界面定義了您與類進行交互的方式。 挑戰在於您需要向其傳遞一個personID ,但是接口不允許它。 因此,實際上該接口並沒有真正定義該類需要做什么。

如果你是不是在更改接口(別的東西已經依賴於它),那么你可以做什么我們做與遺留代碼的位置-敷在界面,我們確實需要。 但這並不能解決問題。 它只是圍繞它創建了一個抽象,因此我們不必不斷處理問題。

public interface IPersonReportGeneratorV2 //Or some better name
{
    string GetReport(IPersonDb personDb, int personId);
}

public class LegacyPersonReportWrapper : IPersonReportGeneratorV2
{
    var generator = new PersonReportGenerator(personDb, personId);
    return generator.Build();
}

現在,您的控制器可以依賴IPersonReportGeneratorV2 仍然有些丑陋,但是現在它被隱藏在新界面的后面。 現在,您可以將包裝器注冊為接口的實現,並讓容器完成其工作。

由於您在設計時不知道personId ,因此您不想通過構造函數注入personId。 (在Autofac中可以做到這一點;它丑陋而復雜。)

有一種更好更好的方法。

public interface IReportGenerator
{
    string Build(ReportSetting setting);
}

public class ReportSetting
{
    public int PersonId { get; set; }
    public Guid CarMake { get; set; }
    public Guid CarModel { get; set; }
}

public class PersonReportGenerator : IReportGenerator
{
    private readonly IPersonDb _personDb;

    public PersonReportGenerator(IPersonDb personDb)
    {
        _personDb = personDb;
    }

    public string Build(ReportSetting setting)
    {
        // you can use setting.PersonId
    }
}

public class CarReportGenerator : IReportGenerator
{
    private readonly ICarDb _cardDb;
    public CarReportGenerator(ICarDb cardDb)
    {
        _cardDb = cardDb; 
    }

    public string Build(ReportSetting setting)
    {
        // you can use setting.CarMake and setting.CarModel
    }
}

Autofac注冊

您可以使用Named and Keyed Services ,並根據名稱將所需的依賴項注入控制器。

例如,

cb.RegisterType<PersonReportGenerator>().Named<IReportGenerator>("PersonReport");
cb.RegisterType<CarReportGenerator>().Named<IReportGenerator>("CarReport");

cb.Register(c => new MyController(c.Resolve<IReportGenerator>("PersonReport")))
    .As<Controller>();

是。 不要在ActionResult解決它。 不要在任何地方明確解決它。

在控制器的構造函數中將其聲明為參數,如下所示:

public class MyController : Controller
{
    private readonly IPersonReportGenerator _personReportGenerator;

    public MyController(IPersonReportGenerator personReportGenerator)
    {
        _personReportGenerator = personReportGenerator;
    }
}

public ActionResult GetReport(int personId)
{
    var report = _personReportGenerator.Builder();
    return new ReportResult(report);
}

(假設“ Builder”是返回報告的方法。)

如果設置了Autofac或任何其他DI容器來創建控制器,則當它創建控制器來處理請求時,它還將解析該控制器的依賴項,包括IPersonReportGenerator

結果是您的控制器不依賴於容器甚至不依賴於容器。 它僅取決於它需要依賴的接口,並且容器提供了它。

如果您還沒有使用容器作為控制器工廠,那么這里是Autofac的文檔 關鍵是容器會創建所有內容。 如果容器創建了控制器,則同時它可以確定需要傳遞給構造函數的內容並創建這些類。 (如果這些類也具有依賴關系,它也會創建依賴關系,依此類推。)只要容器創建了第一個對象,它就會創建所有對象(只要注冊了依賴關系,就像使用IPersonReportGeneratorPersonReportGenerator 。 )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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