【问题标题】:Service Fabric with Generic Services具有通用服务的 Service Fabric
【发布时间】:2016-08-27 09:41:06
【问题描述】:

我希望有一个通用类型服务,即 -

public interface IFooService<T> 
{
   Task<T> Get(int id);
}

但是,Service Fabric 不允许泛型类或泛型方法。我也尝试过类似

public interface INinjaService : IService, IFooService<SuperNinja>
{


}

但它不拾取继承的接口声明

服务类型“Omni.Fabric.Services.NinjaService”未实现 任何服务接口。服务接口是派生的 来自“Microsoft.ServiceFabric.Services.Remoting.IService”类型。

我似乎在 Service Fabric 文档或 stackoverflow 上找不到任何对泛型的引用。要么它仍然太新,要么我可能走错了路。有没有人幸运地实现了这种模式?可以做到吗?应该这样做吗?

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;
        }
    }

【问题讨论】:

  • 可以分享Omni.Fabric.Services.NinjaService源代码吗?
  • @MikeMazmanyan 完成。
  • 这个异常什么时候抛出?
  • 服务类型 'Omni.Fabric.Services.NinjaService' 没有实现任何服务接口。服务接口是派生自“Microsoft.ServiceFabric.Services.Remoting.IService”类型的接口。
  • 我知道异常需要了解什么时候抛出

标签: c# generics azure-service-fabric


【解决方案1】:

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

【讨论】:

  • 我接受了您的回答,因为它是正确的。即使我不喜欢它 - 大声笑。根据您的回答,我觉得这种泛型在未来可能会出现?
  • 很公平!这是我们将来可能会支持的东西,但我目前没有任何具体的日期或详细信息。
【解决方案2】:

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

所以你需要让IFooService&lt;T&gt; 派生自IService,目前不支持。

所以不支持泛型:(

【讨论】:

  • 当我尝试像 INinjaService service = ServiceProxy.Create(...
【解决方案3】:

这个答案可能会迟到,但它可能会对某人有所帮助。我通过确保服务类中实现的每个接口都继承自 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
{
}

希望对您有所帮助。

【讨论】:

  • 这个不行,还是把它看成一个通用接口。
【解决方案4】:

因为我想从一个服务调用另一个服务,所以我所做的解决方法是传递一个带有类型名称的字符串,并通过反射调用另一个方法。

    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;
        }
    }

希望它可以帮助某人。

【讨论】:

    猜你喜欢
    • 2017-10-30
    • 2019-06-21
    • 1970-01-01
    • 2021-03-01
    • 1970-01-01
    • 2018-03-13
    • 2016-08-30
    • 2017-07-10
    • 2018-09-06
    相关资源
    最近更新 更多