2014-10-07 102 views
1

我想通過WebApi方法將XML反序列化爲對象。允許.NET WebApi忽略DOCTYPE聲明

我有下面的類:

[XmlRoot(IsNullable = false)] 
public class MyObject 
{ 
    [XmlElement("Name")] 
    public string Name {get;set;} 
} 

並在控制器的WebAPI下面的方法。

[HttpPost] 
public HttpResponseMessage UpdateMyObject(MyObject model) 
{ 
    //do something with the model 
} 

我現在用的是XmlSerializer通過設置Web項目的啓動如下:

config.Formatters.XmlFormatter.UseXmlSerializer = true; 

發帖時下面的XML中,model正確反序列化,我可以讀屬性的。

<?xml version="1.0" encoding="UTF-8"?> 
<MyObject> 
    <Name>HelloWorld</Name> 
</MyObject> 

然而,當我發佈的XML與DOCTYPE聲明,該model值是空的,看似不上法進入反序列化。即此XML不反序列化爲模型:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE MyObject SYSTEM "http://example.com/MyObject.dtd"> 
<MyObject> 
    <Name>HelloWorld</Name> 
</MyObject> 

希望有人能夠提供幫助。

回答

3

即使是舊的文章,我發現自己在同樣的情況。我最終寫了一個定製版本的XmlMediaTypeFormatter覆蓋了ReadFromStreamAsync方法。

這裏我個人的解決方案:

public class CustomXmlMediaTypeFormatter : XmlMediaTypeFormatter 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="CustomXmlMediaTypeFormatter"/> class. 
    /// This XmlMediaTypeFormatter will ignore the doctype while reading the provided stream. 
    /// </summary> 
    public CustomXmlMediaTypeFormatter() 
    { 
     UseXmlSerializer = true; 
    } 

    public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) 
    { 
     if (type == null) 
      throw new ArgumentNullException("type"); 
     if (readStream == null) 
      throw new ArgumentNullException("readStream"); 

     try 
     { 
      return Task.FromResult(ReadFromStream(type, readStream, content, formatterLogger)); 
     } 
     catch (Exception ex) 
     { 
      var completionSource = new TaskCompletionSource<object>(); 
      completionSource.SetException(ex); 
      return completionSource.Task; 
     } 

    } 

    private object ReadFromStream(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) 
    { 
     var httpContentHeaders = content == null ? (HttpContentHeaders)null : content.Headers; 
     if (httpContentHeaders != null) 
     { 
      var contentLength = httpContentHeaders.ContentLength; 
      if ((contentLength.GetValueOrDefault() != 0L ? 0 : (contentLength.HasValue ? 1 : 0)) != 0) 
       return GetDefaultValueForType(type); 
     } 

     var settings = new XmlReaderSettings 
     { 
      DtdProcessing = DtdProcessing.Ignore 
     }; 

     var deserializer = GetDeserializer(type, content); 
     try 
     { 
      // The standard XmlMediaTypeFormatter will get the encoding from the HttpContent, instead 
      // here the XmlReader will decide by itself according to the content 
      using (var xmlReader = XmlReader.Create(readStream, settings)) 
      { 
       var xmlSerializer = deserializer as XmlSerializer; 
       if (xmlSerializer != null) 
        return xmlSerializer.Deserialize(xmlReader); 

       var objectSerializer = deserializer as XmlObjectSerializer; 
       if (objectSerializer == null) 
        throw new InvalidOperationException("xml object deserializer not available"); 

       return objectSerializer.ReadObject(xmlReader); 
      } 
     } 
     catch (Exception ex) 
     { 
      if (formatterLogger == null) 
      { 
       throw; 
      } 

      formatterLogger.LogError(string.Empty, ex); 
      return GetDefaultValueForType(type); 
     } 
    } 
} 

那麼顯然我已經取代我的配置標準XmlFormatter

config.Formatters.Remove(config.Formatters.XmlFormatter); 
config.Formatters.Add(new CustomXmlMediaTypeFormatter()); 
+0

我一直在尋找解決方案,網上說避免了需要替換默認XmlFormatter,但我找不到任何解決方案,除了上述工作。這工作完全謝謝你的解決方案。 – 2017-01-05 21:15:23

0

我還沒有用DOCTYPE試過它,但是實現IXmlSerializable接口應該可以完全控制XmlSerializer的對象序列化。

IXmlSerializable Interface