简体   繁体   中英

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. 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.

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:

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'

Having looked at IMyAppEntityContext and its implementation, MyAppEntityContext, it does define the two different object sets across two different partial classes; once in the automatically generated MyAppDataModel.Context.cs file:

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

and then once in a MyAppEntityContext.cs file which implements IMyAppEntityContext:

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. 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. 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.

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:

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:

<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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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