从包含集合的InvalidOperationException
创建错误响应时,有没有办法绕过HttpError
?
似乎只有在将响应序列化为XML时才会出现,序列化为JSON的工作绝对正常。
问题似乎与HttpError存储要在Dictionary<string, object>
中序列化的数据有关。如果我添加一个自定义类(FieldError
)的数组,那么它就不会正确地将其序列化为XML。但是,当我直接使用属性为FieldError
类的数组的类直接序列化时,数组会正确地序列化为XML。
有没有什么方法可以让集合作为HTTP错误的一部分进行序列化?
抛出异常时得到的完整响应是:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>The 'ObjectContent`1' type failed to serialize the response body for content type 'text/xml; charset=utf-8'.</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace />
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>Xml type 'xdt:untypedAtomic' does not support a conversion from Clr type 'FieldError' to Clr type 'String'.</ExceptionMessage>
<ExceptionType>System.InvalidCastException</ExceptionType>
<StackTrace>at System.Xml.Schema.XmlUntypedConverter.ChangeListType(Object value, Type destinationType, IXmlNamespaceResolver nsResolver)
at System.Xml.Schema.XmlUntypedConverter.ChangeTypeWildcardDestination(Object value, Type destinationType, IXmlNamespaceResolver nsResolver)
at System.Xml.Schema.XmlUntypedConverter.ToString(Object value, IXmlNamespaceResolver nsResolver)
at System.Xml.Schema.XmlListConverter.ListAsString(IEnumerable list, IXmlNamespaceResolver nsResolver)
at System.Xml.Schema.XmlListConverter.ChangeListType(Object value, Type destinationType, IXmlNamespaceResolver nsResolver)
at System.Xml.Schema.XmlUntypedConverter.ChangeListType(Object value, Type destinationType, IXmlNamespaceResolver nsResolver)
at System.Xml.Schema.XmlUntypedConverter.ChangeTypeWildcardDestination(Object value, Type destinationType, IXmlNamespaceResolver nsResolver)
at System.Xml.Schema.XmlUntypedConverter.ToString(Object value, IXmlNamespaceResolver nsResolver)
at System.Xml.XmlWriter.WriteValue(Object value)
at System.Web.Http.HttpError.System.Xml.Serialization.IXmlSerializable.WriteXml(XmlWriter writer)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteIXmlSerializable(XmlWriterDelegator xmlWriter, Object obj, XmlSerializableWriter xmlSerializableWriter)
at System.Runtime.Serialization.XmlDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
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.Runtime.CompilerServices.TaskAwaiter.GetResult()
at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()
</StackTrace>
</InnerException>
</Error>
我将web api设置为通过JSON和XML序列化响应:
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter { SerializerSettings = { NullValueHandling = NullValueHandling.Ignore } });
config.Formatters.Add(new XmlMediaTypeFormatter { UseXmlSerializer = false });
我有一个ExceptionFilterAttribute
可将我的API引发的任何自定义异常转换为HttpError
并返回错误响应:
public override void OnException(HttpActionExecutedContext context)
{
var apiException = context.Exception as ApiException;
if (apiException != null)
{
context.Response = context.Request.CreateErrorResponse((HttpStatusCode)apiException.ReasonCode, apiException.ToHttpError());
return;
}
base.OnException(context);
}
我的自定义API异常的基类转换为HttpErrors,如下所示:
internal virtual HttpError ToHttpError()
{
var httpError = new HttpError(this.Message) { { "ExceptionType", this.TypeName } };
var innerApiError = this.InnerException as ApiException;
if (innerApiError != null)
{
httpError.Add("InnerError", innerApiError.ToHttpError());
}
else if (this.InnerException != null)
{
httpError.Add("InnerError", new HttpError(this.InnerException.Message) { { "ExceptionType", this.InnerException.GetType().Name } });
}
return httpError;
}
然后我有一个派生异常类,其数组重载ToHttpError
:
public FieldError[] Errors { get; private set; }
internal override HttpError ToHttpError()
{
var error = base.ToHttpError();
error.Add("Errors", this.Errors);
return error;
}
FieldErrors
属性是一个填充数组,FieldError
类声明为:
[DataContract(Namespace = "")]
public class FieldError
{
[DataMember]
public string Field
{
get;
set;
}
[DataMember]
public string Error
{
get;
set;
}
[IgnoreDataMember]
public ApiErrorTypes ErrorType
{
get;
set;
}
}
当我告诉API返回JSON时,我得到的响应是:
{
"Message":"The supplied parameters are invalid.",
"ExceptionType":"InvalidRequestDataException",
"Errors":[
{
"Field":"CollectionDate",
"Error":"Collection date is not in a valid date format"
}
]
}
答案 0 :(得分:0)
我找到解决此问题的唯一方法是创建一个使用DataContract
的新类,并调用context.Request.CreateResponse()
来创建响应,而不是使用HttpError
和context.Request.CreateErrorResponse()