我正在开发一个Web API,其中GET方法需要返回一个对象,该对象的变量将基于XML文件确定。根据客户端要求,返回的格式必须为XML或JSON。我想将XML文件中的数据以XML格式返回给客户端,并在请求JSON时将其用于JSON。
XML中的节点可能增加或减少,因此 我无法在模型中定义固定的类 。我当前的解决方案是返回一个动态对象,但是下面显示了一个异常。我该怎么做才能避免出现异常情况?
获取Api
[AllowAnonymous]
public class DataController : ApiController
{
//GET api/----based on dynamic binding
public object Get()
{
//Read XML
XDocument xDoc = XDocument.Load(@"D:\data.xml");
string jsonStr = JsonConvert.SerializeXNode(xDoc);
dynamic dynamicObject = JsonConvert.DeserializeObject<ExpandoObject>(jsonStr);
return dynamicObject; //THIS LINE IS THROWING RUNTIME ERROR
}
}
示例XML文件:
<Data>
<Name>abcd</Name>
<bad>100</bad>
<status>running</status>
</Data>
当我尝试访问GET API时,网页上会出现以下错误:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'System.Dynamic.ExpandoObject' with data contract name 'ArrayOfKeyValueOfstringanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.
</ExceptionMessage>
<ExceptionType>
System.Runtime.Serialization.SerializationException
</ExceptionType>
<StackTrace>
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()
</StackTrace>
</InnerException>
</Error>
答案 0 :(得分:0)
出现此错误的原因是,您已经声明了要返回类型object
的对象的方法-但实际上已经返回了多态子类型,即ExpandoObject
。由于DataContractSerializer
(和XmlSerializer
)将拒绝序列化意外的多态类型,因此它们会引发您所看到的异常。有关详细信息,请参见
话虽如此,我想提出一种不同的,更简单的方法。首先,定义您的Get()
方法以显式返回XElement
,如下所示:
public XElement Get()
{
//Read XML
XDocument xDoc = XDocument.Load(@"D:\data.xml");
return xDoc.Root;
}
DataContractSerializer
(和XmlSerializer
)都可以序列化此类型的对象(因为implements IXmlSerializable
),因此您的方法现在将成功返回文件{{1 }}按原样请求XML。
现在,请求JSON时该怎么办?事实证明,Json.NET具有内置的转换器XmlNodeConverter
,可以将"D:\data.xml"
与JSON进行串行化。 XElement
在内部使用它,但是它是公共的,因此可以直接使用。因此,如果您将转换器添加到JsonSerializerSettings.Converters
中的转换器的全局Web API列表中,您的方法现在也应该返回适用于JSON的内容。
您未指定所使用的Web API版本。要全局添加转换器,请参见
ASP.NET Web API 2:另请参见 How to set custom JsonSerializerSettings for Json.NET in MVC 4 Web API? 和this answer到 Registering a custom JsonConverter globally in Json.Net 的第二部分。在这种情况下,您的代码将类似于:
JsonConvert.SerializeXNode()
ASP.NET Core MVC:请参见 JsonSerializerSettings and Asp.Net Core 或 Setting JsonConvert.DefaultSettings asp net core 2.0 not working as expected 。再次在这里,您将访问全局protected void Application_Start()
{
var config = GlobalConfiguration.Configuration;
var settings = config.Formatters.JsonFormatter.SerializerSettings;
settings.Converters.Add(new XmlNodeConverter());
}
并添加一个JsonSerializerSettings
,如上所示。