【问题标题】:Autofac not resolving types from assembly scan in asp.net 5Autofac 无法从 asp.net 5 中的程序集扫描中解析类型
【发布时间】:2016-03-25 19:16:29
【问题描述】:

我们有一个 dnx46 网络项目,它在启动期间使用 autofac 程序集扫描来注册类型。我们的 project.json 依赖包括:

"Autofac.Configuration": "4.0.0-rc1-268",
"Autofac.Extensions.DependencyInjection": "4.0.0-rc1-177",
"Autofac.Extras.CommonServiceLocator": "3.2.0",
"Microsoft.AspNet.Hosting": "1.0.0-rc1-final",
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.AspNet.Session": "1.0.0-rc1-final",
"Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
"Microsoft.AspNet.Tooling.Razor": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final",
"Microsoft.Extensions.Logging": "1.0.0-rc1-final",
"Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final",
"Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final",
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-rc1-final",
"Newtonsoft.Json": "8.0.3"

我们的 startup.cs ConfigureServices 方法如下所示:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(serviceType => Configuration);
    services.AddInstance<Microsoft.Extensions.Configuration.IConfiguration>(Configuration);

    services.AddCaching();
    services.AddSession();
    services.AddMvc();

    var builder = new ContainerBuilder();

    var assemblies = Directory.GetFiles(<ourBinDirectoryPath>, "*.dll", SearchOption.TopDirectoryOnly).Select(Assembly.LoadFrom);

    foreach (var assembly in assemblies)
    {
        builder.RegisterAssemblyTypes(assembly).Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repository") || t.Name.EndsWith("DataContext")).AsSelf().AsImplementedInterfaces();
        builder.RegisterAssemblyTypes(assembly).Where(t => !t.Name.EndsWith("Service") && !t.Name.EndsWith("Repository") && !t.Name.EndsWith("DataContext")).AsSelf().AsImplementedInterfaces().InstancePerDependency();
    }

    builder.Populate(services);
    var container = builder.Build();

    return container.Resolve<IServiceProvider>();
}

我们的流程是,我们构建了几个项目,将这个项目需要的 dll 放入自定义 bin 文件夹中。在启动时,我们扫描这些程序集以向 Autofac 注册类型。我们在一个概念验证项目中做到了这一点,并且没有问题。但在我们的新项目中,我们遇到了以下问题:

  1. 如果您尝试在控制器构造函数中解析服务,它 抛出一个错误,表明 Microsoft 依赖注入不能 解决服务。不知道为什么它不使用 Autofac 供应商在这里。
  2. 如果我们在启动时手动解析单个类型以及我们的程序集扫描,我们将在控制器构造中收到错误,指示 Autofac 无法解析服务(此处使用 Autofac 提供程序,但仍然找不到我们的类型)。
  3. 如果我在构建器和容器返回到 ConfigureServices 之前检查它,它似乎已经注册了我们所有的类型。但是,如果我更改控制器以注入 IServiceProvider,然后尝试从中解析服务,它会准确地使用 Autofac 提供程序,但我总是返回 null(未找到服务)。

在尝试了很多事情之后,我将我们的概念验证项目复制到我们的新解决方案中(以防我们在设置新项目时错过了一些小的设置或其他东西),但不良行为仍在继续。我开始认为我们的程序集引入了一些错误(因为这些是复制后唯一改变的东西),但是 Autofac 在扫描期间不会抛出错误,而是没有使用它正确扫描的类型.

编辑 1

我创建并发布了一个very simplified example,它重现了我遇到的问题。您应该能够将其拉下来并运行它以重现错误。您应该在主控制器构造函数中收到一个错误,指示服务解析失败。

注意:运行此示例时,它会执行一个 .bat 文件,该文件将来自域项目的输出 dll 放入您的用户配置文件 .nuget 文件夹中。

编辑 2

根据@Travis Illig 的建议将接口拆分为抽象文件夹。一旦我这样做了,解决方案就开始起作用了。我们将它拆分到我们的“真实”项目中,但它不起作用。仍在尝试找出原因。

编辑 3

所以终于让我们的项目再次工作了。问题最终是几件事:

  1. 我们的 Web 项目中列出了一个抽象项目依赖项,我们还从该程序集加载和扫描 dll(双重加载)。 (我认为这是个大问题。)
  2. 我们的 NuGet 版本很糟糕,所以我认为它们没有正确加载。我们使用的是 1.0.0-1,这是一种无效的预发布格式。将其更新为 1.0.0-b1,一切似乎开始变得更好。

这让我花了更长的时间才弄明白,我目前最大的问题是 Autofac 会默默地失败。我真的希望它会爆炸并给我一些调试输出或表明存在问题的东西。相反,一切似乎都可以正常扫描和加载,但是当您使用容器时,什么都无法解决。

【问题讨论】:

    标签: asp.net asp.net-mvc autofac


    【解决方案1】:

    程序集的加载顺序可能是由于未加载必备程序集而导致某些类型无法加载的顺序。

    例如,假设您有包含接口 IComponent 的程序集 A。还假设您有包含实现IComponent 的类Component 的程序集B。如果您先加载程序集 B,则类型 Component 将无法加载,因为它实现的接口未定义。

    在进行类型扫描时,Autofac 会尝试尽可能安全,并且在遇到无法加载的类型时不会爆炸。您可以在scanning registration source 中看到它使用特殊的安全方法进行加载。

    在您的尖峰代码中,我敢打赌要加载的程序集要少得多,因此您最终以正确的顺序加载了内容。快乐的意外。当您进入较大的项目时,更容易控制加载顺序并导致此类问题。

    【讨论】:

    • 所以我们最终指定了一个程序集加载顺序(所以首先是抽象,然后是基类等)。同样的行为继续。我认为你所说的仍然有道理,但它可能比我希望的更细化。我现在正在单独重新申请课程,直到我可以重复该行为,然后决定我们如何着手解决。谢谢指点。
    • 实际上,您指向代码的指针帮助了我。我没有意识到它可以使用一组程序集,然后创建一个包含所有可加载类型的集合。这可能有助于解决订单问题。我会看看我是否可以利用这一点。
    • 更新:因此更改顺序或一次加载所有程序集不起作用。所以我最终创建了一个全新的项目,它有一个只有 1 个接口和 1 个类的程序集。经历与上述完全相同的行为。当我今晚晚些时候回来时,我可能会将这个新项目推到 github 上,看看是否有人对发生的事情有想法。
    • 好的,我创建了一个简单的示例来重现此问题。 github.com/RemyArmstro/AutofacSample 当你运行它时,你会看到 IOrder 没有在 home 控制器中解析,错误是从 Microsoft DI 抛出的,而不是从 Autofac 抛出的。
    • 将此标记为答案,仅仅是因为我相信您最初的前提是正确的。我认为我们正在加载的一个程序集依赖于我们未加载的另一个程序集(基类)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多