簡體   English   中英

具有通用服務的服務結構

[英]Service Fabric with Generic Services

我希望有一個通用類型的服務,即 -

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

但是,服務結構不允許使用泛型類或泛型方法。 我也嘗試過類似的東西

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

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通信監聽器的方法。

所以在你的情況下,不,還沒有支持泛型。 但這是特定服務通信堆棧的限制,而不是一般服務的限制,當然您可以使用任何所需的通信堆棧

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> ,目前不支持。

因此不支持泛型:(

這個答案可能會遲到,但它可能對某人有所幫助。 我通過確保服務類中實現的每個接口都繼承自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
{
}

希望有所幫助。

由於我想從一個服務到另一個服務進行調用,我所做的解決方法是傳遞一個帶有Type名稱的字符串,並用反射調用另一個方法。

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

希望它可以幫助某人。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM