我们使用Griffin.WebServer替代.Net HttpClient,因为httpclient需要提升权限。在完成了关于该主题的选项后,我们决定使用Griffin.WebServer。抱歉,这没有用Griffin.WebServer标记 - 我没有代表创建该标签。
这个简单的网络服务器响应请求,效果很好 - 一次。然后连接保持打开状态,直到我强行关闭连接(使用TCPView并右键单击 - 关闭连接),或者超时后,后续请求才会处理。
以下是我正在测试的客户:
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();
}
以下是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;
}
}
这是我的听众回调。添加:
context.Response.KeepAlive = false;
没有任何区别......
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;
}
}
修改 我会保留这个以防万一有人需要它(并得到答案 - jgauffin?),但是,我找到了一个简单的解决方案来创建一个不需要提升权限的监听器at this CodeProject page。这是一个非常简单的解决方案,只需一次更改即可。我遇到的一个问题是它不会关闭。它需要将它添加到监听器循环中:
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);
}
然后在关机时包含以下内容:
simpleHttpServer.Listener.Server.Close();
if (!thread.Join(10000)) // try to wait for it...
thread.Abort();
simpleHttpServer = null;
希望这对我在同一搜索中的另一个人有所帮助。这比预期的要长。