Skip to main content
 首页 » 编程设计

c#之允许 .NET WebApi 忽略 DOCTYPE 声明

2024年02月01日26jiqing9006

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

我有以下类(class):

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

以及 WebApi Controller 中的以下方法。

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

我通过在 Web 项目的启动中设置以下内容来使用 XmlSerializer:

config.Formatters.XmlFormatter.UseXmlSerializer = true; 

当我发布以下 XML 时,模型 被正确反序列化,我可以读取它的属性。

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

但是,当我使用 DOCTYPE 声明 POST 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> 

希望有人能够提供帮助。

请您参考如下方法:

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