具有通用服务的服务结构
Service Fabric with Generic Services
我希望有一个通用类型的服务,即 -
public interface IFooService<T>
{
Task<T> Get(int id);
}
但是,服务结构不允许泛型 类 或泛型方法。我也尝试过
public interface INinjaService : IService, IFooService<SuperNinja>
{
}
但它不会选择继承的接口声明
The service type 'Omni.Fabric.Services.NinjaService' does not implement
any service interfaces. A service interface is the one that derives
from 'Microsoft.ServiceFabric.Services.Remoting.IService' type.
我似乎无法在 Service Fabric 文档或 Whosebug 上找到任何对泛型的引用。要么它仍然太新,要么可能我走错了路。有没有人有幸实施这种模式?可以吗?应该做吗?
根据要求提供 NinjaService
public class NinjaService : StatelessService, INinjaService
{
public NinjaService(StatelessServiceContext serviceContext) : base(serviceContext)
{
}
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[] { new ServiceInstanceListener(context => this.CreateServiceRemotingListener(context)) };
}
public Task<SuperNinja> Get(int id)
{
return Task.FromResult(new SuperNinja());
}
}
使用代码(从 Owin WebApi 服务调用
public async Task<SuperNinja> Get(int key)
{
try
{
INinjaService service = ServiceProxy.Create<INinjaService>(new Uri("fabric:/Omni.Fabric/Services"));
var t = await service.Get(key).ConfigureAwait(false);
return t;
}
catch (Exception ex)
{
throw;
}
}
Service Fabric 正在使用此扩展方法删除非服务类型接口
internal static class ServiceTypeExtensions
{
public static Type[] GetServiceInterfaces(this Type serviceType)
{
List<Type> typeList = new List<Type>(((IEnumerable<Type>)serviceType.GetInterfaces()).Where(t => typeof(IService).IsAssignableFrom(t)));
typeList.RemoveAll(t => t.GetNonServiceParentType() != null);
return typeList.ToArray();
}
internal static Type GetNonServiceParentType(this Type type)
{
List<Type> typeList = new List<Type>(type.GetInterfaces());
if (typeList.RemoveAll(t => t == typeof(IService)) == 0)
return type;
foreach (Type type1 in typeList)
{
Type serviceParentType = type1.GetNonServiceParentType();
if (serviceParentType != null)
return serviceParentType;
}
return null;
}
}
并检查结果
if (serviceInterfaces.Length == 0 && !serviceType.IsAbstract)
throws the exception in question
所以我找到了这个案例的解决方法
public interface IServiceWrapper : IService
{
}
public interface INinjaService : IServiceWrapper, IFooService<SuperNinja>
{
}
已更新
经过一些调查,我发现代理正在检查所有接口父级是否需要像 IService 一样,这意味着
Type serviceParentType = serviceInterfaceType.GetNonServiceParentType();
if (serviceParentType != null)
throws another exception
所以你需要从目前不支持的IService
派生IFooService<T>
。
因此不支持泛型:(
Service Fabric 中的服务可以实现通用接口:
interface IMyService<T>
{
T Foo();
}
class Stateful1 : StatefulService, IMyService<string>
{
public Stateful1(StatefulServiceContext context)
: base(context)
{ }
public string Foo()
{
// do foo
}
}
这很好。
不支持的是远程过程调用 (RPC) 的通用接口。这是特定于 Service Remoting 通信堆栈的,它是 IService 和 Remoting Communication Listener 所拥有的。
所以在你的情况下,不,泛型还不受支持。但这是特定服务通信堆栈的限制,而不是一般服务的限制,当然你可以使用 any communication stack you want.
这个答案可能来晚了,但它可能对某人有所帮助。我通过确保服务 class 中实现的每个接口都继承自 IService 来解决这个问题。在您的情况下,您将拥有以下内容:
public interface IFooService<T> : IService
{
Task<T> Get(int id);
}
public interface INinjaService : IFooService<SuperNinja>
{
}
public class NinjaService : StatelessService, INinjaService
{
}
试试看,应该可以。
如果您需要在服务中实现多个接口,我尝试了以下选项:
public interface MyInterfaceA : IService { }
public interface MyInterfaceB : IService { }
public class MyServiceAB : StatelessService, MyInterfaceA, MyInterfaceB
{
}
或
public interface MyInterfaceA : IService { }
public interface MyInterfaceB : IService { }
public interface MyInterfaceC : MyInterfaceA, MyInterfaaceB { }
public class MyServiceC : StatelessService, MyInterfaceC
{
}
希望对您有所帮助。
因为我想从一个服务调用另一个服务,我所做的解决方法是传递一个带有类型名称的字符串,并通过反射调用另一个方法。
public async Task<Result> GetResultAsync(Site site, string indexableType, SearchQuery searchQuery)
{
using (var provider = new Provider(Logger))
{
var indexableT = typeof(IIndexable).Assembly
.GetTypes()
.FirstOrDefault(t => typeof(IIndexable).IsAssignableFrom(t) && t.Name == indexableType);
if (indexableT != null)
{
var generic = provider
.GetType()
.GetMethod("METHOD_NAME_IN_PROVIDER"))
.MakeGenericMethod(indexableT);
//This is the same as calling: await provider.METHOD_NAME_IN_PROVIDER<T>(site, searchQuery);
return await (Task<Result>) generic.Invoke(provider, new object[] { site, searchQuery });
}
return null;
}
}
希望对大家有所帮助。
我希望有一个通用类型的服务,即 -
public interface IFooService<T>
{
Task<T> Get(int id);
}
但是,服务结构不允许泛型 类 或泛型方法。我也尝试过
public interface INinjaService : IService, IFooService<SuperNinja>
{
}
但它不会选择继承的接口声明
The service type 'Omni.Fabric.Services.NinjaService' does not implement any service interfaces. A service interface is the one that derives from 'Microsoft.ServiceFabric.Services.Remoting.IService' type.
我似乎无法在 Service Fabric 文档或 Whosebug 上找到任何对泛型的引用。要么它仍然太新,要么可能我走错了路。有没有人有幸实施这种模式?可以吗?应该做吗?
根据要求提供 NinjaService
public class NinjaService : StatelessService, INinjaService
{
public NinjaService(StatelessServiceContext serviceContext) : base(serviceContext)
{
}
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[] { new ServiceInstanceListener(context => this.CreateServiceRemotingListener(context)) };
}
public Task<SuperNinja> Get(int id)
{
return Task.FromResult(new SuperNinja());
}
}
使用代码(从 Owin WebApi 服务调用
public async Task<SuperNinja> Get(int key)
{
try
{
INinjaService service = ServiceProxy.Create<INinjaService>(new Uri("fabric:/Omni.Fabric/Services"));
var t = await service.Get(key).ConfigureAwait(false);
return t;
}
catch (Exception ex)
{
throw;
}
}
Service Fabric 正在使用此扩展方法删除非服务类型接口
internal static class ServiceTypeExtensions
{
public static Type[] GetServiceInterfaces(this Type serviceType)
{
List<Type> typeList = new List<Type>(((IEnumerable<Type>)serviceType.GetInterfaces()).Where(t => typeof(IService).IsAssignableFrom(t)));
typeList.RemoveAll(t => t.GetNonServiceParentType() != null);
return typeList.ToArray();
}
internal static Type GetNonServiceParentType(this Type type)
{
List<Type> typeList = new List<Type>(type.GetInterfaces());
if (typeList.RemoveAll(t => t == typeof(IService)) == 0)
return type;
foreach (Type type1 in typeList)
{
Type serviceParentType = type1.GetNonServiceParentType();
if (serviceParentType != null)
return serviceParentType;
}
return null;
}
}
并检查结果
if (serviceInterfaces.Length == 0 && !serviceType.IsAbstract)
throws the exception in question
所以我找到了这个案例的解决方法
public interface IServiceWrapper : IService
{
}
public interface INinjaService : IServiceWrapper, IFooService<SuperNinja>
{
}
已更新
经过一些调查,我发现代理正在检查所有接口父级是否需要像 IService 一样,这意味着
Type serviceParentType = serviceInterfaceType.GetNonServiceParentType();
if (serviceParentType != null)
throws another exception
所以你需要从目前不支持的IService
派生IFooService<T>
。
因此不支持泛型:(
Service Fabric 中的服务可以实现通用接口:
interface IMyService<T>
{
T Foo();
}
class Stateful1 : StatefulService, IMyService<string>
{
public Stateful1(StatefulServiceContext context)
: base(context)
{ }
public string Foo()
{
// do foo
}
}
这很好。
不支持的是远程过程调用 (RPC) 的通用接口。这是特定于 Service Remoting 通信堆栈的,它是 IService 和 Remoting Communication Listener 所拥有的。
所以在你的情况下,不,泛型还不受支持。但这是特定服务通信堆栈的限制,而不是一般服务的限制,当然你可以使用 any communication stack you want.
这个答案可能来晚了,但它可能对某人有所帮助。我通过确保服务 class 中实现的每个接口都继承自 IService 来解决这个问题。在您的情况下,您将拥有以下内容:
public interface IFooService<T> : IService
{
Task<T> Get(int id);
}
public interface INinjaService : IFooService<SuperNinja>
{
}
public class NinjaService : StatelessService, INinjaService
{
}
试试看,应该可以。 如果您需要在服务中实现多个接口,我尝试了以下选项:
public interface MyInterfaceA : IService { }
public interface MyInterfaceB : IService { }
public class MyServiceAB : StatelessService, MyInterfaceA, MyInterfaceB
{
}
或
public interface MyInterfaceA : IService { }
public interface MyInterfaceB : IService { }
public interface MyInterfaceC : MyInterfaceA, MyInterfaaceB { }
public class MyServiceC : StatelessService, MyInterfaceC
{
}
希望对您有所帮助。
因为我想从一个服务调用另一个服务,我所做的解决方法是传递一个带有类型名称的字符串,并通过反射调用另一个方法。
public async Task<Result> GetResultAsync(Site site, string indexableType, SearchQuery searchQuery)
{
using (var provider = new Provider(Logger))
{
var indexableT = typeof(IIndexable).Assembly
.GetTypes()
.FirstOrDefault(t => typeof(IIndexable).IsAssignableFrom(t) && t.Name == indexableType);
if (indexableT != null)
{
var generic = provider
.GetType()
.GetMethod("METHOD_NAME_IN_PROVIDER"))
.MakeGenericMethod(indexableT);
//This is the same as calling: await provider.METHOD_NAME_IN_PROVIDER<T>(site, searchQuery);
return await (Task<Result>) generic.Invoke(provider, new object[] { site, searchQuery });
}
return null;
}
}
希望对大家有所帮助。