返回动态对象会引发运行时错误 [英] Returning a dynamic object is throwing runtime error

查看:60
本文介绍了返回动态对象会引发运行时错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个Web API,其中GET方法需要返回一个对象,该对象的变量将基于XML文件确定.根据客户端要求,返回的格式必须为XML或JSON.我想将XML文件中的数据以XML格式返回给客户端,并且当请求JSON时对JSON来说是合理的.

I am developing a Web API, where the GET method needs to return an object, whose variables will be decided based on an XML file. The returned format must be either XML or JSON as requested by the client. I want to return the data inside XML file into XML format to the client, and something reasonable for JSON when JSON is requested.

XML中的节点可能会增加或减少,因此 我无法在模型中定义固定的类 .我当前的解决方案是返回一个动态对象,但是下面显示了一个异常.我该怎么做才能避免出现异常情况?

The nodes in the XML might increase or decrease and therefore I cannot define a fixed class in the Models. My current solution is to return a dynamic object, but I am getting an exception shown below. What can I do to avoid the exception?

获取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时,网页上会出现以下错误:

When I try to access the GET api, the following error appears on the web page:

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

推荐答案

出现此错误的原因是,您已声明您的方法以返回 object 类型的对象-但包含事实返回了一个多态子类型,即 ExpandoObject .由于 DataContractSerializer (和 XmlSerializer )将拒绝序列化意外的多态类型,因此它们会引发您所看到的异常.有关详细信息,请参见

The reason you are getting that error is that you have declared your method to return an object of type object -- but have in fact returned a polymorphic subtype, namely ExpandoObject. Since DataContractSerializer (and XmlSerializer) will refuse to serialize unexpected polymorphic types, they throw the exception you are seeing. For details see

话虽如此,我想提出一种不同的,更简单的方法.首先,定义您的 Get()方法以显式返回 XElement ,如下所示:

That being said, I'd like to suggest a different, simpler approach. First, define your Get() method to explicitly return an XElement like so:

public XElement Get()
{
    //Read XML
    XDocument xDoc = XDocument.Load(@"D:\data.xml");
    return xDoc.Root;
}

DataContractSerializer (和 XmlSerializer )都能够序列化此类型的对象(因为它的内容.

DataContractSerializer (and XmlSerializer) are both able to serialize an object of this type (since it implements IXmlSerializable), so your method will now successfully return contents of the file "D:\data.xml" verbatim when XML is requested.

现在,请求JSON时该怎么办?事实证明,Json.NET具有内置转换器 <代码> XmlNodeConverter 可以将 XElement 与JSON序列化.它由 JsonConvert.SerializeXNode()内部使用,但是是公共的,因此可以直接使用.因此,如果您将转换器添加到 中的转换器的全局Web API列表中JsonSerializerSettings.Converters ,您的方法现在也应该返回适​​用于JSON的内容.

Now, what to do when JSON is requested? As it turns out, Json.NET has a built-in converter XmlNodeConverter that can serialize an XElement to and from JSON. It's used internally by JsonConvert.SerializeXNode() but is public and so can be used directly. Thus if you add the converter to your global Web API list of converters in JsonSerializerSettings.Converters, your method should now return something reasonable for JSON as well.

您未指定所使用的Web API版本.要全局添加转换器,请参见

You don't specify which version of Web API you are using. To add a converter globally, see

  • ASP.NET Web API 2: See How to set custom JsonSerializerSettings for Json.NET in MVC 4 Web API? and also the second part of this answer to Registering a custom JsonConverter globally in Json.Net. In this scenario your code would look something like:

protected void Application_Start()
{
    var config = GlobalConfiguration.Configuration;
    var settings = config.Formatters.JsonFormatter.SerializerSettings;
    settings.Converters.Add(new XmlNodeConverter());
}

  • ASP.NET Core MVC:请参见 JsonSerializerSettings和Asp.Net Core 设置JsonConvert.DefaultSettings asp net core 2.0无法正常工作 .再次在这里,您将访问全局 JsonSerializerSettings 并添加一个 XmlNodeConverter ,如上所示.

  • ASP.NET Core MVC: see JsonSerializerSettings and Asp.Net Core or Setting JsonConvert.DefaultSettings asp net core 2.0 not working as expected. Here again you would access the global JsonSerializerSettings and add an XmlNodeConverter as shown above.

    这篇关于返回动态对象会引发运行时错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆