#xamarinhackday

@GeoffreyHuntley

EndlessCats

Solution Setup

# Install-Package ModernHttpClient
# Install-Package Refit
# Install-Package Fusillade
# Install-Package Akavache
# Install-Package ModernHttpClient
# Install-Package Akavache

EndlessCatsApp.Core

EndlessCatsApp.iOS

EndlessCatsApp.Droid

EndlessCats.WPA81

# Install-Package ModernHttpClient
# Install-Package Akavache
# Install-Package Akavache
[Headers("User-Agent: " + AppSettings.ApiClientUserAgent)]
public interface IEndlessCatsApi
{
    /// <remarks>
    /// - You can redefine the user-agent header on a per request basis via: 
    ///   [Headers("User-Agent: ELinks/0.9.3 (textmode; Linux 2.6.11 i686; 79x24)"]
    ///
    /// - You can remove the user-agent header on a per request basis via:
    ///   [Headers("User-Agent")]
    /// </remarks>
    [Get("/cats")]
    Task<List<CatResponse>> GetMoreCats([Header("X-Auth-Token")] string apiKey);
}

Setup

var endlessCatsApi = RestService.For<IApiService>("http://endlesscats.azurewebsites.net/api");

var cats = await endlessCatsApi.GetMoreCats(AppSettings.ClientApiKey);

Usage

  • Auto-deduplication of requests - if every instance of your TweetView class requests the same avatar image, Fusillade will only do one request and give the result to every instance.

  • Request Limiting - Requests are always dispatched 4 at a time. Issue. Lots of requests without overwhelming the network connection.

  • Request Prioritization - background requests should run at a lower priority than requests initiated by the user, but actually implementing this is quite difficult. With a few changes to your app, you can hint to Fusillade which requests should skip to the front of the queue.

  • Speculative requests - On page load, many apps will try to speculatively cache data (i.e. try to pre-download data that the user might click on). Marking requests as speculative will allow requests until a certain data limit is reached, then cancel future requests (i.e. "Keep downloading data in the background until we've got 5MB of cached data")

Setup

// Set up Fusillade
//
// Fusillade is a super cool library that will make it so that whenever
// we issue web requests, we'll only issue 4 concurrently, and if we
// end up issuing multiple requests to the same resource, it will
// de-dupe them. We're saying here, that we want our *backing*
// HttpMessageHandler to be ModernHttpClient.
Locator.CurrentMutable.RegisterConstant(
                            new NativeMessageHandler(), 
                            typeof(HttpMessageHandler));
    public class ApiService : IApiService
    {
        public const string ApiBaseAddress = "https://endlesscats.azurewebsites.net/api";

        public ApiService(string apiBaseAddress = null)
        {
            Func<HttpMessageHandler, IEndlessCatsApi> createClient = messageHandler =>
            {
                Ensure.ArgumentIsOfType(messageHandler, typeof(RateLimitedHttpMessageHandler), "Fusillade RateLimitedHttpMessageHandler");

                var client = new HttpClient(messageHandler)
                {
                    BaseAddress = new Uri(apiBaseAddress ?? ApiBaseAddress)
                };

                return RestService.For<IEndlessCatsApi>(client);
            };

            _background = new Lazy<IEndlessCatsApi>(() => RestService.For<IEndlessCatsApi>(ApiBaseAddress));
            _userInitiated = new Lazy<IEndlessCatsApi>(() => RestService.For<IEndlessCatsApi>(ApiBaseAddress));
            _speculative = new Lazy<IEndlessCatsApi>(() => RestService.For<IEndlessCatsApi>(ApiBaseAddress));
        }

        private readonly Lazy<IEndlessCatsApi> _background;
        private readonly Lazy<IEndlessCatsApi> _userInitiated;
        private readonly Lazy<IEndlessCatsApi> _speculative;

        public IEndlessCatsApi Background
        {
            get { return _background.Value; }
        }

        public IEndlessCatsApi UserInitiated
        {
            get { return _userInitiated.Value; }
        }

        public IEndlessCatsApi Speculative
        {
            get { return _speculative.Value; }
        }
    }

Usage

const string apiKey = "itsasecret!"

var client = Locator.Current.GetService<IApiService>();


# background
client.Background.GetMoreCats(apiKey);

# user
client.UserInitiatved.GetMoreCats(apiKey);

# speculative
client.Speculative.GetMoreCats(apiKey;
Cats = await BlobCache.LocalMachine.GetOrFetchObject(BlobCacheKeys.Cats,
    async () => {
        var cats = await endlesscatsApi.GetMoreCats();

        if (cats == null || cats == 0) {
            throw new Exception("No cats left!");
        }

        return cats;
    },
    RxApp.MainThreadScheduler.Now + TimeSpan.FromMinutes(5));

Usage

Xamarin Hackday - EndlessCats

By Geoffrey Huntley

Xamarin Hackday - EndlessCats

  • 1,197