简体   繁体   English

实体框架6:无法加载指定的元数据资源

[英]Entity Framework 6: Unable to load the specified metadata resource

First, this is related to another question here on SO: 首先,这与SO上的另一个问题有关:

I've read and debugged my issue with the following SO article & blog: 我通过以下SO文章和博客阅读并调试了我的问题:

MetadataException: Unable to load the specified metadata resource MetadataException:无法加载指定的元数据资源

and

http://blogs.teamb.com/craigstuntz/2010/08/13/38628/ 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: 我有一个WebAPI(2.1),我的WebAPI中的连接字符串是这样的:

    <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): 当我打电话ToList()DbSet在我的WebAPI(伪代码):

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: 当我从WINDOWS SERVICE中调用相同内容时,出现以下错误: 错误

The app.config entry for the connection string is exactly the same as the web.config : 连接字符串的app.config条目与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: 现在,博客显示手动引用dll如下:

<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?? 为什么这会在Web项目中工作,而不是Windows服务项目? I recently changed from EF5 to EF6, and this error has popped up - all this code worked previous to upgrading EF. 我最近从EF5更改为EF6,并且出现了此错误 - 所有这些代码在升级EF之前都有效。 Does anyone have any insight as to why and how/if I can just use * for the dll name in my connection string? 有没有人知道为什么以及如何/如果我可以在我的连接字符串中使用*作为dll名称?

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. 我认为这是服务.exe运行的地方和文件没有在本地复制的问题,但是没有, Project.Data.dll就在那里,它是正确的版本。

I used FusionLog to try and find the error, and no luck there. 我使用FusionLog试图找到错误,没有运气。 I'm pretty confused. 我很困惑。

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. 您遇到的问题只是在运行您的应用程序时提供额外的安全措施以防止二进制种植或DLL高压攻击( 阅读更多 )。

Why should I care? 我为什么要在乎?

As you probably know, there is a specific, well documented order in what every referenced DLL file is looked up. 您可能知道,在每个引用的DLL文件中都有一个特定的,记录良好的顺序。 Usually it starts to search DLL in current application directory and then goes away to more "public" locations like PATH folders, GAC, etc. 通常它会开始在当前应用程序目录中搜索DLL,然后转到更多“公共”位置,如PATH文件夹,GAC等。

Main idea of binary planting is to plant malicious DLL file in a folder which is checked before folder of the legit DLL. 二进制种植的主要思想是在一个文件夹中植入恶意DLL文件,该文件夹在合法DLL的文件夹之前被检查。 Loading such malicious DLL would allow attacker to gain control over the system. 加载此类恶意DLL将允许攻击者获得对系统的控制权。

Usually windows services run under elevated account ( LocalSystem, LocalService, NetworkService, etc ) therefore windows services are good target for binary planting attacks. 通常,Windows服务在提升的帐户( LocalSystem,LocalService,NetworkService等 )下运行因此Windows服务是二进制种植攻击的良好目标。

What can I do? 我能做什么?

Microsoft have taken extra precaution steps to reduce security risks and there is a good reason for that. Microsoft采取了额外的预防措施来降低安全风险,这是有充分理由的。 But you can try to work around you issues. 但你可以尝试解决你的问题。

1) Current directory is not what you expect 1)当前目录不是您所期望的

Windows service starts in system folder (usually something like C:\\Windows\\System32 ) Windows服务在系统文件夹中启动(通常类似于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; 参见Phil Haack的博客文章 ;

2) Read documentation thoroughtly 2)彻底阅读文档

According to EF documentation , wildcard character has special meaning and it limits places where runtime will look for DLL files: 根据EF 文档 ,通配符具有特殊含义,它限制了运行时查找DLL文件的位置:

If you specify a wildcard (*) for assemblyFullName, the Entity Framework runtime will search for resources in the following locations, in this order: 如果为assemblyFullName指定通配符(*),则Entity Framework运行时将按以下顺序搜索以下位置中的资源:

1) The calling assembly. 1)调用程序集。

2) The referenced assemblies. 2)引用的程序集。

3) The assemblies in the bin directory of an application. 3)应用程序的bin目录中的程序集。

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. 由于您的工作文件夹设置为系统文件夹,并且您可能没有引用,EF可能最终会查找错误的位置,并且可能无法加载包含资源的程序集。

3) Stay safe with fully qualified assembly names 3)使用完全合格的装配名称保持安全

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; 虽然我对此并不完全确定并且没有经过测试,但微软可能不允许Windows服务加载DLL而不提供完全限定的程序集名称以降低注入恶意DLL文件的风险;

Good read on securing your Windows services here (specially chapter 5). 很好地阅读了有关保护Windows服务的信息 (特别是第5章)。

4) Debug it! 4)调试它!

EF6 happens to be open source project. EF6恰好是开源项目。 This means that you can get full source of it and debug it. 这意味着您可以获得它的完整源代码并进行调试。 You can find project on CodePlex here . 您可以在此处找到CodePlex上的项目。

将包含ProjectEntities的dll复制到不同的路径,然后在服务项目中引用它。

I'm afraid I wasn't able to reproduce the error that you received, or answer why you needed to change the metadata . 我担心我无法重现您收到的错误,或者回答您需要更改metadata

That said, I did learn that, for the EF connection string, the Windows Service required a different provider connection string than the WebApi did. 也就是说,我确实了解到,对于EF连接字符串,Windows服务需要一个与WebApi不同的provider connection string

The following are the steps to reproduce your error. 以下是重现错误的步骤。 The only difference is that I'm using localdb not SQLExpress. 唯一的区别是我使用的是localdb而不是SQLExpress。

The resultant code from my steps-to-reproduce is online at GitHub here: https://github.com/bigfont/EntityFrameworkWindowsServiceWebApi . 我的步骤重现的结果代码在GitHub上在线: https//github.com/bigfont/EntityFrameworkWindowsServiceWebApi

Here are those steps: 以下是这些步骤:

Create Web API Project 创建Web API项目

  1. Create ASP.NET Web API 2 Empty Project (MyWebApi) 创建ASP.NET Web API 2空项目(MyWebApi)
  2. With NuGet, Install-Package EntityFramework -ProjectName MyWebApi 使用NuGet, Install-Package EntityFramework -ProjectName MyWebApi
  3. Add a new ADO.NET Entity Data Model called MyProjectModel. 添加一个名为MyProjectModel的新ADO.NET实体数据模型。
  4. Add an Entity called Entity1. 添加一个名为Entity1的实体。
  5. Generate the database from the model, calling it MyProject and using localdb. 从模型生成数据库,将其命名为MyProject并使用localdb。
  6. Run the db creation script on (localdb)\\v11.0 在(localdb)\\ v11.0上运行db creation脚本
  7. Add a new WebApi Controller named ValuesController with a Get method that queries the database. 使用查询数据库的Get方法添加名为ValuesController的新WebApi Controller。
  8. Test by running in Visual Studio and going to localhost:123456/api/get 通过在Visual Studio中运行并转到localhost:123456 / api / get进行测试

See: https://msdn.microsoft.com/en-us/data/jj205424.aspx 请参阅: https//msdn.microsoft.com/en-us/data/jj205424.aspx

Create Windows Service Project 创建Windows服务项目

  1. Create Windows Service (MyWindowsService) 创建Windows服务(MyWindowsService)
  2. Use NuGet, Install-Package EntityFramework -ProjectName MyWindowsService 使用NuGet, Install-Package EntityFramework -ProjectName MyWindowsService
  3. Add a new ADO.NET Entity Data Model called MyProjectModel. 添加一个名为MyProjectModel的新ADO.NET实体数据模型。
  4. Add an Entity called Entity1. 添加一个名为Entity1的实体。
  5. Generate the database from the model, calling it MyService, using localdb. 使用localdb从模型生成数据库,将其命名为MyService。
  6. Run the db creation script on (localdb)\\v11.0 在(localdb)\\ v11.0上运行db creation脚本
  7. Add to the OnStart method some code that queries the database. 向OnStart方法添加一些查询数据库的代码。
  8. Add NT AUTHORITY\\SYSTEM as a localdb Login and as a MyService db User. 添加NT AUTHORITY\\SYSTEM作为localdb登录和作为MyService数据库用户。
  9. Test by installing, starting, and writing to file: 通过安装,启动和写入文件进行测试:

PowerShell Installation, Startup, and Uninstall PowerShell安装,启动和卸载

Release> installutil .\MyWindowsService.exe
Release> Start-Service MyService
Release> installutil .\MyWindowsService.exe /u

localdb connection string in the Windows Service Windows服务中的localdb连接字符串

In the connection string for the Windows Service, I wasn't able to use (localdb)\\v11.0 . 在Windows服务的连接字符串中,我无法使用(localdb)\\v11.0 Instead, I needed to use the named pipe. 相反,我需要使用命名管道。 I found the named pipe with this command line: 我用这个命令行找到了命名管道:

> SqlLocalDB.exe info v11.0

Name:               v11.0
Version:            11.0.2100.60
Shared name:
Owner:              MY_COMPUTER\Shaun.Luttin
Auto-create:        Yes
State:              Running
Last start time:    2015-04-09 5:54:34 PM
Instance pipe name: np:\\.\pipe\LOCALDB#1010101\tsql\query

The resultant connection string, using the Instance pipe name, looked like this. 使用实例管道名称生成的连接字符串如下所示。

  <connectionStrings>
    <add name="MyProjectModelContainer" 
         connectionString="
  metadata=
  res://*/MyProjectModel.csdl|
  res://*/MyProjectModel.ssdl|
  res://*/MyProjectModel.msl;
  provider=System.Data.SqlClient;
  provider connection string=&quot;
    data source=np:\\.\pipe\LOCALDB#4BCE6D95\tsql\query;
    initial catalog=MyService;
    Integrated Security=True;
    MultipleActiveResultSets=True;
    App=EntityFramework&quot;" 
         providerName="System.Data.EntityClient" />
  </connectionStrings>

Whereas the WebApi connection string looked like this: 而WebApi连接字符串看起来像这样:

    <add name="MyProjectModelContainer" 
         connectionString="
  metadata=
  res://*/MyProjectModel.csdl|
  res://*/MyProjectModel.ssdl|
  res://*/MyProjectModel.msl;
  provider=System.Data.SqlClient;
  provider connection string=&quot;
    data source=(localdb)\v11.0;
    initial catalog=MyProject;
    integrated security=True;
    MultipleActiveResultSets=True;
    App=EntityFramework&quot;" 
         providerName="System.Data.EntityClient" />
  </connectionStrings>

See also: http://www.connectionstrings.com/sql-server-2012/ 另见: http//www.connectionstrings.com/sql-server-2012/

Needing to use a different connection string with a Windows Service that we do with a WebApi project is a similar problem to what you found. 需要将不同的连接字符串与我们使用WebApi项目执行的Windows服务一起使用,这与您找到的问题类似。 From Sql Server Management Studio, from Visual Studio, and from the WebApi, we can connect by calling the data source (localdb)\\v.11 whereas from a Web Service we need to call it by it's instance named pipe. 从Sql Server Management Studio,Visual Studio和WebApi,我们可以通过调用数据源(localdb)\\ v.11进行连接,而从Web Service我们需要通过它的名为pipe的实例来调用它。

Here's a suspicion: It might be that there are multiple instance of localdb on the computer, and that we needed to absolutely specify which one we want to use. 这是一个怀疑:可能是计算机上有多个localdb实例,我们需要绝对指定我们要使用的实例。 Unfortunately, this doesn't help answer why you needed to change the metadata . 不幸的是,这无助于解答为什么需要更改metadata

This is a similar though different problem than what you faced, because you needed to change the Entity Framework metadata whereas I needed to change the provider connection string . 这是一个与您面临的问题类似的问题,因为您需要更改实体框架metadata而我需要更改provider connection string Coincidence? 巧合?

Please follow the steps bellow: 请按照以下步骤操作:

1.Write click on edmx file and then click open with of the related entity. 1.单击edmx文件,然后单击打开相关实体。

2.Select xml editor and click open. 2.选择xml编辑器,然后单击“打开”。

3.Scroll from top to bottom of the .edmx xml file and look for any error marks. 3.从.edmx xml文件的顶部到底部滚动并查找任何错误标记。

4.If you mind errors then fix that. 如果你介意错误,那么解决它。 5.Rebuild the solution and if no errors found then congratulations :) 5.重建解决方案,如果没有发现错误,那么祝贺:)

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

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