Skip to content

Instantly share code, notes, and snippets.

@kentpickard
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kentpickard/ba94e62febd92a3d35bc to your computer and use it in GitHub Desktop.
Save kentpickard/ba94e62febd92a3d35bc to your computer and use it in GitHub Desktop.
Xamarin MonoTouch: Example of manually closing a ServicePoint connection group when there are no pending requests. This is needed to allow network calls to continue working when the user switches from one wireless network to another. This is a workaround for bug https://bugzilla.xamarin.com/show_bug.cgi?id=23806
public class UserApiClient : BaseApiClient
{
// Example of making a call to API in order to get a user by ID
public Task<User> GetUser(int Id)
{
// using RunWithConnectionCloser will call ServicePoint.CloseConnectionGroup as long as there are no other pending operations.
// Its important that all service calls are wrapped with RunWithConnectionCloser
return BaseApiClient.RunWithConnectionCloser (() => {
// Make service call using RestSharp (what I'm using), HttpWebRequest, HttpClient, or whatever
// this assumes one ApiBaseAddress for all these service calls
var client = GetApiClient (GlobalAppSettings.ApiBaseAddress);
var request = new RestRequest(string.Format("User/Get/{0}", id), Method.GET);
var response = client.Execute(request);
// should check for errors. not showing that...
// Data is an instance of the User class
return response.Data;
});
}
}
public class BaseApiClient
{
// used as lock object for incrementing or decrementing _OpenRequests
static object _OpenRequestsLockObj = new Object();
// tracks the number of open requests
static int _OpenRequests = 0;
// increments the number of open requests
static void _BeforeServiceCall()
{
lock (_OpenRequestsLockObj)
_OpenRequests++;
}
// decrements the number of open requests and closes the connection group if there are none
static void _AfterServiceCall()
{
lock(_OpenRequestsLockObj)
{
_OpenRequests--;
if(_OpenRequests == 0)
{
Debug.WriteLine("Closing Svc Point Connection");
// This will force close the connection once there are no open requests. If the connection is closed while a request is pending,
// it may time out due to internal locks within the ServicePoint, or could just fail depending on exact timeing.
var sp = ServicePointManager.FindServicePoint(new Uri(GlobalAppSettings.ApiBaseAddress));
sp.CloseConnectionGroup(null);
}
}
}
/// <summary>
/// Wraps a async call increments and decrements the number of open connections to the API
/// </summary>
/// <returns>A running task that will provide the requested instance of TResult</returns>
/// <param name="function">function that executes a service call</param>
/// <typeparam name="TResult">type of result</typeparam>
public static Task<TResult> RunWithConnectionCloser<TResult> (Func<TResult> function)
{
return Task.Run (() => {
_BeforeServiceCall();
var r = function();
_AfterServiceCall();
return r;
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment