Unity 4(IOC) + MVC 5 在启动期间无法解析类型
Unity 4(IOC) + MVC 5 unable to resolve types during startup
我将 Unity 4(通过 NuGet)与 ASP.NET MVC 5 一起使用。我已经修改了我所有的控制器和业务 classes 以通过它们的构造函数接收它们的依赖项作为接口。
boostrapper class 包含以下代码:
public class Bootstrapper
{
public static IUnityContainer UnityContainer { get; set; }
public static void Initialize()
{
InitializeUnity();
RegisterTypes();
}
private static void InitializeUnity()
{
UnityContainer = UnityConfig.GetConfiguredContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityContainer));
}
private static void RegisterTypes()
{
new Core.Bootstrapper().RegisterTypes(UnityContainer);
}
}
Core.Bootstrapper().RegisterTypes内容如下:
public IUnityContainer RegisterTypes(IUnityContainer container)
{
// Register repositories
container.RegisterType<IRepository, Repository>()
.RegisterType<IBdeRepository, BdeRepository>()
.RegisterType<IDocumentRepository, DocumentRepository>()
.RegisterType<IHampRepository, HampRepository>()
.RegisterType<IReportsRepository, ReportsRepository>()
.RegisterType<ITransactionRepository, TransactionRepository>();
// Register commands
container.RegisterType<IBaseCommand, BaseCommand>()
.RegisterType<IDailyLetterInfoUpdate, DailyLetterInfoUpdate>()
.RegisterType<IDailyReconciliation, DailyReconciliation>()
.RegisterType<InsertNewRows, InsertNewRows>()
.RegisterType<IOrderDailyLM023, OrderDailyLM023>()
.RegisterType<IOrderMonthlyLM012, OrderMonthlyLM012>()
.RegisterType<IOrderMonthlyLM014, OrderMonthlyLM014>()
.RegisterType<IPerformMonthlyRecastStatusUpdate, PerformMonthlyRecastStatusUpdate>()
.RegisterType<IUpdateReissuedRecasts, UpdateReissuedRecasts>();
// Register utility types
container.RegisterType<ICsvExporter, CsvExporter>()
.RegisterType<ILogger, Logger>();
return container;
}
最后,UnityConfig.cs 和 UnityMvcActivator.cs 与 NuGet 包首次安装它们时的状态相比没有任何变化。
当我启动 MVC 应用程序时,遇到以下错误消息:
Resolution of the dependency failed, type = "System.Web.Mvc.ITempDataProviderFactory", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, System.Web.Mvc.ITempDataProviderFactory, is an interface and cannot be constructed. Are you missing a type mapping?
它提到的 class 似乎是 MVC 本身内部的东西,这让我相信我在配置 Unity 时错过了一些东西,或者我在这样做时搞砸了一些东西。然而,对于我的生活,我无法弄清楚它是什么,尽管我已经咨询了几乎所有我能找到的关于 Whosebug 上错误消息的问题。 (到目前为止,None 的提议解决方案已经解决了这个问题,但很可能我遗漏了一些东西。)
谁能看到我忽略的东西?我做错了什么?
更新:
这里抛出异常:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes(); // Exception thrown on this line.
}
我找到了适合我的特定场景的解决方案,这有点令人惊讶。
我不得不推出自己的 DependencyResolver class 并使用它来代替 Unity 提供的 MVC 解析器。我写的解析器如下:
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
/// <summary>
/// Resolves dependencies against the current DI container.
/// </summary>
public class UnityDependencyResolver : IDependencyResolver
{
/// <summary>
/// The container
/// </summary>
private readonly IUnityContainer container;
/// <summary>
/// Initializes a new instance of the <see cref="UnityDependencyResolver"/> class.
/// </summary>
/// <param name="container">The container.</param>
public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
}
/// <summary>
/// Resolves an instance of the default requested type from the container.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the object to get from the container.</param>
/// <returns>The requested object, if it can be resolved; otherwise, <c>null</c>.</returns>
public object GetService(Type serviceType)
{
return this.container.IsRegistered(serviceType)
? this.container.Resolve(serviceType)
: null;
}
/// <summary>
/// Resolves multiply registered services.
/// </summary>
/// <param name="serviceType">The type of the requested services.</param>
/// <returns>The requested services.</returns>
public IEnumerable<object> GetServices(Type serviceType)
{
return this.container.ResolveAll(serviceType);
}
}
最重要的部分是 GetService 的实现:它必须 return null
如果它不能解析类型,否则,MVC肚皮向上并抛出消息异常,"XXX is an interface, and can't be constructed. Are you missing a binding?"
这当然改变了 Bootstrapper.cs 中这行代码的行为:
DependencyResolver.SetResolver(
new UnityDependencyResolver(UnityContainer));
它使用本地实现而不是默认的 Unity 实现。
奇怪的是,我从中提取的示例应用程序在我的机器上本地运行,而且它没有使用自定义解析器。没有这个 class 也能正常工作。我不知道为什么会这样,这很麻烦(我更喜欢确定性的问题答案),但此时我很高兴我可以重新开始工作。
这里有一个略有不同的实现,其中对 MVC 部分进行了特定排除,改编自 UnityDependencyResolver.cs
中的代码
似乎在启动时有轻微的性能优势,但主要是您不会引发 10 个异常。
/// <summary>
/// Resolves dependencies against the current DI container.
/// </summary>
public class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer container;
// NB Not likely to be be big but will be frequent so use HashSet as O(1) lookup cost - see
private readonly HashSet<Type> excludedTypes;
/// <summary>
/// Initializes a new instance of the <see cref="UnityDependencyResolver"/> class.
/// </summary>
/// <param name="container">The container.</param>
public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
excludedTypes = new HashSet<Type>();
StandardExclusions();
}
/// <summary>
/// Resolves an instance of the default requested type from the container.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the object to get from the container.</param>
/// <returns>The requested object.</returns>
public object GetService(Type serviceType)
{
if (typeof(IController).IsAssignableFrom(serviceType))
{
return container.Resolve(serviceType);
}
try
{
return excludedTypes.Contains(serviceType) ? null : container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
/// <summary>
/// Resolves multiply registered services.
/// </summary>
/// <param name="serviceType">The type of the requested services.</param>
/// <returns>The requested services.</returns>
public IEnumerable<object> GetServices(Type serviceType)
{
return container.ResolveAll(serviceType);
}
public void Exclude<T>()
{
Exclude(typeof(T));
}
public void Exclude(Type type)
{
excludedTypes.Add(type);
}
public void Include<T>()
{
Include(typeof(T));
}
public void Include(Type type)
{
excludedTypes.Remove(type);
}
private void StandardExclusions()
{
Exclude<System.Web.Mvc.IControllerFactory>();
Exclude<System.Web.Mvc.IControllerActivator>();
Exclude<System.Web.Mvc.ITempDataProviderFactory>();
Exclude<System.Web.Mvc.ITempDataProvider>();
Exclude<System.Web.Mvc.Async.IAsyncActionInvokerFactory>();
Exclude<System.Web.Mvc.IActionInvokerFactory>();
Exclude<System.Web.Mvc.Async.IAsyncActionInvoker>();
Exclude<System.Web.Mvc.IActionInvoker>();
Exclude<System.Web.Mvc.IViewPageActivator>();
Exclude<System.Web.Mvc.ModelMetadataProvider>();
}
}
如果您确实覆盖了标准 MVC 接口之一,则可以使用
将其从排除列表中删除
var resolver = new UnityDependencyResolver(container);
resolver.Include<System.Web.Mvc.IActionInvoker>();
我将 Unity 4(通过 NuGet)与 ASP.NET MVC 5 一起使用。我已经修改了我所有的控制器和业务 classes 以通过它们的构造函数接收它们的依赖项作为接口。
boostrapper class 包含以下代码:
public class Bootstrapper
{
public static IUnityContainer UnityContainer { get; set; }
public static void Initialize()
{
InitializeUnity();
RegisterTypes();
}
private static void InitializeUnity()
{
UnityContainer = UnityConfig.GetConfiguredContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityContainer));
}
private static void RegisterTypes()
{
new Core.Bootstrapper().RegisterTypes(UnityContainer);
}
}
Core.Bootstrapper().RegisterTypes内容如下:
public IUnityContainer RegisterTypes(IUnityContainer container)
{
// Register repositories
container.RegisterType<IRepository, Repository>()
.RegisterType<IBdeRepository, BdeRepository>()
.RegisterType<IDocumentRepository, DocumentRepository>()
.RegisterType<IHampRepository, HampRepository>()
.RegisterType<IReportsRepository, ReportsRepository>()
.RegisterType<ITransactionRepository, TransactionRepository>();
// Register commands
container.RegisterType<IBaseCommand, BaseCommand>()
.RegisterType<IDailyLetterInfoUpdate, DailyLetterInfoUpdate>()
.RegisterType<IDailyReconciliation, DailyReconciliation>()
.RegisterType<InsertNewRows, InsertNewRows>()
.RegisterType<IOrderDailyLM023, OrderDailyLM023>()
.RegisterType<IOrderMonthlyLM012, OrderMonthlyLM012>()
.RegisterType<IOrderMonthlyLM014, OrderMonthlyLM014>()
.RegisterType<IPerformMonthlyRecastStatusUpdate, PerformMonthlyRecastStatusUpdate>()
.RegisterType<IUpdateReissuedRecasts, UpdateReissuedRecasts>();
// Register utility types
container.RegisterType<ICsvExporter, CsvExporter>()
.RegisterType<ILogger, Logger>();
return container;
}
最后,UnityConfig.cs 和 UnityMvcActivator.cs 与 NuGet 包首次安装它们时的状态相比没有任何变化。
当我启动 MVC 应用程序时,遇到以下错误消息:
Resolution of the dependency failed, type = "System.Web.Mvc.ITempDataProviderFactory", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, System.Web.Mvc.ITempDataProviderFactory, is an interface and cannot be constructed. Are you missing a type mapping?
它提到的 class 似乎是 MVC 本身内部的东西,这让我相信我在配置 Unity 时错过了一些东西,或者我在这样做时搞砸了一些东西。然而,对于我的生活,我无法弄清楚它是什么,尽管我已经咨询了几乎所有我能找到的关于 Whosebug 上错误消息的问题。 (到目前为止,None 的提议解决方案已经解决了这个问题,但很可能我遗漏了一些东西。)
谁能看到我忽略的东西?我做错了什么?
更新:
这里抛出异常:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes(); // Exception thrown on this line.
}
我找到了适合我的特定场景的解决方案,这有点令人惊讶。
我不得不推出自己的 DependencyResolver class 并使用它来代替 Unity 提供的 MVC 解析器。我写的解析器如下:
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
/// <summary>
/// Resolves dependencies against the current DI container.
/// </summary>
public class UnityDependencyResolver : IDependencyResolver
{
/// <summary>
/// The container
/// </summary>
private readonly IUnityContainer container;
/// <summary>
/// Initializes a new instance of the <see cref="UnityDependencyResolver"/> class.
/// </summary>
/// <param name="container">The container.</param>
public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
}
/// <summary>
/// Resolves an instance of the default requested type from the container.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the object to get from the container.</param>
/// <returns>The requested object, if it can be resolved; otherwise, <c>null</c>.</returns>
public object GetService(Type serviceType)
{
return this.container.IsRegistered(serviceType)
? this.container.Resolve(serviceType)
: null;
}
/// <summary>
/// Resolves multiply registered services.
/// </summary>
/// <param name="serviceType">The type of the requested services.</param>
/// <returns>The requested services.</returns>
public IEnumerable<object> GetServices(Type serviceType)
{
return this.container.ResolveAll(serviceType);
}
}
最重要的部分是 GetService 的实现:它必须 return null
如果它不能解析类型,否则,MVC肚皮向上并抛出消息异常,"XXX is an interface, and can't be constructed. Are you missing a binding?"
这当然改变了 Bootstrapper.cs 中这行代码的行为:
DependencyResolver.SetResolver(
new UnityDependencyResolver(UnityContainer));
它使用本地实现而不是默认的 Unity 实现。
奇怪的是,我从中提取的示例应用程序在我的机器上本地运行,而且它没有使用自定义解析器。没有这个 class 也能正常工作。我不知道为什么会这样,这很麻烦(我更喜欢确定性的问题答案),但此时我很高兴我可以重新开始工作。
这里有一个略有不同的实现,其中对 MVC 部分进行了特定排除,改编自 UnityDependencyResolver.cs
中的代码似乎在启动时有轻微的性能优势,但主要是您不会引发 10 个异常。
/// <summary>
/// Resolves dependencies against the current DI container.
/// </summary>
public class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer container;
// NB Not likely to be be big but will be frequent so use HashSet as O(1) lookup cost - see
private readonly HashSet<Type> excludedTypes;
/// <summary>
/// Initializes a new instance of the <see cref="UnityDependencyResolver"/> class.
/// </summary>
/// <param name="container">The container.</param>
public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
excludedTypes = new HashSet<Type>();
StandardExclusions();
}
/// <summary>
/// Resolves an instance of the default requested type from the container.
/// </summary>
/// <param name="serviceType">The <see cref="Type"/> of the object to get from the container.</param>
/// <returns>The requested object.</returns>
public object GetService(Type serviceType)
{
if (typeof(IController).IsAssignableFrom(serviceType))
{
return container.Resolve(serviceType);
}
try
{
return excludedTypes.Contains(serviceType) ? null : container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
/// <summary>
/// Resolves multiply registered services.
/// </summary>
/// <param name="serviceType">The type of the requested services.</param>
/// <returns>The requested services.</returns>
public IEnumerable<object> GetServices(Type serviceType)
{
return container.ResolveAll(serviceType);
}
public void Exclude<T>()
{
Exclude(typeof(T));
}
public void Exclude(Type type)
{
excludedTypes.Add(type);
}
public void Include<T>()
{
Include(typeof(T));
}
public void Include(Type type)
{
excludedTypes.Remove(type);
}
private void StandardExclusions()
{
Exclude<System.Web.Mvc.IControllerFactory>();
Exclude<System.Web.Mvc.IControllerActivator>();
Exclude<System.Web.Mvc.ITempDataProviderFactory>();
Exclude<System.Web.Mvc.ITempDataProvider>();
Exclude<System.Web.Mvc.Async.IAsyncActionInvokerFactory>();
Exclude<System.Web.Mvc.IActionInvokerFactory>();
Exclude<System.Web.Mvc.Async.IAsyncActionInvoker>();
Exclude<System.Web.Mvc.IActionInvoker>();
Exclude<System.Web.Mvc.IViewPageActivator>();
Exclude<System.Web.Mvc.ModelMetadataProvider>();
}
}
如果您确实覆盖了标准 MVC 接口之一,则可以使用
将其从排除列表中删除var resolver = new UnityDependencyResolver(container);
resolver.Include<System.Web.Mvc.IActionInvoker>();