簡體   English   中英

無法加載指定的元數據資源 Release vs Debug 構建

[英]Unable to load the specified metadata resource Release vs Debug build

幾個小時以來,我一直在為 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 ,則不再拋出異常。

我什至查看了實體框架源代碼。 您可以從 Stacktrace 中看到,這個異常在第170行拋出,因為loaders.Count == 0 我不明白為什么在Release版本中不能從程序集中加載資源,而它在Debug版本中工作。

編輯我剛剛安裝了 Reflector 的試用版來檢查組件。 因此,當查看使用 Debug 配置構建的.dll文件時,我可以清楚地看到嵌入的 3 個資源文件。 但是,在使用 Release 配置構建的程序集中,奇怪的是缺少資源文件!

我找到了解決此問題的方法。

我的目標是一個帶有使用 EDMX 的遺留項目的 .net core 3.1 linux 容器。 首先在代碼中遷移整個 EDMX 將花費大量時間,因此我必須找到一個解決方案使其在 Azure 中工作。

問題是像dotnet publish這樣的 dotnet cli 命令沒有嵌入 csdl、msl 或 ssdl 文件,請參閱問題 #8932 所以不要將它嵌入到輸出程序集中。 這在此線程中進行了部分解釋。

  1. 首先將EDMX的“Conceptual Entity Model”中的“Metadata artifact processing”屬性從“Embeded in Output Assembly”改為“Copy to output directory”,這張圖告訴你如何

請注意,您需要打開 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. 最后將您的連接字符串更改為非嵌入的元數據( 請參閱此處的文檔)。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM