2012-07-25 112 views
2

我有一个asp.net-mvc网站,我正在使用LinFu做IOC。我遇到了一些问题,其中一些操作具有我要注入到控制器中的依赖项,但是如果我调用依赖于该操作的操作,我只想初始化依赖项。有没有更好的方法来做asp.net-mvc中的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); 
    } 
    } 

到initiatize PeopleImporter是相当昂贵的,所以我的问题是,我要解决两两件事:

  1. 我想使IPeopleImporter的implementatioo“可插拔”这样我就可以在国际奥委会的界面到控制器

  2. 我有很多的动作,所以我不希望如果用户从不调用需要它的特定操作,则开始IPeopleImporter的开销。这似乎是在上面的代码,我这样做,initiatization上PersonController的每一个电话

我initiatization代码是这样的:

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

这似乎是常见的模式/问题。有没有推荐的解决方案。在此期间,替代方案(以避免性能打击是简单的“新”的内置控制器内置(并避免国际奥委会)?

+0

我不知道LinFu,但许多其他IOC框架提供工厂注入,可用于在需要时实例化实例。 – Eranga 2012-07-25 03:47:42

+0

你所显示的不是IoC。你一定在这里混淆了这些条款。在IoC中,控制器将依赖关系作为构造函数参数。在你的例子中,你将你的控制器绑定到DI框架(你的情况下是LinFu),并且你正在使用Service Locator模式(在Initialize方法中,你正在查询你的DI框架来检索依赖关系)。这被认为是反模式。 IoC中的 – 2012-07-27 13:08:04

回答

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); 
} 

}

0

我通常通过注入依赖项作为参数来解决这个问题。常见的或低廉的依赖性可以在类的级别被注入而不同寻常的或昂贵的进来作为参数

下面是企业库统一一些示例代码,但你能适应它。

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*/) 
    { 
     ... 
    } 
    } 
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); 
    } 
} 
+0

可以通过构造函数以外的其他方法注入依赖项。当然,构造函数是最常见的,但不是唯一可能的机制 – 2012-07-30 07:43:00

+0

@RuneFS,是的,没错。您可以将属性注入用于非必需的依赖项。 – 2012-07-30 07:59:43

+0

@Darin - 我同意你的观点。 。希望从林福迁出,因为它似乎并不支持适当的国际奥委会,在那里控制员不需要参考国际奥委会容器。 – leora 2012-07-30 16:47:51

相关问题