I am developing a Windows Store App using C# and I am very new at this platform (I have been primarily working on IOS and Android).
I have a simple Async method to download raw data from a remote server. It works ok except that I keep seeing random incomplete reads from the WebResponse class. It is pretty simple method and I cant figure out why it would end prematurely. The remote server is working fine ( ios/web/android fine and are retrieving data) so I am obviously doing something wrong here.
Any help will be great in figuring out this problem.
public async Task<byte[]> doGETRequestAsync(String url)
{
callSuccess = false;
byte[] responseFromServer = null;
try
{
WebRequest request = WebRequest.Create(url);
request.Method = "GET";
WebResponse response = await request.GetResponseAsync();
using (Stream dataStream = response.GetResponseStream())
{
responseFromServer = new byte[response.ContentLength];
int readCount = await dataStream.ReadAsync(responseFromServer, 0, (int)response.ContentLength);
if (readCount != response.ContentLength)
throw new IOException("Premature end of data. Expected: " + response.ContentLength + " received: " + readCount);
}
response.Dispose();
}
catch (HttpRequestException hre)
{
Debug.WriteLine("Exception performing network call : " + hre.ToString());
}
catch (Exception e)
{
Debug.WriteLine("Exception performing network call : " + e.ToString());
}
return responseFromServer;
}
I switched to using HttpClient and HttpClientHandler and it works perfectly. This also supports storing cookies and reusing that on every call.
Here is the code that can handle both GET and POST and return the data as an array of bytes[]. If the response is a utf8 encoded string, then the bytes can be converted to string using System.Text.Encoding.UTF8.GetString(respBytes, 0, respBytes.Length);
Hope it is helpful
class Network
{
static CookieContainer cookieJar = new CookieContainer();
List<KeyValuePair<string, string>> postParameters = new List<KeyValuePair<string, string>>();
// Add post parameter before calling NetworkRequestAsync for POST calls.
public void addPostParameter(String key, String value)
{
postParameters.Add(new KeyValuePair<string, string>(key, value));
}
public async Task<byte[]> NetworkRequestAsync(String url, bool GET_REQUEST)
{
callSuccess = false;
byte[] respBytes = null;
try
{
HttpClientHandler handler = new HttpClientHandler()
{
// Use and reuse cookies in the cookiejar
CookieContainer = cookieJar
};
handler.AllowAutoRedirect = false;
handler.UseCookies = true;
HttpClient client = new HttpClient(handler as HttpMessageHandler)
{
BaseAddress = new Uri(#url)
};
HttpResponseMessage response = null;
if (GET_REQUEST)
{
response = await client.GetAsync(client.BaseAddress);
}
else
{
HttpContent content = new FormUrlEncodedContent(postParameters);
//String postparam=await content.ReadAsStringAsync();
//Debug.WriteLine("Post Param1=" + postparam);
response = await client.PostAsync(client.BaseAddress, content);
callSuccess = true;
}
respBytes = await response.Content.ReadAsByteArrayAsync();
}
catch (Exception e)
{
Debug.WriteLine("Exception performing network call : " + e.ToString());
}
return respBytes;
}
}
Related
I have used SO to help with several issues in the past. However, I cannot find a solution to something I have been struggling with for 2 days now.
I am a noob, please be kind :)
I have an app that I created using Xamarin Studio, targeted for Android. It is a basic GET request from a Rest Api. It was working perfectly until I realized I was not helping myself when it came time to create the same app in IOS and Windows. Once I changed my project to utilize a PCL I started getting errors, primarily around my RestClient class (originally got from http://www.codeproject.com/Tips/497123/How-to-make-REST-requests-with-Csharp)
From my droid app class:
var apiUser = GetString(Resource.String.apiUser);
var apiPass = GetString(Resource.String.apiPass);
//Get token from API
string token = authenticate(apiUser,apiPass);
public static string authenticate(string apiUser, string apiPass)
{
Authentication Auth = new Authentication ();
try
{
// set json by passing AuthenticationUrl as endpoint, returns json data
var o = JObject.Parse(EntryRepository.getJson(PJTApiUrls.getAuthenticationUrl(apiUser,apiPass)));
Auth.Token = (string)o["Token"];
return Auth.Token;
}
catch (Exception e)
{
// Couldn't do stuff. Log the exception.
// TODO possible timeout, try again, if fails again then return error message
if (e.Message.Contains("400") || e.Message.Contains("401"))
{
string error = string.Format("Invalid credentials, please try again");
return error;
} else {
string error = string.Format ("An error occurred: \r\n{0}", e.Message);
return error;
}
}
}
getAuthenticationUrl gets the api URL.
Here is getJson (in PCL):
public static string getJson(string endpoint)
{
string apiurl = endpoint;
var client = new _RestClient();
client.EndPoint = apiurl;
client.ContentType = "application/json";
client.Method = HttpVerb.GET;
//client.Method = HttpVerb.POST;
client.PostData = "";
//client.PostData = "{postData: value}";
//client.PostData = "{'someValueToPost': 'The Value being Posted'}";
var json = client._MakeRequestAsync();
// to append parameters, pass them into make request:
//var json = client.MakeRequest("?param=0");
return json.ToString();
}
And for the _RestClient class (in PCL):
public async Task<string> _MakeRequestAsync()
{
try {
var request = _MakeRequestAsync ("");
return await request;
}
catch (Exception e){
return e.Message;
}
}
public async Task<string> _MakeRequestAsync(string parameters)
{
var uri = new Uri(EndPoint + parameters);
var request = WebRequest.Create(uri) as HttpWebRequest;
using (var response = await request.GetResponseAsync () as HttpWebResponse) {
var responseValue = string.Empty;
if (response.StatusCode != HttpStatusCode.OK) {
var message = String.Format ("Request failed. Received HTTP {0}", response.StatusCode);
throw new Exception (message);
}
// grab the response
using (var responseStream = await Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null)) {
//using (var responseStream = response.GetResponseStream ()) {
if (responseStream != null)
using (var reader = new StreamReader (responseStream)) {
responseValue = reader.ReadToEnd ();
}
}
return responseValue;
}
}
responseValue is returning null
return await request is saying "Status = Waiting for activation"
I have also had the error: "Unexpected character encountered while parsing value: S. Path '', line 0, position 0."
But this works if the RestClient class is within Droid (Instead of the shared PCL) and contains the following:
public string MakeRequest ()
{
return MakeRequest ("");
}
public string MakeRequest (string parameters)
{
var request = (HttpWebRequest)WebRequest.Create (EndPoint + parameters);
request.Method = Method.ToString ();
request.ContentLength = 0;
request.ContentType = ContentType;
if (!string.IsNullOrEmpty (PostData) && Method == HttpVerb.POST) {
var bytes = Encoding.GetEncoding ("iso-8859-1").GetBytes (PostData);
request.ContentLength = bytes.Length;
using (var writeStream = request.GetRequestStream ()) {
writeStream.Write (bytes, 0, bytes.Length);
}
}
using (var response = (HttpWebResponse)request.GetResponse ()) {
var responseValue = string.Empty;
if (response.StatusCode != HttpStatusCode.OK) {
var message = String.Format ("Request failed. Received HTTP {0}", response.StatusCode);
throw new ApplicationException (message);
}
// grab the response
using (var responseStream = response.GetResponseStream ()) {
if (responseStream != null)
using (var reader = new StreamReader (responseStream)) {
responseValue = reader.ReadToEnd ();
}
}
return responseValue;
}
}
I cannot figure this out, any help/guidance is appreciated. Let me know if I can clarify anything.
***** UPDATE ***** Thanks to #milen-pavlov help thus far, here is where I am currently at:
in Android project:
var apiUser = GetString(Resource.String.apiUser);
var apiPass = GetString(Resource.String.apiPass);
//Get token from API
var token = await authenticate(apiUser,apiPass);
lblOutput.Text = token;
calls (also in Android project):
public static async Task<string> authenticate(string apiUser, string apiPass)
{
Authentication Auth = new Authentication ();
try
{
// set json by passing AuthenticationUrl as endpoint, returns json data
var o = JObject.Parse(await EntryRepository.getJson(PJTApiUrls.getAuthenticationUrl(apiUser,apiPass)));
Auth.Token = (string)o["Token"];
return Auth.Token;
}
catch (Exception e)
{
if (e.Message.Contains("400") || e.Message.Contains("401"))
{
string error = string.Format("Invalid credentials, please try again");
return error;
} else {
string error = string.Format ("An error occurred: \r\n{0}", e.Message);
return error;
}
}
}
Calls json class in PCL project:
public static async Task<string> getJson(string endpoint)
{
string apiurl = endpoint;
var client = new _RestClient();
client.EndPoint = apiurl;
client.ContentType = "application/json";
client.Method = HttpVerb.GET;
client.PostData = "";
var json = await client._MakeRequestAsync();
return json;
}
which then calls restclient class in PCL project:
public async Task<string> _MakeRequestAsync()
{
var request = _MakeRequestAsync ("");
return await request;
}
public async Task<string> _MakeRequestAsync(string parameters)
{
var uri = new Uri(EndPoint + parameters);
using (var client = new HttpClient())
{
var response = await client.GetAsync(uri);
return await response.Content.ReadAsAsync<string>();
};
}
End result/error:
Any guidance is appreciated!
Can you use HttpClient instead?
Sample Get request will look similar to this:
public async Task<string> _MakeRequestAsync(string parameters)
{
var uri = new Uri(EndPoint + parameters);
using (var client = new HttpClient())
{
var response = await client.GetAsync(uri);
return await result.Content.ReadAsStringAsync();
};
}
I am trying to call a web service
which returns a JSON response. So far my code is working fine for GET Request but now services on server are POST and I have no idea how to do that! Below is the code for GET Request:
private void callSigninWebservice()
{
setProgressIndicator(true);
SystemTray.ProgressIndicator.Text = "Signing in please wait";
try
{
WebClient webClient = new WebClient();
Uri uri = new Uri(GlobalVariables.URL_USER +
GlobalVariables.URL_STUDENT_SIGNIN_MODE_LOGIN +
GlobalVariables.URL_EMAIL + tbUsername.Text +
GlobalVariables.URL_PASSWORD + tbPassword.Password);
webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
webClient.DownloadStringAsync(uri);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "error came here 1");
}
}
For Response
void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
JObject parentObj = JObject.Parse(e.Result);
String strResult = (String)parentObj[SigninData.JSON_result];
bool bolresult = strResult.Equals(SigninData.JSON_result_success, StringComparison.Ordinal);
if (bolresult)
{
JObject dataObj = (JObject)parentObj[SigninData.JSON_data];
setUserData(dataObj);
NavigationService.Navigate(new Uri("/BasePage.xaml", UriKind.RelativeOrAbsolute));
}
else
{
String error = (String)parentObj[SigninData.JSON_data];
MessageBox.Show("Error : " + error);
}
setProgressIndicator(false);
}
catch (Exception)
{
setProgressIndicator(false);
}
}
This is a simple way of making a post request and receiving a response in JSON for future parse:
internal static async Task<String> GetHttpPostResponse(HttpWebRequest request, string postData)
{
String received = null;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
byte[] requestBody = Encoding.UTF8.GetBytes(postData);
// ASYNC: using awaitable wrapper to get request stream
using (var postStream = await request.GetRequestStreamAsync())
{
// Write to the request stream.
// ASYNC: writing to the POST stream can be slow
await postStream.WriteAsync(requestBody, 0, requestBody.Length);
}
try
{
// ASYNC: using awaitable wrapper to get response
var response = (HttpWebResponse)await request.GetResponseAsync();
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
// ASYNC: using StreamReader's async method to read to end, in case
// the stream i slarge.
received = await reader.ReadToEndAsync();
}
}
catch (WebException we)
{
var reader = new StreamReader(we.Response.GetResponseStream());
string responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
return responseString;
}
return received;
}
I have done POSTING and GETing from server using string post data, but now i have the next WebService:
submitFeedback(String token, String subject, String body, byte[] photo, byte[] video);
private void PostFeedbackData()
{
if (GS.online != true)
{
MessageBox.Show(GS.translations["ErrorMsg0"]);
}
else
{
HttpWebRequest request = HttpWebRequest.CreateHttp("https://****/feedback");
request.Method = "POST";
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
}
}
void GetRequestStreamCallback(IAsyncResult callbackResult)
{
HttpWebRequest myRequest = (HttpWebRequest)callbackResult.AsyncState;
// End the stream request operation
Stream postStream = myRequest.EndGetRequestStream(callbackResult);
// Create the post data
string postData = "";
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
postData = "{\"jsonrpc\": \"2.0\", \"method\": \"getUserSchedule\", \"params\":[" + "\"" + (App.Current as App).UserToken + "\",\"" + FeedbackTitle.Text + "\",\"" + FeedbackContent.Text + "\",\"" + imageBytes + "\"], \"id\": 1}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// 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);
});
}
Look at post data - it is a string, i can't place there imageBytes array. How to do it?
Is there any reason for using HttpWebRequest ?
I am asking that because i think that the correct way of sending files to a service is by multipartform data. With HttpWebRequest you have to manually implement that.
Here is an example that is using Microsoft's HttpClient that might work for you:
public async Task<string> submitFeedback(String token, String subject, String body, byte[] photo, byte[] video) {
var client = new HttpClient();
var content = new MultipartFormDataContent();
// Some APIs do not support quotes in boundary field
foreach (var param in content.Headers.ContentType.Parameters.Where(param => param.Name.Equals("boundary")))
param.Value = param.Value.Replace("\"", String.Empty);
var tok = new StringContent(token);
content.Add(tok, "\"token\"");
var sub = new StringContent(subject);
content.Add(tok, "\"subject\"");
// Add the Photo
var photoContent = new StreamContent(new MemoryStream(photo));
photoContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"photo\"",
FileName = "\"photoname.jpg\""
};
photoContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(photoContent);
// Add the video
var videoContent = new StreamContent(new MemoryStream(video));
videoContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"video\"",
FileName = "\"videoname.jpg\""
};
videoContent.Headers.ContentType = MediaTypeHeaderValue.Parse("video/mp4");
content.Add(videoContent);
HttpResponseMessage resp;
try {
resp = await client.PostAsync("SERVER_URL_GOES_HERE", content);
}
catch (Exception e)
{
return "EXCEPTION ERROR";
}
if (resp.StatusCode != HttpStatusCode.OK)
{
return resp.StatusCode.ToString();
}
var reponse = await resp.Content.ReadAsStringAsync();
return reponse;
}
Change accordingly.
Note: HttpClient is also using HttpWebRequest under the hood.
Also I don't think its a good idea to have the UI thread making the request. That makes no sense since you are blocking the interface and making the async theory useless.
I am trying to use HttpWebRequest and HttpWebResonse asynchronously in a WinForms application without blocking my UI thread.
I saw this similar SO Question which explains how to do it. However, I am not 100% sure the accepted answer is the correct way to do it. The accepted answer is using BeginGetResponse.
According to the MSDN documentation:
The BeginGetResponse method requires some synchronous setup tasks to
complete (DNS resolution, proxy detection, and TCP socket connection,
for example) before this method becomes asynchronous. As a result,
this method should never be called on a user interface (UI) thread
because it might take some time, typically several seconds.
Can someone please provide me with the correct way to do this. Here is my C# function that I'm trying to make work "properly" without blocking my UI thread:
private IDictionary<string, object> CreateWebRequest(string endPoint, string method, string data, bool addAuthHeader)
{
var req = (HttpWebRequest)WebRequest.Create(endPoint);
req.Method = method;
if (addAuthHeader)
{
req.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken);
}
if (!string.IsNullOrEmpty(data))
{
var utfenc = new UTF8Encoding();
byte[] buffer = utfenc.GetBytes(data);
req.ContentLength = buffer.Length;
req.ContentType = "application/x-www-form-urlencoded";
using (Stream strm = req.GetRequestStream())
{
strm.Write(buffer, 0, buffer.Length);
strm.Close();
}
}
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)req.GetResponse();
}
catch (WebException e)
{
if (_accessToken == null)
{
throw;
}
var responseError = (HttpWebResponse)e.Response;
if (responseError.StatusCode == HttpStatusCode.Unauthorized)
{
var stackTrace = new StackTrace();
var q = stackTrace.GetFrame(1).GetMethod().Name;
RefreshAccessCode();
req = (HttpWebRequest)WebRequest.Create(endPoint);
req.Method = method;
if (addAuthHeader)
{
req.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken);
}
response = (HttpWebResponse)req.GetResponse();
}
}
string jsonResponse = null;
if (response != null)
using (Stream stream = response.GetResponseStream())
{
if (stream != null)
{
using (var reader = new StreamReader(stream))
{
jsonResponse = reader.ReadToEnd();
}
}
}
return DeserializeResponse(jsonResponse);
}
If you're open to something besides WebRequest, I'm a fan of System.Net.WebClient. It uses System.Threading.Tasks instead of BeginGetResponse() and EndGetResonse().
public async Task<Dictionary<string, object>> CreateWebRequest(string endPoint, string method, string data, bool addAuthHeader)
{
WebClient client = new WebClient();
if (addAuthHeader)
{
client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken);
}
byte[] buffer = null;
if (!string.IsNullOrEmpty(data))
{
var utfenc = new UTF8Encoding();
buffer = utfenc.GetBytes(data);
}
else
{
buffer = new byte[0];
}
return await client.UploadDataTaskAsync(endPoint, method, buffer)
.ContinueWith((bytes) =>
{
string jsonResponse = null;
using (var reader = new StreamReader(new MemoryStream(bytes)))
{
jsonResponse = reader.ReadToEnd();
}
return DeserializeResponse(jsonResponse);
});
}
}
To use your existing code, just add a method that is intended to execute on the UI thread, and create your web request on a separate thread. When the web request is complete you call the final method on the UI thread. So, a simple version would be:
//do some stuff that wont block the ui thread here
ThreadPool.QueueUserWorkItem((o) =>
{
IDictionary<string, object> result =
CreateWebRequest("lalala", "lol", "butts", true);
BeginInvoke(OnAsyncWebRequestComplete, result);
}, null);
private void OnAsyncWebRequestComplete(IDictionary<string, object> result)
{
//do some stuff on the UI thread here
}
How I can convert my traditional HttpWebRequest "POST" call with Async / Await pattern, Here with this I am attaching my current code, Any one please help me to convert this code using Async / Await pattern for windows phone 8.
public void GetEnvironmentVariables(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback)
{
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject
{
new JProperty("apiKey",_api),
new JProperty("affiliateId",_affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
byte[] requestBody = Encoding.UTF8.GetBytes(serializedResult);
request.BeginGetRequestStream(GetRequestStreamCallback, new object[] { request, requestBody });
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)((object[])asynchronousResult.AsyncState)[0];
using (var postStream = request.EndGetRequestStream(asynchronousResult))
{
var byteArray = (byte[])((object[])asynchronousResult.AsyncState)[1];
// Write to the request stream.
postStream.Write(byteArray, 0, byteArray.Length);
}
request.BeginGetResponse(GetResponseCallback, request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)asynchronousResult.AsyncState;
try
{
var response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
string responseString = reader.ReadToEnd();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err))
CredentialsCallback(Credentails);
else
{
if (Credentails != null)
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we)
{
var reader = new StreamReader(we.Response.GetResponseStream());
string responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
ErrorCallback(we);
}
}
Since Windows Phone 8 doesn't seem to offer the TAP methods you need such as GetRequestStreamAsync the first thing to do is write a little wrapper to provide them for yourself:
public static class WebRequestAsyncExtensions
{
public static Task<Stream> GetRequestStreamAsync(this WebRequest request)
{
return Task.Factory.FromAsync<Stream>(
request.BeginGetRequestStream, request.EndGetRequestStream, null);
}
public static Task<WebResponse> GetResponseAsync(this WebRequest request)
{
return Task.Factory.FromAsync<WebResponse>(
request.BeginGetResponse, request.EndGetResponse, null);
}
}
Note the use of Task.Factory.FromAsync - this is the preferred way to get an await-friendly wrapper around an APM-based async API such as those offered by WebRequest. This is far more efficient than using Task.Factory.StartNew as suggested by someone else, because that would spin up a new thread, whereas this won't need to.
With this in place, you can now write your code in the same way you would on platforms where these TAP-style methods are available (e.g. Windows 8 store apps, desktop apps, etc.):
public async Task GetEnvironmentVariablesAsync(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback)
{
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject
{
new JProperty("apiKey",_api),
new JProperty("affiliateId",_affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
byte[] requestBody = Encoding.UTF8.GetBytes(serializedResult);
// ASYNC: using awaitable wrapper to get request stream
using (var postStream = await request.GetRequestStreamAsync())
{
// Write to the request stream.
// ASYNC: writing to the POST stream can be slow
await postStream.WriteAsync(requestBody, 0, requestBody.Length);
}
try
{
// ASYNC: using awaitable wrapper to get response
var response = (HttpWebResponse) await request.GetResponseAsync();
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
// ASYNC: using StreamReader's async method to read to end, in case
// the stream i slarge.
string responseString = await reader.ReadToEndAsync();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err))
CredentialsCallback(Credentails);
else
{
if (Credentails != null)
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we)
{
var reader = new StreamReader(we.Response.GetResponseStream());
string responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
ErrorCallback(we);
}
}
Note the four lines with // ASYNC: comments - these show where I've made changes. I've collapsed your method down to one, because that's a) possible once you're using async and await and b) much easier than trying to pass things from one method to the next using state arguments.
Notice that the second and fourth of these actually makes async some things you were previously doing synchronously: writing data into the request stream, and reading data out of the response stream. For a small request this probably doesn't matter, but if large amounts of data are being transferred, a synchronous call to Write or ReadToEnd may block. Fortunately, although Windows Phone 8 appears to be missing the TAP methods on WebRequest, it does offer them on Stream and StreamReader so this works without needing to write any extension methods.
I'm new to the community, so here goes my first post. In this case, you can return anytype using a generic Task. This has worked well for me in the past.
Server Side
public class MyController : ApiController
{
public Task<string> PostAsync()
{
return Task.Factory.StartNew(() =>
{
return "populate me with any type and data, but change the type in the response signature.";
});
}
}
Client Side
public class HomeController : Controller
{
public Task<ViewResult> Index()
{
return Task.Factory.StartNew(() =>
{
var model = "use a provider, get some data, or something";
return View(model);
});
}
}
This should do the job:
public async void GetEnvironmentVariables(Action<Credentials> getResultCallback, Action<Exception> getErrorCallback) {
CredentialsCallback = getResultCallback;
ErrorCallback = getErrorCallback;
var uri = new Uri(BaseUri);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json";
var jsonObject = new JObject {
new JProperty("apiKey", _api),
new JProperty("affiliateId", _affid),
};
var serializedResult = JsonConvert.SerializeObject(jsonObject);
var requestBody = Encoding.UTF8.GetBytes(serializedResult);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBody, 0, requestBody.Length);
await GetResponse(request);
}
private async Task GetResponse(WebRequest request) {
Stream resStream = null;
try {
var response = await request.GetResponseAsync();
if (response == null) {
return;
}
resStream = response.GetResponseStream();
if (resStream == null) {
return;
}
var reader = new StreamReader(resStream);
var responseString = await reader.ReadToEndAsync();
Credentails = JsonConvert.DeserializeObject<Credentials>(responseString);
if (Credentails != null && string.IsNullOrEmpty(Credentails.Err)) {
CredentialsCallback(Credentails);
}
else {
if (Credentails != null) {
ErrorCallback(new Exception(string.Format("Error Code : {0}", StorageCredentails.Err)));
}
}
}
catch (WebException we) {
if (resStream != null) {
var reader = new StreamReader(resStream);
var responseString = reader.ReadToEnd();
Debug.WriteLine(responseString);
}
ErrorCallback(we);
}
}