托管实现通用接口的C#泛型类的WCF服务

时间:2011-06-03 12:00:09

标签: .net wcf

我有一个公开Generic接口的WCF服务(该服务有一个实现此接口的泛型类)。

然后我尝试在托管控制台应用程序中托管此服务(仅用于测试目的)。 ThreadStart行导致错误,表示找不到T的类型。

现在我不能通过做主要< T>(string [] args)其中T:IComparable< T>因为它说,没有找到主要入口点。

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

    // 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或字符串BST。然后客户端调用具有给定类型的实际方法,并将服务通道调用到不同的端点,每个端点都暴露出不同类型的BST。

一般如何处理此类案件?

2 个答案:

答案 0 :(得分:5)

当您托管服务时,您无法使用开放式泛型。您必须指定具体类型来托管具体服务。如果要为更多通用参数托管服务,则必须为每个参数类型创建一个新主机,并为每个参数公开一个具有唯一地址的端点。托管服务后,必须能够说出它接受的类型,并在服务描述(WSDL源代码)中描述它们。

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

您可以通过将基类型指定为泛型参数来解决此问题,但即使在此之后,您的服务必须知道可以使用的所有派生类型而不是基本类型(有多种技术可用于此但它们都不提供随机类型)

编辑:

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

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

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

答案 1 :(得分:1)

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

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 做什么与泛型类型?这将确定哪些类型是有效参数。