【问题标题】:WCF service hosting a C# generic class implementing generic Interface托管实现通用接口的 C# 通用类的 WCF 服务
【发布时间】:2011-09-07 18:47:31
【问题描述】:

我有一个 WCF 服务,它公开了一个通用接口(并且该服务有一个实现该接口的通用类)。

然后我尝试在托管控制台应用程序中托管此服务(现在仅用于测试目的)。 ThreadStart 行导致错误提示 type for T not found。

现在我不能通过执行 Main(string[] args) where T: IComparable 来使 Main 通用,因为它说,找不到 Main 入口点。

我的问题是一般如何处理这种情况?

    // Service Hosting app
    static void Main(string[] args)
    {
       new Thread(new ThreadStart(StartBSTService<T>)).Start();
    }

    static void StartBSTService<T>() where T : IComparable<T>
    {
        string baseAddress = "http://localhost:8080/bst";

        StartAService(typeof(BSTService<T>), baseAddress);
    }

编辑:同时添加服务类

  [ServiceContract(Namespace = "http://Microsoft.Samples.GettingStarted")]
  public interface IBSTService<T> where T : IComparable<T> //: ICollection<T>
  {
      [OperationContract]
      void Add(T toAdd);
      // For brevity, not providing all other methods
      // but they are similar IColleciton methods.
  }

public class BSTService<T> : IBSTService<T> where T : IComparable<T>
{
       BinarySearchTree<T> tree = new BinarySearchTree<T>();

       public void Add(T toAdd)
       {
           tree.Add(toAdd);
       }
}

客户端会像使用任何泛型类型一样使用它:

    BSTService<string> client = new BSTService<string>; 
    // OR
    BSTService<int> client = new BSTService<int>;

EDIT2: @asawyer 的观点似乎合乎逻辑,Main 是泛型类的消费者,所以它应该提供类型,但是我是否必须为每种类型启动一个新端点?以及如何处理。就像我可以编写一个服务包装器,它只公开一种方法,比如 INIT(Type typeOfBST)。客户端调用它来告诉服务他想要启动 int 或 string BST。然后客户端调用具有给定类型的真实方法,并且服务将这些调用引导到不同的端点,每个端点都暴露了不同类型的 BST。

一般情况下如何处理?

【问题讨论】:

    标签: .net wcf


    【解决方案1】:

    当您托管服务时,您不能使用开放泛型。您必须指定具体类型来托管具体服务。如果您想为更通用的参数托管服务,您确实必须为每个参数类型创建一个新主机,并为每个参数类型公开一个具有唯一地址的端点。托管服务后,它必须能够说明它接受哪些类型并在服务描述中描述它们(WSDL 的来源)。

    WCF 在您托管服务的基础上工作,该服务必须能够描述它接受的消息 - 因为它会生成服务描述。服务能够根据描述序列化消息。任何平台上的任何客户端都可以使用描述并向服务发送正确的消息 - 客户端将从描述中了解允许的消息内容,因此服务主机必须使用具体类型 - 而不是 T。

    您可以通过将基类型指定为泛型参数来克服这个问题,但即使在此之后,您的服务也必须知道所有可以用来代替基类型的派生类型(有多种技术,但没有一个提供随机类型) .

    编辑:

    从技术上讲,您要求的意思是:将类型的名称从客户端发送到主服务。主服务将检查该类型的服务是否已存在。如果是,它会将服务的 url 发送回客户端。如果不是,它将通过反射创建服务并启动它。它将存储有关新托管服务的信息并将 URL 发送回客户端。

    另一种变体是预先启动所有服务并使用单个 WCF 路由服务将请求路由到正确的服务。

    此类解决方案看起来像是一场维护噩梦,而第一个解决方案的性能会更差,因为每次操作都需要两次网络调用。此外,它通常不能互操作,因为您的客户必须预先获得通用合同才能调用此类服务​​。根本不要这样做 - 定义有限的已用类集并将 KnownTypeDataContractResolver 与单一服务一起使用。

    【讨论】:

    • + 1 用于突出服务模型的功能。您也可以在我的问题中回答 EDIT2 吗?谢谢。
    • 好的,我明白了。谢谢。我试图使服务像底层 BST 类一样通用。因此,客户端可以先进行 INIT(TypeTobeInited) 之类的调用,然后服务创建该 Typed BST 对象,而不是进行 2 次调用。客户端进一步总是调用通用的 Add/Remove 方法,服务解析,如果发送的参数类型与原始 INIT 类型匹配,则继续执行调用。有什么模式可以做到这一点?或者你建议不要那样做(因为这是hacky和维护问题。)
    【解决方案2】:

    当你声明一个泛型类型的实例时,你必须提供一个非泛型类型参数,即

    interface ITest { }
    class Test<T> where T : ITest { }
    

    你不能只说:

    var test = new Test<T>();
    

    T 在这种情况下没有多大意义,你需要一个更具体的类型:

    class ImplementsITest : ITest { }
    
    var test = new Test<ImplementsITest>();
    

    在您的示例中,您需要在 Main() 中声明实例时提供类型

    static void Main(string[] args)
    {
       new Thread(new ThreadStart(StartBSTService<SomeTypeThatActuallyExists>)).Start();
    }
    

    BSTService 对泛型类型做什么?这将确定哪些类型是有效参数。

    【讨论】:

    • 那么我的服务不能是通用的吗?,其中客户端将根据其要求实例化一个类型
    • 如果我错了,请纠正我,但这里的 Main() 实例是 BSTService 类的消费客户端,因此需要提供一个类型。
    • 是的,这似乎合乎逻辑,但是我必须为每种类型启动一个新端点吗?以及如何处理。就像我可以编写一个服务包装器一样,它只公开一种方法,比如 INIT(Type typeOfBST)。客户端调用它来告诉服务他想要启动 int 或 string BST。如何处理?
    • 这超出了您原始泛型问题的范围。我会将此标记为完成并提出一个新的更具体的设计/架构问题。与 cmets 中提出的新问题相比,您将获得更好的答案。 :)
    猜你喜欢
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    相关资源
    最近更新 更多