【问题标题】:Attribute not included in the generated proxy class生成的代理类中不包含属性
【发布时间】:2008-10-01 19:44:44
【问题描述】:

使用 .Net 3.0 和 VS2005。

相关对象从 WCF 服务中使用,然后序列化回 XML 以用于旧版 API。因此,不是序列化 TestObject,而是序列化缺少 [XmlRoot] 属性的 .TestObject;但是,子元素的所有 [Xml*] 属性都在生成的代理代码中,因此它们工作得很好。所以所有子元素都可以正常工作,但封闭元素却没有,因为 [XmlRoot] 属性未包含在生成的代理代码中。包含 [XmlRoot] 属性的原始对象可以手动序列化。

我可以让代理代码包含 [XmlRoot] 属性,以便生成的代理类也正确序列化吗?如果我不能这样做,我怀疑我将不得不使用 [XmlType]但这会造成轻微的破坏,需要我更改其他组件,所以我更喜欢前者。我还想避免手动编辑自动生成的代理类。

这是一些示例代码(我将客户端和服务包含在同一个应用程序中,因为这既快速又用于测试目的。注释掉服务引用代码并在运行应用程序时添加服务引用,然后取消注释服务代码并运行。)

namespace SerializationTest {  
  class Program {  
    static void Main( string[] args ) {  

        Type serviceType = typeof( TestService );  
        using (ServiceHost host = new ServiceHost(   
            serviceType,   
            new Uri[] {   
                new Uri( "http://localhost:8080/" )  
            }  

        ))
        {

            ServiceMetadataBehavior behaviour = new ServiceMetadataBehavior();  
            behaviour.HttpGetEnabled = true;  
            host.Description.Behaviors.Add( behaviour );  

            host.AddServiceEndpoint( serviceType, new BasicHttpBinding(), "TestService" );  
            host.AddServiceEndpoint( typeof( IMetadataExchange ), new BasicHttpBinding(), "MEX" );  


            host.Open();  

            TestServiceClient client = new TestServiceClient();  
            localhost.TestObject to = client.GetObject();  

            String XmlizedString = null;  
            using (MemoryStream memoryStream = new MemoryStream()) {
                XmlSerializer xs = new XmlSerializer( typeof( localhost.TestObject ) );  
                using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream)) {
                    xs.Serialize( xmlWriter, to );  
                    memoryStream = (MemoryStream)xmlWriter.BaseStream;  
                    XmlizedString = Encoding.UTF8.GetString( memoryStream.ToArray() );  
                    Console.WriteLine( XmlizedString );  
                }    
            }    
        }

        Console.ReadKey();  
    }  
}  

[Serializable]  
[XmlRoot( "SomethingElse" )]  
public class TestObject {  

    private bool _worked;  

    public TestObject() { Worked = true; }  

    [XmlAttribute( AttributeName = "AttributeWorked" )]  
    public bool Worked {  
        get { return _worked; }  
        set { _worked = value; }  
    }  
}  

[ServiceContract]  
public class TestService {  

    [OperationContract]  
    [XmlSerializerFormat]  
    public TestObject GetObject() {  
        return new TestObject();  
    }  
  }  
}  

这是生成的 Xml。

<?xml version="1.0" encoding="utf-8"?>
<TestObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" AttributeWorked="true" /> 

【问题讨论】:

  • 您是否控制用于生成代理的 xsd 架构?
  • 我对没有生成 XmlRoot 并不感到惊讶。我觉得奇怪的是生成的类不称为“SomethingElse”。添加 XmlRoot 属性后是否生成了代理?
  • 我相信重点是避免修改架构/生成的代理。只需使用它们接收,然后转身再次发送到遗留端。但是最好避免编写一组新的定义 - 因此希望即时重命名。我建议使用 XmlAttributeOverrides。

标签: c# xml wcf xml-serialization


【解决方案1】:

== IF ==

这仅适用于XmlRoot 属性。 XmlSerializer 有一个构造函数,您可以在其中指定 XmlRoot 属性。

感谢 csgero 指出它。他的评论应该是解决方案。

XmlSerializer Constructor (Type, XmlRootAttribute)

初始化一个新的实例 XmlSerializer 可以序列化的类 将指定类型的对象转换为 XML 文档,并反序列化 XML 文档到指定的对象 类型。它还指定类 用作 XML 根元素。

【讨论】:

  • 不是一个好的构造函数。生成的 Xml 序列化程序程序集未缓存。
【解决方案2】:

我找到了提供解决这种情况的方法的人:

Matevz Gacnik's Weblog

使用XmlAttributeOverrides的方法,我写了以下内容:

    private static XmlSerializer GetOverridedSerializer()
    {
        // set overrides for TestObject element
        XmlAttributes attrsTestObject = new XmlAttributes();
        XmlRootAttribute rootTestObject = new XmlRootAttribute("SomethingElse");
        attrsTestObject.XmlRoot = rootTestObject;

       // create overrider
       XmlAttributeOverrides xOver = new XmlAttributeOverrides();
       xOver.Add(typeof(localhost.TestObject), attrsTestObject);

       XmlSerializer xSer = new XmlSerializer(typeof(localhost.TestObject), xOver);
       return xSer;
    }

只需将该方法放在您示例的Program 类中,并在Main() 中替换以下行:

        //XmlSerializer xs = new XmlSerializer(typeof(localhost.TestObject));
        XmlSerializer xs = GetOverridedSerializer();

然后运行看看结果。

这是我得到的:

<?xml version="1.0" encoding="utf-8"?><SomethingElse xmlns:xsi="http://www.w3.o
rg/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Attribu
teWorked="true" />

【讨论】:

  • 我认为问题不在于使用 XmlSerializer,而在于为代理生成的代码。在实际场景中,XML 序列化将由 WCF 处理,因此您对正在使用的 XmlSerializer 没有直接影响。
  • 对。但重点是能够重新调整数据合约的用途,而无需对其进行物理修改(无论是通过重新生成还是手动编辑),因此不会干扰将其与 WCF 一起使用的初衷。
  • 对不起,你是对的,我没有抓住重点。还有一个更简单的解决方案,使用带有 XmlRootAttribute 参数的 XmlSerializer 构造函数。
  • 对于我的问题,这些覆盖太常见了,所以我认为这个解决方案不是我想要的。我还认为,当我们切换到 2008 年并开始共享类型时,它就不再重要了。因此,即使我没有使用它,我也会将其标记为答案。
猜你喜欢
  • 1970-01-01
  • 2017-12-11
  • 2020-05-22
  • 1970-01-01
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 2013-10-08
  • 2021-03-03
相关资源
最近更新 更多