using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading; using System.Web; using System.Windows.Forms; namespace AppTime { class WebServer { HttpListener listener; Thread thread; //public HttpListenerRequest Request; //public HttpListenerResponse Response; public string WebRootPath; HashSet defaultPage = new HashSet(StringComparer.OrdinalIgnoreCase){ "index.html", "index.htm", "default.html", "default.htm" }; public void Start(int port, object controller, string webfolder = "web") { thread = new Thread(() => { WebRootPath = webfolder = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), webfolder); var folders = Directory.GetDirectories(webfolder, "*", SearchOption.AllDirectories); var webroot = $@"http://localhost:{port}/"; listener = new HttpListener(); foreach (var f in folders) { listener.Prefixes.Add(webroot + f.Substring(webfolder.Length + 1).Replace("\\", "/") + "/"); } listener.Prefixes.Add(webroot); listener.Start(); while (true) { var ctx = listener.GetContext(); //Debug.WriteLine($"Web Request:{ctx.Request.Url}"); //ThreadPool.QueueUserWorkItem(_ => processRequest(ctx, webfolder, controller)); new Thread(() => processRequest( ctx, webfolder, controller) ) { IsBackground = true, Name = "WebServer Process Request" }.Start(); } }) { Name = "WebServer", IsBackground = true }; thread.Start(); } void processRequest(HttpListenerContext context, string webfolder, object controller) { var request = context.Request; var file = webfolder + request.RawUrl.Replace("/", "\\"); string query = ""; var p = file.IndexOf("?"); if (p > 0) { query = file.Substring(p + 1); file = file.Substring(0, p); } var response = context.Response; byte[] data = null; if (Path.GetFileName(Path.GetDirectoryName(file)).Equals("data", StringComparison.OrdinalIgnoreCase)) { try { if (string.IsNullOrWhiteSpace(query)) { using var reader = new StreamReader(request.InputStream); query = reader.ReadToEnd(); } var info = JObject.Parse(HttpUtility.UrlDecode(query)); var method = controller.GetType().GetMethod(Path.GetFileName(file)); var args = info.Value("args").Cast().ToArray(); var @params = method.GetParameters(); for (var i = 0; i < args.Length; i++) { if (args[i] is JObject jo) { args[i] = jo.ToObject(@params[i].ParameterType); } else { args[i] = Convert.ChangeType(args[i], @params[i].ParameterType); } } var result = method.Invoke(controller, args); if (result is byte[] bytes) { data = bytes; } else { data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(result)); } } catch (Exception ex) { data = Encoding.UTF8.GetBytes($"bad request: method:{Path.GetFileName(file)} query:{query}"); } } else { if (Directory.Exists(file)) { var def = Directory.GetFiles(file).FirstOrDefault(f => defaultPage.Contains(Path.GetFileName(f), StringComparer.OrdinalIgnoreCase)); if (def != null) { file = def; } } if (File.Exists(file)) { var mime = MimeMapping.GetMimeMapping(file); response.Headers.Add("Content-type", mime); if (mime.StartsWith("text/")) { response.ContentEncoding = Encoding.GetEncoding("utf-8"); data = Encoding.UTF8.GetBytes(File.ReadAllText(file, Encoding.Default)); } else { data = File.ReadAllBytes(file); } } } if (data == null) { data = Encoding.UTF8.GetBytes($"file not found: {file}"); } response.ContentLength64 = data.Length; var output = response.OutputStream; try { output.Write(data, 0, data.Length); } catch (HttpListenerException ex) { } output.Close(); } public void Stop() { thread.Abort(); listener.Stop(); listener.Close(); } } }