【问题标题】:How to prevent EF4 from dynamically loading all assemblies如何防止 EF4 动态加载所有程序集
【发布时间】:2011-08-02 13:59:49
【问题描述】:

我们使用带有动态程序集加载的 ClickOnce。我最近在解决方案中的“模型”项目中添加了一个 EF4 模型。

应用程序不得使用 app.config 文件作为其连接字符串,因此我使用 EntityConnection 创建 ObjectContext。

应用程序逻辑运行良好,但是,当您在使用 ClickOnce 部署应用程序时创建 ObjectContext 的实例时,EF4 会尝试动态加载所有关联的程序集以查找元数据。

这会强制 clickonce 下载 clickonce dll 映射中的每个程序集!

这是调用 ObjectContext ctor 时的堆栈跟踪:

   at System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
   at System.Data.Metadata.Edm.MetadataAssemblyHelper.SafeLoadReferencedAssembly(AssemblyName assemblyName)
   at System.Data.Metadata.Edm.MetadataAssemblyHelper.<GetNonSystemReferencedAssemblies>d__0.MoveNext()
   at System.Data.Metadata.Edm.DefaultAssemblyResolver.GetAllDiscoverableAssemblies()
   at System.Data.Metadata.Edm.DefaultAssemblyResolver.GetWildcardAssemblies()
   at System.Data.Metadata.Edm.MetadataArtifactLoaderCompositeResource.LoadResources(String assemblyName, String resourceName, ICollection`1 uriRegistry, MetadataArtifactAssemblyResolver resolver)
   at System.Data.Metadata.Edm.MetadataArtifactLoaderCompositeResource.CreateResourceLoader(String path, ExtensionCheck extensionCheck, String validExtension, ICollection`1 uriRegistry, MetadataArtifactAssemblyResolver resolver)
   at System.Data.Metadata.Edm.MetadataArtifactLoader.Create(String path, ExtensionCheck extensionCheck, String validExtension, ICollection`1 uriRegistry, MetadataArtifactAssemblyResolver resolver)
   at System.Data.Metadata.Edm.MetadataCache.SplitPaths(String paths)
   at System.Data.Common.Utils.Memoizer`2.<>c__DisplayClass2.<Evaluate>b__0()
   at System.Data.Common.Utils.Memoizer`2.Result.GetValue()
   at System.Data.Common.Utils.Memoizer`2.Evaluate(TArg arg)
   at System.Data.EntityClient.EntityConnection.GetMetadataWorkspace(Boolean initializeAllCollections)
   at System.Data.Objects.ObjectContext.RetrieveMetadataWorkspaceFromConnection()
   at System.Data.Objects.ObjectContext..ctor(EntityConnection connection, Boolean isConnectionConstructor)

如何防止 EF4 这样做?

谢谢!


遵循 Craig 的建议后,我现在可以创建 ObjectContext 的实例,而无需尝试加载所有程序集。

但是,它现在会在运行查询时尝试加载所有程序集。请参阅下面的堆栈跟踪:

   at System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
   at System.Data.Metadata.Edm.MetadataAssemblyHelper.SafeLoadReferencedAssembly(AssemblyName assemblyName)
   at System.Data.Metadata.Edm.MetadataAssemblyHelper.<GetNonSystemReferencedAssemblies>d__0.MoveNext()
   at System.Data.Metadata.Edm.ObjectItemCollection.ImplicitLoadViewsFromAllReferencedAssemblies(Assembly assembly)
   at System.Data.Mapping.StorageMappingItemCollection.ViewDictionary.SerializedCollectViewsFromReferencedAssemblies(MetadataWorkspace workspace, Dictionary`2 extentMappingViews)
   at System.Data.Mapping.StorageMappingItemCollection.ViewDictionary.SerializedGetGeneratedViews(EntityContainer container)
   at System.Data.Common.Utils.Memoizer`2.<>c__DisplayClass2.<Evaluate>b__0()
   at System.Data.Common.Utils.Memoizer`2.Result.GetValue()
   at System.Data.Common.Utils.Memoizer`2.Evaluate(TArg arg)
   at System.Data.Mapping.StorageMappingItemCollection.ViewDictionary.GetGeneratedView(EntitySetBase extent, MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection)
   at System.Data.Metadata.Edm.MetadataWorkspace.GetGeneratedView(EntitySetBase extent)
   at System.Data.Query.PlanCompiler.PreProcessor.ExpandView(Node node, ScanTableOp scanTableOp, IsOfOp& typeFilter)
   at System.Data.Query.PlanCompiler.PreProcessor.ProcessScanTable(Node scanTableNode, ScanTableOp scanTableOp, IsOfOp& typeFilter)
   at System.Data.Query.PlanCompiler.PreProcessor.Visit(ScanTableOp op, Node n)
   at System.Data.Query.InternalTrees.ScanTableOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Query.PlanCompiler.SubqueryTrackingVisitor.VisitChildren(Node n)
   at System.Data.Query.PlanCompiler.SubqueryTrackingVisitor.VisitRelOpDefault(RelOp op, Node n)
   at System.Data.Query.PlanCompiler.PreProcessor.Visit(ProjectOp op, Node n)
   at System.Data.Query.InternalTrees.ProjectOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Query.PlanCompiler.SubqueryTrackingVisitor.VisitChildren(Node n)
   at System.Data.Query.InternalTrees.BasicOpVisitorOfNode.VisitDefault(Node n)
   at System.Data.Query.InternalTrees.BasicOpVisitorOfNode.VisitPhysicalOpDefault(PhysicalOp op, Node n)
   at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.Visit(PhysicalProjectOp op, Node n)
   at System.Data.Query.InternalTrees.PhysicalProjectOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Query.PlanCompiler.PreProcessor.Process()
   at System.Data.Query.PlanCompiler.PreProcessor.Process(PlanCompiler planCompilerState, StructuredTypeInfo& typeInfo)
   at System.Data.Query.PlanCompiler.PlanCompiler.Compile(List`1& providerCommands, ColumnMap& resultColumnMap, Int32& columnCount, Set`1& entitySets)
   at System.Data.EntityClient.EntityCommandDefinition..ctor(DbProviderFactory storeProviderFactory, DbCommandTree commandTree)
   at System.Data.EntityClient.EntityProviderServices.CreateCommandDefinition(DbProviderFactory storeProviderFactory, DbCommandTree commandTree)
   at System.Data.EntityClient.EntityProviderServices.CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree)
   at System.Data.Common.DbProviderServices.CreateCommandDefinition(DbCommandTree commandTree)
   at System.Data.Objects.Internal.ObjectQueryExecutionPlan.Prepare(ObjectContext context, DbQueryCommandTree tree, Type elementType, MergeOption mergeOption, Span span, ReadOnlyCollection`1 compiledQueryParameters)
   at System.Data.Objects.EntitySqlQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)

如果有任何进一步的帮助,我将不胜感激! 谢谢。


好吧,我认为如果使用*,它应该首先检查当前程序集。 99% 的时间都是正确的。加载每个程序集然后只检查当前程序集对我来说似乎是一个错误。

使用反射来尝试加载每个 dll 应该是可选的。

我仍然有这个问题。包含公司所有业务逻辑的模型库正在其他地方使用(不是上面提到的原始 ClickOnce 应用程序)。该库引用了水晶报告的 DLL,这会导致 EF4 抛出 ReflectTypeLoadException,因为该机器没有安装水晶。

是的,这是没有 * 通配符和预先生成的视图。

真的没有办法明确告诉 EF4 不要加载程序集(它真的不需要)吗?否则看起来我将不得不完全放弃 EF4。

【问题讨论】:

    标签: c# entity-framework-4 assemblies clickonce


    【解决方案1】:

    您应该使用specify the correct assembly in your EF connection string 而不是使用* 通配符。

    【讨论】:

    • 这是有道理的。但是,当我指定 dll 名称时,会引发 FileNotFoundException。我 100% 确定 dll 名称是正确的,并且 dll 位于应用程序文件夹中。它还能在哪里寻找?
    • 尝试不使用.dll -- 程序集名称。
    • 感谢克雷格的帮助!我现在可以初始化 ObjectContext。但是,当查询运行时,它会再次尝试加载所有程序集。我编辑了上面的原始帖子以包含堆栈跟踪。
    • 不确定。如果您尝试pregenerated views 会怎样?
    • 谢谢!现在一切似乎都正常工作。每次创建新查询或修改现有查询时,我是否必须重新生成视图文件?如果有一个脚本来自动化一切,那就太好了。一遍又一遍地重复所有这些步骤很快就会变得非常乏味。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 2023-03-25
    • 2011-04-16
    • 2016-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多