Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

Connecting to Social Network APIs with Spring.NET Social

5.00/5 (2 votes)
21 Nov 2018CPOL8 min read 22.6K   689  
Spring.NET Social helps you to simplify authentication (OAuth) and API binding with Software-as-a-Service (SaaS) providers such as Facebook and Twitter.

Introduction

Spring.NET Social makes it easy to add support for service providers that are not already supported by the framework.

If you review the existing client projects, such as Twitter, Dropbox, LinkedIn and Facebook, you will discover they are implemented in a consistent manner and they apply a set of well-defined extension points.

In this article, you will learn how to add support for new service providers you wish to support.

Process Overview

The process of adding support for a new service provider consists of several steps:

  1. Create a source project for the client code, e.g., Spring.Social.Twitter.
  2. Develop or integrate a binding to the provider's API, e.g., ITwitter.
  3. Create an IServiceProvider model that allows users to authorize with the remote provider and obtain authorized API instances, e.g., TwitterServiceProvider.

The following sections of this article walk you through each of the steps with examples.

Creating a Source Project for the Provider Client Code

We recommend the code for a new Social client code reside within the Spring.Social.{providerId} assembly, where {providerId} is a unique identifier you assign to the service provider you are adding support for.

Within the assembly, we recommend the following namespace structure:

Namespace Provider
Spring.Social.{providerId}.Api The public interface and types that defines the API binding.
Spring.Social.{providerId}.Api.Impl The implementation of the API binding.
Spring.Social.{providerId}.Connect The types necessary to establish connections to the service provider.

You can see this recommended structure in action by reviewing Twitter project:

Here, the central service API type, ITwitter, is located in the Api namespace along with its supporting operations types and data transfer object types.

The primary implementation of that interface, TwitterTemplate, is located in the Api.Impl namespace (along with other internal types that have been excluded from this view).

Finally, the Connect namespace contains the implementations of the IServiceProvider that enable connections to Twitter to be established.

Developing a Binding to the Provider's API

Spring.NET Social favors the development of strongly-typed bindings to external service provider APIs.
This provides a simple, domain-oriented interface for .NET applications to use to consume the API.

Designing a New API Binding

API developers retain full control over the design and implementation of their API bindings.
That said, we offer several design guidelines in an effort to improve overall consistency and quality:

  • Favor separating the API binding interface from the implementation.
    This is illustrated in the Twitter example in the previous section.
    There, "Twitter" is the central API binding type and it is declared in the Spring.Social.Twitter.Api namespace with other public types.
    TwitterTemplate is the primary implementation of this interface and is located in the Spring.Social.Twitter.Api.Impl namespace along with other internal implementation types.
  • Favor organizing the API binding hierarchically by RESTful resource.
    REST-based APIs typically expose access to a number of resources in a hierarchical manner.
    For example, Twitter's API provides access to "status timelines", "searches", "lists", "direct messages", "friends", "geo location", and "users".
    Rather than add all operations across these resources to a single flat "Twitter" interface, the ITwitter interface is organized hierarchically:
C#
public interface ITwitter : IApiBinding
{ 
  IBlockOperations BlockOperations { get; } 
  IDirectMessageOperations DirectMessageOperations { get; } 
  IFriendOperations FriendOperations { get; } 
  IGeoOperations GeoOperations { get; } 
  IListOperations ListOperations { get; } 
  ISearchOperations SearchOperations { get; } 
  ITimelineOperations TimelineOperations { get; } 
  IUserOperations UserOperations { get; } 
  IRestOperations RestOperations { get; } 
} 

IDirectMessageOperations, for example, contains API bindings to Twitter's "direct messages" resource:

C#
public interface IDirectMessageOperations
{ 
  IList<DirectMessage> GetDirectMessagesReceived();
  IList<DirectMessage> GetDirectMessagesReceived(int page, int pageSize);
  IList<DirectMessage> GetDirectMessagesReceived(int page, int pageSize, long sinceId, long maxId);
  IList<DirectMessage> GetDirectMessagesSent();
  IList<DirectMessage> GetDirectMessagesSent(int page, int pageSize); 
  IList<DirectMessage> GetDirectMessagesSent(int page, int pageSize, long sinceId, long maxId)
  DirectMessage GetDirectMessage(long id);
  DirectMessage SendDirectMessage(string toScreenName, string text); 
  DirectMessage SendDirectMessage(long toUserId, string text); 
  void DeleteDirectMessage(long messageId);
} 

Implementing a New API Binding

API developers are free to implement their API binding with whatever REST/HTTP client they see fit. That said, Spring.NET Social's existing bindings such as Twitter all use Spring.NET REST Client Framework's RestTemplate.
RestTemplate is a REST client that provides a uniform object mapping interface across a variety of data exchange formats (JSON, XML, etc.).

As discussed in the previous section, we recommend keeping implementation types separate from the public API types. We also recommend keeping implementation details internal.
The way in which an API binding implementation is constructed will vary based on the API's authorization protocol. For APIs secured with OAuth1, the consumerKey, consumerSecret, accessToken, and accessTokenSecret will be required for construction:

C#
public TwitterTemplate(string consumerKey, string consumerSecret, 
                       string accessToken, string accessTokenSecret) 
{ 
  ... 
} 

For OAuth2, only the accessToken should be required:

C#
public GitHubTemplate(string accessToken) 
{ 
  ... 
} 

Each request made to the API server needs to be signed with the authorization credentials provided during construction of the binding.
This signing process consists of adding an "Authorization" header to each client request before it is executed.
For OAuth1, the process is quite complicated, and is used to support an elaborate request signature verification algorithm between the client and server.
For OAuth2, it is a lot simpler, but does still vary across the various drafts of the OAuth2 specification.

To encapsulate this complexity, for each authorization protocol, Spring Social provides a base class you may extend from to construct a pre-configured RestTemplate instance that performs the request signing for you.

For OAuth1:

C#
public class TwitterTemplate : AbstractOAuth1ApiBinding 
{
  public TwitterTemplate(string consumerKey, string consumerSecret, 
                         string accessToken, string accessTokenSecret) 
    : base(consumerKey, consumerSecret, accessToken, accessTokenSecret);
  {    
  }
}  

For OAuth2:

C#
public class GitHubTemplate : AbstractOAuth2ApiBinding 
{
  public GitHubTemplate(string accessToken) 
    : base(accessToken);
  {        
  }
} 

Once configured as shown above, you simply implement call RestTemplate and implement the various API operations.
The existing Spring.NET Social client modules all invoke their RestTemplate instances in a standard manner:

C#
public TwitterProfile GetUserProfile() 
{
  return this.RestTemplate.GetForObject<TwitterProfile>("account/verify_credentials.json");
}  

For complete implementation examples, consult the source of the existing extensions based on Spring.NET Social.

Testing a New API Binding

As part of the RestTemplate component, Spring.NET REST Client Framework includes a framework for unit testing RestTemplate based code.
This framework consists of a "MockRestServiceServer" that can be used to mock out API calls to the remote service provider.
This allows for the development of independent, performant, automated unit tests that verify client API binding and object mapping behavior.

To use, first create a MockRestServiceServer against the RestTemplate instance used by your API implementation:
In this example, TwitterTemplate uses a RestTemplate to consume Twitter REST API resources.

C#
TwitterTemplate twitter = new TwitterTemplate("consumerKey", "consumerSecret", 
                                              "accessToken", "accessTokenSecret");
MockRestServer mockServer = MockRestServiceServer.CreateServer(twitter.RestTemplate);   

Then, for each test case, record expectations about how the server should be invoked and answer what it should respond with:

C#
[Test]
public void UpdateStatus() 
{
  HttpHeaders responseHeaders = new HttpHeaders();
  responseHeaders.ContentType = MediaType.APPLICATION_JSON;
    
  mockServer.ExpectNewRequest()
    .AndExpectUri("https://api.twitter.com/1/statuses/update.json")
    .AndExpectMethod(HttpMethod.POST)
    .AndExpectHeader("Content-Type", "application/x-www-form-urlencoded")
    .AndExpectBody("status=Test+Message")
    .AndRespondWith(JsonResource("Status"), responseHeaders);

  Tweet tweet = twitter.UserOperations.UpdateStatus("Test Message");
  Assert.AreEqual(12345, tweet.ID);
  Assert.AreEqual("Test Message", tweet.Text);
} 

In the example above, the response body is written from a 'Status.json' embedded resource file located in the same namespace as the test class:

C#
private IResource JsonResource(string filename) 
{
  return new AssemblyResource(filename + ".json", typeof(TwitterTemplateTests));
}

The content of the file should mirror the content the remote service provider would return, allowing the client JSON deserialization behavior to be fully tested:

JavaScript
{
  "id" : 12345,
  "text" : "Tweet 1",
  ...
}

For complete test examples, consult the source of the existing extensions based on Spring.NET Social.

Creating a ServiceProvider Model

As described in the previous section, a client binding to a secure API such as GitHub or Twitter requires valid user authorization credentials to work.
Such credentials are generally obtained by having your application conduct an authorization "dance" or handshake with the service provider.
Spring.NET Social provides the IServiceProvider<T> abstraction to handle this "authorization dance". The abstraction also acts as a factory for native API (T) instances.

Since the authorization dance is protocol-specific, an IServiceProvider specialization exists for each authorization protocol.
For example, if you are connecting to a OAuth2-based provider, you would implement IOAuth2ServiceProvider.
After you've done this, your implementation can be used to conduct the OAuth2 dance and obtain an authorized API instance.
The following sections describe the implementation steps for each ServiceProvider type.

OAuth 2

To implement an OAuth2-based ServiceProvider, first create a subclass of AbstractOAuth2ServiceProvider<T> named {ProviderId}ServiceProvider.
Parameterize generic type T to be the binding to the ServiceProvider's API.
Define a single constructor that accepts a clientId and clientSecret.
Finally, implement GetApi(string) to return a new API instance.

See GitHub and Facebook samples as an example for OAuth2 based service provider:

C#
public class GitHubServiceProvider : AbstractOAuth2ServiceProvider<IGitHub>
{
  public GitHubServiceProvider(string clientId, string clientSecret)
    : base(new OAuth2Template(clientId, clientSecret,
      "https://github.com/login/oauth/authorize",
      "https://github.com/login/oauth/access_token"))
  {
  }

  public override IGitHub GetApi(string accessToken)
  {
    return new GitHubTemplate(accessToken);
  }
} 

In the constructor, you should call base class constructor, passing up the configured OAuth2Template that implements IOAuth2Operations.
The OAuth2Template will handle the "OAuth dance" with the provider, and should be configured with the provided clientId and clientSecret, along with the provider-specific authorizeUrl and accessTokenUrl.

Some providers support provider sign-in through an authentication URL that is distinct from the authorization URL. Using the OAuth2Template constructor as shown above will assume that the authentication URL is the same as the authorization URL. But you may specify a different authentication URL by using OAuth2Template's other constructor.

In GetApi(string), you should construct your API implementation, passing it the access token needed to make authorized requests for protected resources.

OAuth 1

To implement an OAuth2-based ServiceProvider, first create a subclass of AbstractOAuth1ServiceProvider<T> named {ProviderId}ServiceProvider.
Parameterize generic type T to be the binding to the ServiceProvider's API.
Define a single constructor that accepts a consumerKey and consumerSecret.
Finally, implement GetApi(string, string) to return a new API instance.

See Twitter and LinkedIn samples as an example for OAuth1 based service provider:

C#
public class TwitterServiceProvider : AbstractOAuth1ServiceProvider<ITwitter>
{
  public TwitterServiceProvider(string consumerKey, string consumerSecret)
    : base(consumerKey, consumerSecret, new OAuth1Template(consumerKey, consumerSecret,
      "https://api.twitter.com/oauth/request_token",
      "https://api.twitter.com/oauth/authorize",
      "https://api.twitter.com/oauth/authenticate",
      "https://api.twitter.com/oauth/access_token"))
  {
  }

  public override ITwitter GetApi(string accessToken, string secret)
  {
    return new TwitterTemplate(this.ConsumerKey, this.ConsumerSecret, accessToken, secret);
  }
} 

In the constructor, you should call base class constructor, passing up the consumerKey, secret, and configured OAuth1Template that implements IOAuth1Operations.
The OAuth1Template will handle the "OAuth dance" with the provider.
It should be configured with the provided consumerKey and consumerSecret, along with the provider-specific requestTokenUrl, authorizeUrl, authenticateUrl, and accessTokenUrl.
The authenticateUrl parameter is optional and may be left out if the provider doesn't have an authentication URL that is different than the authorization URL.

As you can see here, OAuth1Template is constructed with Twitter's authentication URL (used for provider sign-in), which is distinct from their authorization URL.
Some providers don't have separate URLs for authentication and authorization.
In those cases, you can use OAuth1Template's other constructor which doesn't take the authentication URL as a parameter.

In GetApi(string, string), you should construct your API implementation, passing it the four tokens needed to make authorized requests for protected resources.

Conclusion

Check out the attached sample and see how it's easy to connect and use network social APIs with Spring.NET Social.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)