azure - 如何防止 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它说:
同一个程序集被多次加载到不同的上下文中。
- 这可能会导致令人困惑的错误消息,例如“无法将 'Sample.Plugin' 类型的对象转换为 'Sample.Plugin' 类型”。
- 跨越隔离边界的编组并非易事。一个典型的解决方案是使用在仅加载到默认加载上下文的程序集中定义的接口。
有人可以提供一个例子来说明他们的意思:“一个典型的解决方案是使用在程序集中定义的接口,该接口只加载到默认加载上下文中。 ”?
这是我所属的类的过于简化的结构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();
有任何想法吗??
解决方案
推荐阅读
- wpf - 在 wpf 中显示预订为水平条的时间段,而不使用商业调度程序控件
- c# - C# WPF Listview Groupheader 始终位于顶部
- swift - 使用 Promises 的代码根本不执行
- html - HTML 滑块在移动设备和选项卡上做出响应
- reactjs - 当 axios 被调用时显示“Access-Control-Allow-Origin”错误
- gcc - mediapipe 库无法在 High Sierra 上构建
- python - FFMPEG 输出视频播放开始于 10 秒
- multilabel-classification - 服装分类的预训练模型
- python - 如何在yolov3模型上进行多图批量推理?
- java - 如何让程序一直询问直到输入有效数字?