Null response while making a POST request using HttpClient from android Xamarin - android

Iam sending a POST request from my android app using Xamarin. Iam using HttpClient to make the request
Things I have done:
1) Specified Internet permission
2) Tested the request from Postman for google Chrome
3) Debugged the code step by step
Problem:
1) I get the response as null.
2) Found the issue might be while receiving the response.
Here is my code:-
var resultString = String.Empty;
var registerContent = new StringBuilder();
registerContent.Append("DeviceId=");
registerContent.Append(deviceId);
registerContent.Append("&");
registerContent.Append("Name=");
registerContent.Append(deviceName);
registerContent.Append("&");
registerContent.Append("EncodedAccountNameā€¸=");
registerContent.Append(username);
var client = DataClient.Instance;
var request = new HttpRequestMessage(HttpMethod.Post,new Uri(EndPoints.RegisterDeviceEndPoint, UriKind.Absolute))
{
Content = new StringContent("DeviceId=" + deviceId + "&Name=" + deviceName + "&EncodedAccountName=" + username)
};
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
var result = await client.SendAsync(request);
if (result.StatusCode == HttpStatusCode.OK)
{
resultString = HostUrl.GeAuthorizationtResult(result.Content.ReadAsStringAsync().Result);
}
return resultString;
Any help is appreciated
Thanks

It looks like you have a lot of app-specific code in there, so it's difficult to say what's causing the issue. You can simplify your code by using HttpClient's built-in support for form posts.
var httpClient = new HttpClient();
var values = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("DeviceId", deviceId),
new KeyValuePair<string, string>("Name", deviceName),
new KeyValuePair<string, string>("EncodedAccountName", username)
};
var response = await httpClient.PostAsync(requestUrl, new FormUrlEncodedContent(values));
response.EnsureSuccessStatusCode();
var resultString = await response.Content.ReadAsStringAsync();
Try this and see if it solves the issue. Otherwise, you'll need to expand on what HostUrl.GeAuthorizationtResult() does.

Related

XF 504 on Get request when using Android HttpClient implementation

In my Xamarin Forms app I have a very basic GET request that results in a 504 'Method not allowed' on Android.
This is the controller that I am calling:
[AllowAnonymous]
[HttpGet]
[Route("api/system/backendversion")]
public int GetBackendVersion()
{
return 20200924;
}
This is the code that performs the request
var _client = new HttpClient();
var content = new StringContent(json, Encoding.UTF8, "application/json");
var httpRequest = new HttpRequestMessage(httpMethod, url)
{
Content = content,
Version = HttpVersion.Version10
};
var response = await _client.SendAsync(httpRequest);
The problem disappears when I change the HttpClient implementation from "Android" to "Managed".
Also the webrequest works fine in the XF.UWP version of my app.
I believe I put it on Android for a reason, but I'm unsure what the reason was (probably speed). I'm curious what goes wrong here.
Apperantly it breaks because the content (header?) is set to json when there is no json.
I fixed it like this:
var httpRequest = new HttpRequestMessage(httpMethod, url)
{
Version = HttpVersion.Version10
};
if (!string.IsNullOrWhiteSpace(json))
{
httpRequest.Content = new StringContent(json, Encoding.UTF8, "application/json");
}
var response = await _client.SendAsync(httpRequest);
this error is similar to iOS where you get an error if you put json body in a get request
if (httpMethod == HttpMethod.Get && !string.IsNullOrWhiteSpace(json))
{
Debugger.Break();//a get request with a body is not allowed on iOS and results in a error https://stackoverflow.com/questions/56955595/1103-error-domain-nsurlerrordomain-code-1103-resource-exceeds-maximum-size-i
}

How to make a client which authenticates against ASP.NET WebAPI?

enter image description hereI have created REST API in ASP.NET with http://server/token as URL.
The header having
content-type: application/x-www-form-urlencode
The body have grant_type as password, username and password will get json data with token.
For further data access token can be used above method works with postman
I need to implement a client in Android Studio or Xamarin.
as urls in postman is "example.com/token"; , then in Header Key value pais for content type as ("Content-Type:application/x-www-form-urlencoded) and in body key value pair as (grant_type:password, username:email,password:pass) and after send the response is in json format as follows { "access_token": "token", "token_type": "bearer", "expires_in": 1209599, "userName": "mail#gmail.com", ".issued": "Fri, 09 Dec 2016 19:19:18 GMT", ".expires": "Fri, 23 Dec 2016 19:19:18 GMT" }
this same needed to be done in android
Include in your dependencies System.Net.Http (requires Xamarin profile 111) and then you can use that to create a HttpClient and request the token via HTTP POST (akin to what you were doing in Postman) like this..
_client = new HttpClient();
var uri = new Uri("http://server/token");
var content = new FormUrlEncodedContent(
new List<KeyValuePair<string, string>> {
new KeyValuePair<string, string>("username", _username),
new KeyValuePair<string, string>("password", _password),
new KeyValuePair<string, string>("grant_type", "password")
});
HttpResponseMessage response = await _client.PostAsync(uri, content);
Where _username and _password are strings.
Then read the response out by converting it into a Dictionary or any other reasonable alternative approach to parsing the JSON response.
if (response.StatusCode == HttpStatusCode.OK) {
var jsonContent = await response.Content.ReadAsStringAsync();
var responseDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonContent);
if (responseDict.ContainsKey("access_token"))
_token = responseDict["access_token"];
}
Then once you have the token, you can include it as a default authorization value for all headers from that HttpClient instance!
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token);
Where _token is the token as it's encoded string, e.g. "eyJ0eXAiOiJKV1QiLC..."
Just implemented this and to verify it's correctness - I ran it against a production environment I have set up to verify using JWTs and it worked a charm.
this works, it looks ugly but you can change it
var authCredentials = "grant_type=password&username=" + WebUtility.UrlEncode(LoginBindingModel.Email) + "&password=" + LoginBindingModel.Password;
string response = await Client.MakePostFormRequest("token", authCredentials);
public static async Task<string> MakePostFormRequest(string url, string data)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(BaseUrl + "token");
// Set the Method property of the request to POST.
request.Accept = "*/*";
request.Method = "POST";
// Create POST data and convert it to a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(data);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// Set the ContentLength property of the WebRequest.
//request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = await request.GetRequestStreamAsync().ConfigureAwait(false);
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Dispose();
// Get the response.
WebResponse response = await request.GetResponseAsync().ConfigureAwait(false);
// Display the status.
//Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
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.
TokenViewModel TokenViewModel = JsonConvert.DeserializeObject<TokenViewModel >(responseFromServer);
VariablesGlobales.Token = TokenViewModel.access_token;
VariablesGlobales.LoginStamp = TokenViewModel.LoginStamp;
reader.Dispose();
dataStream.Dispose();
response.Dispose();
return responseFromServer;
}
catch (Exception ex)
{
return "";
}
}
And when you want to authenticate your request
public static async Task<string> MakePostRequest(string url, string data)
{
var result = "";
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(BaseUrl + url);
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
if (VariablesGlobales.Token != "")
{
httpWebRequest.Headers[HttpRequestHeader.Authorization] = "Bearer " + VariablesGlobales.Token;
}
using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)))
{
streamWriter.Write(data);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)(await httpWebRequest.GetResponseAsync().ConfigureAwait(false));
if (httpResponse.StatusCode.ToString() == "OK")
{
result = httpResponse.StatusCode.ToString();
}
else
{
result = "";
}
}
catch (Exception ex)
{
result = "";
}
return result;
}
}

How to get a JSON Object from a Jersey POST Response

I am working at the REST API for a new Social Network Android App at the moment using Spring Android for the Client and Spring Boot for the Server.
I am having trouble securing the Server using Spring Security, because i don't understand how to use it properly. After reading tons of sample apps i gave up on spring security and found this tutorial on how to secure APIs using Jersey.
Instead of javascript i am using the Jersey Client API to test the implementation
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080/demo-business-resource/login");
Invocation.Builder invoBuilder = target.request();
invoBuilder.header("service_key", "3b91cab8-926f-49b6-ba00-920bcf934c2a");
MultivaluedMap formData = new MultivaluedMapImpl();
formData.add("username", "username2");
formData.add( "password", "passwordForUser2");
Response response = invoBuilder.post(Entity.form(formData));
System.out.println(response);
response.getEntity();
The POST request is successful, but i cant get the JSON object which should be the Entity of the Response. response.getEntity(); returns a HttpUrlConnector Object.
Here the related Server Code
#POST
#Path( "login" )
#Produces( MediaType.APPLICATION_JSON )
public Response login(
#Context HttpHeaders httpHeaders,
#FormParam( "username" ) String username,
#FormParam( "password" ) String password ) {
DemoAuthenticator demoAuthenticator = DemoAuthenticator.getInstance();
String serviceKey = httpHeaders.getHeaderString( DemoHTTPHeaderNames.SERVICE_KEY );
try {
String authToken = demoAuthenticator.login( serviceKey, username, password );
JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();
jsonObjBuilder.add( "auth_token", authToken );
JsonObject jsonObj = jsonObjBuilder.build();
return getNoCacheResponseBuilder( Response.Status.OK ).entity( jsonObj.toString() ).build();
} catch ( final LoginException ex ) {
JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();
jsonObjBuilder.add( "message", "Problem matching service key, username and password" );
JsonObject jsonObj = jsonObjBuilder.build();
return getNoCacheResponseBuilder( Response.Status.UNAUTHORIZED ).entity( jsonObj.toString() ).build();
}
}
private Response.ResponseBuilder getNoCacheResponseBuilder( Response.Status status ) {
CacheControl cc = new CacheControl();
cc.setNoCache( true );
cc.setMaxAge( -1 );
cc.setMustRevalidate( true );
return Response.status( status ).cacheControl( cc );
}
I am new to Jersey and i only want to use it to generate the Authentication Token, because i get 404 Not Found errors using Spring. (I am working with spring-jersery )
Here my Spring approach of the client
RestTemplate template = new RestTemplate();
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add("service_key", "3b91cab8-926f-49b6-ba00-920bcf934c2a");
MultiValueMap<String,String> formData=new LinkedMultiValueMap<String,String>();
formData.add("username", "username2");
formData.add( "password", "passwordForUser2");
Model_LoginProfile log = new Model_LoginProfile();
log.setLoginName("username2");
log.setPassword("passwordForUser2");
HttpHeaders requestHeaders=new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
requestHeaders.set("service_key", "3b91cab8-926f-49b6-ba00-920bcf934c2a");
HttpEntity<Model_LoginProfile> requestEntity = new HttpEntity<Model_LoginProfile>(log, requestHeaders);
ResponseEntity<String> result = template.postForEntity("http://localhost:8080/demo-business-resource/login", requestEntity, String.class);
}
Maybe someone has a fix for that as well. :)
Thanks in advance

post json as httpcontent to webapi

I have a webapi that i want to post json to and then return json. Im using xamarin to create my android app but it doesn't seem to support PostAsJsonAsync method for the httpclient. So im now trying PostAsync method that post httpcontent. So what i want to do is convert my json to so that it is of format httpcontent and json so that i can post it to my webapi. This is my code:
var clientRequest = new ResourceByNameRequest
{
Name = "G60",
UserId = "1"
};
var param = JsonConvert.SerializeObject(clientRequest);
HttpContent content = new StringContent(param, Encoding.UTF8, "application/json");
var client = new HttpClient();
var cancellationToken = new CancellationToken();
var result = client.PostAsync("https://mctwebapi-test.entrematic.com/api/Resource/ResourceByName?", content, cancellationToken).Result;
return reslist;
this just runs till the timeout. I can't figure out why it doesn't work. If you have any other suggestions on how to post json to webapi using Xamarin im more than happy to try that out!
Plz help!

Xamarin Android Rest API to PassSlot - nameResolutionFailure

I'm using a REST API to access PassSlot in an attempt to generate a pass / coupon. It seems that when i run the program i get the error: "Error: NameResolutionFailure".
I have:
public static async Task<string> SendAndReceiveJsonRequest()
{
string responseStr = null;
string uri = "https://api.passslot.com/v1/templates/my-template-ID/pass";
// Create a json string with a single key/value pair.
var json = new JObject (new JProperty ("lastName", lastName),
new JProperty ("firstName", firstName),
new JProperty ("percentOff", percentOff),
new JProperty ("offerDescription", offerDescription),
new JProperty ("entityName", entityName),
new JProperty ("expiry", expiry));
//Console.WriteLine ("Jake's JSON " + json.ToString ());
using (var httpClient = new HttpClient ())
{
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("My-Key-Here-xxx-xxx-xxx");
//create the http request content
HttpContent content = new StringContent(json.ToString());
try
{
// Send the json to the server using POST
Task<HttpResponseMessage> getResponse = httpClient.PostAsync(uri, content);
// Wait for the response and read it to a string var
HttpResponseMessage response = await getResponse;
responseStr = await response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
Console.WriteLine("Error communicating with the server: " + e.Message);
}
}
return responseStr;
}
I'm running this on Android 4.4 via a Nexus 4. I'm on 3G (not wifi).
Any hints as to what might be happening here and why i'm getting the error.
In case the url request is in local network, Check if you url ip is set in the hosts device (the hosts setting of the smartphone, tablet, whatever you are using to test)
PD.
To edit the hosts setting device in android you may use this app
https://play.google.com/store/apps/details?id=com.nilhcem.hostseditor

Categories

Resources