【问题标题】:wcf exposing genericswcf 暴露泛型
【发布时间】:2009-08-31 19:39:29
【问题描述】:

我有一个应用程序,其中客户端和服务器共享类型,互操作性不是我们关心的问题之一。我计划为所有启用 Web 的对象创建一个存储库,并且我正在考虑为我的公开服务提供一个通用接口。

类似 T GetObject(int id)

但 wcf 不喜欢它,因为它试图公开其架构(我并不真正关心)

是否可以用 WCF 做这样的事情?我可以使用任何类型的绑定,不必是 httpbinding 或 wsbinding...

【问题讨论】:

标签: wcf generics wcf-binding


【解决方案1】:

不,你不能。无论您是否想要或需要互操作性,WCF 最基本的基础是消息交换。

客户端向服务器发送消息并返回响应。该消息是在客户端和服务器之间传递的所有消息,并且需要可序列化为 XML 或二进制格式。这就是为什么要传递的任何数据都必须是原子的(如 int、string)或 DataContract - WCF 服务堆栈关于如何序列化和反序列化此类对象的描述。

您不能传递任何接口或其他“诡计”——基本上,客户端和服务器之间的所有内容都必须可以在 XML 模式中表达。

所以恐怕你想要达到的目标与 WCF 提供的完全相反。 SOA(面向服务的应用程序)的世界和范式完全不同,并不总是 100% 与 OOP 的理念和机制同步。

马克

【讨论】:

  • 所以如果有人想这样做,MS 提供什么技术堆栈,它是否更适合远程处理(如果那还活着)? Ms 确实扩展了对共享类型的支持(netcontractserializer 等)
  • 我不知道当前是否有任何远程对象的解决方案——这基本上就是你想要做的。这种方法确实存在一些问题,MS 试图用 WCF 解决这些问题 - 但为了解决它,必须采用完全基于消息的模型,该模型不适用于接口和泛型。是的,它支持共享具体类型——但绝对不是接口,也不是真正的泛型。
【解决方案2】:

我想这是可能的,但我不确定你是否想要这个。我会采取以下方法(未经测试,不确定它是否有效)。首先在您的解决方案中创建以下项目结构:

  • ServiceInterfaces
  • ServiceImplementations(参考ServiceInterfacesModelClasses
  • ModelClasses
  • Host(参考ServiceInterfacesServiceImplementations
  • Client(参考ServiceInterfacesModelClasses

ServiceInterfaces 中,您有一个这样的界面(我跳过了命名空间等以使示例更短):

[ServiceContract]
public interface IMyService<T>
{
    T GetObject(int id);
}

ServiceImplementations 中有一个实现IMyService&lt;T&gt; 的类:

public class MyService<T> : IMyService<T>
{
    T GetObject(int id)
    {
        // Create something of type T and return it. Rather difficult
        // since you only know the type at runtime.
    }
}

Host 中,您在App.config(或Web.config)文件中为您的服务提供了正确的配置,并使用以下代码来托管您的服务(假设它是一个独立的应用程序):

ServiceHost host = new ServiceHost(typeof(MessageManager.MessageManagerService))
host.Open();

最后在Client 中,您使用ChannelFactory&lt;TChannel&gt; 类来定义代理:

Binding binding = new BasicHttpBinding(); // For the example, could be another binding.
EndpointAddress address = new EndpointAddress("http://localhost:8000/......");
IMyService<string> myService =
    ChannelFactory<IMyService<string>>.CreateChannel(binding, address);
string myObject = myService.GetObject(42);

同样,我不确定这是否有效。诀窍是在主机和客户端之间共享您的服务接口(@98​​7654345@)和域模型对象(ModelClasses)。在我的示例中,我使用一个字符串从服务方法返回,但它可以是来自 ModelClasses 项目的任何数据协定类型。

【讨论】:

  • 我可以在客户端引用相同的程序集,并使用服务引用实用程序的高级选项卡(我猜是 svcutil)来共享类型,这可行,但现在我想做的是抽象的,猜我正在寻找一个远程类型的解决方案,但应该可以在 wcf ...
  • 您应该使用 Visual Studio 中的“添加服务引用”对话框来实现我的方法。那是行不通的。这就是我使用 ChannelFactory 类的原因。它即时生成服务接口的代理实现,无需元数据。
  • 这很可能行不通(我现在无法测试它),因为您定义了一个带有返回泛型类型“T”的操作的服务 - 但为了正常工作,类型“T”必须是 DataContract,以便 WCF 堆栈可以序列化和反序列化该类型的对象。请记住:您在客户端和服务器之间传递的只是消息 - 没有对象引用、接口引用或任何基于引用的东西!您必须能够将您的请求序列化为某种消息格式,并在另一端将其反序列化 - 这不适用于泛型 :-(
  • 但是假设类型 T 的实例是适当的 DataContract(或 Serializable 或 ISerializable),您认为它会起作用吗?鉴于此实例的类在主机和客户端应用程序之间共享。这不是我曾经构建过的东西,但我看不出它不应该工作的原因。我今天要尝试测试一下。
  • @rwwilden:对于给定的 T 实例,也许 - 但是如果你已经有一个具体的类型,为什么还要使用泛型呢?在 SOA 场景中使用泛型并没有太大帮助...
【解决方案3】:

如果您使用 ServiceKnownTypesDiscovery,您可以做到这一点。

例如:

[ServiceKnownType("GetKnownTypes", typeof(ServiceKnownTypesDiscovery))]
public interface ISomeService
{
    [OperationContract]
    object Request(IRequestBase parameters);
}

GetKnownTypes 可以这样声明:

public static class ServiceKnownTypesDiscovery
{
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
        var types = new List<Type>();

        foreach (var asmFile in Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory, "*.dll"))
        {
            Assembly asm = Assembly.LoadFrom(asmFile);
            types.AddRange(asm.GetTypes().Where(p=> Attribute.IsDefined(p,typeof(DataContractAttribute))));
        }

        return types;
    }
}

在这种情况下,使用 [DataContract] 声明的所有内容(只要它们在服务器和客户端都可发现)都可以序列化。

我希望这会有所帮助!

【讨论】:

  • 但是...您的解决方案不使用泛型
【解决方案4】:

按照前面的示例,您可以声明一个DataContract,其对象为DataMember。然后,您可以添加一个扩展方法来获取和设置对象数据成员的泛型类型。您也可以将其设为内部,这样您将不得不使用扩展方法来获取和设置值。

当然,只有当您使用 svcutil(或 Visual Studio)生成客户端并引用包含数据协定的程序集和具有扩展方法的类时,它才有效。

希望这会有所帮助...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    • 2018-06-19
    • 1970-01-01
    相关资源
    最近更新 更多