【问题标题】:c# Web Api - generic wrapper class for all api responsesc# Web Api - 所有 api 响应的通用包装类
【发布时间】:2018-04-10 15:01:42
【问题描述】:

几天以来,我一直在试图弄清楚如何从我的 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(字符串 消息,类型类型)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 声明类型合同,类型声明类型,类型对象类型)w System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer,对象图,DataContractResolver dataContractResolver) w System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer,对象图,DataContractResolver dataContractResolver) w System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer,对象图,DataContractResolver dataContractResolver) w System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter 作家,对象图)w System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(类型 类型、对象值、流 writeStream、HttpContent 内容)w System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(类型 类型、对象值、流 writeStream、HttpContent 内容、 TransportContext transportContext, CancellationToken cancelToken) --- Koniec śladu stosu z poprzedniej lokalizacji, w której wystąpił wyjątek --- w System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)w System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)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(任务 任务)w System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)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);
    }
}

上面的例子可以正常工作并返回格式正确的数据,但这种方法会导致与命名相关的错误(这样我每次返回时都必须指定响应结构)。

在我看来,这两种方法没有区别,只是在第一种情况下我们获得匿名类型,而在第二种情况下我们使用对象。

所以问题是:

我的第一种方法是否可行?

【问题讨论】:

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

标签: c# generics asp.net-web-api dynamic wrapper


【解决方案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}

【讨论】:

  • 我没有这样考虑问题。谢谢!
【解决方案2】:

注意:虽然这不是您问题的答案,但我想发表评论,以免其他人被误导。

我强烈建议对每个场景都使用 200(OK)响应是不合适的和 RESTful 的。

如果响应代码始终为 200(OK),即使出现错误,客户端也必须检查每个响应的 is_success = true,

正如 MDN 引用的那样:(LINK)

应正确使用 HTTP 响应代码,例如HTTP 响应 状态码指示特定的 HTTP 请求是否已被 成功完成。响应分为五类:

  • 信息响应 (100–199)
  • 成功响应 (200–299)
  • 重定向 (300–399)
  • 客户端错误 (400–499)
  • 服务器错误 (500–599)

例如,

  • 如果请求包含无效数据或不包含所需的 您应该返回 400(错误请求)的字段。
  • 如果服务器出现意外错误,则使用 500(内部服务器错误)
  • 如果在服务器上创建了新资源,则使用 201(已创建)

我还建议阅读有关正确使用 HTTP 方法的信息。 (LINK)

至于一般响应,您可以在成功响应中返回如下内容:(这完全是我的结构,可能不是最佳实践)

{
    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 表示错误在全局异常处理程序中被捕获。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-24
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    • 2020-06-23
    相关资源
    最近更新 更多