REST client API: Silverlight and Windows Phone support (SPRNET-1345)

This commit is contained in:
bbaia
2010-12-30 23:07:54 +00:00
parent e9de2313a5
commit 57a25d344b
154 changed files with 27801 additions and 1789 deletions

View File

@@ -0,0 +1,160 @@
#if SILVERLIGHT
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
namespace Spring.Collections.Specialized
{
public class NameValueCollection : IEnumerable<string>
{
private Dictionary<string, List<string>> innerCollection;
public NameValueCollection()
{
innerCollection = new Dictionary<string, List<string>>();
}
public NameValueCollection(int capacity)
{
innerCollection = new Dictionary<string, List<string>>(capacity);
}
public NameValueCollection(IEqualityComparer<string> comparer)
{
innerCollection = new Dictionary<string, List<string>>(comparer);
}
public NameValueCollection(int capacity, IEqualityComparer<string> comparer)
{
innerCollection = new Dictionary<string, List<string>>(capacity, comparer);
}
public virtual void Add(string name, string value)
{
List<string> list;
if (!this.innerCollection.TryGetValue(name, out list))
{
list = new List<string>();
}
list.Add(value);
this.innerCollection[name] = list;
}
public virtual string Get(string name)
{
string str = null;
List<string> list;
if (this.innerCollection.TryGetValue(name, out list))
{
for (int i = 0; i < list.Count; i++)
{
if (i == 0)
{
str = list[i];
}
else
{
str = str + list[i];
}
if (i != (list.Count - 1))
{
str = str + ",";
}
}
}
return str;
}
public virtual string[] GetValues(string name)
{
List<string> list;
if (this.innerCollection.TryGetValue(name, out list))
{
return list.ToArray();
}
return null;
}
public virtual void Set(string key, string value)
{
List<string> list = new List<string>();
list.Add(value);
this.innerCollection[key] = list;
}
public virtual bool Remove(string key)
{
return this.innerCollection.Remove(key);
}
public virtual string[] AllKeys
{
get
{
int count = this.innerCollection.Count;
string[] array = new string[count];
this.innerCollection.Keys.CopyTo(array, 0);
return array;
}
}
public virtual int Count
{
get
{
return this.innerCollection.Count;
}
}
public virtual string this[string name]
{
get
{
return this.Get(name);
}
set
{
this.Set(name, value);
}
}
#region IEnumerable<string> Membres
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
return this.innerCollection.Keys.GetEnumerator();
}
#endregion
#region IEnumerable Membres
IEnumerator IEnumerable.GetEnumerator()
{
return this.innerCollection.Keys.GetEnumerator();
}
#endregion
}
}
#endif

View File

@@ -0,0 +1,50 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.ComponentModel;
namespace Spring.Http.Client
{
public class ExecuteCompletedEventArgs : AsyncCompletedEventArgs
{
private IClientHttpResponse response;
public IClientHttpResponse Response
{
get
{
// Raise an exception if the operation failed or
// was canceled.
base.RaiseExceptionIfNecessary();
// If the operation was successful, return the
// property value.
return response;
}
}
public ExecuteCompletedEventArgs(IClientHttpResponse response, Exception exception, bool cancelled, object userState)
: base(exception, cancelled, userState)
{
this.response = response;
}
}
}

View File

@@ -0,0 +1,66 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
namespace Spring.Http.Client
{
/// <summary>
/// Represents a client-side HTTP request.
/// </summary>
/// <remarks>
/// <para>
/// Created via an implementation of the <see cref="IClientHttpRequestFactory"/>.
/// </para>
/// <para>
/// A client HTTP request can be executed,
/// getting an <see cref="IClientHttpResponse"/> which can be read from.
/// </para>
/// </remarks>
/// <seealso cref="IClientHttpRequestFactory"/>
/// <seealso cref="IClientHttpResponse"/>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public interface IClientHttpRequest : IHttpOutputMessage
{
/// <summary>
/// Gets the HTTP method of the request.
/// </summary>
HttpMethod Method { get; }
/// <summary>
/// Gets the URI of the request.
/// </summary>
Uri Uri { get; }
#if !SILVERLIGHT
/// <summary>
/// Execute this request, resulting in a <see cref="IClientHttpResponse" /> that can be read.
/// </summary>
/// <returns>The response result of the execution</returns>
IClientHttpResponse Execute();
#endif
void ExecuteAsync(object state, Action<ExecuteCompletedEventArgs> executeCompleted);
void CancelAsync();
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,20 +21,22 @@
using System;
using System.Net;
namespace Spring.Http
namespace Spring.Http.Client
{
/// <summary>
/// Factory for <see cref="HttpWebRequest"/> objects. Requests are created by the <see cref="M:CreateRequest"/> method.
/// Factory for <see cref="IClientHttpRequest"/> objects.
/// Requests are created by the <see cref="M:CreateRequest"/> method.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public interface IHttpWebRequestFactory
public interface IClientHttpRequestFactory
{
/// <summary>
/// Create a new <see cref="HttpWebRequest"/> for the specified URI.
/// Create a new <see cref="IClientHttpRequest"/> for the specified URI and HTTP method.
/// </summary>
/// <param name="uri">The URI to create a request for.</param>
/// <param name="method">The HTTP method to execute.</param>
/// <returns>The created request</returns>
HttpWebRequest CreateRequest(Uri uri);
IClientHttpRequest CreateRequest(Uri uri, HttpMethod method);
}
}

View File

@@ -0,0 +1,59 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
using System.Net;
namespace Spring.Http.Client
{
/// <summary>
/// Represents a client-side HTTP response.
/// </summary>
/// <remarks>
/// <para>
/// Obtained via an 'execution' of the <see cref="IClientHttpRequest"/>.
/// </para>
/// <para>
/// A client HTTP response must be <see cref="M:Close">closed</see>,
/// typically in a <code>finally</code> or via an <code>using</code> block.
/// </para>
/// </remarks>
/// <seealso cref="IClientHttpRequest"/>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public interface IClientHttpResponse : IHttpInputMessage, IDisposable
{
/// <summary>
/// Gets the HTTP status code of the response.
/// </summary>
HttpStatusCode StatusCode { get; }
/// <summary>
/// Gets the HTTP status description of the response.
/// </summary>
string StatusDescription { get; }
/// <summary>
/// Closes this response, freeing any resources created.
/// </summary>
void Close();
}
}

View File

@@ -0,0 +1,457 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.ComponentModel;
using System.Globalization;
using Spring.Util;
namespace Spring.Http.Client
{
/// <summary>
/// <see cref="IClientHttpRequest"/> implementation that uses
/// .NET <see cref="HttpWebRequest"/>'s class to execute requests.
/// </summary>
/// <seealso cref="WebClientHttpRequestFactory"/>
/// <author>Bruno Baia</author>
public class WebClientHttpRequest : IClientHttpRequest
{
private HttpHeaders headers;
private Action<Stream> body;
private HttpWebRequest httpWebRequest;
private bool isExecuted;
private bool isCancelled;
/// <summary>
/// Gets the <see cref="HttpWebRequest"/> instance used.
/// </summary>
public HttpWebRequest HttpWebRequest
{
get { return this.httpWebRequest; }
}
/// <summary>
/// Creates a new instance of <see cref="WebClientHttpRequest"/>
/// with the given <see cref="HttpWebRequest"/> instance.
/// </summary>
/// <param name="request">The <see cref="HttpWebRequest"/> instance to use.</param>
public WebClientHttpRequest(HttpWebRequest request)
{
AssertUtils.ArgumentNotNull(request, "HttpWebRequest");
this.httpWebRequest = request;
this.headers = new HttpHeaders();
}
#region IClientHttpRequest Members
/// <summary>
/// Gets the HTTP method of the request.
/// </summary>
public HttpMethod Method
{
get
{
return (HttpMethod)Enum.Parse(typeof(HttpMethod), this.httpWebRequest.Method, true);
}
}
/// <summary>
/// Gets the URI of the request.
/// </summary>
public Uri Uri
{
get
{
return this.httpWebRequest.RequestUri;
}
}
/// <summary>
/// Gets the message headers.
/// </summary>
public HttpHeaders Headers
{
get { return headers; }
}
/// <summary>
/// Sets the delegate that writes the body message as a stream.
/// </summary>
public Action<Stream> Body
{
get { return this.body; }
set { this.body = value; }
}
#if !SILVERLIGHT
/// <summary>
/// Execute this request, resulting in a <see cref="IClientHttpResponse" /> that can be read.
/// </summary>
/// <returns>The response result of the execution</returns>
public IClientHttpResponse Execute()
{
this.EnsureNotExecuted();
try
{
// Prepare
this.PrepareRequest();
// Write
if (this.body != null)
{
using (Stream stream = this.httpWebRequest.GetRequestStream())
{
this.body(stream);
}
}
// Read
HttpWebResponse httpWebResponse = this.httpWebRequest.GetResponse() as HttpWebResponse;
if (this.httpWebRequest.HaveResponse && httpWebResponse != null)
{
return new WebClientHttpResponse(httpWebResponse);
}
}
catch (WebException ex)
{
// This exception will be raised if the server didn't return 200 - OK
// Try to retrieve more information about the network error
HttpWebResponse httpWebResponse = ex.Response as HttpWebResponse;
if (httpWebResponse != null)
{
this.isExecuted = true;
return new WebClientHttpResponse(httpWebResponse);
}
throw;
}
this.isExecuted = true;
return null;
}
#endif
public void ExecuteAsync(object state, Action<ExecuteCompletedEventArgs> executeCompleted)
{
this.EnsureNotExecuted();
AsyncOperation asyncOperation = AsyncOperationManager.CreateOperation(state);
ExecuteState executeState = new ExecuteState(executeCompleted, asyncOperation);
try
{
// Prepare
this.PrepareRequest();
// Post request
if (this.body != null)
{
this.httpWebRequest.BeginGetRequestStream(new AsyncCallback(ExecuteRequestCallback), executeState);
}
else
{
// Get request
this.HttpWebRequest.BeginGetResponse(new AsyncCallback(ExecuteResponseCallback), executeState);
}
}
catch (Exception ex)
{
if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException)
{
throw;
}
ExecuteAsyncCallback(executeState, null, ex);
}
finally
{
this.isExecuted = true;
}
}
public void CancelAsync()
{
this.isCancelled = true;
try
{
if (this.httpWebRequest != null)
{
this.httpWebRequest.Abort();
}
}
catch (Exception exception)
{
if (((exception is OutOfMemoryException) || (exception is StackOverflowException)) || (exception is ThreadAbortException))
{
throw;
}
}
}
#endregion
#region Async methods/classes
private void ExecuteRequestCallback(IAsyncResult result)
{
ExecuteState state = (ExecuteState)result.AsyncState;
try
{
// Write
using (Stream stream = this.httpWebRequest.EndGetRequestStream(result))
{
this.body(stream);
}
// Read
this.httpWebRequest.BeginGetResponse(new AsyncCallback(ExecuteResponseCallback), state);
}
catch (Exception ex)
{
if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException)
{
throw;
}
ExecuteAsyncCallback(state, null, ex);
}
}
private void ExecuteResponseCallback(IAsyncResult result)
{
ExecuteState state = (ExecuteState)result.AsyncState;
IClientHttpResponse response = null;
Exception exception = null;
try
{
HttpWebResponse httpWebResponse = this.httpWebRequest.EndGetResponse(result) as HttpWebResponse;
if (this.httpWebRequest.HaveResponse == true && httpWebResponse != null)
{
response = new WebClientHttpResponse(httpWebResponse);
}
}
catch (Exception ex)
{
if (ex is ThreadAbortException || ex is StackOverflowException || ex is OutOfMemoryException)
{
throw;
}
exception = ex;
// This exception will be raised if the server didn't return 200 - OK
// Try to retrieve more information about the network error
if (ex is WebException)
{
HttpWebResponse httpWebResponse = ((WebException)ex).Response as HttpWebResponse;
if (httpWebResponse != null)
{
exception = null;
response = new WebClientHttpResponse(httpWebResponse);
}
}
}
ExecuteAsyncCallback(state, response, exception);
}
// This is the method that the underlying, free-threaded asynchronous behavior will invoke.
// This will happen on an arbitrary thread.
private void ExecuteAsyncCallback(ExecuteState state, IClientHttpResponse response, Exception exception)
{
// Package the results of the operation
ExecuteCompletedEventArgs eventArgs = new ExecuteCompletedEventArgs(response, exception, this.isCancelled, state.AsyncOperation.UserSuppliedState);
ExecuteCallbackArgs<ExecuteCompletedEventArgs> callbackArgs = new ExecuteCallbackArgs<ExecuteCompletedEventArgs>(eventArgs, state.ExecuteCompleted);
SendOrPostCallback callback = new SendOrPostCallback(ExecuteResponseReceived);
// End the task. The asyncOp object is responsible for marshaling the call.
state.AsyncOperation.PostOperationCompleted(callback, callbackArgs);
}
private static void ExecuteResponseReceived(object arg)
{
ExecuteCallbackArgs<ExecuteCompletedEventArgs> callbackArgs = (ExecuteCallbackArgs<ExecuteCompletedEventArgs>)arg;
if (callbackArgs.Callback != null)
{
callbackArgs.Callback(callbackArgs.EventArgs);
}
}
private class ExecuteCallbackArgs<T> where T : class
{
public T EventArgs;
public Action<T> Callback;
public ExecuteCallbackArgs(T eventArgs,
Action<T> callback)
{
this.EventArgs = eventArgs;
this.Callback = callback;
}
}
private class ExecuteState
{
public Action<ExecuteCompletedEventArgs> ExecuteCompleted;
public AsyncOperation AsyncOperation;
public ExecuteState(
Action<ExecuteCompletedEventArgs> executeCompleted,
AsyncOperation asyncOperation)
{
this.ExecuteCompleted = executeCompleted;
this.AsyncOperation = asyncOperation;
}
}
#endregion
protected void EnsureNotExecuted()
{
if (this.isExecuted)
{
throw new InvalidOperationException("Client HTTP request already executed or is currently executing.");
}
}
/// <summary>
/// Prepare the request for execution.
/// </summary>
/// <remarks>
/// Default implementation copies headers to the request. Can be overridden in subclasses.
/// </remarks>
protected virtual void PrepareRequest()
{
// Copy headers
foreach (string header in this.headers)
{
// Special headers
switch (header.ToUpper(CultureInfo.InvariantCulture))
{
case "ACCEPT":
{
this.httpWebRequest.Accept = this.headers[header];
break;
}
#if !SILVERLIGHT_3 && !WINDOWS_PHONE
case "CONTENT-LENGTH":
{
this.httpWebRequest.ContentLength = this.headers.ContentLength;
break;
}
#endif
case "CONTENT-TYPE":
{
this.httpWebRequest.ContentType = this.headers[header];
break;
}
#if NET_4_0
case "DATE" :
{
DateTime? date = this.headers.Date;
if (date.HasValue)
{
this.httpWebRequest.Date = date.Value;
}
else
{
this.httpWebRequest.Date = DateTime.MinValue;
}
break;
}
case "HOST" :
{
this.httpWebRequest.Host = this.headers[header];
break;
}
#endif
#if !SILVERLIGHT
case "CONNECTION":
{
string headerValue = this.headers[header];
if (headerValue.Equals("Keep-Alive", StringComparison.OrdinalIgnoreCase))
{
this.httpWebRequest.KeepAlive = true;
}
else if (!headerValue.Equals("Close", StringComparison.OrdinalIgnoreCase))
{
this.httpWebRequest.Connection = headerValue;
}
break;
}
case "EXPECT":
{
this.httpWebRequest.Expect = this.headers[header];
break;
}
case "IF-MODIFIED-SINCE":
{
DateTime? date = this.headers.IfModifiedSince;
if (date.HasValue)
{
this.httpWebRequest.IfModifiedSince = date.Value;
}
else
{
this.httpWebRequest.IfModifiedSince = DateTime.MinValue;
}
break;
}
//case "RANGE":
// {
// break;
// }
case "REFERER":
{
this.httpWebRequest.Referer = this.headers[header];
break;
}
case "TRANSFER-ENCODING":
{
this.httpWebRequest.SendChunked = true;
string headerValue = this.headers[header];
if (!headerValue.Equals("Chunked", StringComparison.OrdinalIgnoreCase))
{
this.httpWebRequest.TransferEncoding = headerValue;
}
break;
}
#endif
#if !SILVERLIGHT_3
case "USER-AGENT":
{
this.httpWebRequest.UserAgent = this.headers[header];
break;
}
#endif
default:
{
// Other headers
this.httpWebRequest.Headers[header] = this.headers[header];
break;
}
}
}
}
}
}

View File

@@ -0,0 +1,213 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;
namespace Spring.Http.Client
{
/// <summary>
/// <see cref="IClientHttpRequestFactory"/> implementation that uses
/// .NET <see cref="HttpWebRequest"/>'s class to create requests.
/// </summary>
/// <author>Bruno Baia</author>
public class WebClientHttpRequestFactory : IClientHttpRequestFactory
{
#region Properties
#if !SILVERLIGHT_3
private bool? _useDefaultCredentials;
/// <summary>
/// Gets or sets a boolean value that controls whether default credentials are sent with this request.
/// </summary>
public bool? UseDefaultCredentials
{
get { return this._useDefaultCredentials; }
set { this._useDefaultCredentials = value; }
}
#endif
private ICredentials _credentials;
/// <summary>
/// Gets or sets authentication information for the request.
/// </summary>
public ICredentials Credentials
{
get { return this._credentials; }
set { this._credentials = value; }
}
#if !SILVERLIGHT
private X509CertificateCollection _clientCertificates;
/// <summary>
/// Gets or sets the collection of security certificates that are associated with this request.
/// </summary>
public X509CertificateCollection ClientCertificates
{
get
{
if (this._clientCertificates == null)
{
this._clientCertificates = new X509CertificateCollection();
}
return this._clientCertificates;
}
}
private IWebProxy _proxy;
/// <summary>
/// Gets or sets proxy information for the request.
/// </summary>
/// <remarks>
/// The default value is set by calling the <see cref="P:System.Net.GlobalProxySelection.Select"/> property.
/// </remarks>
public IWebProxy Proxy
{
get { return this._proxy; }
set { this._proxy = value; }
}
private int? _timeout;
/// <summary>
/// Gets or sets the time-out value in milliseconds for the <see cref="M:System.Net.HttpWebRequest.GetResponse()"/>
/// and <see cref="M:System.Net.HttpWebRequest.GetRequestStream()"/> methods.
/// </summary>
/// <remarks>
/// The default is 100,000 milliseconds (100 seconds).
/// </remarks>
public int? Timeout
{
get { return this._timeout; }
set { this._timeout = value; }
}
#endif
#if SILVERLIGHT && !WINDOWS_PHONE
private WebRequestCreatorType _webRequestCreator;
public WebRequestCreatorType WebRequestCreator
{
get { return this._webRequestCreator; }
set { this._webRequestCreator = value; }
}
#endif
private HttpWebRequest httpWebRequest;
/// <summary>
/// Gets the .NET <see cref="HttpWebRequest"/> used by this factory
/// or <see langword="null"/> if not created.
/// </summary>
public HttpWebRequest HttpWebRequest
{
get { return this.httpWebRequest; }
}
#endregion
/// <summary>
/// Creates a new instance of <see cref="WebClientHttpRequestFactory"/>.
/// </summary>
public WebClientHttpRequestFactory()
{
#if SILVERLIGHT && !WINDOWS_PHONE
this._webRequestCreator = WebRequestCreatorType.Default;
#endif
}
#region IClientHttpRequestFactory Membres
/// <summary>
/// Create a new <see cref="IClientHttpRequest"/> for the specified URI and HTTP method.
/// </summary>
/// <param name="uri">The URI to create a request for.</param>
/// <param name="method">The HTTP method to execute.</param>
/// <returns>The created request</returns>
public virtual IClientHttpRequest CreateRequest(Uri uri, HttpMethod method)
{
#if SILVERLIGHT && !WINDOWS_PHONE
switch (this._webRequestCreator)
{
case WebRequestCreatorType.ClientHttp:
this.httpWebRequest = (HttpWebRequest)System.Net.Browser.WebRequestCreator.ClientHttp.Create(uri);
break;
case WebRequestCreatorType.BrowserHttp:
this.httpWebRequest = (HttpWebRequest)System.Net.Browser.WebRequestCreator.BrowserHttp.Create(uri);
break;
case WebRequestCreatorType.Default:
if (method == HttpMethod.GET || method == HttpMethod.POST)
{
this.httpWebRequest = WebRequest.Create(uri) as HttpWebRequest;
}
else
{
// Force Client HTTP stack
this.httpWebRequest = (HttpWebRequest)System.Net.Browser.WebRequestCreator.ClientHttp.Create(uri);
}
break;
}
#else
this.httpWebRequest = WebRequest.Create(uri) as HttpWebRequest;
#endif
this.httpWebRequest.Method = method.ToString();
#if !SILVERLIGHT_3
if (this._useDefaultCredentials.HasValue)
{
this.httpWebRequest.UseDefaultCredentials = this._useDefaultCredentials.Value;
}
#endif
if (this._credentials != null)
{
this.httpWebRequest.Credentials = this._credentials;
}
#if !SILVERLIGHT
if (this._clientCertificates != null)
{
foreach (X509Certificate2 certificate in this._clientCertificates)
{
this.httpWebRequest.ClientCertificates.Add(certificate);
}
}
if (this._proxy != null)
{
this.httpWebRequest.Proxy = this._proxy;
}
if (this._timeout != null)
{
this.httpWebRequest.Timeout = this._timeout.Value;
}
#endif
return new WebClientHttpRequest(this.httpWebRequest);
}
#endregion
}
#if SILVERLIGHT && !WINDOWS_PHONE
public enum WebRequestCreatorType
{
Default,
BrowserHttp,
ClientHttp
}
#endif
}

View File

@@ -0,0 +1,152 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
using System.Net;
using Spring.Util;
namespace Spring.Http.Client
{
/// <summary>
/// <see cref="IClientHttpResponse"/> implementation that uses
/// .NET <see cref="HttpWebResponse"/>'s class to read responses.
/// </summary>
/// <author>Bruno Baia</author>
public class WebClientHttpResponse : IClientHttpResponse
{
private HttpHeaders headers;
private HttpWebResponse httpWebResponse;
/// <summary>
/// Gets the <see cref="HttpWebResponse"/> instance used.
/// </summary>
public HttpWebResponse HttpWebResponse
{
get { return this.httpWebResponse; }
}
/// <summary>
/// Creates a new instance of <see cref="WebClientHttpResponse"/>
/// with the given <see cref="HttpWebResponse"/> instance.
/// </summary>
/// <param name="response">The <see cref="HttpWebResponse"/> instance to use.</param>
public WebClientHttpResponse(HttpWebResponse response)
{
AssertUtils.ArgumentNotNull(response, "HttpWebResponse");
this.httpWebResponse = response;
this.headers = new HttpHeaders();
#if NET_2_0 || WINDOWS_PHONE
foreach (string header in this.httpWebResponse.Headers)
{
this.headers[header] = this.httpWebResponse.Headers[header];
}
#endif
#if SILVERLIGHT_3
try
{
foreach (string header in this.httpWebResponse.Headers)
{
this.headers[header] = this.httpWebResponse.Headers[header];
}
}
catch(NotImplementedException)
{
this.headers.ContentLength = this.httpWebResponse.ContentLength;
this.headers["Content-Type"] = this.httpWebResponse.ContentType;
}
#elif SILVERLIGHT
if (this.httpWebResponse.SupportsHeaders)
{
foreach (string header in this.httpWebResponse.Headers)
{
this.headers[header] = this.httpWebResponse.Headers[header];
}
}
else
{
this.headers.ContentLength = this.httpWebResponse.ContentLength;
this.headers["Content-Type"] = this.httpWebResponse.ContentType;
}
#endif
}
#region IClientHttpResponse Membres
/// <summary>
/// Gets the message headers.
/// </summary>
public HttpHeaders Headers
{
get { return this.headers; }
}
/// <summary>
/// Gets the body of the message as a stream.
/// </summary>
public Stream Body
{
get
{
return this.httpWebResponse.GetResponseStream();
}
}
/// <summary>
/// Gets the HTTP status code of the response.
/// </summary>
public HttpStatusCode StatusCode
{
get
{
return this.httpWebResponse.StatusCode;
}
}
/// <summary>
/// Gets the HTTP status description of the response.
/// </summary>
public string StatusDescription
{
get
{
return this.httpWebResponse.StatusDescription;
}
}
/// <summary>
/// Closes this response, freeing any resources created.
/// </summary>
public void Close()
{
this.httpWebResponse.Close();
}
void IDisposable.Dispose()
{
((IDisposable)this.httpWebResponse).Dispose();
}
#endregion
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,12 +19,8 @@
#endregion
using System;
using System.IO;
using System.Net;
using System.Collections.Generic;
using Spring.Util;
namespace Spring.Http.Converters
{
/// <summary>
@@ -33,7 +29,7 @@ namespace Spring.Http.Converters
/// <remarks>
/// This base class adds support for setting supported <see cref="MediaType"/>s, through the
/// <see cref="P:SupportedMediaTypes"/> property.
/// It also adds support for 'Content-Type' when writing to the HTTP request.
/// It also adds support for 'Content-Type' when writing to the HTTP message.
/// </remarks>
/// <author>Arjen Poutsma</author>
/// <author>Juergen Hoeller</author>
@@ -41,22 +37,13 @@ namespace Spring.Http.Converters
public abstract class AbstractHttpMessageConverter : IHttpMessageConverter
{
#region Logging
#if !SILVERLIGHT
private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(AbstractHttpMessageConverter));
#endif
#endregion
private IList<MediaType> _supportedMediaTypes = new List<MediaType>();
/// <summary>
/// Gets or sets the list of <see cref="MediaType"/> objects supported by this converter.
/// </summary>
public IList<MediaType> SupportedMediaTypes
{
get { return _supportedMediaTypes; }
set { _supportedMediaTypes = value; }
}
#region Constructor(s)
/// <summary>
@@ -118,7 +105,16 @@ namespace Spring.Http.Converters
}
/// <summary>
/// Read an object of the given type form the given HTTP response, and returns it.
/// Gets or sets the list of <see cref="MediaType"/> objects supported by this converter.
/// </summary>
public IList<MediaType> SupportedMediaTypes
{
get { return _supportedMediaTypes; }
set { _supportedMediaTypes = value; }
}
/// <summary>
/// Read an object of the given type form the given HTTP message, and returns it.
/// </summary>
/// <remarks>
/// This implementation simple delegates to <see cre="ReadInternal"/> method.
@@ -128,44 +124,47 @@ namespace Spring.Http.Converters
/// The type of object to return. This type must have previously been passed to the
/// <see cref="M:CanRead"/> method of this interface, which must have returned <see langword="true"/>.
/// </typeparam>
/// <param name="response">The HTTP response to read from.</param>
/// <param name="message">The HTTP message to read from.</param>
/// <returns>The converted object.</returns>
public T Read<T>(HttpWebResponse response) where T : class
/// <exception cref="HttpMessageNotReadableException">In case of conversion errors</exception>
public T Read<T>(IHttpInputMessage message) where T : class
{
return ReadInternal<T>(response);
return ReadInternal<T>(message);
}
/// <summary>
/// Write an given object to the given HTTP request.
/// Write an given object to the given HTTP message.
/// </summary>
/// <remarks>
/// This implementation delegates to <see cref="M:GetDefaultContentType"/> method if a content
/// type was not provided, and calls <see cref="M:WriteInternal"/>.
/// </remarks>
/// <param name="content">
/// The object to write to the HTTP request. The type of this object must have previously been
/// The object to write to the HTTP message. The type of this object must have previously been
/// passed to the <see cref="M:CanWrite"/> method of this interface, which must have returned <see langword="true"/>.
/// </param>
/// <param name="mediaType">
/// <param name="contentType">
/// The content type to use when writing. May be null to indicate that the default content type of the converter must be used.
/// If not null, this media type must have previously been passed to the <see cref="M:CanWrite"/> method of this interface,
/// which must have returned <see langword="true"/>.
/// </param>
/// <param name="request">The HTTP request to write to.</param>
public void Write(object content, MediaType mediaType, HttpWebRequest request)
/// <param name="message">The HTTP message to write to.</param>
/// <exception cref="HttpMessageNotWritableException">In case of conversion errors</exception>
public void Write(object content, MediaType contentType, IHttpOutputMessage message)
{
if (!StringUtils.HasText(request.ContentType))
HttpHeaders headers = message.Headers;
if (headers.ContentType == null)
{
if (mediaType == null || mediaType.IsWildcardType || mediaType.IsWildcardSubtype)
if (contentType == null || contentType.IsWildcardType || contentType.IsWildcardSubtype)
{
mediaType = GetDefaultContentType(content.GetType());
contentType = GetDefaultContentType(content.GetType());
}
if (mediaType != null)
if (contentType != null)
{
request.ContentType = mediaType.ToString();
headers.ContentType = contentType;
}
}
WriteInternal(content, request);
WriteInternal(content, message);
}
#endregion
@@ -245,51 +244,17 @@ namespace Spring.Http.Converters
/// Abstract template method that reads the actualy object. Invoked from <see cref="M:Read"/>.
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="response">The HTTP response to read from.</param>
/// <param name="message">The HTTP message to read from.</param>
/// <returns>The converted object.</returns>
protected abstract T ReadInternal<T>(HttpWebResponse response) where T : class;
/// <exception cref="HttpMessageNotReadableException">In case of conversion errors</exception>
protected abstract T ReadInternal<T>(IHttpInputMessage message) where T : class;
/// <summary>
/// Abstract template method that writes the actual body. Invoked from <see cref="M:Write"/>.
/// </summary>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected abstract void WriteInternal(object content, HttpWebRequest request);
#region Inner class definitions
// TODO : Move this class ?
internal class IgnoreCloseMemoryStream : MemoryStream
{
public IgnoreCloseMemoryStream()
: base()
{
}
public override void Close()
{
}
public void CopyToAndClose(Stream destination)
{
this.Position = 0;
#if NET_4_0
this.CopyTo(destination);
#else
// From .NET 4.0 Stream.CopyTo method
int bytesCount;
byte[] buffer = new byte[0x1000];
while ((bytesCount = this.Read(buffer, 0, buffer.Length)) != 0)
{
destination.Write(buffer, 0, bytesCount);
}
#endif
base.Close();
}
}
#endregion
/// <param name="content">The object to write to the HTTP message.</param>
/// <param name="message">The HTTP message to write to.</param>
/// <exception cref="HttpMessageNotWritableException">In case of conversion errors</exception>
protected abstract void WriteInternal(object content, IHttpOutputMessage message);
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,35 +59,39 @@ namespace Spring.Http.Converters
/// Abstract template method that reads the actualy object. Invoked from <see cref="M:Read"/>.
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="response">The HTTP response to read from.</param>
/// <param name="message">The HTTP message to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadInternal<T>(HttpWebResponse response)
/// <exception cref="HttpMessageNotReadableException">In case of conversion errors</exception>
protected override T ReadInternal<T>(IHttpInputMessage message)
{
// Get the response stream
using (BinaryReader reader = new BinaryReader(response.GetResponseStream()))
// Read from the message stream
using (BinaryReader reader = new BinaryReader(message.Body))
{
return reader.ReadBytes((int)response.ContentLength) as T;
return reader.ReadBytes((int)message.Headers.ContentLength) as T;
}
}
/// <summary>
/// Abstract template method that writes the actual body. Invoked from <see cref="M:Write"/>.
/// </summary>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteInternal(object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
/// <param name="message">The HTTP message to write to.</param>
/// <exception cref="HttpMessageNotWritableException">In case of conversion errors</exception>
protected override void WriteInternal(object content, IHttpOutputMessage message)
{
// Create a byte array of the data we want to send
byte[] byteData = content as byte[];
// Set the content length in the request headers
request.ContentLength = byteData.Length;
//#if !SILVERLIGHT
// // Set the content length in the message headers
// message.Headers.ContentLength = byteData.Length;
//#endif
// Write to the request
using (Stream postStream = request.GetRequestStream())
// Write to the message stream
message.Body = delegate(Stream stream)
{
postStream.Write(byteData, 0, byteData.Length);
}
stream.Write(byteData, 0, byteData.Length);
};
}
}
}

View File

@@ -1,8 +1,8 @@
#if NET_3_5
#if NET_3_5 && !SILVERLIGHT
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -60,9 +60,8 @@ namespace Spring.Http.Converters.Feed
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="xmlReader">The XmlReader to use.</param>
/// <param name="response">The HTTP response to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadXml<T>(XmlReader xmlReader, HttpWebResponse response)
protected override T ReadXml<T>(XmlReader xmlReader)
{
if (typeof(SyndicationFeed).Equals(typeof(T)))
{
@@ -76,16 +75,16 @@ namespace Spring.Http.Converters.Feed
}
/// <summary>
/// Returns the default <see cref="XmlReaderSettings">XmlReader settings</see>
/// used by this converter to read from the HTTP response.
/// Returns the <see cref="XmlReaderSettings">XmlReader settings</see>
/// used by this converter to read from the HTTP message.
/// </summary>
/// <returns>The XmlReader settings.</returns>
protected override XmlReaderSettings GetDefaultXmlReaderSettings()
protected override XmlReaderSettings GetXmlReaderSettings()
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.CloseInput = true;
settings.IgnoreProcessingInstructions = true;
#if NET_4_0
#if NET_4_0 || SILVERLIGHT
settings.DtdProcessing = DtdProcessing.Ignore;
#else
settings.ProhibitDtd = false;

View File

@@ -1,8 +1,8 @@
#if NET_3_5
#if NET_3_5 && !SILVERLIGHT
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,9 +49,8 @@ namespace Spring.Http.Converters.Feed
/// Abstract template method that writes the actual body using a <see cref="XmlWriter"/>. Invoked from <see cref="M:WriteInternal"/>.
/// </summary>
/// <param name="xmlWriter">The XmlWriter to use.</param>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content)
{
if (content is SyndicationFeed)
{

View File

@@ -1,8 +1,8 @@
#if NET_3_5
#if NET_3_5 && !SILVERLIGHT
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,9 +49,8 @@ namespace Spring.Http.Converters.Feed
/// Abstract template method that writes the actual body using a <see cref="XmlWriter"/>. Invoked from <see cref="M:WriteInternal"/>.
/// </summary>
/// <param name="xmlWriter">The XmlWriter to use.</param>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content)
{
if (content is SyndicationFeed)
{

View File

@@ -0,0 +1,82 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
using System.Net;
using System.Text;
using Spring.Util;
namespace Spring.Http.Converters
{
/// <author>Bruno Baia</author>
public class FileInfoHttpMessageConverter : AbstractHttpMessageConverter
{
/// <summary>
/// Creates a new instance of the <see cref="ByteArrayHttpMessageConverter"/>
/// with 'text/plain; charset=ISO-8859-1', and '*/*' media types.
/// </summary>
public FileInfoHttpMessageConverter() :
base(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL)
{
}
/// <summary>
/// Indicates whether the given class is supported by this converter.
/// </summary>
/// <param name="type">The type to test for support.</param>
/// <returns><see langword="true"/> if supported; otherwise <see langword="false"/></returns>
protected override bool Supports(Type type)
{
return type.Equals(typeof(FileInfo));
}
/// <summary>
/// Abstract template method that reads the actualy object. Invoked from <see cref="M:Read"/>.
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="message">The HTTP message to read from.</param>
/// <returns>The converted object.</returns>
/// <exception cref="HttpMessageNotReadableException">In case of conversion errors</exception>
protected override T ReadInternal<T>(IHttpInputMessage message)
{
throw new NotSupportedException();
}
/// <summary>
/// Abstract template method that writes the actual body. Invoked from <see cref="M:Write"/>.
/// </summary>
/// <param name="content">The object to write to the HTTP message.</param>
/// <param name="message">The HTTP message to write to.</param>
/// <exception cref="HttpMessageNotWritableException">In case of conversion errors</exception>
protected override void WriteInternal(object content, IHttpOutputMessage message)
{
// Write to the message stream
message.Body = delegate(Stream stream)
{
using (FileStream fs = ((FileInfo)content).OpenRead())
{
IoUtils.CopyStream(fs, stream);
}
};
}
}
}

View File

@@ -0,0 +1,519 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Collections.Generic;
#if SILVERLIGHT
using Spring.Collections.Specialized;
#else
using System.Collections.Specialized;
#endif
using Spring.Util;
namespace Spring.Http.Converters
{
/// <summary>
/// Implementation of <see cref="IHttpMessageConverter"/> that can handle form data,
/// including multipart form data (i.e. file uploads).
/// </summary>
/// <remarks>
/// <para>
/// This converter supports the 'application/x-www-form-urlencoded' and 'multipart/form-data' media
/// types, and read the 'application/x-www-form-urlencoded' media type (but not 'multipart/form-data').
/// </para>
/// <para>
/// In other words, this converter can read and write 'normal' HTML forms (as <see cref="NameValueCollection"/>),
/// and it can write multipart form (as <see cref="IDictionary{String,Object}"/>).
/// When writing multipart, this converter uses other <see cref="IHttpMessageConverter"/> to write the respective MIME parts.
/// By default, basic converters are registered (supporting <see cref="String"/> and <see cref="FileInfo"/>, for instance);
/// these can be overridden by setting <see cref="P:PartConverters"/> property.
/// </para>
/// <para>
/// For example, the following snippet shows how to submit an HTML form:
/// <code>
/// RestTemplate template = new RestTemplate(); // FormHttpMessageConverter is configured by default
/// NameValueCollection form = new NameValueCollection();
/// form.Add("field 1", "value 1");
/// form.Add("field 2", "value 2");
/// form.Add("field 2", "value 3");
/// template.PostForLocation("http://example.com/myForm", form);
/// </code>
/// </para>
/// <para>
/// The following snippet shows how to do a file upload:
/// <code>
/// RestTemplate template = new RestTemplate();
/// IDictionary&lt;string, object> parts = new Dictionary&lt;string, object>();
/// parts.Add("field 1", "value 1");
/// parts.Add("file", new FileInfo(@"C:\myFile.jpg"));
/// template.PostForLocation("http://example.com/myFileUpload", parts);
/// </code>
/// </para>
/// </remarks>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public class FormHttpMessageConverter : IHttpMessageConverter
{
private static char[] BOUNDARY_CHARS =
new char[]{'-', '_', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A',
'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z'};
private Random random;
private Encoding _charset;
private IList<MediaType> _supportedMediaTypes;
private IList<IHttpMessageConverter> _partConverters;
/// <summary>
/// Gets or sets the message body converters to use.
/// These converters are used to convert objects to MIME parts.
/// </summary>
public IList<IHttpMessageConverter> PartConverters
{
get { return _partConverters; }
set { _partConverters = value; }
}
/// <summary>
/// Gets or sets the encoding used for writing form data.
/// </summary>
public Encoding Charset
{
get { return this._charset; }
set { _charset = value; }
}
/// <summary>
/// Creates a new instance of the <see cref="FormHttpMessageConverter"/>.
/// </summary>
public FormHttpMessageConverter()
{
this.random = new Random();
#if SILVERLIGHT
this._charset = new UTF8Encoding(false); // Remove byte Order Mask (BOM)
#else
this._charset = Encoding.GetEncoding("ISO-8859-1");
#endif
this._supportedMediaTypes = new List<MediaType>(2);
this._supportedMediaTypes.Add(MediaType.APPLICATION_FORM_URLENCODED);
this._supportedMediaTypes.Add(MediaType.MULTIPART_FORM_DATA);
this._partConverters = new List<IHttpMessageConverter>(3);
this._partConverters.Add(new ByteArrayHttpMessageConverter());
this._partConverters.Add(new StringHttpMessageConverter());
this._partConverters.Add(new FileInfoHttpMessageConverter());
//this._partConverters.Add(new ResourceHttpMessageConverter());
}
#region IHttpMessageConverter Membres
/// <summary>
/// Indicates whether the given class can be read by this converter.
/// </summary>
/// <param name="type">The class to test for readability</param>
/// <param name="mediaType">
/// The media type to read, can be null if not specified. Typically the value of a 'Content-Type' header.
/// </param>
/// <returns><see langword="true"/> if readable; otherwise <see langword="false"/></returns>
public bool CanRead(Type type, MediaType mediaType)
{
if (!typeof(NameValueCollection).IsAssignableFrom(type))
{
return false;
}
if (mediaType != null)
{
return MediaType.APPLICATION_FORM_URLENCODED.Includes(mediaType);
}
return true;
}
/// <summary>
/// Indicates whether the given class can be written by this converter.
/// </summary>
/// <param name="type">The class to test for writability</param>
/// <param name="mediaType">
/// The media type to write, can be null if not specified. Typically the value of an 'Accept' header.
/// </param>
/// <returns><see langword="true"/> if writable; otherwise <see langword="false"/></returns>
public bool CanWrite(Type type, MediaType mediaType)
{
if (!typeof(NameValueCollection).IsAssignableFrom(type) &&
!typeof(IDictionary<string, object>).IsAssignableFrom(type))
{
return false;
}
if (mediaType != null)
{
return MediaType.APPLICATION_FORM_URLENCODED.IsCompatibleWith(mediaType) ||
MediaType.MULTIPART_FORM_DATA.IsCompatibleWith(mediaType);
}
return true;
}
/// <summary>
/// Gets the list of <see cref="MediaType"/> objects supported by this converter.
/// </summary>
public IList<MediaType> SupportedMediaTypes
{
get { return _supportedMediaTypes; }
}
/// <summary>
/// Read an object of the given type form the given HTTP message, and returns it.
/// </summary>
/// <typeparam name="T">
/// The type of object to return. This type must have previously been passed to the
/// <see cref="M:CanRead"/> method of this interface, which must have returned <see langword="true"/>.
/// </typeparam>
/// <param name="message">The HTTP message to read from.</param>
/// <returns>The converted object.</returns>
/// <exception cref="HttpMessageNotReadableException">In case of conversion errors</exception>
public T Read<T>(IHttpInputMessage message) where T : class
{
// Get the message encoding
Encoding encoding;
MediaType mediaType = message.Headers.ContentType;
if (mediaType == null || !StringUtils.HasText(mediaType.CharSet))
{
encoding = this._charset;
}
else
{
encoding = Encoding.GetEncoding(mediaType.CharSet);
}
// Read from the message stream
string body;
using (StreamReader reader = new StreamReader(message.Body, encoding))
{
body = reader.ReadToEnd();
}
string[] pairs = body.Split('&');
NameValueCollection result = new NameValueCollection(pairs.Length);
foreach (string pair in pairs)
{
int idx = pair.IndexOf('=');
if (idx == -1)
{
result.Add(UrlDecode(pair, this._charset), null);
}
else
{
string name = UrlDecode(pair.Substring(0, idx), this._charset);
string value = UrlDecode(pair.Substring(idx + 1), this._charset);
result.Add(name, value);
}
}
return result as T;
}
/// <summary>
/// Write an given object to the given HTTP message.
/// </summary>
/// <param name="content">
/// The object to write to the HTTP message. The type of this object must have previously been
/// passed to the <see cref="M:CanWrite"/> method of this interface, which must have returned <see langword="true"/>.
/// </param>
/// <param name="contentType">
/// The content type to use when writing. May be null to indicate that the default content type of the converter must be used.
/// If not null, this media type must have previously been passed to the <see cref="M:CanWrite"/> method of this interface,
/// which must have returned <see langword="true"/>.
/// </param>
/// <param name="message">The HTTP message to write to.</param>
/// <exception cref="HttpMessageNotWritableException">In case of conversion errors</exception>
public void Write(object content, MediaType contentType, IHttpOutputMessage message)
{
if (content is NameValueCollection)
{
this.WriteForm((NameValueCollection) content, message);
}
else if (content is IDictionary<string, object>)
{
this.WriteMultipart((IDictionary<string, object>) content, message);
}
}
#endregion
#region Write Form
private void WriteForm(NameValueCollection form, IHttpOutputMessage message)
{
message.Headers.ContentType = MediaType.APPLICATION_FORM_URLENCODED;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < form.AllKeys.Length; i++)
{
string name = form.AllKeys[i];
string[] values = form.GetValues(name);
if (values == null)
{
builder.Append(UrlEncode(name, this._charset));
}
else
{
for (int j = 0; j < values.Length; j++)
{
string value = values[j];
builder.Append(UrlEncode(name, this._charset));
builder.Append('=');
builder.Append(UrlEncode(value, this._charset));
if (j != (values.Length - 1))
{
builder.Append('&');
}
}
}
if (i != (form.AllKeys.Length - 1))
{
builder.Append('&');
}
}
// Create a byte array of the data we want to send
byte[] byteData = this._charset.GetBytes(builder.ToString());
//#if !SILVERLIGHT
// // Set the content length in the message headers
// message.Headers.ContentLength = byteData.Length;
//#endif
// Write to the message stream
message.Body = delegate(Stream stream)
{
stream.Write(byteData, 0, byteData.Length);
};
}
private static string UrlDecode(string url, Encoding charset)
{
#if WINDOWS_PHONE
return System.Net.HttpUtility.UrlDecode(url);
#elif SILVERLIGHT
return System.Windows.Browser.HttpUtility.UrlDecode(url);
#else
return System.Web.HttpUtility.UrlDecode(url, charset);
#endif
}
private static string UrlEncode(string url, Encoding charset)
{
#if WINDOWS_PHONE
return System.Net.HttpUtility.UrlEncode(url);
#elif SILVERLIGHT
return System.Windows.Browser.HttpUtility.UrlEncode(url);
#else
return System.Web.HttpUtility.UrlEncode(url, charset);
#endif
}
#endregion
#region Write Multipart
private void WriteMultipart(IDictionary<string, object> parts, IHttpOutputMessage message)
{
string boundary = this.GenerateMultipartBoundary();
IDictionary<string, string> parameters = new Dictionary<string, string>(1);
parameters.Add("boundary", boundary);
MediaType contentType = new MediaType(MediaType.MULTIPART_FORM_DATA, parameters);
message.Headers.ContentType = contentType;
message.Body = delegate(Stream stream)
{
using (StreamWriter streamWriter = new StreamWriter(stream))
{
streamWriter.NewLine = "\r\n";
this.WriteParts(boundary, parts, streamWriter);
this.WriteEnd(boundary, streamWriter);
}
};
}
/// <summary>
/// Generates a multipart boundary.
/// </summary>
/// <remarks>
/// Default implementation returns a random boundary. Can be overridden in subclasses.
/// </remarks>
/// <returns>A multipart boundary</returns>
protected virtual string GenerateMultipartBoundary()
{
char[] boundary = new char[random.Next(11) + 30];
for (int i = 0; i < boundary.Length; i++)
{
boundary[i] = BOUNDARY_CHARS[random.Next(BOUNDARY_CHARS.Length)];
}
return new String(boundary);
}
/// <summary>
/// Return the filename of the given multipart part
/// to be used for the 'Content-Disposition' header.
/// </summary>
/// <remarks>
/// Default implementation returns <see cref="P:FileInfo.FullName"/> if the part is a <see cref="FileInfo"/>,
/// and <see langword="null"/> in other cases. Can be overridden in subclasses.
/// </remarks>
/// <param name="part">The part to determine the file name for</param>
/// <returns>The filename, or <see langword="null"/> if not known</returns>
protected virtual string GetMultipartFilename(object part)
{
if (part is FileInfo)
{
return ((FileInfo)part).FullName;
}
return null;
}
private void WriteParts(string boundary, IDictionary<string, object> parts, StreamWriter streamWriter)
{
foreach(KeyValuePair<string, object> entry in parts)
{
this.WriteBoundary(boundary, streamWriter);
HttpEntity entity = this.GetEntity(entry.Value);
this.WritePart(entry.Key, entity, streamWriter);
streamWriter.WriteLine();
}
}
private void WriteBoundary(string boundary, StreamWriter streamWriter)
{
streamWriter.Write("--");
streamWriter.Write(boundary);
streamWriter.WriteLine();
}
private void WritePart(String name, HttpEntity partEntity, StreamWriter streamWriter)
{
object partBody = partEntity.Body;
Type partType = partBody.GetType();
HttpHeaders partHeaders = partEntity.Headers;
MediaType partContentType = partHeaders.ContentType;
foreach (IHttpMessageConverter messageConverter in this._partConverters)
{
if (messageConverter.CanWrite(partType, partContentType))
{
IHttpOutputMessage multipartMessage = new MultipartHttpOutputMessage(streamWriter);
multipartMessage.Headers["Content-Disposition"] = this.GetContentDispositionFormData(name, this.GetMultipartFilename(partBody));
foreach (string header in partHeaders)
{
multipartMessage.Headers[header] = partHeaders[header];
}
messageConverter.Write(partBody, partContentType, multipartMessage);
return;
}
}
throw new HttpMessageNotWritableException(String.Format(
"Could not write request: no suitable HttpMessageConverter found for part type [{0}]", partType));
}
private void WriteEnd(string boundary, StreamWriter streamWriter)
{
streamWriter.Write("--");
streamWriter.Write(boundary);
streamWriter.Write("--");
streamWriter.WriteLine();
}
private HttpEntity GetEntity(object part)
{
if (part is HttpEntity)
{
return (HttpEntity)part;
}
return new HttpEntity(part);
}
/// <summary>
/// Return the value of the 'Content-Disposition' header for 'form-data'.
/// </summary>
/// <param name="name">The field name</param>
/// <param name="filename">The filename, may be <see langwrod="null"/></param>
/// <returns>The value of the 'Content-Disposition' header</returns>
private string GetContentDispositionFormData(string name, string filename)
{
StringBuilder builder = new StringBuilder();
builder.AppendFormat("form-data; name=\"{0}\"", name);
if (filename != null)
{
builder.AppendFormat("; filename=\"{0}\"", filename);
}
return builder.ToString();
}
/// <summary>
/// Implementation of <see cref="IHttpOutputMessage"/> used for writing multipart data.
/// </summary>
private sealed class MultipartHttpOutputMessage : IHttpOutputMessage
{
private HttpHeaders headers;
private StreamWriter bodyWriter;
public MultipartHttpOutputMessage(StreamWriter bodyWriter)
{
this.headers = new HttpHeaders();
this.bodyWriter = bodyWriter;
}
#region IHttpMessage Membres
public HttpHeaders Headers
{
get { return this.headers; }
}
public Action<Stream> Body
{
get { throw new InvalidOperationException(); }
set { this.WritePartBody(value); }
}
#endregion
private void WritePartBody(Action<Stream> body)
{
foreach (string header in this.headers)
{
bodyWriter.Write(header);
bodyWriter.Write(": ");
bodyWriter.Write(this.headers[header]);
bodyWriter.WriteLine();
}
bodyWriter.WriteLine();
bodyWriter.Flush();
Stream stream = bodyWriter.BaseStream;
stream.Flush();
body(stream);
stream.Flush();
}
}
#endregion
}
}

View File

@@ -0,0 +1,86 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Runtime.Serialization;
namespace Spring.Http.Converters
{
/// <summary>
/// Exception thrown by <see cref="IHttpMessageConverter"/> implementations when the conversion fails.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
#if !SILVERLIGHT
[Serializable]
#endif
public class HttpMessageConversionException : Exception
{
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageConversionException"/> class.
/// </summary>
public HttpMessageConversionException()
{
}
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageConversionException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
public HttpMessageConversionException(string message)
: base(message)
{
}
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageConversionException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
/// <param name="rootCause">
/// The root exception that is being wrapped.
/// </param>
public HttpMessageConversionException(string message, Exception rootCause)
: base(message, rootCause)
{
}
#if !SILVERLIGHT
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageConversionException"/> class.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// that holds the serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/>
/// that contains contextual information about the source or destination.
/// </param>
protected HttpMessageConversionException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endif
}
}

View File

@@ -0,0 +1,87 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Runtime.Serialization;
namespace Spring.Http.Converters
{
/// <summary>
/// Exception thrown by <see cref="IHttpMessageConverter"/> implementations
/// when reading from HTTP message fails.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
#if !SILVERLIGHT
[Serializable]
#endif
public class HttpMessageNotReadableException : HttpMessageConversionException
{
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageNotReadableException"/> class.
/// </summary>
public HttpMessageNotReadableException()
{
}
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageNotReadableException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
public HttpMessageNotReadableException(string message)
: base(message)
{
}
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageNotReadableException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
/// <param name="rootCause">
/// The root exception that is being wrapped.
/// </param>
public HttpMessageNotReadableException(string message, Exception rootCause)
: base(message, rootCause)
{
}
#if !SILVERLIGHT
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageNotReadableException"/> class.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// that holds the serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/>
/// that contains contextual information about the source or destination.
/// </param>
protected HttpMessageNotReadableException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endif
}
}

View File

@@ -0,0 +1,87 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Runtime.Serialization;
namespace Spring.Http.Converters
{
/// <summary>
/// Exception thrown by <see cref="IHttpMessageConverter"/> implementations
/// when writing to HTTP message fails.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
#if !SILVERLIGHT
[Serializable]
#endif
public class HttpMessageNotWritableException : HttpMessageConversionException
{
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageNotWritableException"/> class.
/// </summary>
public HttpMessageNotWritableException()
{
}
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageNotWritableException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
public HttpMessageNotWritableException(string message)
: base(message)
{
}
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageNotWritableException"/> class.
/// </summary>
/// <param name="message">
/// A message about the exception.
/// </param>
/// <param name="rootCause">
/// The root exception that is being wrapped.
/// </param>
public HttpMessageNotWritableException(string message, Exception rootCause)
: base(message, rootCause)
{
}
#if !SILVERLIGHT
/// <summary>
/// Creates a new instance of the <see cref="HttpMessageNotWritableException"/> class.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// that holds the serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/>
/// that contains contextual information about the source or destination.
/// </param>
protected HttpMessageNotWritableException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endif
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,13 +21,12 @@
using System;
using System.Net;
using System.Collections.Generic;
using System.IO;
namespace Spring.Http.Converters
{
// TODO: HttpMessageNotReadableException & HttpMessageNotWritableException exceptions ?
/// <summary>
/// Strategy interface that specifies a converter that can convert from and to HTTP requests and responses.
/// Strategy interface that specifies a converter that can convert from and to HTTP messages.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Juergen Hoeller</author>
@@ -60,29 +59,31 @@ namespace Spring.Http.Converters
IList<MediaType> SupportedMediaTypes { get; }
/// <summary>
/// Read an object of the given type form the given HTTP response, and returns it.
/// Read an object of the given type form the given HTTP message, and returns it.
/// </summary>
/// <typeparam name="T">
/// The type of object to return. This type must have previously been passed to the
/// <see cref="M:CanRead"/> method of this interface, which must have returned <see langword="true"/>.
/// </typeparam>
/// <param name="response">The HTTP response to read from.</param>
/// <param name="message">The HTTP message to read from.</param>
/// <returns>The converted object.</returns>
T Read<T>(HttpWebResponse response) where T : class;
/// <exception cref="HttpMessageNotReadableException">In case of conversion errors</exception>
T Read<T>(IHttpInputMessage message) where T : class;
/// <summary>
/// Write an given object to the given HTTP request.
/// Write an given object to the given HTTP message.
/// </summary>
/// <param name="content">
/// The object to write to the HTTP request. The type of this object must have previously been
/// The object to write to the HTTP message. The type of this object must have previously been
/// passed to the <see cref="M:CanWrite"/> method of this interface, which must have returned <see langword="true"/>.
/// </param>
/// <param name="mediaType">
/// <param name="contentType">
/// The content type to use when writing. May be null to indicate that the default content type of the converter must be used.
/// If not null, this media type must have previously been passed to the <see cref="M:CanWrite"/> method of this interface,
/// which must have returned <see langword="true"/>.
/// </param>
/// <param name="request">The HTTP request to write to.</param>
void Write(object content, MediaType mediaType, HttpWebRequest request);
/// <param name="message">The HTTP message to write to.</param>
/// <exception cref="HttpMessageNotWritableException">In case of conversion errors</exception>
void Write(object content, MediaType contentType, IHttpOutputMessage message);
}
}

View File

@@ -1,8 +1,8 @@
#if NET_3_5
#if NET_3_5 || WINDOWS_PHONE
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,18 +20,17 @@
#endregion
using System;
using System.Xml;
using System.IO;
using System.Net;
using System.Xml;
using System.Text;
using System.Collections.Generic;
using System.Runtime.Serialization.Json;
using Spring.Util;
namespace Spring.Http.Converters.Json
{
// TODO : Support for known types, etc...
/// <summary>
/// Implementation of <see cref="IHttpMessageConverter"/> that can read and write JSON.
/// </summary>
@@ -45,7 +44,18 @@ namespace Spring.Http.Converters.Json
/// <summary>
/// Default encoding for JSON.
/// </summary>
public static readonly Encoding DEFAULT_CHARSET = Encoding.UTF8;
public static readonly Encoding DEFAULT_CHARSET = new UTF8Encoding(false); // Remove byte Order Mask (BOM)
private IEnumerable<Type> _knownTypes;
/// <summary>
/// Gets or sets types that may be present in the object graph.
/// </summary>
public IEnumerable<Type> KnownTypes
{
get { return _knownTypes; }
set { _knownTypes = value; }
}
/// <summary>
/// Creates a new instance of the <see cref="JsonHttpMessageConverter"/>
@@ -70,27 +80,34 @@ namespace Spring.Http.Converters.Json
/// Abstract template method that reads the actualy object. Invoked from <see cref="M:Read"/>.
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="response">The HTTP response to read from.</param>
/// <param name="message">The HTTP message to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadInternal<T>(HttpWebResponse response)
/// <exception cref="HttpMessageNotReadableException">In case of conversion errors</exception>
protected override T ReadInternal<T>(IHttpInputMessage message)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
using (Stream stream = response.GetResponseStream())
{
return (T)serializer.ReadObject(stream) as T;
}
DataContractJsonSerializer serializer = this.GetSerializer(typeof(T));
return (T)serializer.ReadObject(message.Body) as T;
}
/// <summary>
/// Abstract template method that writes the actual body. Invoked from <see cref="M:Write"/>.
/// </summary>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteInternal(object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
/// <param name="message">The HTTP message to write to.</param>
/// <exception cref="HttpMessageNotWritableException">In case of conversion errors</exception>
protected override void WriteInternal(object content, IHttpOutputMessage message)
{
// Get the request encoding
#if SILVERLIGHT
// Write to the message stream
message.Body = delegate(Stream stream)
{
DataContractJsonSerializer serializer = this.GetSerializer(content.GetType());
serializer.WriteObject(stream, content);
};
#else
// Get the message encoding
Encoding encoding;
MediaType mediaType = MediaType.ParseMediaType(request.ContentType);
MediaType mediaType = message.Headers.ContentType;
if (mediaType == null || !StringUtils.HasText(mediaType.CharSet))
{
encoding = DEFAULT_CHARSET;
@@ -100,23 +117,35 @@ namespace Spring.Http.Converters.Json
encoding = Encoding.GetEncoding(mediaType.CharSet);
}
DataContractJsonSerializer serializer = new DataContractJsonSerializer(content.GetType());
DataContractJsonSerializer serializer = this.GetSerializer(content.GetType());
// Write to the request
using (IgnoreCloseMemoryStream requestStream = new IgnoreCloseMemoryStream())
// Write to the message stream
message.Body = delegate(Stream stream)
{
using (XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(requestStream, encoding, false))
// Using JsonReaderWriterFactory directly to set encoding
using (XmlDictionaryWriter jsonWriter = JsonReaderWriterFactory.CreateJsonWriter(stream, encoding, false))
{
serializer.WriteObject(jsonWriter, content);
}
};
#endif
}
// Set the content length in the request headers
request.ContentLength = requestStream.Length;
using (Stream postStream = request.GetRequestStream())
{
requestStream.CopyToAndClose(postStream);
}
/// <summary>
/// Creates an instance of <see cref="DataContractJsonSerializer"/> to
/// serialize or deserialize an object of the specified type.
/// </summary>
/// <param name="type">The type of instances to serialize or deserialize.</param>
/// <returns>The serializer to use.</returns>
protected virtual DataContractJsonSerializer GetSerializer(Type type)
{
if (this._knownTypes == null)
{
return new DataContractJsonSerializer(type);
}
else
{
return new DataContractJsonSerializer(type, this._knownTypes);
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,14 +42,22 @@ namespace Spring.Http.Converters
/// <summary>
/// Default encoding for strings.
/// </summary>
#if SILVERLIGHT
public static readonly Encoding DEFAULT_CHARSET = new UTF8Encoding(false); // Remove byte Order Mask (BOM)
#else
public static readonly Encoding DEFAULT_CHARSET = Encoding.GetEncoding("ISO-8859-1");
#endif
/// <summary>
/// Creates a new instance of the <see cref="ByteArrayHttpMessageConverter"/>
/// with 'text/plain; charset=ISO-8859-1', and '*/*' media types.
/// </summary>
public StringHttpMessageConverter() :
#if SILVERLIGHT
base(new MediaType("text", "plain", "UTF-8"), MediaType.ALL)
#else
base(new MediaType("text", "plain", "ISO-8859-1"), MediaType.ALL)
#endif
{
}
@@ -67,13 +75,14 @@ namespace Spring.Http.Converters
/// Abstract template method that reads the actualy object. Invoked from <see cref="M:Read"/>.
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="response">The HTTP response to read from.</param>
/// <param name="message">The HTTP message to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadInternal<T>(HttpWebResponse response)
/// <exception cref="HttpMessageNotReadableException">In case of conversion errors</exception>
protected override T ReadInternal<T>(IHttpInputMessage message)
{
// Get the response encoding
// Get the message encoding
Encoding encoding;
MediaType mediaType = MediaType.ParseMediaType(response.ContentType);
MediaType mediaType = message.Headers.ContentType;
if (mediaType == null || !StringUtils.HasText(mediaType.CharSet))
{
encoding = DEFAULT_CHARSET;
@@ -83,8 +92,8 @@ namespace Spring.Http.Converters
encoding = Encoding.GetEncoding(mediaType.CharSet);
}
// Get the response stream
using (StreamReader reader = new StreamReader(response.GetResponseStream(), encoding))
// Read from the message stream
using (StreamReader reader = new StreamReader(message.Body, encoding))
{
return reader.ReadToEnd() as T;
}
@@ -93,13 +102,14 @@ namespace Spring.Http.Converters
/// <summary>
/// Abstract template method that writes the actual body. Invoked from <see cref="M:Write"/>.
/// </summary>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteInternal(object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
/// <param name="message">The HTTP message to write to.</param>
/// <exception cref="HttpMessageNotWritableException">In case of conversion errors</exception>
protected override void WriteInternal(object content, IHttpOutputMessage message)
{
// Get the request encoding
// Get the message encoding
Encoding encoding;
MediaType mediaType = MediaType.ParseMediaType(request.ContentType);
MediaType mediaType = message.Headers.ContentType;
if (mediaType == null || !StringUtils.HasText(mediaType.CharSet))
{
encoding = DEFAULT_CHARSET;
@@ -112,14 +122,16 @@ namespace Spring.Http.Converters
// Create a byte array of the data we want to send
byte[] byteData = encoding.GetBytes(content as string);
// Set the content length in the request headers
request.ContentLength = byteData.Length;
//#if !SILVERLIGHT
// // Set the content length in the message headers
// message.Headers.ContentLength = byteData.Length;
//#endif
// Write to the request
using (Stream postStream = request.GetRequestStream())
// Write to the message stream
message.Body = delegate(Stream stream)
{
postStream.Write(byteData, 0, byteData.Length);
}
stream.Write(byteData, 0, byteData.Length);
};
}
}
}

View File

@@ -1,181 +0,0 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
using System.Net;
using System.Web;
using System.Text;
using System.Collections.Specialized;
using Spring.Util;
namespace Spring.Http.Converters
{
/// <summary>
/// Implementation of <see cref="IHttpMessageConverter"/> that can handle form data,
/// including multipart form data (i.e. file uploads).
/// </summary>
/// <remarks>
/// <para>
/// This converter supports the 'application/x-www-form-urlencoded' media type.
/// </para>
/// <para>
/// For example, the following snippet shows how to submit an HTML form:
/// <code>
/// RestTemplate template = new RestTemplate(); // UrlEncodedFormHttpMessageConverter is configured by default
/// NameValueCollection form = new NameValueCollection();
/// form.Add("field 1", "value 1");
/// form.Add("field 2", "value 2");
/// form.Add("field 2", "value 3");
/// template.PostForLocation("http://example.com/myForm", form);
/// </code>
/// </para>
/// </remarks>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public class UrlEncodedFormHttpMessageConverter : AbstractHttpMessageConverter
{
private Encoding charset = Encoding.GetEncoding("ISO-8859-1");
/// <summary>
/// Sets the encoding used for writing form data.
/// </summary>
public Encoding Charset
{
set { charset = value; }
}
/// <summary>
/// Creates a new instance of the <see cref="UrlEncodedFormHttpMessageConverter"/>
/// with 'application/x-www-form-urlencoded' media type.
/// </summary>
public UrlEncodedFormHttpMessageConverter() :
base(MediaType.APPLICATION_FORM_URLENCODED)
{
}
/// <summary>
/// Indicates whether the given class is supported by this converter.
/// </summary>
/// <param name="type">The type to test for support.</param>
/// <returns><see langword="true"/> if supported; otherwise <see langword="false"/></returns>
protected override bool Supports(Type type)
{
return type.Equals(typeof(NameValueCollection));
}
/// <summary>
/// Abstract template method that reads the actualy object. Invoked from <see cref="M:Read"/>.
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="response">The HTTP response to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadInternal<T>(HttpWebResponse response)
{
// Get the response encoding
Encoding encoding;
MediaType mediaType = MediaType.ParseMediaType(response.ContentType);
if (mediaType == null || !StringUtils.HasText(mediaType.CharSet))
{
encoding = this.charset;
}
else
{
encoding = Encoding.GetEncoding(mediaType.CharSet);
}
// Get the response stream
string body;
using (StreamReader reader = new StreamReader(response.GetResponseStream(), encoding))
{
body = reader.ReadToEnd();
}
string[] pairs = body.Split('&');
NameValueCollection result = new NameValueCollection(pairs.Length);
foreach (string pair in pairs)
{
int idx = pair.IndexOf('=');
if (idx == -1)
{
result.Add(HttpUtility.UrlDecode(pair, this.charset), null);
}
else
{
string name = HttpUtility.UrlDecode(pair.Substring(0, idx), this.charset);
string value = HttpUtility.UrlDecode(pair.Substring(idx + 1), this.charset);
result.Add(name, value);
}
}
return result as T;
}
/// <summary>
/// Abstract template method that writes the actual body. Invoked from <see cref="M:Write"/>.
/// </summary>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteInternal(object content, HttpWebRequest request)
{
StringBuilder builder = new StringBuilder();
NameValueCollection form = content as NameValueCollection;
for(int i=0; i < form.AllKeys.Length; i++)
{
string name = form.GetKey(i);
string[] values = form.GetValues(name);
if (values == null)
{
builder.Append(HttpUtility.UrlEncode(name, this.charset));
}
else
{
for (int j = 0; j < values.Length; j++)
{
string value = values[j];
builder.Append(HttpUtility.UrlEncode(name, this.charset));
builder.Append('=');
builder.Append(HttpUtility.UrlEncode(value, this.charset));
if (j != (values.Length - 1))
{
builder.Append('&');
}
}
}
if (i != (form.AllKeys.Length - 1))
{
builder.Append('&');
}
}
// Create a byte array of the data we want to send
byte[] byteData = this.charset.GetBytes(builder.ToString());
// Set the content length in the request headers
request.ContentLength = byteData.Length;
// Write to the request
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,26 +40,7 @@ namespace Spring.Http.Converters.Xml
/// <summary>
/// Default encoding for XML.
/// </summary>
public static readonly Encoding DEFAULT_CHARSET = new UTF8Encoding(false); // Remove byte Order Mask (BOM) when using XmlTextWriter
private XmlReaderSettings _xmlReaderSettings;
/// <summary>
/// Gets or sets the <see cref="XmlReaderSettings">XmlReader settings</see>
/// used by this converter to read from the HTTP response.
/// </summary>
public XmlReaderSettings XmlReaderSettings
{
get
{
if (_xmlReaderSettings == null)
{
_xmlReaderSettings = this.GetDefaultXmlReaderSettings();
}
return _xmlReaderSettings;
}
set { _xmlReaderSettings = value; }
}
public static readonly Encoding DEFAULT_CHARSET = new UTF8Encoding(false); // Remove byte Order Mask (BOM)
/// <summary>
/// Creates a new instance of the <see cref="AbstractHttpMessageConverter"/>
@@ -84,29 +65,31 @@ namespace Spring.Http.Converters.Xml
/// Abstract template method that reads the actualy object. Invoked from <see cref="M:Read"/>.
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="response">The HTTP response to read from.</param>
/// <param name="message">The HTTP message to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadInternal<T>(HttpWebResponse response)
/// <exception cref="HttpMessageNotReadableException">In case of conversion errors</exception>
protected override T ReadInternal<T>(IHttpInputMessage message)
{
using (Stream stream = response.GetResponseStream())
XmlReaderSettings settings = this.GetXmlReaderSettings();
// Read from the message stream
using (XmlReader xmlReader = XmlReader.Create(message.Body, settings))
{
using (XmlReader xmlReader = XmlReader.Create(stream, this.XmlReaderSettings))
{
return ReadXml<T>(xmlReader, response);
}
return ReadXml<T>(xmlReader);
}
}
/// <summary>
/// Abstract template method that writes the actual body. Invoked from <see cref="M:Write"/>.
/// </summary>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteInternal(object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
/// <param name="message">The HTTP message to write to.</param>
/// <exception cref="HttpMessageNotWritableException">In case of conversion errors</exception>
protected override void WriteInternal(object content, IHttpOutputMessage message)
{
// Get the request encoding
// Get the message encoding
Encoding encoding;
MediaType mediaType = MediaType.ParseMediaType(request.ContentType);
MediaType mediaType = message.Headers.ContentType;
if (mediaType == null || !StringUtils.HasText(mediaType.CharSet))
{
encoding = DEFAULT_CHARSET;
@@ -116,22 +99,17 @@ namespace Spring.Http.Converters.Xml
encoding = Encoding.GetEncoding(mediaType.CharSet);
}
// Write to the request
using (IgnoreCloseMemoryStream requestStream = new IgnoreCloseMemoryStream())
XmlWriterSettings settings = this.GetXmlWriterSettings();
settings.Encoding = encoding;
// Write to the message stream
message.Body = delegate(Stream stream)
{
using (XmlTextWriter xmlWriter = new XmlTextWriter(requestStream, encoding))
using (XmlWriter xmlWriter = XmlWriter.Create(stream, settings))
{
WriteXml(xmlWriter, content, request);
WriteXml(xmlWriter, content);
}
// Set the content length in the request headers
request.ContentLength = requestStream.Length;
using (Stream postStream = request.GetRequestStream())
{
requestStream.CopyToAndClose(postStream);
}
}
};
}
/// <summary>
@@ -139,24 +117,22 @@ namespace Spring.Http.Converters.Xml
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="xmlReader">The XmlReader to use.</param>
/// <param name="response">The HTTP response to read from.</param>
/// <returns>The converted object.</returns>
protected abstract T ReadXml<T>(XmlReader xmlReader, HttpWebResponse response) where T : class;
protected abstract T ReadXml<T>(XmlReader xmlReader) where T : class;
/// <summary>
/// Abstract template method that writes the actual body using a <see cref="XmlWriter"/>. Invoked from <see cref="M:WriteInternal"/>.
/// </summary>
/// <param name="xmlWriter">The XmlWriter to use.</param>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected abstract void WriteXml(XmlWriter xmlWriter, object content, HttpWebRequest request);
/// <param name="content">The object to write to the HTTP message.</param>
protected abstract void WriteXml(XmlWriter xmlWriter, object content);
/// <summary>
/// Returns the default <see cref="XmlReaderSettings">XmlReader settings</see>
/// used by this converter to read from the HTTP response.
/// Returns the <see cref="XmlReaderSettings">XmlReader settings</see>
/// used by this converter to read from the HTTP message.
/// </summary>
/// <returns>The XmlReader settings.</returns>
protected virtual XmlReaderSettings GetDefaultXmlReaderSettings()
protected virtual XmlReaderSettings GetXmlReaderSettings()
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Auto;
@@ -165,5 +141,20 @@ namespace Spring.Http.Converters.Xml
settings.IgnoreWhitespace = true;
return settings;
}
/// <summary>
/// Returns the <see cref="XmlWriterSettings">XmlWriter settings</see>
/// used by this converter to write to the HTTP message.
/// </summary>
/// <returns>The XmlWriter settings.</returns>
protected virtual XmlWriterSettings GetXmlWriterSettings()
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.CloseOutput = false;
settings.NewLineHandling = NewLineHandling.Entitize;
settings.OmitXmlDeclaration = true;
settings.CheckCharacters = false;
return settings;
}
}
}

View File

@@ -1,8 +1,8 @@
#if NET_3_0
#if NET_3_0 || SILVERLIGHT
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,11 +23,10 @@ using System;
using System.Net;
using System.Xml;
using System.Runtime.Serialization;
using System.Collections.Generic;
namespace Spring.Http.Converters.Xml
{
// TODO : Support for known types, etc...
/// <summary>
/// Implementation of <see cref="IHttpMessageConverter"/> that can read and write XML
/// using <see cref="DataContractSerializer"/>.
@@ -45,6 +44,17 @@ namespace Spring.Http.Converters.Xml
/// <author>Bruno Baia</author>
public class DataContractHttpMessageConverter : AbstractXmlHttpMessageConverter
{
private IEnumerable<Type> _knownTypes;
/// <summary>
/// Gets or sets types that may be present in the object graph.
/// </summary>
public IEnumerable<Type> KnownTypes
{
get { return _knownTypes; }
set { _knownTypes = value; }
}
/// <summary>
/// Creates a new instance of the <see cref="DataContractHttpMessageConverter"/>
/// with 'text/xml', 'application/xml', and 'application/*-xml' media types.
@@ -72,11 +82,10 @@ namespace Spring.Http.Converters.Xml
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="xmlReader">The XmlReader to use.</param>
/// <param name="response">The HTTP response to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadXml<T>(XmlReader xmlReader, HttpWebResponse response)
protected override T ReadXml<T>(XmlReader xmlReader)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
DataContractSerializer serializer = this.GetSerializer(typeof(T));
return serializer.ReadObject(xmlReader) as T;
}
@@ -84,13 +93,30 @@ namespace Spring.Http.Converters.Xml
/// Abstract template method that writes the actual body using a <see cref="XmlWriter"/>. Invoked from <see cref="M:WriteInternal"/>.
/// </summary>
/// <param name="xmlWriter">The XmlWriter to use.</param>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content)
{
DataContractSerializer serializer = new DataContractSerializer(content.GetType());
DataContractSerializer serializer = this.GetSerializer(content.GetType());
serializer.WriteObject(xmlWriter, content);
}
/// <summary>
/// Creates an instance of <see cref="DataContractSerializer"/> to
/// serialize or deserialize an object of the specified type.
/// </summary>
/// <param name="type">The type of instances to serialize or deserialize.</param>
/// <returns>The serializer to use.</returns>
protected virtual DataContractSerializer GetSerializer(Type type)
{
if (this._knownTypes == null)
{
return new DataContractSerializer(type);
}
else
{
return new DataContractSerializer(type, this._knownTypes);
}
}
}
}
#endif

View File

@@ -1,8 +1,8 @@
#if NET_3_5
#if NET_3_5 || WINDOWS_PHONE
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,8 +26,6 @@ using System.Xml.Linq;
namespace Spring.Http.Converters.Xml
{
// TODO : Support XElement.Load options
/// <summary>
/// Implementation of <see cref="IHttpMessageConverter"/> that can read and write XML
/// from a <see cref="XElement"/> (Linq to XML).
@@ -63,9 +61,8 @@ namespace Spring.Http.Converters.Xml
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="xmlReader">The XmlReader to use.</param>
/// <param name="response">The HTTP response to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadXml<T>(XmlReader xmlReader, HttpWebResponse response)
protected override T ReadXml<T>(XmlReader xmlReader)
{
return XElement.Load(xmlReader) as T;
}
@@ -74,9 +71,8 @@ namespace Spring.Http.Converters.Xml
/// Abstract template method that writes the actual body using a <see cref="XmlWriter"/>. Invoked from <see cref="M:WriteInternal"/>.
/// </summary>
/// <param name="xmlWriter">The XmlWriter to use.</param>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content)
{
XElement xElement = content as XElement;
xElement.WriteTo(xmlWriter);

View File

@@ -1,7 +1,8 @@
#region License
#if !SILVERLIGHT
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,9 +60,8 @@ namespace Spring.Http.Converters.Xml
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="xmlReader">The XmlReader to use.</param>
/// <param name="response">The HTTP response to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadXml<T>(XmlReader xmlReader, HttpWebResponse response)
protected override T ReadXml<T>(XmlReader xmlReader)
{
XmlDocument document = new XmlDocument();
document.Load(xmlReader);
@@ -72,12 +72,12 @@ namespace Spring.Http.Converters.Xml
/// Abstract template method that writes the actual body using a <see cref="XmlWriter"/>. Invoked from <see cref="M:WriteInternal"/>.
/// </summary>
/// <param name="xmlWriter">The XmlWriter to use.</param>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content)
{
XmlDocument document = content as XmlDocument;
document.WriteTo(xmlWriter);
}
}
}
}
#endif

View File

@@ -1,7 +1,8 @@
#region License
#if !SILVERLIGHT || WINDOWS_PHONE
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,14 +20,12 @@
#endregion
using System;
using System.Xml;
using System.Net;
using System.Xml;
using System.Xml.Serialization;
namespace Spring.Http.Converters.Xml
{
// TODO : Support for known types, etc...
/// <summary>
/// Implementation of <see cref="IHttpMessageConverter"/> that can read and write XML
/// using <see cref="XmlSerializer"/>.
@@ -38,6 +37,17 @@ namespace Spring.Http.Converters.Xml
/// <author>Bruno Baia</author>
public class XmlSerializableHttpMessageConverter : AbstractXmlHttpMessageConverter
{
private Type[] _knownTypes;
/// <summary>
/// Gets or sets types that may be present in the object graph.
/// </summary>
public Type[] KnownTypes
{
get { return _knownTypes; }
set { _knownTypes = value; }
}
/// <summary>
/// Creates a new instance of the <see cref="XmlSerializableHttpMessageConverter"/>
/// with 'text/xml', 'application/xml', and 'application/*-xml' media types.
@@ -65,11 +75,10 @@ namespace Spring.Http.Converters.Xml
/// </summary>
/// <typeparam name="T">The type of object to return.</typeparam>
/// <param name="xmlReader">The XmlReader to use.</param>
/// <param name="response">The HTTP response to read from.</param>
/// <returns>The converted object.</returns>
protected override T ReadXml<T>(XmlReader xmlReader, HttpWebResponse response)
protected override T ReadXml<T>(XmlReader xmlReader)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
XmlSerializer serializer = this.GetSerializer(typeof(T));
return serializer.Deserialize(xmlReader) as T;
}
@@ -77,12 +86,30 @@ namespace Spring.Http.Converters.Xml
/// Abstract template method that writes the actual body using a <see cref="XmlWriter"/>. Invoked from <see cref="M:WriteInternal"/>.
/// </summary>
/// <param name="xmlWriter">The XmlWriter to use.</param>
/// <param name="content">The object to write to the HTTP request.</param>
/// <param name="request">The HTTP request to write to.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content, HttpWebRequest request)
/// <param name="content">The object to write to the HTTP message.</param>
protected override void WriteXml(XmlWriter xmlWriter, object content)
{
XmlSerializer serializer = new XmlSerializer(content.GetType());
XmlSerializer serializer = this.GetSerializer(content.GetType());
serializer.Serialize(xmlWriter, content);
}
/// <summary>
/// Creates an instance of <see cref="XmlSerializer"/> to
/// serialize or deserialize an object of the specified type.
/// </summary>
/// <param name="type">The type of instances to serialize or deserialize.</param>
/// <returns>The serializer to use.</returns>
protected virtual XmlSerializer GetSerializer(Type type)
{
if (this._knownTypes == null)
{
return new XmlSerializer(type);
}
else
{
return new XmlSerializer(type, this._knownTypes);
}
}
}
}
}
#endif

View File

@@ -1,129 +0,0 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;
namespace Spring.Http
{
/// <summary>
/// Factory for <see cref="HttpWebRequest"/> objects. Requests are created by the <see cref="M:CreateRequest"/> method.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public class DefaultHttpWebRequestFactory : IHttpWebRequestFactory
{
// TODO : Add other properties
private X509CertificateCollection _clientCertificates;
private ICredentials _credentials;
private IWebProxy _proxy;
private int? _timeout;
/// <summary>
/// Gets or sets the collection of security certificates that are associated with this request.
/// </summary>
public X509CertificateCollection ClientCertificates
{
get
{
if (this._clientCertificates == null)
{
this._clientCertificates = new X509CertificateCollection();
}
return this._clientCertificates;
}
}
/// <summary>
/// Gets or sets authentication information for the request.
/// </summary>
public ICredentials Credentials
{
get { return _credentials; }
set { _credentials = value; }
}
/// <summary>
/// Gets or sets proxy information for the request.
/// </summary>
/// <remarks>
/// The default value is set by calling the <see cref="P:System.Net.GlobalProxySelection.Select"/> property.
/// </remarks>
public IWebProxy Proxy
{
get { return _proxy; }
set { _proxy = value; }
}
/// <summary>
/// Gets or sets the time-out value in milliseconds for the <see cref="M:System.Net.HttpWebRequest.GetResponse()"/>
/// and <see cref="M:System.Net.HttpWebRequest.GetRequestStream()"/> methods.
/// </summary>
/// <remarks>
/// The default is 100,000 milliseconds (100 seconds).
/// </remarks>
public int? Timeout
{
get { return _timeout; }
set { _timeout = value; }
}
#region IHttpWebRequestFactory Membres
/// <summary>
/// Create a new <see cref="HttpWebRequest"/> for the specified URI.
/// </summary>
/// <param name="uri">The URI to create a request for.</param>
/// <returns>The created request</returns>
public HttpWebRequest CreateRequest(Uri uri)
{
HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
if (this._clientCertificates != null)
{
foreach (X509Certificate2 certificate in this._clientCertificates)
{
request.ClientCertificates.Add(certificate);
}
}
if (this._credentials != null)
{
request.Credentials = this._credentials;
}
if (this._proxy != null)
{
request.Proxy = this._proxy;
}
if (this._timeout != null)
{
request.Timeout = this._timeout.Value;
}
return request;
}
#endregion
}
}

View File

@@ -0,0 +1,60 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System.Net;
namespace Spring.Http
{
/// <summary>
/// Represents a HTTP entity message, as defined in the HTTP specification.
/// <a href="http://tools.ietf.org/html/rfc2616#section-7">HTTP 1.1, section 7</a>
/// </summary>
/// <author>Bruno Baia</author>
public class HttpEntity : HttpEntity<object>
{
/// <summary>
/// Creates a new instance of <see cref="HttpEntity"/> with the given body.
/// </summary>
/// <param name="body">The entity body.</param>
public HttpEntity(object body) :
base(body)
{
}
/// <summary>
/// Creates a new instance of <see cref="HttpEntity"/> with the given headers.
/// </summary>
/// <param name="headers">The entity headers.</param>
public HttpEntity(HttpHeaders headers) :
base(headers)
{
}
/// <summary>
/// Creates a new instance of <see cref="HttpEntity"/> with the given body and headers.
/// </summary>
/// <param name="body">The entity body.</param>
/// <param name="headers">The entity headers.</param>
public HttpEntity(object body, HttpHeaders headers) :
base(body, headers)
{
}
}
}

View File

@@ -0,0 +1,91 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System.Net;
namespace Spring.Http
{
/// <summary>
/// Represents a HTTP entity message, as defined in the HTTP specification.
/// <a href="http://tools.ietf.org/html/rfc2616#section-7">HTTP 1.1, section 7</a>
/// </summary>
/// <typeparam name="T">The type of the entity body.</typeparam>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public class HttpEntity<T> where T : class
{
private HttpHeaders headers;
private T body;
/// <summary>
/// Gets the entity headers.
/// </summary>
public HttpHeaders Headers
{
get { return this.headers; }
}
/// <summary>
/// Gets the entity body. May be null.
/// </summary>
public T Body
{
get { return this.body; }
}
/// <summary>
/// Indicates whether this entity has a body.
/// </summary>
/// <returns></returns>
public bool HasBody
{
get { return (this.body != null); }
}
/// <summary>
/// Creates a new instance of <see cref="HttpEntity{T}"/> with the given body.
/// </summary>
/// <param name="body">The entity body.</param>
public HttpEntity(T body)
: this(body, new HttpHeaders())
{
}
/// <summary>
/// Creates a new instance of <see cref="HttpEntity{T}"/> with the given headers.
/// </summary>
/// <param name="headers">The entity headers.</param>
public HttpEntity(HttpHeaders headers)
: this(null, headers)
{
}
/// <summary>
/// Creates a new instance of <see cref="HttpEntity{T}"/> with the given body and headers.
/// </summary>
/// <param name="body">The entity body.</param>
/// <param name="headers">The entity headers.</param>
public HttpEntity(T body, HttpHeaders headers)
{
this.body = body;
this.headers = headers;
}
}
}

View File

@@ -0,0 +1,503 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Globalization;
using System.Collections.Generic;
using Spring.Util;
#if SILVERLIGHT
using Spring.Collections.Specialized;
#else
using System.Collections.Specialized;
#endif
namespace Spring.Http
{
/// <summary>
/// Represents HTTP request and response headers, mapping string header names to list of string values.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public class HttpHeaders : NameValueCollection
{
private const string ACCEPT = "Accept";
private const string ACCEPT_CHARSET = "Accept-Charset";
private const string ALLOW = "Allow";
private const string CACHE_CONTROL = "Cache-Control";
private const string CONTENT_LENGTH = "Content-Length";
private const string CONTENT_TYPE = "Content-Type";
private const string DATE = "Date";
private const string ETAG = "ETag";
private const string EXPIRES = "Expires";
private const string IF_MODIFIED_SINCE = "If-Modified-Since";
private const string IF_NONE_MATCH = "If-None-Match";
private const string LAST_MODIFIED = "Last-Modified";
private const string LOCATION = "Location";
private const string PRAGMA = "Pragma";
private static readonly DateTimeFormatInfo DateTimeFormatInfo = new DateTimeFormatInfo();
#region Constructor(s)
/// <summary>
/// Creates a new, empty instance of the <see cref="HttpHeaders"/> object.
/// </summary>
public HttpHeaders() :
base(8, StringComparer.OrdinalIgnoreCase)
{
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the array of acceptable <see cref="MediaType">media types</see>,
/// as specified by the 'Accept' header.
/// </summary>
/// <remarks>
/// Returns an empty array when the acceptable media types are unspecified.
/// </remarks>
public MediaType[] Accept
{
get
{
string[] values = this.GetMultiValues(ACCEPT);
if (values == null || values.Length == 0)
{
return new MediaType[0];
}
else
{
MediaType[] result = new MediaType[values.Length];
for (int i = 0; i < values.Length; i++)
{
result[i] = MediaType.Parse(values[i]);
}
return result;
}
}
set
{
foreach (MediaType mediaType in value)
{
this.Add(ACCEPT, mediaType.ToString());
}
}
}
//**
// * Set the list of acceptable {@linkplain Charset charsets}, as specified by the {@code Accept-Charset} header.
// * @param acceptableCharsets the acceptable charsets
// */
//public void setAcceptCharset(List<Charset> acceptableCharsets) {
// StringBuilder builder = new StringBuilder();
// for (Iterator<Charset> iterator = acceptableCharsets.iterator(); iterator.hasNext();) {
// Charset charset = iterator.next();
// builder.append(charset.name().toLowerCase(Locale.ENGLISH));
// if (iterator.hasNext()) {
// builder.append(", ");
// }
// }
// set(ACCEPT_CHARSET, builder.toString());
//}
//**
// * Return the list of acceptable {@linkplain Charset charsets}, as specified by the {@code Accept-Charset}
// * header.
// * @return the acceptable charsets
// */
//public List<Charset> getAcceptCharset() {
// List<Charset> result = new ArrayList<Charset>();
// String value = getFirst(ACCEPT_CHARSET);
// if (value != null) {
// String[] tokens = value.split(",\\s*");
// for (String token : tokens) {
// int paramIdx = token.indexOf(';');
// if (paramIdx == -1) {
// result.add(Charset.forName(token));
// }
// else {
// result.add(Charset.forName(token.substring(0, paramIdx)));
// }
// }
// }
// return result;
//}
/// <summary>
/// Gets or sets the array of allowed <see cref="HttpMethod">HTTP methods</see>,
/// as specified by the 'Allow' header.
/// </summary>
/// <remarks>
/// Returns an empty array when the allowed methods are unspecified.
/// </remarks>
public HttpMethod[] Allow
{
get
{
string[] values = this.GetMultiValues(ALLOW);
if (values == null || values.Length == 0)
{
return new HttpMethod[0];
}
else
{
HttpMethod[] result = new HttpMethod[values.Length];
for (int i = 0; i < values.Length; i++)
{
result[i] = (HttpMethod)Enum.Parse(typeof(HttpMethod), values[i], true);
}
return result;
}
}
set
{
foreach (HttpMethod method in value)
{
this.Add(ALLOW, method.ToString());
}
}
}
/// <summary>
/// Gets or sets the value of the 'Cache-Control' header.
/// </summary>
public string CacheControl
{
get
{
return this.Get(CACHE_CONTROL);
}
set
{
this.Set(CACHE_CONTROL, value);
}
}
/// <summary>
/// Gets or sets the length of the body in bytes,
/// as specified by the 'Content-Length' header.
/// </summary>
/// <remarks>
/// Returns -1 when the content-length is unknown.
/// </remarks>
public long ContentLength
{
get
{
string value = this.GetSingleValue(CONTENT_LENGTH);
return (value != null ? long.Parse(value) : -1);
}
set
{
this.Set(CONTENT_LENGTH, value.ToString());
}
}
/// <summary>
/// Gets or sets the <see cref="MediaType">media type</see> of the body,
/// as specified by the 'Content-Type' header.
/// </summary>
/// <remarks>
/// Returns <see langword="null"/> when the content type is unknown.
/// </remarks>
public MediaType ContentType
{
get
{
string value = this.GetSingleValue(CONTENT_TYPE);
return (value != null ? MediaType.Parse(value) : null);
}
set
{
if (value.IsWildcardType)
{
throw new ArgumentException("'Content-Type' header cannot contain wildcard type '*'", "Content-Type");
}
if (value.IsWildcardSubtype)
{
throw new ArgumentException("'Content-Type' header cannot contain wildcard subtype '*'", "Content-Type");
}
this.Set(CONTENT_TYPE, value.ToString());
}
}
//**
// * Returns the date and time at which the message was created, as specified by the {@code Date} header.
// * <p>The date is returned as the number of milliseconds since January 1, 1970 GMT. Returns -1 when the date is unknown.
// * @return the creation date/time
// * @throws IllegalArgumentException if the value can't be converted to a date
// */
//**
// * Sets the date and time at which the message was created, as specified by the {@code Date} header.
// * <p>The date should be specified as the number of milliseconds since January 1, 1970 GMT.
// * @param date the date
// */
/// <summary>
/// Gets or sets the date and time at which the message was created,
/// as specified by the 'Date' header.
/// </summary>
/// <remarks>
/// Returns <see langword="null"/> when the date is unknown.
/// </remarks>
public DateTime? Date
{
get
{
return this.GetSingleDate(DATE);
}
set
{
this.SetDate(DATE, value);
}
}
/// <summary>
/// Gets or sets the entity tag of the body, as specified by the 'ETag' header.
/// </summary>
public string ETag
{
get
{
return this.Unquote(this.Get(ETAG));
}
set
{
this.Set(ETAG, this.Quote(value));
}
}
/// <summary>
/// Gets or sets the date and time at which the message is no longer valid,
/// as specified by the 'Expires' header.
/// </summary>
public string Expires
{
get
{
return this.Get(EXPIRES);
}
set
{
this.Set(EXPIRES, value);
}
}
/// <summary>
/// Gets or sets the date and time as specified by the 'If-Modified-Since' header.
/// </summary>
/// <remarks>
/// Returns <see langword="null"/> when the date is unknown.
/// </remarks>
public DateTime? IfModifiedSince
{
get
{
return this.GetSingleDate(IF_MODIFIED_SINCE);
}
set
{
this.SetDate(IF_MODIFIED_SINCE, value);
}
}
/// <summary>
/// Gets or sets the value of the 'If-None-Match' header.
/// </summary>
public string[] IfNoneMatch
{
get
{
string[] values = this.GetMultiValues(IF_NONE_MATCH);
if (values == null || values.Length == 0)
{
return new string[0];
}
else
{
string[] result = new string[values.Length];
for (int i = 0; i < values.Length; i++)
{
result[i] = Unquote(values[i]);
}
return result;
}
}
set
{
foreach (string str in value)
{
this.Add(IF_NONE_MATCH, this.Quote(str));
}
}
}
/// <summary>
/// Gets or sets the time the resource was last changed,
/// as specified by the 'Last-Modified' header.
/// </summary>
/// <remarks>
/// Returns <see langword="null"/> when the date is unknown.
/// </remarks>
public DateTime? LastModified
{
get
{
return this.GetSingleDate(LAST_MODIFIED);
}
set
{
this.SetDate(LAST_MODIFIED, value);
}
}
/// <summary>
/// Gets or sets the (new) location of a resource,
/// as specified by the 'Location' header.
/// </summary>
public Uri Location
{
get
{
string value = this.GetSingleValue(LOCATION);
return (value != null ? new Uri(value, UriKind.RelativeOrAbsolute) : null);
}
set
{
this.Set(LOCATION, value.ToString());
}
}
/// <summary>
/// Gets or sets the value of the 'Pragma' header.
/// </summary>
public string Pragma
{
get
{
return this.Get(PRAGMA);
}
set
{
this.Set(PRAGMA, value);
}
}
#endregion
#region Private methods
private string Quote(string s)
{
if (s == null)
{
return null;
}
if (!s.StartsWith("\"") && !s.EndsWith("\""))
{
s = "\"" + s + "\"";
}
return s;
}
private string Unquote(string s)
{
if (s == null)
{
return null;
}
if (s.StartsWith("\"") && s.EndsWith("\""))
{
s = s.Substring(1, s.Length - 2);
}
return s;
}
private DateTime? GetSingleDate(string headerName)
{
string headerValue = GetSingleValue(headerName);
if (headerValue != null)
{
return DateTime.Parse(headerValue, DateTimeFormatInfo).ToUniversalTime();
}
else
{
return null;
}
}
private void SetDate(string headerName, DateTime? date)
{
if (date.HasValue)
{
this.Set(headerName, date.Value.ToUniversalTime().ToString("R", DateTimeFormatInfo));
}
else
{
this.Remove(headerName);
}
}
#endregion
/// <summary>
/// Return the header value for the given header name, if any.
/// </summary>
/// <param name="headerName">The header name</param>
/// <returns>The first header value; or <see langword="null"/></returns>
/// <exception cref="NotSupportedException">
/// If multiple values are stored for the given header name.
/// </exception>
public string GetSingleValue(string headerName)
{
string[] headerValues = this.GetValues(headerName);
if (headerValues == null || headerValues.Length == 0)
{
return null;
}
if (headerValues.Length == 1)
{
return headerValues[0];
}
throw new NotSupportedException(String.Format(
"Multiple values not supported for header '{0}'", headerName));
}
/// <summary>
/// Return an array of header values for the given header name, if any.
/// </summary>
/// <param name="headerName">The header name</param>
/// <returns>The array of header values; or <see langword="null"/></returns>
public string[] GetMultiValues(string headerName)
{
string headerValue = this.Get(headerName);
if (headerValue == null)
{
return null;
}
else
{
return headerValue.Split(',');
}
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ namespace Spring.Http
/// <a href="http://tools.ietf.org/html/rfc2616#section-5.1.1">HTTP 1.1, section 6</a>
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia</author>
/// <author>Bruno Baia (.NET)</author>
public enum HttpMethod
{
/// <summary>

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ using System.Net;
namespace Spring.Http
{
/// <summary>
/// Represents a HTTP response message with no entity.
/// Represents a HTTP response message with no body.
/// </summary>
/// <author>Bruno Baia</author>
public class HttpResponseMessage : HttpResponseMessage<object>
@@ -44,7 +44,7 @@ namespace Spring.Http
/// <param name="headers">The response headers.</param>
/// <param name="statusCode">The HTTP status code.</param>
/// <param name="statusDescription">The HTTP status description.</param>
public HttpResponseMessage(WebHeaderCollection headers, HttpStatusCode statusCode, string statusDescription) :
public HttpResponseMessage(HttpHeaders headers, HttpStatusCode statusCode, string statusDescription) :
base(null, headers, statusCode, statusDescription)
{
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,29 +28,11 @@ namespace Spring.Http
/// </summary>
/// <typeparam name="T">The type of the response body.</typeparam>
/// <author>Bruno Baia</author>
public class HttpResponseMessage<T> where T : class
public class HttpResponseMessage<T> : HttpEntity<T> where T : class
{
private WebHeaderCollection headers;
private T body;
private HttpStatusCode statusCode;
private string statusDescription;
/// <summary>
/// Gets the response headers.
/// </summary>
public WebHeaderCollection Headers
{
get { return this.headers; }
}
/// <summary>
/// Gets the response body. May be null.
/// </summary>
public T Body
{
get { return this.body; }
}
/// <summary>
/// Gets the HTTP status code of the response.
/// </summary>
@@ -94,7 +76,7 @@ namespace Spring.Http
/// <param name="headers">The response headers.</param>
/// <param name="statusCode">The HTTP status code.</param>
/// <param name="statusDescription">The HTTP status description.</param>
public HttpResponseMessage(WebHeaderCollection headers, HttpStatusCode statusCode, string statusDescription) :
public HttpResponseMessage(HttpHeaders headers, HttpStatusCode statusCode, string statusDescription) :
this(null, headers, statusCode, statusDescription)
{
}
@@ -106,12 +88,11 @@ namespace Spring.Http
/// <param name="headers">The response headers.</param>
/// <param name="statusCode">The HTTP status code.</param>
/// <param name="statusDescription">The HTTP status description.</param>
public HttpResponseMessage(T body, WebHeaderCollection headers, HttpStatusCode statusCode, string statusDescription)
public HttpResponseMessage(T body, HttpHeaders headers, HttpStatusCode statusCode, string statusDescription) :
base(body, headers)
{
this.statusCode = statusCode;
this.statusDescription = statusDescription;
this.body = body;
this.headers = headers;
}
}
}

View File

@@ -0,0 +1,47 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
namespace Spring.Http
{
/// <summary>
/// Represents an HTTP message, consisting of <see cref="P:Headers">headers</see>
/// and a readable <see cref="P:Body">body</see>.
/// </summary>
/// <remarks>
/// Typically implemented by an HTTP request on the server-side, or a response on the client-side.
/// </remarks>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public interface IHttpInputMessage
{
/// <summary>
/// Gets the message headers.
/// </summary>
HttpHeaders Headers { get; }
/// <summary>
/// Gets the body of the message as a stream.
/// </summary>
Stream Body { get; }
}
}

View File

@@ -0,0 +1,47 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
namespace Spring.Http
{
/// <summary>
/// Represents an HTTP message, consisting of <see cref="P:Headers">headers</see>
/// and a writable <see cref="P:Body">body</see>.
/// </summary>
/// <remarks>
/// Typically implemented by an HTTP request on the client-side, or a response on the server-side.
/// </remarks>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public interface IHttpOutputMessage
{
/// <summary>
/// Gets the message headers.
/// </summary>
HttpHeaders Headers { get; }
/// <summary>
/// Sets the delegate that writes the body message as a stream.
/// </summary>
Action<Stream> Body { get; set; }
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -255,8 +255,8 @@ namespace Spring.Http
AssertUtils.ArgumentHasText(subtype, "'subtype' must not be empty");
//checkToken(type);
//checkToken(subtype);
this.type = type.ToLowerInvariant();
this.subtype = subtype.ToLowerInvariant();
this.type = type.ToLower(CultureInfo.InvariantCulture);
this.subtype = subtype.ToLower(CultureInfo.InvariantCulture);
this.parameters = new Dictionary<string, string>(parameters, StringComparer.InvariantCultureIgnoreCase);
//if (parameters.Count > 0)
//{
@@ -550,9 +550,12 @@ namespace Spring.Http
/// <summary>
/// Parse the given String into a single <see cref="MediaType"/>.
/// </summary>
/// <remarks>
/// This method can be used to parse a 'Content-Type' header.
/// </remarks>
/// <param name="mediaType">The string to parse.</param>
/// <returns>The media type.</returns>
public static MediaType ParseMediaType(string mediaType)
public static MediaType Parse(string mediaType)
{
if (!StringUtils.HasText(mediaType))
{
@@ -600,29 +603,6 @@ namespace Spring.Http
return new MediaType(type, subtype, parameters);
}
/// <summary>
/// Parse the given, comma-seperated string into a list of <see cref="MediaType"/> objects.
/// </summary>
/// <remarks>
/// This method can be used to parse an 'Accept' or 'Content-Type' header.
/// </remarks>
/// <param name="mediaTypes">The string to parse.</param>
/// <returns>The list of media types.</returns>
public static List<MediaType> ParseMediaTypes(string mediaTypes)
{
List<MediaType> mediaTypeList = new List<MediaType>();
if (!StringUtils.HasText(mediaTypes))
{
return mediaTypeList;
}
string[] tokens = mediaTypes.Split(',');
foreach (string token in tokens)
{
mediaTypeList.Add(ParseMediaType(token));
}
return mediaTypeList;
}
/// <summary>
/// Return a string representation of the given list of <see cref="MediaType"/> objects.
/// </summary>
@@ -638,7 +618,7 @@ namespace Spring.Http
{
if (builder.Length > 0)
{
builder.Append(", ");
builder.Append(',');
}
builder.Append(mediaType);
}

View File

@@ -0,0 +1,76 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Net;
using System.Runtime.Serialization;
namespace Spring.Http.Rest
{
/// <summary>
/// Exception thrown when an HTTP 4xx is received.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
#if !SILVERLIGHT
[Serializable]
#endif
public class HttpClientErrorException : HttpStatusCodeException
{
/// <summary>
/// Creates a new instance of <see cref="HttpClientErrorException"/>
/// based on a <see cref="HttpStatusCode"/>.
/// </summary>
/// <param name="statusCode">The HTTP status code.</param>
public HttpClientErrorException(HttpStatusCode statusCode)
: base (statusCode)
{
}
/// <summary>
/// Creates a new instance of <see cref="HttpClientErrorException"/>
/// based on a <see cref="HttpStatusCode"/> and a status description.
/// </summary>
/// <param name="statusCode">The HTTP status code.</param>
/// <param name="statusDescription">The HTTP status description.</param>
public HttpClientErrorException(HttpStatusCode statusCode, string statusDescription)
: base (statusCode, statusDescription)
{
}
#if !SILVERLIGHT
/// <summary>
/// Creates a new instance of the <see cref="HttpClientErrorException"/> class.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// that holds the serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/>
/// that contains contextual information about the source or destination.
/// </param>
protected HttpClientErrorException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endif
}
}

View File

@@ -0,0 +1,76 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Net;
using System.Runtime.Serialization;
namespace Spring.Http.Rest
{
/// <summary>
/// Exception thrown when an HTTP 5xx is received.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
#if !SILVERLIGHT
[Serializable]
#endif
public class HttpServerErrorException : HttpStatusCodeException
{
/// <summary>
/// Creates a new instance of <see cref="HttpServerErrorException"/>
/// based on a <see cref="HttpStatusCode"/>.
/// </summary>
/// <param name="statusCode">The HTTP status code.</param>
public HttpServerErrorException(HttpStatusCode statusCode)
: base (statusCode)
{
}
/// <summary>
/// Creates a new instance of <see cref="HttpServerErrorException"/>
/// based on a <see cref="HttpStatusCode"/> and a status description.
/// </summary>
/// <param name="statusCode">The HTTP status code.</param>
/// <param name="statusDescription">The HTTP status description.</param>
public HttpServerErrorException(HttpStatusCode statusCode, string statusDescription)
: base (statusCode, statusDescription)
{
}
#if !SILVERLIGHT
/// <summary>
/// Creates a new instance of the <see cref="HttpServerErrorException"/> class.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// that holds the serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/>
/// that contains contextual information about the source or destination.
/// </param>
protected HttpServerErrorException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endif
}
}

View File

@@ -0,0 +1,129 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Net;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace Spring.Http.Rest
{
/// <summary>
/// Base class for exceptions based on a <see cref="HttpStatusCode"/>.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
#if !SILVERLIGHT
[Serializable]
#endif
public class HttpStatusCodeException : RestClientException
{
private HttpStatusCode statusCode;
private string statusDescription;
/// <summary>
/// Gets the HTTP status code.
/// </summary>
public HttpStatusCode StatusCode
{
get { return this.statusCode; }
}
/// <summary>
/// Gets the HTTP status description.
/// </summary>
public string StatusDescription
{
get { return this.statusDescription; }
}
/// <summary>
/// Creates a new instance of <see cref="HttpStatusCodeException"/>
/// based on a <see cref="HttpStatusCode"/>.
/// </summary>
/// <param name="statusCode">The HTTP status code.</param>
public HttpStatusCodeException(HttpStatusCode statusCode)
: base(String.Format("The server returned '{0}' with the status code {0:d}.", statusCode))
{
this.statusCode = statusCode;
this.statusDescription = statusCode.ToString();
}
/// <summary>
/// Creates a new instance of <see cref="HttpStatusCodeException"/>
/// based on a <see cref="HttpStatusCode"/> and a status description.
/// </summary>
/// <param name="statusCode">The HTTP status code.</param>
/// <param name="statusDescription">The HTTP status description.</param>
public HttpStatusCodeException(HttpStatusCode statusCode, string statusDescription)
: base(String.Format("The server returned '{0}' with the status code {1:d} - {1}.", statusDescription, statusCode))
{
this.statusCode = statusCode;
this.statusDescription = statusDescription;
}
#if !SILVERLIGHT
/// <summary>
/// Creates a new instance of the <see cref="RestClientException"/> class.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// that holds the serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/>
/// that contains contextual information about the source or destination.
/// </param>
protected HttpStatusCodeException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
if (info != null)
{
this.statusCode = (HttpStatusCode)info.GetInt32("StatusCode");
this.statusDescription = info.GetString("StatusDescription");
}
}
/// <summary>
/// Populates the <see cref="System.Runtime.Serialization.SerializationInfo"/> with
/// information about the exception.
/// </summary>
/// <param name="info">
/// The <see cref="System.Runtime.Serialization.SerializationInfo"/> that holds
/// the serialized object data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="System.Runtime.Serialization.StreamingContext"/> that contains contextual
/// information about the source or destination.
/// </param>
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(
SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
if (info != null)
{
info.AddValue("StatusCode", (int)this.statusCode);
info.AddValue("StatusDescription", this.statusDescription);
}
}
#endif
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,19 +18,22 @@
#endregion
using System.IO;
using System.Net;
using Spring.Http.Client;
namespace Spring.Http.Rest
{
/// <summary>
/// Callback interface for code that operates on a <see cref="HttpWebRequest"/>.
/// Callback interface for code that operates on a <see cref="IClientHttpRequest"/>.
/// Allows to manipulate the request headers, and write to the request body.
/// </summary>
/// <remarks>
/// <para>
/// Callback interface used by <see cref="RestTemplate"/>'s senders methods.
/// Implementations of this interface perform the actual work of writing data
/// to a <see cref="HttpWebRequest"/>, but don't need to worry about exception
/// to a <see cref="IClientHttpRequest"/>, but don't need to worry about exception
/// handling or closing resources.
/// </para>
/// <para>
@@ -42,11 +45,13 @@ namespace Spring.Http.Rest
public interface IRequestCallback
{
/// <summary>
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="HttpWebRequest"/> to write data.
/// Gets called by <see cref="RestTemplate"/> with an <see cref="IClientHttpRequest"/> to write data.
/// </summary>
/// <remarks>
/// Does not need to care about closing the request or about handling errors:
/// this will all be handled by the <see cref="RestTemplate"/> class.
/// </summary>
/// </remarks>
/// <param name="request">The active HTTP request.</param>
void DoWithRequest(HttpWebRequest request);
void DoWithRequest(IClientHttpRequest request);
}
}

View File

@@ -0,0 +1,54 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using Spring.Http.Client;
namespace Spring.Http.Rest
{
/// <summary>
/// Strategy interface used by the <see cref="RestTemplate"/> to determine
/// whether a particular response has an error or not.
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public interface IResponseErrorHandler
{
/// <summary>
/// Indicates whether the given response has any errors.
/// </summary>
/// <remarks>
/// Implementations will typically inspect the status code of the response.
/// </remarks>
/// <param name="response">The response to inspect.</param>
/// <returns>
/// <see langword="true"/> if the response has an error; otherwise <see langword="false"/>.
/// </returns>
bool HasError(IClientHttpResponse response);
/// <summary>
/// Handles the error in the given response.
/// This method is only called when <see cref="M:HasError"/> has returned <see langword="true"/>.
/// </summary>
/// <param name="response">The response with the error</param>
void HandleError(IClientHttpResponse response);
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,17 +20,19 @@
using System.Net;
using Spring.Http.Client;
namespace Spring.Http.Rest
{
/// <summary>
/// Callback interface for code that operates on a <see cref="HttpWebResponse"/>.
/// Callback interface for code that operates on a <see cref="IClientHttpResponse"/>.
/// Allows to manipulate the response headers, and extract the response body.
/// </summary>
/// <remarks>
/// <para>
/// Generic callback interface used by <see cref="RestTemplate"/>'s retrieval methods.
/// Implementations of this interface perform the actual work of extracting data
/// from a <see cref="HttpWebResponse"/>, but don't need to worry about exception
/// from a <see cref="IClientHttpResponse"/>, but don't need to worry about exception
/// handling or closing resources.
/// </para>
/// <para>
@@ -42,11 +44,11 @@ namespace Spring.Http.Rest
public interface IResponseExtractor<T> where T : class
{
/// <summary>
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="HttpWebResponse"/> to extract data.
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="IClientHttpResponse"/> to extract data.
/// Does not need to care about closing the request or about handling errors:
/// this will all be handled by the <see cref="RestTemplate"/> class.
/// </summary>
/// <param name="response">The active HTTP request.</param>
T ExtractData(HttpWebResponse response);
T ExtractData(IClientHttpResponse response);
}
}

View File

@@ -0,0 +1,607 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Net;
using System.Collections.Generic;
namespace Spring.Http.Rest
{
/// <summary>
/// Interface specifying a basic set of RESTful operations.
/// </summary>
/// <remarks>
/// Not often used directly, but a useful option to enhance testability,
/// as it can easily be mocked or stubbed.
/// </remarks>
/// <see cref="RestTemplate"/>
/// <author>Arjen Poutsma</author>
/// <author>Juergen Hoeller</author>
/// <author>Bruno Baia (.NET)</author>
public interface IRestAsyncOperations
{
#region GET
/// <summary>
/// Retrieve a representation by doing a GET on the specified URL.
/// The response (if any) is converted and returned.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given URI variables, if any.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The converted object</returns>
void GetForObjectAsync<T>(string url, string[] uriVariables, Action<MethodCompletedEventArgs<T>> getCompleted) where T : class;
/// <summary>
/// Retrieve a representation by doing a GET on the specified URL.
/// The response (if any) is converted and returned.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given dictionary.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The converted object</returns>
void GetForObjectAsync<T>(string url, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<T>> getCompleted) where T : class;
/// <summary>
/// Retrieve a representation by doing a GET on the specified URL.
/// The response (if any) is converted and returned.
/// </summary>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <returns>The converted object</returns>
void GetForObjectAsync<T>(Uri url, Action<MethodCompletedEventArgs<T>> getCompleted) where T : class;
/// <summary>
/// Retrieve an entity by doing a GET on the specified URL.
/// The response is converted and stored in an <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given URI variables, if any.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The HTTP response message.</returns>
void GetForMessageAsync<T>(string url, string[] uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage<T>>> getCompleted) where T : class;
/// <summary>
/// Retrieve an entity by doing a GET on the specified URL.
/// The response is converted and stored in an <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given dictionary.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The HTTP response message.</returns>
void GetForMessageAsync<T>(string url, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage<T>>> getCompleted) where T : class;
/// <summary>
/// Retrieve an entity by doing a GET on the specified URL.
/// The response is converted and stored in an <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <returns>The HTTP response message.</returns>
void GetForMessageAsync<T>(Uri url, Action<MethodCompletedEventArgs<HttpResponseMessage<T>>> getCompleted) where T : class;
#endregion
#region HEAD
/// <summary>
/// Retrieve all headers of the resource specified by the URI template.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given URI variables, if any.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>All HTTP headers of that resource</returns>
void HeadForHeadersAsync(string url, string[] uriVariables, Action<MethodCompletedEventArgs<HttpHeaders>> headCompleted);
/// <summary>
/// Retrieve all headers of the resource specified by the URI template.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given dictionary.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>All HTTP headers of that resource</returns>
void HeadForHeadersAsync(string url, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<HttpHeaders>> headCompleted);
/// <summary>
/// Retrieve all headers of the resource specified by the URI template.
/// </summary>
/// <param name="url">The URL.</param>
/// <returns>All HTTP headers of that resource</returns>
void HeadForHeadersAsync(Uri url, Action<MethodCompletedEventArgs<HttpHeaders>> headCompleted);
#endregion
#region POST
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the value of the 'Location' header.
/// This header typically indicates where the new resource is stored.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The value for the Location header.</returns>
void PostForLocationAsync(string url, object request, string[] uriVariables, Action<Uri> postCompleted);
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the value of the 'Location' header.
/// This header typically indicates where the new resource is stored.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The value for the Location header.</returns>
void PostForLocationAsync(string url, object request, IDictionary<string, string> uriVariables, Action<Uri> postCompleted);
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the value of the 'Location' header.
/// This header typically indicates where the new resource is stored.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <returns>The value for the Location header.</returns>
void PostForLocationAsync(Uri url, object request, Action<Uri> postCompleted);
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the representation found in the response.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The converted object.</returns>
void PostForObjectAsync<T>(string url, object request, string[] uriVariables, Action<MethodCompletedEventArgs<T>> postCompleted) where T : class;
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the representation found in the response.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The converted object.</returns>
void PostForObjectAsync<T>(string url, object request, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<T>> postCompleted) where T : class;
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the representation found in the response.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <returns>The converted object.</returns>
void PostForObjectAsync<T>(Uri url, object request, Action<MethodCompletedEventArgs<T>> postCompleted) where T : class;
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The HTTP response message.</returns>
void PostForMessageAsync<T>(string url, object request, string[] uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage<T>>> postCompleted) where T : class;
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The HTTP response message.</returns>
void PostForMessageAsync<T>(string url, object request, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage<T>>> postCompleted) where T : class;
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <returns>The HTTP response message.</returns>
void PostForMessageAsync<T>(Uri url, object request, Action<MethodCompletedEventArgs<HttpResponseMessage<T>>> postCompleted) where T : class;
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The HTTP response message with no entity.</returns>
void PostForMessageAsync(string url, object request, string[] uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage>> postCompleted);
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The HTTP response message with no entity.</returns>
void PostForMessageAsync(string url, object request, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage>> postCompleted);
/// <summary>
/// Create a new resource by POSTing the given object to the URI template,
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
/// <returns>The HTTP response message with no entity.</returns>
void PostForMessageAsync(Uri url, object request, Action<MethodCompletedEventArgs<HttpResponseMessage>> postCompleted);
#endregion
#region PUT
/// <summary>
/// Create or update a resource by PUTting the given object to the URI.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be PUT, may be null.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
void PutAsync(string url, object request, string[] uriVariables, Action<MethodCompletedEventArgs<object>> putCompleted);
/// <summary>
/// Create or update a resource by PUTting the given object to the URI.
/// </summary>
/// <remarks>
/// <para>
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be PUT, may be null.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
void PutAsync(string url, object request, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<object>> putCompleted);
/// <summary>
/// Create or update a resource by PUTting the given object to the URI.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be PUT, may be null.</param>
void PutAsync(Uri url, object request, Action<MethodCompletedEventArgs<object>> putCompleted);
#endregion
#region DELETE
/// <summary>
/// Delete the resources at the specified URI.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given URI variables, if any.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
void DeleteAsync(string url, string[] uriVariables, Action<MethodCompletedEventArgs<object>> deleteCompleted);
/// <summary>
/// Delete the resources at the specified URI.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given dictionary.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
void DeleteAsync(string url, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<object>> deleteCompleted);
/// <summary>
/// Delete the resources at the specified URI.
/// </summary>
/// <param name="url">The URL.</param>
void DeleteAsync(Uri url, Action<MethodCompletedEventArgs<object>> deleteCompleted);
#endregion
#region OPTIONS
/// <summary>
/// Return the value of the Allow header for the given URI.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given URI variables, if any.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The value of the allow header.</returns>
void OptionsForAllowAsync(string url, string[] uriVariables, Action<IList<HttpMethod>> optionsCompleted);
/// <summary>
/// Return the value of the Allow header for the given URI.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given dictionary.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The value of the allow header.</returns>
void OptionsForAllowAsync(string url, IDictionary<string, string> uriVariables, Action<IList<HttpMethod>> optionsCompleted);
/// <summary>
/// Return the value of the Allow header for the given URI.
/// </summary>
/// <param name="url">The URL.</param>
/// <returns>The value of the allow header.</returns>
void OptionsForAllowAsync(Uri url, Action<IList<HttpMethod>> optionsCompleted);
#endregion
#region Exchange
/// <summary>
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given URI variables, if any.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The HTTP response message.</returns>
void ExchangeAsync<T>(string url, HttpMethod method, HttpEntity requestEntity, string[] uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage<T>>> methodCompleted) where T : class;
/// <summary>
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given dictionary.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The HTTP response message.</returns>
void ExchangeAsync<T>(string url, HttpMethod method, HttpEntity requestEntity, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage<T>>> methodCompleted) where T : class;
/// <summary>
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <returns>The HTTP response message.</returns>
void ExchangeAsync<T>(Uri url, HttpMethod method, HttpEntity requestEntity, Action<MethodCompletedEventArgs<HttpResponseMessage<T>>> methodCompleted) where T : class;
/// <summary>
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given URI variables, if any.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The HTTP response message with no entity.</returns>
void ExchangeAsync(string url, HttpMethod method, HttpEntity requestEntity, string[] uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage>> methodCompleted);
/// <summary>
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given dictionary.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The HTTP response message with no entity.</returns>
void ExchangeAsync(string url, HttpMethod method, HttpEntity requestEntity, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<HttpResponseMessage>> methodCompleted);
/// <summary>
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <returns>The HTTP response message with no entity.</returns>
void ExchangeAsync(Uri url, HttpMethod method, HttpEntity requestEntity, Action<MethodCompletedEventArgs<HttpResponseMessage>> methodCompleted);
#endregion
#region General execution
/// <summary>
/// Execute the HTTP method to the given URI template, preparing the request with the
/// <see cref="IRequestCallback"/>, and reading the response with an <see cref="IResponseExtractor{T}"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given URI variables, if any.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestCallback">Object that prepares the request.</param>
/// <param name="responseExtractor">Object that extracts the return value from the response.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>An arbitrary object, as returned by the <see cref="IResponseExtractor{T}"/>.</returns>
void ExecuteAsync<T>(string url, HttpMethod method, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor, string[] uriVariables, Action<MethodCompletedEventArgs<T>> methodCompleted) where T : class;
/// <summary>
/// Execute the HTTP method to the given URI template, preparing the request with the
/// <see cref="IRequestCallback"/>, and reading the response with an <see cref="IResponseExtractor{T}"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given dictionary.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestCallback">Object that prepares the request.</param>
/// <param name="responseExtractor">Object that extracts the return value from the response.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>An arbitrary object, as returned by the <see cref="IResponseExtractor{T}"/>.</returns>
void ExecuteAsync<T>(string url, HttpMethod method, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor, IDictionary<string, string> uriVariables, Action<MethodCompletedEventArgs<T>> methodCompleted) where T : class;
/// <summary>
/// Execute the HTTP method to the given URI template, preparing the request with the
/// <see cref="IRequestCallback"/>, and reading the response with an <see cref="IResponseExtractor{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestCallback">Object that prepares the request.</param>
/// <param name="responseExtractor">Object that extracts the return value from the response.</param>
/// <returns>An arbitrary object, as returned by the <see cref="IResponseExtractor{T}"/>.</returns>
void ExecuteAsync<T>(Uri url, HttpMethod method, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor, Action<MethodCompletedEventArgs<T>> methodCompleted) where T : class;
#endregion
// TODO : void CancelAsync();
}
}

View File

@@ -1,7 +1,8 @@
#region License
#if !SILVERLIGHT
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +29,8 @@ namespace Spring.Http.Rest
/// Interface specifying a basic set of RESTful operations.
/// </summary>
/// <remarks>
/// Not often used directly, but a useful option to enhance testability, as it can easily be mocked or stubbed.
/// Not often used directly, but a useful option to enhance testability,
/// as it can easily be mocked or stubbed.
/// </remarks>
/// <see cref="RestTemplate"/>
/// <author>Arjen Poutsma</author>
@@ -36,6 +38,9 @@ namespace Spring.Http.Rest
/// <author>Bruno Baia (.NET)</author>
public interface IRestOperations
{
// TODO : use object[] instead of string[]
// TODO : use IDictionary<string, object> instead of IDictionary<string, string>
#region GET
/// <summary>
@@ -121,7 +126,7 @@ namespace Spring.Http.Rest
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>All HTTP headers of that resource</returns>
WebHeaderCollection HeadForHeaders(string url, params string[] uriVariables);
HttpHeaders HeadForHeaders(string url, params string[] uriVariables);
/// <summary>
/// Retrieve all headers of the resource specified by the URI template.
@@ -132,14 +137,14 @@ namespace Spring.Http.Rest
/// <param name="url">The URL.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>All HTTP headers of that resource</returns>
WebHeaderCollection HeadForHeaders(string url, IDictionary<string, string> uriVariables);
HttpHeaders HeadForHeaders(string url, IDictionary<string, string> uriVariables);
/// <summary>
/// Retrieve all headers of the resource specified by the URI template.
/// </summary>
/// <param name="url">The URL.</param>
/// <returns>All HTTP headers of that resource</returns>
WebHeaderCollection HeadForHeaders(Uri url); //throws RestClientException;
HttpHeaders HeadForHeaders(Uri url);
#endregion
@@ -155,7 +160,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
@@ -174,7 +179,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
@@ -189,7 +194,7 @@ namespace Spring.Http.Rest
/// This header typically indicates where the new resource is stored.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
@@ -205,7 +210,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
@@ -224,7 +229,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
@@ -239,7 +244,7 @@ namespace Spring.Http.Rest
/// and returns the representation found in the response.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
@@ -256,7 +261,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
@@ -275,7 +280,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
@@ -290,7 +295,7 @@ namespace Spring.Http.Rest
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
@@ -307,7 +312,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
@@ -325,7 +330,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
@@ -339,7 +344,7 @@ namespace Spring.Http.Rest
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be POSTed, may be null.</param>
@@ -358,7 +363,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given URI variables, if any.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
@@ -374,7 +379,7 @@ namespace Spring.Http.Rest
/// URI Template variables are expanded using the given dictionary.
/// </para>
/// <para>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </para>
/// </remarks>
/// <param name="url">The URL.</param>
@@ -386,7 +391,7 @@ namespace Spring.Http.Rest
/// Create or update a resource by PUTting the given object to the URI.
/// </summary>
/// <remarks>
/// The request parameter can be a <see cref="HttpRequestMessage"/> in order to add additional HTTP headers to the request.
/// The request parameter can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="request">The Object to be PUT, may be null.</param>
@@ -461,7 +466,7 @@ namespace Spring.Http.Rest
#region Exchange
/// <summary>
/// Execute the HTTP request to the given URI template, writing the given request message to the request,
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
@@ -469,13 +474,16 @@ namespace Spring.Http.Rest
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="requestMessage">The HTTP request message to write to the request.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The HTTP response message.</returns>
HttpResponseMessage<T> Exchange<T>(string url, HttpRequestMessage requestMessage, params string[] uriVariables) where T : class;
HttpResponseMessage<T> Exchange<T>(string url, HttpMethod method, HttpEntity requestEntity, params string[] uriVariables) where T : class;
/// <summary>
/// Execute the HTTP request to the given URI template, writing the given request message to the request,
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <remarks>
@@ -483,62 +491,77 @@ namespace Spring.Http.Rest
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="requestMessage">The HTTP request message to write to the request.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The HTTP response message.</returns>
HttpResponseMessage<T> Exchange<T>(string url, HttpRequestMessage requestMessage, IDictionary<string, string> uriVariables) where T : class;
HttpResponseMessage<T> Exchange<T>(string url, HttpMethod method, HttpEntity requestEntity, IDictionary<string, string> uriVariables) where T : class;
/// <summary>
/// Execute the HTTP request to the given URI template, writing the given request message to the request,
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response as <see cref="HttpResponseMessage{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="requestMessage">The HTTP request message to write to the request.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <returns>The HTTP response message.</returns>
HttpResponseMessage<T> Exchange<T>(Uri url, HttpRequestMessage requestMessage) where T : class;
HttpResponseMessage<T> Exchange<T>(Uri url, HttpMethod method, HttpEntity requestEntity) where T : class;
/// <summary>
/// Execute the HTTP request to the given URI template, writing the given request message to the request,
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given URI variables, if any.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="requestMessage">The HTTP request message to write to the request.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>The HTTP response message with no entity.</returns>
HttpResponseMessage Exchange(string url, HttpRequestMessage requestMessage, params string[] uriVariables);
HttpResponseMessage Exchange(string url, HttpMethod method, HttpEntity requestEntity, params string[] uriVariables);
/// <summary>
/// Execute the HTTP request to the given URI template, writing the given request message to the request,
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <remarks>
/// URI Template variables are expanded using the given dictionary.
/// </remarks>
/// <param name="url">The URL.</param>
/// <param name="requestMessage">The HTTP request message to write to the request.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>The HTTP response message with no entity.</returns>
HttpResponseMessage Exchange(string url, HttpRequestMessage requestMessage, IDictionary<string, string> uriVariables);
HttpResponseMessage Exchange(string url, HttpMethod method, HttpEntity requestEntity, IDictionary<string, string> uriVariables);
/// <summary>
/// Execute the HTTP request to the given URI template, writing the given request message to the request,
/// Execute the HTTP method to the given URI template, writing the given request message to the request,
/// and returns the response with no entity as <see cref="HttpResponseMessage"/>.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="requestMessage">The HTTP request message to write to the request.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestEntity">
/// The HTTP entity (headers and/or body) to write to the request, may be <see langword="null"/>.
/// </param>
/// <returns>The HTTP response message with no entity.</returns>
HttpResponseMessage Exchange(Uri url, HttpRequestMessage requestMessage);
HttpResponseMessage Exchange(Uri url, HttpMethod method, HttpEntity requestEntity);
#endregion
#region General execution
/// <summary>
/// Execute the HTTP request to the given URI template, preparing the request with the
/// Execute the HTTP method to the given URI template, preparing the request with the
/// <see cref="IRequestCallback"/>, and reading the response with an <see cref="IResponseExtractor{T}"/>.
/// </summary>
/// <remarks>
@@ -546,14 +569,15 @@ namespace Spring.Http.Rest
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestCallback">Object that prepares the request.</param>
/// <param name="responseExtractor">Object that extracts the return value from the response.</param>
/// <param name="uriVariables">The variables to expand the template.</param>
/// <returns>An arbitrary object, as returned by the <see cref="IResponseExtractor{T}"/>.</returns>
T Execute<T>(string url, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor, params string[] uriVariables) where T : class; //throws RestClientException;
T Execute<T>(string url, HttpMethod method, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor, params string[] uriVariables) where T : class;
/// <summary>
/// Execute the HTTP request to the given URI template, preparing the request with the
/// Execute the HTTP method to the given URI template, preparing the request with the
/// <see cref="IRequestCallback"/>, and reading the response with an <see cref="IResponseExtractor{T}"/>.
/// </summary>
/// <remarks>
@@ -561,23 +585,26 @@ namespace Spring.Http.Rest
/// </remarks>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestCallback">Object that prepares the request.</param>
/// <param name="responseExtractor">Object that extracts the return value from the response.</param>
/// <param name="uriVariables">The dictionary containing variables for the URI template.</param>
/// <returns>An arbitrary object, as returned by the <see cref="IResponseExtractor{T}"/>.</returns>
T Execute<T>(string url, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor, IDictionary<string, string> uriVariables) where T : class;
T Execute<T>(string url, HttpMethod method, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor, IDictionary<string, string> uriVariables) where T : class;
/// <summary>
/// Execute the HTTP request to the given URI template, preparing the request with the
/// Execute the HTTP method to the given URI template, preparing the request with the
/// <see cref="IRequestCallback"/>, and reading the response with an <see cref="IResponseExtractor{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the response value.</typeparam>
/// <param name="url">The URL.</param>
/// <param name="method">The HTTP method (GET, POST, etc.)</param>
/// <param name="requestCallback">Object that prepares the request.</param>
/// <param name="responseExtractor">Object that extracts the return value from the response.</param>
/// <returns>An arbitrary object, as returned by the <see cref="IResponseExtractor{T}"/>.</returns>
T Execute<T>(Uri url, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor) where T : class;
T Execute<T>(Uri url, HttpMethod method, IRequestCallback requestCallback, IResponseExtractor<T> responseExtractor) where T : class;
#endregion
}
}
#endif

View File

@@ -0,0 +1,50 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.ComponentModel;
namespace Spring.Http.Rest
{
public class MethodCompletedEventArgs<T> : AsyncCompletedEventArgs where T : class
{
private T response;
public T Response
{
get
{
// Raise an exception if the operation failed or
// was canceled.
base.RaiseExceptionIfNecessary();
// If the operation was successful, return the
// property value.
return response;
}
}
public MethodCompletedEventArgs(T response, Exception exception, bool cancelled, object userState)
: base(exception, cancelled, userState)
{
this.response = response;
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,9 @@ namespace Spring.Http.Rest
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
#if !SILVERLIGHT
[Serializable]
#endif
public class RestClientException : Exception
{
/// <summary>
@@ -63,6 +65,7 @@ namespace Spring.Http.Rest
{
}
#if !SILVERLIGHT
/// <summary>
/// Creates a new instance of the <see cref="RestClientException"/> class.
/// </summary>
@@ -78,5 +81,6 @@ namespace Spring.Http.Rest
: base(info, context)
{
}
#endif
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,10 +19,12 @@
#endregion
using System;
using System.IO;
using System.Net;
using System.Collections.Generic;
using Spring.Util;
using Spring.Http.Client;
using Spring.Http.Converters;
namespace Spring.Http.Rest.Support
@@ -32,12 +34,12 @@ namespace Spring.Http.Rest.Support
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public class AcceptHeaderRequestCallback : MethodRequestCallback
public class AcceptHeaderRequestCallback : IRequestCallback
{
#region Logging
#if !SILVERLIGHT
private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(AcceptHeaderRequestCallback));
#endif
#endregion
/// <summary>
@@ -53,26 +55,26 @@ namespace Spring.Http.Rest.Support
/// <summary>
/// Creates a new instance of <see cref="AcceptHeaderRequestCallback"/>.
/// </summary>
/// <param name="method">The HTTP method.</param>
/// <param name="responseType">The expected response body type.</param>
/// <param name="messageConverters">The list of <see cref="IHttpMessageConverter"/> to use.</param>
public AcceptHeaderRequestCallback(HttpMethod method, Type responseType, IList<IHttpMessageConverter> messageConverters) :
base(method)
public AcceptHeaderRequestCallback(Type responseType, IList<IHttpMessageConverter> messageConverters)
{
this.responseType = responseType;
this.messageConverters = messageConverters;
}
#region IRequestCallback Membres
/// <summary>
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="HttpWebRequest"/> to write data.
/// Gets called by <see cref="RestTemplate"/> with an <see cref="IClientHttpRequest"/> to write data.
/// </summary>
/// <remarks>
/// Does not need to care about closing the request or about handling errors:
/// this will all be handled by the <see cref="RestTemplate"/> class.
/// </summary>
/// </remarks>
/// <param name="request">The active HTTP request.</param>
public override void DoWithRequest(HttpWebRequest request)
public virtual void DoWithRequest(IClientHttpRequest request)
{
base.DoWithRequest(request);
if (responseType != null)
{
List<MediaType> allSupportedMediaTypes = new List<MediaType>();
@@ -99,19 +101,21 @@ namespace Spring.Http.Rest.Support
MediaType.SortBySpecificity(allSupportedMediaTypes);
#region Instrumentation
#if !SILVERLIGHT
if (LOG.IsDebugEnabled)
{
LOG.Debug(String.Format(
"Setting request Accept header to '{0}'",
MediaType.ToString(allSupportedMediaTypes)));
}
#endif
#endregion
request.Accept = MediaType.ToString(allSupportedMediaTypes);
request.Headers.Accept = allSupportedMediaTypes.ToArray();
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,96 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Net;
using Spring.Http.Client;
namespace Spring.Http.Rest.Support
{
/// <summary>
/// Default implementation of the <see cref="IResponseErrorHandler"/> interface.
/// </summary>
/// <remarks>
/// <para>
/// This error handler checks for the status code on the <see cref="IClientHttpResponse"/> :
/// any client code error (4xx) or server code error (5xx) is considered to be an error.
/// </para>
/// <para>
/// This behavior can be changed by overriding the <see cref="M:HasError(HttpStatusCode)"/> method.
/// </para>
/// </remarks>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public class DefaultResponseErrorHandler : IResponseErrorHandler
{
#region IResponseErrorHandler Members
/// <summary>
/// Indicates whether the given response has any errors.
/// </summary>
/// <remarks>
/// This implementation delegates to <see cref="M:HasError(HttpStatusCode)"/>
/// with the response status code.
/// </remarks>
/// <param name="response">The response to inspect.</param>
/// <returns>
/// <see langword="true"/> if the response has an error; otherwise <see langword="false"/>.
/// </returns>
public virtual bool HasError(IClientHttpResponse response)
{
return this.HasError(response.StatusCode);
}
/// <summary>
/// Handles the error in the given response.
/// This method is only called when <see cref="M:HasError"/> has returned <see langword="true"/>.
/// </summary>
/// <param name="response">The response with the error</param>
public virtual void HandleError(IClientHttpResponse response)
{
int type = (int)response.StatusCode / 100;
switch (type)
{
case 4 :
throw new HttpClientErrorException(response.StatusCode, response.StatusDescription);
case 5:
throw new HttpServerErrorException(response.StatusCode, response.StatusDescription);
default :
throw new HttpStatusCodeException(response.StatusCode, response.StatusDescription);
}
}
#endregion
/// <summary>
/// Checks if the given status code is a client code error (4xx) or a server code error (5xx).
/// </summary>
/// <param name="statusCode">The HTTP status code.</param>
/// <returns>
/// <see langword="true"/> if the response has an error; otherwise <see langword="false"/>.
/// </returns>
protected virtual bool HasError(HttpStatusCode statusCode)
{
int type = (int)statusCode / 100;
return type == 4 || type == 5;
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@
using System.Net;
using Spring.Http.Client;
namespace Spring.Http.Rest.Support
{
/// <summary>
@@ -27,15 +29,15 @@ namespace Spring.Http.Rest.Support
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public class HeadersResponseExtractor : IResponseExtractor<WebHeaderCollection>
public class HeadersResponseExtractor : IResponseExtractor<HttpHeaders>
{
/// <summary>
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="HttpWebResponse"/> to extract data.
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="IClientHttpResponse"/> to extract data.
/// Does not need to care about closing the request or about handling errors:
/// this will all be handled by the <see cref="RestTemplate"/> class.
/// </summary>
/// <param name="response">The active HTTP request.</param>
public WebHeaderCollection ExtractData(HttpWebResponse response)
public HttpHeaders ExtractData(IClientHttpResponse response)
{
return response.Headers;
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,9 +19,11 @@
#endregion
using System;
using System.IO;
using System.Net;
using System.Collections.Generic;
using Spring.Http.Client;
using Spring.Http.Converters;
namespace Spring.Http.Rest.Support
@@ -31,109 +33,77 @@ namespace Spring.Http.Rest.Support
/// </summary>
/// <author>Arjen Poutsma</author>
/// <author>Bruno Baia (.NET)</author>
public class HttpMessageRequestCallback : AcceptHeaderRequestCallback
public class HttpEntityRequestCallback : AcceptHeaderRequestCallback
{
#region Logging
private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(HttpMessageRequestCallback));
#if !SILVERLIGHT
private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(HttpEntityRequestCallback));
#endif
#endregion
private HttpRequestMessage requestMessage;
private HttpEntity requestEntity;
/// <summary>
/// Creates a new instance of <see cref="HttpMessageRequestCallback"/>.
/// Creates a new instance of <see cref="HttpEntityRequestCallback"/>.
/// </summary>
/// <param name="method">The HTTP method.</param>
/// <param name="requestBody">The object to write to the request.</param>
/// <param name="requestBody">
/// The object to write to the request.
/// Can be a <see cref="HttpEntity"/> in order to add additional HTTP headers to the request.
/// </param>
/// <param name="messageConverters">The list of <see cref="IHttpMessageConverter"/> to use.</param>
public HttpMessageRequestCallback(HttpMethod method, object requestBody, IList<IHttpMessageConverter> messageConverters) :
this(method, requestBody, null, messageConverters)
public HttpEntityRequestCallback(object requestBody, IList<IHttpMessageConverter> messageConverters) :
this(requestBody, null, messageConverters)
{
}
/// <summary>
/// Creates a new instance of <see cref="HttpMessageRequestCallback"/>.
/// Creates a new instance of <see cref="HttpEntityRequestCallback"/>.
/// </summary>
/// <param name="method">The HTTP method.</param>
/// <param name="requestBody">The object to write to the request.</param>
/// <param name="responseType">The expected response body type.</param>
/// <param name="messageConverters">The list of <see cref="IHttpMessageConverter"/> to use.</param>
public HttpMessageRequestCallback(HttpMethod method, object requestBody, Type responseType, IList<IHttpMessageConverter> messageConverters) :
base(method, responseType, messageConverters)
public HttpEntityRequestCallback(object requestBody, Type responseType, IList<IHttpMessageConverter> messageConverters) :
base(responseType, messageConverters)
{
if (requestBody is HttpRequestMessage)
if (requestBody is HttpEntity)
{
this.requestMessage = (HttpRequestMessage)requestBody;
this.requestMessage.Method = method;
this.requestEntity = (HttpEntity)requestBody;
}
else
{
this.requestMessage = new HttpRequestMessage(requestBody, method);
this.requestEntity = new HttpEntity(requestBody);
}
}
/// <summary>
/// Creates a new instance of <see cref="HttpMessageRequestCallback"/>.
/// Gets called by <see cref="RestTemplate"/> with an <see cref="IClientHttpRequest"/> to write data.
/// </summary>
/// <param name="requestMessage">The HTTP request message.</param>
/// <param name="messageConverters">The list of <see cref="IHttpMessageConverter"/> to use.</param>
public HttpMessageRequestCallback(HttpRequestMessage requestMessage, IList<IHttpMessageConverter> messageConverters) :
this(requestMessage, null, messageConverters)
{
}
/// <summary>
/// Creates a new instance of <see cref="HttpMessageRequestCallback"/>.
/// </summary>
/// <param name="requestMessage">The HTTP request message.</param>
/// <param name="responseType">The expected response body type.</param>
/// <param name="messageConverters">The list of <see cref="IHttpMessageConverter"/> to use.</param>
public HttpMessageRequestCallback(HttpRequestMessage requestMessage, Type responseType, IList<IHttpMessageConverter> messageConverters) :
base(requestMessage.Method, responseType, messageConverters)
{
this.requestMessage = requestMessage;
}
/// <summary>
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="HttpWebRequest"/> to write data.
/// <remarks>
/// Does not need to care about closing the request or about handling errors:
/// this will all be handled by the <see cref="RestTemplate"/> class.
/// </summary>
/// </remarks>
/// <param name="request">The active HTTP request.</param>
public override void DoWithRequest(HttpWebRequest request)
public override void DoWithRequest(IClientHttpRequest request)
{
base.DoWithRequest(request);
// headers
if (requestMessage.Headers.Count > 0)
foreach (string header in requestEntity.Headers)
{
foreach(string headerName in requestMessage.Headers)
{
// TODO : Check other special cases or create a HttpHeaders class
// Special cases
if (headerName == "Content-Type")
{
request.ContentType = requestMessage.Headers[HttpRequestHeader.ContentType];
}
else
{
request.Headers.Add(headerName, requestMessage.Headers[headerName]);
}
}
request.Headers[header] = requestEntity.Headers[header];
}
// body
if (requestMessage.Body != null)
if (requestEntity.HasBody)
{
object requestBody = requestMessage.Body;
MediaType requestContentType = MediaType.ParseMediaType(requestMessage.Headers[HttpRequestHeader.ContentType]);
object requestBody = requestEntity.Body;
MediaType requestContentType = requestEntity.Headers.ContentType;
foreach (IHttpMessageConverter messageConverter in base.messageConverters)
{
if (messageConverter.CanWrite(requestBody.GetType(), requestContentType))
{
#region Instrumentation
#if !SILVERLIGHT
if (LOG.IsDebugEnabled)
{
if (requestContentType != null)
@@ -149,7 +119,7 @@ namespace Spring.Http.Rest.Support
requestBody, messageConverter));
}
}
#endif
#endregion
messageConverter.Write(requestBody, requestContentType, request);
@@ -157,7 +127,7 @@ namespace Spring.Http.Rest.Support
}
}
string message = String.Format(
"Could not write request: no suitable IHttpMessageConverter found for request type [{0}]",
"Could not write request: no suitable IHttpMessageConverter found for request type [{0}]",
requestBody.GetType().FullName);
if (requestContentType != null)
{
@@ -165,6 +135,13 @@ namespace Spring.Http.Rest.Support
}
throw new RestClientException(message);
}
else
{
if (request.Headers.ContentLength == -1)
{
request.Headers.ContentLength = 0;
}
}
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@
using System.Net;
using Spring.Http.Client;
namespace Spring.Http.Rest.Support
{
/// <summary>
@@ -29,12 +31,12 @@ namespace Spring.Http.Rest.Support
public class HttpMessageResponseExtractor : IResponseExtractor<HttpResponseMessage>
{
/// <summary>
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="HttpWebResponse"/> to extract data.
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="IClientHttpResponse"/> to extract data.
/// Does not need to care about closing the request or about handling errors:
/// this will all be handled by the <see cref="RestTemplate"/> class.
/// </summary>
/// <param name="response">The active HTTP request.</param>
public HttpResponseMessage ExtractData(HttpWebResponse response)
public HttpResponseMessage ExtractData(IClientHttpResponse response)
{
return new HttpResponseMessage(response.Headers, response.StatusCode, response.StatusDescription);
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
using System.Net;
using System.Collections.Generic;
using Spring.Http.Client;
using Spring.Http.Converters;
namespace Spring.Http.Rest.Support
@@ -44,12 +45,12 @@ namespace Spring.Http.Rest.Support
}
/// <summary>
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="HttpWebResponse"/> to extract data.
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="IClientHttpResponse"/> to extract data.
/// Does not need to care about closing the request or about handling errors:
/// this will all be handled by the <see cref="RestTemplate"/> class.
/// </summary>
/// <param name="response">The active HTTP request.</param>
public HttpResponseMessage<T> ExtractData(HttpWebResponse response)
public HttpResponseMessage<T> ExtractData(IClientHttpResponse response)
{
T body = httpMessageConverterExtractor.ExtractData(response);
return new HttpResponseMessage<T>(body, response.Headers, response.StatusCode, response.StatusDescription);

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ using System.Net;
using System.Collections.Generic;
using Spring.Util;
using Spring.Http.Client;
using Spring.Http.Converters;
namespace Spring.Http.Rest.Support
@@ -36,9 +37,9 @@ namespace Spring.Http.Rest.Support
public class MessageConverterResponseExtractor<T> : IResponseExtractor<T> where T : class
{
#region Logging
#if !SILVERLIGHT
private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(MessageConverterResponseExtractor<T>));
#endif
#endregion
private IList<IHttpMessageConverter> messageConverters;
@@ -53,32 +54,31 @@ namespace Spring.Http.Rest.Support
}
/// <summary>
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="HttpWebResponse"/> to extract data.
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="IClientHttpResponse"/> to extract data.
/// Does not need to care about closing the request or about handling errors:
/// this will all be handled by the <see cref="RestTemplate"/> class.
/// </summary>
/// <param name="response">The active HTTP request.</param>
public T ExtractData(HttpWebResponse response)
public T ExtractData(IClientHttpResponse response)
{
string contentType = response.Headers[HttpResponseHeader.ContentType];
if (!StringUtils.HasText(contentType))
MediaType mediaType = response.Headers.ContentType;
if (mediaType == null)
{
throw new RestClientException("Could not extract response: no Content-Type found");
}
MediaType mediaType = MediaType.ParseMediaType(contentType);
foreach(IHttpMessageConverter messageConverter in messageConverters)
{
if (messageConverter.CanRead(typeof(T), mediaType))
{
#region Instrumentation
#if !SILVERLIGHT
if (LOG.IsDebugEnabled)
{
LOG.Debug(String.Format(
"Reading [{0}] as '{1}' using [{2}]",
typeof(T).FullName, mediaType, messageConverter));
}
#endif
#endregion
return messageConverter.Read<T>(response);

View File

@@ -1,72 +0,0 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Net;
namespace Spring.Http.Rest.Support
{
/// <summary>
/// Request callback implementation that sets the HTTP method.
/// </summary>
/// <author>Bruno Baia</author>
public class MethodRequestCallback : IRequestCallback
{
#region Logging
private static readonly Common.Logging.ILog LOG = Common.Logging.LogManager.GetLogger(typeof(MethodRequestCallback));
#endregion
/// <summary>
/// The HTTP method.
/// </summary>
protected HttpMethod method;
/// <summary>
/// Creates a new instance of <see cref="MethodRequestCallback"/>.
/// </summary>
/// <param name="method">The HTTP method.</param>
public MethodRequestCallback(HttpMethod method)
{
this.method = method;
}
/// <summary>
/// Gets called by <see cref="RestTemplate"/> with an opened <see cref="HttpWebRequest"/> to write data.
/// Does not need to care about closing the request or about handling errors:
/// this will all be handled by the <see cref="RestTemplate"/> class.
/// </summary>
/// <param name="request">The active HTTP request.</param>
public virtual void DoWithRequest(HttpWebRequest request)
{
#region Instrumentation
if (LOG.IsDebugEnabled)
{
LOG.Debug(String.Format("Setting request Method to '{0}'", this.method));
}
#endregion
request.Method = this.method.ToString();
}
}
}

View File

@@ -78,6 +78,7 @@
<Name>System</Name>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
</ItemGroup>
@@ -87,7 +88,13 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Http\Converters\UrlEncodedFormHttpMessageConverter.cs" />
<Compile Include="Collections\Specialized\NameValueCollection.cs" />
<Compile Include="Http\Client\ExecuteCompletedEventArgs.cs" />
<Compile Include="Http\Converters\FileInfoHttpMessageConverter.cs" />
<Compile Include="Http\Converters\FormHttpMessageConverter.cs" />
<Compile Include="Http\Converters\HttpMessageConversionException.cs" />
<Compile Include="Http\Converters\HttpMessageNotReadableException.cs" />
<Compile Include="Http\Converters\HttpMessageNotWritableException.cs" />
<Compile Include="Http\Converters\Feed\Atom10FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\AbstractFeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\Rss20FeedHttpMessageConverter.cs" />
@@ -97,15 +104,28 @@
<Compile Include="Http\Converters\Xml\XmlDocumentHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlSerializableHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\DataContractHttpMessageConverter.cs" />
<Compile Include="Http\DefaultHttpWebRequestFactory.cs" />
<Compile Include="Http\Client\IClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\IClientHttpResponse.cs" />
<Compile Include="Http\HttpEntity.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\HttpEntity`1.cs" />
<Compile Include="Http\HttpHeaders.cs" />
<Compile Include="Http\HttpResponseMessage.cs" />
<Compile Include="Http\HttpResponseMessage`1.cs" />
<Compile Include="Http\IHttpWebRequestFactory.cs" />
<Compile Include="Http\HttpRequestMessage.cs" />
<Compile Include="Http\Client\IClientHttpRequest.cs" />
<Compile Include="Http\IHttpInputMessage.cs" />
<Compile Include="Http\IHttpOutputMessage.cs" />
<Compile Include="Http\Rest\HttpClientErrorException.cs" />
<Compile Include="Http\Rest\HttpServerErrorException.cs" />
<Compile Include="Http\Rest\HttpStatusCodeException.cs" />
<Compile Include="Http\Rest\IResponseErrorHandler.cs" />
<Compile Include="Http\Rest\IRestAsyncOperations.cs" />
<Compile Include="Http\Rest\MethodCompletedEventArgs.cs" />
<Compile Include="Http\Rest\Support\AcceptHeaderRequestCallback.cs" />
<Compile Include="Http\Rest\Support\DefaultResponseErrorHandler.cs" />
<Compile Include="Http\Rest\Support\HttpEntityRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor`1.cs" />
<Compile Include="Http\Rest\Support\MethodRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HttpMessageRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HeadersResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor.cs" />
<Compile Include="Http\Converters\AbstractHttpMessageConverter.cs" />
@@ -120,7 +140,11 @@
<Compile Include="Http\Rest\RestClientException.cs" />
<Compile Include="Http\Rest\RestTemplate.cs" />
<Compile Include="Http\Converters\StringHttpMessageConverter.cs" />
<Compile Include="Http\Client\WebClientHttpRequest.cs" />
<Compile Include="Http\Client\WebClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\WebClientHttpResponse.cs" />
<Compile Include="Util\AssertUtils.cs" />
<Compile Include="Util\IoUtils.cs" />
<Compile Include="Util\StringUtils.cs" />
<Compile Include="Util\UriTemplate.cs" />
</ItemGroup>

View File

@@ -0,0 +1,132 @@
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{5A955F0B-EEC7-427C-9E6B-A26B8B51558D}</ProjectGuid>
<ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Spring</RootNamespace>
<AssemblyName>Spring.Http</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<SilverlightApplication>false</SilverlightApplication>
<ValidateXaml>true</ValidateXaml>
<ThrowErrorsInValidation>true</ThrowErrorsInValidation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\build\VS.Net.2008-SL\Spring.Http\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;SILVERLIGHT;SILVERLIGHT_3</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>Spring.Http.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\..\build\VS.Net.2008-SL\Spring.Http\Release\</OutputPath>
<DefineConstants>TRACE;SILVERLIGHT;SILVERLIGHT_3</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceModel.Web" />
<Reference Include="System.Windows" />
<Reference Include="mscorlib" />
<Reference Include="system" />
<Reference Include="System.Core" />
<Reference Include="System.Xml" />
<Reference Include="System.Net" />
<Reference Include="System.Windows.Browser" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\CommonAssemblyInfo.cs">
<Link>CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Collections\Specialized\NameValueCollection.cs" />
<Compile Include="Http\Client\IClientHttpRequest.cs" />
<Compile Include="Http\Client\IClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\IClientHttpResponse.cs" />
<Compile Include="Http\Client\ExecuteCompletedEventArgs.cs" />
<Compile Include="Http\Client\WebClientHttpRequest.cs" />
<Compile Include="Http\Client\WebClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\WebClientHttpResponse.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\AbstractHttpMessageConverter.cs" />
<Compile Include="Http\Converters\ByteArrayHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\AbstractFeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\Atom10FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\Rss20FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\FileInfoHttpMessageConverter.cs" />
<Compile Include="Http\Converters\FormHttpMessageConverter.cs" />
<Compile Include="Http\Converters\HttpMessageConversionException.cs" />
<Compile Include="Http\Converters\HttpMessageNotReadableException.cs" />
<Compile Include="Http\Converters\HttpMessageNotWritableException.cs" />
<Compile Include="Http\Converters\IHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Json\JsonHttpMessageConverter.cs" />
<Compile Include="Http\Converters\StringHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\AbstractXmlHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\DataContractHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XElementHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlDocumentHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlSerializableHttpMessageConverter.cs" />
<Compile Include="Http\HttpEntity.cs" />
<Compile Include="Http\HttpEntity`1.cs" />
<Compile Include="Http\HttpHeaders.cs" />
<Compile Include="Http\HttpMethod.cs" />
<Compile Include="Http\HttpResponseMessage.cs" />
<Compile Include="Http\HttpResponseMessage`1.cs" />
<Compile Include="Http\IHttpInputMessage.cs" />
<Compile Include="Http\IHttpOutputMessage.cs" />
<Compile Include="Http\MediaType.cs" />
<Compile Include="Http\Rest\MethodCompletedEventArgs.cs" />
<Compile Include="Http\Rest\HttpClientErrorException.cs" />
<Compile Include="Http\Rest\HttpServerErrorException.cs" />
<Compile Include="Http\Rest\HttpStatusCodeException.cs" />
<Compile Include="Http\Rest\IRequestCallback.cs" />
<Compile Include="Http\Rest\IResponseErrorHandler.cs" />
<Compile Include="Http\Rest\IResponseExtractor.cs" />
<Compile Include="Http\Rest\IRestAsyncOperations.cs" />
<Compile Include="Http\Rest\IRestOperations.cs" />
<Compile Include="Http\Rest\RestClientException.cs" />
<Compile Include="Http\Rest\RestTemplate.cs" />
<Compile Include="Http\Rest\Support\AcceptHeaderRequestCallback.cs" />
<Compile Include="Http\Rest\Support\DefaultResponseErrorHandler.cs" />
<Compile Include="Http\Rest\Support\HeadersResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\HttpEntityRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor`1.cs" />
<Compile Include="Http\Rest\Support\MessageConverterResponseExtractor.cs" />
<Compile Include="Util\AssertUtils.cs" />
<Compile Include="Util\IoUtils.cs" />
<Compile Include="Util\StringUtils.cs" />
<Compile Include="Util\UriTemplate.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\v3.0\Microsoft.Silverlight.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
<SilverlightProjectProperties />
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>

View File

@@ -81,6 +81,7 @@
<Name>System</Name>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Runtime.Serialization">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
@@ -99,7 +100,25 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Http\Converters\UrlEncodedFormHttpMessageConverter.cs" />
<Compile Include="Collections\Specialized\NameValueCollection.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Client\ExecuteCompletedEventArgs.cs" />
<Compile Include="Http\Client\IClientHttpRequest.cs" />
<Compile Include="Http\Client\IClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\IClientHttpResponse.cs" />
<Compile Include="Http\Client\WebClientHttpRequest.cs" />
<Compile Include="Http\Client\WebClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\WebClientHttpResponse.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\FileInfoHttpMessageConverter.cs" />
<Compile Include="Http\Converters\FormHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\HttpMessageNotReadableException.cs" />
<Compile Include="Http\Converters\HttpMessageNotWritableException.cs" />
<Compile Include="Http\Converters\HttpMessageConversionException.cs" />
<Compile Include="Http\Converters\Feed\Atom10FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\AbstractFeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\Rss20FeedHttpMessageConverter.cs" />
@@ -109,15 +128,25 @@
<Compile Include="Http\Converters\Xml\XmlDocumentHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlSerializableHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\DataContractHttpMessageConverter.cs" />
<Compile Include="Http\DefaultHttpWebRequestFactory.cs" />
<Compile Include="Http\IHttpInputMessage.cs" />
<Compile Include="Http\HttpEntity.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\HttpEntity`1.cs" />
<Compile Include="Http\HttpHeaders.cs" />
<Compile Include="Http\HttpResponseMessage.cs" />
<Compile Include="Http\HttpResponseMessage`1.cs" />
<Compile Include="Http\IHttpWebRequestFactory.cs" />
<Compile Include="Http\HttpRequestMessage.cs" />
<Compile Include="Http\IHttpOutputMessage.cs" />
<Compile Include="Http\Rest\HttpClientErrorException.cs" />
<Compile Include="Http\Rest\HttpServerErrorException.cs" />
<Compile Include="Http\Rest\HttpStatusCodeException.cs" />
<Compile Include="Http\Rest\IResponseErrorHandler.cs" />
<Compile Include="Http\Rest\IRestAsyncOperations.cs" />
<Compile Include="Http\Rest\MethodCompletedEventArgs.cs" />
<Compile Include="Http\Rest\Support\AcceptHeaderRequestCallback.cs" />
<Compile Include="Http\Rest\Support\DefaultResponseErrorHandler.cs" />
<Compile Include="Http\Rest\Support\HttpEntityRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor`1.cs" />
<Compile Include="Http\Rest\Support\MethodRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HttpMessageRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HeadersResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor.cs" />
<Compile Include="Http\Converters\AbstractHttpMessageConverter.cs" />
@@ -133,6 +162,7 @@
<Compile Include="Http\Rest\RestTemplate.cs" />
<Compile Include="Http\Converters\StringHttpMessageConverter.cs" />
<Compile Include="Util\AssertUtils.cs" />
<Compile Include="Util\IoUtils.cs" />
<Compile Include="Util\StringUtils.cs" />
<Compile Include="Util\UriTemplate.cs" />
</ItemGroup>

View File

@@ -0,0 +1,139 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{01FA5AEB-20A3-42FF-B2E9-A2FE9A7236D1}</ProjectGuid>
<ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Spring</RootNamespace>
<AssemblyName>Spring.Http</AssemblyName>
<TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
<SilverlightApplication>false</SilverlightApplication>
<ValidateXaml>true</ValidateXaml>
<ThrowErrorsInValidation>true</ThrowErrorsInValidation>
</PropertyGroup>
<!-- This property group is only here to support building this project using the
MSBuild 3.5 toolset. In order to work correctly with this older toolset, it needs
to set the TargetFrameworkVersion to v3.5 -->
<PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\build\VS.Net.2010-SL\Spring.Http\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;SILVERLIGHT</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>Spring.Http.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\..\build\VS.Net.2010-SL\Spring.Http\Release\</OutputPath>
<DefineConstants>TRACE;SILVERLIGHT</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="system" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceModel.Web" />
<Reference Include="System.Windows" />
<Reference Include="System.Windows.Browser" />
<Reference Include="System.Xml" />
<Reference Include="System.Net" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\CommonAssemblyInfo.cs">
<Link>CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Collections\Specialized\NameValueCollection.cs" />
<Compile Include="Http\Client\ExecuteCompletedEventArgs.cs" />
<Compile Include="Http\Client\IClientHttpRequest.cs" />
<Compile Include="Http\Client\IClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\IClientHttpResponse.cs" />
<Compile Include="Http\Client\WebClientHttpRequest.cs" />
<Compile Include="Http\Client\WebClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\WebClientHttpResponse.cs" />
<Compile Include="Http\Converters\AbstractHttpMessageConverter.cs" />
<Compile Include="Http\Converters\ByteArrayHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\AbstractFeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\Atom10FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\Rss20FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\FileInfoHttpMessageConverter.cs" />
<Compile Include="Http\Converters\FormHttpMessageConverter.cs" />
<Compile Include="Http\Converters\HttpMessageConversionException.cs" />
<Compile Include="Http\Converters\HttpMessageNotReadableException.cs" />
<Compile Include="Http\Converters\HttpMessageNotWritableException.cs" />
<Compile Include="Http\Converters\IHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Json\JsonHttpMessageConverter.cs" />
<Compile Include="Http\Converters\StringHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\AbstractXmlHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\DataContractHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XElementHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlDocumentHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlSerializableHttpMessageConverter.cs" />
<Compile Include="Http\HttpEntity.cs" />
<Compile Include="Http\HttpEntity`1.cs" />
<Compile Include="Http\HttpHeaders.cs" />
<Compile Include="Http\HttpMethod.cs" />
<Compile Include="Http\HttpResponseMessage.cs" />
<Compile Include="Http\HttpResponseMessage`1.cs" />
<Compile Include="Http\IHttpInputMessage.cs" />
<Compile Include="Http\IHttpOutputMessage.cs" />
<Compile Include="Http\MediaType.cs" />
<Compile Include="Http\Rest\HttpClientErrorException.cs" />
<Compile Include="Http\Rest\HttpServerErrorException.cs" />
<Compile Include="Http\Rest\HttpStatusCodeException.cs" />
<Compile Include="Http\Rest\IRequestCallback.cs" />
<Compile Include="Http\Rest\IResponseErrorHandler.cs" />
<Compile Include="Http\Rest\IResponseExtractor.cs" />
<Compile Include="Http\Rest\IRestAsyncOperations.cs" />
<Compile Include="Http\Rest\IRestOperations.cs" />
<Compile Include="Http\Rest\MethodCompletedEventArgs.cs" />
<Compile Include="Http\Rest\RestClientException.cs" />
<Compile Include="Http\Rest\RestTemplate.cs" />
<Compile Include="Http\Rest\Support\AcceptHeaderRequestCallback.cs" />
<Compile Include="Http\Rest\Support\DefaultResponseErrorHandler.cs" />
<Compile Include="Http\Rest\Support\HeadersResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\HttpEntityRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor`1.cs" />
<Compile Include="Http\Rest\Support\MessageConverterResponseExtractor.cs" />
<Compile Include="Util\AssertUtils.cs" />
<Compile Include="Util\IoUtils.cs" />
<Compile Include="Util\StringUtils.cs" />
<Compile Include="Util\UriTemplate.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
<SilverlightProjectProperties />
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.20506</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{36227431-B822-461E-A7AF-651E34F23A8C}</ProjectGuid>
<ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Spring</RootNamespace>
<AssemblyName>Spring.Http</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
<TargetFrameworkProfile>WindowsPhone</TargetFrameworkProfile>
<TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
<SilverlightApplication>false</SilverlightApplication>
<ValidateXaml>true</ValidateXaml>
<ThrowErrorsInValidation>true</ThrowErrorsInValidation>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\build\VS.Net.2010-WP\Spring.Http\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>Spring.Http.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\..\build\VS.Net.2010-WP\Spring.Http\Release\</OutputPath>
<DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Servicemodel" />
<Reference Include="System.Servicemodel.Web" />
<Reference Include="System.Windows" />
<Reference Include="system" />
<Reference Include="System.Core" />
<Reference Include="System.Xml" />
<Reference Include="System.Net" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml.Serialization" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\CommonAssemblyInfo.cs">
<Link>CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Collections\Specialized\NameValueCollection.cs" />
<Compile Include="Http\Client\ExecuteCompletedEventArgs.cs" />
<Compile Include="Http\Client\IClientHttpRequest.cs" />
<Compile Include="Http\Client\IClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\IClientHttpResponse.cs" />
<Compile Include="Http\Client\WebClientHttpRequest.cs" />
<Compile Include="Http\Client\WebClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\WebClientHttpResponse.cs" />
<Compile Include="Http\Converters\AbstractHttpMessageConverter.cs" />
<Compile Include="Http\Converters\ByteArrayHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\AbstractFeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\Atom10FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\Rss20FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\FileInfoHttpMessageConverter.cs" />
<Compile Include="Http\Converters\FormHttpMessageConverter.cs" />
<Compile Include="Http\Converters\HttpMessageConversionException.cs" />
<Compile Include="Http\Converters\HttpMessageNotReadableException.cs" />
<Compile Include="Http\Converters\HttpMessageNotWritableException.cs" />
<Compile Include="Http\Converters\IHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Json\JsonHttpMessageConverter.cs" />
<Compile Include="Http\Converters\StringHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\AbstractXmlHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\DataContractHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XElementHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlDocumentHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlSerializableHttpMessageConverter.cs" />
<Compile Include="Http\HttpEntity.cs" />
<Compile Include="Http\HttpEntity`1.cs" />
<Compile Include="Http\HttpHeaders.cs" />
<Compile Include="Http\HttpMethod.cs" />
<Compile Include="Http\HttpResponseMessage.cs" />
<Compile Include="Http\HttpResponseMessage`1.cs" />
<Compile Include="Http\IHttpInputMessage.cs" />
<Compile Include="Http\IHttpOutputMessage.cs" />
<Compile Include="Http\MediaType.cs" />
<Compile Include="Http\Rest\HttpClientErrorException.cs" />
<Compile Include="Http\Rest\HttpServerErrorException.cs" />
<Compile Include="Http\Rest\HttpStatusCodeException.cs" />
<Compile Include="Http\Rest\IRequestCallback.cs" />
<Compile Include="Http\Rest\IResponseErrorHandler.cs" />
<Compile Include="Http\Rest\IResponseExtractor.cs" />
<Compile Include="Http\Rest\IRestAsyncOperations.cs" />
<Compile Include="Http\Rest\IRestOperations.cs" />
<Compile Include="Http\Rest\MethodCompletedEventArgs.cs" />
<Compile Include="Http\Rest\RestClientException.cs" />
<Compile Include="Http\Rest\RestTemplate.cs" />
<Compile Include="Http\Rest\Support\AcceptHeaderRequestCallback.cs" />
<Compile Include="Http\Rest\Support\DefaultResponseErrorHandler.cs" />
<Compile Include="Http\Rest\Support\HeadersResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\HttpEntityRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor`1.cs" />
<Compile Include="Http\Rest\Support\MessageConverterResponseExtractor.cs" />
<Compile Include="Util\AssertUtils.cs" />
<Compile Include="Util\IoUtils.cs" />
<Compile Include="Util\StringUtils.cs" />
<Compile Include="Util\UriTemplate.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />
<ProjectExtensions />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -113,48 +113,97 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Http\Converters\Feed\Rss20FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\UrlEncodedFormHttpMessageConverter.cs" />
<Compile Include="Http\HttpResponseMessage.cs" />
<Compile Include="Http\HttpResponseMessage`1.cs" />
<Compile Include="Http\DefaultHttpWebRequestFactory.cs" />
<Compile Include="Collections\Specialized\NameValueCollection.cs" />
<Compile Include="Http\Client\ExecuteCompletedEventArgs.cs" />
<Compile Include="Http\Client\IClientHttpRequest.cs" />
<Compile Include="Http\Client\IClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\IClientHttpResponse.cs" />
<Compile Include="Http\Client\WebClientHttpRequest.cs" />
<Compile Include="Http\Client\WebClientHttpRequestFactory.cs" />
<Compile Include="Http\Client\WebClientHttpResponse.cs" />
<Compile Include="Http\Converters\AbstractHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\ByteArrayHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\Feed\AbstractFeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\Atom10FeedHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Feed\AbstractFeedHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\Feed\Atom10FeedHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\Feed\Rss20FeedHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\FileInfoHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\FormHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\HttpMessageConversionException.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\HttpMessageNotReadableException.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\HttpMessageNotWritableException.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\IHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\Json\JsonHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Json\JsonHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\StringHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\Xml\AbstractXmlHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\DataContractHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XElementHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlDocumentHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\XmlSerializableHttpMessageConverter.cs" />
<Compile Include="Http\Converters\Xml\AbstractXmlHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\Xml\DataContractHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\Xml\XElementHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\Xml\XmlDocumentHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\Converters\Xml\XmlSerializableHttpMessageConverter.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Http\IHttpInputMessage.cs" />
<Compile Include="Http\IHttpOutputMessage.cs" />
<Compile Include="Http\HttpEntity.cs" />
<Compile Include="Http\HttpEntity`1.cs" />
<Compile Include="Http\HttpHeaders.cs" />
<Compile Include="Http\HttpResponseMessage.cs" />
<Compile Include="Http\HttpResponseMessage`1.cs" />
<Compile Include="Http\HttpMethod.cs" />
<Compile Include="Http\HttpRequestMessage.cs" />
<Compile Include="Http\IHttpWebRequestFactory.cs" />
<Compile Include="Http\MediaType.cs" />
<Compile Include="Http\Rest\HttpClientErrorException.cs" />
<Compile Include="Http\Rest\HttpServerErrorException.cs" />
<Compile Include="Http\Rest\HttpStatusCodeException.cs" />
<Compile Include="Http\Rest\IRequestCallback.cs" />
<Compile Include="Http\Rest\IResponseErrorHandler.cs" />
<Compile Include="Http\Rest\IResponseExtractor.cs" />
<Compile Include="Http\Rest\IRestAsyncOperations.cs" />
<Compile Include="Http\Rest\IRestOperations.cs" />
<Compile Include="Http\Rest\MethodCompletedEventArgs.cs" />
<Compile Include="Http\Rest\RestClientException.cs" />
<Compile Include="Http\Rest\RestTemplate.cs" />
<Compile Include="Http\Rest\Support\AcceptHeaderRequestCallback.cs" />
<Compile Include="Http\Rest\Support\DefaultResponseErrorHandler.cs" />
<Compile Include="Http\Rest\Support\HttpEntityRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor`1.cs" />
<Compile Include="Http\Rest\Support\HeadersResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\HttpMessageRequestCallback.cs" />
<Compile Include="Http\Rest\Support\HttpMessageResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\MessageConverterResponseExtractor.cs" />
<Compile Include="Http\Rest\Support\MethodRequestCallback.cs" />
<Compile Include="Util\AssertUtils.cs" />
<Compile Include="Util\IoUtils.cs" />
<Compile Include="Util\StringUtils.cs">
<SubType>Code</SubType>
</Compile>
@@ -177,6 +226,7 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,49 @@
#region License
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.IO;
namespace Spring.Util
{
/// <summary>
/// Utility methods for IO handling.
/// </summary>
/// <author>Bruno Baia</author>
internal sealed class IoUtils
{
/// <summary>
/// Copies one stream into another.
/// </summary>
public static void CopyStream(Stream source, Stream destination)
{
#if NET_4_0
source.CopyTo(destination);
#else
int bytesCount;
byte[] buffer = new byte[0x1000];
while ((bytesCount = source.Read(buffer, 0, buffer.Length)) != 0)
{
destination.Write(buffer, 0, bytesCount);
}
#endif
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,9 +25,6 @@ using System.Collections.Generic;
namespace Spring.Util
{
// TODO : Check .NET 3.5 class
// TODO : Back to original Java behavior Expand(params string[]) method ?
/// <summary>
/// Represents a URI template. An URI template is a URI-like String that contained variables
/// marked of in braces {}, which can be expanded to produce a URI.
@@ -38,8 +35,11 @@ namespace Spring.Util
public class UriTemplate
{
/** Captures URI template variable names. */
#if SILVERLIGHT
private static Regex VARIABLENAMES_REGEX = new Regex(@"\{([^/]+?)\}");
#else
private static Regex VARIABLENAMES_REGEX = new Regex(@"\{([^/]+?)\}", RegexOptions.Compiled);
//private static Regex VARIABLENAMES_REGEX = new Regex(@"\{[^{}]+\}", RegexOptions.Compiled);
#endif
/** Replaces template variables in the URI template. */
private static string VARIABLEVALUE_PATTERN = "(?<{0}>.*)";
@@ -110,20 +110,6 @@ namespace Spring.Util
}
return new Uri(uri, UriKind.RelativeOrAbsolute);
//string[] uriVariableValues = new String[this.variableNames.Length];
//for (int i = 0; i < this.variableNames.Length; i++)
//{
// string variableName = this.variableNames[i];
// if (!uriVariables.ContainsKey(variableName))
// {
// throw new ArgumentException(String.Format(
// "'uriVariables' dictionary has no value for '{0}'",
// variableName));
// }
// uriVariableValues[i] = uriVariables[variableName];
//}
//return Expand(uriVariableValues);
}
/// <summary>
@@ -208,33 +194,14 @@ namespace Spring.Util
return this.uriTemplate;
}
//private static string[] GetVariableNames(string uriTemplate)
//{
// List<string> variableNames = new List<string>();
// foreach (Match match in VARIABLENAMES_REGEX.Matches(uriTemplate))
// {
// string token = match.Value;
// token = token.Substring(1, token.Length - 2);
// if (!variableNames.Contains(token))
// {
// variableNames.Add(token);
// }
// }
// return variableNames.ToArray();
//}
private static string Replace(string uriTemplate, string token, string value)
{
string quotedToken = BRACE_LEFT + token + BRACE_RIGHT;
return uriTemplate.Replace(quotedToken, value);
}
/**
* Static inner class to parse uri template strings into a matching regular expression.
*/
private class Parser
}
// Static inner class to parse uri template strings into a matching regular expression.
private class Parser
{
private List<String> variableNames = new List<String>();
private StringBuilder patternBuilder = new StringBuilder();
@@ -277,7 +244,7 @@ namespace Spring.Util
public Regex GetMatchRegex()
{
return new Regex(this.patternBuilder.ToString(), RegexOptions.Compiled);
return new Regex(this.patternBuilder.ToString());
}
}
}