【发布时间】:2018-01-31 05:38:29
【问题描述】:
当前项目:
- ASP.NET MVC 5 boilerplate (Github)
- 为 Unity 切换 Autofac
当我将 DI 从 AutoFac 切换到 Unity 时,我无法让样板文件(robots.txt、sitemap.xml)中内置的服务恢复并运行。特别是,我无法将这些服务的 Autofac 条目翻译成适当的 Unity 条目。
我的 HomeController 默认构造函数与默认构造没有变化,至少对于我正在对其进行试金石测试的 robots.txt:
private readonly IRobotsService _robotsService;
public HomeController(IRobotsService robotsService) {
_robotsService = robotsService;
}
我的 HomeController 中的 robots.txt 方法同样是样板的默认方法:
[NoTrailingSlash]
[OutputCache(CacheProfile = CacheProfileName.RobotsText)]
[Route("robots.txt", Name = HomeControllerRoute.GetRobotsText)]
public ContentResult RobotsText() {
Trace.WriteLine($"robots.txt requested. User Agent:<{Request.Headers.Get("User-Agent")}>.");
var content = _robotsService.GetRobotsText();
return Content(content, ContentType.Text, Encoding.UTF8);
}
IRobotsService 和 RobotsService 文件也是样板的默认文件 - 它们完全未修改(为简洁起见删除了 cmets):
namespace Project.Website.Services {
public interface IRobotsService {
string GetRobotsText();
}
}
namespace Project.Website.Services {
using Boilerplate.Web.Mvc;
using Constants;
using System.Text;
using System.Web.Mvc;
public sealed class RobotsService : IRobotsService {
private readonly UrlHelper _urlHelper;
public RobotsService(UrlHelper urlHelper) => _urlHelper = urlHelper;
public string GetRobotsText() {
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("user-agent: *");
stringBuilder.AppendLine("disallow: /error/");
stringBuilder.Append("sitemap: ");
// Commented out so it wouldn't trigger the sitemap, which is not active:
//stringBuilder.AppendLine(_urlHelper.AbsoluteRouteUrl(HomeControllerRoute.GetSitemapXml).TrimEnd('/'));
return stringBuilder.ToString();
}
}
}
Autofac原来的Startup.Container.cs相当广泛,但是robots.txt服务是由以下人注入的:
builder.RegisterType<RobotsService>().As<IRobotsService>().InstancePerRequest();
当我的 UnityConfig.cs 文件具有以下内容时:
container.RegisterType<RobotsService>(new TransientLifetimeManager());
我明白了
当前类型
JCI_Vernon.Website.Services.IRobotsService是一个接口,不能构造。您是否缺少类型映射?
这很好地告诉我我必须包含 IRobotsService,但是当我的 UnityConfig 文件具有以下内容时:
container.RegisterType<IRobotsService, RobotsService>(new TransientLifetimeManager());
我明白了
当前类型
System.Web.HttpContextBase是一个抽象类,无法构造。您是否缺少类型映射?
我不确定我哪里出错了,因为我项目中的所有其他 Unity DI 都是使用这两个变体之一配置的。
任何帮助将不胜感激。
编辑:包括我的主要项目(可见网站)中的 Unity 文件。
UnityMvcActivator.cs:
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(JCI_Vernon.Website.UnityMvcActivator), nameof(JCI_Vernon.Website.UnityMvcActivator.Start))]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(JCI_Vernon.Website.UnityMvcActivator), nameof(JCI_Vernon.Website.UnityMvcActivator.Shutdown))]
namespace JCI_Vernon.Website {
using System.Linq;
using System.Web.Mvc;
using Unity.AspNet.Mvc;
/// <summary>
/// Provides the bootstrapping for integrating Unity with ASP.NET MVC.
/// </summary>
public static class UnityMvcActivator {
/// <summary>
/// Integrates Unity when the application starts.
/// </summary>
public static void Start() {
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(UnityConfig.Container));
DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
// Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>
/// Disposes the Unity container when the application is shut down.
/// </summary>
public static void Shutdown() {
UnityConfig.Container.Dispose();
}
}
}
UnityConfig.cs:
namespace JCI_Vernon.Website {
using Data;
using Domain;
using Identity;
using Microsoft.AspNet.Identity;
using Services;
using Store;
using System;
using System.Web;
using System.Web.Mvc;
using Unity;
using Unity.Injection;
using Unity.Lifetime;
using Unity.Mvc5;
public static class UnityConfig {
public static IUnityContainer Container { get; internal set; }
public static void RegisterComponents() {
var container = new UnityContainer();
container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager(), new InjectionConstructor("DefaultConnection"));
container.RegisterType<IUserStore<IdentityUser, Guid>, UserStore>(new TransientLifetimeManager());
container.RegisterType<RoleStore>(new TransientLifetimeManager());
container.RegisterInstance<HttpContextBase>(new HttpContextWrapper(HttpContext.Current), new TransientLifetimeManager());
container.RegisterType<IRobotsService, RobotsService>(new Unity.AspNet.Mvc.PerRequestLifetimeManager());
//container.RegisterType<ISitemapService, SitemapService>(new InjectionConstructor());
//container.RegisterType<ISitemapPingerService, SitemapPingerService>(new InjectionConstructor());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
}
在我的UnityMvcActivator.cs 中,我有一个PerRequestLifetimeManager 行对每次更改都进行了评论和取消评论,没有观察到差异。在没有 Unity.Mvc(如 using Unity.AspNet.Mvc;)的情况下,在 UnityConfig.cs 中使用 PerRequestLifetimeManager 的任何尝试都失败了。
将UnityConfig.cs 更改为包含Unity.AspNet.Mvc 会导致大量垃圾:虽然我能够在没有明显Intellisense 错误的情况下让PerRequestLifetimeManager 被接受,但UnityMvcActivator.cs 突然无法解析其UnityConfig.Container 条目而没有一个非常奇怪的条目UnityConfig.cs顶部的入口:
public static IUnityContainer Container { get; internal set; }
UnityConfig.cs 中的 SetResolver 需要显式声明 new Unity.Mvc5.UnityDependencyResolver(container) 以免引发 Intellisense 混淆。
另外,运行时出现以下错误:
无法加载文件或程序集“Unity.Abstractions,Version=3.1.3.0,Culture=neutral,PublicKeyToken=6d32ff45e0ccc69f”或其依赖项之一。找到的程序集的清单定义与程序集引用不匹配。 (HRESULT 异常:0x80131040)
尽管整个解决方案都是在 v5.x 下创建的,但为什么它仍试图针对 Unity 的 v3.x,这导致我的灰质无休止的崩溃。是的,我对整个解决方案以及各个项目进行了全面清理和重建。
编辑 2:
可能遇到了一个有趣的皱纹。高兴的是,我决定完全重新安装所有 NuGet 包,刷新一下。自然,当您升级或重新安装 Unity 时,它会尝试覆盖您的统一文件,这就是为什么您总是需要备份您的 UnityConfig.cs 否则您的注册将消失。每次都发生在我身上。单身的。他妈的。项目。好烦。
所以无论如何,我进行了一次全面刷新,我的UnityConfig.cs 突然发生了重大变化。之前如上,包括 v5 内的所有升级,但刷新为我提供了以下内容(为简洁起见,删除了 cmets):
namespace JCI_Vernon.Website {
using System;
using Unity;
public static class UnityConfig {
#region Unity Container
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() => {
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer Container => container.Value;
#endregion
public static void RegisterTypes(IUnityContainer container) {
// TODO: Register your type's mappings here.
// container.RegisterType<IProductRepository, ProductRepository>();
}
}
}
是的,很奇怪。不知道为什么的重大变化。旧版本工作得很好,它只是把它的 cookie 吹到了这篇文章所涉及的特定类型映射上。
另外,我必须知道将Global.cs 条目更改为什么才能加载我的类型映射,因为仅使用显而易见的(将无法找到的UnityConfig.RegisterComponents() 更改为UnityConfig.RegisterTypes())不会使任何意义——我如何通过容器?
【问题讨论】:
-
when you do an upgrade or reinstall of Unity, it tries to overwrite your unity files- 这是我从不将“适配器包”用于任何 DI 容器的原因之一。通过自己连接实现来保持直截了当要简单得多。我的建议是manually go through the project 并取出任何“旧”Unity 东西并升级到相应的“新”Unity 东西。然后进行“新”配置。 -
仅供参考 - 我找到了“新”PerRequestLifetimeManager here。
-
@NightOwl888 - 是的,我上面提到的
Unity.Mvc,以及下面答案的cmets。还是个问题。
标签: dependency-injection asp.net-mvc-5 autofac