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

时间:2015-03-12 18:56:05

标签: c# entity-framework configuration windows-services entity-framework-6

首先,这与SO上的另一个问题有关:

我已阅读并调试了以下SO文章&博客:

MetadataException: Unable to load the specified metadata resource

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

但是......除了这个'修复'之外,我还有其他问题

我有一个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" />

当我在我的WebAPI(伪代码)中的ToList()上调用DbSet时:

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

效果很好!

当我在 WINDOWS SERVICE 中调用时,我收到以下错误: Error

连接字符串的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" />

现在,博客显示手动引用 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>

这不起作用/解决问题

我能够解决它的唯一方法是使用完全限定的名称:

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

为什么这样工作?为什么这会在Web项目中工作,而不是Windows服务项目?我最近从EF5更改为EF6,并且出现了此错误 - 所有这些代码在升级EF之前都有效。有没有人知道为什么以及如何/如果我可以在我的连接字符串中使用*作为dll名称?

我认为服务 .exe 正在运行且文件未在本地复制的问题,但是没有, Project.Data.dll 是那里和它是正确的版本。

我使用FusionLog尝试查找错误,但没有运气。我很困惑。

4 个答案:

答案 0 :(得分:5)

为什么会这样?

您遇到的问题仅仅是在运行您的应用程序时提供额外的安全措施以防止二进制种植或DLL高压攻击(read more)。

我为什么要关心?

您可能知道,每个引用的DLL文件都有一个特定的well documented顺序。通常它会开始搜索当前应用程序目录中的DLL,然后转到更多的公共&#34; PATH文件夹,GAC等位置

二进制种植的主要思想是在一个文件夹中植入恶意DLL文件,该文件夹在合法DLL的文件夹之前被检查。加载此类恶意DLL将允许攻击者获得对系统的控制权。

通常,Windows服务在提升的帐户( LocalSystem,LocalService,NetworkService等)下运行,因此Windows服务是二进制种植攻击的良好目标。

我该怎么办?

Microsoft采取了额外的预防措施来降低安全风险,这是有充分理由的。但你可以尝试解决你的问题。

1)当前目录不是您所期望的

Windows服务在系统文件夹中启动(通常类似于C:\Windows\System32

好消息是它很容易修复。您只需要在服务启动时更改当前目录。

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

见Phil Haack的blog post;

2)彻底阅读文档

根据EF documentation,通配符具有特殊含义,它限制了运行时查找DLL文件的位置:

  

如果为assemblyFullName指定通配符(*),则为Entity   Framework运行时将搜索以下资源   地点,按此顺序:

     

1)调用程序集。

     

2)引用的程序集。

     

3)应用程序bin目录中的程序集。

由于您的工作文件夹设置为系统文件夹,并且您的引用可能不存在,EF可能最终会查找错误的位置,并且可能无法加载包含资源的程序集。

3)使用完全限定的程序集名称保持安全

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

关于保护Windows服务的良好读数here(特别是第5章)。

4)调试它!

EF6恰好是开源项目。这意味着您可以获得它的完整源代码并进行调试。您可以在CodePlex上找到项目here

答案 1 :(得分:2)

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

答案 2 :(得分:1)

我担心自己无法重现您收到的错误,或者回答您需要更改metadata的原因。

也就是说,我确实了解到,对于EF连接字符串,Windows服务需要与WebApi不同的provider connection string

以下是重现错误的步骤。唯一的区别是我使用localdb而不是SQLExpress。

我的步骤重现的结果代码在GitHub上在线:https://github.com/bigfont/EntityFrameworkWindowsServiceWebApi

以下是这些步骤:

创建Web API项目

  1. 创建ASP.NET Web API 2空项目(MyWebApi)
  2. 使用NuGet,Install-Package EntityFramework -ProjectName MyWebApi
  3. 添加一个名为MyProjectModel的新ADO.NET实体数据模型。
  4. 添加名为Entity1的实体。
  5. 从模型生成数据库,将其命名为MyProject并使用localdb。
  6. 在(localdb)\ v11.0
  7. 上运行数据库创建脚本
  8. 使用查询数据库的ValuesController方法添加名为Get的新WebApi控制器。
  9. 通过在Visual Studio中运行并转到localhost:123456 / api / get
  10. 进行测试

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

    创建Windows服务项目

    1. 创建Windows服务(MyWindowsService)
    2. 使用NuGet,Install-Package EntityFramework -ProjectName MyWindowsService
    3. 添加一个名为MyProjectModel的新ADO.NET实体数据模型。
    4. 添加名为Entity1的实体。
    5. 使用localdb从模型生成数据库,并将其命名为MyService。
    6. 在(localdb)\ v11.0
    7. 上运行数据库创建脚本
    8. 向OnStart方法添加一些查询数据库的代码。
    9. NT AUTHORITY\SYSTEM添加为localdb登录,并添加为MyService数据库用户。
    10. 通过安装,启动和写入文件进行测试:
    11. PowerShell安装,启动和卸载

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

      localdb连接字符串

      在Windows服务的连接字符串中,我无法使用(localdb)\v11.0。相反,我需要使用命名管道。我用这个命令行找到了命名管道:

      > 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
      

      使用实例管道名称生成的连接字符串如下所示。

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

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

      另请参阅:http://www.connectionstrings.com/sql-server-2012/

      需要将不同的连接字符串与我们使用WebApi项目执行的Windows服务一起使用,这与您找到的问题类似。从Sql Server Management Studio,Visual Studio和WebApi,我们可以通过调用数据源(localdb)\ v.11进行连接,而从Web Service我们需要通过它的实例命名管道来调用它。

      这里有一个怀疑:可能是计算机上有多个localdb实例,我们需要绝对指定我们要使用的实例。不幸的是,这并不能帮助您回答为什么需要更改metadata

      这是一个与您面临的问题类似的问题,因为您需要更改实体框架metadata,而我需要更改provider connection string。巧合?

答案 3 :(得分:-1)

请按照以下步骤操作:

1.单击edmx文件,然后单击打开相关实体。

2.选择xml编辑器,然后单击“打开”。

3.从.edmx xml文件的顶部到底部滚动并查找任何错误标记。

4.如果你介意错误,那么解决它。 5.重建解决方案,如果没有发现错误,那么祝贺:)