Mario Boulet

Mario Boulet

  • NA
  • 4
  • 1.3k

Windows Service - BeginGetContext of HTTPListener class

Apr 13 2021 8:57 PM
Hi everyone,
I created two kind of programming codes. The first one, I simply use HTTPListener class in .NET. The last one, I use a complex method with more than one thread to treat entering SOAP Request. For them, I return SOAP Response. These solutions runs perfectly within Windows Forms Application.
But, I have a big problem. The BeginGetContext of HTTPListener seems to be quiet and never trigger within Windows Service. I don't think this issue is normal. These two algorithms runs without issue within Windows Forms Application. Naturally, if I start the Windows Service, the Windows Forms Application doesn't listen in same time. I only run one of them to prevent collision.
I have a valid self signed certificate. It runs under Windows Forms Application with no issue. I use the same for Windows Service, except with using OnStart and OnStop. This is at this moment the situation is problematic.
I delete and add a SSL Certificate each time to be sure that I have loaded certificate within Windows.
I prefer to have simplicity with programming code. I am a fan to "keep it simple". I don't care to keep any of them. I want the best one.
Do you experiment this behavior in your life? I transfer many application from Windows Forms Application to Windows Service without any kind of issue in the past.
If I execute the DOS command : " telnet localhost 30010 ", the Windows Service listen really the port of communication 30010. But, the BeginGetContext didn't trigger to my function ListenerCallback or ContextReady like it is supposed to do.
I read basic documentations concerning HTTPListener class. I control the situation within Windows Forms Application. All methods runs perfectly. This is just if I use the Windows Service. The BeginGetContext doesn't react like it is supposed to react within Windows Service environment.
First one :
public partial class SOAPServer_Service : ServiceBase {
    public string ErrorMessage = "";
    private HttpListener Listener;
    public SOAPServer_Service() {
        InitializeComponent();
    }
    protected void OnStart(string[] args) {
        try {
            this.ErrorMessage = "";
            string Port = "30010",
            HashCertificat = "8f3146c64cb75a716a3543dfc10c2967acab9471",
            URLEnvironment = "https://10.182.133.101:30010/WS/";
            Process ProcessusDelete = new Process();
            ProcessStartInfo StartInfoDelete = new ProcessStartInfo();
            StartInfoDelete.WindowStyle = ProcessWindowStyle.Hidden;
            StartInfoDelete.FileName = "cmd.exe";
            StartInfoDelete.Arguments = "/C C:\\Windows\\System32\\netsh http delete sslcert ipport=0.0.0.0:" + Port;
            StartInfoDelete.Verb = "runas";
            ProcessusDelete.StartInfo = StartInfoDelete;
            ProcessusDelete.Start();
            ProcessusDelete.WaitForExit(10000);
            ProcessusDelete.Close();
            Process ProcessusAdd = new Process();
            ProcessStartInfo StartInfoAdd = new ProcessStartInfo();
            StartInfoAdd.WindowStyle = ProcessWindowStyle.Hidden;
            StartInfoAdd.FileName = "cmd.exe";
            StartInfoAdd.Arguments = "/C C:\\Windows\\System32\\netsh http add sslcert ipport=0.0.0.0:" + Port + " certhash=" + HashCertificat + " appid={e2eaacd9-92e6-43cc-b51c-7a7887149607}";
            StartInfoAdd.Verb = "runas";
            ProcessusAdd.StartInfo = StartInfoAdd;
            ProcessusAdd.Start();
            ProcessusAdd.WaitForExit(10000);
            ProcessusAdd.Close();
            if (HttpListener.IsSupported) {
                if (this.Listener == null) {
                    this.Listener = new HttpListener();
                }
                this.Listener.Prefixes.Add(URLEnvironment);
                this.Listener.Start();
                // It seems to be not effective
                IAsyncResult Result = this.Listener.BeginGetContext(new AsyncCallback(this.ListenerCallback), this.Listener);
            } else {
                this.ErrorMessage = "The operating system is not up to date!";
                return false;
            }
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fs = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_OnStart.txt", FileMode.Create)) {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                    sw.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
    protected override void OnStop() {
        try {
            this.ErrorMessage = "";
            if (this.Listener != null) {
                this.Listener.Close();
                this.Listener = null;
            }
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fs = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_OnStop.txt", FileMode.Create)) {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                    sw.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
    private void ListenerCallback(IAsyncResult Result) {
        try {
            string SOAPRequest = "",
            SOAPResponse = "";
            this.ErrorMessage = "";
            HttpListenerContext Context = this.Listener.EndGetContext(Result);
            HttpListenerRequest Request = Context.Request;
            HttpListenerResponse Response = Context.Response;
            if (Request.HasEntityBody) {
                Stream S = Request.InputStream;
                StreamReader SR = new StreamReader(S, Encoding.UTF8);
                SOAPRequest = SR.ReadToEnd();
                SR.Close();
                S.Close();
                using (FileStream fsIn = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Trace_Request_" + DateTime.Now.ToString("s").Replace("/", "").Replace("-", "").Replace(":", "") + ".xml", FileMode.Create)) {
                    using (StreamWriter swIn = new StreamWriter(fsIn, Encoding.UTF8)) {
                        swIn.WriteLine(SOAPRequest);
                    }
                }
                //... {creation of SOAP response}
                using (FileStream fsOut = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Trace_Response_" + DateTime.Now.ToString("s").Replace("/", "").Replace("-", "").Replace(":", "") + ".xml", FileMode.Create)) {
                    using (StreamWriter swOut = new StreamWriter(fsOut, Encoding.UTF8)) {
                        swOut.WriteLine(SOAPResponse);
                    }
                }
                byte[] byteSOAPResponse = UTF8Encoding.UTF8.GetBytes(SOAPResponse);
                using (Stream StreamSender = Response.OutputStream) {
                    StreamSender.Write(byteSOAPResponse, 0, byteSOAPResponse.Length);
                    StreamSender.Close();
                }
                Response.Close();
                Result = this.Listener.BeginGetContext(new AsyncCallback(this.ListenerCallback), this.Listener);
            }
        } catch (Exception E) {
            this.ErrorMessage = this.RecupereException(E);
            using (FileStream fs = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_ListenerCallback_" + DateTime.Now.ToString("s").Replace("/", "").Replace("-", "").Replace(":", "") + ".txt", FileMode.Create)) {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                    swEntree.WriteLine("TryCatch : ");
                    swEntree.WriteLine(this.ErrorMessage);
                }
            }
            return;
        }
    }
    protected string RecupereException(Exception E) {
        string M = "";
        while (E != null) {
            M += E.Message;
            E = E.InnerException;
        }
        return M;
    }
}
Second one :
public partial class SOAPServer_Service : ServiceBase {
    public string ErrorMessage = "";
    private int NbrThread = 5;
    private SOAPServer_OSS ServerSOAP;
    public SOAPServer_Service() {
        InitializeComponent();
        this.ServerSOAP = new SOAPServer_OSS(this.NbrThread);
    }
    protected void OnStart(string[] args) {
        try {
            this.ServerSOAP.Start();
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fs = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_OnStart.txt", FileMode.Create)) {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                    sw.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
    protected override void OnStop() {
        try {
            this.ServerSOAP.Stop();
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fs = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_OnStop.txt", FileMode.Create)) {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                    sw.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
    protected string GetCompleteException(Exception E) {
        string M = "";
        while (E != null) {
            M += E.Message;
            E = E.InnerException;
        }
        return M;
    }
}
class SOAPServer_OSS : IDisposable {
    private readonly HttpListener listener;
    private readonly Thread listenerThread;
    private readonly Thread[] thread;
    private readonly ManualResetEvent state_listener,
                                                               state_queue;
    private Queue<HttpListenerContext> queue;
    public string port = "30010",
    hashCertificat = "8f3146c64cb75a716a3543dfc10c2967acab9471";
    public SOAPServer_OSS(int NbrThread) {
        this.thread = new Thread[NbrThread];
        this.queue = new Queue<HttpListenerContext>();
        this.state_listener = new ManualResetEvent(false);
        this.state_queue = new ManualResetEvent(false);
        this.listener = new HttpListener();
        this.listenerThread = new Thread(this.HandleRequests);
    }
    protected string GetCompleteException(Exception E) {
        string M = "";
        while (E != null) {
            M += E.Message;
            E = E.InnerException;
        }
        return M;
    }
    public void Start() {
        try {
            Process ProcessusDelete = new Process();
            ProcessStartInfo StartInfoDelete = new ProcessStartInfo();
            StartInfoDelete.WindowStyle = ProcessWindowStyle.Hidden;
            StartInfoDelete.FileName = "cmd.exe";
            StartInfoDelete.Arguments = "/C C:\\Windows\\System32\\netsh http delete sslcert ipport=0.0.0.0:" + this.port;
            StartInfoDelete.Verb = "runas";
            ProcessusDelete.StartInfo = StartInfoDelete;
            ProcessusDelete.Start();
            ProcessusDelete.WaitForExit(10000);
            ProcessusDelete.Close();
            Process ProcessusAdd = new Process();
            ProcessStartInfo StartInfoAdd = new ProcessStartInfo();
            StartInfoAdd.WindowStyle = ProcessWindowStyle.Hidden;
            StartInfoAdd.FileName = "cmd.exe";
            StartInfoAdd.Arguments = "/C C:\\Windows\\System32\\netsh http add sslcert ipport=0.0.0.0:" + this.port + " certhash=" + this.hashCertificat + " appid={e2eaacd9-92e6-43cc-b51c-7a7887149607}";
            StartInfoAdd.Verb = "runas";
            ProcessusAdd.StartInfo = StartInfoAdd;
            ProcessusAdd.Start();
            ProcessusAdd.WaitForExit(10000);
            ProcessusAdd.Close();
            this.listener.Prefixes.Add(String.Format(@"https://+:{0}/WS/", this.port));
            this.listener.Start();
            this.listenerThread.Start();
            for (int i = 0; i < this.thread.Length; i++) {
                this.thread[i] = new Thread(this.Worker);
                this.thread[i].Name = "Thread_" + (i + 1).ToString();
                this.thread[i].Start();
            }
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fsEntree = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_SOAPServer_Start.txt", FileMode.Create)) {
                using (StreamWriter swEntree = new StreamWriter(fsEntree, Encoding.UTF8)) {
                    swEntree.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
    public void Dispose() { this.Stop(); }
    public void Stop() {
        try {
            this.state_listener.Set();
            this.listenerThread.Join();
            foreach (Thread T in this.thread) {
                T.Join();
            }
 
            this.listener.Stop();
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fsEntree = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_Stop.txt", FileMode.Create)) {
                using (StreamWriter swEntree = new StreamWriter(fsEntree, Encoding.UTF8)) {
                    swEntree.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
    private void HandleRequests() {
        try {
            while (this.listener.IsListening) {
                // It seems to be not effective
                var context = this.listener.BeginGetContext(this.ContextReady, null);
                WaitHandle[] wait = new[] { this.state_listener, context.AsyncWaitHandle };
                if (0 == WaitHandle.WaitAny(wait)) {
                    return;
                }
            }
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fsEntree = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_HandleRequests.txt", FileMode.Create)) {
                using (StreamWriter swEntree = new StreamWriter(fsEntree, Encoding.UTF8)) {
                    swEntree.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
    private void ContextReady(IAsyncResult ar) {
        try {
            lock (this.queue) {
                this.queue.Enqueue(this.listener.EndGetContext(ar));
                this.state_queue.Set();
            }
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fsEntree = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_ContextReady.txt", FileMode.Create)) {
                using (StreamWriter swEntree = new StreamWriter(fsEntree, Encoding.UTF8)) {
                    swEntree.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
    private void Worker() {
        try {
            WaitHandle[] wait = new[] { this.state_queue, this.state_listener };
            while (0 == WaitHandle.WaitAny(wait)) {
                HttpListenerContext context;
                lock (this.queue) {
                    if (this.queue.Count > 0) {
                        context = this.queue.Dequeue();
                    } else {
                        this.state_queue.Reset();
                        continue;
                    }
                }
 
                this.ProcessRequest(context);
            }
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fsEntree = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_Worker.txt", FileMode.Create)) {
                using (StreamWriter swEntree = new StreamWriter(fsEntree, Encoding.UTF8)) {
                    swEntree.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
    private void ProcessRequest(HttpListenerContext Contexte) {
        try {
            HttpListenerRequest Request = Contexte.Request;
            HttpListenerResponse Response = Contexte.Response;
            if (Request.HasEntityBody) {
                Stream S = Request.InputStream;
                StreamReader SR = new StreamReader(S, Encoding.UTF8);
                SOAPRequest = SR.ReadToEnd();
                SR.Close();
                S.Close();
                using (FileStream fsIn = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Trace_Request_" + DateTime.Now.ToString("s").Replace("/", "").Replace("-", "").Replace(":", "") + ".xml", FileMode.Create)) {
                    using (StreamWriter swIn = new StreamWriter(fsIn, Encoding.UTF8)) {
                        swIn.WriteLine(SOAPRequest);
                    }
                }
                //... {creation of SOAP response}
                using (FileStream fsOut = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Trace_Response_" + DateTime.Now.ToString("s").Replace("/", "").Replace("-", "").Replace(":", "") + ".xml", FileMode.Create)) {
                    using (StreamWriter swOut = new StreamWriter(fsOut, Encoding.UTF8)) {
                        swOut.WriteLine(SOAPResponse);
                    }
                }
                byte[] byteSOAPResponse = UTF8Encoding.UTF8.GetBytes(SOAPResponse);
                using (Stream StreamSender = Response.OutputStream) {
                    StreamSender.Write(byteSOAPResponse, 0, byteSOAPResponse.Length);
                    StreamSender.Close();
                }
                Response.Close();
            }
        } catch (Exception E) {
            this.ErrorMessage = this.GetCompleteException(E);
            using (FileStream fsEntree = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Exception_ProcessRequest_" + DateTime.Now.ToString("s").Replace("/", "").Replace("-", "").Replace(":", "") + ".txt", FileMode.Create)) {
                using (StreamWriter swEntree = new StreamWriter(fsEntree, Encoding.UTF8)) {
                    swEntree.WriteLine("TryCatch : ");
                    swEntree.WriteLine(this.ErrorMessage);
                }
            }
        }
    }
}
Do you have any suggestions?