简体   繁体   English

使用Entity Framework for ASP.NET MVC应用程序与Windows Service的行为不一致

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

I'm in the process of updating an existing ASP.NET MVC application to include some new functionality from another ASP.NET MVC application, and one component of this is a Windows service which will generate some documents following user input on the web app. 我正在更新现有的ASP.NET MVC应用程序以包括另一个ASP.NET MVC应用程序的一些新功能,而其中的一个组件是Windows服务,它将在用户在Web应用程序上输入后生成一些文档。 The whole solution uses Autofac for dependency injection, and Entity Framework for database interaction, with the model generated via an EDMX file using Database First. 整个解决方案使用Autofac进行依赖项注入,使用Entity Framework进行数据库交互,并使用使用Database First通过EDMX文件生成的模型。

The issue is that while the web application works fine, whenever the service tries to perform anything that goes back to the database, it throws an exception: 问题在于,尽管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' 对象集“ MyApp.Data.IMyAppEntityContext.AccreditationRules”和“ AccreditationRules”都可以包含“ MyApp.Data.AccreditationRule”类型的实例

Having looked at IMyAppEntityContext and its implementation, MyAppEntityContext, it does define the two different object sets across two different partial classes; 在查看了IMyAppEntityContext及其实现MyAppEntityContext之后,它确实在两个不同的部分类中定义了两个不同的对象集。 once in the automatically generated MyAppDataModel.Context.cs file: 一次进入自动生成的MyAppDataModel.Context.cs文件:

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

and then once in a MyAppEntityContext.cs file which implements IMyAppEntityContext: 然后一次在实现IMyAppEntityContext的MyAppEntityContext.cs文件中:

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

Please note that I'm fairly confident that the object/object set itself is not the issue - AccreditationRules happens to be the first set in each file as it's first alphabetically, and if I comment it out and remove all references to it, I get the same error just for the second object set on the list instead. 请注意,我很确定对象/对象集本身不是问题-AccreditationRules恰好是每个文件中的第一个集,因为它是按字母顺序排列的第一个,如果我注释掉它并删除对其的所有引用,我会得到相同的错误只是针对列表中设置的第二个对象。 Furthermore, the first time the service tries to use the database, it does this by executing a completely unrelated stored procedure that returns a different object altogether. 此外,服务首次尝试使用数据库时,它通过执行完全不相关的存储过程来执行此操作,该存储过程将完全返回另一个对象。

If I need to change how this is structured then fine, been planning to move away from the EDMX file approach at some point anyway - however what I don't understand is why this is fine for the ASP.NET MVC app and not for the Windows service app. 如果我需要更改其结构,那就好了,打算无论如何都打算离开EDMX文件方法-但是,我不明白的是为什么这对ASP.NET MVC应用程序适用,而不对Windows服务应用程序。 They both register the same modules, they use the same repository classes which then themselves interact with the database, it's just one works fine and the other doesn't. 他们两个都注册了相同的模块,使用了相同的存储库类,然后它们自己与数据库进行交互,只是一个很好,而另一个则没有。 I'm guessing that somewhere in the ASP.NET MVC app it's doing something differently to make it work, but apart from some MVC specific steps (eg registering MVC controllers) there's not really any difference - it registers the correct objects from the right assemblies so that's not an issue. 我猜想在ASP.NET MVC应用程序的某个地方 ,它的工作方式有所不同,但是除了某些MVC特定的步骤(例如,注册MVC控制器)之外,没有什么区别-它从正确的程序集中注册了正确的对象所以这不是问题。

In case it helps, here's my ConfigureContainer() method from my ASP.NET MVC app, which gets called in Application_Start() within Global.asax.cs: 如果有帮助的话,这是我的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);
}

And the following is called when my service starts: 当我的服务启动时,将调用以下命令:

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();
}

and then that gets used by the service as follows: 然后该服务将按如下方式使用该服务:

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

Is anyone able to shed any light on this or point me in the right direction? 有谁能对此有所了解或为我指明正确的方向?

So after trying various different things and going down multiple rabbit holes, the solution was far more mundane than I expected - my connection string was wrong! 因此,在尝试了各种不同的操作并钻了多个兔子洞之后,解决方案比我预期的要平凡得多-我的连接字符串有误!

Originally my service had the following connection string: 最初,我的服务具有以下连接字符串:

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

but my ASP.NET MVC web app had one that looked like this: 但是我的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" />

Copied the connection string from my MVC app to my service, works absolutely fine now. 将连接字符串从我的MVC应用复制到我的服务,现在可以正常使用了。

Guessing that with the latter, EF gets told what the model is and that works fine, but with the former EF doesn't know what model to use so tries to work one out, and then throws the exception I was getting because of the duplicate declaration. 猜测是后者,EF被告知模型是什么,并且可以正常工作,但是对于前者,EF不知道要使用哪种模型,因此尝试解决这个问题,然后抛出由于重复而得到的异常宣言。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM