我正在研究一个简单的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:找不到与此ID -488762776的接口
在Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.GetInterfaceDetails(Int32 interfaceId)
在Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.CreateSerializers(Int32 interfaceId)
在System.Collections.Concurrent.ConcurrentDictionary 2.GetOrAdd(TKey key, Func
2 valueFactory处)
在Microsoft.ServiceFabric.Services.Remoting.V2.ServiceRemotingMessageSerializersManager.GetRequestBodySerializer(Int32 interfaceId)
在Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportMessageHandler.CreateRemotingRequestMessage(FabricTransportMessage fabricTransportMessage,秒表秒表)
在Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.FabricTransportMessageHandler.d__7.MoveNext())'
我在诊断事件中没有发现任何看起来很有希望的东西,而且我在该站点和其他地方看到的类似问题的唯一提及通常涉及不同程序集中的类型,鉴于此,这不是问题共享接口包含在NuGet程序包中。
有什么想法我可能在这里出错吗?
答案 0 :(得分:1)
请参阅此答案的底部以直接获得最终解决方案。
我找到了部分令人满意的答案。但是,我不完全知道它为什么起作用。我偶然发现了这纯属偶然。我一直在研究一种通过结构请求无缝传递标头的方法,这就是我最终遇到的问题。
参考上面的侦听器代码,并特别注意这一行:
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)
最终解释
所有这些归结于我的错误。请注意,我最初是为serviceRemotingMessageHandler分配null,这是不正确的。在查看源代码之后,有一个构造函数将为您创建一个调度程序。通过按我的方式分配null,侦听器内不存在调度程序。
public FabricTransportServiceRemotingListener(
ServiceContext serviceContext,
IService serviceImplementation,
FabricTransportRemotingListenerSettings remotingListenerSettings = null,
IServiceRemotingMessageSerializationProvider serializationProvider = null)
: this(
serviceContext,
new ServiceRemotingMessageDispatcher(
serviceContext,
serviceImplementation,
GetMessageBodyFactory(serializationProvider, remotingListenerSettings)),
remotingListenerSettings,
serializationProvider)
{
}
异常消息肯定使我误入歧途,但至少对于(自残)问题有很好的解释。
答案 1 :(得分:0)
我确实曾经遇到过相同的问题,但是除了使用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);
}
基本上,它消除了在服务和客户端之间共享相同接口的要求。
答案 2 :(得分:0)
我只是遇到了这个问题,对我来说,这是接口名称空间的一种情况。愚蠢的错误是我只是将类复制到另一个没有名称空间的项目中。