【问题标题】:WCF - Cannot create abstract classWCF - 无法创建抽象类
【发布时间】:2012-10-01 19:43:47
【问题描述】:

我正在编写一个 WCF Web 服务并传入一个复杂类型作为该方法的参数。复杂类型如下所示:

 [DataContract(Namespace = "")]
public class MyRequest 
{
    [DataMember()]
    public string TransactionId { get; set; }

    [DataMember(IsRequired = true)]
    public bool IsRollback { get; set; }

    [DataMember(IsRequired = true)]
    public OrderType OrderType { get; set; }

    [DataMember(IsRequired = true)]
    public ICustomerId CustomerId { get; set; }

    [DataMember()]
    public long OrderId { get; set; }

    [DataMember()]
    public AnotherComplexType PurchaseInfo { get; set; }

webservice 方法如下所示:

[ServiceKnownType(typeof(CustomerIdByName))]
[ServiceKnownType(typeof(CustomerIdByAccount))]
public OrderResult Execute(MyRequest order) {
}

界面如下:

[KnownType(typeof(CustomerIdByAccount))]    
[KnownType(typeof(CustomerIdByName))]
public interface ICustomerId{

string GetId();
}

当我使用 SOAP 端点发出请求时,一切正常。但是当将请求传递到 REST 端点时,我得到了序列化错误。

这是我正在使用的请求

<MyRequest>
<CustomerId>
<AccountId>59251</AccountId>
</CustomerId>
<IsRollback>false</IsRollback>
<OrderId>0</OrderId>
<OrderType>OrderSubscription</OrderType>
<PurchaseInfo>
<ObjectId>196521</ObjectId>
</PurchaseInfo>
<TransactionId>ABC123</TransactionGuid>
</MyRequest>

由于我在这一点上卡了太久,然后我将 ICustomerId 成员更改为实现 ICustomerId 的抽象类。再次,SOAP 端点工作正常,但将请求发送到其余端点我收到一条错误消息,指出“无法创建抽象类”

我在这里遗漏了什么或做错了什么?

这是否因为接口嵌套在复杂类型中而不是 webservice 方法的直接参数而失败?我使用了接收接口作为参数的 web 服务,并且使用 KnownType 装饰器它们工作得很好。同样的问题也适用于抽象类,这是不是因为抽象类嵌套在 MyRequest 复杂类型的成员中而不起作用?

这是我收到的错误消息:

命名空间中的元素 CustomerId 不能将子内容反序列化为对象。请使用 XmlNode[] 反序列化这种 XML 模式

【问题讨论】:

  • OrderResult Execute(OrderRequest order) 不返回任何内容。另外,MyRequest 是否实现了IMyRequest 支持的所有内容?
  • 是否有关于儿童的数据合同/数据成员?
  • 我有一个扩展抽象 CustomerId 的具体类。它被称为“CustomerIdByAccount”,它有一个公共属性“AccountId”。我使用用于请求的示例 XML 更新了问题
  • OrderResultAnotherComplexType 也需要是 DataContracts。
  • 它们是数据合约。 CustomerId 是 ICustomerId 类型的数据成员,反序列化器似乎不理解 CustomerIdByAccount 是实现该接口的已知类型。

标签: c# wcf rest soap abstract


【解决方案1】:

您是否尝试过将界面装饰为 RESTful 方法?

[ServiceContract]
public interface IMyRequest
{
    [OperationContract]
    [WebInvoke(
       UriTemplate = "Requests/GetID",
       Method = "POST",
       BodyStyle = WebMessageBodyStyle.Wrapped)]
    string GetId(MyRequest myRequest);
...

还有:

  • 确保 [DataMember] 属性与您的请求负载相匹配。在您的 XML 请求负载中传递的所有内容都必须由服务中的序列化程序捕获。我建议保持命名相同,但您可以使用 [DataMember(name="MyProperty")] 对其进行映射。此外,您的 [DataContract] 必须映射为匹配 XML 有效负载的父节点的名称,例如 [DataContract(Name="MyRequest")],但前提是该类的名称与 xml 节点不同。这样做,它会将您的 xml 反序列化为服务器端对象/dto
  • 您遇到的错误听起来像是在抱怨 DataContract 内部的复杂类型。您的复杂类型需要与 MyRequest 类型一样进行序列化修饰。
  • 还要确保您的 REST 端点绑定到 webHttpBinding

【讨论】:

  • 对不起,接口不是服务的接口。我还有一个用于放置 WebInvoke 注释等的接口。此接口仅用于客户标识符,我们现在仅使用帐户 ID 来识别客户,但将来可能是设备序列号、地址、等等......这就是为什么我想为这个数据成员使用接口而不是固定类型,随着我们的成长,我可以继续添加更多类型。问题是,即使我使用该接口的已知类型命中反序列化器,它仍然不知道如何反序列化它。
  • 很公平,但我仍然看到您的有效负载与 dto 对象不匹配。而且您有一个接口作为仅公开方法的成员。方法不序列化。所以我不确定编译器如何知道要使用哪个实现,因为该实现将无法在序列化/反序列化过程中生存。
  • 嗯,我的意思是有办法解决这个问题,但我会问自己,你是否真的需要经历那种痛苦或重新思考。一般来说,您不会想要处理通过 WCF 服务传递对象的完整实现的痛苦。 IMO,在客户端处理纯 xml,然后在服务中管理它。
  • 我不知道方法不会序列化。我的第一次尝试是在界面中创建一个属性“Id”,CustomerIdByAccount 将有一个私有成员来保存帐户 ID,但“Id”属性上的“get”将以字符串格式返回相同的私有值。没用...同样的错误。我还尝试制作一个实现 ICustomerId 接口的 CustomerId 抽象类。然后 CustomerIdByAccount 扩展抽象类。我收到一条错误消息,指出“无法创建抽象类”。你能想到另一种选择吗?非常感谢您的帮助!
  • 我认为您仍然可以使用与您相同的方式使用界面来完成它,现在我考虑了一下。但它仍然感觉像是一种设计气味。否则,我认为真正的问题是您的有效负载与您的业务对象不匹配。嗯……你的体型包了吗?另外,尝试添加 knowntypeof(CustomerId)。请记住,继承不会通过序列化持续存在,这就是为什么您必须通过 knowntypeof 拼出继承。如果这不起作用,请尝试放弃接口并使用基本类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-07
  • 1970-01-01
  • 2015-08-07
相关资源
最近更新 更多