Skip to content

Instantly share code, notes, and snippets.

@rudygt
Created May 7, 2013 02:38
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rudygt/5529897 to your computer and use it in GitHub Desktop.
Save rudygt/5529897 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reactive.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Amib.Threading;
using Funq;
using ServiceStack.Common.Web;
using ServiceStack.Logging;
using ServiceStack.ServiceHost;
using ServiceStack.ServiceInterface;
using ServiceStack.Text;
using ServiceStack.WebHost.Endpoints;
using ServiceStack.WebHost.Endpoints.Support;
namespace SSSelfHosted {
public class Program {
private static void Main(string[] args) {
var listeningOn = args.Length == 0 ? "http://*:9090/" : args[0];
var appHost = new AppHost();
appHost.Init();
appHost.Start(listeningOn);
Console.WriteLine("AppHost Created at {0}, listening on {1}", DateTime.Now, listeningOn);
Console.ReadKey();
}
}
public class AppHost : AppHostHttpListenerSmartThreadPool {
public AppHost() : base("StarterTemplate HttpListener", typeof(HelloService).Assembly) {}
public override void Configure(Funq.Container container) {}
}
[Route("/sayHello/{Name}")]
public class HelloRequest : IReturn<HelloResponse> {
public string Name { get; set; }
}
public class HelloResponse {
public string Message { get; set; }
public string Status { get; set; }
}
public class HelloService : Service, IGet<HelloRequest> {
private static Random r = new Random();
public object Get(HelloRequest request) {
var timer = new Stopwatch();
timer.Start();
while(timer.ElapsedMilliseconds < 100)
Thread.SpinWait(1000000);
timer.Stop();
return new HelloResponse() {
Message = "hello " + request.Name,
Status = "OK -> " + timer.ElapsedMilliseconds
};
}
}
#region smartthreadpool
public abstract class AppHostHttpListenerSmartThreadPool : AppHostHttpListenerBase {
private readonly AutoResetEvent _listenForNextRequest = new AutoResetEvent(false);
private readonly SmartThreadPool _threadPoolManager;
private readonly ILog _log = LogManager.GetLogger(typeof(HttpListenerBase));
private const int IdleTimeout = 300;
protected AppHostHttpListenerSmartThreadPool(int poolSize = 500) {
_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
protected AppHostHttpListenerSmartThreadPool(string serviceName, params Assembly[] assembliesWithServices)
: this(serviceName, 500, assembliesWithServices) {}
protected AppHostHttpListenerSmartThreadPool(string serviceName, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, assembliesWithServices) {
_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
protected AppHostHttpListenerSmartThreadPool(string serviceName, string handlerPath, params Assembly[] assembliesWithServices)
: this(serviceName, handlerPath, 500, assembliesWithServices) {}
protected AppHostHttpListenerSmartThreadPool(string serviceName, string handlerPath, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, handlerPath, assembliesWithServices) {
_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
private bool disposed = false;
protected override void Dispose(bool disposing) {
if(disposed) return;
lock(this) {
if(disposed) return;
if(disposing)
_threadPoolManager.Dispose();
// new shared cleanup logic
disposed = true;
base.Dispose(disposing);
}
}
/// <summary>
/// Starts the Web Service
/// </summary>
/// <param name="urlBase">
/// A Uri that acts as the base that the server is listening on.
/// Format should be: http://127.0.0.1:8080/ or http://127.0.0.1:8080/somevirtual/
/// Note: the trailing slash is required! For more info see the
/// HttpListener.Prefixes property on MSDN.
/// </param>
public override void Start(string urlBase) {
// *** Already running - just leave it in place
if(IsStarted)
return;
if(Listener == null)
Listener = new HttpListener();
Listener.Prefixes.Add(urlBase);
IsStarted = true;
Listener.Start();
ThreadPool.QueueUserWorkItem(Listen);
}
// Loop here to begin processing of new requests.
private void Listen(object state) {
while(Listener.IsListening) {
if(Listener == null) return;
try {
Listener.BeginGetContext(ListenerCallback, Listener);
_listenForNextRequest.WaitOne();
}
catch(Exception ex) {
_log.Error("Listen()", ex);
return;
}
if(Listener == null) return;
}
}
// Handle the processing of a request in here.
private void ListenerCallback(IAsyncResult asyncResult) {
var listener = asyncResult.AsyncState as HttpListener;
HttpListenerContext context;
if(listener == null) return;
var isListening = listener.IsListening;
try {
if(!isListening) {
_log.DebugFormat("Ignoring ListenerCallback() as HttpListener is no longer listening");
return;
}
// The EndGetContext() method, as with all Begin/End asynchronous methods in the .NET Framework,
// blocks until there is a request to be processed or some type of data is available.
context = listener.EndGetContext(asyncResult);
}
catch(Exception ex) {
// You will get an exception when httpListener.Stop() is called
// because there will be a thread stopped waiting on the .EndGetContext()
// method, and again, that is just the way most Begin/End asynchronous
// methods of the .NET Framework work.
string errMsg = ex + ": " + isListening;
_log.Warn(errMsg);
return;
}
finally {
// Once we know we have a request (or exception), we signal the other thread
// so that it calls the BeginGetContext() (or possibly exits if we're not
// listening any more) method to start handling the next incoming request
// while we continue to process this request on a different thread.
_listenForNextRequest.Set();
}
_log.InfoFormat("{0} Request : {1}", context.Request.UserHostAddress, context.Request.RawUrl);
RaiseReceiveWebRequest(context);
_threadPoolManager.QueueWorkItem(() => {
try {
ProcessRequest(context);
}
catch(Exception ex) {
var error = string.Format("Error this.ProcessRequest(context): [{0}]: {1}", ex.GetType().Name, ex.Message);
_log.ErrorFormat(error);
try {
var sb = new StringBuilder();
sb.AppendLine("{");
sb.AppendLine("\"ResponseStatus\":{");
sb.AppendFormat(" \"ErrorCode\":{0},\n", ex.GetType().Name.EncodeJson());
sb.AppendFormat(" \"Message\":{0},\n", ex.Message.EncodeJson());
sb.AppendFormat(" \"StackTrace\":{0}\n", ex.StackTrace.EncodeJson());
sb.AppendLine("}");
sb.AppendLine("}");
context.Response.StatusCode = 500;
context.Response.ContentType = ContentType.Json;
byte[] sbBytes = sb.ToString().ToUtf8Bytes();
context.Response.OutputStream.Write(sbBytes, 0, sbBytes.Length);
context.Response.Close();
}
catch(Exception errorEx) {
error = string.Format("Error this.ProcessRequest(context)(Exception while writing error to the response): [{0}]: {1}",
errorEx.GetType().Name, errorEx.Message);
_log.ErrorFormat(error);
}
}
});
}
}
#endregion
#region threadpool
public abstract class AppHostHttpListenerThreadPool : AppHostHttpListenerBase {
private readonly AutoResetEvent _listenForNextRequest = new AutoResetEvent(false);
//private readonly SmartThreadPool _threadPoolManager;
private readonly ILog _log = LogManager.GetLogger(typeof(HttpListenerBase));
private const int IdleTimeout = 300;
protected AppHostHttpListenerThreadPool(int poolSize = 500) {
//_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
protected AppHostHttpListenerThreadPool(string serviceName, params Assembly[] assembliesWithServices)
: this(serviceName, 500, assembliesWithServices) {}
protected AppHostHttpListenerThreadPool(string serviceName, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, assembliesWithServices) {
//_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
protected AppHostHttpListenerThreadPool(string serviceName, string handlerPath, params Assembly[] assembliesWithServices)
: this(serviceName, handlerPath, 500, assembliesWithServices) {}
protected AppHostHttpListenerThreadPool(string serviceName, string handlerPath, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, handlerPath, assembliesWithServices) {
//_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
private bool disposed = false;
protected override void Dispose(bool disposing) {
if(disposed) return;
lock(this) {
if(disposed) return;
/*if (disposing)
_threadPoolManager.Dispose();*/
// new shared cleanup logic
disposed = true;
base.Dispose(disposing);
}
}
/// <summary>
/// Starts the Web Service
/// </summary>
/// <param name="urlBase">
/// A Uri that acts as the base that the server is listening on.
/// Format should be: http://127.0.0.1:8080/ or http://127.0.0.1:8080/somevirtual/
/// Note: the trailing slash is required! For more info see the
/// HttpListener.Prefixes property on MSDN.
/// </param>
public override void Start(string urlBase) {
// *** Already running - just leave it in place
if(IsStarted)
return;
if(Listener == null)
Listener = new HttpListener();
Listener.Prefixes.Add(urlBase);
IsStarted = true;
Listener.Start();
ThreadPool.QueueUserWorkItem(Listen);
}
// Loop here to begin processing of new requests.
private void Listen(object state) {
while(Listener.IsListening) {
if(Listener == null) return;
try {
Listener.BeginGetContext(ListenerCallback, Listener);
_listenForNextRequest.WaitOne();
}
catch(Exception ex) {
_log.Error("Listen()", ex);
return;
}
if(Listener == null) return;
}
}
// Handle the processing of a request in here.
private void ListenerCallback(IAsyncResult asyncResult) {
var listener = asyncResult.AsyncState as HttpListener;
HttpListenerContext context;
if(listener == null) return;
var isListening = listener.IsListening;
try {
if(!isListening) {
_log.DebugFormat("Ignoring ListenerCallback() as HttpListener is no longer listening");
return;
}
// The EndGetContext() method, as with all Begin/End asynchronous methods in the .NET Framework,
// blocks until there is a request to be processed or some type of data is available.
context = listener.EndGetContext(asyncResult);
}
catch(Exception ex) {
// You will get an exception when httpListener.Stop() is called
// because there will be a thread stopped waiting on the .EndGetContext()
// method, and again, that is just the way most Begin/End asynchronous
// methods of the .NET Framework work.
string errMsg = ex + ": " + isListening;
_log.Warn(errMsg);
return;
}
finally {
// Once we know we have a request (or exception), we signal the other thread
// so that it calls the BeginGetContext() (or possibly exits if we're not
// listening any more) method to start handling the next incoming request
// while we continue to process this request on a different thread.
_listenForNextRequest.Set();
}
_log.InfoFormat("{0} Request : {1}", context.Request.UserHostAddress, context.Request.RawUrl);
RaiseReceiveWebRequest(context);
ThreadPool.QueueUserWorkItem(o => {
try {
ProcessRequest(context);
}
catch(Exception ex) {
var error = string.Format("Error this.ProcessRequest(context): [{0}]: {1}", ex.GetType().Name, ex.Message);
_log.ErrorFormat(error);
try {
var sb = new StringBuilder();
sb.AppendLine("{");
sb.AppendLine("\"ResponseStatus\":{");
sb.AppendFormat(" \"ErrorCode\":{0},\n", ex.GetType().Name.EncodeJson());
sb.AppendFormat(" \"Message\":{0},\n", ex.Message.EncodeJson());
sb.AppendFormat(" \"StackTrace\":{0}\n", ex.StackTrace.EncodeJson());
sb.AppendLine("}");
sb.AppendLine("}");
context.Response.StatusCode = 500;
context.Response.ContentType = ContentType.Json;
byte[] sbBytes = sb.ToString().ToUtf8Bytes();
context.Response.OutputStream.Write(sbBytes, 0, sbBytes.Length);
context.Response.Close();
}
catch(Exception errorEx) {
error = string.Format("Error this.ProcessRequest(context)(Exception while writing error to the response): [{0}]: {1}",
errorEx.GetType().Name, errorEx.Message);
_log.ErrorFormat(error);
}
}
});
}
}
#endregion
#region task
public abstract class AppHostHttpListenerTask : AppHostHttpListenerBase {
private readonly AutoResetEvent _listenForNextRequest = new AutoResetEvent(false);
//private readonly SmartThreadPool _threadPoolManager;
private readonly ILog _log = LogManager.GetLogger(typeof(HttpListenerBase));
private const int IdleTimeout = 300;
protected AppHostHttpListenerTask(int poolSize = 500) {
//_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
protected AppHostHttpListenerTask(string serviceName, params Assembly[] assembliesWithServices)
: this(serviceName, 500, assembliesWithServices) {}
protected AppHostHttpListenerTask(string serviceName, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, assembliesWithServices) {
//_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
protected AppHostHttpListenerTask(string serviceName, string handlerPath, params Assembly[] assembliesWithServices)
: this(serviceName, handlerPath, 500, assembliesWithServices) {}
protected AppHostHttpListenerTask(string serviceName, string handlerPath, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, handlerPath, assembliesWithServices) {
//_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
private bool disposed = false;
protected override void Dispose(bool disposing) {
if(disposed) return;
lock(this) {
if(disposed) return;
/*if (disposing)
_threadPoolManager.Dispose();*/
// new shared cleanup logic
disposed = true;
base.Dispose(disposing);
}
}
/// <summary>
/// Starts the Web Service
/// </summary>
/// <param name="urlBase">
/// A Uri that acts as the base that the server is listening on.
/// Format should be: http://127.0.0.1:8080/ or http://127.0.0.1:8080/somevirtual/
/// Note: the trailing slash is required! For more info see the
/// HttpListener.Prefixes property on MSDN.
/// </param>
public override void Start(string urlBase) {
// *** Already running - just leave it in place
if(IsStarted)
return;
if(Listener == null)
Listener = new HttpListener();
Listener.Prefixes.Add(urlBase);
IsStarted = true;
Listener.Start();
ThreadPool.QueueUserWorkItem(Listen);
}
// Loop here to begin processing of new requests.
private void Listen(object state) {
while(Listener.IsListening) {
if(Listener == null) return;
try {
Listener.BeginGetContext(ListenerCallback, Listener);
_listenForNextRequest.WaitOne();
}
catch(Exception ex) {
_log.Error("Listen()", ex);
return;
}
if(Listener == null) return;
}
}
// Handle the processing of a request in here.
private void ListenerCallback(IAsyncResult asyncResult) {
var listener = asyncResult.AsyncState as HttpListener;
HttpListenerContext context;
if(listener == null) return;
var isListening = listener.IsListening;
try {
if(!isListening) {
_log.DebugFormat("Ignoring ListenerCallback() as HttpListener is no longer listening");
return;
}
// The EndGetContext() method, as with all Begin/End asynchronous methods in the .NET Framework,
// blocks until there is a request to be processed or some type of data is available.
context = listener.EndGetContext(asyncResult);
}
catch(Exception ex) {
// You will get an exception when httpListener.Stop() is called
// because there will be a thread stopped waiting on the .EndGetContext()
// method, and again, that is just the way most Begin/End asynchronous
// methods of the .NET Framework work.
string errMsg = ex + ": " + isListening;
_log.Warn(errMsg);
return;
}
finally {
// Once we know we have a request (or exception), we signal the other thread
// so that it calls the BeginGetContext() (or possibly exits if we're not
// listening any more) method to start handling the next incoming request
// while we continue to process this request on a different thread.
_listenForNextRequest.Set();
}
_log.InfoFormat("{0} Request : {1}", context.Request.UserHostAddress, context.Request.RawUrl);
RaiseReceiveWebRequest(context);
Task.Factory.StartNew(() => {
try {
ProcessRequest(context);
}
catch(Exception ex) {
var error = string.Format("Error this.ProcessRequest(context): [{0}]: {1}", ex.GetType().Name, ex.Message);
_log.ErrorFormat(error);
try {
var sb = new StringBuilder();
sb.AppendLine("{");
sb.AppendLine("\"ResponseStatus\":{");
sb.AppendFormat(" \"ErrorCode\":{0},\n", ex.GetType().Name.EncodeJson());
sb.AppendFormat(" \"Message\":{0},\n", ex.Message.EncodeJson());
sb.AppendFormat(" \"StackTrace\":{0}\n", ex.StackTrace.EncodeJson());
sb.AppendLine("}");
sb.AppendLine("}");
context.Response.StatusCode = 500;
context.Response.ContentType = ContentType.Json;
byte[] sbBytes = sb.ToString().ToUtf8Bytes();
context.Response.OutputStream.Write(sbBytes, 0, sbBytes.Length);
context.Response.Close();
}
catch(Exception errorEx) {
error = string.Format("Error this.ProcessRequest(context)(Exception while writing error to the response): [{0}]: {1}",
errorEx.GetType().Name, errorEx.Message);
_log.ErrorFormat(error);
}
}
});
}
}
#endregion
public abstract class AppHostHttpListenerEventBased : AppHostHttpListenerBase {
private readonly ILog _log = LogManager.GetLogger(typeof(HttpListenerBase));
private readonly SmartThreadPool _threadPoolManager;
private const int IdleTimeout = 300;
protected AppHostHttpListenerEventBased(int poolSize = 500) {
_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
protected AppHostHttpListenerEventBased(string serviceName, params Assembly[] assembliesWithServices)
: this(serviceName, 500, assembliesWithServices) {}
protected AppHostHttpListenerEventBased(string serviceName, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, assembliesWithServices) {
_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
protected AppHostHttpListenerEventBased(string serviceName, string handlerPath, params Assembly[] assembliesWithServices)
: this(serviceName, handlerPath, 500, assembliesWithServices) {}
protected AppHostHttpListenerEventBased(string serviceName, string handlerPath, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, handlerPath, assembliesWithServices) {
_threadPoolManager = new SmartThreadPool(IdleTimeout, poolSize);
}
private bool disposed = false;
private HttpServer _server = null;
private IDisposable _handler = null;
protected override void Dispose(bool disposing) {
if(disposed) return;
lock(this) {
if(disposed) return;
if(disposing) {
_handler.Dispose();
_server.Dispose();
}
// new shared cleanup logic
disposed = true;
base.Dispose(disposing);
}
}
/// <summary>
/// Starts the Web Service
/// </summary>
/// <param name="urlBase">
/// A Uri that acts as the base that the server is listening on.
/// Format should be: http://127.0.0.1:8080/ or http://127.0.0.1:8080/somevirtual/
/// Note: the trailing slash is required! For more info see the
/// HttpListener.Prefixes property on MSDN.
/// </param>
public override void Start(string urlBase) {
// *** Already running - just leave it in place
if(IsStarted)
return;
_server = new HttpServer(urlBase);
_handler = _server.Where(ctx => true)
.Subscribe(ctx => _threadPoolManager.QueueWorkItem(() => DoRealWork(ctx.c)));
IsStarted = true;
}
public void DoRealWork(HttpListenerContext context) {
_log.InfoFormat("{0} Request : {1}", context.Request.UserHostAddress, context.Request.RawUrl);
RaiseReceiveWebRequest(context);
try {
ProcessRequest(context);
}
catch(Exception ex) {
var error = string.Format("Error this.ProcessRequest(context): [{0}]: {1}", ex.GetType().Name, ex.Message);
_log.ErrorFormat(error);
try {
var sb = new StringBuilder();
sb.AppendLine("{");
sb.AppendLine("\"ResponseStatus\":{");
sb.AppendFormat(" \"ErrorCode\":{0},\n", ex.GetType().Name.EncodeJson());
sb.AppendFormat(" \"Message\":{0},\n", ex.Message.EncodeJson());
sb.AppendFormat(" \"StackTrace\":{0}\n", ex.StackTrace.EncodeJson());
sb.AppendLine("}");
sb.AppendLine("}");
context.Response.StatusCode = 500;
context.Response.ContentType = ContentType.Json;
byte[] sbBytes = sb.ToString().ToUtf8Bytes();
context.Response.OutputStream.Write(sbBytes, 0, sbBytes.Length);
context.Response.Close();
}
catch(Exception errorEx) {
error = string.Format("Error this.ProcessRequest(context)(Exception while writing error to the response): [{0}]: {1}",
errorEx.GetType().Name, errorEx.Message);
_log.ErrorFormat(error);
}
}
}
}
public class HttpAsyncHost : AppHostHttpListenerBase {
private HttpListener _listener;
private readonly ILog _log = LogManager.GetLogger(typeof(HttpListenerBase));
private readonly int _accepts;
/// <summary>
/// Creates an asynchronous HTTP host.
/// </summary>
/// <param name="handler">Handler to serve requests with</param>
/// <param name="accepts">
/// Higher values mean more connections can be maintained yet at a much slower average response time; fewer connections will be rejected.
/// Lower values mean less connections can be maintained yet at a much faster average response time; more connections will be rejected.
/// </param>
///
public HttpAsyncHost(int accepts = 4) {
_listener = new HttpListener();
// Multiply by number of cores:
_accepts = accepts*Environment.ProcessorCount;
}
protected HttpAsyncHost(string serviceName, params Assembly[] assembliesWithServices)
: this(serviceName, 500, assembliesWithServices) {
_listener = new HttpListener();
// Multiply by number of cores:
_accepts = 4*Environment.ProcessorCount;
}
protected HttpAsyncHost(string serviceName, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, assembliesWithServices) {
_listener = new HttpListener();
// Multiply by number of cores:
_accepts = 4*Environment.ProcessorCount;
}
protected HttpAsyncHost(string serviceName, string handlerPath, params Assembly[] assembliesWithServices)
: this(serviceName, handlerPath, 500, assembliesWithServices) {
_listener = new HttpListener();
// Multiply by number of cores:
_accepts = 4*Environment.ProcessorCount;
}
protected HttpAsyncHost(string serviceName, string handlerPath, int poolSize, params Assembly[] assembliesWithServices)
: base(serviceName, handlerPath, assembliesWithServices) {
_listener = new HttpListener();
// Multiply by number of cores:
_accepts = 4*Environment.ProcessorCount;
}
public List<string> Prefixes {
get { return _listener.Prefixes.ToList(); }
}
public override void Start(string urlBase) {
//Profiler.Settings.ProfilerProvider = new SingletonProfilerProvider();
//Profiler.Settings.Storage = new MemoryStorage();
//this.Config.WebHostUrl = "/";
// *** Already running - just leave it in place
if(IsStarted)
return;
Run(urlBase);
IsStarted = true;
}
public void Run(params string[] uriPrefixes) {
_listener.IgnoreWriteExceptions = true;
// Add the server bindings:
foreach(var prefix in uriPrefixes)
_listener.Prefixes.Add(prefix);
Task.Run(async () => {
// Configure the handler:
try {
// Start the HTTP listener:
_listener.Start();
}
catch(HttpListenerException hlex) {
Console.Error.WriteLine(hlex.Message);
return;
}
// Accept connections:
// Higher values mean more connections can be maintained yet at a much slower average response time; fewer connections will be rejected.
// Lower values mean less connections can be maintained yet at a much faster average response time; more connections will be rejected.
var sem = new Semaphore(_accepts, _accepts);
while(true) {
sem.WaitOne();
#pragma warning disable 4014
_listener.GetContextAsync().ContinueWith(async (t) => {
string errMessage;
try {
sem.Release();
var ctx = await t;
await ProcessListenerContext(ctx, this);
return;
}
catch(Exception ex) {
errMessage = ex.ToString();
}
await Console.Error.WriteLineAsync(errMessage);
});
#pragma warning restore 4014
}
}).Wait();
}
private void DoRealWork(HttpListenerContext context) {
try {
//req_start();
ProcessRequest(context);
//req_stop();
}
catch(Exception ex) {
string error = string.Format("Error this.ProcessRequest(context): [{0}]: {1}", ex.GetType().Name, ex.Message);
_log.ErrorFormat(error);
try {
var sb = new StringBuilder();
sb.AppendLine("{");
sb.AppendLine("\"ResponseStatus\":{");
sb.AppendFormat(" \"ErrorCode\":{0},\n", ex.GetType().Name.EncodeJson());
sb.AppendFormat(" \"Message\":{0},\n", ex.Message.EncodeJson());
sb.AppendFormat(" \"StackTrace\":{0}\n", ex.StackTrace.EncodeJson());
sb.AppendLine("}");
sb.AppendLine("}");
context.Response.StatusCode = 500;
context.Response.ContentType = ContentType.Json;
byte[] sbBytes = sb.ToString().ToUtf8Bytes();
context.Response.OutputStream.Write(sbBytes, 0, sbBytes.Length);
context.Response.Close();
}
catch(Exception errorEx) {
error = string.Format("Error this.ProcessRequest(context)(Exception while writing error to the response): [{0}]: {1}",
errorEx.GetType().Name, errorEx.Message);
_log.ErrorFormat(error);
}
}
}
private async Task ProcessListenerContext(HttpListenerContext listenerContext, HttpAsyncHost host) {
Debug.Assert(listenerContext != null);
try {
RaiseReceiveWebRequest(listenerContext);
// Get the response action to take:
var action = await Task<bool>.Factory.StartNew(() => {
//DoRealWork(listenerContext);
DoRealWork(listenerContext);
return true;
});
// Close the response and send it to the client:
listenerContext.Response.Close();
}
catch(HttpListenerException) {
// Ignored.
}
catch(Exception ex) {
// TODO: better exception handling
Trace.WriteLine(ex.ToString());
}
}
public override void Configure(Container container) {
throw new NotImplementedException();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment