2010-04-02 44 views
1

我正在升级我们的Web服务以支持版本控制。我们将发布我们的版本的Web服务,像这样:这个版本的.NET asmx Web服务:将对象属性序列化为字符串属性以支持版本化

http://localhost/project/services/1.0/service.asmx 
http://localhost/project/services/1.1/service.asmx 

的一个要求是,我不能打破原有的WSDL(1.0 WSDL)。面临的挑战在于如何通过Web服务背后的逻辑来处理新版本的类(该逻辑包括许多命令和适配器类)。请注意,升级到WCF目前不是一个选项。

为了说明这一点,我们来看一个博客和帖子的例子。在引入版本之前,我们传递了具体的对象而不是接口。所以AddPostToBlog命令将采取Post对象而不是IPost

// Old AddPostToBlog constructor. 
public AddPostToBlog(Blog blog, Post post) { 
    // constructor body 
} 

随着引进的版本,我想保持原有的Post,同时增加了PostOnePointOnePostPostOnePointOne都将实现IPost接口(它们没有扩展抽象类,因为继承打破了wsdl,尽管我想通过一些奇妙的xml序列化技巧可以解决这个问题)。

// New AddPostToBlog constructor. 
public AddPostToBlog(Blog blog, IPost post) { 
    // constructor body 
} 

这给我带来了关于序列化的问题。原始Post类具有名为Type的枚举属性。对于各种跨平台兼容性问题,我们将我们的Web服务中的枚举更改为字符串。所以,我想做到以下几点:

// New IPost interface. 
public interface IPost 
{ 
    object Type { get; set; } 
} 

// Original Post object. 
public Post 
{ 
    // The purpose of this attribute would be to maintain how 
    // the enum currently is serialized even though now the 
    // type is an object instead of an enum (internally the 
    // object actually is an enum here, but it is exposed as 
    // an object to implement the interface). 
    [XmlMagic(SerializeAsEnum)] 
    object Type { get; set; } 
} 

// New version of Post object 
public PostOnePointOne 
{ 
    // The purpose of this attribute would be to force 
    // serialization as a string even though it is an object. 
    [XmlMagic(SerializeAsString)] 
    object Type { get; set; } 
} 

XmlMagic指System.Xml命名空间的XmlAttribute或其他部分,让我来控制的对象属性的类型被序列化(取决于我正在序列化的对象的版本)。

有谁知道如何做到这一点?

回答

0

我不清楚你想要什么,用IPost和Post等等。

看来你想更新你的web服务。您使用“版本”一词。我不清楚的是,外部接口正在发生什么变化。你没有描述过。

我们都同意服务的内部实现应该对服务的消费者不透明,对吗?因此,无论您是否更新了实施方案,该服务的客户都不应该知道。无论您使用IPost还是Post或IWhatever,客户都不会在乎,一定不会意识到。对服务消费者唯一重要的是线上签名 - 公共接口。 WSDL。

你已经说过你是不允许打破原来的WSDL。我不知道这意味着什么。这是否意味着

  • 新的服务必须使用相同的WSDL
  • 新的服务可以使用不同的WSDL,但老客户必须继续运行?
  • 别的东西?

通常,当人们版本的网络服务,他们的意思是改变这种坐上线发送的消息发言。

1版可能看起来像:

<Post xmlns="http://www.example.com/webservices/2010/04"> 
    <AuthorId>217</AuthorId> 
    <Posted>2010-04-07T22:02:23.2214747Z</Posted> 
    <Title>Hello, I must be going.</Title> 
    <Content>...</Content> 
    <Type>Rant</Type> 
</Post> 

为了保持兼容,版本2只能添加元素。例如,LastEdited元素添加到消息:

<Post xmlns="http://www.example.com/webservices/2010/04"> 
    <AuthorId>217</AuthorId> 
    <Posted>2010-04-07T22:02:23.2214747Z</Posted> 
    <LastEdited>2010-04-07T22:02:23.2214747Z</LastEdited> 
    <Title>This is Getting Very Interesting</Title> 
    <Content>...</Content> 
    <Type>Rant</Type> 
</Post> 

当我说兼容的,我的意思是版本1个文件像上面会去seriailzable由第2个服务。

你在做这样的事吗?如果是这样,详细说明。

你没有描述任何。您的描述仅关注服务的内部实施。您还没有提到任何关于外部可访问接口的信息,这是“版本化”服务时需要关注的主要方面。


如果你只是想办法一个属性序列化为一个字符串,该属性的类型没有合适的toString()实现,你可以使用代理属性。模式如下所示:用[XmlIgnore]标记实际属性。创建String类型的额外“代理”属性,并带有读取或更新实际属性的getter和setter。像这样:

[XmlRoot("Post", Namespace="http://www.example.com/webservices/2010/04")] 
public class Post1_1 
{ 
    public Int32 AuthorId { get; set; } 
    public DateTime Posted { get; set; } 
    public String Title { get; set; } 
    public PostType @Type { get; set; } 

    [XmlIgnore] 
    public DateTime LastEdited { get; set; } 

    [XmlElement("LastEdited")] 
    public String LastEdited_Surrogate 
    { 
     get 
     { 
      if (LastEdited > (DateTime.UtcNow - new TimeSpan(24,0,0))) 
       return "Today"; 
      else if (LastEdited > (DateTime.UtcNow - new TimeSpan(48,0,0))) 
       return "Yesterday"; 
      else 
       return LastEdited.ToString(); 
     } 

     set 
     { 
      if (value == "Today") 
       LastEdited = DateTime.UtcNow; 
      else if (value == "Yesterday") 
       LastEdited = DateTime.UtcNow - new TimeSpan(24,0,0); 
      else 
       LastEdited = DateTime.Parse(value); 
     } 
    } 
}