Skip to content

Instantly share code, notes, and snippets.

@dbones
Created June 22, 2014 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbones/76073f272e6e60c66411 to your computer and use it in GitHub Desktop.
Save dbones/76073f272e6e60c66411 to your computer and use it in GitHub Desktop.
a wrapper around the webrequest, using a connection style. because i can
namespace HttpJsonTest
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
class Program
{
static void Main(string[] args)
{
//http://192.168.1.123:5984/test_suite_db/_all_docs
var connection = new Connection("http://192.168.1.123:5984");
var request = new Request("/:db/_all_docs", HttpVerbType.Get);
request.AddUrlSegment("db", "test_suite_db");
connection.Execute(request, response => Console.Write(response.Content.ReadToEnd()));
Console.Read();
}
}
/// <summary>
/// Auth mechanism to be applied on the http connection
/// </summary>
public interface IAuthentication
{
void Apply(IRequest request);
}
/// <summary>
/// RFC 2617
/// </summary>
public class BasicAuthentication : IAuthentication
{
private string authHeader;
public BasicAuthentication(string userName, string password)
{
var encoded = Convert.ToBase64String(Encoding.Default.GetBytes(userName + ":" + password));
authHeader = "Basic " + encoded;
}
public void Apply(IRequest request)
{
request.AddHeader("Authorization", authHeader);
}
}
/// <summary>
/// RFC 2109
/// </summary>
public class CookieAuthentication : IAuthentication
{
private Cookie _authSession;
public CookieAuthentication(
string serverUrl,
string userName,
string password)
{
var connection = new Connection(serverUrl);
var request = new FormRequest("/_session", HttpVerbType.Post);
request.AddFormParameter("name", userName);
request.AddFormParameter("password", password);
connection.Execute(request, response =>
{
if (response.Status == HttpStatusCode.OK)
{
_authSession = response.Cookies["AuthSession"];
}
});
}
public void Apply(IRequest request)
{
request.AddCookie(_authSession);
}
}
public interface IConnection
{
/// <summary>
/// set the authentication to use for all request on this connection
/// </summary>
IAuthentication Authentication { get; set; }
/// <summary>
/// set the proxy to use for this connection
/// </summary>
/// <remarks>
/// setting it to null will make the connection faster
/// </remarks>
IWebProxy Proxy { get; set; }
/// <summary>
/// Execute a command against this connection/endpoint
/// </summary>
/// <param name="request">request to execute</param>
/// <param name="responseHandler"></param>
void Execute(IRequest request, Action<IResponse> responseHandler);
}
public interface IRequest
{
IWebProxy Proxy { get; set; }
void Execute(string baseUrl, Action<Response> handleRequest, IWebProxy proxy = null);
void AddHeader(string key, string header);
void AddCookie(Cookie cookie);
void AddParameter(string key, string value);
void AddUrlSegment(string key, string value);
void AddContent(Action<StreamWriter> writeConent, HttpContentType contentType);
}
public interface IResponse
{
HttpStatusCode Status { get; }
StreamReader Content { get; }
long NumberOfBytes { get; }
CookieCollection Cookies { get; set; }
WebHeaderCollection Headers { get; }
}
public class Connection : IConnection
{
private readonly string _baseUrl;
public Connection(string baseUrl)
{
_baseUrl = baseUrl;
}
public IAuthentication Authentication { get; set; }
public IWebProxy Proxy { get; set; }
public void Execute(IRequest request, Action<IResponse> responseHandler)
{
try
{
if (Authentication != null)
{
Authentication.Apply(request);
}
request.Execute(_baseUrl, responseHandler, Proxy);
}
catch (Exception ex)
{
throw new RequestException(request, ex);
}
}
}
public class Request : IRequest
{
protected string _url;
protected readonly List<string> _params = new List<string>();
protected readonly List<Action<HttpWebRequest>> _configs = new List<Action<HttpWebRequest>>();
protected Action<StreamWriter> _writeContent;
protected HttpVerbType _httpVerb = HttpVerbType.Get;
public Request(string url, HttpVerbType verbType)
{
_url = url;
SetVerb(verbType);
}
public virtual IWebProxy Proxy { get; set; }
public virtual void Execute(string baseUrl, Action<Response> handleRequest, IWebProxy proxy = null)
{
string url = CreateUrl(baseUrl);
var request = (HttpWebRequest)WebRequest.Create(url);
request.Proxy = proxy ?? Proxy;
Setup(request);
request.AutomaticDecompression =
DecompressionMethods.GZip | DecompressionMethods.Deflate | DecompressionMethods.None;
if (_httpVerb != HttpVerbType.Get)
{
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
_writeContent(streamWriter);
}
}
using (var httpResponse = (HttpWebResponse) request.GetResponse())
{
var stream = httpResponse.GetResponseStream();
if (stream == null)
{
var response = new Response(httpResponse);
handleRequest(response);
}
else
{
using (var contentReader = new StreamReader(stream))
{
var response = new Response(httpResponse, contentReader);
handleRequest(response);
}
}
}
}
public virtual void AddHeader(string key, string header)
{
_configs.Add(request => request.Headers.Add(key, header));
}
public void AddCookie(Cookie cookie)
{
_configs.Add(request => request.CookieContainer.Add(cookie));
}
public virtual void AddParameter(string key, string value)
{
var encoded = HttpUtility.UrlEncode(value);
_params.Add(string.Format("{0}={1}", key, encoded));
}
public virtual void AddUrlSegment(string key, string value)
{
var encoded = HttpUtility.UrlEncode(value);
_url = _url.Replace(string.Format(":{0}", key), encoded);
}
public virtual void AddContent(Action<StreamWriter> writeConent, HttpContentType contentType)
{
SetContentType(contentType);
_writeContent = writeConent;
}
private string CreateUrl(string baseUrl)
{
var builder = new StringBuilder();
builder.Append(baseUrl);
if (!string.IsNullOrWhiteSpace(_url))
{
//try and ensure there is a /
if (!baseUrl.EndsWith("/") && !_url.StartsWith("/"))
{
builder.Append("/");
}
builder.Append(_url);
}
if (_params.Any())
{
var @params = string.Join("&", _params);
builder.Append("?");
builder.Append(@params);
}
return builder.ToString();
}
private void Setup(HttpWebRequest request)
{
foreach (var config in _configs)
{
config(request);
}
}
protected void SetContentType(HttpContentType contentType)
{
string value;
switch (contentType)
{
case HttpContentType.Json:
value = "text/json";
break;
case HttpContentType.Form:
value = "application/x-www-form-urlencoded";
break;
default:
throw new ArgumentOutOfRangeException("contentType");
}
_configs.Add(request => request.ContentType = value);
}
private void SetVerb(HttpVerbType verbType)
{
_httpVerb = verbType;
string value;
switch (verbType)
{
case HttpVerbType.Post:
value = "POST";
break;
case HttpVerbType.Get:
value = "GET";
break;
default:
throw new ArgumentOutOfRangeException("verbType");
}
_configs.Add(request => request.Method = value);
}
}
public class FormRequest : Request
{
protected List<string> _formParams = new List<string>();
public FormRequest(string url, HttpVerbType verbType) : base(url, verbType)
{
SetContentType(HttpContentType.Form);
if (verbType == HttpVerbType.Get)
{
throw new NotSupportedException("cannot use Get verb");
}
}
public override void Execute(string baseUrl, Action<Response> handleRequest, IWebProxy proxy = null)
{
if (_formParams.Any())
{
_writeContent = writer => writer.Write(string.Join("&", _formParams));
}
base.Execute(baseUrl, handleRequest, proxy);
}
public override void AddContent(Action<StreamWriter> writeConent, HttpContentType contentType)
{
throw new NotImplementedException("use AddFormParameter");
}
public virtual void AddFormParameter(string key, string value)
{
var encoded = HttpUtility.UrlEncode(value);
_formParams.Add(string.Format("{0}={1}", key, encoded));
}
}
public class Response : IResponse
{
public Response(HttpWebResponse response, StreamReader contentReader = null)
{
Content = contentReader;
Status = response.StatusCode;
NumberOfBytes = response.ContentLength;
Headers = response.Headers;
Cookies = response.Cookies;
}
public CookieCollection Cookies { get; set; }
public WebHeaderCollection Headers { get; private set; }
public HttpStatusCode Status { get; private set; }
public StreamReader Content { get; private set; }
public long NumberOfBytes { get; private set; }
}
public enum HttpVerbType
{
Post,
Get
}
public enum HttpContentType
{
Json,
Xml,
Form
}
public class RequestException : Exception
{
public RequestException(IRequest request)
{
Request = request;
}
public RequestException(IRequest request, Exception innerException)
: base("", innerException)
{
Request = request;
}
public IRequest Request { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment