Archive

Archive for the ‘REST’ Category

Changing the supported media types of the default media formatters in the ASP.NET Web API client library

January 15, 2014 Leave a comment

A couple of days ago, I encountered an issue when calling a REST service. The REST service was returning JSON data, but the content type in the HTTP header was set to “text/javascript”. This caused the default JSON formatter of the ASP.NET Web API client not to recognize the data (he expects “application/json”). It took me a while to find this proper solution as I wanted to avoid creating a custom formatter, but the ASP.NET Web API client library allows to modify the supported content types for the default content formatters.

HttpClient client = new HttpClient();

MediaTypeFormatterCollection formatters = new MediaTypeFormatterCollection();
formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));

HttpResponseMessage response = await client.GetAsync(url);
SearchResult result = await response.Content.ReadAsAsync(formatters);
Advertisements
Categories: ASP.NET Web API, C#, REST

Google OAuth 2.0 on Windows Phone

March 11, 2013 6 comments

Introduction

OAuth is a protocol for authorization. It allows desktop, mobile and web applications to access web resources (mostly REST services) on behalf of a user. The protocol permits this without the user having to share its credentials (typically, a username and password pair) with the application. OAuth is a widely implemented protocol. Various companies (like Facebook, Twitter, Google, Microsoft, Dropbox …) use it to protect their APIs.

In this article, I will explain how we can implement support for Google OAuth in a Windows Phone application.

How does OAuth work

In a nutshell when developing a mobile application, a developer must register its application to the vendor of the service (in our case Google) who will assign a clientId and a clientSecret to the application.

The login flow starts with the application opening an embedded web browser control. This web control must load a specific Google login page. In the query string, the clientId of the application and the requested scopes are sent to the login page. Scopes are the actions the application wants to perform on behalf of the user. Google will handle the user authentication and consent, but at the end an authorization code is sent to the web browser control (using the “title” of the final HTML page).

OAuth Windows Phone authorization flow

After having received the authorization code, the application can exchange this for an access token and a refresh token. The access token can be used by the application to perform the necessary operations on behalf of the user. The refresh token must be stored for future use; it allows to request a new access token when the previous one expired.

Implementing Google OAuth on Windows Phone

You will have to register your application at https://code.google.com/apis/console#access. This will provide you a clientId and clientSecret that you can use to identity your application to the user when performing the OAuth flow.

My implementation consists of 2 big components, a class called “OAuthAuthorization” and a Windows Phone Page called “LogingPage”.

When the developer calls the method “Authorize” of the OAuthAuthorization class, the login page is opened on the screen. This page will show the embedded web browser control full screen (an important detail is that scripting support for this embedded must be activated; by default it is disabled). The Google login page is opened and navigated event handler is attached to the browser control. When the web browser control is redirected to the success page of the login flow, the authorization code is extracted and the login page is closed.


public partial class LoginPage : PhoneApplicationPage
{
    public LoginPage()
    {
        InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        IDictionary parameters = this.NavigationContext.QueryString;

        string authEndpoint = parameters["authEndpoint"];
        string clientId = parameters["clientId"];
        string scope = parameters["scope"];

        string uri = string.Format("{0}?response_type=code&client_id={1}&redirect_uri={2}&scope={3}",
            authEndpoint,
            clientId,
            "urn:ietf:wg:oauth:2.0:oob",
            scope);

        webBrowser.Navigate(new Uri(uri, UriKind.Absolute));
    }

    private void webBrowser_Navigated(object sender, NavigationEventArgs e)
    {
        string title = (string)webBrowser.InvokeScript("eval", "document.title.toString()");

        if (title.StartsWith("Success"))
        {
            string authorizationCode = title.Substring(title.IndexOf('=') + 1);
            PhoneApplicationService.Current.State["MobileOauth.AuthorizationCode"] = authorizationCode;

            NavigationService.GoBack();
        }
    }
}

Using the client id and the client secret, the OAuthAuthorization class will call a Google REST API to exchange the authorization code for an access token and a refresh token.

public class OAuthAuthorization
{
    private readonly string authEndpoint;
    private readonly string tokenEndpoint;
    private readonly PhoneApplicationFrame frame;

    public OAuthAuthorization(string authEndpoint, string tokenEndpoint)
    {
        this.authEndpoint = authEndpoint;
        this.tokenEndpoint = tokenEndpoint;
        this.frame = (PhoneApplicationFrame)(Application.Current.RootVisual);
    }

    public async Task Authorize(string clientId, string clientSecret, IEnumerable scopes)
    {
        string uri = string.Format("/MobileOauth;component/LoginPage.xaml?authEndpoint={0}&clientId={1}&scope={2}",
                                    authEndpoint,
                                    clientId,
                                    string.Join(" ", scopes));

        SemaphoreSlim semaphore = new SemaphoreSlim(0, 1);

        Observable.FromEvent(
            h => new NavigatingCancelEventHandler(h),
            h => this.frame.Navigating += h,
            h => this.frame.Navigating -= h)
                    .SkipWhile(h => h.EventArgs.NavigationMode != NavigationMode.Back)
                    .Take(1)
                    .Subscribe(e => semaphore.Release());

        frame.Navigate(new Uri(uri, UriKind.Relative));

        await semaphore.WaitAsync();

        string authorizationCode = (string)PhoneApplicationService.Current.State["MobileOauth.AuthorizationCode"];

        return await RequestAccessToken(authorizationCode, clientId, clientSecret);
    }

    public async Task RefreshAccessToken(string clientId, string clientSecret, string refreshToken)
    {
        HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(tokenEndpoint);
        httpRequest.Method = "POST";
        httpRequest.ContentType = "application/x-www-form-urlencoded";

        using (Stream stream = await httpRequest.GetRequestStreamAsync())
        {
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write("refresh_token=" + Uri.EscapeDataString(refreshToken) + "&");
                writer.Write("client_id=" + Uri.EscapeDataString(clientId) + "&");
                writer.Write("client_secret=" + Uri.EscapeDataString(clientSecret) + "&");
                writer.Write("grant_type=refresh_token");
            }
        }

        using (WebResponse response = await httpRequest.GetResponseAsync())
        {
            using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
            {
                string result = streamReader.ReadToEnd();
                TokenPair tokenPair = JsonConvert.DeserializeObject(result);
                tokenPair.RefreshToken = refreshToken;

                return tokenPair;
            }
        }
    }

    private async Task RequestAccessToken(string authorizationCode, string clientId,
                                            string clientSecret)
    {
        HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(tokenEndpoint);
        httpRequest.Method = "POST";
        httpRequest.ContentType = "application/x-www-form-urlencoded";

        using (Stream stream = await httpRequest.GetRequestStreamAsync())
        {
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write("code=" + Uri.EscapeDataString(authorizationCode) + "&");
                writer.Write("client_id=" + Uri.EscapeDataString(clientId) + "&");
                writer.Write("client_secret=" + Uri.EscapeDataString(clientSecret) + "&");
                writer.Write("redirect_uri=" + Uri.EscapeDataString("urn:ietf:wg:oauth:2.0:oob") + "&");
                writer.Write("grant_type=authorization_code");
            }
        }

        using (WebResponse response = await httpRequest.GetResponseAsync())
        {
            using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
            {
                string result = streamReader.ReadToEnd();
                return JsonConvert.DeserializeObject(result);
            }
        }
    }
}

Using the OAuth implementation

The implemented framework is simple in usage. The following example shows how to use it:

// Request an access token
OAuthAuthorization authorization = new OAuthAuthorization(
    "https://accounts.google.com/o/oauth2/auth", 
    "https://accounts.google.com/o/oauth2/token");
TokenPair tokenPair = await authorization.Authorize(
    ClientId,
    ClientSecret,
    new string[] {GoogleScopes.CloudPrint, GoogleScopes.Gmail});

// Request a new access token using the refresh token (when the access token was expired)
TokenPair refreshTokenPair = await authorization.RefreshAccessToken(
    ClientId,
    ClientSecret,
    tokenPair.RefreshToken);

The access token must be sent using the Authorization: Bearer HTTP header when calling a Google API.

Conclusion

Implementing OAuth support on Windows Phone is quite simple to do. The authentication and user consent logic is handled by Google and integrated into an app by embedding the web browser control. Once a token is obtained, the application can perform the requested actions on behalf of the user until the user revokes the access for the application.

I have put the source code on GitHub as a reusable framework. The OAuth framework should also be usable with the various other OAuth providers.

You can find it at: https://github.com/pieterderycke/MobileOAuth.

Categories: REST, Windows Phone 8

Translating an address to GPS coordinates with the Google Geocoding REST service

February 21, 2012 1 comment

For a hobby project, I recently needed to calculate distances between stores and find nearby stores. In order to implement the required functionality, I have used the Google Geocoding service to have GPS coordinates for all my database entries and then it was just a matter of applying the correct math.

The Google Geocoding service is a REST service offered free of charge by Google and no developer sign-up is required. It can translate an address string into GPS coordinates. Result data can be returned in XML or JSON format. The only limitation is that the free version can only geocode 2500 addresses per day.

More technical information can be found on the following web page: http://code.google.com/intl/en-US/apis/maps/documentation/geocoding.

In this blog post, I want to share the tinny wrapper I have created to simplify calling this web service.

I first created a generic interface for the Geocoder.

public interface IGeocoder
{
    Coordinates Geocode(string address);
}

I also created a small data structure for my coordinates.

public class Coordinates
{
    public Coordinates(double latitude, double longitude)
    {
        Latitude = latitude;
        Longitude = longitude;
    }

    public double Latitude { get; private set; }

    public double Longitude { get; private set; }
}

Then I wrote the following implementation that uses the Google web service. I use the XML format for geocoded addresses because XML is easier to parse in .Net applications without requiring 3rd party libraries. If you want to use this service from a WP7 application it would be better to use the more compact JSON format.

public class GoogleGeocoder : IGeocoder
{
    private const string ServiceUri = "http://maps.googleapis.com/maps/api/geocode/xml?address={0}&region=be&sensor=false";

    public Coordinates Geocode(string address)
    {
        if (string.IsNullOrEmpty(address))
            throw new ArgumentNullException("address");

        string requestUriString = string.Format(ServiceUri, Uri.EscapeDataString(address));

        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUriString);

        try
        {
            WebResponse response = request.GetResponse();

            XDocument xdoc = XDocument.Load(response.GetResponseStream());

            // Verify the GeocodeResponse status
            string status = xdoc.Element("GeocodeResponse").Element("status").Value;
            ValidateGeocodeResponseStatus(status, address);

            XElement locationElement = xdoc.Element("GeocodeResponse").Element("result").Element("geometry").Element("location");
            double latitude = (double)locationElement.Element("lat");
            double longitude = (double)locationElement.Element("lng");

            return new Coordinates(latitude, longitude);
        }
        catch (WebException ex)
        {
            switch(ex.Status)
            {
                case WebExceptionStatus.NameResolutionFailure:
                    throw new ServiceOfflineException("The Google Maps geocoding service appears to be offline.", ex);
                default:
                    throw;
            }
        }

    }

    private void ValidateGeocodeResponseStatus(string status, string address)
    {
        switch (status)
        {
            case "ZERO_RESULTS":
                string message = string.Format("No coordinates found for address \"{0}\".", address);
                throw new UnknownAddressException(message);
            case "OVER_QUERY_LIMIT":
                throw new OverQueryLimitException();
            case "OK":
                break;
            default:
                throw new Exception("Unkown status code: " + status + ".");
        }
    }
}
Categories: C#, REST

WCF REST tip 3: WebOperationContext

October 6, 2011 2 comments

People with experience in programming WCF services are probably aware that you can get information about the currently executing operation in a WCF service by retrieving the property “OperationContext.Current” inside a service method. This gives you access to incoming and outgoing message headers and properties.

This is sufficient for classic WCF services, but it lacks information that could be important for REST based WCF services. Luckily for us, Microsoft has foreseen this and they have created an additional Operation Context for these types of services: the WebOperationContext. The WebOperationContext provides easy access to various parts of the HTTP request and response messages: HTTP headers, HTTP method, …

In the following short example, I show how to retrieve the user agent of the caller and send it back formatted as JSON or as XML depending on the value of the Accept header in the request.

[DataContract]
public class UserAgentInfo
{
    public UserAgentInfo(string userAgent)
    {
        UserAgent = userAgent;
    }

    [DataMember]
    public string UserAgent { get; set; }
}
[WebGet(UriTemplate = "MyUserAgent")]
public Message GetMyUserAgent()
{
    string accept = WebOperationContext.Current.IncomingRequest.Accept;
    string userAgentValue = WebOperationContext.Current.IncomingRequest.UserAgent;
    UserAgentInfo userAgent = new UserAgentInfo(userAgentValue);

    switch (accept)
    {
        case "application/json":
            return WebOperationContext.Current.CreateJsonResponse<UserAgentInfo>(userAgent);
        default:
            return WebOperationContext.Current.CreateXmlResponse<UserAgentInfo>(userAgent);
    }
}
Categories: C#, REST, WCF

Configuring the WCF Web API without using the fluent API

Microsoft will add first class support for REST web services into the next version of WCF. A preview of this can be downloaded from: http://wcf.codeplex.com. After having seen the presentation of Glenn Block at the Belgium Microsoft Techdays, I wanted to start playing a little bit with the API and a couple of days ago I finally found the time to do it.

I am quite happy with the way how they will handle REST in .Net and it will make developing real REST services (instead of REST like services …) more easy. The only thing that annoyed me slightly was the fact that is not possible to configure the WCF Web API from the web.config. In my company we have different environments (development, test, …) and we have to promote the assemblies from one environment to the other, but we can have different config files depending on the environment. In the classical WCF, this allows us to enable custom logging or monitoring in for example test but not in production. With the fluent API, this kind of deployment time configuration is not possible. With our deployment system, if we would want to add WCF Web message handlers or operation handlers in test, it would also go to production or we would first have to promote a modified version to test without logging.

In order to fix this, I have written a custom service behavior that allows adding message handlers using the configuration file. Of course this could easily be extended with the other configuration options of the fluent API, but I want to keep my example as simple as possible. If people would be interested in a version with complete web.config support, then please let me know.

Hooking into the WCF Web API was remarkable easy. It adds endpoints of type HttpEndpoint for the REST services to the WCF stack. The HttpEndpoint provides access to features like the active message handlers. So all I had to do was looping over the endpoints in my service behavior and if it was of type HttpEndpoint than I added all the message handlers that were defined in the config file.

public class HttpConfigBehavior : IServiceBehavior
{
    private Type[] messageHandlers;

    public HttpConfigBehavior(IEnumerable<Type> messageHandlers)
    {
        if (messageHandlers == null)
            throw new ArgumentNullException("messageHandlers");

        this.messageHandlers = messageHandlers.ToArray();
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
        Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
        foreach (ServiceEndpoint serviceEndpoint in endpoints)
        {
            HttpEndpoint httpEndpoint = serviceEndpoint as HttpEndpoint;
            if (httpEndpoint != null)
            {
                httpEndpoint.MessageHandlerFactory = new HttpMessageHandlerFactory(messageHandlers);
            }
        }
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
}

In order to add in from the config file, I also had to create a BehaviorExtensionElement and the necessary configuration classes.

public class HttpConfigBehaviorExtensionElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(HttpConfigBehavior); }
    }

    protected override object CreateBehavior()
    {
        return new HttpConfigBehavior(
            MessageHandlers.OfType<MessageHandlerConfigurationElement>().Select(e => e.Type));
    }

    [ConfigurationProperty("messageHandlers")]
    public MessageHandlerConfigurationCollection MessageHandlers
    {
        get
        {
            return (MessageHandlerConfigurationCollection)base["messageHandlers"];
        }
        set
        {
            base["messageHandlers"] = value;
        }
    }
}
[ConfigurationCollection(typeof(MessageHandlerConfigurationElement))]
public class MessageHandlerConfigurationCollection : ConfigurationElementCollection
{
    public MessageHandlerConfigurationElement this[int index]
    {
        get
        {
            return (MessageHandlerConfigurationElement)base.BaseGet(index);
        }
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new MessageHandlerConfigurationElement();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((MessageHandlerConfigurationElement)element).Name;
    }
}
public class MessageHandlerConfigurationElement : ConfigurationElement
{
    [ConfigurationProperty("name", IsRequired=true)]
    public string Name
    {
        get
        {
            return (string)base["name"];
        }
        set
        {
            base["name"] = value;
        }
    }

    [ConfigurationProperty("type", IsRequired = true)]
    [TypeConverter(typeof(TypeNameConverter))]
    public Type Type
    {
        get
        {
            return (Type)base["type"];
        }
        set
        {
            base["type"] = value;
        }
    }
}
public class TypeNameConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(Type);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        return Type.GetType((string)value);
    }
}

We can now define WCF Web API message handlers from the config file:

<system.serviceModel>

  <behaviors>
    <serviceBehaviors>
      <behavior>
        <httpConfig>
          <messageHandlers>
            <add name="logger"
                  type="MvcApplication45.Util.LoggingChannel, MvcApplication45, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          </messageHandlers>
        </httpConfig>
      </behavior>
    </serviceBehaviors>
  </behaviors>

  <extensions>
    <behaviorExtensions>
      <add name="httpConfig" type="MvcApplication45.Util.HttpConfigBehaviorExtensionElement, MvcApplication45, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
    </behaviorExtensions>
  </extensions>

  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>

Conclusion

Although it is not provided out of the box, the WCF Web API can easily be configured using the web.config file. All that is required is some good old “classic” WCF knowledge. Your investment in learning classic WCF is thus definitely not lost. Glimlach

Categories: C#, REST, WCF

Adding synchronous methods to WebRequest on Windows Phone 7

May 23, 2011 6 comments

In general, I really like developing for Windows Phone 7. The tools like Visual Studio and Blend are of excellent quality and both Silverlight and XNA are very good frameworks. I only have one big annoyance and that’s the fact WebRequest does not support synchronous method calls. I am completely aware of the fact that you should not do heavy operations on the UI thread and I perform all my REST calls on a background thread, but I don’t like the fact that Microsoft forces me to make these calls asynchronously. As a developer, I would prefer to make this choice myself.

I have created 2 simple extension methods to add synchronous behavior to WebRequest.

public static class WebRequestExtensions
{
	public static WebResponse GetResponse(this WebRequest request)
	{
		AutoResetEvent autoResetEvent = new AutoResetEvent(false);

		IAsyncResult asyncResult = request.BeginGetResponse(r => autoResetEvent.Set(), null);

		// Wait until the call is finished
		autoResetEvent.WaitOne();

		return request.EndGetResponse(asyncResult);
	}

	public static Stream GetRequestStream(this WebRequest request)
	{
		AutoResetEvent autoResetEvent = new AutoResetEvent(false);

		IAsyncResult asyncResult = request.BeginGetRequestStream(r => autoResetEvent.Set(), null);

		// Wait until the call is finished
		autoResetEvent.WaitOne();

		return request.EndGetRequestStream(asyncResult);
	}
}

Please note: using an AutoResetEvent comes with a performance penalty, so this code is less efficient than a real synchronous method implementation.

Plase note 2: I know that you normally can also retrieve a WaitHandle from an IAsyncResult object instead of creating an AutoResetEvent manually, but this is not possible on WP7.

Categories: C#, REST, Windows Phone 7

WCF REST tip 2: WebFaultException

April 30, 2011 12 comments

Introduction

SOAP supports propagating exceptions from the service to the client. This is called “faults” and in WCF this is represented by the FaultException class. Exceptions in REST services are represented by a HTTP status code >= 400. Not a lot of people seem to be aware that WCF supports setting HTTP status error codes by throwing a WebFaultException. Most people doing REST in WCF seem to use the StatusCode property of the OutgoingResponse object that can be accessed from the WebOperationContext.

Because the WebFaultException derives from the regular FaultException, it has the advantage that it results in service implementations that can use SOAP based bindings or HTTP based bindings by just changing the web.config or app.config. Just like the regular FaultException, the WebFaultException exists in two versions: a non generic version and a generic version. The non generic version only supports setting the HTTP status code, while the generic version allows to specify a DataContract class that should be send to the client.

Demo WCF service

We will create a small sample WCF service to show usage of the WebFaultException class. The WCF service will always return a HTTP 401 status code along with some more detailed information about the error in JSON format.

The detail for the WebFaultException is very simple, it consists of 2 properties: a reason field and a detailed information field.

namespace JsonErrorMessage.Service
{
    [DataContract]
    public class ErrorData
    {
        public ErrorData(string reason, string detailedInformation)
        {
            Reason = reason;
            DetailedInformation = detailedInformation;
        }

        [DataMember]
        public string Reason { get; private set; }

        [DataMember]
        public string DetailedInformation { get; private set; }
    }
}

The interface of the service is very simple; it consist of only one method:

namespace JsonErrorMessage.Service
{
    [ServiceContract]
    public interface IHelloService
    {
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        void Hello();
    }
}

The implementation of the service is of course very simple:

namespace JsonErrorMessage.Service
{
    public class HelloService : IHelloService
    {
        public void Hello()
        {
            ErrorData errorData = new ErrorData("You are not allowed to access this service.",
                "We don't allow anybody to access this service.");

            throw new WebFaultException<ErrorData>(errorData,
                HttpStatusCode.Unauthorized);
        }
    }
}

And finally the following configuration needs to be added into the web.config or app.config file:

<system.serviceModel>
  <services>
    <service name="JsonErrorMessage.Service.HelloService">
      <endpoint address=""
                binding="webHttpBinding"
                contract="JsonErrorMessage.Service.IHelloService" />
    </service>
  </services>
</system.serviceModel>

Testing the demo WCF service

I will use Fiddler to test the implementation of the WCF service. Fiddler is a free tool to debug HTTP traffic and I highly recommend using it.

Fiddler has a request builder that allows creating HTTP requests very easily:

Fiddler Request Builder

When we execute this HTTP request we get the following result back:

Response Unauthorized JSon

The server returned a 401 error code and the body is our DataContract in JSON format. This is the result that we wanted.

Categories: C#, REST, WCF