views:

115

answers:

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

    public IMappingService MappingService { get; set;}
}

How do I set up StructureMap to get the Instance of IMappingService?

Edit:

With the help of Joshua Flanagan I now have the following code:

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

As you can see the HybridViewResult needs the IMappingService dependency.

If I would use a constructur in the ConventionController I would "pollute" my EmployeeController (imho).

If EmployeeController would directly need the IMapping dependency I would use the constructor for injecting. But this would not be necessary, because there is already the IMapping property of the ConventionController. So as Darin Dimitrov said, this would violate the DI principle.

How do I refactor my code? Do I really have to use constructor injection?

Edit 2

How could I order StructureMap to create an instance of the HybridViewResult? If this would be possible the controllers would not need to know about a IMapping dependency. Is it at all possible to get an generic object (not boxed) from StructureMap?

+1  A: 

I assume you are already getting your controllers out of StructureMap. If thats the case, you just need to add the SetAllProperties() call to your container configuration. SetAllProperties allows you to define the criteria for the properties that should be injected.

Joshua Flanagan
For getting a controller instance I use a delegate and set him up at start: StructureMapControllerFactory.CreateDependencyCallback = type => ObjectFactory.GetInstance(type); How could I inject the setter of the property of the base class of the controller? I use StructureMap 2.6.1
Rookian
Somewhere in your code you are calling ObjectFactory.Initialize() and/or ObjectFactory.Configure(). Within those calls, one of your options is SetAllProperties, and that's where you would define which properties should get set (ex: all properties of type IMappingService).
Joshua Flanagan