2
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?

Rookian
  • 19,841
  • 28
  • 110
  • 180
  • Any reason for not using constructor injection? If your controller depends on this service and cannot function without it it is better to use constructor injection. Property injection is useful for dependencies that are not required like for example logging but the class can still function if they are not present (null). – Darin Dimitrov Sep 28 '10 at 09:33
  • If I would use contructor injection every controller must have a constructor with IMappingService. I do not want this. In the CodeCampServer is a public static delegate as an alternative. – Rookian Sep 28 '10 at 09:55
  • If the controller needs this dependency in order to work it would be better to provide it in the constructor. Everything else is leaking and false dependency injection. If that's how it's done in the CodeCampServer it simply means that this code is wrong and shouldn't be used as model to teach best practices. – Darin Dimitrov Sep 28 '10 at 09:57
  • sry I have to correct my statements. The CodeCampServer use an AutoMappedViewResult and within this class that derives from ViewResult they have public static Func Map = (a, b, c) => { throw new InvalidOperationException("The Mapping function must be set on the AutoMapperResult class");}; I will edit my post ... please have a look – Rookian Sep 28 '10 at 10:44
  • I think Darin is correct and you should go with constructor injection. I'm confused as to how AutoMappedViewResult relates to the problem. – Castrohenge Sep 29 '10 at 14:00
  • I updated my question ... @Castrohenge in the CodeCampServer AutoMapper (object to object framework) is used for mapping from a domain model to a viewmodel. AutoMappedViewResult is an ActionResult that hides the mapping code that would have be written in the controller. The AutoMappedViewResult uses a delegate to not couple the UI to the AutoMapper. I thought the delegate was on the ConventionController but it isn't. The ConventionController has a method called AutoMappedView which returns AutoMappedViewResult. So the dependency is not on the controller, it is on the AutoMappedViewResult. – Rookian Sep 29 '10 at 20:38

2 Answers2

2

Actually, no, SetAllProperties() does not work for abstract classes. This is a weakness in the Structuremap implementation. I'm sorry for you, as I am for myself, that Property Injection does not work for base abstract classes. For the base abstract classes, you will need to use constructor injection (which, contrary to all the hype around here, is not always the best way to go when satisfying dependencies).

Bob
  • 41
  • 2
1

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
  • 8,527
  • 2
  • 31
  • 40
  • 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 Sep 28 '10 at 19:27
  • 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 Sep 28 '10 at 20:05
  • http://stackoverflow.com/questions/3833872/bestpractice-di-with-asp-net-mvc-and-structuremap-how-to-inject-dependencies-in – Rookian Nov 06 '10 at 17:47