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

时间:2017-08-14 12:36:55

标签: c# .net entity-framework

我已经在实体框架中出现了一个特殊问题几个小时。

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

我有一个aspnet core mvc应用(v1.1)引用.NET Framework 4.7项目(Data Access Layer)并将Entity Framework 6.1.3安装为NuGet包。< / p>

我正在使用设计师,所以我有一个.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版本中运行时,会抛出异常。但是,如果我使用optimize code文件禁用项目.edmx,则会再次抛出 异常。

我甚至查看过你在Stacktrace中可以看到的Entity Framework source code.,这个异常会在行170处抛出,因为loaders.Count == 0。我不明白为什么无法在Release版本中从程序集加载资源,而它在Debug版本中工作。

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

1 个答案:

答案 0 :(得分:0)

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

我的目标是使用EDMX与旧项目的.net核心3.1 linux容器。 首先,要在代码中迁移整个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