3

I have two projects that use the following Unity logic:

container.RegisterType<IUnitOfWork, MyDbContext>(
    new HierarchicalLifetimeManager(),
    new InjectionFactory(
        c => new MyDbContext(configurationService.MySqlConnectionString)
    )
);
container.RegisterType<DbContext, MyDbContext>(
    new HierarchicalLifetimeManager()
);

The first project is a web application that utilises the Unity.MVC4 package so has a bespoke DependencyResolver doing some of the work - this works perfectly.

The second is a non-web application so uses a normal Unity package instance but errors when a call is made that uses MyDbContext. The exception is

System.Data.Entity.Core.MetadataException: Schema specified is not valid. Errors: EntityDataModel.MyProject.ssdl(2,2) : error 0152: The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' for the 'System.Data.SqlClient' ADO.NET provider could not be loaded. Make sure the provider assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.

I've setup both projects to call the same service, which is in a separate project, in an attempt to isolate the source of the problem to the second project's Unity logic. I should also note I'm using Entity Framework 6 as the ORM.

My question is what Unity code do I need to get the second project to work, or is there some app.config entry I can add to reference the EF assemblies?

Update: After some additional work I noticed that if I reference the DbContext assemblies:

  • EntityFramework
  • EntityFramework.SqlServer

in the second projects the problem disappears. I want to avoid referencing these assemblies because my client projects shouldn't have any knowledge of the ORM.

I've also tried updating the connection string so I'm manually specifying the ORM project's assembly (where my EDMX file is) as mentioned in this StackOverflow question but that hasn't made any difference.

metadata=res://nameOfDll/Model.csdl|res://nameOfDll/Model.ssdl|res://nameOfDll/Model.msl

Community
  • 1
  • 1
Bern
  • 7,808
  • 5
  • 37
  • 47
  • are you sure you are providing all the assemblies needed? what about the runtime used? Is the second app built for Any CPU? – onof Jun 05 '13 at 12:17
  • definitely. both projects share the same repository (and DbContext), and connection string. the only difference I can seem to identify is the Unity.MVC3 doesn't some dependency resolution that I need to resolve manually for the second project. That's the question I'm trying to answer. – Bern Jun 05 '13 at 14:09
  • Your composition root (it is place where you init container) should know about all your dependencies. – Kirill Bestemyanov Jun 11 '13 at 14:53
  • That's right and I have that in place, for some reason unless I'm using Unity.MVC4 over Unity I have to include the EF assemblies in the client project - which seems odd. I have a feeling I need to manually resolve them - which is the question I'm looking to answer. – Bern Jun 12 '13 at 05:51

1 Answers1

2

You're doing it in the right way.

With DI you can remove dependencies from your application. So that you can get a "Repository agnostic" application. And you have effectively done it. At least on the projects that 'declare' the dependencies.

However, when the application has to run, you need to specify the concrete objects which will be used for the "declared" abstract dependencies (interface, abstract class) is required.

You do this by registering the types which object will be used for each abstract dependency. In you sample, when a IUnitOfWork or a DbContext, an instance of MyDbContext is provided.

So the projects that 'declare' the dependencies are completely independent of a particular implementation.

However, when you register the dependent types, you're loosing that independence.

Let's see it with an example:

If I say "I'm thirsty, I need to drink but I don't mind what I drink", I'm dependent on any drink, not on a particular one. But If I say "When I'm thirsty I want to drink coke" I'm dependent on coke.

The first part is the abstract definition of the dependency: "any drink" (like the abstract IUnitOfWork or DbContext). And the second part is the concrete dependency: "coke" (like MyDbContext).

So, I'm independent from coke as long as I don't specify that's what I want to drink. But once I say it, I'm dependent.

Perhaps what you're looking for is a way to change the repository at runtime. You can do it: don't register the dependencies in your code, because you need to make a reference to the project with the chosen concrete types. Do it in an external configuration (i.e. a file), so that you can compile your project without reference to the dependencies, and provide the required assemblies at runtime.

NOTE: When I say "declare" I mean using any of the patterns for injecting dependencies, like constructor injection (most advisabke) or any other injection pattern (property dependencies).

Bern
  • 7,808
  • 5
  • 37
  • 47
JotaBe
  • 38,030
  • 8
  • 98
  • 117
  • Thanks for your time but the the question isn't about DI or IoC (as I understand all that), it's really to do with getting those two EF assemblies to be recognised by my composition root. Unity.MVC4 addresses it automatically somehow (project 1) but with just Unity (project 2) I have to include the EF assemblies in the root project even though I never reference them there. They're referenced in the composition root project. If this helps clarify the issue I'd still be interested in some help. – Bern Jun 12 '13 at 05:49
  • 1
    Ok, now I understand it. You should have a look at the assemblies in the bin folder. I bet that in the deployed web app the EF asssemblies are included, and, in the second project they are missing. Can you check it? – JotaBe Jun 12 '13 at 08:44
  • How odd. There is no project reference but the EntityFramework.SqlServer.dll was sitting in the \bin folder - even after a Clean Solution it didn't get removed. If I remove it manually and run the project I get the same exception. Nice one @JotaBe. Any thoughts on how to resolve this? – Bern Jun 12 '13 at 09:14
  • By "resolve" I mean get my composition root using the EF assembly without having to include it in my client projects? FYI: It's included in the composition root project. – Bern Jun 12 '13 at 09:21
  • Which projects are you using, which references are there between them and what is the composition root? Did you include the Nuget package for EF6 in your composition root? It does include the missing dll. – JotaBe Jun 12 '13 at 09:32
  • I have 4 projects; 1 web application (the one with the EF assembly that wasn't referenced but lived in the bin folder, 1 windows application, 1 service/repository application, and 1 separate composition root folder which handles DI and is shared by the web and windows applications. I've centralised the main DI plumbing into the DI project for DRY. The service/repository application uses EF as the ORM so the web and windows application don't need to worry about what ORM they're using. So the necessary EF wiring logic in the DI project is my concern. – Bern Jun 13 '13 at 07:35
  • Does you composition root project include the Nuget EF 6 package? Are both EF6 assemblies in the references of this project? Although the package includes both assemblies, if there has been a problem in the package installation, they can be missing from the references. If this references are missing add them: your composition root needs them. After this they should be included when building/deploying your apps, no matter if they are Winforms or Web apps. – JotaBe Jun 13 '13 at 09:48
  • Yes the EF6 reference is in the composition root project. I'm just not sure how to overcome the "System.Data.Entity.Core.MetadataException" exception without making a reference to the EF assemblies in the web/windows application. Any thoughts? Am I missing some Unity resolve logic in the composition root project? – Bern Jun 13 '13 at 10:14
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/31718/discussion-between-bern-and-jotabe) – Bern Jun 13 '13 at 13:00