views:

1206

answers:

3

I'm trying to get structuremap to correctly create my controllers, I'm using DI to inject an INewsService into a NewsController and thats the only constructor I have.

public class NewsController : Controller
{
    private readonly INewsService newsService;

    public NewsController(INewsService newsService)
    {
     this.newsService = newsService;
    }

    public ActionResult List()
    {
  var newsArticles = newsService.GetNews();
        return View(newsArticles);
    }
}

and I'm using this code to start the app

public class Application : HttpApplication
{
 protected void Application_Start()
 {
  RegisterIoC();
  RegisterViewEngine(ViewEngines.Engines);
        RegisterRoutes(RouteTable.Routes);
 }

 public static void RegisterIoC()
 {
  ObjectFactory.Initialize(config => {
   config.UseDefaultStructureMapConfigFile = false;
   config.AddRegistry<PersistenceRegistry>();
   config.AddRegistry<DomainRegistry>();
   config.AddRegistry<ControllerRegistry>();
  });
  DependencyResolver.InitializeWith(new StructureMapDependencyResolver());
        ControllerBuilder.Current.SetControllerFactory(typeof(IoCControllerFactory));            
 }
}

But Structuremap doesn't seem to want to inject the INewsService and I get the error No parameterless constructor defined for this object.

What have I missed?

A: 

Unless I'm missing something, you are not telling StructureMap what concrete type to use for INewsService. You need to add something like:

TheConcreteTypeOf<INewsService>.Is<MyConcreteNewsService>();

I don't know the exact syntax off the top of my head, but that's what you're missing. Once you specify that then it will know what instance of the INewsService to inject into the controller.

Micah
I'm adding all the right mappings in registries, such as INewsService, so It shouldn't be that that's causing the problem.
Leon
I'm not seing the code where you are instantiating it.
Micah
Can you show the code in the registries?
Micah
+5  A: 

I use the "Default Conventions" mechanism that StructureMap provides to avoid needing to individually configure each interface. Below is the code I use to make that work:

My Global.asax has this line in Application_Start (which uses the StructureMap factory from MvcContrib):

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    ObjectFactory.Initialize(x =>
    {
        x.AddRegistry(new RepositoryRegistry());
    });
    ControllerBuilder.Current.SetControllerFactory(typeof(StructureMapControllerFactory));
}

And the RepositoryRegistry class looks like this:

public class RepositoryRegistry : Registry
{

    public RepositoryRegistry()
    {
        Scan(x =>
        {
            x.Assembly("MyAssemblyName");
            x.With<DefaultConventionScanner>();
        });

    }

}

The DefaultConventionScanner looks for pairs of Interfaces/Classes that follow the nameing convention of ISomethingOrOther and SomethingOrOther and automatically associates the latter as a concrete type for the former interface.

If you didn't want to use that default convention mechanism, then you would add code in the Registry class to explicity map each of your interfaces to the concrete types with this syntax:

ForRequestedType<ISomethingOrOther>().TheDefaultIsConcreteType<SomethingOrOther>();
Erv Walter
Thanks!, this helped me alot, I was able to get around my problem :)
Leon
@Erv what namespace is Scan located in? I seem to be missing a using or reference.
ahsteele
In the version we are using (which is 8 months out of date--I have not looked at what has changed recently), Scan is a method on the Registry base class that RepositoryRegistry inherits from in the example.
Erv Walter
A: 

ASP.NET MVC currently instantiates controllers using the default parameterless constructor, which precludes any constructor-based dependency injection. To do that, you really need to use the MvcContrib project, which has built-in support for StructureMap (and Castle/Spring.NET/Unity), although the current documentation is non-existent (literally, you get a stub wiki page, not a good sign). Erv Walter's code sample in this thread shows how to set up the StructureMap integration.

David Keaveny