We're using Griffin.WebServer as a replacement for the .Net HttpClient because the httpclient requires elevated privileges. After exhausting our options on that subject, we decided on Griffin.WebServer. Sorry this is not tagged with Griffin.WebServer - I do not have rep to create that tag.
This simple webserver responds to requests, and works great - once. Then the connection stays open, and a subsequent request will not process until I have closed the connection forcibly (using TCPView and right-click - Close Connection), or it times out.
Here is the client I am testing with:
static void Main(string[] args)
{
try
{
var request = new
{
JsonData1 = 50538,
JsonData2 = 2,
JsonData3 = 1
};
var handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri("http://ALocalMachine:8800/listener/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.ConnectionClose = true;
Task<HttpResponseMessage> postTask = client.PostAsJsonAsync("RunTest/", request);
postTask.Wait();
if (!postTask.Result.IsSuccessStatusCode)
{
throw new Exception("Unable to start test run - " + postTask.Result.ReasonPhrase);
}
var responseTask = postTask.Result.Content.ReadAsStringAsync();
responseTask.Wait();
dynamic response = JsonConvert.DeserializeObject(responseTask.Result);
var results = new
{
Error = "",
Success = true
};
}
// this request fails with connection forcebly closed
var request = new
{
JsonData1 = 50539,
JsonData2 = 3,
JsonData3 = 4
};
var handler = new HttpClientHandler();
handler.UseDefaultCredentials = true;
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri("http://ALocalMachine:8800/listener/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.ConnectionClose = true;
Task<HttpResponseMessage> postTask = client.PostAsJsonAsync("RunTest/", request);
postTask.Wait();
if (!postTask.Result.IsSuccessStatusCode)
{
throw new Exception("Unsuccessful - " + postTask.Result.ReasonPhrase);
}
var responseTask = postTask.Result.Content.ReadAsStringAsync();
responseTask.Wait();
dynamic response = JsonConvert.DeserializeObject(responseTask.Result);
var results = new
{
Error = "",
Success = true
};
}
Console.WriteLine("successful");
}
catch (Exception ex)
{
Console.WriteLine("failed with error: " + ex.ToString());
}
Console.ReadLine();
}
Below is the Griffin IWorkerModule.
public class MyModule : IWorkerModule
{
public class ListenerNotifyEventArgs : EventArgs
{
public IHttpContext Context { get; set; }
}
public delegate void ListenerNotifyEventHandler(object sender, ListenerNotifyEventArgs e);
public event ListenerNotifyEventHandler OnListenerNotify;
public void BeginRequest(IHttpContext context)
{
}
public void EndRequest(IHttpContext context)
{
}
public void HandleRequestAsync(IHttpContext context, Action<IAsyncModuleResult> callback)
{
// Since this module only supports sync
callback(new AsyncModuleResult(context, HandleRequest(context)));
}
public ModuleResult HandleRequest(IHttpContext context)
{
if (OnListenerNotify != null)
OnListenerNotify(null, new ListenerNotifyEventArgs(){Context = context});
return ModuleResult.Stop;
}
}
Here is my listener callback. Adding the:
context.Response.KeepAlive = false;
didn't make any difference...
private void ListenerCallback(object sender, MyModule.ListenerNotifyEventArgs eventArgs)
{
var context = eventArgs.Context;
try
{
var requestDetails = context.Request.Uri.AbsolutePath.Substring("/TestifyAgent/".Length);
if (requestDetails.ToLower().StartsWith("runtest"))
{
var data_text = new StreamReader(context.Request.Body, context.Request.ContentEncoding).ReadToEnd();
dynamic requestVals = JsonConvert.DeserializeObject(data_text);
int jsonData1 = Convert.ToInt32(requestVals.JsonData1);
int jsonData2 = Convert.ToInt32(requestVals.JsonData2);
int jsonData3 = Convert.ToInt32(requestVals.JsonData3);
StartProcess(jsonData1, jsonData2, jsonData3);
var returnData = new
{
Result = "Success",
Environment.MachineName,
runRequest.TestCaseRunId
};
var returnJsonData = JsonConvert.SerializeObject(returnData);
var returnUtfData = Encoding.UTF8.GetBytes(returnJsonData);
context.Response.StatusCode = (int) HttpStatusCode.OK;
context.Response.StatusDescription = "OK";
context.Response.ContentType = "text/html";
context.Response.Body = new MemoryStream();
context.Response.Body.Write(returnUtfData, 0, returnUtfData.Length);
context.Response.Body.Flush();
context.Response.Body.Position = 0;
context.Response.KeepAlive = false;
return;
}
else
{
var buffer = Encoding.UTF8.GetBytes("<html><head></head><body><h1>500 - Server Error</h1></body></html>");
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
context.Response.StatusDescription = "Bad Request";
context.Response.ContentType = "text/html";
context.Response.Body = new MemoryStream();
context.Response.Body.Write(buffer, 0, buffer.Length);
context.Response.Body.Flush();
context.Response.Body.Position = 0;
context.Response.KeepAlive = false;
Notify("Invalid Request method:" + context.Request.Method + " Url: " + context.Request.Uri.AbsoluteUri);
return;
}
}
catch (Exception ex)
{
TrySendErrorOrWriteEventLog(ex);
try
{
var buffer =
Encoding.UTF8.GetBytes("<html><head></head><body><h1>500 - Server Error</h1>Error processing request:" +
context.Request.Method + " Error: " + ex.Message + "</body></html>");
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
context.Response.StatusDescription = "Internal Server Error";
context.Response.ContentType = "text/html";
context.Response.Body.Write(buffer, 0, buffer.Length);
context.Response.Body.Flush();
context.Response.Body.Position = 0;
}
catch { }
return;
}
}
EDIT:
I will leave this open in case someone needs it (and it gets answered - jgauffin?), however, I found a simple solution for creating a listener that did not require elevated privileges at this CodeProject page. It is a very straightforward solution and with one change it works very well. The one issue I had with it is that it won't shut down. It needs this added to the listener loop:
public abstract class SimpleHttpServer {
protected int port;
private TcpListener _listener;
// this lets us call in with Listener.Server.Close(); when we want to shutdown
public TcpListener Listener { get { return _listener; } }
public bool IsActive { get; set; }
public SimpleHttpServer(int port)
{
this.port = port;
}
public void listen()
{
IsActive = true;
_listener = new TcpListener(port);
_listener.Start();
while (IsActive)
{
try
{
TcpClient s = _listener.AcceptTcpClient();
SimpleHttpProcessor processor = new SimpleHttpProcessor(s, this);
Thread thread = new Thread(new ThreadStart(processor.process));
thread.Start();
Thread.Sleep(1);
}
catch (Exception ex)
{ // shutdown requested?
if (ex.Message.Contains("A blocking operation was interrupted by a call to WSACancelBlockingCall"))
return;
}
}
}
public abstract void handleGETRequest(SimpleHttpProcessor p);
public abstract void handlePOSTRequest(SimpleHttpProcessor p, StreamReader inputData);
}
Then in your shutdown include something like this:
simpleHttpServer.Listener.Server.Close();
if (!thread.Join(10000)) // try to wait for it...
thread.Abort();
simpleHttpServer = null;
Hope this is helpful to another in the same search as I was. This took way longer than it should have.
Source: http://stackoverflow.com/questions/27139443/how-do-i-close-a-connection-on-a-request-to-the-griffin-webserver
We're using Griffin.WebServer as a replacement for the .Net HttpClient because the httpclient requires elevated privileges. After exhausting our options on that subject, we decided on Griffin.WebServer. Sorry this is not tagged with Griffin.WebServer - I do not have rep to create that tag.
This simple webserver responds to requests, and works great - once. Then the connection stays open, and a subsequent request will not process until I have closed the connection forcibly (using TCPView and right-click - Close Connection), or it times out.
Here is the client I am testing with:
Below is the Griffin IWorkerModule.
Here is my listener callback. Adding the:
didn't make any difference...
EDIT: I will leave this open in case someone needs it (and it gets answered - jgauffin?), however, I found a simple solution for creating a listener that did not require elevated privileges at this CodeProject page. It is a very straightforward solution and with one change it works very well. The one issue I had with it is that it won't shut down. It needs this added to the listener loop:
Then in your shutdown include something like this:
Hope this is helpful to another in the same search as I was. This took way longer than it should have.