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.
Related
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;
}
This question has been asked a million times, and yet none of the responses work for me. The one I was most excited about was Http Post for Windows Phone 8 but because it requires delegates, it's not right for my code... the Postdata function is called from repositories, it would be nice to get a response straight from this function!
How do I add post parameters to this code? I've been trying to get it to work for a good 10 hours now.
// Repository code
string url = "/bla/bla/" + blaId + "/";
Dictionary<string, string> postParams = new Dictionary<string, string>();
postParams.Add("value", message);
string response = await BlaDataContext.PostData(url, postParams);
// ...
public static async Task<string> PostData(string url, Dictionary<String, String> postParams)
{
HttpWebRequest request = WebRequest.CreateHttp(APIURL + url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
postParams.Add("oauth_token", Contract.AccessToken); // where do I add this to the request??
try
{
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
Debug.WriteLine(response.ContentType);
Stream responseStream = response.GetResponseStream();
string data;
using (var reader = new StreamReader(responseStream))
{
data = reader.ReadToEnd();
}
responseStream.Close();
return data;
}
catch (Exception e)
{
// whatever
}
}
HttpWebRequest request = WebRequest.CreateHttp("" + url);
//we could move the content-type into a function argument too.
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
postParams.Add("oauth_token", ""); // where do I add this to the request??
try
{
//this is how you do it
using(var stream = await request.GetRequestStreamAsync())
{
byte[] jsonAsBytes = Encoding.UTF8.GetBytes(string.Join("&", postParams.Select(pp => pp.Key + "=" + pp.Value)));
await stream.WriteAsync(jsonAsBytes, 0, jsonAsBytes.Length);
}
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
Debug.WriteLine(response.ContentType);
System.IO.Stream responseStream = response.GetResponseStream();
string data;
using (var reader = new System.IO.StreamReader(responseStream))
{
data = reader.ReadToEnd();
}
responseStream.Close();
return data;
}
Async Await HttpWebRequest Extensions:
public static class HttpExtensions
{
public static Task<Stream> GetRequestStreamAsync(this HttpWebRequest request)
{
var tcs = new TaskCompletionSource<Stream>();
try
{
request.BeginGetRequestStream(iar =>
{
try
{
var response = request.EndGetRequestStream(iar);
tcs.SetResult(response);
}
catch (Exception exc)
{
tcs.SetException(exc);
}
}, null);
}
catch (Exception exc)
{
tcs.SetException(exc);
}
return tcs.Task;
}
public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest request)
{
var taskComplete = new TaskCompletionSource<HttpWebResponse>();
request.BeginGetResponse(asyncResponse =>
{
try
{
HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState;
HttpWebResponse someResponse =
(HttpWebResponse)responseRequest.EndGetResponse(asyncResponse);
taskComplete.TrySetResult(someResponse);
}
catch (WebException webExc)
{
HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response;
taskComplete.TrySetResult(failedResponse);
}
}, request);
return taskComplete.Task;
}
}
With the extensions, I think it's a little cleaner.
You need to write the parameters to the request body.
You could use an extension method like this one:
public static void AddFormData(this HttpWebRequest request, IDictionary<string, string> data)
{
using (var memStream = new MemoryStream())
using (var writer = new StreamWriter(memStream))
{
bool first = true;
foreach (var d in data)
{
if (!first)
writer.Append("&");
writer.Write(Uri.EscapeDataString(d.Key));
writer.Write("=");
writer.Write(Uri.EscapeDataString(d.Value));
first = false;
}
writer.Flush();
request.ContentLength = memStream.Length;
memStream.Position = 0;
using (var reqStream = request.GetRequestStream())
{
memStream.CopyTo(reqStream);
}
}
}
Call it like this:
request.AddFormData(postParams);
I am verifying my ios in app purchase receipt on my server using C# web service
I got receipt as string by doing below in Xcode:
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
NSString* receiptString = [[NSString alloc] initWithString:transaction.payment.productIdentifier];
NSLog(#"%#",receiptString);
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
NSString *jsonObjectString = [receipt base64EncodedStringWithOptions:0];
}
and I am sending that string(receipt) to my C# web service as parameter.
Here is my web service method:
[WebMethod(Description = "Purchase Item Verify")]
public string PurchaseItem(string receiptData)
{
string returnmessage = "";
try
{
var json = "{ 'receipt-data': '" + receiptData + "'}";
ASCIIEncoding ascii = new ASCIIEncoding();
byte[] postBytes = Encoding.UTF8.GetBytes(json);
HttpWebRequest request;
request = WebRequest.Create("https://sandbox.itunes.apple.com/verifyReceipt") as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = postBytes.Length;
Stream postStream = request.GetRequestStream();
postStream.Write(postBytes, 0, postBytes.Length);
postStream.Close();
var sendresponse = (HttpWebResponse)request.GetResponse();
string sendresponsetext = "";
using (var streamReader = new StreamReader(sendresponse.GetResponseStream()))
{
sendresponsetext = streamReader.ReadToEnd();
}
returnmessage = sendresponsetext;
}
catch (Exception ex)
{
ex.Message.ToString();
}
return returnmessage;
}
It always return {"status":21002}.
I have been searching for two days , but still can't find out the solution. Can someone help me, what am i wrong ?
**I am testing on sandbox that is why i use sandbox URL. I can verify the transaction receipt within my app.
I got solution
The final code that works for me is:
public string PurchaseItem(string receiptData)
{
string returnmessage = "";
try
{
// var json = "{ 'receipt-data': '" + receiptData + "'}";
var json = new JObject(new JProperty("receipt-data", receiptData)).ToString();
ASCIIEncoding ascii = new ASCIIEncoding();
byte[] postBytes = Encoding.UTF8.GetBytes(json);
// HttpWebRequest request;
var request = System.Net.HttpWebRequest.Create("https://sandbox.itunes.apple.com/verifyReceipt");
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = postBytes.Length;
//Stream postStream = request.GetRequestStream();
//postStream.Write(postBytes, 0, postBytes.Length);
//postStream.Close();
using (var stream = request.GetRequestStream())
{
stream.Write(postBytes, 0, postBytes.Length);
stream.Flush();
}
// var sendresponse = (HttpWebResponse)request.GetResponse();
var sendresponse = request.GetResponse();
string sendresponsetext = "";
using (var streamReader = new StreamReader(sendresponse.GetResponseStream()))
{
sendresponsetext = streamReader.ReadToEnd().Trim();
}
returnmessage = sendresponsetext;
}
catch (Exception ex)
{
ex.Message.ToString();
}
return returnmessage;
Spending two and half days just to change a method. Thanks GOD.
Here's an alternative asynchronous implementation using HTTPClient:
public static async Task<string> CheckReceiptWithAppStore()
{
string responseStr = null;
string uri = "https://sandbox.itunes.apple.com/verifyReceipt";
string receiptData = // Get your receipt from wherever you store it
var json = new JObject(new JProperty("receipt-data", receiptData),
new JProperty("password", "paste-your-shared-secret-here")).ToString();
using (var httpClient = new HttpClient())
{
if (receiptData != null)
{
HttpContent content = new StringContent(json);
try
{
Task<HttpResponseMessage> getResponse = httpClient.PostAsync(uri, content);
HttpResponseMessage response = await getResponse;
responseStr = await response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
Console.WriteLine("Error verifying receipt: " + e.Message);
}
}
}
return responseStr;
}
The shared secret is not required for non-subscription based purchases.
For managing subscriptions, #Jerry Naing's answer also requires the provision of your shared secret (can be retrieved/generated from iTunes Connect). Easiest way to include this is just to add an additional property in the line defining the json var.
var json = new JObject(new JProperty("receipt-data", receiptData), new JProperty("password", "put_your_shared_secret_here")).ToString();
Failing to provide the shared secret will result in a 21004 status response.
This code example was also helpful to me and may help others: For C# developers there is a useful open-source project called APNS-Sharp which includes receipt verification code that works in ASP.NET. In particular, the Receipt.cs and ReceiptVerification.cs files in the Jdsoft.Apple.AppStore directory
Found it from this page about Xamarin: inapp purcasing ios Transactions and Verification
I need to make the following code async and awaitable.
I need to get a lot of data from the web server, and then this data will be used to populate the xaml page in my application.
So, I need the DefLogin() method to be awaitable.
Is it possible?
public void DefLogin()
{
postData = "My Data To Post";
var url = new Uri("Url To Post to", UriKind.Absolute);
webRequest = WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "text/xml";
webRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), webRequest);
}
public void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
Stream postStream = webRequest.EndGetRequestStream(asynchronousResult);
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
Debug.WriteLine("Start BEGINGetResponse");
webRequest.BeginGetResponse(new AsyncCallback(GetResponseCallback), webRequest);
}
public void GetResponseCallback(IAsyncResult asynchronousResult)
{
try
{
HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response;
response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamResponse);
string Response = streamReader.ReadToEnd();
streamResponse.Close();
streamReader.Close();
response.Close();
if (Response == "")
{
//show some error msg to the user
Debug.WriteLine("ERROR");
}
else
{
//Your response will be available in "Response"
Debug.WriteLine(Response);
}
}
catch (WebException)
{
//error
}
}
I saw this question on StackOverflow: Converting ordinary Http Post web request with Async and Await, but I could not understand the answer properly.
Please can anyone help? I would be really grateful!
You can use TaskFactory.FromAsync to convert APM to TAP, making a lot of tiny extension methods like this:
public static Task<Stream> GetRequestStreamAsync(this WebRequest request)
{
return TaskFactory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, null);
}
and do the same for WebRequest.GetResponse and (if necessary) Stream.Write, Stream.Flush, etc.
Then you can write your actual logic using async and await without any callbacks:
public async Task DefLoginAsync()
{
postData = "My Data To Post";
var url = new Uri("Url To Post to", UriKind.Absolute);
webRequest = WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "text/xml";
using (Stream postStream = await webRequest.GetRequestStreamAsync())
{
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
await postStream.WriteAsync(byteArray, 0, byteArray.Length);
await postStream.FlushAsync();
}
try
{
string Response;
using (var response = (HttpWebResponse)await webRequest.GetResponseAsync());
using (Stream streamResponse = response.GetResponseStream())
using (StreamReader streamReader = new StreamReader(streamResponse))
{
Response = await streamReader.ReadToEndAsync();
}
if (Response == "")
{
//show some error msg to the user
Debug.WriteLine("ERROR");
}
else
{
//Your response will be available in "Response"
Debug.WriteLine(Response);
}
}
catch (WebException)
{
//error
}
}
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