azure - Service Fabric:System.ArgumentException:找不到使用此 ID -488762776 的接口
问题描述
我正在开发一个简单的 Service Fabric 群集,我想从无状态 ASP.NET Core 2.0 Web API 调用无状态服务。
我做的第一件事是创建一个带有简单接口和 DTO 的 .NET Standard 2.0 类库:
public interface IMicroService : IService
{
Task<MyDto> GetMahDto(int id);
}
public class MyDto
{
public string Name { get; set; }
}
然后我从中创建了一个 NuGet 包,并将该包作为依赖项添加到我的 Web API(MyServiceApi 项目)和无状态服务(MyService)。
服务的监听器定义为
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
var fabricListener = new ServiceInstanceListener((context) =>
{
var fabricRemotingListener = new FabricTransportServiceRemotingListener(
serviceContext: context,
serviceRemotingMessageHandler: null,
remotingListenerSettings: new Microsoft.ServiceFabric.Services.Remoting.FabricTransport.Runtime.FabricTransportRemotingListenerSettings()
{
EndpointResourceName = "myendpoint"
},
serializationProvider: null);
return fabricRemotingListener;
},
"mylistener");
return new ServiceInstanceListener[] { fabricListener };
}
接口实现很简单
public Task<MyDto> GetMahDto(int id)
{
return Task.FromResult(new MyDto() { Name=$"Hallo from TheService in FabricSandbox3 project, id: {id}" });
}
在 MyServiceApi 中,我有一个控制器方法,看起来像
[HttpGet]
public async Task<MyDto> Get()
{
var svc = ServiceProxy.Create<ContractsStandard.IMicroService>(new Uri("fabric:/FabricSandbox4/TheService"), listenerName: "mylistener");
return await svc.GetMahDto(23);
}
当我启动调试器时,我可以进入 MyServiceApi 的控制器方法,但它会抛出以下异常:
System.AggregateException: '发生一个或多个错误。(异常 System.ArgumentException 在服务上未处理,无法序列化以传输到客户端。详细的远程异常信息:System.ArgumentException:在 Microsoft.ServiceFabric.Services.Remoting.V2 上找不到具有此 ID -488762776 的接口。 ServiceRemotingMessageSerializersManager.GetInterfaceDetails(Int32 interfaceId) 在 Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.CreateSerializers(Int32 interfaceId) 在 System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func
2 valueFactory) 在 Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportMessageHandler.CreateRemotingRequestMessage(FabricTransportMessage fabricTransportMessage, Stopwatch stopwatch) 在 Microsoft.ServiceFabric.Services.GetRequestBodySerializer(Int32 interfaceId) 在 Microsoft.ServiceFabric .Services.Remoting.V2.FabricTransport.Runtime.FabricTransportMessageHandler.d__7.MoveNext())'
我在我的诊断事件中没有发现任何看起来很有希望的东西,而且我看到的类似问题的唯一提及(在这个站点和其他地方)通常涉及不同程序集中的类型,这不是问题,因为共享接口包含在 NuGet 包中。
有什么想法我可能会在这里出错吗?
解决方案
请参阅此答案的底部以直接获得最终解决方案。
我找到了一个部分令人满意的答案。但是,我不完全知道它为什么起作用。我偶然发现这一点纯属偶然。我一直在研究一种通过结构请求无缝传递标头的方法,这就是我最终实现这一目标的方式。
参考上面的监听器代码,并特别注意这一行:
serviceRemotingMessageHandler: null,
为了让它工作,我创建了自己的 IServiceRemotingMessageHandler 实现。请注意,它只是将调用委托给基类型:
class TestRemotingDispatcher : ServiceRemotingMessageDispatcher, IServiceRemotingMessageHandler
{
public TestRemotingDispatcher(
ServiceContext serviceContext, IService serviceImplementation, IServiceRemotingMessageBodyFactory serviceRemotingMessageBodyFactory = null) :
base(serviceContext, serviceImplementation, serviceRemotingMessageBodyFactory)
{
}
public override void HandleOneWayMessage(IServiceRemotingRequestMessage requestMessage)
{
base.HandleOneWayMessage(requestMessage);
}
public override Task<IServiceRemotingResponseMessageBody> HandleRequestResponseAsync(
ServiceRemotingDispatchHeaders requestMessageDispatchHeaders, IServiceRemotingRequestMessageBody requestMessageBody, CancellationToken cancellationToken)
{
return base.HandleRequestResponseAsync(requestMessageDispatchHeaders, requestMessageBody, cancellationToken);
}
public override Task<IServiceRemotingResponseMessage> HandleRequestResponseAsync(IServiceRemotingRequestContext requestContext, IServiceRemotingRequestMessage requestMessage)
{
return base.HandleRequestResponseAsync(requestContext, requestMessage);
}
}
然后听者变成
var fabricListener = new ServiceInstanceListener((context) =>
{
var fabricRemotingListener = new FabricTransportServiceRemotingListener(
serviceContext: context,
serviceRemotingMessageHandler: new TestRemotingDispatcher(context, this),
remotingListenerSettings: new Microsoft.ServiceFabric.Services.Remoting.FabricTransport.Runtime.FabricTransportRemotingListenerSettings()
{
EndpointResourceName = "mngendpoint"
},
serializationProvider: null);
return fabricRemotingListener;
},
"mnglistener");
这按预期工作。如果我弄清楚原因,我会更新。
编辑:我还没有弄清楚为什么显式分配 serviceRemotingMessageHandler 有效,但是上面显示的 ServiceRemotingMessageDispatcher 的子类型不是必需的。它将通过分配内置实现来工作:
serviceRemotingMessageHandler: new ServiceRemotingMessageDispatcher(context, serviceInstance)
最终解释
这一切都归结为我的错误。注意我最初将 null 分配给 serviceRemotingMessageHandler,这是不正确的。查看源代码后,有一个构造函数将为您创建一个调度程序。通过按照我的方式分配 null,侦听器中不存在调度程序。
public FabricTransportServiceRemotingListener(
ServiceContext serviceContext,
IService serviceImplementation,
FabricTransportRemotingListenerSettings remotingListenerSettings = null,
IServiceRemotingMessageSerializationProvider serializationProvider = null)
: this(
serviceContext,
new ServiceRemotingMessageDispatcher(
serviceContext,
serviceImplementation,
GetMessageBodyFactory(serializationProvider, remotingListenerSettings)),
remotingListenerSettings,
serializationProvider)
{
}
异常消息肯定让我走错了路,但至少对(自己造成的)问题有一个很好的解释。
推荐阅读
- c# - 图形委托模拟
- python - 如何解析比特币区块链 blkxxxxx.dat 文件,尤其是交易部分
- javascript - 赛普拉斯和卡夫卡自动化
- kotlin - 未解决的参考:切换到视图绑定后的 myViewHolder
- python - 从 csv 文件中读取字典
- r - Shiny 基于数字输入创建新变量并绘制由我自己解决
- php - PHP 从从 url 传递的数组中获取数据
- angular - Angular ng Snotify 不生成错误消息
- wordpress - 有没有办法在已完成的订单电子邮件模板中自动插入每个订单的发货跟踪号
- excel - 将任何日期添加到相应单元格时,如何编写公式以删除excel中单元格中的值