1

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:

Response is null

Any guidance is appreciated!

6
  • You're not awaiting _MakeRequestAsync (""); use var request = await _MakeRequestAsync (""); Commented Mar 12, 2015 at 7:03
  • Can you test you service with fiddler or something similar to ensure you're actually getting data back? Commented Mar 12, 2015 at 13:48
  • with that addition, it does not build: var request = await _MakeRequestAsync (""); "Cannot await 'string'" I just don't understand why this works perfectly (without async/await) when all classes are kept within the Droid project, but once moved to the PCL project everything goes wrong. Commented Mar 12, 2015 at 19:04
  • Maybe I am over thinking it. The initial api call is to GET (with contentType = application/json) an authentication token (when passed the api url with credentials appended to the url). Here is the raw result returned (via postman): {"PartnerId":"XYZuserApi","Token":"Wa8rhN-LFUm3_vWoPKQsCw"}. In the above sample, I am trying to obtain the token as a variable, using PCL. Commented Mar 12, 2015 at 20:05
  • just compared with an example of mine, use: return await result.Content.ReadAsStringAsync(); Commented Mar 13, 2015 at 6:56

1 Answer 1

0

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();
            };
        }
Sign up to request clarification or add additional context in comments.

10 Comments

Thank you Milen. Using your provided snippet, I got the following error: 'System.Net.Http.HttpContent' does not contain a definition for 'ReadAsAsync'.
After adding the package 'Microsoft.AspNet.WebApi.Client' I was able to get past the above mentioned error (thanks to stackoverflow.com/questions/14520762/…) However, now I get the following when debugging: "await response.Content.ReadAsAsync<string>() response is null"
so if you use it like var res = await _MakeRequestAsync(myparams) you're getting null ?
Have a look at these examples: asp.net/web-api/overview/advanced/…
I modified the call like so: var json = await client._MakeRequestAsync(); Now I am getting "cannot convert from Task<string> to string" error in the following line in 'authenticate' (full code above): var o = JObject.Parse(EntryRepository.getJson(PJTApiUrls.getAuthenticationUrl(apiUser,apiPass)));
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.