将 Entity Framework 用于 ASP.NET MVC 应用与 windows 服务的行为不一致

Inconsistent behaviour using Entity Framework for ASP.NET MVC app vs windows service

我正在更新现有的 ASP.NET MVC 应用程序以包含来自另一个 ASP.NET MVC 应用程序的一些新功能,其中一个组件是 Windows 服务它将根据用户在网络应用程序上的输入生成一些文档。整个解决方案使用 Autofac 进行依赖注入,Entity Framework 进行数据库交互,模型通过使用数据库优先的 EDMX 文件生成。

问题是,虽然 Web 应用程序运行良好,但每当服务尝试执行任何返回到数据库的操作时,它都会抛出异常:

Multiple object sets per type are not supported. The object sets 'MyApp.Data.IMyAppEntityContext.AccreditationRules' and 'AccreditationRules' can both contain instances of type 'MyApp.Data.AccreditationRule'

查看了 IMyAppEntityContext 及其实现 MyAppEntityContext,它确实在两个不同的部分 类 中定义了两个不同的对象集;一旦在自动生成的 MyAppDataModel.Context.cs 文件中:

public virtual DbSet<AccreditationRule> AccreditationRules { get; set; }

然后在实现 IMyAppEntityContext 的 MyAppEntityContext.cs 文件中一次:

IDbSet<AccreditationRule> IMyAppEntityContext.AccreditationRules
{
    get { return AccreditationRules;  }
}

请注意,我非常有信心 object/object 集本身不是问题 - AccreditationRules 恰好是每个文件中的第一个集,因为它按字母顺序排列,如果我将其注释掉并删除所有对它的引用,我只为列表中的第二个对象集得到同样的错误。此外,服务第一次尝试使用数据库时,它通过执行一个完全不相关的存储过程来实现,returns 完全是一个不同的对象。

如果我需要改变它的结构,那很好,无论如何我都计划在某个时候放弃 EDMX 文件方法 - 但是我不明白的是为什么这对 ASP.NET MVC 应用程序,不适用于 Windows 服务应用程序。他们都注册了相同的模块,他们使用相同的存储库 类 然后他们自己与数据库交互,它只是一个工作正常而另一个没有。我猜 某处 在 ASP.NET MVC 应用程序中它正在做一些不同的事情来使其工作,但除了一些 MVC 特定步骤(例如注册 MVC 控制器)之外并没有真正任何区别 - 它从正确的程序集中注册正确的对象,所以这不是问题。

如果有帮助,这是我的 ASP.NET MVC 应用程序中的 ConfigureContainer() 方法,它在 Global.asax.cs:

中的 Application_Start() 中被调用
public static void ConfigureContainer()
{
    var builder = new ContainerBuilder();

    var asm = BuildManager.GetReferencedAssemblies().Cast<Assembly>()
        .Where(x => x.FullName.StartsWith("MyApp."))
        .ToArray();

    builder.RegisterAssemblyModules(asm);
    RegisterLocalTypes(builder); //register types specific to this app

    //MVC specific registration
    builder.RegisterControllers(typeof(MvcApplication).Assembly);
    builder.RegisterApiControllers(typeof(MvcApplication).Assembly);
    builder.RegisterFilterProvider();
    builder.RegisterModule(new AutofacWebTypesModule());

    var container = builder.Build();

    //more MVC specific configuration
    var resolver = new AutofacDependencyResolver(container);
    DependencyResolver.SetResolver(resolver);
    var config = GlobalConfiguration.Configuration;
    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}

我的服务启动时会调用以下内容:

public static IContainer AutofacContainer = null;

private void SetupAutofacContainer()
{
    var builder = new ContainerBuilder();

    var asm = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory)
        .Where(file => Path.GetExtension(file) == ".dll")
        .Select(file => Assembly.LoadFrom(file))
        .Where(_ => _.FullName.StartsWith("MyApp."));

    builder.RegisterAssemblyModules(asm.ToArray());
    RegisterLocalTypes(builder); //register types specific to this app        

    AutofacContainer = builder.Build();
}

然后服务按如下方式使用它:

using (var scope = AutofacContainer.BeginLifetimeScope())
{
    //the actual service code
}

有没有人能阐明这一点或为我指明正确的方向?

所以在尝试了各种不同的东西并钻进了多个兔子洞之后,解决方案比我预期的要简单得多 - 我的连接字符串是错误的!

最初我的服务有以下连接字符串:

<add name="MyAppEntityContext" connectionString="data source=server;initial catalog=db;integrated security=True;MultipleActiveResultSets=True;" providerName="System.Data.SqlClient" />

但是我的 ASP.NET MVC web 应用程序看起来像这样:

<add name="MyAppEntityContext" connectionString="metadata=res://*/MyAppDataModel.csdl|res://*/MyAppDataModel.ssdl|res://*/MyAppDataModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=server;initial catalog=db;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

已将连接字符串从我的 MVC 应用程序复制到我的服务,现在工作得很好。

猜测对于后者,EF 被告知模型是什么并且工作正常,但是对于前者 EF 不知道要使用什么模型所以尝试找出一个模型,然后抛出异常我是由于重复声明。