I'm using GWT RPC to communicate between client and server.
I want to be able to read the browser's date on the server side, and for that I'm using setRpcRequestBuilder from the class ServiceDefTarget to costumize my request, and add the header I want.
On the client side I'm using:
private static final RpcRequestBuilder rpcReqBuilder = new RpcRequestBuilder() {
#Override
protected RequestBuilder doCreate(String serviceEntryPoint) {
RequestBuilder builder = super.doCreate(serviceEntryPoint);
builder.setHeader("Date1", new Date().toString());
return builder;
}
};
......
((ServiceDefTarget) greetingService).setRpcRequestBuilder(rpcReqBuilder);
//rpc call
greetingService.greetServer(.........)
On the server side I do:
HttpServletRequest request = this.getThreadLocalRequest();
Enumeration<?> enumeration = request.getHeaderNames();
while (enumeration.hasMoreElements()) {
String name = (String) enumeration.nextElement();
String value = request.getHeader(name);
System.out.println(name + ": " + value);
}
which among all the default headers prints
Date1: Tue Apr 10 12:19:28 BST 2012
Ok, this works fine, but when I try to set the "Date" header, then it doesn't show up on the server side. Why is that? Anybody can help. I'll be very helpfull. :)
Date is a predefined header of HTTP, and by definition, XMLHttpRequest (the thing behind GWT's RequestBuilder) cannot let you set it to an arbitrary value.
Anyway, when crafting your own headers, you should add a prefix to avoid conflicts with other things on the network adding headers, something like MyApp-Date or X-MyApp-Date (like GWT does it with X-GWT-Permutation and X-GWT-Module-Base in GWT-RPC and RequestFactory)
Related
If one omits the Accept header in a request to an Asp.Net web API the server will return (415) Unsupported Media Type
I am looking for a way to force the API to assume a default return type (in my case, application/json) when the request does not contain an Accept value in its headers.
After a substantial amount of reading and searching, I'm not sure this is even possible?
You can force the framework to use XML formatter when HTTP Accept header is missing, by doing the following trick:
var jsonFormatter = config.Formatters.JsonFormatter;
config.Formatters.Remove(config.Formatters.JsonFormatter);
config.Formatters.Add(jsonFormatter);
This way the JSON formatter will be the second registered formatter in the list, and the XML will be the first one.
This is content negotiator resposibility to choose the right formatter to serialize the response object. But by default WebApi framework gets JsonFormatter if could not find appropriate formatter.
If there are still no matches, the content negotiator simply picks the first formatter that can serialize the type.
So it is strange behavior. Anyway you could set up custom content negotiator to choose explicit JsonFormatter if request does not have Accept header.
public class JsonContentNegotiator : DefaultContentNegotiator
{
protected override MediaTypeFormatterMatch MatchAcceptHeader(IEnumerable<MediaTypeWithQualityHeaderValue> sortedAcceptValues, MediaTypeFormatter formatter)
{
var defaultMatch = base.MatchAcceptHeader(sortedAcceptValues, formatter);
if (defaultMatch == null)
{
//Check to find json formatter
var jsonMediaType = formatter.SupportedMediaTypes.FirstOrDefault(h => h.MediaType == "application/json");
if (jsonMediaType != null)
{
return new MediaTypeFormatterMatch(formatter, jsonMediaType, 1.0, MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral);
}
}
return defaultMatch;
}
}
And replace in HttpConfiguration object
config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator());
I'm trying to pass data via post method from my client to a server.
I'm using WebApi to do so.
This i the code i used:
client:
var client = new RestClient();
client.EndPoint = #"http://localhost:57363/hello";
client.Method = HttpVerb.POST;
client.PostData = "{value: Hello}";
var json = client.MakeRequest();
Console.WriteLine(json);
Console.Read();
server:
// POST api/<controller>
public string Post([FromBody]string value)
{
return value + ", world.";
}
The server responds as expected when using postman. However, the client passes a null value instead of the real value.
What am i doing wrong?
First of all a correct json would look like "{value: 'Hello'}".
I use json-online to easily validate such inline json.
On the other hand, I think that you should send just the value in this case, not the entire json (because you are trying to resolve a simple type,a string), so the client should send a request like:
client.PostData = "'Hello'";
I'm using the Advanced Rest Client Chrome extension to test a request to a Web API 2 endpoint. I'm trying to include a value in the "From" header but the value is null when it is not a valid email address. By reading the spec, it looks like it only SHOULD be a valid email address, not that it MUST. Is this something that is happening because of Web API, Chrome, the extension, or something else?
After your comment about Fiddler seeing the header, I was curious so I did a little test. Here is my controller code:
public class FromController : ApiController
{
[Route("api/from")]
public dynamic Get()
{
string from1 = null;
string from2 = null;
string from3 = null;
from1 = this.Request.Headers.From;
IEnumerable<string> headers;
if (this.Request.Headers.TryGetValues("From", out headers))
{
from2 = headers.FirstOrDefault();
}
if (HttpContext.Current.Request.Headers.AllKeys.Contains("From"))
{
from3 = HttpContext.Current.Request.Headers["From"];
}
var output = new
{
From1 = from1,
From2 = from2,
From3 = from3
};
return output;
}
}
Test 1: Send e#test.com as the From header outputs:
{
"From1": "e#test.com",
"From2": "e#test.com",
"From3": "e#test.com"
}
Everything is as expected.
Test 2: Send junk as the From header outputs:
{
"From1": null,
"From2": "junk",
"From3": "junk"
}
This shows your findings of the header being null, but you can get it via the other methods.
Internally it's running some parsing on the values. The value is stored in an invalid container so asking for it directly results in null. By asking via TryGetValue, it ignores any "helpful" parsing so you'll get the value.
I added the old HttpContext.Current.Request just to see since this is more raw form, but I'd steer clear from using this in production and try to stick with this.Request for anything while in a Controller. I like to use HttpContext.Current.Request.SaveAs(fileName, true) to see what the actual raw request is. I did this first and saw the header so I knew it had to be accessible somehow.
I created a custom dispatcher to handle versioning that uses a customer media type. It looks something like this:
application/vnd.mycompany.myapi-v1+json
The extraction of the version number in order to select the correct controller is all up and working, but being new to MVC, I am not sure how to set the response format. What we want to do is set the response format to match the request. So in this example, the response will be in json. Now I assume I'm going to have to extract that from this content type as well which is fine, but could someone give me an example of how i set the response format of this request in MVC4 assuming I have already created the method which will extract the format as a string?
private string GetResponseFormat(){
//some shennanigans here
}
P.S. the reason for not having the client use the accept header during the request is that there are already clients out there that are using our old service which would set the accept header to match the request.
You can also use Content method to return custom response type:
string responseType = GetResponseFormat();
...
switch(responseType){
case "json":
string json = "yourJSON";
return Content(json, "application/json");
case "xml":
string xml = "yourXML";
return Content(xml, "text/xml");
default:
string plaintxt = "yourPlaintext";
return Content(plaintxt, "text/plain"):
}
I was able to clear the existing Accept header and add to it:
private void SetResponseFormatToRequestFormat(HttpRequestMessage request)
{
// figure out what the request format was
_contentTypeHeader = request.Content.Headers.ContentType.ToString();
if(_contentTypeHeader.Contains("xml")) _contentType = "application/xml";
if (_contentTypeHeader.Contains("json")) _contentType = "application/json";
// set response format to the same as the request format
request.Headers.Accept.Clear();
request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(_contentType));
}
In order to support a legacy application that's in the field, I need my ASP.NET MVC app to return an empty response that also has a Content-Type. One of IIS, ASP.NET, or ASP.NET MVC is removing my Content-Type when I send back a null response. Is there any way around this?
(While not requiring an empty response with a set Content-Type would obviously be the ideal solution, the clients are already out there, and many of them cannot be upgraded.)
EDIT: Since there was a request for code: I'm proxying the request from the new web application to the one that older clients rely on. To do this, I have a subclass of ActionResult, called LegacyResult, that you can simply return for those methods that need to be handled by the old software. This is the relevant part of its code:
public override void ExecuteResult(ControllerContext context)
{
using (var legacyResponse = GetLegacyResponse(context))
{
var clientResponse = context.HttpContext.Response;
clientResponse.Buffer = false;
clientResponse.ContentType = legacyResponse.ContentType; /* Yes, I checked that legacyResponse.ContentType is never string.IsNullOrEmpty */
if (legacyResponse.ContentLength >= 0) clientResponse.AddHeader("Content-Length", legacyResponse.ContentLength.ToString());
var legacyInput = legacyResponse.GetResponseStream();
using (var clientOutput = clientResponse.OutputStream)
{
var rgb = new byte[32768];
int cb;
while ((cb = legacyInput.Read(rgb, 0, rgb.Length)) > 0)
{
clientOutput.Write(rgb, 0, cb);
}
clientOutput.Flush();
}
}
}
If legacyInput has data, then Content-Type is set appropriately. Otherwise, it's not. I can actually kluge the old backend to send an empty v. non-empty response for exactly the same request, and observe the difference in Fiddler.
EDIT 2: Poking around with Reflector reveals that, if headers have not been written at the time that HttpResponse.Flush is called, then Flush writes out the headers itself. The problem is that it only writes out a tiny subset of the headers. One of the missing ones is Content-Type. So it seems that, if I can force headers out to the stream, I can avoid this problem.
You have to trick the response into writing the headers, by falsely telling it there's content, then suppressing it:
/// [inside the writing block]
var didWrite = false;
while ((cb = legacyInput.Read(rgb, 0, rgb.Length)) > 0)
{
didWrite = true;
clientOutput.Write(rgb, 0, cb);
}
if (!didWrite)
{
// The stream needs a non-zero content length to write the correct headers, but...
clientResponse.AddHeader("Content-Length", "1");
// ...this actually writes a "Content-Length: 0" header with the other headers.
clientResponse.SuppressContent = true;
}