返回动态对象会引发运行时错误

时间:2018-10-08 09:12:26

标签: c# asp.net serialization deserialization xml-serialization

我正在开发一个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>

1 个答案:

答案 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版本。要全局添加转换器,请参见