Skip to content

Commit a0f67ed

Browse files
committed
Reimplemented copy/move as http method-agnostic
Can now execute arbitrary HTTP methods (such as "copy" or "move") using get- or post-style request semantics. Added sync and async support for both. Refactored a bit of RestClient.Sync and RestClient.Async to facilitate this.
1 parent 88543d8 commit a0f67ed

File tree

9 files changed

+263
-211
lines changed

9 files changed

+263
-211
lines changed

RestSharp/Enum.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ public enum Method
4848
DELETE,
4949
HEAD,
5050
OPTIONS,
51-
PATCH,
52-
COPY,
53-
MOVE,
51+
PATCH
5452
}
5553

5654
/// <summary>

RestSharp/Http.Async.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,25 @@ public HttpWebRequest PatchAsync(Action<HttpResponse> action)
7777
return PutPostInternalAsync("PATCH", action);
7878
}
7979

80-
public HttpWebRequest CopyAsync(Action<HttpResponse> action)
81-
{
82-
return PutPostInternalAsync("COPY", action);
83-
}
80+
/// <summary>
81+
/// Execute an async POST-style request with the specified HTTP Method.
82+
/// </summary>
83+
/// <param name="httpMethod">The HTTP method to execute.</param>
84+
/// <returns></returns>
85+
public HttpWebRequest AsPostAsync(Action<HttpResponse> action, string httpMethod)
86+
{
87+
return PutPostInternalAsync(httpMethod.ToUpperInvariant(), action);
88+
}
8489

85-
public HttpWebRequest MoveAsync(Action<HttpResponse> action)
90+
/// <summary>
91+
/// Execute an async GET-style request with the specified HTTP Method.
92+
/// </summary>
93+
/// <param name="httpMethod">The HTTP method to execute.</param>
94+
/// <returns></returns>
95+
public HttpWebRequest AsGetAsync(Action<HttpResponse> action, string httpMethod)
8696
{
87-
return PutPostInternalAsync("MOVE", action);
88-
}
97+
return GetStyleMethodInternalAsync(httpMethod.ToUpperInvariant(), action);
98+
}
8999

90100
private HttpWebRequest GetStyleMethodInternalAsync(string method, Action<HttpResponse> callback)
91101
{

RestSharp/Http.Sync.cs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,31 +79,35 @@ public HttpResponse Delete()
7979
return GetStyleMethodInternal("DELETE");
8080
}
8181

82+
/// <summary>
83+
/// Execute a PATCH request
84+
/// </summary>
85+
public HttpResponse Patch()
86+
{
87+
return PostPutInternal("PATCH");
88+
}
89+
8290
/// <summary>
83-
/// Execute a COPY request
91+
/// Execute a GET-style request with the specified HTTP Method.
8492
/// </summary>
85-
public HttpResponse Copy()
86-
{
87-
return PostPutInternal("COPY");
93+
/// <param name="httpMethod">The HTTP method to execute.</param>
94+
/// <returns></returns>
95+
public HttpResponse AsGet(string httpMethod)
96+
{
97+
return GetStyleMethodInternal(httpMethod.ToUpperInvariant());
8898
}
8999

90100
/// <summary>
91-
/// Execute a MOVE request
101+
/// Execute a POST-style request with the specified HTTP Method.
92102
/// </summary>
93-
public HttpResponse Move()
103+
/// <param name="httpMethod">The HTTP method to execute.</param>
104+
/// <returns></returns>
105+
public HttpResponse AsPost(string httpMethod)
94106
{
95-
return PostPutInternal("MOVE");
107+
return PostPutInternal(httpMethod.ToUpperInvariant());
96108
}
97109

98-
/// <summary>
99-
/// Execute a PATCH request
100-
/// </summary>
101-
public HttpResponse Patch()
102-
{
103-
return PostPutInternal("PATCH");
104-
}
105-
106-
private HttpResponse GetStyleMethodInternal(string method)
110+
private HttpResponse GetStyleMethodInternal(string method)
107111
{
108112
var webRequest = ConfigureWebRequest(method, Url);
109113

RestSharp/IHttp.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ public interface IHttp
5252
HttpWebRequest PostAsync(Action<HttpResponse> action);
5353
HttpWebRequest PutAsync(Action<HttpResponse> action);
5454
HttpWebRequest PatchAsync(Action<HttpResponse> action);
55-
HttpWebRequest CopyAsync(Action<HttpResponse> action);
56-
HttpWebRequest MoveAsync(Action<HttpResponse> action);
55+
HttpWebRequest AsPostAsync(Action<HttpResponse> action, string httpMethod);
56+
HttpWebRequest AsGetAsync(Action<HttpResponse> action, string httpMethod);
5757

5858
#if FRAMEWORK
5959
HttpResponse Delete();
@@ -63,8 +63,8 @@ public interface IHttp
6363
HttpResponse Post();
6464
HttpResponse Put();
6565
HttpResponse Patch();
66-
HttpResponse Copy();
67-
HttpResponse Move();
66+
HttpResponse AsPost(string httpMethod);
67+
HttpResponse AsGet(string httpMethod);
6868

6969
IWebProxy Proxy { get; set; }
7070
#endif

RestSharp/IRestClient.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,44 @@ public interface IRestClient
7777
#endif
7878

7979
Uri BuildUri(IRestRequest request);
80+
81+
/// <summary>
82+
/// Executes a GET-style request and callback asynchronously, authenticating if needed
83+
/// </summary>
84+
/// <param name="request">Request to be executed</param>
85+
/// <param name="callback">Callback function to be executed upon completion providing access to the async handle.</param>
86+
/// <param name="httpMethod">The HTTP method to execute</param>
87+
RestRequestAsyncHandle ExecuteAsyncGet(IRestRequest request, Action<IRestResponse, RestRequestAsyncHandle> callback, string httpMethod);
88+
89+
/// <summary>
90+
/// Executes a POST-style request and callback asynchronously, authenticating if needed
91+
/// </summary>
92+
/// <param name="request">Request to be executed</param>
93+
/// <param name="callback">Callback function to be executed upon completion providing access to the async handle.</param>
94+
/// <param name="httpMethod">The HTTP method to execute</param>
95+
RestRequestAsyncHandle ExecuteAsyncPost(IRestRequest request, Action<IRestResponse, RestRequestAsyncHandle> callback, string httpMethod);
96+
97+
/// <summary>
98+
/// Executes a GET-style request and callback asynchronously, authenticating if needed
99+
/// </summary>
100+
/// <typeparam name="T">Target deserialization type</typeparam>
101+
/// <param name="request">Request to be executed</param>
102+
/// <param name="callback">Callback function to be executed upon completion</param>
103+
/// <param name="httpMethod">The HTTP method to execute</param>
104+
RestRequestAsyncHandle ExecuteAsyncGet<T>(IRestRequest request, Action<IRestResponse<T>, RestRequestAsyncHandle> callback, string httpMethod);
105+
106+
/// <summary>
107+
/// Executes a GET-style request and callback asynchronously, authenticating if needed
108+
/// </summary>
109+
/// <typeparam name="T">Target deserialization type</typeparam>
110+
/// <param name="request">Request to be executed</param>
111+
/// <param name="callback">Callback function to be executed upon completion</param>
112+
/// <param name="httpMethod">The HTTP method to execute</param>
113+
RestRequestAsyncHandle ExecuteAsyncPost<T>(IRestRequest request, Action<IRestResponse<T>, RestRequestAsyncHandle> callback, string httpMethod);
114+
115+
IRestResponse ExecuteAsGet(IRestRequest request, string httpMethod);
116+
IRestResponse ExecuteAsPost(IRestRequest request, string httpMethod);
117+
IRestResponse<T> ExecuteAsGet<T>(IRestRequest request, string httpMethod) where T : new();
118+
IRestResponse<T> ExecuteAsPost<T>(IRestRequest request, string httpMethod) where T : new();
80119
}
81120
}

RestSharp/RestClient.Async.cs

Lines changed: 108 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -32,63 +32,81 @@ public partial class RestClient
3232
/// <param name="callback">Callback function to be executed upon completion providing access to the async handle.</param>
3333
public virtual RestRequestAsyncHandle ExecuteAsync(IRestRequest request, Action<IRestResponse, RestRequestAsyncHandle> callback)
3434
{
35-
var http = HttpFactory.Create();
36-
AuthenticateIfNeeded(this, request);
37-
38-
// add Accept header based on registered deserializers
39-
var accepts = string.Join(", ", AcceptTypes.ToArray());
40-
AddDefaultParameter("Accept", accepts, ParameterType.HttpHeader);
41-
42-
ConfigureHttp(request, http);
43-
44-
HttpWebRequest webRequest = null;
45-
var asyncHandle = new RestRequestAsyncHandle();
46-
47-
Action<HttpResponse> response_cb = r => ProcessResponse(request, r, asyncHandle, callback);
48-
49-
if (UseSynchronizationContext && SynchronizationContext.Current != null) {
50-
var ctx = SynchronizationContext.Current;
51-
var cb = response_cb;
52-
53-
response_cb = resp => ctx.Post(s => cb(resp), null);
54-
}
55-
56-
switch(request.Method)
57-
{
58-
case Method.GET:
59-
webRequest = http.GetAsync(response_cb);
60-
break;
61-
case Method.POST:
62-
webRequest = http.PostAsync(response_cb);
63-
break;
64-
case Method.PUT:
65-
webRequest = http.PutAsync(response_cb);
66-
break;
67-
case Method.DELETE:
68-
webRequest = http.DeleteAsync(response_cb);
69-
break;
70-
case Method.HEAD:
71-
webRequest = http.HeadAsync(response_cb);
72-
break;
73-
case Method.OPTIONS:
74-
webRequest = http.OptionsAsync(response_cb);
75-
break;
76-
case Method.PATCH:
77-
webRequest = http.PatchAsync(response_cb);
78-
break;
79-
case Method.COPY:
80-
webRequest = http.CopyAsync(response_cb);
81-
break;
82-
case Method.MOVE:
83-
webRequest = http.MoveAsync(response_cb);
84-
break;
35+
string method = Enum.GetName(typeof (Method), request.Method);
36+
switch (request.Method)
37+
{
38+
case Method.PATCH:
39+
case Method.POST:
40+
case Method.PUT:
41+
return ExecuteAsync(request, callback, method, DoAsGetAsync);
42+
43+
default:
44+
return ExecuteAsync(request, callback, method, DoAsPostAsync);
8545
}
86-
87-
asyncHandle.WebRequest = webRequest;
88-
return asyncHandle;
8946
}
9047

91-
private void ProcessResponse(IRestRequest request, HttpResponse httpResponse, RestRequestAsyncHandle asyncHandle, Action<IRestResponse, RestRequestAsyncHandle> callback)
48+
/// <summary>
49+
/// Executes a GET-style request and callback asynchronously, authenticating if needed
50+
/// </summary>
51+
/// <param name="request">Request to be executed</param>
52+
/// <param name="callback">Callback function to be executed upon completion providing access to the async handle.</param>
53+
/// <param name="httpMethod">The HTTP method to execute</param>
54+
public virtual RestRequestAsyncHandle ExecuteAsyncGet(IRestRequest request, Action<IRestResponse, RestRequestAsyncHandle> callback, string httpMethod)
55+
{
56+
return ExecuteAsync(request, callback, httpMethod, DoAsPostAsync);
57+
}
58+
59+
/// <summary>
60+
/// Executes a POST-style request and callback asynchronously, authenticating if needed
61+
/// </summary>
62+
/// <param name="request">Request to be executed</param>
63+
/// <param name="callback">Callback function to be executed upon completion providing access to the async handle.</param>
64+
/// <param name="httpMethod">The HTTP method to execute</param>
65+
public virtual RestRequestAsyncHandle ExecuteAsyncPost(IRestRequest request, Action<IRestResponse, RestRequestAsyncHandle> callback, string httpMethod)
66+
{
67+
request.Method = Method.POST; // Required by RestClient.BuildUri...
68+
return ExecuteAsync(request, callback, httpMethod, DoAsGetAsync);
69+
}
70+
71+
private RestRequestAsyncHandle ExecuteAsync(IRestRequest request, Action<IRestResponse, RestRequestAsyncHandle> callback, string httpMethod, Func<IHttp, Action<HttpResponse>, string, HttpWebRequest> getWebRequest)
72+
{
73+
var http = HttpFactory.Create();
74+
AuthenticateIfNeeded(this, request);
75+
76+
// add Accept header based on registered deserializers
77+
var accepts = string.Join(", ", AcceptTypes.ToArray());
78+
AddDefaultParameter("Accept", accepts, ParameterType.HttpHeader);
79+
80+
ConfigureHttp(request, http);
81+
82+
var asyncHandle = new RestRequestAsyncHandle();
83+
84+
Action<HttpResponse> response_cb = r => ProcessResponse(request, r, asyncHandle, callback);
85+
86+
if (UseSynchronizationContext && SynchronizationContext.Current != null)
87+
{
88+
var ctx = SynchronizationContext.Current;
89+
var cb = response_cb;
90+
91+
response_cb = resp => ctx.Post(s => cb(resp), null);
92+
}
93+
94+
asyncHandle.WebRequest = getWebRequest(http, response_cb, httpMethod);
95+
return asyncHandle;
96+
}
97+
98+
private static HttpWebRequest DoAsGetAsync(IHttp http, Action<HttpResponse> response_cb, string method)
99+
{
100+
return http.AsGetAsync(response_cb, method);
101+
}
102+
103+
private static HttpWebRequest DoAsPostAsync(IHttp http, Action<HttpResponse> response_cb, string method)
104+
{
105+
return http.AsPostAsync(response_cb, method);
106+
}
107+
108+
109+
private void ProcessResponse(IRestRequest request, HttpResponse httpResponse, RestRequestAsyncHandle asyncHandle, Action<IRestResponse, RestRequestAsyncHandle> callback)
92110
{
93111
var restResponse = ConvertToRestResponse(request, httpResponse);
94112
callback(restResponse, asyncHandle);
@@ -102,16 +120,42 @@ private void ProcessResponse(IRestRequest request, HttpResponse httpResponse, Re
102120
/// <param name="callback">Callback function to be executed upon completion</param>
103121
public virtual RestRequestAsyncHandle ExecuteAsync<T>(IRestRequest request, Action<IRestResponse<T>, RestRequestAsyncHandle> callback)
104122
{
105-
return ExecuteAsync(request, (response, asyncHandle) =>
106-
{
107-
IRestResponse<T> restResponse = response as RestResponse<T>;
108-
if (response.ResponseStatus != ResponseStatus.Aborted)
109-
{
110-
restResponse = Deserialize<T>(request, response);
111-
}
112-
113-
callback(restResponse, asyncHandle);
114-
});
123+
return ExecuteAsync(request, (response, asyncHandle) => DeserializeResponse(request, callback, response, asyncHandle));
115124
}
125+
126+
/// <summary>
127+
/// Executes a GET-style request and callback asynchronously, authenticating if needed
128+
/// </summary>
129+
/// <typeparam name="T">Target deserialization type</typeparam>
130+
/// <param name="request">Request to be executed</param>
131+
/// <param name="callback">Callback function to be executed upon completion</param>
132+
/// <param name="httpMethod">The HTTP method to execute</param>
133+
public virtual RestRequestAsyncHandle ExecuteAsyncGet<T>(IRestRequest request, Action<IRestResponse<T>, RestRequestAsyncHandle> callback, string httpMethod)
134+
{
135+
return ExecuteAsyncGet(request, (response, asyncHandle) => DeserializeResponse(request, callback, response, asyncHandle), httpMethod);
136+
}
137+
138+
/// <summary>
139+
/// Executes a POST-style request and callback asynchronously, authenticating if needed
140+
/// </summary>
141+
/// <typeparam name="T">Target deserialization type</typeparam>
142+
/// <param name="request">Request to be executed</param>
143+
/// <param name="callback">Callback function to be executed upon completion</param>
144+
/// <param name="httpMethod">The HTTP method to execute</param>
145+
public virtual RestRequestAsyncHandle ExecuteAsyncPost<T>(IRestRequest request, Action<IRestResponse<T>, RestRequestAsyncHandle> callback, string httpMethod)
146+
{
147+
return ExecuteAsyncPost(request, (response, asyncHandle) => DeserializeResponse(request, callback, response, asyncHandle), httpMethod);
148+
}
149+
150+
private void DeserializeResponse<T>(IRestRequest request, Action<IRestResponse<T>, RestRequestAsyncHandle> callback, IRestResponse response, RestRequestAsyncHandle asyncHandle)
151+
{
152+
IRestResponse<T> restResponse = response as RestResponse<T>;
153+
if (response.ResponseStatus != ResponseStatus.Aborted)
154+
{
155+
restResponse = Deserialize<T>(request, response);
156+
}
157+
158+
callback(restResponse, asyncHandle);
159+
}
116160
}
117161
}

0 commit comments

Comments
 (0)