[英]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
}
}
您可以使用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的文档 。 关键是容器会创建所有内容。 如果容器创建了控制器,则同时它可以确定需要传递给构造函数的内容并创建这些类。 (如果这些类也具有依赖关系,它也会创建依赖关系,依此类推。)只要容器创建了第一个对象,它就会创建所有对象(只要注册了依赖关系,就像使用IPersonReportGenerator
和PersonReportGenerator
。 )
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.