【问题标题】:Unable to load the specified metadata resource Release vs Debug build无法加载指定的元数据资源 Release vs Debug build
【发布时间】:2017-08-14 12:36:55
【问题描述】:

我已经为 Entity Framework 中的一个特殊问题摸索了好几个小时。

以下问题重复,因为他们的回答对我没有帮助:

我有一个 aspnet core mvc 应用程序 (v1.1),它引用了一个 .NET Framework 4.7 项目 (Data Access Layer),并将 Entity Framework 6.1.3 作为 NuGet 包安装。

我正在使用设计器,所以我有一个 .edmx 文件。
我在运行时遇到以下异常:

System.Data.Entity.Core.MetadataException: Unable to load the specified metadata resource.
   at System.Data.Entity.Core.Metadata.Edm.MetadataArtifactLoaderCompositeResource.LoadResources(String assemblyName, String resourceName, ICollection`1 uriRegistry, MetadataArtifactAssemblyResolver resolver)
   at System.Data.Entity.Core.Metadata.Edm.MetadataArtifactLoaderCompositeResource.CreateResourceLoader(String path, ExtensionCheck extensionCheck, String validExtension, ICollection`1 uriRegistry, MetadataArtifactAssemblyResolver resolver)
   at System.Data.Entity.Core.Metadata.Edm.MetadataArtifactLoader.Create(String path, ExtensionCheck extensionCheck, String validExtension, ICollection`1 uriRegistry, MetadataArtifactAssemblyResolver resolver)
   at System.Data.Entity.Core.Metadata.Edm.MetadataCache.SplitPaths(String paths)
   at System.Data.Entity.Core.Common.Utils.Memoizer`2.<>c__DisplayClass2.<Evaluate>b__0()
   at System.Data.Entity.Core.Common.Utils.Memoizer`2.Result.GetValue()
   at System.Data.Entity.Core.Common.Utils.Memoizer`2.Evaluate(TArg arg)
   at System.Data.Entity.Core.Metadata.Edm.MetadataCache.GetArtifactLoader(DbConnectionOptions effectiveConnectionOptions)
   at System.Data.Entity.Core.Metadata.Edm.MetadataCache.GetMetadataWorkspace(DbConnectionOptions effectiveConnectionOptions)
   at System.Data.Entity.Core.EntityClient.EntityConnection.GetMetadataWorkspace()
   at System.Data.Entity.Core.Objects.ObjectContext.RetrieveMetadataWorkspaceFromConnection()
   at System.Data.Entity.Core.Objects.ObjectContext..ctor(EntityConnection connection, Boolean isConnectionConstructor, ObjectQueryExecutionPlanFactory objectQueryExecutionPlanFactory, Translator translator, ColumnMapFactory columnMapFactory)
   at System.Data.Entity.Internal.InternalConnection.CreateObjectContextFromConnectionModel()
   at System.Data.Entity.Internal.LazyInternalConnection.CreateObjectContextFromConnectionModel()
   at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
   at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
   at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
   at System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator()
   at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)

我有以下连接字符串:

metadata=res://*/MyContext.csdl|res://*/MyContext.ssdl|res://*/MyContext.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=MyDatabase;integrated security=True;multipleactiveresultsets=True;App=EntityFramework"

问题是,在Debug 构建中运行时,应用程序运行时没有任何问题。但是,在 Release 构建中运行时,会引发异常。但是,如果我在带有 .edmx 文件的项目上禁用 optimize code,则不再抛出异常。

我什至查看了Entity Framework source code. 你可以从 Stacktrace 中看到,这个异常在170 行被抛出,因为loaders.Count == 0。我不明白为什么不能在 Release 构建中从程序集中加载资源,而它在 Debug 构建中工作。

编辑 我刚刚安装了 Reflector 的试用版来检查组件。因此,当查看使用 Debug 配置构建的 .dll 文件时,我可以清楚地看到嵌入的 3 个资源文件。但是,在使用 Release 配置构建的程序集中,奇怪的是缺少资源文件!

【问题讨论】:

  • 我遇到了一个非常相似的问题,我的设置和你的很相似——完整的框架实体框架项目,由.net core mvc app引用。如果我在 VS 中运行我的项目,或者将其部署到 Azure,一切都很好。如果我从命令行使用“dotnet run”,我偶尔会收到此错误。到目前为止,在 VS 中进行清理和重建已经摆脱了它。但是现在在我的两台开发机器中的一台上,每次使用“dotnet run”都会发生这种情况,但在 VS 中根本没有!将继续挖掘,但请更新这是你发现任何进一步的东西。
  • 作为后续。我已经确认您所观察到的 - 当我使用 dotnet run 构建项目时,资源没有包含在实体程序集中。也许这是相同的根本问题。无论如何感谢您的帖子 - 我通过运行 VS 生成的 .exe 而不是使用 dotnet run (坚持重建实体程序集)来解决它。
  • 这似乎是 dotnet CLI 中的一个错误:请参阅 this issue。很遗憾微软没有对此做出回应。
  • 我也有这个问题。当我解决它时,我会尽量记住在这里回答。

标签: c# .net entity-framework


【解决方案1】:

我找到了解决这个问题的方法。

我的目标是一个 .net core 3.1 linux 容器,其中包含一个使用 EDMX 的遗留项目。 首先在代码中迁移整个 EDMX 将花费大量时间,因此我必须找到一种解决方案以使其在 Azure 中工作。

问题是像dotnet publish 这样的dotnet cli 命令不嵌入csdl、msl 或ssdl 文件,请参阅issues #8932。 所以不要将它嵌入到输出程序集中。这在thread 中有部分解释。

  1. 首先将 EDMX 的“概念实体模型”中的“元数据工件处理”属性从“嵌入输出程序集”更改为“复制到输出目录”this picture show you how

请注意,您需要打开 EDMX 文件(双击),因为单击会显示文件的属性。

  1. 复制 csdl、msl 和 ssdl 文件以进行发布。我通过 csproj 文件中的 PostBuild 事件来做到这一点。像这样:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Condition="'$(OS)' == 'Unix'" Command="echo *** cp -a $(ProjectDir)$(OutDir)* $(TargetDir)" />
    <Exec Condition="'$(OS)' == 'Unix'" Command="cp -a $(ProjectDir)$(OutDir)* $(TargetDir)" />

    <Exec Condition="'$(OS)' != 'Unix'" Command="echo *** copy /Y $(ProjectDir)$(OutDir)* $(TargetDir)" />
    <Exec Condition="'$(OS)' != 'Unix'" Command="copy /Y $(ProjectDir)$(OutDir)* $(TargetDir)" />
</Target>

请注意,您必须调整复制命令路径以匹配您的解决方案(例如,如果您的 EDMX 项目位于子项目中)。

  1. 最后将您的连接字符串更改为非嵌入式元数据 (see doc here)。

来自

connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string=[...]"

connectionString="metadata=/app;provider=System.Data.SqlClient;provider connection string=[...]"

由于发布/调试/发布时文件夹更改,我在我的应用程序中创建了这个小函数来更改连接字符串:

private string EntityConnectionString(string connectionString)
{
    EntityConnectionStringBuilder csb = new EntityConnectionStringBuilder
    {
        ProviderConnectionString = connectionString,
        Metadata = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
    };
    csb.Provider = "System.Data.SqlClient";
    return csb.ConnectionString;
}

只需将经典非EDMX格式的连接字符串提供给函数的connectionString参数即可。即:

data source=[...];initial catalog=EntityframeworkTest;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework

【讨论】:

    猜你喜欢
    • 2013-04-12
    • 2023-03-10
    • 2016-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-01
    • 2014-06-13
    相关资源
    最近更新 更多