Questions about MVC

Vote:
 

Hi, I have some questions regarding MVC in EPiServer that I don't really understand. If a question is to "big" to answer in an easy way I would really appreciate if someone could provide a link to where I can read more about the relevant topic. I have had problems finding information for some topics but that may be me that is just bad at finding information =)

I have been looking on Joel Abrahamsson's excellent article "ASP.NET MVC Templates for EPiServer 7 CMS" and been trying to understand the code and how things actually works but there is some parts that I don't really understand. I'm quite new to both asp.net and to EpiServer ( but  not to programming) so please bear with me if some questions seems "stupid".

1. First a question about initialization. I have read in the developer guide that to have a discoverable initialization module the class has to be decorated with [InitializableModule] or [ModuleDependency(...)] and implement the interface IInitializableModule. If those criterias are met the class implementing the methods in IInitializableModule are executed during startup automagically from the framework. This is all logic and described in the developer guide. However in the code for the "MVC Templates" there is class defined as below

[InitializableModule]
public class DependencyResolverInitialization : IConfigurableModule
{
    public void ConfigureContainer(ServiceConfigurationContext context)
   { .....

The Interface IConfigurableModule implements IInitializableModule so its logic that it will be discovered during the initialization phase. However I assume the method defined IConfigurableModule called ConfigureContainer is also executed during startup? Am I supposed to understand that due to the fact that it implements IInitializableModule and therefore ConfigureContainer is called as well or am I missing something else here? Is there any documentation about this, or am I just bad at finding things? The parameter sent in, ServiceConfigurationContext context, is that a reference to the actual IoC-container then ( which if I understood it right is StructureMap )? 

2. Another question, possibly related to IoC and StructureMap. In the "MVC Templates" there is Controller called PreviewController which has a constructor that looks like below:

public PreviewController(IContentLoader contentLoader, ContentAreaRowBalancer rowBalancer)
{
    _contentLoader = contentLoader;
    _rowBalancer = rowBalancer;
}

How are the parameters sent into that constructor resolved? The way I understood it asp.net could map parameters from an incoming request to parameters named the same way in the function signature or in properties named the same in some wrapping class. But in this case I can't see how that can happen? Is there some configuration file somewhere that configures things like this or is there some magic happening somewhere? I'm not even sure what is responsible for this, is it asp.net, episerver or some IoC functionality?

Hope someone can help me to put some light on these topics. If I seem to lack some elementary knowledge here please point me in the right direction for where to read up. It's hard but fun to learn new things =)

 

 

#66062
Feb 19, 2013 12:46
Vote:
 

Hi

Regarding number 1:

IConfigurableModule is a special kind of IInitializableModule (as you pointed out the interface is inherited). What it adds in addition is a method ConfigureContainer (which is called once during initialization before Initialize), in the implementation you are able to add/register your custom abstractions to the IOC container through context.Container.

Regarding 2:

In MVC there is a possibility to define your own DependencyResolver, you can see in the class DependencyResolverInitialization (in the template project) that a implemenation that uses the StructureMap container is registered.

#66064
Feb 19, 2013 13:03
Vote:
 

Hi Johan and thanks for your answer. I looked into the implementation of the DependencyResolverInitialization and I think I understand it. However I have some followup question that if I am lucky you have time to answer.

1. The parameter sent into the ConfigureContainer method is of type ServiceConfigurationContext. I assume that one is sent in from the framework during the initialization process. The Container property of ServiceConfigurationContext is of type IContainer which seems to be a StructureMap specific interface declared in namespace StructureMap. Does that mean that EPiServer uses StructureMap as IoC container and that can't be changed to another IoC container ( if I for some reason would want that )?

2. In my original question I asked about how the parameters to the controller PreviewController could be resolved. Perhaps you answered that implicitly in your answer by saying that StructureMap was used (in the template project), and I just did not understand it =) . But is that the case, is it StructureMap that is responsible for injecting the correct parameters to the previewcontroller in this case? Because I can't see any configuration in DependencyResolverInitialization that is related to parameters sent to controllers. Does that happen "magically" under the hoods and there is no need for an explicit configuration file or similar? If that is the case I need to do some reading of StructureMap =)

 

#66087
Feb 19, 2013 21:17
Vote:
 

Regarding 1:

It is correct that EPiServer uses StructureMap internally and you are not supposed to change the IOC container that is used internally. You can however have your own IOC container for your own abstractions if you like.

It is also only in ConfigureContainer that the StructureMap container is exposed, otherwise when retieveing instances from container you normally use IServiceLocator interface which is an abstraction over container implementations. So for EPiServer it would probably be possible to change IOC container without more than a minor breaking change.

And in theory it would probably be possible to exchange StructureMap container toward another container by listening to e.g. InitCompleted and in there read all registrations from structureMap and register them in another container and then set ServiceLocator.Current to the new container. But this is just in theory and nothing we support officially....

Regarding 2:

If you put a breakpoint in the constructor you can see from the stacktrace that the code originates from System.Web.Mvc.DefaultControllerFactory which then calls the registered DependencyResolver (in our case StructureMapDependencyResolver) to resolve the dependencies.

So the "magic" is really the line

DependencyResolver.SetResolver(new StructureMapDependencyResolver(context.Container));

in class DependencyResolverInitialization. There is where we register our custom dependency resolver with MVC. Then MVC will use that to resolve dependencies e.g. when creating controller instances.

#66092
Feb 20, 2013 7:33
Vote:
 

Thanks Johan for great answers!

#66105
Feb 20, 2013 11:42
Vote:
 

I looked into structureMap yesterday and thanks to your explanation and some reading things are starting to make more sense. However there are still a couple of things that I don't fully understand and hopefully you can ( once again ) help me put some light on them =) I'm not sure if it was the correct way to continue this thread when I had marked it as resolved but I did that instead of starting an new one.

1. In PreviewController it takes two parameters (IContentLoader contentLoader, ContentAreaRowBalancer rowBalancer). Where does the registration happen? With registration I mean the part x.For<IContentLoader>().Use<ContentLoader>(); or however is it defined in this case. Does the registration for IContentLoader happen inside "native" EPiServer code?

2. But the ContentAreaRowBalancer is declared outside EPiServer "native" code, but I can't see any registration for it. I was expecting to see a x.For<ContentAreaRowBalancer>().Use<ContentAreaRowBalancer>(); or similar somewhere in the code. Isn't this part necessary so the container knows what to inject?

StructureMapDependencyResolver basically just wraps StructureMap here so I assume there had to be some registration going on. Am I missing some elementary logic here, is there some autowiring happening here or where does all the registration occur?

#66145
Feb 21, 2013 10:29
Vote:
 

1. IContentLoader is part of EPiServer CMS and hence is the default implementation of the interface registered as part of the initialization of CMS itself.

2. Concrete classes as ContentAreaRowBalancer does not need to be explicitlty registered with the container. The container can resolve instances of concrete classes anyway and will use the constructor with most parameters and locate the parameter dependencies within the container.

As alternative to explicitly register entries in container like:

 x.For<IContentLoader>().Use<ContentLoader>(); 

you can use attribute ServiceConfiguration attribute like example below:

[ServiceConfiguration(typeof(IContentDataBuilder))]
public class ContentDataBuilder : IContentDataBuilder

During initialization EPiServer will scan for all types with the attribute and do the registration with IOC container.

#66152
Feb 21, 2013 13:46
Vote:
 

Thanks again! Now I finally get it =)

#66157
Feb 21, 2013 15:25
Vote:
 

Hi,

Excellent post, but can I just ask, Is it necessary to Set the dependencyResolver with:

DependencyResolver.SetResolver(new StructureMapDependencyResolver(context.Container);

I presume that EPiServer has already set the dependency resolver and so I am merely configuring the container in my IConfigurableModule with 

x.For<IMyInterface>().Use<MyConcreteClass>();

This works ok on my machine but my colleague gets

StructureMap Exception Code: 202 No Default Instance defined for PluginFamily IMyInterface ....

 

I was afraid that if I re set the dependency resolver, then I would loose the default dependency resolver setup by EPiServer ?

Is this the case ?

 

Is re-setting the dependency resolver with your own implementation best practice ? Or why would you need to do it, if EPiServer already sets it for you ?

 

 

#72078
Jun 10, 2013 10:04
Vote:
 

The dependency resolver is set by the template project EPiServer.Templates.Alloy.Mvc (so it is not set in CMS it self), that means that if you are building your templates based on that project it will be set for you. If you however build your own templates then you need to set it your self. 

#72081
Jun 10, 2013 10:53
This thread is locked and should be used for reference only. Please use the Episerver CMS 7 and earlier versions forum to open new discussions.