Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin Portable Class Library Gets Proxy Access Denied on iPhone Simulator

I've run into a bit of an issue with the iPhone simulator when trying to access a WCF REST service. I've asked the question on the Xamarin forums, but no joy.

Some context:

  • I have a PCL for a Xamarin cross platform project, in VS 2012.
  • I use the Portable Microsoft HttpClient package and the Json.NET package.
  • I have a pretty simple WCF REST service sitting in the background.

When testing

  • I can access the service fine from a browser on the dev machine.
  • I can access it fine using a console application going via the PCL.
  • I can access it fine via the app, from a real android device on the WiFi network of the same corporate network.
  • I can access it fine from Safari on the build Mac.
  • I can access it fine from Safari on the iPhone simulator on the build Mac.

The issue is, as soon as I try to access the service via the app on the iPhone simulator, I get a 407, Proxy Access Denied error.

Here is the code I'm using to set up the connection:

private static HttpRequestMessage PrepareRequestMessage(HttpMethod method, string baseUri, 
    string queryParameters, out HttpClient httpClient, string bodyContent)
{
    var finalUri = new Uri(baseUri + queryParameters);

    var handler = new HttpClientHandler();

    httpClient = new HttpClient(handler);  

    var requestMessage = new HttpRequestMessage(method, finalUri);

    if (handler.SupportsTransferEncodingChunked())
    {
        requestMessage.Headers.TransferEncodingChunked = true;
    }

    if (method == HttpMethod.Post || method == HttpMethod.Put)
    {
        requestMessage.Content = 
            new StringContent(bodyContent, Encoding.UTF8, "application/json");
    }

    return requestMessage;
}

That code gives me the 407 error.

I have tried setting the proxy by using various combinations of SupportsProxy and SupportsUseProxy. (Both returning false from the simulator.) I've tried forcing the proxy settings regardless. I've tried setting the credentials on the handler itself. I've tried playing with the UseDefaultCredentials and UseProxy flags. I've also tried setting the IfModifiedSince value in the message header. I've tried using the PortableRest package as well.

All of that only seemed to make things worse. Where I was initially getting the 407 error, the call to httpClient.GetAsync would just immediately return null.

I am at a bit of a loss here, so any help would be greatly appreciated.

PS. For completeness, the rest of the surrounding code that makes the call: (please forgive crappy exception handling, I'm still playing around with the errors)

public static async Task<T> SendRESTMessage<T>(HttpMethod method, string baseUri, 
    string queryParameters, T contentObject)
{
    HttpClient httpClient;

    var payload = string.Empty;
    if (contentObject != null)
    {
        payload = JsonConvert.SerializeObject(contentObject);
    }
    var requestMessage = 
        PrepareRequestMessage(method, baseUri, queryParameters, out httpClient, payload);

    HttpResponseMessage responseMessage = null;
    try
    {
        if (method == HttpMethod.Get)
        {
            responseMessage = await httpClient.GetAsync(requestMessage.RequestUri);                    
        }
        else
        {
            responseMessage = await httpClient.SendAsync(requestMessage);
        }
    }
    catch (HttpRequestException exc)
    {
        var innerException = exc.InnerException as WebException;
        if (innerException != null)
        {
            throw new Exception("Unable to connect to remote server.");
        }
    }

    return await HandleResponse<T>(responseMessage);
}

private static async Task<T> HandleResponse<T>(HttpResponseMessage responseMessage)
{
    if (responseMessage != null)
    {
        if (!responseMessage.IsSuccessStatusCode)
        {                                       
            throw new Exception("Request was unsuccessful");
        }

        var jsonString = await responseMessage.Content.ReadAsStringAsync();
        var responseObject = JsonConvert.DeserializeObject<T>(jsonString);
        return responseObject;
    }                

    return default(T);
}        

This was my attempt at implementing IWebProxy quick and dirty, which I think could have made things worse:

public class MyProxy : IWebProxy
{
    private System.Net.ICredentials creds;        

    public ICredentials Credentials
    {
        get
        {
            return creds;
        }
        set
        {
            creds = value;
        }
    }

    public Uri GetProxy(Uri destination)
    {
        return new Uri("proxy addy here");
    }

    public bool IsBypassed(Uri host)
    {
        return true;
    }
}

Thanks again for taking the time to read my question.

like image 736
Amos_Keeto Avatar asked Jan 28 '26 09:01

Amos_Keeto


1 Answers

So I finally got it working.

Turns out it was something really stupid, but being new to iOS mobile dev and the fact that the service worked via Safari on the simulator threw me for a loop.

I read that the simulator uses the proxy settings as defined on the Mac. So I went to the network settings and added the service address to the proxy bypass list.

Works like a charm now.

If anybody feels there is a better way to do this, please add your opinions.

like image 182
Amos_Keeto Avatar answered Jan 31 '26 06:01

Amos_Keeto



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!