问题描述
我正在尝试通过WebApi方法将XML反序列化为对象.
I am trying to deserialize XML to an object through a WebApi Method.
我有以下课程:
[XmlRoot(IsNullable = false)]
public class MyObject
{
[XmlElement("Name")]
public string Name {get;set;}
}
以及WebApi控制器中的以下方法.
And the following Method in a WebApi Controller.
[HttpPost]
public HttpResponseMessage UpdateMyObject(MyObject model)
{
//do something with the model
}
我通过在Web项目的启动中设置以下内容来使用XmlSerializer
:
I am using the XmlSerializer
by setting the following in the startup of the Web Project:
config.Formatters.XmlFormatter.UseXmlSerializer = true;
当我发布以下XML时,model
已正确反序列化,并且我可以读取其属性.
When I POST the following XML, the model
is correctly deserialized, and I can read the properties of it.
<?xml version="1.0" encoding="UTF-8"?>
<MyObject>
<Name>HelloWorld</Name>
</MyObject>
但是,当我使用DOCTYPE声明发布XML时,model
值为null,并且似乎在方法输入时未反序列化. IE.该XML不会反序列化为模型:
However, when I POST the XML with a DOCTYPE declaration, the model
value is null and seemingly not being deserialized on method-entry. I.e. this XML does not deserialize to a model:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE MyObject SYSTEM "http://example.com/MyObject.dtd">
<MyObject>
<Name>HelloWorld</Name>
</MyObject>
希望有人能够提供帮助.
Hope someone is able to help.
推荐答案
即使是旧帖子,我也遇到了同样的情况.我最后写了一个自定义版本的 XmlMediaTypeFormatter ,该版本覆盖了 ReadFromStreamAsync 方法.
Even if is an old post, I found myself in the same situation. I ended up in writing a customized version of the XmlMediaTypeFormatter overriding the ReadFromStreamAsync method.
这是我的个人解决方案:
Here my personal solution:
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 :
Then obviously I've replaced the standard XmlFormatter of my configuration:
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.Add(new CustomXmlMediaTypeFormatter());
这篇关于允许.NET WebApi忽略DOCTYPE声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!