Httpclient Slow Performance same computer Android Emulator Xamarin - xamarin

I am using the HttpClient but my results are taking up to 6 seconds coming back from the same machine on the same subnet and ip range of 192.168. When I call the api directly from the ip address the results are more or less instant so why is it so slow with httpclient on the same computer.
I have seen other so's that suggest set to use proxy as false is the best way to go.
I have also tested this on a stock phone and it takes around 8 seconds for the login to be successful on the phone.
private HttpClient _client;
public async Task<String> Getusers()
{
var content = "";
HttpClientHandler hch = new HttpClientHandler();
hch.Proxy = null;
hch.UseProxy = false;
_client = new HttpClient(hch);
var uri = new Uri(Constants.ApiEndPoint + "/Users"); // Your url is here
try
{
var response = await _client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
content = await response.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
throw ex;
}
return content;
}
Here is my login method in case anyone can see something wrong with it.
private async void BtnLogin_Clicked(object sender, EventArgs e)
{
string content = await Getusers(); //Sends a GET request to the specified Uri and returns the response body as a string in an asynchronous operation
List<Users> _users = JsonConvert.DeserializeObject<List<Users>>(content); //Deserializes or converts JSON String into a collection of Post
var userName = txtUserName.Text;
var password = txtPassword.Text;
var isValidUser = _users.Where(w => w.UserName == userName && w.password == password).FirstOrDefault();
var driverId = _users.Where(w => w.UserName == userName && w.password == password).FirstOrDefault().ID;
if (isValidUser != null)
{
Application.Current.Properties["driverId"] = driverId;
Application.Current.MainPage = new MainPage();
}
else
{
lblError.Text = "Error your credentials are invalid, please try again";
}
}

Related

Invalid state from server. Possible forgery! error in Xamarin.Auth

Why I get this error message when trying to use the Xamarin.Auth Api?
I am running on Android Plataform and using Xamarin.Forms
OAuth2Authenticator auth = new OAuth2Authenticator
(
clientId: AppKeyDropboxtoken,
scope: "",
authorizeUrl: new Uri("https://www.dropbox.com/oauth2/authorize"),
redirectUrl: new Uri(RedirectUri),
isUsingNativeUI: false
);
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
// Use eventArgs.Account to do wonderful things
this.AccessToken = eventArgs.Account.Properties["access_token"].ToString();
Debug.WriteLine("AccessToken: " + this.AccessToken);
openDropboxFileList();
}
};
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(auth);
Create a class and add this code below:
public class AuthenticatorExtensions : OAuth2Authenticator
{
public AuthenticatorExtensions(string clientId, string clientSecret, string scope, Uri authorizeUrl, Uri redirectUrl, Uri accessTokenUrl, GetUsernameAsyncFunc getUsernameAsync = null, bool isUsingNativeUI = false) : base(clientId, clientSecret, scope, authorizeUrl, redirectUrl, accessTokenUrl, getUsernameAsync, isUsingNativeUI)
{
}
protected override void OnPageEncountered(Uri url, System.Collections.Generic.IDictionary<string, string> query, System.Collections.Generic.IDictionary<string, string> fragment)
{
// Remove state from dictionaries.
// We are ignoring request state forgery status
// as we're hitting an ASP.NET service which forwards
// to a third-party OAuth service itself
if (query.ContainsKey("state"))
{
query.Remove("state");
}
if (fragment.ContainsKey("state"))
{
fragment.Remove("state");
}
base.OnPageEncountered(url, query, fragment);
}
}
Then use it as below:
[Obsolete]
private void SignInGoogleAuth()
{
try
{
string clientId = null;
string redirectUri = null;
//Xamarin.Auth.CustomTabsConfiguration.CustomTabsClosingMessage = null;
clientId = Constants.GoogleAndroidClientId;
redirectUri = Constants.GoogleAndroidRedirectUrl;
account = store.FindAccountsForService(Constants.AppName).FirstOrDefault();
var authenticator = new AuthenticatorExtensions(
clientId,
null,
Constants.GoogleScope,
new Uri(Constants.GoogleAuthorizeUrl),
new Uri(redirectUri),
new Uri(Constants.GoogleAccessTokenUrl),
null,
true);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
AuthenticationState.Authenticator = authenticator;
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(authenticator);
}
catch (Exception ex)
{
ShowAlert("Alert", ex.Message);
}
}
[Obsolete]
async void OnAuthCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
if (e.IsAuthenticated)
{
// If the user is authenticated, request their basic user data from Google
// UserInfoUrl = https://www.googleapis.com/oauth2/v2/userinfo
var request = new OAuth2Request("GET", new Uri(Constants.GoogleUserInfoUrl), null, e.Account);
var response = await request.GetResponseAsync();
if (response != null)
{
// Deserialize the data and store it in the account store
// The users email address will be used to identify data in SimpleDB
string userJson = await response.GetResponseTextAsync();
StaticVariables.googleProfile = JsonConvert.DeserializeObject<GoogleProfile>(userJson);
}
if (account != null)
{
store.Delete(account, Constants.AppName);
}
await store.SaveAsync(account = e.Account, Constants.AppName);
Application.Current.Properties.Remove("Id");
Application.Current.Properties.Remove("FirstName");
Application.Current.Properties.Remove("LastName");
Application.Current.Properties.Remove("DisplayName");
Application.Current.Properties.Remove("EmailAddress");
Application.Current.Properties.Remove("ProfilePicture");
Application.Current.Properties.Add("Id", StaticVariables.googleProfile.Id);
Application.Current.Properties.Add("FirstName", StaticVariables.googleProfile.GivenName);
Application.Current.Properties.Add("LastName", StaticVariables.googleProfile.FamilyName);
Application.Current.Properties.Add("DisplayName", StaticVariables.googleProfile.Name);
Application.Current.Properties.Add("EmailAddress", StaticVariables.googleProfile.Email);
Application.Current.Properties.Add("ProfilePicture", StaticVariables.googleProfile.Picture);
await Navigation.PushAsync(new GoogleProfilePage());
}
}
[Obsolete]
void OnAuthError(object sender, AuthenticatorErrorEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
Debug.WriteLine("Authentication error: " + e.Message);
}
I was getting the infamous "Possible Forgery!" error and overrode OnPageEncountered() to work around it as many have done. This turns out to be unnecessary as well as insecure.
Oauth2Authenticator is stateful so you will get this problem if you don't use the same instance of OAuth2Authenticator to invoke OnPageLoading() as was used to initiate the authentication.
To resolve, just save the instance of OAuth2Authenticator used for initiating authentication and then reuse it when calling OnPageLoading() in your OauthInterceptor.

How to make async call to api (http). in c#. inside a Task

I am developeing a chatbot using microsoftbotframmwok where I have some requirement to make a call from my task to an api(httpclient). but it is not working. when i test the api from an stand alone console application in side main method it works. but in my application it doesn't work.
I tried to call an api from an simple method without task but when it makes a cal its basically halts or stucked somewhere, i converted my function into task and while making an api call i used await keyword to call it asynchronously but it is returning error, while reading it not the result.
here is the my code which make an api call
private async Task<String> getProblem(IDialogContext context)
{
var response = "Thannks for contacting..";
//here some code logix..
SnowApiClient client = new SnowApiClient(Url, UserId, ApiPassword);
IncidentRequestPayload payload = new IncidentRequestPayload();
payload.caller_id = "tet111";
payload.assignment_group = "it";
payload.category = "complaint";
payload.u_feedback_type = "Praise";
payload.service_offering = "Application Management";
payload.priority = 2;
payload.short_description = "computer battery is dead";
payload.comments = String.Empty;
ApiResponse objResponse = await client.CreateIncident(payload);
//objResponse.payload.number;
return response;
}
//code for CreateIncident...in Api project librarary
public async Task<ApiResponse> CreateIncident(IncidentRequestPayload payload)
{
var incidentRequest = new ApiRequest { method = CreateIncidentMethod, payload = payload };
var createResult = await ExecuteRequest(incidentRequest);
return await ReadIncident(createResult.payload.incNumber);
}
public async Task<ApiResponse> ReadIncident(string number)
{
var incidentRequest = new ApiRequest { method = ReadIncidentMethod, payload = new RequestPayload { number = number } };
return await ExecuteRequest(incidentRequest);
}
private async Task<ApiResponse> ExecuteRequest(ApiRequest requestObject)
{
HttpResponseMessage response = await _client.PostAsJsonAsync("/SRintegratedAPI.rest", requestObject);
ApiResponse responseObject = null;
if (response.IsSuccessStatusCode)
{
responseObject = await response.Content.ReadAsAsync<ApiResponse>();
}
else
{
throw new System.Net.WebException(response.ReasonPhrase);
}
if (responseObject.result != "ok")
{
throw new System.Net.WebException(responseObject.message);
}
return responseObject;
}
I don't understand how and where do i used async/await here in basicalaly in my getProblem function.
please help

Xamarin http webservice issue

I m trying to use http request webservice issue is that when we post wrong username and password the login service generate exception and it can't return any value in async calls.
A code snippet would help assist with the problem ...
However using a try catch should help you catch your exception and prevent application from crashing and handling the exceptions accordingly.
As seen in my sample code below I cater for the incorrect details entered / connectivity problems. I peform the http async request then parse the xml to my model handling the exceptions accordingly
var response = await WebRequestHelper.MakeAsyncRequest(url, content);
if (response.IsSuccessStatusCode == true)
{
Debug.WriteLine("Login Successfull" + "result.IsSuccessStatusCode" + response.IsSuccessStatusCode);
var result = response.Content.ReadAsStringAsync().Result;
result = result.Replace("<xml>", "<LoginResult>").Replace("</xml>", "</LoginResult>");
loginResult = XMLHelper.FromXml<LoginResult>(result);
if (loginResult != null)
{
login.Type = ResultType.OK;
login.Result = loginResult;
}
else
{
login.Type = ResultType.WrongDetails;
}
}
else
{
Debug.WriteLine("Login Failed" + "result.IsSuccessStatusCode" + response.IsSuccessStatusCode);
login.Type = ResultType.WrongDetails;
}
}
catch (Exception ex)
{
login.Type = ResultType.ConnectivityProblem;
}
Web Request
public static async Task<HttpResponseMessage> MakeAsyncRequest(string url, Dictionary<string, string> content)
{
var httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(0, 5, 0);
httpClient.BaseAddress = new Uri(url);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type: application/x-www-form-urlencoded", "application/json");
if (content == null)
{
content = new Dictionary<string, string>();
}
var encodedContent = new FormUrlEncodedContent(content);
var result = await httpClient.PostAsync(httpClient.BaseAddress, encodedContent);
return result;
I would recommend wrapping the response in a generic ServiceResponse where you can store the exceptions. await methods can be included in try/catch blocks so the standard process can be followed.
E.G.
public async Task<ServiceResponse<T>> PostAsync<T>(String address, object dto){
var content = Serializer.SerializeObject (dto);
var response = await client.PostAsync (
address,
new StringContent (content));
if (response.IsSuccessStatusCode) {
try {
var responseString = await response.Content.ReadAsStringAsync ();
return new ServiceResponse<T> (Serializer.DeserializeObject<T> (responseString),
response.StatusCode);
} catch (Exception ex) {
return new ServiceResponse<T> (response.StatusCode, ex);
}
} else {
return new ServiceResponse<T> (response.StatusCode);
}
}
With the ServiceResponse defined as :
public class ServiceResponse<T>
{
public HttpStatusCode StatusCode { get; set;}
public T Value { get; set;}
public String Content { get; set;}
public Exception Error {get;set;}
public ServiceResponse(T value, HttpStatusCode httpStatusCode){
this.Value = value;
this.StatusCode = httpStatusCode;
}
public ServiceResponse(HttpStatusCode httpStatusCode, Exception error = null){
this.StatusCode = httpStatusCode;
this.Error = error;
}
}
This will give you a clean way of managing all your HTTP responses and any errors that may occur.

Azure Notification Hub and WP8 Intermitant notifications

This is a fairly long piece of code but I am getting nowhere with this and cannot see any issues, although I am new to using notification hubs. I am trying to register for targeted notifications (the logged on user) using the notification hub in Azure. After the registration, a test notification is sent.
The issue I am having is that sometimes the notification is sent to the device, and sometimes it is not. It mostly isn't but occasionally when I step through the code on the server, i will get the notification on the emulator come through. Once when I deployed the app to my phone the notification came though on the emulator! I cannot discover a pattern.
My Controller class looks like this;
private NotificationHelper hub;
public RegisterController()
{
hub = NotificationHelper.Instance;
}
public async Task<RegistrationDescription> Post([FromBody]JObject registrationCall)
{
var obj = await hub.Post(registrationCall);
return obj;
}
And the helper class (which is used elsewhere so is not directly in the controller) looks like this;
public static NotificationHelper Instance = new NotificationHelper();
public NotificationHubClient Hub { get; set; }
// Create the client in the constructor.
public NotificationHelper()
{
var cn = "<my-cn>";
Hub = NotificationHubClient.CreateClientFromConnectionString(cn, "<my-hub>");
}
public async Task<RegistrationDescription> Post([FromBody] JObject registrationCall)
{
// Get the registration info that we need from the request.
var platform = registrationCall["platform"].ToString();
var installationId = registrationCall["instId"].ToString();
var channelUri = registrationCall["channelUri"] != null
? registrationCall["channelUri"].ToString()
: null;
var deviceToken = registrationCall["deviceToken"] != null
? registrationCall["deviceToken"].ToString()
: null;
var userName = HttpContext.Current.User.Identity.Name;
// Get registrations for the current installation ID.
var regsForInstId = await Hub.GetRegistrationsByTagAsync(installationId, 100);
var updated = false;
var firstRegistration = true;
RegistrationDescription registration = null;
// Check for existing registrations.
foreach (var registrationDescription in regsForInstId)
{
if (firstRegistration)
{
// Update the tags.
registrationDescription.Tags = new HashSet<string>() {installationId, userName};
// We need to handle each platform separately.
switch (platform)
{
case "windows":
var winReg = registrationDescription as MpnsRegistrationDescription;
winReg.ChannelUri = new Uri(channelUri);
registration = await Hub.UpdateRegistrationAsync(winReg);
break;
case "ios":
var iosReg = registrationDescription as AppleRegistrationDescription;
iosReg.DeviceToken = deviceToken;
registration = await Hub.UpdateRegistrationAsync(iosReg);
break;
}
updated = true;
firstRegistration = false;
}
else
{
// We shouldn't have any extra registrations; delete if we do.
await Hub.DeleteRegistrationAsync(registrationDescription);
}
}
// Create a new registration.
if (!updated)
{
switch (platform)
{
case "windows":
registration = await Hub.CreateMpnsNativeRegistrationAsync(channelUri,
new string[] {installationId, userName});
break;
case "ios":
registration = await Hub.CreateAppleNativeRegistrationAsync(deviceToken,
new string[] {installationId, userName});
break;
}
}
// Send out a test notification.
await SendNotification(string.Format("Test notification for {0}", userName), userName);
return registration;
And finally, my SendNotification method is here;
internal async Task SendNotification(string notificationText, string tag)
{
try
{
var toast = PrepareToastPayload("<my-hub>", notificationText);
// Send a notification to the logged-in user on both platforms.
await NotificationHelper.Instance.Hub.SendMpnsNativeNotificationAsync(toast, tag);
//await hubClient.SendAppleNativeNotificationAsync(alert, tag);
}
catch (ArgumentException ex)
{
// This is expected when an APNS registration doesn't exist.
Console.WriteLine(ex.Message);
}
}
I suspect the issue is in my phone client code, which is here and SubscribeToService is called immediately after WebAPI login;
public void SubscribeToService()
{
_channel = HttpNotificationChannel.Find("mychannel");
if (_channel == null)
{
_channel = new HttpNotificationChannel("mychannel");
_channel.Open();
_channel.BindToShellToast();
}
_channel.ChannelUriUpdated += async (o, args) =>
{
var hub = new NotificationHub("<my-hub>", "<my-cn>");
await hub.RegisterNativeAsync(args.ChannelUri.ToString());
await RegisterForMessageNotificationsAsync();
};
}
public async Task RegisterForMessageNotificationsAsync()
{
using (var client = GetNewHttpClient(true))
{
// Get the info that we need to request registration.
var installationId = LocalStorageManager.GetInstallationId(); // a new Guid
var registration = new Dictionary<string, string>()
{
{"platform", "windows"},
{"instId", installationId},
{"channelUri", _channel.ChannelUri.ToString()}
};
var request = new HttpRequestMessage(HttpMethod.Post, new Uri(ApiUrl + "api/Register/RegisterForNotifications"));
request.Content = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json");
string message;
try
{
HttpResponseMessage response = await client.SendAsync(request);
message = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
message = ex.Message;
}
_registrationId = message;
}
}
Any help would be greatly appriciated as I have been stuck on this now for days! I know this is a lot of code to paste up here but it is all relevant.
Thanks,
EDIT: The SubscribeToService() method is called when the user logs in and authenticates with the WebAPI. The method is here;
public async Task<User> SendSubmitLogonAsync(LogonObject lo)
{
_logonObject = lo;
using (var client = GetNewHttpClient(false))
{
var logonString = String.Format("grant_type=password&username={0}&password={1}", lo.username, lo.password);
var sc = new StringContent(logonString, Encoding.UTF8);
var response = await client.PostAsync("Token", sc);
if (response.IsSuccessStatusCode)
{
_logonResponse = await response.Content.ReadAsAsync<TokenResponseModel>();
var userInfo = await GetUserInfoAsync();
if (_channel == null)
SubscribeToService();
else
await RegisterForMessageNotificationsAsync();
return userInfo;
}
// ...
}
}
I have solved the issue. There are tons of fairly poorly organised howto's for azure notification hubs and only one of them has this note toward the bottom;
NOTE:
You will not receive the notification when you are still in the app.
To receive a toast notification while the app is active, you must
handle the ShellToastNotificationReceived event.
This is why I was experiencing intermittent results, as i assumed you would still get a notification if you were in the app. And this little note is pretty well hidden.
Have you used proper tag / tag expressions while register/send the message. Also, Where are you storing the id back from the notification hub. It should be used when you update the channel uri (it will expire).
I would suggest to start from scratch.
Ref: http://msdn.microsoft.com/en-us/library/dn530749.aspx

How to set Timeout for httpwebrequest in windows phone 8 app?

i am developing an windows phone 8 app , in my app i am calling services and downloading some data into my app .
i am using httpwebrequest for request, but i am not able to set timeout to my httpwebrequest object.
This is how i have created and used my httpwebrequest :-
public async Task<string> ServiceRequest(string serviceurl, string request, string methodname)
{
string response = "";
try
{
var httpwebrequest = WebRequest.Create(new Uri(serviceurl)) as HttpWebRequest;
httpwebrequest.Method = "POST";
httpwebrequest.Headers["SOAPAction"] = "http://tempuri.org/" + iTestservice + "/" + methodname + "";
httpwebrequest.ContentType = "text/xml";
byte[] data = Encoding.UTF8.GetBytes(request);
using (var requestStream = await Task<Stream>.Factory.FromAsync(httpwebrequest.BeginGetRequestStream, httpwebrequest.EndGetRequestStream, null))
{
await requestStream.WriteAsync(data, 0, data.Length);
}
response = await httpRequest(httpwebrequest);
}
catch (Exception ex)
{
return null;
}
return response;
}
public async Task<string> httpRequest(HttpWebRequest request)
{
string received;
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
{
using (var responseStream = response.GetResponseStream())
{
using (var sr = new StreamReader(responseStream))
{
received = await sr.ReadToEndAsync();
}
}
}
return received;
}
My Doubt is :-
1) How can i set timeout property to Httpwebrequest ??
2)What are the different ways in which i can set the timeout property in my windows phone 8 app ??
Please let me know .
Thanks in Advance.
You can't use HttpWebRequest.Timeout on Windows Phone because it doesn't exist for that platform.
If you're open to using a beta library, you could install HttpClient via NuGet and use its Timeout property.
Otherwise, you're probably best off to use TaskEx.Delay, which is part of Microsoft.Bcl.Async. After installing that library, you would replace this line:
response = await httpRequest(httpwebrequest);
with this:
var httpTask = httpRequest(httpwebrequest);
var completeTask = await TaskEx.WhenAny(httpTask, TaskEx.Delay(5000));
if (completeTask == httpTask)
return await httpTask;
else
return null; // timeout
You can use HttpStatusCode.HttpStatusCode is an enum which can be used to get the type of error in HttpWebRequest.
catch(WebException ex)
{
HttpWebResponse response = (HttpWebResponse)ex.Response;
if(response.StatusCode==HttpStatusCode.GatewayTimeout)
{
}
}
The GatewayTimeout indicates that an intermediate proxy server timed out while waiting for a response from another proxy or the origin server.For more information you can refer to the msdn
site for this.Hope it helps

Resources