Initialization, Attributes and IoC

Vote:
 

Ok - I've got an interesting issue

We are building a CMS6R2 site which is actually an MVC / WebForm hybrid and we're using StructureMap as an IoC conatiner - fun eh :)

As part of the MVC build - we've produced our own custom attribute to mark whether a user has access to a particular Controller / ActionResult via our own authentication mechanism. We want our attribute to be flexible too which means that it too is dependent on the conatiner for resolving its dependencies. As we don't have control over the creation of attributes - the constructor directly makes a call to the StructureMap ObjectFactory to resolve its dependencies when instantiated.

The issue I'm having is with the EPiServer Initialization process. This is started by the EPiServer.Global class (in its constructor) - and runs before our bootstrapper that sets up the container. During the assembly scanning process it touches our security atrribute class which tries to resolve its dependency from the uninitialised container. Bang - Exception!

I thought that adding Framework.config settings or assembly attributes [assembly: PreventAssemblyScan] set on the relevant project to remove the selected assemblies from the scan would resolve this - but either I'm missing something or its still performing some sort of scan.

If this is impossible; I guess my only option is to reflect out the EPiServer Global class and implement all the functionality in my own Global.asax and make sure the conatiner is initialized before the call to InitializationModule.FrameworkInitialization. That feels like cheating though.


 

#56879
Feb 14, 2012 16:38
Vote:
 

Could you post a stack trace?

#56880
Feb 14, 2012 16:44
Vote:
 
[StructureMapException: StructureMap Exception Code:  202
No Default Instance defined for PluginFamily Banana.Security.IMembershipLoginService, Banana.Security, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]
   StructureMap.BuildSession.<.ctor>b__0(Type t) in c:\code\structuremap\Source\StructureMap\BuildSession.cs:31
   StructureMap.Util.Cache`2.get_Item(KEY key) in c:\code\structuremap\Source\StructureMap\Util\Cache.cs:83
   StructureMap.BuildSession.CreateInstance(Type pluginType) in c:\code\structuremap\Source\StructureMap\BuildSession.cs:192
   StructureMap.Container.GetInstance() in c:\code\structuremap\Source\StructureMap\Container.cs:155
   Banana.Security.MembershipLoginServiceFactory.get_Instance() in E:\New\Projects\Banana\trunk\Banana.Security\MembershipLoginServiceFactory.cs:19
   Banana.Security.SecurePageAttribute..ctor() in E:\New\Projects\Banana\trunk\Banana.Security\SecurePageAttribute.cs:26
   System.RuntimeTypeHandle.CreateCaInstance(RuntimeType type, IRuntimeMethodInfo ctor) +0
   System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes, Boolean isDecoratedTargetSecurityTransparent) +1320
   System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeType type, RuntimeType caType, Boolean inherit) +235
   EPiServer.PlugIn.AssemblyTypeInfo.TypeHasPlugInAttributes(Type type) +50
   EPiServer.PlugIn.AssemblyTypeInfo.ScanAssembly() +213
   EPiServer.PlugIn.AssemblyTypeInfo.get_HasPlugInAttributes() +16
   EPiServer.PlugIn.PlugInLocator.get_Assemblies() +360
   EPiServer.PlugIn.PlugInLocator.FindPlugInAttributes() +81
   EPiServer.PlugIn.PlugInRuntime.InitRunTimePlugins(Boolean reset) +63
   EPiServer.PlugIn.PlugInRuntime.Start(Boolean reset) +67
   EPiServer.Web.InitializationModule.<StaticInitialization>b__c() +11
   EPiServer.Web.InitializeEngine.Initialize() +516
   EPiServer.Web.InitializationModule.StaticInitialization() +1494
   EPiServer.Web.InitializationModule.Initialize(InitializationEngine context) +46
   EPiServer.Framework.Initialization.InitializationEngine.InitializeModules() +647
   EPiServer.Framework.Initialization.InitializationEngine.Initialize(HostType hostType) +115
   EPiServer.Framework.Initialization.InitializationModule.Initialize(HostType hostType) +199
   EPiServer.Framework.Initialization.InitializationModule.FrameworkInitialization(HostType hostType) +64
   EPiServer.Global..ctor() +74
   Banana.Web.Global..ctor() +40

 
    

 

#56882
Feb 14, 2012 16:52
Vote:
 

Maybe a stupid question, but do you have to use ObjectFactory in the attribute's ctor?

#56883
Feb 14, 2012 17:01
Vote:
 

Ideally I need some way of injecting the dependency into the attribute. What other options are there?

#56884
Feb 14, 2012 17:08
Vote:
 
Resolve it from ObjectFactory when you need it?
#56886
Feb 14, 2012 17:12
Vote:
 

I can't really do that - as the dependency is in an attribute which is applied to ActionResults / controllers etc. The issue here is that the attribute gets instantiated before the container has been setup by the EPiServer initialization scanning from custom attributes. I guess I could refactor my code to bring that logic into every controller action that requires it. Not very nice though.

Anyway Mr Forsberg has come up with a very sensible suggestion - which was using ObjectFactory.TryGetInstance<> - knowing that the only time it wouldn't resolve was during the Initialization where it doesn't really matter.

Ideally though - EPiServer should:

  • Ensure that all assembly scanning can be configured - ie ignore rules (such as in EPiServerFramework.config) should be honoured by all assembly scanning systems
  • Provide a way for us to perform logic before the EPiServer initialization process begins - though I can understand why they wanted this to be performed at the very first available time on application startup (ctor of EpiServer.Global)

 

 

#56889
Feb 14, 2012 17:26
Vote:
 

Nice!

Just for the record though, I was thinking you'd overide the OnAuthorization or AuthorizeCore methods in which you could request the dependency from ObjectFactory. Sorry for not saying that more clearly before, I was posting from my phone :)

I agree regarding the assembly scanning. Although from the little research I did it should work. But to me, these issues are on Microsoft for relying so heavily on attributes for authorization as that's not very flexible.

#56890
Edited, Feb 14, 2012 17:58
Vote:
 

Yea, I agree with what Joel is saying. If you implement IAuthorizationFilter you should be able to call you container in the OnAuthorization method and do nothing regarding the container in the constructor.

#56891
Feb 14, 2012 18:23
Vote:
 

Even thought this doesn't help with the current issue, I would like to mention that all different assembly scannings that is done in the 6 R2 products has since been refactored to use a single scan. There will also be another method available for setting up any IoC containers before the main framework initialization cycle is run. These improvements will be available in the next major release.

#56903
Feb 15, 2012 9:40
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.