0

I am trying to delete item from table. There is Ajax link for it.

@Ajax.ActionLink("Delete", "DeleteConfirm", new { id = Model.ID }, new AjaxOptions {
    HttpMethod = "POST", UpdateTargetId = "TableID", OnSuccess = "CloseDialog", OnFailure = "AlerDialog"
  })

It calls DeleteConfirm method from controller with POST method. I made simple controller which should do something so ActionLink should catch error and run OnFailure function (to show alert dialog).

Controller:

public ActionResult DeleteConfirm(int id)
        {            
            // code here
        }

What to return from controller method so OnFailure function invokes?

2
  • why you think onFailure should be executed? it will be called only when there is something wrong on server side i.e any response other than 200. Or client side script is unable to parse the response according to the given data type. would you mind showing the complete code of controller and failure and success methos? Commented Feb 8, 2013 at 13:01
  • DeleteConfirm should delete one row in database based on given id. But if deleting row with given id fails (for example there is referential integrity error) I want to force controller to raise error so OnFailure Javascript method should be called to display alert to user, with some message: "You can't remove this record". In short I just want to make situation to call OnFailure AJAX option. Commented Feb 8, 2013 at 13:22

3 Answers 3

2

OnError is fired when error happens on serverside. By error, I mean exception, and I think you can't pass exception message on clientside except of 500 Server error. I think that good aproach is to have some CustomResponse class that your action will return. In your case, something like:

Class DeletionResponse
{
    public bool IsDeletionSuccesfull {get; set; }
    public string Message {get; set;}
}

In DeleteConfirm action you create new response, which maybe needs to inheriteActionResult class(I'm not sure because I'm new to MVC). If some error ocures while deleting, set DeletionSuccesfull to false, and Message to message of exception, or some custom message.

On client side, the point is to examine success in OnSuccess handler, and then decide what to do. Something like:

function handleResponse(deletionResponse){
  if(deletionResponse.d.IsDeletionSuccesfull){
     CloseDialog();
  }
  else{
     AlertDialog(deletionResponse.d.Message);
  }
}
Sign up to request clarification or add additional context in comments.

4 Comments

why would you handle an error in the OnSuccess method?
First, what is an error? In context of ajax, and these functions http error is an error, not your business logic, whatever that logic is. In this case validation of existance of the row in db is business logic too. These functions handles ajax calls. If call is succesfull (no exception on server, or broken communication), OnSuccess method is executed. Else, OnError is executed. If you throw ex on server, it will be returned as 500- server error, because ex is mapped to that http response.
but that is not what the op asked for. The question was how to get the OnFailure method to fire. The business logic can have an error if you want it to. It is just as much an error as a http error.
Ok. Question: How to get the OnFailure method to fire? Answer: Throw exception on server, onError will fire. Unplug the server, onError will fire. BUT. That's not the point, right? Checkout api.jquery.com/jQuery.ajax for description of error function.
1

The OnFailure will fire based off the status code of the result, so something like this would give the desired effect.

return new HttpStatusCodeResult(HttpStatusCode.InternalServerError, "Reason for failure");

Also, not sure if it's related but shouldn't your OnFailure text be "AlertDialog" instead of "AlerDialog"?

EDIT: In your controller action you should be able to test that the request is being made via Ajax by using this Extension method MVC provides Request.IsAjaxRequest(). Note that there is no true way to check if a request is an Ajax request on the server, this method is utilizing the presence of a custom header jQuery sets for all ajax requests it makes, in other words don't use Request.IsAjaxRequest() in business logic.

Source for IsAjaxRequest() method

namespace System.Web.Mvc
{
    public static class AjaxRequestExtensions
    {
        public static bool IsAjaxRequest(this HttpRequestBase request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            return (request["X-Requested-With"] == "XMLHttpRequest") || ((request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest"));
        }
    }
}

4 Comments

Yes, it should be AlertDialog but it doesn't matter here. Biggest problem is how to force controller to return error so OnError function is executed. I will try your solution.
I didn't worked because first parameter of HttpStatusCodeResult should be int so I did casting. It builds now. But it returns HTTP error 500 (Internal Server Error): page. But it's not what I wanted to achieve. I want to call OnFailure function.
It should have been an Ajax request, worst case if the onFailure wasn't working the postback should have appeared to do nothing at all. The fact that you're getting redirected to a 500 error page tells me the ajax isn't working. Try the development tools in your browser to see if the request is actually going out as Ajax, and make sure you're site is referencing the Unobtrusive Ajax file. LEt me know if that helps.
Correction, I've only ever used this method with the Unobtrusive Ajax, in theory I think it's supposed to work without it but I've never done it without the Unobtrusive implementation.
1

how about throwing an exception?

public ActionResult DeleteConfirm(int id)
    {
        try
        {
            //make your call to the database here
            return View();
        }
        catch (ExceptionType1 ex)
        {
            //log the details of your error for support purposes, alerting tracing etc. 
            ex.Message = "Nice message for user"
            throw ex;
        }
        catch (ExceptionType2 ex)
        {
            //log the details of your error for support purposes, alerting tracing etc. 
            ex.Message = "Another nice message for user"
            throw ex;
        }
    }

Your ajax call would then know it was a failure, and run the correct function.

8 Comments

This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient reputation you will be able to comment on any post.
As it happens it will not let me comment on the original post, I could however add example code to my answer to clarify what I mean.
Yes of course is does while you are debugging, it throws an exception. You could set your debugger not to brake on exceptions if you want to see how it will behave when in production. In a production environment with no debugger attached it will not stop the application running. It will return the exception to the calling ajax. Your failure function could if you want then display the exception, or you could just display a friendly message to the user.
How else would detect if your database call failed? If it fails it will raise an exception? And you should have calls to external resources (like a DB) wrapped in a try catch anyway? So should you not just pass that exception back to the calling code, causing it to fail, and thus run the failure JavaScript function? If it is the wrong way to do it then I am open to correction, but this works fine for me!
Unless you explain how to tell one error from another on the client this is actually an anti-answer and bad practice. Treating expected (i.e. cannot delete item due to foreign key constraint) and unexpected errors the same way is bad. Now if you explain how to check the exception type or message on the client and treating it differently this would be very useful.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.