I have a webservice written in C#. When errors occur on the server, I would like to inform the user client side. This works fine by throwing exceptions server side, which is then sent to my error handler client side.
However, I would like to, when I throw the exception, to set a property describing how serious I think the error is at this point. Thus I can decide client side how to display the error:
WebService.Method(some_value, handle_response, handle_error);
function handle_response (response) {
//Do something...
}
function handle_error (error) {
if(error.level === 'Critical') {
//Show critical message.
} else if(error.level === 'Warning') {
//Show warning message.
} else
...
}
}
My solution so far has been to create a custom exception inheriting from System.Exception.
My webservice returns with a JSON formatted result.
My problem is how to get my property through to the client side JSON response?
Web service:
public Response zzz() {
Response result;
try {
...
} catch (MyException) {
result.HasError = true;
result.Error.Level = Normal;
result.Error.Message = "It's OK.";
} catch (Exception) {
result.HasError = true;
result.Error.Level = Critical;
result.Error.Message = "!!!!";
}
}
Then check Response.HasError
Related
So, guys I have a route in my API that receives a JSON than it is treated and sended back.
What is wrong with that? Nothing.
But has a strange behavior that sometimes I send a json document and receive error 500 with the message "An unxpected erro occurred" but If I send it again (without change nothing) then it works;
Please guys, can you help me telling me how can I catch an exception for this, if there is one.
This is the code that receives the request:
public async Task<string> SaveHumanChat(JObject talk)
{
if (!ModelState.IsValid)
return BadRequest(ModelState).ToString();
var conversa = talk.ToString();
try
{
return await _service.SaveHumanChat(conversa);
}
catch (Exception e)
{
return e.Message;
}
}
Ps: I've tried to use ArgumentException but without success.
Up to now if a web api 2 error happened and I caught it, I'd return a custom object and fill in the error message from the catch. This would however make the actually http.post() go into success method instead of the error and then I'd have to look at my own boolean success variable and if true all good, if false show error. This is kind of annoying as I have to look for errors in 2 different places for 2 different reasons. From Web API 2 is there a way I can make the http.post() trigger the error callback while I fill out the error message if I catch an error in the web api controller?
[HttpPost]
public MyResponseObject UpdateData(RequestObject req)
{
MyResponseObject resp = new MyResponseObject();
resp.Success = true;
try{
// error happens here
}catch(Exception ex){
resp.Success = false;
resp.Msg = ex.Message;
}
return resp;
}
The http.post() call will still be successful but now I have to look in the success callback for my resp.Success to see if it was REALLY successful or not. Sure the API call was able to be made, but something went wrong inside of it. I'd like to just be able to display that message and fail the call so the http.post() error callback is called with the exception message.
Just throw an exception:
throw new HttpResponseException(HttpStatusCode.InternalServerError);
If you want to customize the response that is returned you can create a HttpResponseMessage with more detail:
var response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("We messed up"),
ReasonPhrase = "Error"
}
throw new HttpResponseException(resp);
Documentation here
I have a MVC 5 backend written in C#. It serves MVC views written in Razor and also some Angular 2 pages.
What is the best way to handle potential errors when calling server from client? I really would like to establish a pattern that is robust and works in all situations. Below is what I have tried so far.
Backend C# code:
public class MyController : Controller
{
[HttpGet]
public ActionResult GetUsers()
{
try
{
// Lot of fancy server code ...
throw new Exception("Dummy error");
return GetCompressedResult(json);
}
catch (Exception ex)
{
throw new HttpException(501, ex.Message);
}
}
private FileContentResult GetCompressedResult(string json)
{
// Transform to byte array
var bytes = Encoding.UTF8.GetBytes(json);
// Compress array
var compressedBytes = bytes.Compress();
HttpContext.Response.AppendHeader("Content-encoding", "gzip");
return new FileContentResult(compressedBytes, "application/json");
}
}
Client side Angular 2 code:
public loadDataFromServer() {
let response = this.http.get(this.urlGetData)
.map((res: Response) => res.json())
.catch(this.handleError);
response.subscribe(response => {
// Process valid result ...
},
err => { console.error(err); }
);
};
private handleError(error: Response | any) {
let errMsg: string;
if (error instanceof Response) {
const body = JSON.parse(JSON.stringify(error || null))
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
This is a printscreen of the error object processed by handleError method:
This all raises some questions:
Is it correct to throw custom HttpException from server?
Is handleError method correct or maybe too complex?
On client side I would like to see the custom error message, but currently it is just found in an enormous "blob" of HTML that is nasty to parse.
Is client side error handling necessary BOTH in get call and subscribe action?
My current suggestion is to let server respond with Json object for all handled exceptions.
On client side I check result object for possible error property before handling valid result.
The handleResponseError method will parse typed Response object and throw observable message. But at least my browser (Chrome 57) seems to automatically log response errors to console. So if subscriber need no specific extra handling for different errors, then the subscriber need no extra action for err object.
Please feedback if there are better ways!
Backend C# code:
public class MyController : Controller
{
[HttpGet]
public ActionResult GetUsers()
{
try
{
// Lot of fancy server code ...
throw new ArgumentException("Dummy error");
// Normal return of result ...
}
catch (Exception ex)
{
return Json(new { error = $"{ex.GetType().FullName}: '{ex.Message}'" }, JsonRequestBehavior.AllowGet);
}
}
}
Client side Angular 2 code:
public loadDataFromServer() {
let response = this.http.get(this.urlGetData)
.map((res: Response) => res.json())
.catch(this.handleResponseError);
response.subscribe(result => {
if (result.error) {
this.displayJsonError(this.urlGetUsers, result.error);
}
else {
// Process valid result
}
});
};
private handleResponseError(value: Response | any) {
let errorMessage = value.toString();
let response = value as Response;
if (response) {
errorMessage = `${response.status}: ${response.statusText}\n${response.toString()}`;
}
if (value.error) {
errorMessage = value.error;
}
if (value.message) {
errorMessage = value.message;
}
return Observable.throw(errorMessage);
}
private displayJsonError(url: string, error: string) {
console.error(`Call to '${url}' failed with ${error}`);
}
public IHttpActionResult Save(item)
{
try
{
result = MyRepository.Save(item);
return Ok(result);
}
catch
{
// What should I do here?
// I wish to return an error response how can i do that?
}
}
If it has no exception,I can return Ok.
But if there is an exception what should I do?
Note that I have javascript client
In Web API 2, you can use BadRequest to return an error message.
public IHttpActionResult Save(item)
{
try
{
result = MyRepository.Save(item);
return Ok(result);
}
catch
{
return BadRequest("Error message");
}
}
FYI: Do not use try catch block just to swallow an exception. I personally do not like using try catch block inside Action method. Instead, I let Web API 2 Global Exception Handler handles exceptions. It is the out of the scope of your original question.
Create a model to hold what error information you want to return and pass that.
public IHttpActionResult Save(item) {
try {
result = MyRepository.Save(item);
return Ok(result);
} catch {
// What should I do here? Create a model to hold the data you want to return
var myErrorModel = new {
code = "My custom error code or 500 server error code",
message = "some friendly error message"
};
// I wish to return an error response how can i do that?
var response = Request.CreateResponse(HttpStatusCode.InternalServerError, myErrorModel);
return ResponseMessage(response);
}
}
In your javascript client in the error handler you can then access the model properties and handle the error as you see fit.
var handleResponse = function (data) {
var code = data.code;
var message = data.message
};
UPDATE:
Agreeing with #Win, I personally don't like doing this in the controller actions as it is a Cross-cutting concern and have basically moved everything from within the catch block into a global error handler.
You can use HttpResponseException to send an error message.
public IHttpActionResult Save(item)
{
try
{
result = MyRepository.Save(item);
return Ok(result);
}
catch
{
var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent(string.Format("Error Message!!"),
ReasonPhrase = "Error Reason phrase"
};
throw new HttpResponseException(resp);
}
}
Use HttpResponseException as below:
throw new HttpResponseException(HttpStatusCode.InternalServerError)
Or another way is:
var response = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent("some error"),
ReasonPhrase = "Not Found"
};
throw new HttpResponseException(response);
I am having trouble getting a custom error message back from my file delete handler. I am not sure but it looks like the delete is handled differently to the upload.
From the docs:
You may return any response you like, as the XMLHttpRequest object will be passed to your onDeleteComplete handler for further examination. However, the response code you return is important to Fine Uploader, as it uses this to determine if the delete has succeeded or not. The following response codes indicate success for this specific request: 200, 202, and 204. Any other response code indicates a failure.
In my server handler for the delete I have this to catch the error and send back response to FineUploader.
catch (Exception ex)
{
//const string json = "{\"success\":false}";
const string json = "{\"success\":false,\"error\":\"THIS IS THE ERROR\"}";
//const string json = "{\"error\":\" HERE IS THE ERROR! \"}";
var response = (Response)json;
response.ContentType = "text/plain";
//response.StatusCode = HttpStatusCode.InternalServerError;
return response;
}
I have tried sending back {"success":false} along with the error, just {"success":false} and just the error. I have checked that the json is valid.
However it seems to do nothing at all. All that matters to FineUploader is response.StatusCode. If I send a fail response code then FineUploader recognises the error and displays the message for that code. It also comes back in errorReason in the onError callback.
If I do not set the response status code it defaults to OK and no error is raised.
I have looked at the example code for php and see this in the delete handler:
if (is_dir($target)){
$this->removeDir($target);
return array("success" => true, "uuid" => $uuid);
} else {
return array("success" => false,
"error" => "File not found! Unable to delete.".$url,
"path" => $uuid
);
}
Clearly, that code is sending back a "success":fail with a custom error message.
But I can't work out in that code what response status is being sent back.
Update 1: Here is the js on the client to handler the server response:
callbacks: {
onError: function(id, name, errorReason, xhrOrXdr) {
alert(qq.format("Error on file number {} - {}. Reason: {}", id, name, errorReason));
console.log(errorReason);
}
So, am I doing something wrong?
Update 2:
Ok, I have had a look at onDeleteComplete and my client code now looks like this:
callbacks: {
onDeleteComplete: function(id, xhr, isError) {
alert("onDeleteComplete => id is:" + id + " Is error?:" + isError);
},
onError: function(id, name, errorReason, xhrOrXdr) {
alert(qq.format("onError => Error on file number {} - {}. Reason: {}", id, name, errorReason));
console.log(errorReason);
},
Now when I delete a file in the browser I get the onError alert first and then the onDeleteComplete. In neither case can I find any way to show the error message I want to send back from my server handler. The onError always seems to just show the HttpStatus error message and not the one defined in my json response. The onDeleteComplete has no parameter to bring back the error.
I am not sure if it's just me but I found this confusing and inconsistent.
For uploads you can do this:
failedUploadTextDisplay: {
mode: "custom",
responseProperty: "errorMessage"
},
What this means is that your server can send back a custom response error and this will be displayed below the file in the event of an error.
So my C# Nancy server code does this on error:
catch (Exception ex)
{
FormResponse.success = false;
FormResponse.errorMessage = ex.Message;
return Response.AsJson(FormResponse).WithStatusCode(HttpStatusCode.BadRequest);
}
This sends back json that looks like this:
{"errorMessage":"A file with that name already exists and cannot be overwritten!","success":false}
FineUploader then shows this message under the file like this:
Which is great. However for file delete there is no such feature I can find.
So for unexpected delete failures I will have to find a workaround:
I have the onDeleteComplete callback which I assumed could use to get the error:
onDeleteComplete: function(id, xhr, isError) {
if (isError) {
console.log("Error in delete!!");
if (typeof xhrOrXdr != 'undefined' && xhrOrXdr != null) {
console.log("resp text=" + xhrOrXdr.responseText);
var t = JSON.parse(xhrOrXdr.responseText);
console.log(t['errorMessage']);
}
}
But this does not work because when isError = true the xhr object is null.
So there's no way to get the error in onDeleteComplete.
It would be nice if FineUploader had something like this:
failedDeleteTextDisplay: {
mode: "custom",
responseProperty: "errorMessage"
},
But it doesn't. So it looks like I have to handle the delete error in the OnError callback. But since I won't know which kind of action it is. Delete or Upload then I will have to send another parameter back in my json to handle the switch since I only need to change the default error message for failed deletes.
So, my final workaround for now is this. The onError handler deals with both delete and upload errors. My server now sends back another parameter in the json called 'actionType'. This can either be 'delete' or 'upload'. If it's a delete action error then some jquery hides the default error messages and shows the new one.
onError: function(id, name, errorReason, xhrOrXdr) {
if (typeof xhrOrXdr != 'undefined' && xhrOrXdr != null) {
var t = JSON.parse(xhrOrXdr.responseText);
// if the error was result of delete then show the custom message on the panel
if (t["actionType"] === "delete") {
$("#CustomError").html("Delete failed: " + t["errorMessage"] );
$("#ErrorContainer").hide();
}
}
},
UPDATE:
Well this is embarrassing. I raised this as a bug and it turns out it was my code at fault. This is a demonstration and reminder to me about the pitfalls of javascript. Id' been looking at this code for some time:
onDeleteComplete: function(id, xhr, isError) {
if (isError) {
console.log("Error in delete!!");
if (typeof xhrOrXdr != 'undefined' && xhrOrXdr != null) {
It was only when Ray looked at my bug report that he spotted an obvious error.
My function variable was called xhr but my code was looking for xhrOrXdr.
I just didn't see it. And since it's javascript there were no complaints in the console. I am used to coding in C# with Resharper where that kind of thing is impossible. Neither Resharper or VS intellisense were able to warn me.
So the bug was my bug and the onDelete callback works as described.
It's a learning process..