c# Web Api - 所有 api 响应的通用包装器类

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

几天以来,我一直在尝试弄清楚如何从我的 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);
    }
}

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

在我看来,这两种方法没有区别,除了第一种情况我们得到匿名类型,第二种情况我们使用对象。

那么问题是:

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

最佳答案

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

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

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

正如 MDN 引用的:( LINK )

The HTTP response codes should be used properly for e.g. HTTP response status codes indicate whether a specific HTTP request has been successfully completed. Responses are grouped into five classes:

  • 信息回复 (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表示错误被全局异常处理器捕获。

关于c# Web Api - 所有 api 响应的通用包装器类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47001587/

相关文章:

c# - 为什么 typeof(Child<>).BaseType.IsGenericTypeDefinition 是假的?

asp.net - 在 ASP.NET 中自定义授权作为过滤器或在 Controller 的构造函数中?

wcf - 我可以结合使用 WCF 和 WebApi 吗?

c# - 我如何在 C# 中使用 XNA 来减少碰撞时的生命周期?

c# - 类型转换器因原始类型而损坏?

c# - linq2entities 的 IQueryable 扩展方法

c# - PasswordHasher 方法的用户参数有什么用?

c# - .OrderBy 函数的 System.Linq.Expressions.Expression

c# - 从泛型类返回一个单例

c# - 使用单个身份验证层对多个 WebAPI 进行身份验证