MVC3& Unity.Mvc
我的 MVC3 项目遇到了奇怪的问题。我遵循了一个使用 Unity.Mvc 的 IOC 简单示例。
如果我的对象及其接口位于 Web 项目本身(在本例中为 IMessageService 和 MessageService),则它可以正常工作。他们显然正在工作,没有任何问题。
但是,当我尝试从外部程序集注册我的业务服务对象时,它们永远不会被设置为任何内容(始终为空)。注册时应用程序启动时没有错误等。
有人有什么想法吗?这里绝望......
更新:
#Region "Imports"
Imports MyProject.Services
Imports MyProject.Services.Interfaces
Imports MyProject.Web.Mvc.Bootstrap
Imports MyProject.Web.Mvc.Services
Imports Microsoft.Practices.Unity
Imports Unity.Mvc3
#End Region
#Region "Assembly Meta"
' This tells the app to run the "Start" method prior to running the App_Start method in Global.asax
<Assembly: WebActivator.PreApplicationStartMethod(GetType(UnityDI), "Start")>
#End Region
Namespace MyProject.Web.Mvc.Bootstrap
''' <summary>
''' Class to setup dependency injection and register types/services.
''' </summary>
''' <remarks></remarks>
Public NotInheritable Class UnityDI
''' <summary>
''' Method to register the Unity dependency injection component.
''' </summary>
''' <remarks>
''' This line of code below could alternatively be placed in Global.asax App_Start(), doing
''' so in this manner ensures that this gets run "PreStart".
''' </remarks>
Public Shared Sub Start()
' Set DI resolver
' NOTE: ECD - The UnityDependencyResolver below is part of the Unity.Mvc3 assembly
DependencyResolver.SetResolver(New UnityDependencyResolver(RegisterIocServices()))
End Sub
''' <summary>
''' Registers the IOC types/services.
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Shared Function RegisterIocServices() As IUnityContainer
' Create Unity dependency container
Dim dependencyContainer As IUnityContainer = New UnityContainer
' Register the relevant types/services for the container here through classes or configuration
With dependencyContainer
.RegisterType(Of IFormsAuthenticationService, FormsAuthenticationService)()
.RegisterType(Of IContactService, ContactService)()
.RegisterType(Of IProductItemService, ProductItemService)()
.RegisterType(Of ICustomerProductItemService, CustomerProductItemService)()
.RegisterType(Of ISystemTableItemService, SystemTableItemService)()
.RegisterType(Of ICatalogCodeService, CatalogCodeService)()
.RegisterType(Of IOrderService, OrderService)()
' TEST: This one is in the MVC project and works, the above are an external library
.RegisterType(Of IMessageService, MessageService)()
End With
Return dependencyContainer
End Function
End Class
End Namespace
上面的代码是我的注册过程。我也尝试过将其直接放入 global.asax 中并具有相同的行为。
更新2
解决了我的问题。
在我的控制器中,我具有以下属性:
<Dependency()>
Private Property CatalogCodeService As ICatalogCodeService
<Dependency()>
Private Property ContactService As IContactService
<Dependency()>
Private Property CustomerProductItemService As ICustomerProductItemService
但是在操作方法中访问服务总是会抛出错误,表明没有任何这些对象的实例。所以我认为这是我发布的原始代码或者我注册的方式中的某些内容。
事实证明这不是我的注册码,这完全没问题。
问题是什么?
这些属性必须是“公共”的! Private、Protected、Friend 都不适用于 IOC。一旦我将这些属性更改为“公共”,一切就开始完美运行。
我还没有验证这在 C# 中是否相同,所以如果有人可以添加他们的两分钱,请务必这样做。
去算算...
Strange issue I am having with my MVC3 project. I have followed a simple example of IOC using Unity.Mvc.
It works fine if my object and it's interface are in the web project itself (in this case IMessageService and MessageService). They clearly are working, no problems there.
But when I try to register my business service objects from an external assembly, they never get set to anything (always null). There are no errors in App-Start when they get registered, etc.
Anyone have any ideas? Desperate here....
UPDATE:
#Region "Imports"
Imports MyProject.Services
Imports MyProject.Services.Interfaces
Imports MyProject.Web.Mvc.Bootstrap
Imports MyProject.Web.Mvc.Services
Imports Microsoft.Practices.Unity
Imports Unity.Mvc3
#End Region
#Region "Assembly Meta"
' This tells the app to run the "Start" method prior to running the App_Start method in Global.asax
<Assembly: WebActivator.PreApplicationStartMethod(GetType(UnityDI), "Start")>
#End Region
Namespace MyProject.Web.Mvc.Bootstrap
''' <summary>
''' Class to setup dependency injection and register types/services.
''' </summary>
''' <remarks></remarks>
Public NotInheritable Class UnityDI
''' <summary>
''' Method to register the Unity dependency injection component.
''' </summary>
''' <remarks>
''' This line of code below could alternatively be placed in Global.asax App_Start(), doing
''' so in this manner ensures that this gets run "PreStart".
''' </remarks>
Public Shared Sub Start()
' Set DI resolver
' NOTE: ECD - The UnityDependencyResolver below is part of the Unity.Mvc3 assembly
DependencyResolver.SetResolver(New UnityDependencyResolver(RegisterIocServices()))
End Sub
''' <summary>
''' Registers the IOC types/services.
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Private Shared Function RegisterIocServices() As IUnityContainer
' Create Unity dependency container
Dim dependencyContainer As IUnityContainer = New UnityContainer
' Register the relevant types/services for the container here through classes or configuration
With dependencyContainer
.RegisterType(Of IFormsAuthenticationService, FormsAuthenticationService)()
.RegisterType(Of IContactService, ContactService)()
.RegisterType(Of IProductItemService, ProductItemService)()
.RegisterType(Of ICustomerProductItemService, CustomerProductItemService)()
.RegisterType(Of ISystemTableItemService, SystemTableItemService)()
.RegisterType(Of ICatalogCodeService, CatalogCodeService)()
.RegisterType(Of IOrderService, OrderService)()
' TEST: This one is in the MVC project and works, the above are an external library
.RegisterType(Of IMessageService, MessageService)()
End With
Return dependencyContainer
End Function
End Class
End Namespace
Above code is my registration process. I have also tried putting this directly in the global.asax and have the same behavior.
UPDATE 2
Figured out my issue.
In my controller, I have the following properties:
<Dependency()>
Private Property CatalogCodeService As ICatalogCodeService
<Dependency()>
Private Property ContactService As IContactService
<Dependency()>
Private Property CustomerProductItemService As ICustomerProductItemService
But accessing the services in an action method always threw an error that there was no instance of any of these objects. So I assumed it was the original code I posted or something in there in the way I was registering.
Turns out it was not my registration code, which is perfectly fine.
The issue?
The properties have to be "Public"!! Private, Protected, Friend all do not work for IOC. Once I changed those properties to "Public", everything started working perfectly fine.
I have not verified that this is the same in C#, so if anyone can add their two cents, please by all means do so.
Go figure...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
更新二:
上面的实现使用公共属性,它遵循依赖注入的“属性注入”模式。
此后我改用了更合适的“构造函数注入”方法。
通过此更改,我的控制器使用的服务属性可以是私有且只读的。
Mark Seemann 的“.NET 中的依赖注入”,很棒的书。我强烈建议任何实现依赖注入的人或那些只是想了解更多相关知识的人。
UPDATE II:
The above implementation was using public properties, which follows the "Property Injection" pattern of dependency injection.
I have since switched to the more appropriate "Constructor Injection" method.
With this change, that property for my services that my controller(s) use can be private AND read only.
"Dependency Injection in .NET" by Mark Seemann, great book. I highly suggest it for anyone implementing dependency injection or those just wanting to learn more about it.