0

In controller I used to return json like this:

[System.Web.Http.HttpGet]

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

Since extjs expect success message as part of json I had to add this to every response, and object with all data I usually add to result.

Now I have web api. Here you have to define return type of some method as object and based on accept header the result will be json or xml(I had a lot of problems since IE doesn't send this header and I got always xml as return - but I solved this config formatters add):

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

It works. But now there is no {success = true, msg = ""} as part of returned json. How can I add this to be returned the same way as with controller? (without creating custom HttpContent class since it is ugly workaround).

And at the end, does it have any sense to use web api at all and not use mvc controller-the old way? There are problems with accept headers, it is harder to test(I must simulate ajax call while with controller there is just url to call) and as it seems it is more work to get the appropriate json. The only benefit of web api as i see is to get different serialization to client based on accept header, but in reality there is no need to get other data than json(at least I don't need it). So, why not use mvc controller instead web api?

tereško
  • 58,060
  • 25
  • 98
  • 150
Simon
  • 1,955
  • 5
  • 35
  • 49

2 Answers2

2

You can create a class as ResultBase as below

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

then change your controller code as below

public ResultBase<MyObject> GetData(){
    ...
    return new ResultBase<MyObject>{success = true, msg = "", result = myObject};
}
Reza
  • 18,865
  • 13
  • 88
  • 163
0

Web api is designed to return Http Status codes when there is a failure. You can then include the message in the response. Also here is a list of possible status codes that you could send back. There are built in methods for the more common response reasons. So your Web Api method ends up looking something like this (see code sample below). Now the calling client will know if a status of 200 is received (default for Ok) then everything was processed correctly on the server, otherwise handle the Http status code and do something with the message or response object.

This pattern will prevent you from having to add a success and message property to all of your responses. It also allows you to catch some common validation using Action Filters like authorization checks using the Authorize filter attribute.

[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();
    }
}

So, why not use mvc controller instead web api?

This question has been asked before, see these SO posts


Edit

Based on the latest comment. Here is some code that you can use to dynamically create a generic response object without having to manually wrap everything. By creating some extension methods you can abstract the response wrapper to some helper methods.

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; }
}

Edit

Not sure if you have already tried this but I checked out the documentation for extjs.

Callback Options

Not every AJAX request succeeds: sometimes the server is down, or your internet connection drops, or something else bad happens. Ext.Ajax allows you to specify separate callbacks for each of these cases

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");
    }
});

So based on this pattern it seems like my first scenario, using Web API as Microsoft intended with proper failure status codes in case of error, should be possible.

Community
  • 1
  • 1
Igor
  • 60,821
  • 10
  • 100
  • 175
  • Igor, extjs requires that every response with json has also success = true or false and msg is optional(to show error message usually). So, for my need your solution won't work. Is there some option to return ResultBase as result of every request which has some parameter in request=true? If false, then your way(which I currently don't need, but never know). Otherwise I have to add ResultBase to every web api function. – Simon Mar 24 '16 at 08:30
  • Thank you Igor. This extension now works for all calls to all controller methods. How can I use it for only those requests, which have specific parameter in request, like "ext=1"? – Simon Mar 24 '16 at 13:33
  • @Simon - I don't follow. Could you provide an example of what you mean? – Igor Mar 24 '16 at 13:40
  • When you call web api, you can add query string parameter, for example: ext=1 Then you return in response "ResultWrapper" with success and msg only in case when ext=1. Now if you add ApiControllerExtensions it will be valid for all requests, even those not coming from ext. – Simon Mar 24 '16 at 15:35
  • Igor, just one explanation. With this extension every IHttpActionResult will have this message pattern when calling Ok as return. Is it possible to create OkExt() method and calling this method when wanted to have ext message pattern? – Simon Mar 29 '16 at 07:26
  • @Simon - yes, you can name the method as you see fit. – Igor Mar 29 '16 at 11:48