Getting No Response When Calling WebAPI Post with application/json header - asp.net-web-api

I've got a very simple WebAPI controller (all system defaults) and when I do a post to it, the fact that it has Content-Type: application/json makes the post (from fiddler) hang (not return).
My headers are as follows:
Content-Length: 2
Content-Type: application/json
and the post body is simply
[]
My WebAPI controller just looks like this:
namespace WebAPI.rest
{
public class SendGridController : ApiController
{
public HttpResponseMessage Post()
{
try
{
HttpContent requestContent = Request.Content;
string json = requestContent.ReadAsStringAsync().Result.Trim();
}
catch (Exception ex)
{
throw ex;
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
When I make the same post (with fiddler) to http://respondto.it/ it returns no problem

If you are running under ASP.NET the the .Result is probably not a wise idea. I ran your code under self-host and it worked fine.
Try this,
public class SendGridController : ApiController
{
public async Task<HttpResponseMessage> Post()
{
try
{
HttpContent requestContent = Request.Content;
string json = await requestContent.ReadAsStringAsync();
}
catch (Exception ex)
{
throw ex;
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
}

The problem turned out to be an old version of webapi. Once I updated to webapi2, the problem went away.

Related

Model Binder Not Finding Post Data

I have a simple jquery post
function saveImage(base64) {
$.post("http://localhost:50575/api/images", {base64Data: base64});
}
That is going against a .net core controller
[HttpPost]
public async Task<ActionResult> Post(string base64Data)
{
var base64 = Request.Form["base64Data"];
return Ok();
}
When the data is posted, base64Data is null. However, base64, which is populated from the form variables has a value.
Is there any reason why this shouldn't work?
What sent by $.post("http://localhost:50575/api/images", {base64Data: base64}) is:
POST /api/images HTTP/1.1
Content-Type: application/x-www-form-urlencoded
base64Data=xxxxxxxx
Since you send the request with a content-type of application/x-www-form-urlencoded and have the request processed by a ApiController , you should decorate the parameter with a [FromForm]
public async Task<ActionResult> Post([FromForm] string base64Data)
{
// ...
}
Or if you would like to send the request encoded with application/json , you should firstly create a DTO to hold the whole playload :
public class Base64Dto{
public string Base64Data{get;set;}
}
and decorate the parameter with a [FromBody] at the same time :
public async Task<ActionResult> Post([FromBody] Base64Dto base64Data)
{
// var base64 = Request.Form["base64Data"];
return Ok();
}
Another way to hold the whole payload with Base64Dto , is to send the request with a header of Content-Type: application/x-www-form-urlencoded , and use a [FromForm] attribute at the same time :
public async Task<ActionResult> Post([FromForm] Base64Dto base64Data)
{
// var base64 = Request.Form["base64Data"];
return Ok();
}

How to do content based dynamic routing in zuul?

I am working on a micro-services based architecture which includes Spring-Boot, Eureka, Zuul at key level. My problem is as follows:
Service1 : /api/v1/service1 POST
Service2 : /api/v2/service2 POST
application.yml looks like
zuul:
routes:
service1:
path: /api/v1/**
service2:
path: /api/v1/**
common:
path: /common/endpoint
Also I have written a filter where I am trying to take input via this common endpoint and deduct based on post request where to enroute the request i.e. to service1 or service2. But here I am stuck and nothing seems to work out, even after several google searches and checking out other people's problem I am not yet able to found my solution.
here is how my Filter looks like:
public class CommonEndpointFilter extends ZuulFilter {
#Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
if ((ctx.get("proxy") != null) && ctx.get("proxy").equals("common")) {
return true;
}
return false;
}
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
InputStream in = (InputStream) ctx.get("requestEntity");
if (in == null) {
try {
in = request.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
String body = null;
try {
body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
if (body.indexOf("somethingrelatedtoservice1") != -1) {
//forward the request to Service1: /api/v1/service1
} else if (body.indexOf("somethingrelatedtoservice2") != -1) {
//forward the request to Service2: /api/v1/service2
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public String filterType() {
return FilterConstants.ROUTE_TYPE;
}
#Override
public int filterOrder() {
return 0;
}
}
I am not able to figure out how to forward the request further to those services and then obtain response to send back via common endpoint.
What am I doing wrong here ? How can I proceed so I don't have to use hardcoded url of any of the service. Please guide me through this.
I have tried out some of the things like:
1. using DiscoveryClient to obtain instance and use setRouteHost method of context. It always throws a zuulfilter exception URL is not proper common/endpoint is appended after the url of service obtained via DiscoveryClient.
2. I tried stupidest thing that came to mind, using RestTemplate to make a request and obtain response and put that in context response which didn't work either, however request was forwarded to the service but I wouldn't receive any response.
Any help is appreciated!!

Why this externa web service call go into error only when the call is performed using Spring RestTemplate?

I am working on a Spring project implementing a simple console application that have to call an external REST web service passing to it a parameter and obtaining a response from it.
The call to this webservice is:
http://5.249.148.180:8280/GLIS_Registration/6
where 6 is the specified ID. If you open this address in the browser (or by cURL tool) you will obtain the expected error message:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<sampleid>IRGC 100000</sampleid>
<genus>Oryza</genus>
<error>PGRFA sampleid [IRGC 100000], genus [Oryza] already registered for this owner</error>
</response>
This error message is the expected response for this request and I correctly obtain it also using cURL tool to perform the request.
So I have to perform this GET request from my Spring application.
To do it I create this getResponse() method into a RestClient class:
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RestClient {
RestTemplate restTemplate;
String uriResourceRegistrationApi;
public RestClient() {
super();
restTemplate = new RestTemplate();
uriResourceRegistrationApi = "http://5.249.148.180:8280/GLIS_Registration/7";
}
public ResponseEntity<String> getResponse() {
ResponseEntity<String> response = restTemplate.getForEntity(uriResourceRegistrationApi, String.class);
return response;
}
}
Then I call this method from this test method:
#Test
public void singleResourceRestTest() {
System.out.println("singleResourceRestTest() START");
ResponseEntity<String> result = restClient.getResponse();
System.out.println("singleResourceRestTest() END");
}
But I am experiencing a very strange behavior, what it happens is:
1)The call to my external web service seems that happens (I saw it from the web services log).
2) The web service retrieve the parameter having value 7 but then it seems that can't use it as done without problem performing the request from the browser or by the shell statment:
curl -v http://5.249.148.180:8280/GLIS_Registration/7
But now, calling in this way, my webservice (I can't post the code because it is a WSO2 ESB flow) give me this error message:
<200 OK,<?xml version="1.0" encoding="UTF-8"?>
<response>
<error>Location information not correct</error>
<error>At least one between <genus> and <cropname> is required</error>
<error>Sample ID is required</error>
<error>Date is required</error>
<error>Creation method is required</error>
</response>,{Vary=[Accept-Encoding], Content-Type=[text/html; charset=UTF-8], Date=[Fri, 05 May 2017 14:07:09 GMT], Transfer-Encoding=[chunked], Connection=[keep-alive]}>
Looking the web service log it seems that performing the call using RestTemplate it have some problem to use the retrieved ID=7 to perform a database query.
I know it looks terribly strange and you can see: "The problem is of your web service and not of the Spring RestTemplate". This is only partially true because I implemented this custom method that perform a low level Http GET call, this callWsOldStyle() (putted into the previous RestClient class):
public void callWsOldStyle() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL restAPIUrl = new URL("http://5.249.148.180:8280/GLIS_Registration/7");
connection = (HttpURLConnection) restAPIUrl.openConnection();
connection.setRequestMethod("GET");
// Read the response
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder jsonData = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
jsonData.append(line);
}
System.out.println(jsonData.toString());
}catch(Exception e) {
e.printStackTrace();
}
finally {
// Clean up
IOUtils.closeQuietly(reader);
if(connection != null)
connection.disconnect();
}
}
Using this method instead the RestTemplate one it works fine and this line:
System.out.println(jsonData.toString());
print the expected result:
<?xml version="1.0" encoding="UTF-8"?><response><sampleid>IRGC 100005</sampleid><genus>Oryza</genus><error>PGRFA sampleid [IRGC 100005], genus [Oryza] already registered for this owner</error></response>
To summarize:
Calling my WS from the browser it works.
Calling my WS using cURL it works.
Calling my WS using my callWsOldStyle() method it works.
Calling my WS using the method that use RestTemplate it go into error when my WS receive and try to handle the request.
So, what can be the cause of this issue? What am I missing? Maybe can depend by some wrong header or something like this?
As Pete said you are receiving an internal server error (status code 500) so you should check the server side of this rest service.
In any case you can do the following for the resttemplate
create an org.springframework.web.client.RequestCallback object if
you need to do something in the request
create an org.springframework.web.client.ResponseExtractor<String>
object in order to extract your data
use the resttemplate
org.springframework.web.client.RequestCallback
public class SampleRequestCallBack implements RequestCallback
{
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException
{
}
}
org.springframework.web.client.ResponseExtractor
public class CustomResponseExtractor implements ResponseExtractor<String>
{
private static final Logger logger = LoggerFactory.getLogger(CustomResponseExtractor.class.getName());
#Override
public String extractData(ClientHttpResponse response) throws IOException
{
try
{
String result = org.apache.commons.io.IOUtils.toString(response.getBody(), Charset.forName("UTF8"));
if( logger.isInfoEnabled() )
{
logger.info("Response received.\nStatus code: {}\n Result: {}",response.getStatusCode().value(), result);
}
return result;
}
catch (Exception e)
{
throw new IOException(e);
}
}
}
REST TEMPLATE CALL
#Test
public void testStack()
{
try
{
String url = "http://5.249.148.180:8280/GLIS_Registration/6";
String response = restTemplate.execute(url, HttpMethod.GET, new SampleRequestCallBack(), new CustomResponseExtractor());;
logger.info(response);
}
catch (Exception e)
{
logger.error("Errore", e);
}
}
Angelo

How to return xml or json with ASP.NET web mvc 6 depending on Accept Header

I have implemented a web api controller using ASP.NET mvc 6 and I would like to return the result of the controller as json or xml, depending on the client's Accept header. For example, if the client sends a GET request with "Accept: application/xml", then the returned response should be xml. If the header is "Accept: application/json", then it should be json. At the moment the controller always returns json. Is there a way of configuring this? Note: this question is indeed a duplicate of How to return XML from an ASP.NET 5 MVC 6 controller action. However the solution provided there did not solve my problem. The accepted answer below worked for me.
The controller is given below and is the one provided by the ASP.NET 5 web api template:
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET: api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id:int}")]
public string Get(int id)
{
return "value";
}
// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
Thanks for your help!
I did the research for you, you may continue alone:
needed:
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.Core": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-rc1-final"
startup:
services.Configure<MvcOptions>(options =>
{
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
});
go on from here
another
and antoher

Get current Uri when redirected in WebClient wp7

I hope that I won't start a topic that's done already but I didn't find any proper answer here nor anywere else.
So here we go:
I use a WebClient to download HTML Code from a webpage, then I send a new request with that WebClient and the WebPage redirects me. Now I want to now where the Site has put me.
The WebClient Class itself doesn't have any suitable properties, I already tried to rewrite the class so that I could get the Response URI but somehow it doesn't work for wp7.
So any ideas how to get the URI where my WebClient got redirected? Or any idea why the application crashes when I want to use my own class:
public class MyWebClient : WebClient
{
Uri _responseUri;
public Uri ResponseUri
{
get { return _responseUri; }
}
protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
{
WebResponse response = base.GetWebResponse(request, result);
_responseUri = response.ResponseUri;
return response;
}
}
}
Thanks in advance!
HttpWebRequest is the solution here, since WebClient is a wrapper around it anyway. Something like this should work for your specific situation:
private HttpWebRequest request;
private bool flagIt = true;
public MainPage()
{
InitializeComponent();
request = (HttpWebRequest)WebRequest.Create("http://google.com");
request.BeginGetResponse(new AsyncCallback(GetData), request);
}
public void GetData(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
Debug.WriteLine(response.ResponseUri.ToString());
if (flagIt)
{
request = (HttpWebRequest)WebRequest.Create("http://microsoft.com");
request.BeginGetResponse(new AsyncCallback(GetData), request);
flagIt = false;
}
}
I am initiating the request in the main page constructor and then I am handling it in the callback. Notice how I am getting the ResponseUri - your final destination.
You don't need to handle AllowAutoRedirect if you don't want blocking the redirect and simply getting the URL, like I am doing in the snippet above.

Resources