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();
Related
I am unable to send data from my client app to a web method, i dont actually know what i am doing wrong any help would be appreciate.
Client:
public void syncClient(Customer c)
{
try
{
var datos = new JavaScriptSerializer().Serialize(c);
DataContractJsonSerializer ser =
new DataContractJsonSerializer(typeof(string));
MemoryStream mem = new MemoryStream();
ser.WriteObject(mem, datos);
string data = Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length);
string url = store.ParentUrl + "Api/syncClientFromChild";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = #"application/json"; //set the content type to JSON
request.Method = "POST";
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] send = encoding.GetBytes(data);
request.ContentLength = send.Length;
using (Stream newStream = request.GetRequestStream())
{
newStream.Write(send, 0, send.Length);
}
WebResponse ws1 = request.GetResponse();
JavaScriptSerializer serializer = new JavaScriptSerializer();
ApiCtrlResponse response = serializer.Deserialize<ApiCtrlResponse>(serializer.Serialize(ws1.GetResponseStream()));
if (response.success == true)
{
c.Synced = true;
_customerService.UpdateCustomer(c);
}
}
catch (Exception A)
{
}
}
I believe thats fine, but the other method i always get null in the string i need to receive:
[System.Web.Services.WebMethod]
public ActionResult syncClientFromChild(string Customer)
{
// do something
}
What i am missing ? Thanks in advance !
use a Model to accept Http Post,try to not use string,like
public class ReceiveModel
{
string Customer;
}
public ActionResult syncClientFromChild(ReceiveModel model)
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;
}
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
I have a jquery routine that calls an MVC action which will do a PUT/POST to an API url. The call from jQuery is fine and works as well as the call to the API using C#. A response is received from the API in JSON format when checked via Firebug/Fiddler.
How do i get that response to be sent back to the calling jQuery?
My C# code is:
public string callAPIPut(string ApiUrl, string JsonString)
{
WebRequest request = WebRequest.Create(ApiUrl);
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(JsonString);
request.ContentType = "application/json; charset=utf-8";
request.Method = WebRequestMethods.Http.Put;
request.ContentLength = JsonString.Length;
Stream newStream = request.GetRequestStream();
newStream.Write(data, 0, JsonString.Length);
newStream.Close();
return ""; // How do I return the JSON response from the API?
}
When doing a GET i could use something like the following to get the response back to the calling jQuery:
response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
serviceResponse = sr.ReadToEnd();
}
return serviceResponse;
I dont know how to return the response when doing a Put/Post?
public ActionResult CallAPIPut(string ApiUrl, string JsonString)
{
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
byte[] data = Encoding.Default.GetBytes(JsonString);
byte[] result = client.UploadData(ApiUrl, "PUT", data);
return Content(Encoding.Default.GetString(result), "application/json");
}
}
or make it more intelligently, by wrapping in a custom and reusable action result to avoid cluttering your controller with infrastructure plumbing:
public class ApiResult : ActionResult
{
public ApiResult(string apiUrl, string jsonData)
: this(apiUrl, jsonData, "PUT")
{
}
public ApiResult(string apiUrl, string jsonData, string method)
{
ApiUrl = apiUrl;
JsonData = jsonData;
Method = method;
}
public string ApiUrl { get; private set; }
public string JsonData { get; private set; }
public string Method { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
var contentType = "application/json";
response.ContentType = contentType;
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = contentType;
byte[] data = Encoding.Default.GetBytes(JsonData);
byte[] result = client.UploadData(ApiUrl, Method, data);
response.Write(Encoding.Default.GetString(result));
}
}
}
and now your controller action simply becomes:
public ActionResult CallAPIPut(string apiUrl, string jsonString)
{
return new ApiResult(apiUrl, jsonString);
}
Stream newStream = request.GetRequestStream();
newStream.Write(data, 0, JsonString.Length);
newStream.Close();
You're posting JSON to the server. To get JSON you need to post/put and use the ResponseStream to read the data the server returned.
A sample:
using System;
using System.IO;
using System.Net;
using System.Text;
namespace Examples.System.Net
{
public class WebRequestGetExample
{
public static void Main ()
{
// Create a request for the URL.
WebRequest request = WebRequest.Create (
"http://www.contoso.com/default.html");
// If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials;
// Get the response.
WebResponse response = request.GetResponse ();
// Display the status.
Console.WriteLine (((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
Stream dataStream = response.GetResponseStream ();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader (dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd ();
// Display the content.
Console.WriteLine (responseFromServer);
// Clean up the streams and the response.
reader.Close ();
response.Close ();
}
}
}
Sample from http://msdn.microsoft.com/en-us/library/456dfw4f.aspx
Edit: You would return the responseFromServer and consume that in you're Javascript callback.
protected void UploadFile(object sender, EventArgs e)
{
if (fileUpload.HasFile)
{
if (fileUpload.PostedFile.ContentType == "text/xml")
{
Stream inputstream = fileUpload.PostedFile.InputStream;
byte[] streamAsBytes = (ConvertStreamToByteArray(inputstream));
string stringToSend = BitConverter.ToString(streamAsBytes);
xmlstream.Value = stringToSend;
sendXML.Visible = true;
infoLabel.Text = string.Empty;
/*
string path = Server.MapPath("GenericHandler.ashx");
WebClient wc = new WebClient();
wc.UploadFile(path,"POST", fileUpload.PostedFile);
Something like this maybe? But is there any way to do it without saving the file? */
}
else
{
infoLabel.Text = "Please select an XML file";
sendXML.Visible = false;
}
}
}
This is my current code. The xml gets saved in a hidden field as a hex string and sent via jquery ajax. But it would be much better to send the file itself and process it in the handler. Is that possible?
Try the following code, i haven't tested it but it should work, instead of string pass the byte[] to the method
private string PostData(string url, byte[] postData)
{
HttpWebRequest request = null;
Uri uri = new Uri(url);
request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postData.Length;
using (Stream writeStream = request.GetRequestStream())
{
writeStream.Write(postData, 0, postData.Length);
}
string result = string.Empty;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8))
{
result = readStream.ReadToEnd();
}
}
}
return result;
}
Found the code here at Http Post in C#
Yes, you can create a HttpWebRequest, set it's Method to POST (if that's what you need) and then create a form field in the request with your file data. You will need to understand a little bit about how HTTP requests work and how to properly create that form field in the request, but it's doable (and not overly difficult).