The subject is selfexplanatory. I've developer and production environments. Developer env. is my localhost machine. I've action methods in contolers that sets response status code to 500 when something wents wrong (error occured, or logical inconsistance) and returns Json-answer. My common method looks like that:
[HttpPost]
public ActionResult DoSomething(int id)
{
try
{
// some useful code
}
catch(Exception ex)
{
Response.StatusCode = 500;
Json(new { message = "error" }, JsonBehaviour.AllowGet)
}
}
On the client side in production env. when such an error occured ajax.response looks like an HTML-code, instead of expected JSON.
Consider this:
<div class="content-container">
<fieldset>
<h2>500 - Internal server error.</h2>
<h3>There is a problem with the resource you are looking for, and it cannot be displayed.</h3>
</fieldset>
</div>
Filter context is not an option. I think it is some sort of IIS or web.config issue.
SOLUTION:
We decided to add TrySkipIisCustomErrors in BeginRequest in Global.asax and it is solved problems in each method in our application.
I guess that IIS is serving some friendly error page. You could try skipping this page by setting the TrySkipIisCustomErrors property on the response:
catch(Exception ex)
{
Response.StatusCode = 500;
Response.TrySkipIisCustomErrors = true;
return Json(new { message = "error" }, JsonBehaviour.AllowGet)
}
Is your IIS configured to treat application/json as a valid mime-type? You may check that in properties for the server in IIS Manager and click MIME Types. If json is not there then click "New", enter "JSON" for the extension, and "application/json" for the MIME type.
I solved this by writing a custom json result, which uses json.net as the serializer. This is overkill for just the IIS fix but it means it's reusable.
public class JsonNetResult : JsonResult
{
//public Encoding ContentEncoding { get; set; }
//public string ContentType { get; set; }
public object Response { get; set; }
public HttpStatusCode HttpStatusCode { get; set; }
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult(HttpStatusCode httpStatusCode = HttpStatusCode.OK)
{
Formatting = Formatting.Indented;
SerializerSettings = new JsonSerializerSettings { };
SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
HttpStatusCode = httpStatusCode;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
HttpResponseBase response = context.HttpContext.Response;
response.TrySkipIisCustomErrors = true;
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
response.StatusCode = (int) HttpStatusCode;
if (Response != null)
{
JsonTextWriter writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
JsonSerializer serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Response);
writer.Flush();
}
}
}
Use:
try
{
return new JsonNetResult()
{
Response = "response data here"
};
}
catch (Exception ex)
{
return new JsonNetResult(HttpStatusCode.InternalServerError)
{
Response = new JsonResponseModel
{
Messages = new List<string> { ex.Message },
Success = false,
}
};
}
Related
How to create a Custom Exception Handler Middleware. This middleware should generate a custom response based on the Calling Client. If the client is requesting via AJAX then the response should be a JSON Response describing the Error otherwise Redirect the client to Error page.
Controller code
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
middleware code
public class ErrorHandlerMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception error)
{
var response = context.Response;
var customError = new CustomError();
switch (error)
{
case AppException e:
// custom application error
customError.StatusCode = (int)HttpStatusCode.BadRequest;
break;
case KeyNotFoundException e:
// not found error
customError.StatusCode = (int)HttpStatusCode.NotFound;
break;
default:
// unhandled error
customError.StatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
customError.ErrorMessage = error?.Message;
if (context.Request.ContentType == "application/json;")
{
var result = JsonSerializer.Serialize(customError);
await response.WriteAsync(result);
}
else
{
context.Response.Redirect("/Errors/CustomError");
}
}
}
Custom Error class code
public class CustomError
{
public int StatusCode { get; set; }
public string ErrorMessage { get; set; }
}
Error View model
public class ErrorViewModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
you could add the code in your startup class:
app.UseStatusCodePagesWithReExecute("/errors/{0}");
add a controller(In my case I tested with HttpContext.Request.Headers["Content-Type"] ,it should be context.Request.ContentType == "application/json;" for MVC project ):
public class ErrorsController : Controller
{
[Route("errors/{statusCode}")]
public IActionResult CustomError(int statusCode)
{
if (HttpContext.Request.Headers["Content-Type"] == "application/json")
{
var cuserr = new CustomError() { ErrorMessage = "err", StatusCode = statusCode };
return new JsonResult(cuserr);
}
else
{
if (statusCode == 404)
{
return View("~/Views/Errors/404.cshtml");
}
return View("~/Views/Errors/500.cshtml");
}
}
}
and the views:
The result:
for more details,you could read the offcial document:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-6.0
globally, I have the following object:
public class Geraet
{
public long Geraetenr { get; set; }
public int Typ { get; set; }
public string Platz { get; set; }
public string Bezeichnung { get; set; }
public int Tr { get; set; }
public string Ip { get; set; }
public string Bespielt { get; set; }
}
I populate a list of those objects, serialize them and send them via webservice:
[HttpGet]
public IHttpActionResult Get_Feedback()
{
List<Geraet> geraeteliste = null;
try
{
geraeteliste = GetSpielgeraeteFromDatabase();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
if (geraeteliste == null)
{
return Ok("No record found!");
}
else
{
var json = Newtonsoft.Json.JsonConvert.SerializeObject(geraeteliste);
return Json(json);
}
}
The data received by webservice looks like the following:
"[{\"Geraetenr\":123456789,\"Typ\":61,\"Platz\":\"1-01\",\"Bezeichnung\":\"CSII ADM430\",\"Tr\":3,\"Ip\":\"123.123.123.123\",\"Bespielt\":\"0\"},{\"Geraetenr\":987654321,\"Typ\":61,\"Platz\":\"2-12\",\"Bezeichnung\":\"M-BOX PUR+ GOLD\",\"Tr\":3,\"Ip\":\"124.124.124.124\",\"Bespielt\":\"0\"}]"
In my Xamarin App, I have the same object given above and trying to deserialize it:
private List<Geraet> GetSpielgeraeteFromWebservice()
{
List<Geraet> geraeteliste;
var request = HttpWebRequest.Create(Constants.GeraetelistServicePath);
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var json = reader.ReadToEnd();
geraeteliste = JsonConvert.DeserializeObject<List<Geraet>>(json);
}
}
return geraeteliste;
}
Unfortunately, I get an runtime error in the line geraeteliste = JsonConvert.DeserializeObject<List<Geraet>>(json); saying:
Unhandled Exception:
Newtonsoft.Json.JsonSerializationException: Error converting value "[{"Geraetenr":123456789,"Typ":61,"Platz":"1-01","Bezeichnung":"CSII ADM430","Tr":3,"Ip":"123.123.123.123","Bespielt":"0"},{"Geraetenr":987654321,"Typ":61,"Platz":"2-12","Bezeichnung":"M-BOX PUR+ GOLD","Tr":3,"Ip":"124.124.124.124","Bespielt":"0"}]" to type 'System.Collections.Generic.List`1[GroceryList.Classes.Geraet]'. Path '', line 1, position 3421.
The sending / retrieving stuff does work, otherwise error message would be in the line var json = reader.ReadToEnd(); or I wouldn't have gotten the right values in the error message. So something with the deserialization does not work.
Can anyone maybe help and tell me what is or could be the problem? Why can't he convert? It is the right order and the right values?
Best regards
Actually when we call API and send request in JSON format we are expecting response also come into JSON format. But here back end team sending me response in String format therefore my onErrorResponse () method get called. Here my status code is 200. But due to format of response not executed onResponse () method. So will you please help me to handle this? Might be I have to use CustomRequest here. Any suggestoin will be appreciated. Thanks
I have used volley json object request for accessing server.
My Request format is:
JSONObject json1 = new JSONObject();
try{
json1.put("","");
}catch(JSONException e){
e.printStackTrace();
}
new SampleJsonObjTask(MainActivity.this, json1);
and my SampleJsonObjTask class is:
public class SampleJsonObjTask {
public static ProgressDialog progress;
private static RequestQueue queue;
JSONObject main;
JsonObjectRequest req;
private MainActivity context;
public SampleJsonObjTask(MainActivity context, JSONObject main) {
progress = new ProgressDialog(context);
progress.setMessage("Loading...");
progress.setCanceledOnTouchOutside(false);
progress.setCancelable(false);
progress.show();
this.context = context;
this.main = main;
ResponseTask();
}
private void ResponseTask() {
if (queue == null) {
queue = Volley.newRequestQueue(context);
}
req = new JsonObjectRequest(Request.Method.POST, "", main,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
progress.dismiss();
Log.e("response","response--->"+response.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("error", "error--->" + error.toString());
NetworkResponse response = error.networkResponse;
Log.e("statusCode","statusCode--->"+response.statusCode);
String json = null;
if (response != null && response.data != null) {
switch (response.statusCode) {
case 400:
break;
case 401:
json = new String(response.data);
break;
case 502:
json = new String(response.data);
break;
case 200:
json = new String(response.data);
break;
}
progress.dismiss();
}
}
})
{
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/json");
return params;
}
};
req.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 0, 1f));
queue.add(req);
}}
Here the Response coming like string format that is Value OK, please help me to how to get the string response which i have mentioned below.
com.android.volley.ParseError: org.json.JSONException: Value OK of type java.lang.String cannot be converted to JSONObject
How to get this string response by using json object request.
RequestQueue queue = Volley.newRequestQueue(context);
StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
dialog.cancel();
Log.d("response", response);
}catch (Exception e){
volleyResponseCallBack.onFailure("Something went wrong!");
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
String message = null;
dialog.cancel();
if (volleyError instanceof NetworkError) {
message = "Cannot connect to Internet...Please check your connection!";
} else if (volleyError instanceof ServerError) {
message = "The server could not be found. Please try again after some time!!";
} else if (volleyError instanceof AuthFailureError) {
message = "Cannot connect to Internet...Please check your connection!";
} else if (volleyError instanceof ParseError) {
message = "Parsing error! Please try again after some time!!";
} else if (volleyError instanceof NoConnectionError) {
message = "Cannot connect to Internet...Please check your connection!";
} else if (volleyError instanceof TimeoutError) {
message = "Connection TimeOut! Please check your internet connection.";
}
if (!(message == null)) {
Log.d("response", message);
}
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/json");
return params;
}
};
stringRequest.setRetryPolicy(new DefaultRetryPolicy(
0,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
queue.add(stringRequest);
I recently downloaded Visual Studio 2017, on Xamarin I start a new proyect, everything goes Ok, when I try to consume REST Api service, the app dont do the request, I install my nugets on all my proyect in this order:
1. Microsoft build
2. Micrososft.net.http
3. Newtonjson
the app only do the request on UWP app, not in Android app, not in IOS App, Im kind of tired to find this error, I need help
here's the link I took for example: https://www.youtube.com/watch?v=xNP-K37mssA&t=785s in in spanish by the way.
---- JSON OBJECT CLASS--
namespace App1
{
public class WingetResult
{
public int userId { get; set; }
public int id { get; set; }
public string title { get; set; }
public string body { get; set; }
}
}
-----Generic get request-----
namespace App1
{
public class RestClient
{
//Metodo generico para cualquier peticion tipo get
public async Task<T> Get<T>(string url)
{
try
{
HttpClient client = new HttpClient();
var response = await client.GetAsync(url);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var jsonString = await response.Content.ReadAsStringAsync();
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonString);
}
else
{
System.Diagnostics.Debug.WriteLine("else HTTP CLIENT STATUS no es OK");
}
}
catch (Exception e)
{
}
return default(T);
}
}
}
----MAIN PAGE CODE------
namespace App1
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
Device.BeginInvokeOnMainThread(async () => {
RestClient client = new RestClient();
var wingetResult = await client.Get<WingetResult>("https://jsonplaceholder.typicode.com/posts/1");
if (wingetResult != null)
{
label1.Text = wingetResult.title;
}
else {
label1.Text = "no";
}
});
}
}
}
Your issue is with the HTTPS request
i will suggest you to use ModernHttpClient
How to send a file inside JSON to a service?
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json)]
public string Upload(UploadRequest request)
{
return request.FileBytes.Length.ToString();
//return request.FileName;
}
[DataContract]
public class UploadRequest
{
[DataMember]
public int ProfileID { get; set; }
[DataMember]
public string FileName { get; set; }
[DataMember]
public byte[] FileBytes { get; set; }
}
I tried FileBytes as Stream, but received and error: "cannot create instance of an abstract class".
$('#file2').change(function () {
var request =
{
"ProfileID": 1,
"FileName": this.files[0].name,
"FileBytes": this.files[0]
}
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:45039/Files.svc/Upload', true);
xhr.setRequestHeader("Content-type", "application/json");
xhr.onreadystatechange = function (aEvt) {
if (this.readyState == 4) {
if (this.status == 200)
$("#status").html(this.responseText);
else
$("#status").html("Error " + this.status.toString() + ": " + this.responseText);
}
};
xhr.send(JSON.stringify(request));
});
If the file is sent directly (xhr.send(this.files[0]) with Upload(Stream myfile), then WCF converts the posted file to a Stream. Is there a way to do that with the Stream inside the DataContract?
It turns out the answer is yes. You have to define the class as a MessageContract rather than a DataContract with only one property allowed to be a [MessageBodyMember]. The other properties to be [MessageHeader].
WCF will not map multi-part form data to a DataContract or MessageContract. Apparently this is due to WCF not buffering the message body and streaming it instead. The message body could be quite large so that does make sense.