首页 > 解决方案 > 用于 Web Api 调用 HttpSelfHostServer 的 Console.ReadKey 块

问题描述

我有一个控制台应用程序,它(除其他外)使用 HttpSelfHostServer 托管一个 Web api 控制器。应用程序启动一个前台线程做一些事情,并等待用户按键,然后应用程序将退出。这很好用。我使用 Console.ReadKey 等待输入。

当我添加一个 HttpSelfHostServer 和一个 Web Api 控制器时,会发生奇怪的事情。每次在控制器中接收到一个 http 请求时,都会使用一个新线程。我猜它会从 Threadpool 中获取一个线程。在这个线程中,我做了一个 Console.WriteLine()。这在大多数情况下都有效,直到突然停止工作。处理在 Console.WriteLine 中被阻止。是不是碰巧得到了在 Console.ReadKey 上等待的线程?

总而言之,我的应用程序做了三件事:

  1. 一个线程正在等待用户按键然后停止应用程序
  2. 一个线程正在做其他处理工作。
  3. Web Api 控制器为每个 Web 请求启动一个新线程,进行一些处理,包括一个 console.writeline。此处理相当快,并且返回 HttpStatusCode.OK 很快。除非 console.writeline 挂起。然后它永远不会返回,并且任何更多的 Web Api 调用块也在这里。直到按下一个键。然后突然所有这些阻塞的线程都被释放了。

怎么了?怎么解决?

请参阅下面的基本实现。

public static class Program
{
    public WebServer MyWebServer { get; set; }

    static void Main(string[] args)
    {
        if (Environment.UserInteractive)
        {
            // running as console app
            Console.WriteLine($"START PROGRAM");
            
            Start(args); // Call stuff that sets up a foreground thread to do some processing.

            Console.WriteLine("Press any key to stop...");
            Console.ReadKey(true);

            Console.WriteLine($"STOP PROGRAM");
            
            Stop(); // Call stuff to stop the processing in the other thread.
        }
        else
        {
            // running as service
            using (var service = new Service())
            {
                ServiceBase.Run(service);
            }
        }
    }
    
    public void Start()
    {
        MyWebServer = new WebServer();
        MyWebServer.Start();
        Do_some_other_stuff_on_another_thread();
    }

    public void Stop()
    {
        Stop_the_other_thread();
        MyWebServer.Stop();
    }
    
}

public class WebServer
{
    // This is a self hosting WepApi webserver.
    private HttpSelfHostServer Server { get; set; }

    public void Start()
    {
        try
        {
            config.Routes.MapHttpRoute("My Api", "api/{controller}/{action}");
            Server = new HttpSelfHostServer(config);
            Server.OpenAsync();
            Console.WriteLine("STARTING WEBSERVER");
        }
        catch (Exception ex)
        {
            Console.WriteLine("WEBSERVER EXCEPTION: " + ex.Message);
        }
    }

    public void Stop()
    {
        Server.CloseAsync();
        Console.WriteLine("WEBSERVER STOP");
    }
}


public class MyController : ApiController
{
    [HttpPost]
    public HttpResponseMessage Trigger()
    {
        try
        {
            // This console writeline is sometimes blocked.
            Console.WriteLine("MyController.Trigger: We got a web api request");
            
            
            ProcessTriggerRequest();
            return Request.CreateResponse(HttpStatusCode.OK);
        }
        catch (Exception ex)
        {
            return Request.CreateResponse(HttpStatusCode.InternalServerError);
        }
    }
}

标签: c#multithreadingconsolethreadpoolself-host-webapi

解决方案


推荐阅读