Entity Framework 6: Unable to load the specified metadata resource

c# configuration entity-framework entity-framework-6 windows-services

Question

First, this is related to another question here on SO:

I've read and debugged my issue with the following SO article & blog:

MetadataException: Unable to load the specified metadata resource

and

http://blogs.teamb.com/craigstuntz/2010/08/13/38628/

BUT...I'm still having questions beyond just this 'fix'

I have a WebAPI (2.1), the connection string in my WebAPI is as so:

    <connectionStrings>
<add name="ProjectEntities" connectionString="
     metadata=res://*/ProjectModel.csdl|
     res://*/ProjectModel.ssdl|
     res://*/ProjectModel.msl;          
     provider=System.Data.SqlClient;          
     provider connection string=&quot;          
     data source=192.168.0.1;          
     initial catalog=Project;          
     persist security info=True;          
     user id=***;          
     password=***;          
     multipleactiveresultsets=True;          
     App=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" />

When I call ToList() on a DbSet in my WebAPI (pseudo code):

DbContext _DbContext = new ProjectEntities();
DbSet<TEntity> _dbSet = _DbContext.Set<TEntity>();
_dbSet.ToList();

It works great!

When I call the same from within a WINDOWS SERVICE, I get the following error: Error

The app.config entry for the connection string is exactly the same as the web.config:

<connectionStrings>
<add name="ProjectEntities" connectionString="
     metadata=res://*/ProjectModel.csdl|
     res://*/ProjectModel.ssdl|
     res://*/ProjectModel.msl;          
     provider=System.Data.SqlClient;          
     provider connection string=&quot;          
     data source=192.168.0.1;          
     initial catalog=Project;          
     persist security info=True;          
     user id=***;          
     password=***;          
     multipleactiveresultsets=True;          
     App=EntityFramework&quot;" 
     providerName="System.Data.EntityClient" />

Now, the blog shows to reference the dll manually as so:

<connectionStrings>
    <add name="ProjectEntities" connectionString="
         metadata=res://Project.Data.dll/ProjectModel.csdl|
         res://Project.Data.dll/ProjectModel.ssdl|
         res://Project.Data.dll/ProjectModel.msl;          
         provider=System.Data.SqlClient;          
         provider connection string=&quot;          
         data source=192.168.0.1;          
         initial catalog=Project;          
         persist security info=True;          
         user id=***;          
         password=***;          
         multipleactiveresultsets=True;          
         App=EntityFramework&quot;" 
         providerName="System.Data.EntityClient" />
  </connectionStrings>

This does NOT work/fix the issue

The only way I've been able to fix it, is to use the fully qualified name:

<connectionStrings>
    <add name="ProjectEntities" connectionString="
         metadata=res://Project.Data, Version=1.6.0.0, Culture=neutral, PublicKeyToken=null/ProjectModel.csdl|
         res://Project.Data, Version=1.6.0.0, Culture=neutral, PublicKeyToken=null/ProjectModel.ssdl|
         res://Project.Data, Version=1.6.0.0, Culture=neutral, PublicKeyToken=null/ProjectModel.msl;          
         provider=System.Data.SqlClient;          
         provider connection string=&quot;          
         data source=192.168.250.125\sqlexpress;          
         initial catalog=Project;          
         persist security info=True;          
         user id=***;          
         password=***;          
         multipleactiveresultsets=True;          
         App=EntityFramework&quot;" 
         providerName="System.Data.EntityClient" />
  </connectionStrings>

Why does this work like this? Why would this work in a web project, but not a windows service project?? I recently changed from EF5 to EF6, and this error has popped up - all this code worked previous to upgrading EF. Does anyone have any insight as to why and how/if I can just use * for the dll name in my connection string?

I thought it was an issue of where the service .exe was running and a file wasn't copied locally, but nope, the Project.Data.dll is there and it's the right version.

I used FusionLog to try and find the error, and no luck there. I'm pretty confused.

1
9
5/23/2017 12:01:30 PM

Accepted Answer

Why this happens?

The issue you are having is just a result of extra security measures to prevent binary planting or DLL hi-jacking attack (read more) when running your application as as windows service.

Why should I care?

As you probably know, there is a specific, well documented order in what every referenced DLL file is looked up. Usually it starts to search DLL in current application directory and then goes away to more "public" locations like PATH folders, GAC, etc.

Main idea of binary planting is to plant malicious DLL file in a folder which is checked before folder of the legit DLL. Loading such malicious DLL would allow attacker to gain control over the system.

Usually windows services run under elevated account (LocalSystem, LocalService, NetworkService, etc) therefore windows services are good target for binary planting attacks.

What can I do?

Microsoft have taken extra precaution steps to reduce security risks and there is a good reason for that. But you can try to work around you issues.

1) Current directory is not what you expect

Windows service starts in system folder (usually something like C:\Windows\System32)

Good news are that it is very easy to fix. You just have to change current directory on services startup.

System.IO.Directory.SetCurrentDirectory(System.AppDomain.CurrentDomain.BaseDirectory);

See blog post from Phil Haack;

2) Read documentation thoroughtly

According to EF documentation, wildcard character has special meaning and it limits places where runtime will look for DLL files:

If you specify a wildcard (*) for assemblyFullName, the Entity Framework runtime will search for resources in the following locations, in this order:

1) The calling assembly.

2) The referenced assemblies.

3) The assemblies in the bin directory of an application.

As your working folder is set to system folder and you references probably are not there, EF might end up looking in wrong places and your assemblies containing resources might not be loaded.

3) Stay safe with fully qualified assembly names

Although I am not completely sure about this and haven't tested, but Microsoft just might have disallowed Windows services to load DLL without providing fully qualified assembly name to reduce risk of injecting malicious DLL files;

Good read on securing your Windows services here (specially chapter 5).

4) Debug it!

EF6 happens to be open source project. This means that you can get full source of it and debug it. You can find project on CodePlex here.

5
4/13/2015 10:37:42 PM

Popular Answer

Copy the dll containing ProjectEntities to different path and then reference the same in your service project.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow