BestPractices:StructureMap和ASP.NET MVC 2 - 在一个抽象基础控制器中的Setter Injection / Contructur Injection

时间:2010-09-28 09:31:11

标签: c# asp.net-mvc asp.net-mvc-2 structuremap setter

public abstract class ConventionController : Controller
{
    public const int PageSize = 5;

    public IMappingService MappingService { get; set;}
}

如何设置StructureMap以获取IMappingService的实例?

修改

Joshua Flanagan 的帮助下,我现在有以下代码:

EmployeeController

public class EmployeeController : ConventionController
{
    private readonly ITeamEmployeeRepository _teamEmployeeRepository;

    public EmployeeController(ITeamEmployeeRepository teamEmployeeRepository)
    {
        _teamEmployeeRepository = teamEmployeeRepository;
    }

    public ActionResult Index(int page = 1)
    {
        // The IMappingService dependency is hidden in the AutoMappedHybridView method that is a part of the ConventionController, easy use in the controller
        return AutoMappedHybridView<TeamEmployee, TeamEmployeeForm>(_teamEmployeeRepository.GetPagedEmployees(page, PageSize));

       // With constructor injection I had to write this ...
       // return new HybridViewResult<TSourceElement, TDestinationElement>(_mappingService, _teamEmployeeRepository.GetPagedEmployees(page, PageSize));
    }
 }

ConventionController

public abstract class ConventionController : Controller
{
    public const int PageSize = 5;

    // This property is inject via StructureMap
    public IMappingService MappingService { get; private set; }

    public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement,TDestinationElement>(PagedList<TSourceElement> pagedList, string viewNameForAjaxRequest)
    {
        return new HybridViewResult<TSourceElement, TDestinationElement>(MappingService, pagedList, viewNameForAjaxRequest);
    }

    public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement,TDestinationElement>(PagedList<TSourceElement> pagedList)
    {
        return new HybridViewResult<TSourceElement, TDestinationElement>(MappingService, pagedList);
    }

    public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement, TDestinationElement>(TSourceElement sourceElement)
    {
        return new HybridViewResult<TSourceElement, TDestinationElement>(MappingService, sourceElement);
    }

    public HybridViewResult<TSourceElement, TDestinationElement> AutoMappedHybridView<TSourceElement, TDestinationElement>(TSourceElement sourceElement, string viewNameForAjaxRequest)
    {
        return new HybridViewResult<TSourceElement, TDestinationElement>(MappingService, sourceElement, viewNameForAjaxRequest);
    }
}

HybridViewResult

public class HybridViewResult<TSourceElement, TDestinationElement> : BaseHybridViewResult
{
    public HybridViewResult(IMappingService mappingService, PagedList<TSourceElement> pagedList)
    {
        ViewModel = mappingService.MapToViewModelPagedList<TSourceElement, TDestinationElement>(pagedList);
    }

    public HybridViewResult(IMappingService mappingService, PagedList<TSourceElement> pagedList, string viewNameForAjaxRequest)
    {
        ViewNameForAjaxRequest = viewNameForAjaxRequest;
        ViewModel = mappingService.MapToViewModelPagedList<TSourceElement, TDestinationElement>(pagedList);
    }

    public HybridViewResult(IMappingService mappingService, TSourceElement model)
    {
        ViewModel = mappingService.Map<TSourceElement, TDestinationElement>(model);
    }

    public HybridViewResult(IMappingService mappingService, TSourceElement model, string viewNameForAjaxRequest)
    {
        ViewNameForAjaxRequest = viewNameForAjaxRequest;
        ViewModel = mappingService.Map<TSourceElement, TDestinationElement>(model);
    }
}

正如您所看到的,HybridViewResult需要IMappingService依赖项。

如果我在ConventionController中使用构造函数,我会“污染”我的EmployeeController(imho)。

如果EmployeeController直接需要IMapping依赖,我会使用构造函数进行注入。但这不是必需的,因为已经有了ConventionController的IMapping属性。正如 Darin Dimitrov 所说,这会违反DI原则。

如何重构我的代码?我真的必须使用构造函数注入吗?

修改2

我如何命令StructureMap创建HybridViewResult的实例?如果这是可能的,控制器将不需要知道IMapping依赖性。是否可以从StructureMap获取通用对象(未装箱)?

2 个答案:

答案 0 :(得分:2)

实际上,不,SetAllProperties()为抽象类工作。这是Structuremap实现中的一个弱点。我很抱歉,就像我自己一样,Property Injection不适用于基本抽象类。对于基本抽象类,您将需要使用构造函数注入(与此处的所有炒作相反,在满足依赖项时并不总是最好的方法)。

答案 1 :(得分:1)

我假设您已经将控制器从StructureMap中取出。如果是这种情况,您只需要将SetAllProperties()调用添加到容器配置中。 SetAllProperties允许您定义应注入的属性的条件。