2014-01-29 18 views
1

我有一個C#應用程序,它只能作爲本地機器的Web服務器。 我使用this site作爲我的Web服務器的基礎。c#在接收請求時啓動表單的簡單Web服務器

所以,這裏是我的問題,主應用程序產生一個偵聽器線程來偵聽和處理響應。

在Program.cs中

static class Program 
{ 
    [STAThread] 
    static void Main() 
    { 
     Application.Run(new SysTrayApp()); 
    } 
} 

在SysTrayApp.cs:

public partial class SysTrayApp : Form 
{ 
    ... 
    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 
     WebServer myWebServer = new WebServer(WebServer.Response, "http://localhost:8080/"); 
     myWebServer.Run(); 
    } 
} 

在WebServer.cs

... 
public void Run() 
{ 
    ThreadPool.QueueUserWorkItem((o) => 
    { 
     Console.WriteLine("Webserver running..."); 
     try 
     { 
      while (_listener.IsListening) 
      { 
       var ctx = _listener.GetContext(); 
       try 
       { 
        string rstr = _responderMethod(ctx.Request); 
        byte[] buf = Encoding.UTF8.GetBytes(rstr); 
        ctx.Response.ContentLength64 = buf.Length; 
        ctx.Response.OutputStream.Write(buf, 0, buf.Length); 
       } 
       catch { } // suppress any exceptions 
       finally 
       { 
        // always close the stream 
        ctx.Response.OutputStream.Close(); 
       } 
      } 
     } 
     catch { } // suppress any exceptions 
    }); 
} 

當接收到一個請求,我想顯示一個Windows窗體到本地環境(而不是HTTP響應)。問題是我收到請求時不再處於主要STAThread中,因此我無法正確打開表單。

如果我嘗試在偵聽器線程中打開它,表單會凍結,因爲偵聽器開始偵聽並阻塞線程。類似的事情發生,如果我打開一個線程池線程。

public static string Response(HttpListenerRequest request) 
{ 

    Form form = new Form(); 
    form.Show(); 

    return "TEST!"; 
} 

如果我在一個新的正常線程中打開它,窗體彈出,然後線程關閉,然後窗體再次關閉。

public static string Response(HttpListenerRequest request) 
{ 
    Thread thread = new Thread(startForm); 
    thread.Start(); 
    return "TEST!"; 
} 

public static void startForm() 
{ 
    Form form = new Form(); 
    form.Show(); 
} 

所以,從我可以計算出,僅在主應用程序/ UI線程的形式似乎正常,也上班,你不能阻止主線程,否則形式凍結。因此,從WebServer偵聽器中,我如何觸發主線程上窗體的打開? 我應該在主窗體上創建一個啓動第二個窗體並嘗試從偵聽器線程觸發它的事件嗎?

還是有更好的方法來做到這一點?

P.S.我是一個PHP/Python程序員,不得不冒險進入C#只是爲了一個項目,所以我不知道我在做什麼。

+1

*調用*工作線程中的'SysTrayApp'的一個方法(它可以做任何你想做的事情)。 –

+0

謝謝。我快速瀏覽了微軟參考網站,** Invoke **看起來很有希望。你有沒有一個我將如何用它來解決問題的例子? 我會在調用** SysTrayApp方法之一的調用者線程中調用**嗎?它會使它在主線程中運行嗎? – Jayd

+0

Jayd,因爲評論我有點長,所以我發佈了它作爲答案。 –

回答

2

可以在工作線程調用一個的SysTrayApp方法如下

public class SysTrayApp : Form 
{ 
    public SysTrayApp() 
    { 
     Task.Factory.StartNew(Process, TaskCreationOptions.LongRunning); 
    } 

    void ActualWork(DateTime dt) 
    { 
     this.Text = dt.ToString(); 
    } 

    void Process() 
    { 
     while(true) 
     { 
      this.Invoke((Action)(() => ActualWork(DateTime.Now))); 
      Thread.Sleep(1000); 
     } 
    } 
} 

BTW:不要使用線程的線程池長時間運行的任務。 Why .net Threadpool is used only for short time span tasks?

+1

謝謝。這工作完美。 我不得不將'SysTrayApp'的主要實例傳遞給監聽器線程,但它工作得很好。謝謝你的幫助。 – Jayd