【问题标题】:Add fields to web api return object向 web api 返回对象添加字段
【发布时间】:2016-03-23 15:37:43
【问题描述】:

在控制器中,我曾经像这样返回 json:

[System.Web.Http.HttpGet]

    public JsonResult GetData()
    {
     return Json(new { success = true, msg = "", result = myObject},   JsonRequestBehavior.AllowGet);
    }

由于 extjs 期望成功消息作为 json 的一部分,因此我必须将其添加到每个响应中,并将包含我通常添加到结果中的所有数据的对象添加到结果中。

现在我有了 web api。在这里,您必须将某些方法的返回类型定义为对象,并且基于接受标头,结果将是 json 或 xml(我遇到了很多问题,因为 IE 不发送此标头并且我总是将 xml 作为返回 - 但我解决了此配置格式化程序添加):

public myObject GetData(){
    ...
    return myObject;
}

它有效。但是现在没有 {success = true, msg = ""} 作为返回 json 的一部分。 如何添加它以与控制器相同的方式返回? (不创建自定义 HttpContent 类,因为它是丑陋的解决方法)。

最后,使用 web api 而不使用 mvc 控制器——旧方式有什么意义吗? 接受标头存在问题,更难测试(我必须模拟 ajax 调用,而控制器只有要调用的 url),而且似乎获得适当的 json 需要更多的工作。 正如我所见,web api 的唯一好处是根据接受标头对客户端进行不同的序列化,但实际上除了 json 之外不需要获取其他数据(至少我不需要它)。那么,为什么不使用 mvc 控制器来代替 web api 呢?

【问题讨论】:

    标签: json asp.net-mvc asp.net-web-api


    【解决方案1】:

    您可以创建一个类为ResultBase,如下所示

    class ResultBase<T> {
     public bool success {get;set;}
     public string msg {get;set;}
     public T result {get;set;}
    }
    

    然后更改您的控制器代码如下

    public ResultBase<MyObject> GetData(){
        ...
        return new ResultBase<MyObject>{success = true, msg = "", result = myObject};
    }
    

    【讨论】:

    • 谢谢。这正是我想要的。
    • @Simon 很高兴它对您有所帮助,是否会将我的帖子标记为正确答案?
    【解决方案2】:

    Web api 设计为在发生故障时返回 Http 状态代码。然后,您可以在响应中包含该消息。还有here is a list of possible status codes,您可以发回。对于更常见的响应原因,有内置方法。因此,您的 Web Api 方法最终看起来像这样(请参阅下面的代码示例)。现在调用客户端将知道是否收到状态 200(默认为 Ok),然后服务器上的所有内容都已正确处理,否则处理 Http 状态代码并对消息或响应对象执行某些操作。

    此模式将使您不必在所有回复中添加successmessage 属性。它还允许您使用操作过滤器捕获一些常见的验证,例如使用 Authorize 过滤器属性的授权检查。

    [HttpGet]
    public IHttpActionResult GetData()
    {
        try {
            object somethingToReturn;
            // do something to populate your result
            return Ok(somethingToReturn);
        } 
        catch(SomeDataException someException){
            // log or do something
            return BadRequest("The object A could not be found with these parameters!");
        }
        catch(Exception totallyUnexpectedException){
            // log or do something
            return InternalServerError();
        }
    }
    

    那么,为什么不使用 mvc 控制器而不是 web api 呢?

    以前有人问过这个问题,请参阅这些 SO 帖子


    编辑

    基于最新评论。下面是一些代码,您可以使用它们来动态创建通用响应对象,而无需手动包装所有内容。通过创建一些扩展方法,您可以将响应包装器抽象为一些辅助方法。

    public class TestController : ApiController
    {
        [HttpGet]
        public IHttpActionResult Get()
        {
            var success = false;
            try
            {
                var someResult = new SomeObject() {Name = "igor"};
                // do something
                if (success)
                    return this.Ok(new SomeObject() {Name = "igor"}); // sends success
                return this.Failure(someResult, "some known error"); // sends failure with partial object (if possible)
            }
            catch (Exception ex)
            {
                return this.Failure("Something bad happened"); // sends failure with no object because you could not create it
            }
        }
    }
    
    public static class ApiControllerExtensions
    {
        public static OkNegotiatedContentResult<ResultWrapper<T>> Ok<T>(this ApiController controller, T content)
        {
            return new OkNegotiatedContentResult<ResultWrapper<T>>(new ResultWrapper<T>() { Result = content, Success = true, Message = null }, controller);
        }
        public static OkNegotiatedContentResult<ResultWrapper<T>> Failure<T>(this ApiController controller, T content, string message)
        {
            return new OkNegotiatedContentResult<ResultWrapper<T>>(new ResultWrapper<T>() { Result = content, Success = false, Message = message }, controller);
        }
        public static OkNegotiatedContentResult<FailureResult> Failure(this ApiController controller, string message)
        {
            return new OkNegotiatedContentResult<FailureResult>(new FailureResult() { Success = false, Message = message }, controller);
        }
    }
    
    public class ResultWrapper<T>
    {
        public T Result { get; set; }
        public string Message { get; set; }
        public bool Success { get; set; }
    }
    public class FailureResult // simple class used strictly for failures (unless you ever have an operation with no result that can succeed then modify the name and reuse)
    {
        public string Message { get; set; }
        public bool Success { get; set; }
    }
    
    public class SomeObject
    {
        public string Name { get; set; }
    }
    

    编辑

    不确定您是否已经尝试过,但我查看了the documentation for extjs

    回调选项

    并非每个 AJAX 请求都会成功:有时服务器已关闭,或者您的互联网连接中断,或者发生了其他不好的事情。 Ext.Ajax 允许您为每种情况指定单独的回调

    Ext.Ajax.request({
        url: 'myUrl',
    
        success: function(response) {
            console.log("Spiffing, everything worked");
        },
    
        failure: function(response) {
            console.log("Curses, something terrible happened");
        },
    
        callback: function(options, success, response) {
            console.log("It is what it is");
        }
    });
    

    因此,基于这种模式,我的第一个场景似乎是,按照 Microsoft 的意图使用 Web API,并在出现错误时使用适当的故障状态代码。

    【讨论】:

    • Igor,extjs 要求每个带有 json 的响应也有 success = true 或 false 并且 msg 是可选的(通常显示错误消息)。因此,出于我的需要,您的解决方案将不起作用。是否有一些选项可以返回 ResultBase 作为在 request=true 中具有某些参数的每个请求的结果?如果是假的,那么你的方式(我目前不需要,但永远不知道)。否则我必须将 ResultBase 添加到每个 web api 函数中。
    • 谢谢伊戈尔。此扩展现在适用于对所有控制器方法的所有调用。如何仅将它用于那些在请求中具有特定参数的请求,例如“ext=1”?
    • @Simon - 我不关注。你能举例说明你的意思吗?
    • 当您调用web api时,您可以添加查询字符串参数,例如:ext=1 然后您在响应中返回“ResultWrapper”,并在ext=1的情况下返回成功和msg。现在,如果您添加 ApiControllerExtensions,它将对所有请求都有效,即使那些不是来自分机的请求。
    • 伊戈尔,只是一种解释。有了这个扩展,当调用 Ok 作为返回时,每个 IHttpActionResult 都会有这个消息模式。是否可以创建 OkExt() 方法并在需要 ext 消息模式时调用此方法?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-10
    • 2014-05-16
    • 1970-01-01
    • 2015-10-09
    • 2015-08-27
    • 2021-06-13
    • 1970-01-01
    相关资源
    最近更新 更多