I need help changing the encoding of the response header on .Net Core 1.1.
We're developing an application and we created a custom header called "X-Application-Error" where any error that happens at the backend of the aplication returns a response code 500 and inside the header the message. This way I use the "app.UseExceptionHandler" to catch the errors, put it inside the header, and the front end, if it recieves and response code 500, displays the message sent at the header.
This is working as expected, the trouble that I'm having is that I need to send chacters like "é", "ã" and others, and the default encoding of the header is UTF-8, so it doesn't display those characters.
At the .net framework, we can use the "HttpResponse.HeaderEncoding" Property to change it (https://msdn.microsoft.com/en-us/library/system.web.httpresponse.headerencoding(v=vs.110).aspx)
but I can't find the equivalent for the .Net Core (1.1)
I found a similar question here (C# WebClient non-english request header value encoding) but no answer too.
Ok, I have found a work around (and yes, it seems obvious to me now).
From what I understood .Net Core won't allow characters like "á", "ã" inside a header if they are not encoded. So I just used "WebUtility.UrlEncode(string)" and sent the message encoded. At the FrontEnd, Angular decoded the message automatically. The code is like:
app.UseExceptionHandler(
builder =>
{
builder.Run(
async context =>
{
//Some validations I make
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
try
{
context.Response.Headers.Add("Application-Error", WebUtility.UrlEncode(error.Error.Message));
}catch(Exception e)
{
context.Response.Headers.Add("Application-Error", e.Message);
}
//the rest of the code
}
});
});
Related
When i POST a request to my .net core 2 mvc backend it returns json data.
I want to optionally change the headers as so , which i will then return a csv file of the data for download
'Accept': 'text/csv',
'Content-Type': `text/csv; charset=utf-8`
I set the controller base class with this Produces filter
[Produces("application/json", "text/csv")]
But those headers always cause .net to return 415 Unsupported Media Type
The controller action looks like this
[HttpPost]
public async Task<IActionResult> Post([FromBody] PostArgs args)
You source of problem is Content-Type: text/csv; charset=utf-8 header.
[FromBody] forces MVC middleware to use the input formatter for model binding (I am talking about PostArgs model). And by default, ASP.NET Core registers only one, JSON input formatter. Cause you set Content-Type, middleware cannot use that default formatter (as Content-Type header says that data in request body should be processed as CSV, not JSON) and so it throws 415 Unsupported Media Type error.
... I want to optionally change the headers as so , which i will then return a csv file of the data for download
Actually, it looks like you understand in wrong way what Content-Type header does:
In requests, (such as POST or PUT), the client tells the server what type of data is actually sent.
In other words, you only need to specify the Accept header, cause
The Accept request HTTP header advertises which content types, expressed as MIME types, the client is able to understand. Using content negotiation, the server then selects one of the proposals.
And it is the server then, who uses a Content-Type header in responses to tell the client what the content type of the returned content (in response) actually is.
To return csv data, you return a ContentResult rather than a JsonResult object. This allows you to define the Content-Type:
return new ContentResult("csv-data", "text/csv", 200);
If you want to return a physical file you could return a FileResult object.
By default, the Accepts header isn't enforced. You can enforce it via configuration:
services.AddMvc(config =>
{
config.RespectBrowserAcceptHeader = true;
});
In order to accept additional formats, you'll also need to add InputFormatters:
services.AddMvc(config =>
{
config.RespectBrowserAcceptHeader = true;
config.InputFormatters.Add(new TextInputFormatter())
config.OutputFormatters.Add(new StringOutputFormatter());
});
Considering that in my Zend Framework module I'm able to access via browser or REST. When I got a 404 via REST, this is the content:
{"httpStatus":404,"title":"Not Found"}
So how do I test this response using PHPUnit?
I have already a test for another route that is working:
public function testIndexActionCanBeAccessed()
{
$this->dispatch('/ws/dashboard');
$this->assertResponseStatusCode(200);
$this->assertModuleName('Ws');
$this->assertControllerName('Ws\Controller\Dashboard');
$this->assertControllerClass('DashboardController');
$this->assertMatchedRouteName('application/ws');
}
But I don't know how to do this other case.
public function testIndexActionCanBeAccessed()
{
$this->dispatch('/ws/asd');
$this->assertResponseStatusCode(404); // this is OK
// but how check the json response?
}
Also, if I do this $response = $this->getResponse(); I got the entire HTML 404 html file, which is not what I want.
You may want to check to ensure that the controller is actually returning a JSON response.
Also, your Accept header for the AJAX request should specify application/json.
I am trying to replace a Jetty-based back-end by a pure spray-can + spray-routing one.
The front-end posts JSON content using the text/json media type. I've never had any problems with this with Jetty. I have just realized that it is not a standard type thanks to spray, which only accepts the correct and standard application/json media type.
Is there any easy way to map one to the other at the server side? I would really like to avoid having to introduce an ad-hoc release of the client side of the application to deal with this. Of course, I will make the change for the next scheduled release, but for now I need a "quick and dirty" fix.
I have tried changing the header from text/json to application/json using the following function:
def correctJsonHeaders(req:spray.http.HttpRequest) = {
val tweakedHeaders = req.headers.map{ hdr =>
if(hdr.name == "Content-Type" && hdr.value == "text/json")
`Content-Type`(`application/json`)
else
hdr
}
req.copy(headers = tweakedHeaders)
}
in my route directive, like so:
path("route"){
mapRequest(correctJsonHeaders){
post{
respondWithMediaType(`application/json`) {
handleWith{ x:TypeThatUnmarshallsFromJson =>
bizLogicReturningAJsonString(x)
}
}
}
}
}
Although the header is correctly changed, I still get a 415 error (which goes away if I change the media type to application/json at the client)
After reading the documentation on the spray-http Content-Type Header, I changed my function to:
def correctJsonHeaders(req:spray.http.HttpRequest) = {
if(req.headers.exists(hdr => hdr.name == "Content-Type" && hdr.value == "text/json")){
val tweakedEntity = spray.http.HttpEntity(`application/json`, req.entity.data)
req.copy(entity = tweakedEntity)
}
else req
}
which seems to work. The trick was to change the HttpEntity, instead of the header.
The lack of support for custom Accept and Content-Type headers is caused by the implementation of the JSON marshaller you use. Have a look at the source code of these traits to see where this happens:
spray.httpx.LiftJsonSupport
spray.httpx.Json4sJacksonSupport
spray.httpx.PlayJsonSupport
spray.httpx....
Simply solve this by implementing your own PlayJsonSupport trait and add your custom MediaType and ContentType to the two delegate functions. We needed this as well because we put our vendor version in our accept headers to support versioning on our REST services.
Am currently communicating to a Mobile device using Windows Compact Framework 3.5. The message sent to the device is built is as thus,
HttpResponseMessage result;
var response = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"windows-1252\"?><message type=\"response\"><header><datetime>2013-04-03T09:49:35</datetime><sender version=\"1.1.4.1138\"><userid>Connect Server</userid></sender><commandlist><module>ADMIN</module><command1>VALIDATE</command1></commandlist><result type=\"ok\"/></header></message>");
result = Request.CreateResponse(HttpStatusCode.OK, response);
The device then retrieves the message and then uses
Encoding.UTF8.GetString(responseContent);
After decoding the message is:
<base64Binary xmlns="http://schemas.microsoft.com/2003/10/Serialization/">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0id2luZG93cy0xMjUyIj8+PG1lc3NhZ2UgdHlwZT0icmVzcG9uc2UiPjxoZWFkZXI+PGRhdGV0aW1lPjIwMTMtMDQtMDNUMDk6NDk6MzU8L2RhdGV0aW1lPjxzZW5kZXIgdmVyc2lvbj0iMS4xLjQuMTEzOCI+PHVzZXJpZD5Db25uZWN0IFNlcnZlcjwvdXNlcmlkPjwvc2VuZGVyPjxjb21tYW5kbGlzdD48bW9kdWxlPkFETUlOPC9tb2R1bGU+PGNvbW1hbmQxPlZBTElEQVRFPC9jb21tYW5kMT48L2NvbW1hbmRsaXN0PjxyZXN1bHQgdHlwZT0ib2siLz48L2hlYWRlcj48L21lc3NhZ2U+</base64Binary>
Tried decoding the message on the server before sending it off and it's fine. Unsure what could be going wrong.
Any help would be greatly appreciated.
Request.CreateResponse() uses ObjectContent. For this scenario, you don't want that. You should use either StringContent or StreamContent to return the XML. See this question for details https://stackoverflow.com/a/15372410/6819
You are encoding your XML as binary. You are then returning a byte array. Then your client requests XML in the Accept: application/xml header. The Web API serializes the binary into XML. That's what you're seeing.
Just return the XML as a string and you should have no problems, unless you've tried that already?
See here for similar question.
I am making a POST request with RestSharp (on windows phone 7.1 client). I sent string to a service in a request body. Looks like the service is successfully called and it returns proper value (integer), however response object is null:
client.ExecuteAsync<T>(request, (response) => {
data = response.Data; // response is null in debugger
});
I cant understand why is that so.
<T> isn't a valid value for that call. I'm not sure that would even build there unless you've wrapped it in a generic method.
Also, is the response coming back as plain text? What's the Content-Type returned? Most likely, you should just use ExecuteAsync(request, callback) without the generic parameter and grab the data out of response.Content which is a string of the response body. response.Data is for the automatically deserialized XML or JSON (or custom) response if you use the generic method overload that specifies a type to deserialize to.
This seems to be an ongoing issue with RestSharp asynchronous calls - for HTTP transport errors ErrorException object is useless (returns null). Check the StatusCode property if it returns with anything but HttpStatusCode.OK. StatusDescription is not extremely useful either as it doesn't match complete status message from server response payload.