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获取通用对象(未装箱)?
答案 0 :(得分:2)
实际上,不,SetAllProperties()不为抽象类工作。这是Structuremap实现中的一个弱点。我很抱歉,就像我自己一样,Property Injection不适用于基本抽象类。对于基本抽象类,您将需要使用构造函数注入(与此处的所有炒作相反,在满足依赖项时并不总是最好的方法)。
答案 1 :(得分:1)
我假设您已经将控制器从StructureMap中取出。如果是这种情况,您只需要将SetAllProperties()
调用添加到容器配置中。 SetAllProperties允许您定义应注入的属性的条件。