首页 > 解决方案 > 如何防止 Azure Function v3 多次加载相同的程序集?

问题描述

我有一个 Azure v3 Function 应用程序(.NET Core 3.1 - Consumption plan),它具有多个服务总线触发的功能。每个函数调用不同事件处理类中的方法,传递消息实体作为参数。事件处理类和不同的消息类都属于同一个dll(VS项目),我们称之为MyCompany.Domain.dll。

由于某种原因,在处理大量消息时,我收到此错误,其中 AllOpenSagasCleared 是一种消息类型(事件)。注意加载的 DLL 数量:

****** 在异常中 - 加载的 MyNamespace.Domain DLL 数:9 ******

为 MyNamespace.Validations.ClientTaskProgress 处理 MyNamespace.Events.AllOpenSagasCleared 时出错 ---> System.ArgumentException:“MyNamespace.Guided.Tasks.Events.AllOpenSagasCleared”类型的对象无法转换为“MyNamespace.Guided.Tasks.Events.AllOpenSagasCleared”类型'。在 System.RuntimeType.TryChangeType(对象值,活页夹活页夹,CultureInfo 文化,布尔需求SpecialCast)在 System.RuntimeType.CheckValue(对象值,活页夹活页夹,CultureInfo 文化,BindingFlags invokeAttr)在 System.Reflection.MethodBase.CheckArguments(对象 [] System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfoculture) 在 System.Reflection 的参数、BindingFlags invokeAttr、CultureInfo 文化、签名 sig)。

这是事件处理基类ClientTaskProgress(抽象)中的代码,它通过将消息(事件)对象作为参数传递的反射调用同一类中的方法:

var method = GetType().GetMethod("Handle", new[] { @event.GetType() }); ;
method.Invoke(this, new[] { @event});

异常来自上面的 Invoke 调用。添加一些日志记录后,我发现 MyCompany.Domain.dll 程序集在 Function Context 下被多次加载AppDomain.CurrentDomain.GetAssemblies

阅读本文档:https ://docs.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext?view=netcore-3.1它说:

同一个程序集被多次加载到不同的上下文中。

有人可以提供一个例子来说明他们的意思:“一个典型的解决方案是使用在程序集中定义的接口,该接口只加载到默认加载上下文中。 ”?

这是我所属的类的过于简化的结构MyNamespace.Domain.dll

public class ClientTaskProgress: TypeEventModel, IHandle<AllOpenSagasCleared>, IHandle<ResetTask>
{
    public void Handle(AllOpenSagasCleared message)
    {
        //Trivial code
    }

    public void Handle(ResetTask message)
    {
        //Trivial code
    }
}

public abstract class TypeEventModel
{
     public void PlayEvent(object @event)
     {
          var method = GetType().GetMethod("Handle", new[] { @event.GetType() }); ;
          method.Invoke(this, new[] { @event});        
     }
}

public class AllOpenSagasCleared : IDomainEvent
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public DateTime DateTime { get; set; } = DateTime.UtcNow;
    
}

从上面的代码看来,传递给我的事件处理类中的参数的 @event 对象Handle是从加载的不同MyNamespace.Domain程序集创建的,因此由于类型不匹配而失败,即使它们在技术上是相同的类型定义,只是来自不同的加载程序集。

这就是我打印加载程序集数量的方式:

var domainAssemblyCount= AppDomain.CurrentDomain.GetAssemblies().Where(x => x.FullName.ToUpper().Contains("MYNAMESPACE.DOMAIN")).ToList().Count();

有任何想法吗??

标签: azure.net-coreazure-function-app

解决方案


推荐阅读