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..
Related
I have an EmbedIO API and want to return an HttpException, like for example "401 - unauthorized". If a username is not found upon logging in, I throw an HttpException inside my API endpoint method, like the following:
// return 401
throw HttpException.Unauthorized(message="user name does not exist", data=myData);
But it seems like EmbedIO ignores the data, which I thought would be included in my response content. But instead I get a "standard" response, generated by the server that only uses my message and says:
401 -
Unauthorized401 -
UnauthorizedException type:
EmbedIO.HttpExceptionMessage: user name does not
existIf this error is completely unexpected to you, and you
think you should not seeing this page, please contact the server
administrator, informing them of the time this error occurred and the
action(s) you performed that resulted in this error.
Does anybody know how to return a response with custom content that is specified throught the "data" parameter? Like for example
{
"userName" : "testUser",
"userNameExist" : "false",
"attempt" : 5
}
You can define the response with the HandleHttpException method:
var server = new WebServer(8877);
server.HandleHttpException(async (context, exception) =>
{
context.Response.StatusCode = exception.StatusCode;
switch (exception.StatusCode)
{
case 401:
await context.SendDataAsync(new { userName = "testUser", userNameExist = false, attempt = 5 });
break;
default:
await HttpExceptionHandler.Default(context, exception);
break;
}
});`
Look here: https://unosquare.github.io/embedio/wiki/Cookbook.html#setting-a-custom-error-page
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.
I am using Flurl Client to call a restful API with a post data. There is a validation performed on the server on the data I submit and it returns back a header containing an error message for the user.
As the request requirement doesn't satisfy server marks the request as 400 BadRequest. In the below code on line cli.Request(uri).PostJsonAsync(data) it throws the FlurlHttpException with appropriate status code.
Now, as there is a problem with the input data by the user I want to report the user back with the error message which I receive from the server in the header. However, I am unable to access the response headers as the request has failed.
Is there any other way to access the response headers from a failed request using Flurl?
try
{
using (var cli = new FlurlClient(baseUrl))
{
var httpResponse = await cli.Request(uri).PostJsonAsync(data);
var errorMessage = httpResponse.GetHeaderValue("errorMessage");
}
}
catch (FlurlHttpException ex)
{
}
Using an event handler works, but I think those are better for cross-cutting concerns like logging that you don't want cluttering the main flow of your app. You basically want to allow and/or handle 400 responses as part of that main flow. You can do that more directly with AllowHtttpStatus, which can be set on the client:
cli.AllowHtttpStatus(HttpStatusCode.BadRequest);
or the request:
var httpResponse = await cli
.Request(uri)
.AllowHttpStatus(HttpStatusCode.BadRequest)
.PostJsonAsync(data);
Either way, the call will not throw on a 400.
Another way to do this, and one I'd recommend if your app logic takes a completely different path on an error condition than on a success condition, is to keep your try/catch in place and use the Response property of the exception to handle the error condition:
try
{
await cli.Request(uri).PostJsonAsync(data);
// handle success condition
}
catch (FlurlHttpException ex) when (ex.Response?.StatusCode == 400)
{
var errorMessage = ex.Response.GetHeaderValue("errorMessage");
// handle error condition
}
As a side note, there are some significant changes coming in 3.0 that you should be aware of as they touch on some of these areas directly:
https://github.com/tmenier/Flurl/issues/354
https://github.com/tmenier/Flurl/issues/488
I am configuring the Error Event Handler to report any error. As a result, the code doesn't jump to the exception block it asynchronously fires the event handler, and the rest of my subsequent code executes OK with an appropriate httpResponseMessage, StatusCode, headers everything.
...
FlurlHttp.Configure(settings => settings.OnErrorAsync = HandleFlurlErrorAsync);
using (var cli = new FlurlClient(baseUrl))
{
var httpResponse = await cli.Request(uri).PostJsonAsync(data);
var errorMessage = httpResponse.GetHeaderValue("errorMessage");
}
...
private async Task HandleFlurlErrorAsync(HttpCall call)
{
//Log your exception here
call.ExceptionHandled = true;
}
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 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