Bestpractices: StructureMap и ASP.NET MVC 2 - Внедрение сеттера / Внедрение конструктора в абстрактный базовый контроллер - PullRequest
2 голосов
/ 28 сентября 2010
public abstract class ConventionController : Controller
{
    public const int PageSize = 5;

    public IMappingService MappingService { get; set;}
}

Как мне настроить StructureMap для получения экземпляра IMappingService?

Edit:

С помощью Джошуа Фланаган Теперь у меня есть следующий код:

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.

Если бы я использовал constructur в ConventionController, я бы "загрязнил" мой EmployeeController (imho).

Если EmployeeController будет напрямую нуждаться в зависимости IMapping, я бы использовал конструктор для внедрения. Но в этом нет необходимости, потому что уже есть свойство IMapping в ConventionController. Итак, как сказал Дарин Димитров , это нарушило бы принцип DI.

Как мне изменить мой код? Я действительно должен использовать инжектор конструктора?

Редактировать 2

Как я могу заказать StructureMap для создания экземпляра HybridViewResult? Если бы это было возможно, контролерам не нужно было бы знать о зависимости IMapping. Можно ли вообще получить общий объект (не в штучной упаковке) из StructureMap?

Ответы [ 2 ]

2 голосов
/ 05 октября 2011

На самом деле, нет, SetAllProperties () работает не для абстрактных классов. Это слабое место в реализации Structuremap. Я сожалею за вас, как и за себя, что Property Injection не работает для базовых абстрактных классов. Для базовых абстрактных классов вам нужно будет использовать инжекцию конструктора (что, вопреки всей навязчивой идее, не всегда является лучшим способом удовлетворения зависимостей).

1 голос
/ 28 сентября 2010

Я предполагаю, что вы уже выводите свои контроллеры из StructureMap.Если это так, вам просто нужно добавить вызов SetAllProperties() в конфигурацию вашего контейнера.SetAllProperties позволяет вам определять критерии для свойств, которые должны быть внедрены.

...