【问题标题】:Allow .NET WebApi to disregard DOCTYPE declaration允许 .NET WebApi 忽略 DOCTYPE 声明
【发布时间】:2014-10-07 04:03:40
【问题描述】:

我正在尝试通过 WebApi 方法将 XML 反序列化为对象。

我有以下课程:

[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>

但是,当我发布带有 DOCTYPE 声明的 XML 时,model 值为 null,并且似乎没有在方法条目上反序列化。 IE。此 XML 不会反序列化为模型:

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

希望有人能够提供帮助。

【问题讨论】:

    标签: c# xml asp.net-web-api xml-serialization asp.net-web-api2


    【解决方案1】:

    即使是旧帖子,我也发现自己处于同样的境地。我最终编写了一个自定义版本的 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());
    

    【讨论】:

    • 我在网上寻找避免需要替换默认 XmlFormatter 的解决方案,但我找不到除上述之外的任何解决方案。这非常有效,感谢您的解决方案。
    【解决方案2】:

    我没有尝试使用 DOCTYPE,但实现 IXmlSerializable 接口应该可以让您完全控制 XmlSerializer 的对象序列化。

    IXmlSerializable Interface

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-21
      • 1970-01-01
      • 2015-03-19
      相关资源
      最近更新 更多