Skip to content

Instantly share code, notes, and snippets.

@cyberzed
Created February 15, 2012 19:59
Show Gist options
  • Save cyberzed/1838562 to your computer and use it in GitHub Desktop.
Save cyberzed/1838562 to your computer and use it in GitHub Desktop.
Rx powered ServiceStack SL Client
public class ServiceClient<TRequest, TResponse>
where TRequest : class
where TResponse : class
{
private readonly string _baseUri;
private ISubject<TResponse> completionChannel;
public ServiceClient(string baseUri = "/api")
{
// make sure the base uri is set appropriately
if (!baseUri.StartsWith("http", StringComparison.InvariantCultureIgnoreCase))
{
var source = Application.Current.Host.Source;
var rootUri = source.AbsoluteUri.Substring(0, source.AbsoluteUri.Length - source.AbsolutePath.Length);
if (!baseUri.StartsWith("/"))
{
baseUri = "/" + baseUri;
}
baseUri = rootUri + baseUri;
}
_baseUri = baseUri;
// cookies are on by default
EnableCookies = true;
}
public bool EnableCookies { get; set; }
public IObservable<TResponse> Send(string uri, string method, TRequest data = null)
{
completionChannel = new AsyncSubject<TResponse>();
// set up the web request
var webRequest = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(new Uri(_baseUri + uri));
webRequest.Method = method;
// if cookies are enabled, pass them in from the browser
if (EnableCookies)
{
webRequest.CookieContainer = new CookieContainer();
webRequest.CookieContainer.SetCookies(new Uri(_baseUri), HtmlPage.Document.Cookies);
}
// set the accept header so our response is in json
webRequest.Accept = "application/json";
// if we have data to stream, start streaming. Otherwise we can get the response now.
if (data != null)
{
webRequest.BeginGetRequestStream(RequestCallback, new DataContainer(webRequest, data));
}
else
{
webRequest.BeginGetResponse(ResponseCallback, webRequest);
}
return completionChannel.ObserveOnDispatcher();
}
private void RequestCallback(IAsyncResult asyncResult)
{
try
{
// Get the web request stream
var container = (DataContainer)asyncResult.AsyncState;
var webRequest = container.WebRequest;
var stream = webRequest.EndGetRequestStream(asyncResult);
// set the content type to json
webRequest.ContentType = "application/json";
// serialize the object to json and write it to the stream
//var serializer = new DataContractJsonSerializer(typeof(TRequest));
//serializer.WriteObject(stream, container.Data);
//stream.Flush();
//stream.Close();
// If you want to use ServiceStack's serializer, replace the previous code block with this one.
using (var writer = new StreamWriter(stream))
{
var serializer = new JsonSerializer<TRequest>();
serializer.SerializeToWriter(container.Data, writer);
}
// now we can get the response
webRequest.BeginGetResponse(ResponseCallback, webRequest);
}
catch (Exception ex)
{
// Raise our own event for the error on the UI thread
completionChannel.OnError(ex);
}
}
private void ResponseCallback(IAsyncResult asyncResult)
{
try
{
// Get the web response
var webRequest = (HttpWebRequest)asyncResult.AsyncState;
var webResponse = webRequest.EndGetResponse(asyncResult);
// Get the web response stream
var stream = webResponse.GetResponseStream();
// Deserialize the json data in the response stream
//var serializer = new DataContractJsonSerializer(typeof(TResponse));
//var response = (TResponse)serializer.ReadObject(stream);
// If you want to use ServiceStack's serializer, replace the previous code block with this one.
TResponse response;
using (var reader = new StreamReader(stream))
{
var serializer = new JsonSerializer<TResponse>();
response = serializer.DeserializeFromReader(reader);
}
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// if cookies are enabled, pass them back to the browser
if (EnableCookies && webRequest.CookieContainer != null)
{
var cookieHeader = webRequest.CookieContainer.GetCookieHeader(new Uri(_baseUri));
HtmlPage.Document.Cookies = cookieHeader;
}
});
//Raise our own event for the response
completionChannel.OnNext(response);
completionChannel.OnCompleted();
}
catch (Exception ex)
{
// Raise our own event for the error on the UI thread
completionChannel.OnError(ex);
}
}
public IObservable<TResponse> Get(string uri)
{
return Send(uri, "GET");
}
public IObservable<TResponse> Post(string uri, TRequest data = null)
{
return Send(uri, "POST", data);
}
public IObservable<TResponse> Put(string uri, TRequest data = null)
{
return Send(uri, "PUT", data);
}
public IObservable<TResponse> Patch(string uri, TRequest data = null)
{
return Send(uri, "PATCH", data);
}
public IObservable<TResponse> Delete(string uri, TRequest data = null)
{
return Send(uri, "DELETE", data);
}
private class DataContainer
{
public DataContainer(HttpWebRequest webRequest, TRequest data)
{
WebRequest = webRequest;
Data = data;
}
public HttpWebRequest WebRequest { get; private set; }
public TRequest Data { get; private set; }
}
}
var ssClient = new ServiceClient<HelloRequest, HelloResponse>("");
var request = new HelloRequest { Name = "Stefan" };
ssClient.Post("/hello", request).Subscribe(helloResponse => MessageBox.Show(helloResponse.Greeting));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment