Introducing Refit 2.0

I've just released a brand new version of Refit, the portable C# library inspired by Jake Wharton's Retrofit.

What's Refit?

Refit (along with http://json2csharp.com) allow you to really quickly create client libraries for Web APIs, by defining their contract in an Interface, and letting Refit do the grunt work of implementing the API for you. Here's an example:

public interface IGitHubService  
{
    [Get("/users/{user}/repos")]
    Task<List<Repo>> ListRepos(string user);
}

Now, use RestService to get an implementation of this Interface that does the work for you:

var client = RestService.For<IGitHubService>("https://api.github.com");  
var repos = await client.ListRepos("paulcbetts");  

Check out the ReadMe for a ton of great examples that demonstrate what you can do with Refit. Here's what's new in Refit 2.0:

Support for Xamarin.iOS 64-bit (#38)

Refit 2.0 uses a completely different system to generate the backing classes for your interfaces. In Refit 1.0, these classes would be generated at runtime using Castle.Core, which worked on most platforms, but fails on any Ahead-of-Time compiled platform, such as Xamarin.iOS.

Refit 2.0 instead generates classes at compile-time, by analyzing your app's source files with Roslyn, and generates a new RefitStubs.cs file that will be compiled along with your app. As well as enabling Xamarin.iOS 64-bit support, this class is easily subclassed and extended via partial classes, so customizing individual method behavior is now much easier.

Unfortunately, because of build system limitations, this method doesn't work with Xamarin.iOS 32-bit - you'll need to upgrade to the new Unified API before this will work in your app.

Support for Windows Store / Windows Phone 8.1 Universal Apps (#59, thanks @bennor)

Because of the compile-time code generation mentioned above, Refit 2.0 now has full support for WinRT (Windows Store) and Windows Phone 8.1 Universal applications too!

Observables in Refit are now Cold (#56, thanks to @balauru for some of the work)

Observables in Refit 1.x are backed by AsyncSubject, meaning that they replay a single result to subscribers, even after the network request ends. In Refit 2.0, Observables now do no work until Subscribed to, and each Subscription will generate a new network request, in line with Retrofit. Observables in Refit 2.0 now also will cancel network operations if the Subscription is disposed, allowing you to efficiently cancel requests if they are no longer needed.

Before:

var observable = someRestService.ReturnsAnObservable();  
var result1 = await observable;  
var result2 = await observable;

// result2 is just a replayed result1, the network request was made when
// we called ReturnsAnObservable regardless if anyone cared.
result1 == result2;  
>>> true

After:

// Does nothing
var observable = someRestService.ReturnsAnObservable();

// Makes a web request
var result1 = await observable;

// Makes a *different* web request
var result2 = await observable;

result1 == result2;  
>>> maybe?

Form Property Aliasing (#55, thanks @bennor)

When POSTing bodies serialized via BodySerializationMethod.UrlEncoded, the AliasAs tag now also works on properties in the model class:

Before:

public interface IMeasurementProtocolApi  
{
    [Post("/collect")]
    Task Collect([Body(BodySerializationMethod.UrlEncoded)] Measurement measurement);
}

public class Measurement  
{
    public string t { get; set; } // This isn't even the worst of them
}

await api.Collect(new Measurement { t = "what even is t?" });  

After:

// This part doesn't change
public interface IMeasurementProtocolApi  
{
    [Post("/collect")]
    Task Collect([Body(BodySerializationMethod.UrlEncoded)] Measurement measurement);
}

// This stuff does
public Measurement  
{
    [AliasAs("t")] 
    public string Type { get; set; }
}

await api.Collect(new Measurement { Type = "event" });