Service Fabric:System.ArgumentException:找不到具有此 ID 的接口 -488762776
Service Fabric: System.ArgumentException: No interface found with this Id -488762776
我正在开发一个简单的 Service Fabric 集群,我想在其中从无状态 ASP.NET Core 2.0 web API.
调用无状态服务
我做的第一件事是创建一个具有简单界面和 DTO 的 .NET Standard 2.0 class 库:
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: No interface found with this Id -488762776
在 Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.GetInterfaceDetails(Int32 接口 ID)
在 Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.CreateSerializers(Int32 接口 ID)
在 System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func
2 值工厂)
在 Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.GetRequestBodySerializer(Int32 接口 ID)
在 Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportMessageHandler.CreateRemotingRequestMessage(FabricTransportMessage fabricTransportMessage, Stopwatch 秒表)
在 Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportMessageHandler.d__7.MoveNext())'
我在我的诊断事件中没有发现任何看起来有希望的东西,而且我看到的唯一提到的类似问题(在这个站点和其他地方)通常涉及不同程序集中的类型,这不是问题假定共享接口包含在 NuGet 包中。
我有什么地方可能出错的想法吗?
我确实遇到过一次同样的问题,但无法解决,然后使用 NonIServiceProxy method:
public async Task<MyDto> Get()
{
var svc = ServiceProxy.CreateNonIServiceProxy<ContractsStandard.IMicroService>(new Uri("fabric:/FabricSandbox4/TheService"), listenerName: "mylistener");
return await svc.GetMahDto(23);
}
基本上它消除了在服务和客户端之间共享相同接口的要求。
查看此答案的底部以直接获得最终解决方案。
我找到了部分令人满意的答案。但是,我不完全知道它为什么起作用。我偶然发现了这个纯属偶然。我一直在研究一种无缝传递 headers 结构请求的方法,这就是我最终达到这个目标的方式。
参考上面的监听代码,特别注意这一行:
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 的子类型。它将通过分配 built-in 实现来工作:
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)
{
}
异常消息肯定让我走错了路,但至少对 (self-inflicted) 问题有一个很好的解释。
我刚遇到这个问题,对我来说这是接口的命名空间问题。愚蠢的错误我只是将 class 复制到另一个没有命名空间的项目中。
我正在开发一个简单的 Service Fabric 集群,我想在其中从无状态 ASP.NET Core 2.0 web API.
调用无状态服务我做的第一件事是创建一个具有简单界面和 DTO 的 .NET Standard 2.0 class 库:
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: No interface found with this Id -488762776
在 Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.GetInterfaceDetails(Int32 接口 ID)
在 Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.CreateSerializers(Int32 接口 ID)
在 System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func
2 值工厂)
在 Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.GetRequestBodySerializer(Int32 接口 ID)
在 Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportMessageHandler.CreateRemotingRequestMessage(FabricTransportMessage fabricTransportMessage, Stopwatch 秒表)
在 Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportMessageHandler.d__7.MoveNext())'
我在我的诊断事件中没有发现任何看起来有希望的东西,而且我看到的唯一提到的类似问题(在这个站点和其他地方)通常涉及不同程序集中的类型,这不是问题假定共享接口包含在 NuGet 包中。
我有什么地方可能出错的想法吗?
我确实遇到过一次同样的问题,但无法解决,然后使用 NonIServiceProxy method:
public async Task<MyDto> Get()
{
var svc = ServiceProxy.CreateNonIServiceProxy<ContractsStandard.IMicroService>(new Uri("fabric:/FabricSandbox4/TheService"), listenerName: "mylistener");
return await svc.GetMahDto(23);
}
基本上它消除了在服务和客户端之间共享相同接口的要求。
查看此答案的底部以直接获得最终解决方案。
我找到了部分令人满意的答案。但是,我不完全知道它为什么起作用。我偶然发现了这个纯属偶然。我一直在研究一种无缝传递 headers 结构请求的方法,这就是我最终达到这个目标的方式。
参考上面的监听代码,特别注意这一行:
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 的子类型。它将通过分配 built-in 实现来工作:
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)
{
}
异常消息肯定让我走错了路,但至少对 (self-inflicted) 问题有一个很好的解释。
我刚遇到这个问题,对我来说这是接口的命名空间问题。愚蠢的错误我只是将 class 复制到另一个没有命名空间的项目中。