Why is my HttpWebRequest POST method to my WebAPI server failing? - post

I've successfully received data from my WebAPI project ("GET"), but my attempt to Post is not working. Here is the relevant server/WebAPI code:
public Department Add(Department item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
departments.Add(item);
return item;
}
...which fails on the "departments.Add(item);" line, when this code from the client is invoked:
const string uri = "http://localhost:48614/api/departments";
var dept = new Department();
dept.Id = 8;
dept.AccountId = "99";
dept.DeptName = "Something exceedingly funky";
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "POST";
var deptSerialized = JsonConvert.SerializeObject(dept); // <-- This is JSON.NET; it works (deptSerialized has the JSONized versiono of the Department object created above)
using (StreamWriter sw = new StreamWriter(webRequest.GetRequestStream()))
{
sw.Write(deptSerialized);
}
HttpWebResponse httpWebResponse = webRequest.GetResponse() as HttpWebResponse;
using (StreamReader sr = new StreamReader(httpWebResponse.GetResponseStream()))
{
if (httpWebResponse.StatusCode != HttpStatusCode.OK)
{
string message = String.Format("POST failed. Received HTTP {0}", httpWebResponse.StatusCode);
throw new ApplicationException(message);
}
MessageBox.Show(sr.ReadToEnd());
}
...which fails on the "HttpWebResponse httpWebResponse = webRequest.GetResponse() as HttpWebResponse;" line.
The err msg on the server is that departments is null; deptSerialized is being populated with the JSON "record" so...what is missing here?
UPDATE
Specifying the ContentType did, indeed, solve the dilemma. Also, the StatusCode is "Created", making the code above throw an exception, so I changed it to:
using (StreamReader sr = new StreamReader(httpWebResponse.GetResponseStream()))
{
MessageBox.Show(String.Format("StatusCode == {0}", httpWebResponse.StatusCode));
MessageBox.Show(sr.ReadToEnd());
}
...which shows "StatusCode == Created" followed by the JSON "record" (array member? term.?) I created.

You forgot to set the proper Content-Type request header:
webRequest.ContentType = "application/json";
You wrote some JSON payload in the body of your POST request but how do you expect the Web API server to know that you sent JSON payload and not XML or something else? You need to set the proper Content-Type request header for that matter.

Related

Call WebApi method, Error 404 Not Found

Im having a problem with a WebMethod MVC
This is the method in the controller
[HttpPost]
public IHttpActionResult GetData(int Company,
int FromYear,int ToYear, int language ,
int DATA_SERIES_TYPE, bool PERIOD_Q1)
{
var ds = new DataSet();
try
{
ds = Actions.GetValues(Company, FromYear, ToYear,DATA_SERIES_TYPE);
return Ok(ds);
}
catch(Exception ex)
{
return InternalServerError(ex);
}
}
I have this method in an API, when i call the api from another project using webrequest
Dim Request As WebRequest = WebRequest.Create("http://localhost/PBWebApi/api/GetData")
With strJson
.Append("{")
.Append($"Company:{_dynaSolver.CompanyCode.ToString()}" & ",")
.Append($"FromYear:{_dynaSolver.FromYear.ToString}" & ",")
.Append($"ToYear:{_dynaSolver.ToYear.ToString}" & ",")
.Append($"language:{CType(_dynaSolver.DataLanguage, Integer).ToString}" & ",")
.Append($"DATA_SERIES_TYPE:{ CType(_dynaSolver.Fundamentals, Integer).ToString}")
.Append("}")
End With
Dim data = Encoding.UTF8.GetBytes(strJson.ToString)
With Request
.Method = "POST"
.ContentType = "application/json; charset=utf-8"
.ContentLength = data.Length
End With
Dim stream = Request.GetRequestStream()
stream.Write(data, 0, data.Length)
stream.Close()
Dim response = Request.GetResponse().GetResponseStream
Dim reader As StreamReader = New StreamReader(response)
Dim res = reader.ReadToEnd()
dsRes = JsonConvert.DeserializeObject(Of DataSet)(res)
reader.Close()
response.Close()
When i execute this, the response gives this error.
No HTTP resource was found that matches the request URI
I tried using just one parameter in another function but i got the same result.
I tried using fiddler but i got the same error.
I fixed the problem creating and object called id and adding all the properties to that object.
After that i send the object as json in the content and it works.
Regards

Create to database using web api

I am trying to insert a new entry in my database using web api. I have two web projects: one is a UI project where all the user interaction will occur and the other is a services project which will handle all interactions with my database.
Below is my post method that will take in form data for creating a new team.
// POST: Api/Team/Create
[HttpPost]
public ActionResult Create(Team team)
{
try
{
if (ModelState.IsValid)
{
HttpEndPointContext httpEndPoint = new HttpEndPointContext()
{
AuthenticationMethod = HttpAuthenticationMethods.None,
Ssl = false,
HttpMethod = HttpMethod.Post,
Path = "localhost:32173/api/team/",
QueryStrings = null,
PayloadData = SerializationHelper.Current.Serialize(team.ToString(), SerializationTypes.Xml)
};
IProcessResult result = HttpConnectionManager.Current.SendMessage(httpEndPoint);
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
And this is my method for dealing with my PayloadStream/PayloadData attribute in the above method:
private void StreamPayload(HttpWebRequest webRequest, HttpEndPointContext httpEndPointContext)
{
if (httpEndPointContext.HttpMethod == new HttpMethod("GET"))
return;
//TODO: FIX MAYBE .... sometimes we want to post body with GET.
//Stream vs string
if (httpEndPointContext.PayloadStream == null)
{
//Wrap with SOAP Envelope and method if defined in SoapDefinition
string data = httpEndPointContext.PayloadData ?? String.Empty;
if (httpEndPointContext.SoapDefinition != null)
{
//If parameters is set, clear existing payload data.
data = String.Empty;
if (httpEndPointContext.SoapDefinition.Parameters != null)
foreach (var parameter in httpEndPointContext.SoapDefinition.Parameters)
{
data += String.Format("<{0}>{1}</{0}>", parameter.Key, parameter.Value);
}
data = String.Format("<s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'>" +
"<s:Body><{0} xmlns='{2}'>" +
"{1}</{0}></s:Body></s:Envelope>",
httpEndPointContext.SoapDefinition.SoapMethod, data,httpEndPointContext.SoapDefinition.SoapGlobalKey);
}
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(data);
httpEndPointContext.PayloadStream = new MemoryStream(byteArray);
}
using (Stream requestStream = webRequest.GetRequestStream())
{
StreamHelper.Current.CopyStreams(httpEndPointContext.PayloadStream, requestStream);
requestStream.Close();
}
}
And the code for getting the server response. I'm currently getting an Internal Server (500) Error. Not sure why.
public IProcessResult SendMessage(HttpEndPointContext httpEndPointContext)
{
HttpWebRequest webRequest = CreateWebRequest(httpEndPointContext);
StreamPayload(webRequest, httpEndPointContext);
IProcessResult result = GetWebResponse(webRequest, httpEndPointContext);
return result;
}
private IProcessResult GetWebResponse(HttpWebRequest webRequest, HttpEndPointContext httpEndPointContext)
{
//Get Response
WebResponse response;
IProcessResult result = new ProcessResult(Statuses.Success);
try
{
response = webRequest.GetResponse();
}
catch (System.Net.WebException ex)
{
//Do exception handling. Still get the response for 500s etc.
result.Error.Exception = ex;
result.Status = Constants.Statuses.FailedUnknown;
result.ResponseCodeDescription = ex.Status.ToString();
result.ResponseCode = ex.Status.ToString();
result.Error.ErrorCode = ex.Status.ToString();
response = ex.Response;
//The error did not have any response, such as DNS lookup.
if (response == null)
return result;
}
try
{
//Get the response stream.
Stream responseData = response.GetResponseStream();
if (responseData == null)
throw new CoreException("No Response Data in GetWebResponse.",
"No Response Data in GetWebResponse. EndPoint:{0}", httpEndPointContext.ToString());
// Open the stream using a StreamReader for easy access.
var reader = new StreamReader(responseData);
// Read the content.
result.ResponseData = reader.ReadToEnd();
}
finally
{
response.Close();
}
result.ResponseCode = ((int)((HttpWebResponse)response).StatusCode).ToString();
result.ResponseCodeDescription = ((HttpWebResponse) response).StatusDescription;
return result;
}
And finally, my method for inserting to the database, found in my services project:
//POST api/controller/5
public IProcessResult Insert(Team team)
{
return TeamBusinessManager.Current.Insert(SecurityManager.Current.ConnectionContext, new Team());
}
I'm confused as to why I'm getting the 500 error. I'm not sure if it's the PayloadData attribute in my POST method or is it something wrong with my method in my services project.

Pass through the HTTP response to the client in MVC 6

I am new to Web API and HTTP.
I am using the MVC 6 (beta version). I have a proxy service (Web API) which has a POST method to get response from another service with XML content returned. I need to return the response content to the client since the client can't call the service directly.
// In my proxy service
public HttpResponseMessage Post(String content)
{
using ( HttpClient client = new HttpClient() ) {
.......
HttpResponseMessage response = client.PostAsync(uri, content).Result;
// I get everything I need in the "response".
// How to return the response or it body to the client.
// return response;
}
}
II need to return the "response" to the client with no or minimum changes. I tried "return response", or create a new HttpResponseMessage, but I only got something like
{"Headers":[{"Key":"Content-Type","Value":["text/xml"]}]}
in the body.
So is there a simple way to pass the response back to the client? Thanks.
The ASP.NET team is currently working on a "proxy middleware" that does exactly what you're looking for: https://github.com/aspnet/Proxy
Here's how it works internally:
public async Task Invoke(HttpContext context)
{
var requestMessage = new HttpRequestMessage();
if (string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
{
var streamContent = new StreamContent(context.Request.Body);
requestMessage.Content = streamContent;
}
// Copy the request headers
foreach (var header in context.Request.Headers)
{
if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value) && requestMessage.Content != null)
{
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
requestMessage.Headers.Host = _options.Host + ":" + _options.Port;
var uriString = $"{_options.Scheme}://{_options.Host}:{_options.Port}{context.Request.PathBase}{context.Request.Path}{context.Request.QueryString}";
requestMessage.RequestUri = new Uri(uriString);
requestMessage.Method = new HttpMethod(context.Request.Method);
using (var responseMessage = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
{
context.Response.StatusCode = (int)responseMessage.StatusCode;
foreach (var header in responseMessage.Headers)
{
context.Response.Headers.SetValues(header.Key, header.Value.ToArray());
}
foreach (var header in responseMessage.Content.Headers)
{
context.Response.Headers.SetValues(header.Key, header.Value.ToArray());
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
context.Response.Headers.Remove("transfer-encoding");
await responseMessage.Content.CopyToAsync(context.Response.Body);
}
}
https://github.com/aspnet/Proxy/blob/dev/src/Microsoft.AspNet.Proxy/ProxyMiddleware.cs

How to ensure UploadStringCompletedEventHandler event has been executed successfully?

How to ensure UploadStringCompletedEventHandler event has been executed successfully ? in following code you can see i am calling function UploadMyPOST with my lastreads parameter having some data. Now you can see i am saving a variable named response into the MyClassXYZ varialbe. in the extreme last you can see there is a event which invoked by the method UploadMyPost() is filling the server response into the response variable. Now here issue is UploadMyPost(lastreads) executes successfully but its invoked event does not executes. Even cursor do not go on that event by which i am not able to fill server response into the response variable. So Anyone know any approach by which i can wait until that event successfully execute and i could able to save server response ?
private async void MyMethod(MyClassXYZ lastreads)
{
await UploadMyPOST(lastreads);
MyClassXYZ serverResponse = response;
if (serverResponse.Book == null)
{
//Do Something.
}
}
private void UploadMyPOST(MyClassXYZ lastreads)
{
apiData = new MyClassXYZApi()
{
AccessToken = thisApp.currentUser.AccessToken,
Book = lastreads.Book,
Page = lastreads.Page,
Device = lastreads.Device
};
//jsondata is my global variable of MyClassXYZ class.
jsondata = Newtonsoft.Json.JsonConvert.SerializeObject(apiData);
MyClassXYZ responsedData = new MyClassXYZ();
Uri lastread_url = new Uri(string.Format("{0}lastread", url_rootPath));
WebClient wc = new WebClient();
wc.Headers["Content-Type"] = "application/json;charset=utf-8";
wc.UploadStringCompleted += new UploadStringCompletedEventHandler(MyUploadStringCompleted);
wc.UploadStringAsync(lastread_url, "POST", jsondata);
}
private void MyUploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
try
{
if (e.Error == null)
{
string resutls = e.Result;
DataContractJsonSerializer json = new DataContractJsonSerializer(typeof(MyClassXYZ));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(resutls));
response = (MyClassXYZ)json.ReadObject(ms);
}
else
{
string sx = e.Error.ToString();
}
}
catch(Exception exe)
{
}
}
//After Stephen suggession i used the HttpClient so i have written new code with the help of HttpClient. Code is building successfully but at run time cursor goes out from this method to the parent method where from its calling.
private async Task<string> UploadMyPOST(MyClassXYZ lastreads)
{
string value = "";
try
{
apiData = new LastReadAPI()
{
AccessToken = thisApp.currentUser.AccessToken,
Book = lastreads.Book,
Page = lastreads.Page,
Device = lastreads.Device
};
jsondata = Newtonsoft.Json.JsonConvert.SerializeObject(apiData);
LastRead responsedData = new LastRead();
Uri lastread_url = new Uri(string.Format("{0}lastread", url_rootPath));
HttpClient hc = new HttpClient();
//After following line cursor go back to main Method.
var res = await hc.PostAsync(lastread_url, new StringContent(jsondata));
res.EnsureSuccessStatusCode();
Stream content = await res.Content.ReadAsStreamAsync();
return await Task.Run(() => Newtonsoft.Json.JsonConvert.SerializeObject(content));
value = "kd";
}
catch
{ }
return value;
}
I recommend that you use HttpClient or wrap the UploadStringAsync/UploadStringCompleted pair into a Task-based method. Then you can use await like you want to in MyMethod.
Thank you Stephen Clear you leaded me in a right direction and i did POST my request successfully using HttpClient.
HttpClient hc = new HttpClient();
hc.BaseAddress = new Uri(annotation_url.ToString());
HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, myUrl);
HttpContent myContent = req.Content = new StringContent(myJsonData, Encoding.UTF8, "application/json");
var response = await hc.PostAsync(myUrl, myContent);
//Following line for pull out the value of content key value which has the actual resposne.
string resutlContetnt = response.Content.ReadAsStringAsync().Result;
DataContractJsonSerializer deserializer_Json = new DataContractJsonSerializer(typeof(MyWrapperClass));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(resutlContetnt.ToString()));
AnnotateResponse = deserializer_Json.ReadObject(ms) as Annotation;

Send POST request for REST api method call

I have a problem with sending POST http request. It stops on (HttpWebResponse)request.GetResponse() and after timeout throws timeout expired exception, but if i send the same request via GET all works fine.
Does any body know what it can be?
try
{
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
if (content != null)
request.GetRequestStream().Write(content, 0, content.Length);
using (var response = (HttpWebResponse)request.GetResponse())
{
return new Response(response);
}
}
catch (WebException exception)
{
return new Response(exception);
}
Most likely, this is due to the code on the server not exposing this method as a POST. If the server doesn't explicitly set anyhting, it defaults to GET only.
Fixed problem with this code:
using (var requestStream = request.GetRequestStream())
{
if (content != null)
{
requestStream.Write(content, 0, content.Length);
}
requestStream.Close();
using (var response = (HttpWebResponse)request.GetResponse())
{
return new Response(response);
}
}

Resources