Invoking RESTful services in .NET is typically done using the HttpWebRequest class. For common REST operations this approach is too low level as shown below.
Uri address = new Uri("http://example.com/hotels/1/bookings"); HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest; request.Method = "POST"; string requestBody = // create booking request content byte[] byteData = UTF8Encoding.UTF8.GetBytes(requestBody); request.ContentLength = byteData.Length; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(byteData, 0, byteData.Length); } using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) { if (response.StatusCode == HttpStatusCode.Created) { string location = response.Headers["Location"]; if (location != null) { Console.WriteLine("Created new booking at: " + location); } } }
![]() | Note |
---|---|
There is another class called WebClient but does not support HTTP headers and HTTP status code/description. |
RestTemplate provides higher level methods that correspond to each of the six main HTTP methods that make invoking many RESTful services a one-liner and enforce REST best practices.
HTTP Method | RestTemplate Method |
DELETE | Delete(Uri url) and 2 more |
GET | GetForObject<T>(Uri url) and 2 more |
GetForMessage<T>(Uri url) and 2 more | |
HEAD | HeadForHeaders(Uri url) and 2 more |
OPTIONS | OptionsForAllow(Uri url) and 2 more |
POST | PostForLocation<T>(Uri url, object request) and 2 more |
PostForObject<T>(Uri url, object request) and 2 more | |
PostForMessage<T>(Uri url, object request) and 2 more | |
PostForMessage(Uri url, object request) and 2 more | |
PUT | Put(Uri url, object request) and 2 more |
The two other methods mentioned take URI template arguments in two
forms, either as a object
variable length argument or
an IDictionary<string, object>
.
For
example,
// using variable length arguments string result = restTemplate.GetForObject<string>("http://example.com/hotels/{hotel}/bookings/{booking}", 42, 21); // using a IDictionary<string, object> IDictionary<string, object> vars = new Dictionary<string, object>(1); vars.Add("hotel", 42); string result = restTemplate.GetForObject<string>("http://example.com/hotels/{hotel}/rooms/{hotel}", vars);
The names of RestTemplate methods follow a naming convention, the first part indicates what HTTP method is being invoked and the second part indicates what is returned. For example,
GetForObject<T>()
will perform a GET, and return the HTTP response body converted into
an object type of your choice.PostForLocation()
will
do a POST, converting the given object into a HTTP request and return
the response HTTP Location header where the newly created object can
be found.PostForMessage<T>()
will do a POST,
converting the given object into a HTTP request and return the full
HTTP response message composed of the status code and description, the
response headers and the response body converted into an object type
of your choice.The request object to be POSTed or PUTed, may be a HttpEntity instance in order to add additional HTTP headers. An example is shown below.
Booking requestBody = // create booking request content HttpEntity entity = new HttpEntity(requestBody); entity.Headers["MyRequestHeader"] = "MyValue"; template.PostForLocation("http://example.com/hotels/{id}/bookings", entity, 1);
![]() | Note |
---|---|
These operations are synchronous and are not available for Silverlight and Windows Phone because all related network calls have to be asynchronous. |
All REST operations are also available for asynchronous calls. The asynchronous methods are suffixed by the word 'Async' based on common .NET naming conventions.
Note, that asynchronous call were initially added to
support Silverlight and Windows Phone, but nothing prevents you from
using them for Windows Forms and WPF applications to not freeze the UI
when invoking RESTful services.
An example using an asynchronous
method is shown below :
template.GetForObjectAsync<string>("http://example.com/hotels/bookings", r => { if (r.Error != null) { Console.WriteLine(r.Error); } else { Console.WriteLine(r.Response); } });
In some cases it may be useful to set up the base url of the
request once. This is possible by setting the base address in the
constructor or by setting the property
BaseAddress
.
For example:
RestTemplate template = new RestTemplate("http://example.com"); Booking booking1 = template.GetForObject<Booking>("/hotels/{id}/bookings", 1); Booking booking2 = template.GetForObject<Booking>("/hotels/{id}/bookings", 2);
Objects passed to and returned from REST operations are converted
to and from HTTP messages by
IHttpMessageConverter instances.
Converters for the main mime types are registered by default, but
you can also write your own converter and register it via the
MessageConverters
property.
The default converter instances registered with the template,
depending of the target Framework, are
ByteArrayHttpMessageConverter,
StringHttpMessageConverter,
FormHttpMessageConverter,
XmlDocumentHttpMessageConverter,
XElementHttpMessageConverter,
Atom10FeedHttpMessageConverter and
Rss20FeedHttpMessageConverter.
You can override these defaults using the
MessageConverters
property. This is required if
you want to use the
XmlSerializableHttpMessageConverter/DataContractHttpMessageConverter
or
JsonHttpMessageConverter/NJsonHttpMessageConverter.
For example :
// Add a new converter to the default list RestTemplate template = new RestTemplate("http://twitter.com"); template.MessageConverters.Add(new JsonHttpMessageConverter());
See HTTP message
conversion chapter for detailed description of each
converter.
In case of an exception processing the HTTP method, an exception of the type RestClientException will be thrown. The interface IResponseErrorHandler allows you to determine whether a particular response has an error. The default implementation throws an exception when a HTTP client or server error happens (HTTP status code 4xx or 5xx).
The default behavior can be changed by plugging in another
implementation into the RestTemplate via the
ErrorHandler
property. The example below shows
a custom IResponseErrorHandler
implementation which gives the user total control over the response.
public class MyResponseErrorHandler : IResponseErrorHandler { public bool HasError(IClientHttpResponse response) { return false; } public void HandleError(IClientHttpResponse response) { // This method should not be called because HasError returns false. throw new InvalidOperationException(); } } RestTemplate template = new RestTemplate("http://example.com"); template.ErrorHandler = new MyResponseErrorHandler(); HttpResponseMessage responseMessage = template.PostForMessage("/notfound", null); // throw HttpClientErrorException with default implementation if (responseMessage.StatusCode == HttpStatusCode.NotFound) { // ... }
RestTemplate uses a request factory to
create instances of the
IClientHttpRequest interface. Default
implementation uses the .NET Framework class
HttpWebRequest. This can be overridden by
specifying an implementation of
IClientHttpRequestFactory via the
RequestFactory
property.
The default implementation
WebClientHttpRequestFactory uses an instance of
HttpWebRequest which can be configured with
credentials information or proxy settings. An example setting the proxy
is shown below :
WebClientHttpRequestFactory requestFactory = new WebClientHttpRequestFactory(); requestFactory.Proxy = new WebProxy("http://proxy.example.com:8080"); requestFactory.Proxy.Credentials = new NetworkCredential("userName", "password", "domain"); RestTemplate template = new RestTemplate("http://example.com"); template.RequestFactory = requestFactory;
In Silverlight, HTTP handling can be performed by the browser or the client.
See How to: Specify Browser or Client HTTP Handling on MSDN.
By default, WebClientHttpRequestFactory will use the browser HTTP stack
for HTTP methods GET and POST, and force the client HTTP stack for other HTTP methods.
This can be overridden by setting the WebRequestCreator
property.
RestTemplate template = new RestTemplate("http://example.com"); ((WebClientHttpRequestFactory)rt.RequestFactory).WebRequestCreator = WebRequestCreatorType.ClientHttp;
RestTemplate allows you to intercept HTTP
request creation and/or execution. You can create your own interceptor
and register it via the RequestInterceptors
property.
Four types of interceptors are provided :
An example of an interceptor measuring HTTP request execution time is shown below.
public class PerfRequestSyncInterceptor : IClientHttpRequestSyncInterceptor { public IClientHttpResponse Execute(IClientHttpRequestSyncExecution execution) { Stopwatch stopwatch = Stopwatch.StartNew(); IClientHttpResponse response = execution.Execute(); stopwatch.Stop(); Console.WriteLine(String.Format( "Sync {0} request for '{1}' took {2}ms and resulted in {3:d} - {3}", execution.Method, execution.Uri, stopwatch.ElapsedMilliseconds, response.StatusCode)); return response; } } RestTemplate template = new RestTemplate(); template.RequestInterceptors.Add(new PerfRequestSyncInterceptor());
Note that you can also make PerfRequestSyncInterceptor implement IClientHttpRequestAsyncInterceptor to support both synchronous and asynchronous requests.
RestTemplate, as any other class can be
configured in the Spring.NET container.
For example, using XML
configuration :
<object id="RestTemplate" type="Spring.Rest.Client.RestTemplate, Spring.Rest"> <constructor-arg name="baseAddress" value="http://example.com"/> <property name="ErrorHandler"> <object type="MyErrorHandler"/> </property> <property name="MessageConverters"> <list> <object type="MyHttpMessageConverter"/> </list> </property> <property name="RequestInterceptors"> <list> <object type="MyClientHttpRequestInterceptor"/> </list> </property> <property name="RequestFactory.UseDefaultCredentials" value="true"/> <property name="RequestFactory.Timeout" value="10000"/> </object>
The default request factory implementation WebClientHttpRequestFactory, that uses the HttpWebRequest class, can be used to authenticate the HTTP request. Supported authentication schemes include Basic, Digest, Negotiate (SPNEGO), Kerberos, NTLM, and Certificates.
WebClientHttpRequestFactory requestFactory = new WebClientHttpRequestFactory(); requestFactory.Credentials = new NetworkCredential("userName", "password", "domain"); RestTemplate template = new RestTemplate("http://example.com"); template.RequestFactory = requestFactory;
You can also directly cast the default request factory to WebClientHttpRequestFactory :
RestTemplate template = new RestTemplate("http://example.com"); ((WebClientHttpRequestFactory)template.RequestFactory).UseDefaultCredentials = true;
Basic authentication is supported by the
WebClientHttpRequestFactory (see previous
section), but this implementation will wait the challenge
response from server before to send the 'Authorization' header value. As
this can be an issue in some cases, Spring provides a custom request interceptor
named BasicSigningRequestInterceptor that forces
Basic authentication. This is shown below
RestTemplate template = new RestTemplate("http://example.com"); template.RequestInterceptors.Add(new BasicSigningRequestInterceptor("login", "password"));
This will be supported in a future version based on the Spring.Social Java project. The implementation is based on request interceptors.
Besides the REST operations described in the previous section, the
RestTemplate also has the
Exchange()
method, which can be used for
arbitrary HTTP method execution based on HTTP messages. The method takes
as arguments the HTTP request message composed of the request Uri, the
HTTP method and the HTTP entity (headers and body) and returns the HTTP
response message composed of the status code, status description and the
HTTP entity (headers and body).
HttpResponseMessage<T> Exchange<T>(Uri url, HttpMethod method, HttpEntity requestEntity) where T : class; // also has 2 overloads for URI template based URL.
Perhaps most importantly, the Exchange()
method can be used to add request headers and read response headers for
every REST operation. For example:
HttpEntity requestEntity = new HttpEntity(); requestEntity.Headers["MyRequestHeader"] = "MyValue"; HttpResponseMessage<string> response = template.Exchange<string>("/hotels/{hotel}", HttpMethod.GET, requestEntity, 42); string responseHeader = response.Headers["MyResponseHeader"]; string body = response.Body; HttpStatusCode statusCode = response.StatusCode; string statusDescription = response.StatusDescription;
In the above example, we first prepare a request message that
contains the MyRequestHeader
header. We then retrieve
the response message, and read the
MyResponseHeader
.
Last but not least, the Execute()
method is
behind everything RestTemplate does.
T Execute<T>(Uri url, HttpMethod method, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor) where T : class; // also has 2 overloads for URI template based URL.
The IRequestCallback interface is defined as
public interface IRequestCallback { void DoWithRequest(IClientHttpRequest request); }
The IResponseExtractor<T> interface is defined as
public interface IResponseExtractor<T> where T : class { T ExtractData(IClientHttpResponse response); }
The Execute
method allow you to manipulate
the request/response headers, write to the request body and read from the
response body.
Note, when using the execute method you do not have to worry about any resource management, the template will always close the request and handle any errors. Refer to the API documentation for more information on using the execute method and the meaning of its other method arguments.