2010-04-06 2 views
1

У меня есть wsdl с стороннего сервера. Ran svcutil и закончил с наборомXmlSerializer Deserialize failures

XmlNode AMethod(object Request); 

методы. Существует отдельный 100-страничный pdf-файл, описывающий объекты ответа/запроса для каждого метода.

Моя мысль была обернута веб-методами и использует XmlSerializer для возврата строго типизированных объектов. Возвращенный xml выглядит так (я удалил заголовки мыла):

<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:type="ResponseExt" 
     xmlns="http://www.thirdparty.com/lr/"> 
    <Code>0</Code> 
    <Message>SUCCESS</Message> 
    <SessionId>session_token</SessionId> 
</Response> 

Посмотрел просто. Созданный класс (из документа/провод захватывает): время

[XmlRoot("Response")] 
//EDIT added XmlType 
[XmlType("ResponseExt", Namespace = "http://www.thirdparty.com/lr/")] 
public class MyClass { 
    public string Code {get; set;} 
    public string Message {get; set;} 
    public string SessionId {get; set;} 
} 

Обработки:

//XmlNode node = xml from above 
XmlSerializer serializer = new XmlSerializer(typeof(MyClass)); 
XmlNodeReader reader = new XmlNodeReader(node); 
Myclass myclass = serializer.Deserialize(reader) as MyClass 

Последняя линия, где она взрывается с внутренним сообщением исключения: Указанный тип не был признан: имя = 'ResponseExt', namespace = 'http://www.thirdparty.com/lr/', по адресу <Response xmlns=''>.
Я не могу понять, как сделать Serializer счастливым и что именно эти два означают

XSI: тип = "ResponseExt" XMLNS = "http://www.thirdparty.com/lr/

Как всегда любые советы и указатель оценены


EDIT:. Принимается ответ ниже

Я все еще получал исключение, пока я не нашел это, надеюсь, что это сэкономит какое-то время. Я начал работать назад. Захваченный xml на проводе. Дезерминирован для моих созданных классов с правильными атрибутами: работал как шарм. Пробовал снова из webservice - исключение. По какой-то причине XmlSerializer не распознает ResponseExt.

XmlSerializer serializer = new XmlSerializer(typeof(Response)); 
XmlNode node = (XmlNode)results[0]; 
XmlDocument doc = new XmlDocument(); 
doc.LoadXml(node.OuterXml); //reload node 
XmlNodeReader reader = new XmlNodeReader(doc.FirstChild); //there is only one node 
Response rsp = serializer.Deserialize(reader) as Response; //works 

EDIT: основная проблема wsdl-файл не был заполнен. Проведя 2 дня на этом и обнаружив это (уродливое) обходное решение, сторонний поставщик предоставил полный WSDL со всеми типами, которые десериализуются без ошибок.

+0

нормально, я обновил свой ответ после того, как вы обновили вопрос. – Cheeso

ответ

1

Почему вы вручную десериализируете XML, когда у вас есть WSDL?

Если у вас есть WSDL, используйте инструмент svcutil.exe или средство wsdl.exe для создания прокси-классов и DTO для отправки и приема XML-сообщений на проводе.

Пункт набора инструментов веб-сервисов, или «стек», должен предоставить это для вас, чтобы вам не пришлось самостоятельно создавать классы и код сериализации XML.

Вы попробовали? Вы пытались запустить WSDL через один из этих инструментов? Или вы пытались «Добавить веб-ссылку» в Visual Studio?


После обновления вопроса я предлагаю вам изменить WSDL, а не писать собственный код.Вы можете создать пользовательский WSDL для службы, который будет правильно генерировать классы прокси, которые вы хотите. Если вам не нужны все 100 методов (или сколько их есть), то оставьте их. Если вы хотите создать собственный объект из метода, тогда определите complexType, соответствующий этому объекту. Это намного проще и надежнее, чем ручной десериализационный код XML для каждого метода.


Если вам не нравится эта идея, и хотите придерживаться вручную пишешь код XML десериализации, то вам нужно сделать две вещи:

  1. присоединять a namespace to the XmlRoot attribute.

  2. измените название своего класса на ResponseExt и выведите его из класса под названием Response. Украсьте этот класс Response атрибутом XmlInclude. Это выравнивает использование the Xml Serializer with the xsi:type used in the XML fragment.

Он выглядит в коде:

[XmlRoot("Response", Namespace="http://www.thirdparty.com/lr/")] 
public class ResponseExt : Response { 
} 

[XmlRoot("Response", Namespace="http://www.thirdparty.com/lr/")] 
[XmlInclude(typeof(ResponseExt))] 
public class Response { 
    public string Code {get; set;} 
    public string Message {get; set;} 
    public string SessionId {get; set;} 
} 

public class XsiType 
{ 
    public static void Main(string[] args) 
    { 
     try 
     { 
      string filename = "XsiType.xml"; 
      XmlSerializer s1 = new XmlSerializer(typeof(Response)); 
      ResponseExt r = null; 
      using(System.IO.StreamReader reader= System.IO.File.OpenText(filename)) 
      { 
       r= (ResponseExt) s1.Deserialize(reader); 
      } 

      var builder = new System.Text.StringBuilder(); 
      var xmlws = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true }; 
      using (var writer = System.Xml.XmlWriter.Create(builder, xmlws)) 
      { 
       //s1.Serialize(writer, r, ns); 
       s1.Serialize(writer, r); 
      } 
      string xml = builder.ToString(); 
      System.Console.WriteLine(xml); 

     } 
     catch (System.Exception exc1) 
     { 
      Console.WriteLine("Exception: {0}", exc1.ToString()); 
     } 
    } 
} 

родственный: How can I force the use of an xsi:type attribute?

+0

Cheeso, я действительно запускал инструменты, к сожалению, wsdl не содержит информацию о запросе/ответе, все методы берут объект и возвращают XmlNode. Существует отдельный документ, описывающий каждый метод. Я уточнил вопрос, чтобы прояснить проблему. – smvlad

+0

Хорошо, я обновил свой ответ. – Cheeso

+0

обновил код с помощью пространств имен, переименовал классы. все тот же исключение – smvlad