Пример в документации HttpListener может использоваться для обработки только одного вызова.Для обработки большего количества вызовов код между listener.Start()
и listener.Stop()
должен выполняться в цикле.
Чтобы сделать этот код асинхронным, все, что нужно, это использовать асинхронные версии HttpListener.GetContext
и Stream.Write
:
public static async Task ListenAsync(params string[] prefixes)
{
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
using(var listener = new HttpListener())
{
// Add the prefixes.
foreach (string s in prefixes)
{
listener.Prefixes.Add(s);
}
listener.Start();
Console.WriteLine("Listening...");
for (int i=0;i<3;i++)
{
var context = await listener.GetContextAsync();
Console.WriteLine($"Got {i}");
var response = context.Response;
string responseString = $"<HTML><BODY> Hello world {i}!</BODY></HTML>";
var buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
using(var output = response.OutputStream)
{
await output.WriteAsync(buffer,0,buffer.Length);
}
}
listener.Stop();
}
}
ListenAsync
необходимо вызывать только один раз и ждать доэто завершается.В этом случае он обрабатывает до 3 запросов в цикле перед выходом.
Вызвать его в консольном приложении можно так же просто, как:
static async Task Main(string[] args)
{
Console.WriteLine("Starting !");
await ListenAsync(@"http://*:19999/");
Console.WriteLine("Finished");
}
Чтобы остановить слушателя в потоке-безопасным образом, CancellationToken должен использоваться, чтобы сигнализировать, что слушатель должен отменить. GetContextAsync () сам не может принять токен отмены.Однако его можно прервать, вызвав HttpListener.Abort .Если GetContextAsync()
ожидает, когда это произойдет, будет выдано ObjectDisposedException
.
Основной метод ждет нажатия клавиши сейчас, прежде чем подать сигнал об отмене и ждать, пока ListenAsync
завершит свой текущий запрос:
static async Task Main(string[] args)
{
Console.WriteLine("Starting !");
using(var cts=new CancellationTokenSource())
{
try
{
var task= ListenAsync(cts.Token, @"http://*:19999/");
Console.ReadKey();
cts.Cancel();
await task;
}
catch(ObjectDisposedException)
{
Console.WriteLine("Listener aborted");
}
}
Console.WriteLine("Finished");
}
ListenAsync
сам использует token.Register(()=>listener.Abort());
на маркере отмены, чтобы прервать слушателя.Цикл for
меняется на while(!token.IsCancellationRequested)
, позволяя слушателю продолжать слушать, пока не будет нажата клавиша:
public static async Task ListenAsync(CancellationToken token,params string[] prefixes)
{
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
using(var listener = new HttpListener())
{
foreach (string s in prefixes)
{
listener.Prefixes.Add(s);
}
listener.Start();
Console.WriteLine("Listening. Hit any key to end.");
//Abort if the token is signalled
token.Register(()=>listener.Abort());
int i=0;
//Loop until cancellation is requested
while (!token.IsCancellationRequested)
{
var context = await listener.GetContextAsync();
Console.WriteLine($"Got {i++}");
var response = context.Response;
string responseString = $"<HTML><BODY> Hello world {i}!</BODY></HTML>";
var buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
using(var output = response.OutputStream)
{
await output.WriteAsync(buffer,0,buffer.Length);
}
}
listener.Stop();
}
}