C# Web Api - 通用的API响应包装器类

4

最近几天我一直在尝试解决如何从我的Web API通用响应中返回一个包装类,其中一个属性将具有动态指向的类型。

下面的代码片段展示了我的目标:

[RoutePrefix("api")]
public class TestController : ApiController
{
    [HttpGet]
    [Route("test")]
    public HttpResponseMessage Test3()
    {
        Smth smth = new Smth()
        {
            Something = "dsfdsfdsfs"
        };

        object apiResponse = this.GetResponse(true, smth);

        return base.Request.CreateResponse(HttpStatusCode.OK, apiResponse);
    }

    public object GetResponse(bool isSuccess, dynamic responseObject, string[] messages = null)
    {
        return new
        {
            is_success = isSuccess,
            response_object = responseObject,
            messages = messages
        };
    }
}

很不幸,这种方法行不通 - 我仍然会得到以下错误信息:
异常消息
无法对类型进行序列化<> f__AnonymousType0`3 [System.Boolean,System.Object,System.String []] ...
异常类型
System.Runtime.Serialization.InvalidDataContractException
堆栈跟踪

System.Runtime.Serialization.DataContract.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type) w System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type) w System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type) w System.Runtime.Serialization.DataContractSerializer.GetDataContract(DataContract declaredTypeContract, Type declaredType, Type objectType) w System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) w System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) w System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) w System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph) w System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content) w System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) --- Koniec śladu stosu z poprzedniej lokalizacji, w której wystąpił wyjątek --- w System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) w System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) w System.Net.Http.HttpContent.d__49.MoveNext() --- Koniec śladu stosu z poprzedniej lokalizacji, w której wystąpił wyjątek --- w System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) w System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) w System.Web.Http.Owin.HttpMessageHandlerAdapter.d__13.MoveNext()
在我的研究中,我在论坛上找到了一些工作良好的示例:
[RoutePrefix("api")]
public class TestController : ApiController
{
    [HttpGet]
    [Route("test")]
    public HttpResponseMessage Test3()
    {
        Smth smth = new Smth()
        {
            Something = "dsfdsfdsfs"
        };

        var apiReponse = new
        {
            is_success = true,
            response_object = smth,
            messages = new string[] { "dsfsfdds" }
        };

        return base.Request.CreateResponse(HttpStatusCode.OK, apiReponse);
    }
}

上面的例子可以正常工作并返回格式正确的数据,但这种方法会导致与命名相关的错误(因为每次返回数据时都必须指定响应结构)。
在我看来,这两种方法没有区别,除了第一种情况下我们获得匿名类型,而第二种情况下我们使用对象。
所以问题是:
我的第一种方法是否可行?

你得到了什么错误? - derloopkat
我添加了异常详细信息,但我截断了异常消息的片段 - 它不是英文 :) - Piotr Kwiatkowski
2
尝试使用json将动态对象序列化为字符串。如果失败了,就将整个该死的东西序列化。 - Kell
2个回答

3
注意:虽然这不是你问题的答案,但我想发表一下意见,以免误导其他人。
我强烈建议在所有情况下都使用200(OK)响应并非合适的RESTful做法。
如果即使在错误的情况下,响应代码始终为200(OK),那么客户端必须检查每个响应的“is_success = true”。
正如MDN引用的话:(链接) HTTP响应代码应该被正确使用,例如,HTTP响应状态码表示特定的HTTP请求是否已成功完成。响应被分为五类:
1.信息响应(100-199) 2.成功响应(200-299) 3.重定向(300-399) 4.客户端错误(400-499) 5.服务器错误(500-599)
例如,
- 如果请求包含无效数据或不包含所需字段,则应返回400(Bad Request)。 - 如果服务器出现意外错误,则使用500(Internal Server Error)。 - 如果在服务器上创建新资源,则使用201(Created)。
我还建议阅读有关正确使用HTTP方法的文章。 (链接)
至于通用响应,可以在成功响应中返回以下内容:(这完全是我的结构,可能不是最佳实践)
{
    ResponseCode:1,
    Message:"User created",
    Data:{//Any complex object
         purchases:[
            {data 1},
            {data 2}
          ]
       },
    Exception:null
}

若服务器出现错误(仅用于开发):

{
    ResponseCode:2,
    Message:"Caught in Global exception filter",
    Data:null,
    Exception: {//Do not send this in production
        Message: "An error has occurred.",
        ExceptionMessage:,
        ExceptionType":,
        StackTrace: ,
        InnerException: {
     }
   }
}

这里的ResponseCode是您自定义的代码,可用于更详细地描述问题,例如在上面的示例中,ResponseCode:2表示错误被全局异常处理程序捕获。


1
基本上,将对象序列化为字符串的JSON表示形式,并返回内容类型为“application/json”的结果。
Smth smth = new Smth()
{
    Something = "dsfdsfdsfs"
};
var serializer = new JavaScriptSerializer();
string json = serializer.Serialize(this.GetResponse(true, smth));
var response = this.Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(json, Encoding.UTF8, "application/json");
return response;

返回
{"is_success":true,"response_object":{"Something":"dsfdsfdsfs"},"messages":null}

我没有这样想过问题。谢谢! - Piotr Kwiatkowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接