Skip to content

Instantly share code, notes, and snippets.

@prabirshrestha
Created September 13, 2012 02:41
Show Gist options
  • Save prabirshrestha/3711497 to your computer and use it in GitHub Desktop.
Save prabirshrestha/3711497 to your computer and use it in GitHub Desktop.
namespace Api
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
public class SampleApi
{
private const string UserAgent = "Api SDK";
private const int BufferSize = 1024 * 4; //4kb
[EditorBrowsable(EditorBrowsableState.Never)]
public Func<Uri, HttpWebRequestWrapper> HttpWebRequestFactory { get; set; }
#if (!SILVERLIGHT || NETFX_CORE)
public virtual object Api(string httpMethod, string path, object parameters, Type resultType)
{
Stream input;
var httpHelper = PrepareRequest(httpMethod, path, parameters, resultType, out input);
if (input != null)
{
try
{
using (var stream = httpHelper.OpenWrite())
{
var buffer = new byte[BufferSize];
int bytesRead;
while (true)
{
bytesRead = input.Read(buffer, 0, buffer.Length);
if (bytesRead <= 0)
break;
stream.Write(buffer, 0, bytesRead);
stream.Flush();
}
}
}
catch (WebExceptionWrapper ex)
{
if (ex.GetResponse() == null) throw;
}
finally
{
input.Dispose();
}
}
Stream responseStream = null;
object result = null;
bool read = false;
try
{
responseStream = httpHelper.OpenRead();
read = true;
}
catch (WebExceptionWrapper ex)
{
var response = ex.GetResponse();
if (response == null) throw;
if (response.StatusCode != HttpStatusCode.NotModified)
responseStream = httpHelper.OpenRead();
read = true;
}
finally
{
if (read)
result = ProcessResponse(httpHelper, responseStream, resultType);
}
return result;
}
#endif
public virtual IAsyncResult BeginApi(string httpMethod, string path, object parameters, Type resultType, object userState)
{
throw new NotImplementedException();
}
public virtual object EndApi(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}
//public virtual Task<object> ApiAsync(string httpMethod, string path, object parameters, Type resultType, object userState, CancellationToken cancellationToken)
//{
// Stream input;
// var httpHelper = PrepareRequest(httpMethod, path, parameters, resultType, out input);
// Task<object> task = null;
// Task writeTask;
// if (input == null)
// {
// var tcs = new TaskCompletionSource<object>();
// tcs.TrySetResult(null);
// writeTask = tcs.Task;
// }
// else
// {
// writeTask = httpHelper
// .OpenWriteTaskAsync(cancellationToken)
// .Then(writeStream =>
// {
// using (var stream = writeStream)
// {
// var buffer = new byte[BufferSize];
// int bytesRead;
// while (true)
// {
// bytesRead = input.Read(buffer, 0, buffer.Length);
// if (bytesRead <= 0)
// break;
// stream.Write(buffer, 0, bytesRead);
// stream.Flush();
// }
// }
// });
// writeTask = writeTask.Catch(
// t =>
// {
// if (t.IsFaulted)
// {
// var ex = t.Exception.GetBaseException() as WebExceptionWrapper;
// if (ex.GetResponse() != null)
// return true;
// }
// return false;
// });
// writeTask = writeTask.Finally(() => input.Dispose());
// }
// bool read = false;
// var readTask = writeTask.Then(() => httpHelper.OpenReadTaskAsync(cancellationToken))
// .Then(() => read = true);
// var catchReadTask = readTask.Catch(t =>
// {
// var tcs = new TaskCompletionSource<bool>();
// if (t.IsFaulted)
// {
// var ex = t.Exception.GetBaseException() as WebExceptionWrapper;
// var response = ex.GetResponse();
// if (response == null)
// {
// tcs.TrySetResult(false);
// return tcs.Task;
// }
// if (response.StatusCode != HttpStatusCode.NotModified)
// {
// return httpHelper.OpenReadTaskAsync(cancellationToken)
// .Then(() =>
// {
// read = true;
// return true;
// });
// }
// read = true;
// }
// tcs.TrySetResult(false);
// return tcs.Task;
// });
// catchReadTask.Finally(() => { });
// return task;
//}
public virtual Task<object> ApiAsync(string httpMethod, string path, object parameters, Type resultType, object userState, CancellationToken cancellationToken)
{
Stream input;
var httpHelper = PrepareRequest(httpMethod, path, parameters, resultType, out input);
Task task;
if (input == null)
{
var tcs = new TaskCompletionSource<object>();
tcs.SetResult(null);
task = tcs.Task;
}
else
{
throw new NotImplementedException();
}
bool read = false;
return
task
.Then(() => httpHelper.OpenReadTaskAsync(cancellationToken))
.ContinueWith(t =>
{
if (t.IsFaulted)
{
var ex = t.Exception.GetBaseException() as WebExceptionWrapper;
if (ex == null)
{
t.Wait();
}
else
{
var response = ex.GetResponse();
if (response == null) t.Wait();
if (response.StatusCode != HttpStatusCode.NotModified)
{
return httpHelper
.OpenReadTaskAsync(cancellationToken)
.Then(stream =>
{
read = true;
return CompletedTask(stream);
});
}
else
{
read = true;
return CompletedTask(t.Result);
}
}
throw new InvalidAsynchronousStateException();
}
else if (t.IsCanceled) return CancelledTask<Stream>();
else
{
read = true;
return CompletedTask(t.Result);
}
})
.Unwrap()
.ContinueWith(t =>
{
if (t.IsFaulted) t.Wait();
else if (t.IsCanceled) return CancelledTask<object>();
else if (read)
{
var tcs = new TaskCompletionSource<object>();
var result = ProcessResponse(httpHelper, t.Result, resultType);
tcs.TrySetResult(result);
return tcs.Task;
}
throw new InvalidAsynchronousStateException();
})
.Unwrap();
}
public virtual Task<object> ApiAsync(string httpMethod, string path, object parameters, Type resultType)
{
return ApiAsync(httpMethod, path, parameters, resultType, null, CancellationToken.None);
}
private static Task<T> CancelledTask<T>()
{
var tcs = new TaskCompletionSource<T>();
tcs.TrySetCanceled();
return tcs.Task;
}
private static Task<T> CompletedTask<T>(T result)
{
var tcs = new TaskCompletionSource<T>();
tcs.TrySetResult(result);
return tcs.Task;
}
[EditorBrowsable(EditorBrowsableState.Never)]
protected HttpWebRequestWrapper CreateHttpWebRequest(Uri uri)
{
if (HttpWebRequestFactory != null)
return HttpWebRequestFactory(uri);
return new HttpWebRequestWrapper((HttpWebRequest)WebRequest.Create(uri));
}
[EditorBrowsable(EditorBrowsableState.Never)]
protected object JsonDeserialize(string json, Type resultType)
{
return SimpleJson.DeserializeObject(json, resultType);
}
[EditorBrowsable(EditorBrowsableState.Never)]
protected object JsonSerialize(object json)
{
return SimpleJson.SerializeObject(json);
}
private HttpHelper PrepareRequest(string httpMethod, string path, object parameters, Type resultType, out Stream input)
{
input = null;
var uri = new Uri("https://graph.facebook.com" + AddStartingSlashIfNotPresent(path));
var request = CreateHttpWebRequest(uri);
request.AllowAutoRedirect = false;
#if !(SILVERLIGHT || NETFX_CORE)
request.AllowWriteStreamBuffering = true;
request.UserAgent = UserAgent;
#endif
return new HttpHelper(request);
}
private object ProcessResponse(HttpHelper httpHelper, Stream responseStream, Type resultType)
{
IDictionary<string, object> result = PrepareResultForResponse(httpHelper);
var response = httpHelper.HttpWebResponse;
if (response.StatusCode == HttpStatusCode.NotModified)
return result;
string responseString;
using (var stream = responseStream)
{
using (var reader = new StreamReader(stream))
{
responseString = reader.ReadToEnd();
}
}
result["body"] = JsonDeserialize(responseString, resultType);
return result;
}
[DebuggerStepThrough]
private IDictionary<string, object> PrepareResultForResponse(HttpHelper httpHelper)
{
var response = httpHelper.HttpWebResponse;
var result = new JsonObject();
result["status"] = (int)response.StatusCode;
var headers = new JsonObject();
foreach (var headerName in response.Headers.AllKeys)
headers[headerName] = response.Headers[headerName];
result["headers"] = headers;
return result;
}
/// <summary>
/// Add starting slash if not present.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static string AddStartingSlashIfNotPresent(string input)
{
if (string.IsNullOrEmpty(input))
return "/";
// if not null or empty
if (input[0] != '/')
{
// if doesn't start with / then add /
return "/" + input;
}
else
{
// else return the original input.
return input;
}
}
}
public class SampleApiAttachment
{
public string FileName { get; set; }
public string ContentType { get; set; }
private object _attachment;
public object Attachment
{
get { return _attachment; }
set
{
if (value != null)
{
if (value is Stream || value is byte[])
_attachment = value;
}
_attachment = value;
}
}
}
public class ProgressData
{
public long TotalBytes { get; set; }
public long ReadBytes { get; set; }
public double Percentage { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment