call HttpPost method from Client in C# code - c#

I am new to MVC and C#, so sorry if this question seems too basic.
For a HttpPost Controller like below, how do to call this method directly from a client-side program written in C#, without a browser (NOT from a UI form in a browser with a submit button)? I am using .NET 4 and MVC 4.
I am sure the answer is somehwere on the web, but haven't found one so far. Any help is appreciated!
[HttpPost]
public Boolean PostDataToDB(int n, string s)
{
//validate and write to database
return false;
}

For example with this code in the server side:
[HttpPost]
public Boolean PostDataToDB(int n, string s)
{
//validate and write to database
return false;
}
You can use different approches:
With WebClient:
using (var wb = new WebClient())
{
var data = new NameValueCollection();
data["n"] = "42";
data["s"] = "string value";
var response = wb.UploadValues("http://www.example.org/receiver.aspx", "POST", data);
}
With HttpRequest:
var request = (HttpWebRequest)WebRequest.Create("http://www.example.org/receiver.aspx");
var postData = "n=42&s=string value";
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
With HttpClient:
using (var client = new HttpClient())
{
var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("n", "42"));
values.Add(new KeyValuePair<string, string>("s", "string value"));
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://www.example.org/receiver.aspx", content);
var responseString = await response.Content.ReadAsStringAsync();
}
With WebRequest
WebRequest request = WebRequest.Create ("http://www.example.org/receiver.aspx");
request.Method = "POST";
string postData = "n=42&s=string value";
byte[] byteArray = Encoding.UTF8.GetBytes (postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream ();
dataStream.Write (byteArray, 0, byteArray.Length);
dataStream.Close ();
//Response
WebResponse response = request.GetResponse ();
Console.WriteLine (((HttpWebResponse)response).StatusDescription);
dataStream = response.GetResponseStream ();
StreamReader reader = new StreamReader (dataStream);
string responseFromServer = reader.ReadToEnd ();
Console.WriteLine (responseFromServer);
reader.Close ();
dataStream.Close ();
response.Close ();
see msdn

You can use
First of all you should return valid resutl:
[HttpPost]
public ActionResult PostDataToDB(int n, string s)
{
//validate and write to database
return Json(false);
}
After it you can use HttpClient class from Web Api client libraries NuGet package:
public async bool CallMethod()
{
var rootUrl = "http:...";
bool result;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_rootUrl);
var response= await client.PostAsJsonAsync(methodUrl, new {n = 10, s = "some string"});
result = await response.Content.ReadAsAsync<bool>();
}
return result;
}
You can also use WebClient class:
[HttpPost]
public Boolean PostDataToDB(int n, string s)
{
//validate and write to database
return false;
}
public async bool CallMethod()
{
var rootUrl = "http:...";
bool result;
using (var client = new WebClient())
{
var col = new NameValueCollection();
col.Add("n", "1");
col.Add("s", "2");
var res = await client.UploadValuesAsync(address, col);
string res = Encoding.UTF8.GetString(res);
result = bool.Parse(res);
}
return result;
}

If you decide to use HttpClient implementation. Do not create and dispose of HttpClient for each call to the API. Instead, re-use a single instance of HttpClient. You can achieve that declaring the instance static or implementing a singleton pattern.
Reference: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
How to implement singleton (good starting point, read the comments on that post): https://codereview.stackexchange.com/questions/149805/implementation-of-a-singleton-httpclient-with-generic-methods

Hopefully below code will help you
[ActionName("Check")]
public async System.Threading.Tasks.Task<bool> CheckPost(HttpRequestMessage request)
{
string body = await request.Content.ReadAsStringAsync();
return true;
}

Related

411 - Length Required When Attempting to POST

I am developing a mobile application using Xamarin. This makes it so I cannot call webRequest.ContentLength = 0.
Here is how I am attempting to post:
Client calls:
await new AssetEndpoint().UpdateStatus(Authentication, CurrentAsset, ApprovalStatuses[0]);
AssetEndpoint.UpdateStatus:
public Task UpdateStatus(Authentication auth, Asset asset, ApprovalStatus newStatus)
{
return PostResponseAsync(auth, string.Format(
ApiUpdateStatus, asset.UID, newStatus.Id));
}
Endpoint.PostResponseAsync:
protected async Task<string> PostResponseAsync(Authentication auth, string apiCall)
{
var request = WebRequest.Create(string.Concat(BaseUriPath, apiCall)) as HttpWebRequest;
request.ContentType = "application/json";
request.Method = method;
request.Headers["Authorization"] = string.Concat("bearer ", auth.Token.Value);
var response = await request.GetResponseAsync().ConfigureAwait(false);
using (var reader = new StreamReader(response.GetResponseStream()))
{
return await reader.ReadToEndAsync();
}
}
So I do go about fixing this error? I cannot seem to figure out how to set the content length.
It can be the problem in Xamarin version you are using:
http://forums.xamarin.com/discussion/comment/58076#Comment_58076
public class RestClientTest
{
public static async Task<string> Login()
{
try
{
var request = WebRequest.CreateHttp(path);
request.Headers["Username"] = "xxxxxxxxx";
request.Headers["Password"] = "xxxxxxxxxxx";
request.ContentType = "application/json";
request.Method = "POST";
byte[] byteArray = new byte[] { 0x31, 0x32, 0x33, 0x34, 0x35 };
using (Stream dataStream = await request.GetRequestStreamAsync())
{
await dataStream.WriteAsync(byteArray, 0, byteArray.Length);
}
var response = await request.GetResponseAsync().ConfigureAwait(false);
using (var reader = new StreamReader(response.GetResponseStream()))
{
string resp = await reader.ReadToEndAsync();
return resp;
}
}
catch (Exception ex)
{
return "Error";
}
}
}
If that doesn't work for you I can provide HttpClient sample if you want to try. Without knowing what you are posting I cannot help more. I also tested this code without sending any data in the body and it works too.

HTTP request with C#

I want to convert the Object received in the function and do as needed to convert it to an object ({"some_key": "some_value"}).
Here is my code:
public HttpRequests(string url, string method, Object data)
{
//The following prepares data, according to received parameter
if (data is Array)
{
data = (Array)data;
}
else if (data is Dictionary<Object, Object>)
{
data = ((Dictionary<string, string>)data)["something"] = platform_secret;
data = ((Dictionary<string, string>)data)["something2"] = "1";
}
method = method.ToUpper(); //POST or GET
this.url = just_url + url;
this.data = Newtonsoft.Json.JsonConvert.SerializeObject(data);
this.method = method;
}
public Object performRequest()
{
if (this.data != null && url != null)
{
WebRequest request = HttpWebRequest.Create(url);
byte[] data_bytes = Encoding.ASCII.GetBytes(Convert.ToChar(data)[]);
//^ this does not work. Am I supposed to do this?
// as I said, what I want is to get an object {key: something} that can be read
// by $_POST["key"] in the server
request.Method = method;
request.ContentType = "application/x-www-form-urlencoded"; //TODO: check
//request.ContentLength = ((Dictionary<string, string>) data);
request.ContentLength = data_bytes.Length;
Stream dataStream = request.GetRequestStream(); //TODO: not async at the moment
//{BEGIN DOUBT
dataStream.Write(data_bytes, 0, data_bytes.Length);
dataStream.Close();
//DOUBT: DO THIS ^ or THIS:_ ???
StreamWriter writer = new StreamWriter(dataStream);
writer.Write(this.data);
//End DOUBT}
WebResponse response = request.GetResponse();
Stream dataResponse = response.GetResponseStream();
writer.Close();
response.Close();
dataStream.Close();
return dataResponse.
}
What exactly am I missing here?
As you initially assign this.data = Newtonsoft.Json.JsonConvert.SerializeObject(data);, suppose his.data has type string (you can change if it is otherwise).
Then instead of byte[] data_bytes = Encoding.ASCII.GetBytes(Convert.ToChar(data)[]); you need to write just byte[] data_bytes = Encoding.ASCII.GetBytes(data);
After use this
//{BEGIN DOUBT
dataStream.Write(data_bytes, 0, data_bytes.Length);
dataStream.Close();
It will help to do the call with some data but it does not help to solve your problem. request.ContentType = "application/x-www-form-urlencoded"; does not expect that the data is Newtonsoft.Json.JsonConvert.SerializeObject serialized. It expects a string containing & separated pairs that are urlencoded.
name1=value1&name2=value2&name3=value3
So, you need to use this format instead of JSON.
You need to use the first piece of code. Here is and exmaple.
But the second piece could work too, I guess. You have missed nothing on C# side. A problem could be in the data you are going to transfer, however. If it is not correctly encoded, for example.
You should be doing something closer to the lines of this...
void Main()
{
var formSerializer = new FormEncodedSerializer();
formSerializer.Add("key", "value");
formSerializer.Add("foo", "rnd");
formSerializer.Add("bar", "random");
var uri = #"http://example.com";
var contentType = #"application/x-www-form-urlencoded";
var postData = formSerializer.Serialize();
var http = new Http();
Console.WriteLine (http.Post(uri, postData, contentType));
}
public class Http
{
public string Post(string url, string data, string format)
{
var content = Encoding.UTF8.GetBytes(data);
var contentLength = content.Length;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ServicePoint.Expect100Continue = false;
request.Method = "POST";
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.ContentType = format;
request.ContentLength = contentLength;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(content, 0, content.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream responseStream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(responseStream))
{
return reader.ReadToEnd();
}
}
}`
public class FormEncodedSerializer
{
private Dictionary<string, string> formKeysPairs;
public FormEncodedSerializer(): this(new Dictionary<string, string>())
{
}
public FormEncodedSerializer(Dictionary<string, string> kvp)
{
this.formKeysPairs = kvp;
}
public void Add(string key, string value)
{
formKeysPairs.Add(key, value);
}
public string Serialize()
{
return string.Join("", this.formKeysPairs.Select(f => string.Format("&{0}={1}", f.Key,f.Value))).Substring(1);
}
public void Clear()
{
this.formKeysPairs.Clear();
}
}
I did not really understand what your service expects, in which format you have to send the data.
Anyway, if you set ContentType like "application/x-www-form-urlencoded", you must encode your data with this format. You can simply do it with this code;
var values = ((Dictionary<string, string>)data).Aggregate(
new NameValueCollection(),
(seed, current) =>
{
seed.Add(current.Key, current.Value);
return seed;
});
So, your data is sent like "something=platform_secret&something2=1"
Now, you can send form data simply:
WebClient client = new WebClient();
var result = client.UploadValues(url, values);
I think your first function with signature public HttpRequests(string url, string method, Object data) dosn't seem have any logical error but in your second function with signature public Object performRequest() you have some issue:
if your HTTP method is GET you don't need to write content stream.
if your method is POST and your data are JSON you need setting up HTTP requester like this:
request.ContentType = "application/json";
and finally, flush your stream before you close it, like this request.Flush();

Set a body for WebClient when making a Post Request

So I have an api that I want to call to. The first call is an ahoy call and in the body of the request I need to send the ship_type, piratename and my piratepass. I then want to read the response which has my treasure booty that i will use for later.
I'm able to do this with web request. but i feel like there is a better way to do it with webclient.
(way I currently do it in webrequest)
//Credentials for the Pirate api
string piratename = "IvanTheTerrible";
string piratepass= "YARRRRRRRR";
string URI = "https://www.PiratesSuperSecretHQ.com/sandyShores/api/respectmyauthority";
WebRequest wr = WebRequest.Create(URI);
wr.Method = "POST";
wr.ContentType = "application/x-www-form-urlencoded";
string bodyData = "ship_type=BattleCruiser&piratename=" + piratename + "&piratepass=" + piratepass;
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] byte1 = encoder.GetBytes(bodyData);
wr.ContentLength = byte1.Length;
//writes the body to the request
Stream newStream = wr.GetRequestStream();
newStream.Write(byte1, 0, byte1.Length);
newStream.Close();
WebResponse wrep = wr.GetResponse();
string result;
using (var reader = new StreamReader(wrep.GetResponseStream()))
{
result = reader.ReadToEnd(); // do something fun...
}
Thanks in advance either way.
You can do with this simple code
Uri uri = new Uri("yourUri");
string data = "yourData";
WebClient client = new WebClient();
var result = client.UploadString(uri, data);
Remember that you can use UploadStringTaskAsync if you want to be async
You can try like below as well:
public String wcPost(){
Map<String, String> bodyMap = new HashMap();
bodyMap.put("key1","value1");
WebClient client = WebClient.builder()
.baseUrl("domainURL")
.build();
String responseSpec = client.post()
.uri("URI")
.headers(h -> h.setBearerAuth("token if any"))
.body(BodyInserters.fromValue(bodyMap))
.exchange()
.flatMap(clientResponse -> {
if (clientResponse.statusCode().is5xxServerError()) {
clientResponse.body((clientHttpResponse, context) -> {
return clientHttpResponse.getBody();
});
return clientResponse.bodyToMono(String.class);
}
else
return clientResponse.bodyToMono(String.class);
})
.block();
return responseSpec;
}

C# Capture HTTP response when the page is fully loaded

I want to send a http post request and capture the response. I have written following code.
System.Net.WebRequest req = System.Net.WebRequest.Create(URI);
req.Proxy = new System.Net.WebProxy(ProxyString, true);
//Add these, as we're doing a POST
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
//We need to count how many bytes we're sending.
//Post'ed Faked Forms should be name=value&
byte [] bytes = System.Text.Encoding.ASCII.GetBytes(Parameters);
req.ContentLength = bytes.Length;
System.IO.Stream os = req.GetRequestStream ();
os.Write (bytes, 0, bytes.Length); //Push it out there
os.Close ();
System.Net.WebResponse resp = req.GetResponse();
if (resp== null) return null;
System.IO.StreamReader sr =
new System.IO.StreamReader(resp.GetResponseStream());
return sr.ReadToEnd().Trim();
Update 1:
I tried making use of PostAsync method. Still the same result.
public static async void Req()
{
using (var client = new HttpClient())
{
var values = new Dictionary<string, string>
{
{ "type1", "val1" },
{ "type2", "val2" },
{ "type3", "val3"}
};
var content = new FormUrlEncodedContent(values);
var r1 = await client.PostAsync(URL, content);
var responseString = await r1.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
Console.ReadLine();
}
}
But its capturing only partial response. My Page takes 10-12 seconds to load. How do I make my script wait and capture complete response?
This could be due to that the response is encoded in som other encoding then UTF8 that StreamReader defaults to. Please check the encoding of the response and alter the call to streamreader from
new System.IO.StreamReader(resp.GetResponseStream());
to
new System.IO.StreamReader(resp.GetResponseStream(), Encoding.ASCII);
for ASCII encoding
working code. Just pass the correct parameters to the method.
public static async void Req()
{
using (var client = new HttpClient())
{
var values = new Dictionary<string, string>
{
{ "type1", "val1" },
{ "type2", "val2" },
{ "type3", "val3"}
};
var content = new FormUrlEncodedContent(values);
var r1 = await client.PostAsync(URL, content);
var responseString = await r1.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
Console.ReadLine();
}
}
}

WP7 Create helper class for easy use HttpWebRequest with POST method

Actually I have something like this:
private void createHttpRequest()
{
System.Uri myUri = new System.Uri("..url..");
HttpWebRequest myHttpRequest = (HttpWebRequest)HttpWebRequest.Create(myUri);
myHttpRequest.Method = "POST";
myHttpRequest.ContentType = "application/x-www-form-urlencoded";
myHttpRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), myHttpRequest);
}
void GetRequestStreamCallback(IAsyncResult callbackResult)
{
HttpWebRequest myRequest = (HttpWebRequest)callbackResult.AsyncState;
// End the stream request operation
Stream postStream = myRequest.EndGetRequestStream(callbackResult);
string hash = HashHelper.createStringHash("123", "TEST", "0216");
// Create the post data
byte[] byteArray = createByteArrayFromHash(hash);
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the web request
myRequest.BeginGetResponse(new AsyncCallback(GetResponsetStreamCallback), myRequest);
}
void GetResponsetStreamCallback(IAsyncResult callbackResult)
{
HttpWebRequest request = (HttpWebRequest)callbackResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callbackResult);
using (StreamReader httpWebStreamReader = new StreamReader(response.GetResponseStream()))
{
string result = httpWebStreamReader.ReadToEnd();
ApiResponse apiResponse = (ApiResponse)JsonConvert.DeserializeObject<ApiResponse>(result);
}
}
It's good, it's working but now I must use these methods in every page and just change method createByteArrayFromHash which creates request. What if I want to create helper class that can help me to do this in something about 3 lines of code in page. How would you do that? I was thinking about this way but how to add request before response? Or would you do it another way? Thanks
Yeah, it's better to use async and await. Here is an example of such a wrapper:
public async Task<string> SendRequestGetResponse(string postData, CookieContainer cookiesContainer = null)
{
var postRequest = (HttpWebRequest)WebRequest.Create(Constants.WebServiceUrl);
postRequest.ContentType = "Your content-type";
postRequest.Method = "POST";
postRequest.CookieContainer = new CookieContainer();
postRequest.CookieContainer = App.Session.Cookies;
using (var requestStream = await postRequest.GetRequestStreamAsync())
{
byte[] postDataArray = Encoding.UTF8.GetBytes(postData);
await requestStream.WriteAsync(postDataArray, 0, postDataArray.Length);
}
var postResponse = await postRequest.GetResponseAsync() as HttpWebResponse;
if (postResponse != null)
{
var postResponseStream = postResponse.GetResponseStream();
var postStreamReader = new StreamReader(postResponseStream);
// Can use cookies if you need
if (cookiesContainer == null)
{
if (!string.IsNullOrEmpty(postResponse.Headers["YourCookieHere"]))
{
var cookiesCollection = postResponse.Cookies;
// App.Session is a global object to store cookies and etc.
App.Session.Cookies.Add(new Uri(Constants.WebServiceUrl), cookiesCollection);
}
}
string response = await postStreamReader.ReadToEndAsync();
return response;
}
return null;
}
You can modify it as you wish

Categories