无法加载指定的元数据资源 Release vs Debug build

4
我一直在为Entity Framework中的一个奇怪问题苦恼了几个小时。
以下问题不是重复的,因为它们的答案对我没有帮助:
- MetadataException: 无法加载指定的元数据资源 - Entity Framework - 无法加载指定的元数据资源 - 无法加载指定的元数据资源
我有一个aspnet core mvc应用程序(v1.1),引用了一个.NET Framework 4.7项目(数据访问层),并安装了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 源代码。 从堆栈跟踪中可以看出,这个异常在第 170 行被抛出,因为 loaders.Count == 0。我不明白为什么在 Release 构建中无法从程序集中加载资源,而在 Debug 构建中却可以正常工作。 编辑 我刚刚安装了 Reflector 的试用版来检查程序集。所以当查看使用 Debug 配置构建的 .dll 文件时,我可以清楚地看到嵌入了 3 个资源文件。然而,在使用 Release 配置构建的程序集中,奇怪的是缺少了这些资源文件!

我遇到了一个非常类似的问题,我的设置与你的相似 - 完整的框架实体框架项目,被 .net core mvc 应用程序引用。如果我在 VS 中运行我的项目,或者将其部署到 Azure,一切都很好。如果我从命令行使用 "dotnet run",偶尔会出现这个错误。在 VS 中进行清理和重建到目前为止已经解决了这个问题。但是现在,在我的两台开发机器中的其中一台上,每次使用 "dotnet run" 都会出现这个问题,但在 VS 中完全没有!我会继续挖掘,但如果您发现任何进一步的信息,请更新此内容。 - fubaar
作为跟进,我已经确认了你所观察到的情况——当我使用dotnet run构建项目时,资源未被包含在实体程序集中。也许这是同样的潜在问题。无论如何,感谢你的帖子——我已经通过运行VS生成的.exe文件来解决它,而不是使用dotnet run(它坚持重新构建实体程序集)。 - fubaar
1
这似乎是dotnet CLI中的一个错误:请参见此问题。很遗憾微软没有对此做出回应。 - QuantumHive
我也遇到这个问题。我会尝试记得在解决它后回复这里。 - catbadger
1个回答

2

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

我正在针对一个使用EDMX的遗留项目,以 .net core 3.1 linux 容器为目标。 将整个EDMX迁移到代码优先需要花费很多时间,因此我不得不找到一个解决方案,使其在Azure中正常工作。

问题是像 dotnet publish 这样的 dotnet cli 命令不会嵌入 csdl、msl 或 ssdl 文件,请参见 issues #8932。 因此不要将其嵌入输出程序集。这在这个 thread 中部分解释了。

  1. 首先,将EDMX的“概念实体模型”的“元数据工件处理”属性从“嵌入到输出程序集”更改为“复制到输出目录” 这张图片展示了如何操作

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

复制 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. 最后,将连接字符串更改为非嵌入式元数据(在此处查看文档)。

来自

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

感谢,对我有效。对于那些 EMX 编辑器无法工作的人,只需对 XML 文件进行以下更改:<Connection> <DesignerInfoPropertySet> <DesignerProperty Name="MetadataArtifactProcessing" Value="CopyToOutputDirectory" /> </DesignerInfoPropertySet> </Connection> - user1215839

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接