Properties not injecting - ASP.Net MVC project

Aug 27, 2010 at 3:59 PM

The problem is that the Properties are always set to Nothing - Here are the details:

I'm trying to setup automatic DI when a controller is created in my asp.net mvc project

Class to override Controller creation: 

 

Imports Microsoft.Practices.Unity
Public Class UnityControllerFactory
    Inherits DefaultControllerFactory
    Private _aContainer As Microsoft.Practices.Unity.UnityContainer
    Public Sub New(ByVal aContainer As Microsoft.Practices.Unity.UnityContainer)
        _aContainer = aContainer
    End Sub
    Protected Overrides Function GetControllerInstance(ByVal requestContext As System.Web.Routing.RequestContext, ByVal controllerType As System.Type) As System.Web.Mvc.IController
        Return _aContainer.BuildUp(MyBase.GetControllerInstance(requestContext, controllerType))
    End Function

End Class

 

 

Snippet from Global.asax - Application_Start()

 

        Dim myContainer As UnityContainer
        Application.Lock()
        Try
            myContainer = TryCast(Application("aContainer"), IUnityContainer)
            If myContainer Is Nothing Then
                myContainer = New UnityContainer()
                myContainer.AddExtension(New EnterpriseLibraryCoreExtension())
                ' Add your own custom registrations and mappings here as required
                Application("aContainer") = myContainer
            End If
            ControllerBuilder.Current.SetControllerFactory(New UnityControllerFactory(myContainer))
        Finally
            Application.UnLock()
        End Try

 

Properites in my ComputerController Class

 

        Private _AuthProvider As IAuthorizationProvider
        Private _SecCache As ISecurityCacheProvider
        <Dependency("AuthProvider")> _
        Public Property SecCache() As ISecurityCacheProvider
            Get
                Return _SecCache
            End Get
            Set(ByVal value As ISecurityCacheProvider)
                _SecCache = value
            End Set
        End Property
        <Dependency("RuleProvider")> _
        Public Property AuthProvider() As IAuthorizationProvider
            Get
                Return _AuthProvider
            End Get
            Set(ByVal value As IAuthorizationProvider)
                _AuthProvider = value
            End Set
        End Property

I can see wen the controller is created  and .buildup is called. I can inspected the registrations in the unity container and I see "IAuthorizationProvider" and "ISecurityCacheProvider"; but when I inspect the controller class after buildup is called, both properties are "nothing"

Below is a snippet form the Controller action method where I am able to resolve the IAuthorizationProvider and and set the property Manually  and my code works. 

 

 

Dim c = CType(HttpContext.Application("aContainer"), UnityContainer)
AuthProvider = c.Resolve(Of IAuthorizationProvider)("RuleProvider")

I'm not sure what I doing wrong... I'm very new to unity and am still working through all the documentation. If this is not the right place to post this please let me know. 

Thanks for any help 

dale

 

 

Aug 29, 2010 at 11:47 AM

You may not be doing anything wrong - Unity cannot always resolve objects, particularly if it receives
a type of object as the buildup parameter as in the case of a generic process.  

Although this blog uses interception to wire-up the controllers we are applying the same principal.  The
key is to send Buildup the type as well as instance - in my case I make it the responsibility of the class
to buildup itself (via its baseclass). 

        // The type will be that of the derived class.
        // BuildUp of the parent controller
        value.BuildUp(GetType(), this);
Aug 29, 2010 at 10:23 PM

Dale, your minimum change to get everything working properly is to change your controller factory to this:

    Protected Overrides Function GetControllerInstance(ByVal requestContext As System.Web.Routing.RequestContext, ByVal controllerType As System.Type) As System.Web.Mvc.IController
        Return DirectCast(_aContainer.Resolve(controllerType), IController)
    End Function

Let the container create the object rather than the base controller factory class. This also has the advantage that you can then also use constructor injection, not just limit your dependencies to properties.

If you for some reason want to stick with not using the container for creation, you can instead do this:

    Protected Overrides Function GetControllerInstance(ByVal requestContext As System.Web.Routing.RequestContext, ByVal controllerType As System.Type) As System.Web.Mvc.IController
        dim controller as IController = MyBase.GetControllerInstance(requestContext, controllerType)
        _aContainer.BuildUp(controller.GetType(), controller)
        Return controller
    End Function

but I strongly recommend the previous - it's just so much more flexible.

 

Aug 30, 2010 at 1:46 PM

Thanks for the responses. 

When I add the type to the BuildUp call or try to let the Container resolve the Controller I get the following Error

Resolution of the dependency failed, type = "ShepherdMVC.ShepherdMVC.ComputerController", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - The current type,               Microsoft.Practices.EnterpriseLibrary.Security.IAuthorizationProvider, is an interface and cannot be constructed. Are you missing a type mapping? ----------------------------------------------- At the time of the exception, the container was:    Resolving ShepherdMVC.ShepherdMVC.ComputerController,(none)   Resolving parameter "authProvider" of constructor ShepherdMVC.ShepherdMVC.ComputerController(Microsoft.Practices.EnterpriseLibrary.Security.IAuthorizationProvider authProvider, Microsoft.Practices.EnterpriseLibrary.Security.ISecurityCacheProvider SecCache)     Resolving Microsoft.Practices.EnterpriseLibrary.Security.IAuthorizationProvider,(none)

From that error it looks like I haven't registered IAuthorizationProvider or ISecurityCacheProvider with the container, but like I said above I can resolve them if I make a call to the unity container in my controller function.  

A few notes: 

    I am not registering the ComputerContorller with the Unity Container (I should not have to right?)

    I am letting the Enterprise Config do all the configuration on the Container.

 

I'm still looking into he Interception possibilities. 

Thanks again

dale

 

Aug 30, 2010 at 5:07 PM

Dale,

At this point I'm going to need to see a small but complete repro case of the problem. There's nothing obviously wrong in the code snippets you've posted, so the problem must be in one of the ones you haven't.

 

Sep 3, 2010 at 9:33 AM
Dale_C wrote:

Resolving parameter "authProvider" of constructor ShepherdMVC.ShepherdMVC.ComputerController(Microsoft.Practices.EnterpriseLibrary.Security.IAuthorizationProvider authProvider, Microsoft.Practices.EnterpriseLibrary.Security.ISecurityCacheProvider SecCache)    

You have named typed mappings but the error indicates that you are not specifying the names during constructor injection - the above error reads to me:

"resolving parameter authProvider of ComputerController(IAuthorizationProvider authProvider, ISecurityCacheProvider SecCache)"

Not being familiar with VB.NET I copied the following out of the "Annotating Objects for Constructor Injection" - "Specifying Named Type Mappings" section of the Unity 2.0 documentation

 Public Class MyObject
  Public Sub New(<Dependency("DataService")> myDataService As IMyService)
    ' work with the service here
  End Sub
End Class