2

我有一个 asp.net-mvc 站点,我正在使用 LinFu 来做 IOC。我遇到了一个问题,其中许多操作具有我想注入控制器的依赖项,但我只想在调用依赖于它的操作时初始化依赖项。

所以在我的控制器中,我的控制器中有以下代码:

   public PersonController
   {

    private IPeopleImporter _peopleImporter;

    public override void Initialize(LinFu.IoC.Interfaces.IServiceContainer source)
    {
        _peopleImporter= source.GetService<IPeopleImporter>();
        base.Initialize(source);
    }

    public JsonResult GetDetails(int id)
    {
        var p = _peopleImporter.Get(id);
        var personDetails = new {p.Id, p.FirstName, p.LastName, StandardId = p.StandardIdLogin, p.PersonNumber};
        return Json(personDetails);
    }
   }

启动 PeopleImporter 非常昂贵,所以我的问题是我想解决两件事:

  1. 我想让 IPeopleImporter 的实现“可插入”,这样我就可以在接口中将 IOC 放入控制器

  2. 我有很多操作,所以如果用户从不调用需要它的特定操作,我不希望启动 IPeopleImporter 的成本。似乎在上面的代码中,我在每次调用 PersonController 时都进行了初始化

我的初始化代码是这样的:

this.AddService(typeof(IPeopleImporter), typeof(DatabaseImporter), LifecycleType.Singleton);

这似乎是常见的模式/问题。有没有推荐的解决方案。同时,替代方案(避免性能损失是简单地“新建”控制器内部的概念实现(并避免 IOC)?

4

3 回答 3

3

第一步是将这个动作放入一个单独的控制器中。这样您就不必为此控制器中的其他操作支付初始化价格。

然后使用真正的 IoC 模式,而不是您当前使用的被视为反模式的服务定位器。在 IoC 中,控制器不应该知道所使用的特定 DI 框架的任何信息。在 IoC 中,控制器接收所有依赖项作为构造函数参数

public PersonsController: Controller
{
    private readonly IPeopleImporter _peopleImporter;
    public PersonsController(IPeopleImporter peopleImporter)
    {
        _peopleImporter = peopleImporter;
    }

    public ActionResult GetDetails(int id)
    {
        var p = _peopleImporter.Get(id);
        var personDetails = new { p.Id, p.FirstName, p.LastName, StandardId = p.StandardIdLogin, p.PersonNumber };
        return Json(personDetails, JsonRequestBehavior.AllowGet);
    }
}
于 2012-07-27T13:11:15.357 回答
1

您可以使用下一个技巧来完成您的任务。您不能注入 IPeopleImporter 的实例,而是注入这种类型的工厂:

private readonly Func<IPeopleImporter> _peopleImporterFactory;

并在你需要的地方使用这个工厂:

var peopleImporter = __peopleImporterFactory();

例子:

 public PersonController

{

private readonly Func<IPeopleImporter> _peopleImporterFactory;

public PersonController(Func<IPeopleImporter> peopleImporterFactory)
{
    _peopleImporterFactory = peopleImporterFactory;
}

public JsonResult GetDetails(int id)
{
    var peopleImporter = _peopleImporterFactory();
    var p = peopleImporter.Get(id);
    var personDetails = new {p.Id, p.FirstName, p.LastName, StandardId = p.StandardIdLogin, p.PersonNumber};
    return Json(personDetails);
}

}

于 2012-07-30T07:37:03.337 回答
0

我通常通过将依赖项作为参数注入到我的操作中来解决这个问题。可以在类级别注入常见或廉价的依赖项,而不寻常或昂贵的依赖项作为参数进入。

以下是 Enterprise Library Unity 的一些示例代码,但您可以修改它:

public class UnityActionInvoker : ControllerActionInvoker
{
    readonly IUnityContainer container;

    public UnityActionInvoker(IUnityContainer container)
    {
        this.container = container;
    }

    protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
    {
        Type parameterType = parameterDescriptor.ParameterType;

        if (parameterType != typeof(string) && !parameterType.IsValueType && container.IsRegistered(parameterType))
        {
            return container.Resolve(parameterType).AssertNotNull();
        }

        return base.GetParameterValue(controllerContext, parameterDescriptor);
    }
}

您可以通过在控制器的构造函数(或所有控制器的公共基类)ControllerActionInvoker中进行设置来挂钩它。Controller.ActionInvoker

以下是您的控制器的外观:

   public PersonController
   {
    public JsonResult GetDetails(int id, IPeopleImporter _peopleImporter /*injected*/)
    {
        ...
    }
   }
于 2012-07-27T13:10:22.677 回答