1

I've been following the online tutorials for my MVC project using Knockout and Entity Framework. I am also using a repository pattern.

From what I've been finding, the tutorials are returning strings when performing HTTP POST requests, as I have below. My concern is that the controller is returning strings - it just seems very rudimentary, and I can't seem to find a solid sample/tutorial of how I can do these POST requests otherwise (while not returning a view), as well as catching both database exceptions and POST exceptions as well.

Javascript:

self.saveNRI = function () {
        var token = $('[name=__RequestVerificationToken]').val();
        var headers = {};
        headers["__RequestVerificationToken"] = token;
        $.ajax({
            type: "POST",
            url: '/nris/Create',
            headers: headers,
            dataType: 'json',
            data: ko.toJSON(self.nri),
            contentType: 'application/json',
            success: function (result) { },
            error: function (err) {
                if (err.responseText == "Success") {
                    window.location.href = '/nris/Index/';
                }
                if (err.responseText == "Failed") {
                    alert("save failed");
                }
            }
        });
    }

Controller:

[HttpPost]
public string Create(DTO incomingModel)
{  
    if (ModelState.IsValid){
        try
        {
            _nriRepository.Insert(incomingModel);                    
        }
        catch (Exception ex)
        {
            return "Failed";
        }         
    }
    return "Success";
}

Repository:

public async void Insert(DTO n)
{
    //Insert code removed for brevity
        await _context.SaveChangesAsync();
}
alex
  • 6,818
  • 9
  • 52
  • 103
chickenricekid
  • 390
  • 4
  • 19
  • 1
    Take a look at the following post for some ideas for how to handle exception on AJAX calls: http://stackoverflow.com/questions/4707755/asp-net-mvc-ajax-error-handling – David Tansey Jan 14 '15 at 20:17
  • @chickenricekid it's been a while since this received your attention. Can you comment on whether the answers can be improved, or accept one of them? thanks. – Guilherme Rodrigues Jan 20 '15 at 17:42
  • 1
    @gadr90 apologies - I've been on a couple business trips with a few more scheduled, so I haven't had a chance to fully implement your answer. However, it does seem like that's the answer I'm looking for, and regardless it's still valuable information. I'll go ahead and accept your answer. Thanks again! – chickenricekid Jan 20 '15 at 17:44
  • thanks :) please do update us after you tried – Guilherme Rodrigues Jan 20 '15 at 17:47

2 Answers2

4

It's probably a Good Idea® to use good old regular HTTP Status Codes to communicate the results of operations on your API.

The appropriate code to communicate a success when creating a resource is 201. Usually, the response body will contain the ID or URL for the newly created resource.

10.2.2 201 Created

The request has been fulfilled and resulted in a new resource being created. The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a Location header field. The response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. The origin server MUST create the resource before returning the 201 status code. If the action cannot be carried out immediately, the server SHOULD respond with 202 (Accepted) response instead.

However, you can also use more generic status code 200 to indicate success:

10.2.1 200 OK

The request has succeeded. The information returned with the response is dependent on the method used in the request, for example:

GET an entity corresponding to the requested resource is sent in the response;

HEAD the entity-header fields corresponding to the requested resource are sent in the response without any message-body;

POST an entity describing or containing the result of the action;

TRACE an entity containing the request message as received by the end server.

To communicate failures, you'll probably use codes in the range of 4xx or 5xx.

A 4xx means the failure is on the side of the client. For example, the client did not send all required properties to create the resource. The generic 400 is handy:

10.4.1 400 Bad Request

The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.

The 5xx, however, indicates that your server encountered problems while fulfilling the request.

10.5.4 503 Service Unavailable

The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. The implication is that this is a temporary condition which will be alleviated after some delay. If known, the length of the delay MAY be indicated in a Retry-After header. If no Retry-After is given, the client SHOULD handle the response as it would for a 500 response.

On the client side, you can rely on jQuery.ajax to appropriately route your callbacks based on status code. You should use the newer Promise-based API instead of success and errors callbacks. For example:

var jqxhr = $.ajax( "example.php" )
  .done(function() {
    alert( "success" );
  })
  .fail(function() {
    alert( "error" );
  })
  .always(function() {
    alert( "complete" );
  });

source: http://api.jquery.com/jquery.ajax/

You can use the excellent httpstat.us web service to test out response codes. Just append the desired response code to the URL and it will return a mock answer. For example, a success: http://httpstat.us/200

Guilherme Rodrigues
  • 2,818
  • 1
  • 17
  • 22
2

I like @gadr90's answer best, but I thought I'd also mention that you can return JSON from an ActionResult in MVC, directly.

[HttpPost]
public JsonResult Create(DTO incomingModel)
{  
    if (ModelState.IsValid)
    {
        try
        {
            _nriRepository.Insert(incomingModel);                    
        }
        catch (Exception ex)
        {
            var x = new
            {
                status = "Failed",
                message = ex.Message,
            };
            return this.Json(x);
        }         
    }
    var x = new
    {
        status = "Success",
        message = "",
    };
    return this.Json(x);
}
roryok
  • 9,325
  • 17
  • 71
  • 138