Last active
August 29, 2015 14:10
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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