using Models; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Service; using SqlSugar; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace ServerApp.WebServer { public class WebService { public string dbConStr; private HttpListener svcHttpListener; public Action LogEvent; public Action GetReportEvent; private void logEvent(string msg, string warn = "正常") { LogEvent?.Invoke(warn, msg); } private void getReportEvent(UploadDataRecords data) { GetReportEvent?.Invoke(data); } RecordsService service = new RecordsService(); public void start(string HttpIP, int HttpPort) { try { if (HttpPort > 0) { //logEvent("Web服务启动..."); this.svcHttpListener = new HttpListener(); List lstIp = HttpUtil.getLocalIPList(); //logEvent($"Web服务已启动,运行于端口:{Config.LocalHttpPort.ToString()}, 监听Ip:{string.Join("|", lstIp)}"); //if (!string.IsNullOrWhiteSpace(Config.LocalIp) && lstIp.FindIndex(m => m.Contains(Config.LocalIp)) >= 0)//没指定IP/指定的不对 //{ // lstIp.Clear(); // lstIp.Add(Config.LocalIp); //} //lstIp.Clear(); if (lstIp.Count < 1) { lstIp.Add(HttpIP); lstIp.Add("127.0.0.1"); } logEvent($"Web服务已启动,运行于端口:{HttpPort.ToString()}, 监听Ip:{string.Join("|", lstIp)}"); //for (int i = 0; i < lstIp.Count; i++) // this.svcHttpListener.Prefixes.Add("http://" + lstIp[i] + ":" + HttpPort.ToString() + "/"); this.svcHttpListener.Prefixes.Add("http://*:" + HttpPort.ToString() + "/"); //svcHttpListener.Prefixes.Add($"https://+:{HttpPort}"); this.svcHttpListener.Start(); //logEvent($"Web服务已启动,运行于端口:{Config.LocalHttpPort.ToString()}, 监听Ip:{string.Join("|", lstIp)}"); //this.svcHttpListener.GetContext().Response.AppendHeader("Access-Control-Allow-Origin", "*");//后台跨域请求,通常设置为配置文件 //this.svcHttpListener.GetContext().Response.AppendHeader("Access-Control-Allow-Credentials", "true"); //后台跨域请求 this.svcHttpListener.BeginGetContext(new AsyncCallback(this.GetContextCallBack), this.svcHttpListener); } //------WEB Socket //if (Config.localIp != "" && Config.localSocketPort > 0) //{ // logEvent( "WebSocket服务启动..."); // this.wssv = new WebSocketServer(Config.localSocketPort); // this.wssv.AddWebSocketService("/socket1"); // this.wssv.Start(); // logEvent( "WebSocket服务已启动。"); //} } catch (Exception ex) { logEvent("Web服务启动失败,ex=" + ex.Message, "错误"); } } public void stop() { logEvent("正在停止WEB服务..."); try { if (this.svcHttpListener != null && this.svcHttpListener.IsListening) { this.svcHttpListener.Stop(); this.svcHttpListener.Close(); this.logEvent("Web服务已停止!"); } //if (this.svcWebSocket != null && this.svcWebSocket.IsListening) //{ // this.svcWebSocket.Stop(); // this.svcWebSocket = null; // this.AddTextEvent("WebSocket", "WebSocket服务已停止!"); //} } catch (Exception ex) { logEvent("Web服务停止失败,ex=" + ex.Message, "错误"); } } private void GetContextCallBack(IAsyncResult ar) { this.svcHttpListener = (ar.AsyncState as HttpListener); HttpListenerContext httpListenerContext; try { httpListenerContext = this.svcHttpListener.EndGetContext(ar); //httpListenerContext.Response.AppendHeader("Access-Control-Allow-Origin", "*");//后台跨域请求,通常设置为配置文件 //httpListenerContext.Response.AppendHeader("Access-Control-Allow-Credentials", "true"); //后台跨域请求 //httpListenerContext.Response.AppendHeader("Access-Control-Allow-Methods", "GET,POST"); httpListenerContext.Response.AddHeader("Access-Control-Allow-Origin", "*"); httpListenerContext.Response.AddHeader("Access-Control-Allow-Headers", "*"); httpListenerContext.Response.AddHeader("Access-Control-Allow-Methods", "*"); this.svcHttpListener.BeginGetContext(new AsyncCallback(this.GetContextCallBack), this.svcHttpListener); } catch (Exception ex) { logEvent("ex:" + ex.StackTrace, "错误"); return; } // string sessionId = Convert.ToInt32(DateTime.Now.ToString("mmssfff")).ToString();//.ToString("X"); string reqHttpMethod = httpListenerContext.Request.HttpMethod; string reqUrl = httpListenerContext.Request.RawUrl; string reqData = ""; try { this.logEvent($"{sessionId} / 收到请求:{reqHttpMethod} To Url:{reqUrl}"); reqData = HttpUtil.getPostData(httpListenerContext.Request); this.logEvent($"{sessionId} / 请求数据:{reqData}"); var subUrls = reqUrl.Trim(new char[] { '/' }).Split(new char[] { '/' }); if (subUrls[0].ToLower() == "static") { #region //string InputStream = ""; //上传的数据 //using (var streamReader = new StreamReader(httpListenerContext.Request.InputStream)) // InputStream = streamReader.ReadToEnd(); // string filePath = Config.appBasePath; string filePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); foreach (var sub in subUrls) filePath += "\\" + sub; if (!File.Exists(filePath)) filePath = filePath + "\\index.html"; if (!File.Exists(filePath)) { httpListenerContext.Response.ContentLength64 = 0; httpListenerContext.Response.StatusCode = 404; httpListenerContext.Response.Abort(); } else { httpListenerContext.Response.StatusCode = 200; string exeName = Path.GetExtension(filePath); httpListenerContext.Response.ContentType = HttpUtil.GetContentType(exeName); FileStream fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite); int byteLength = (int)fileStream.Length; byte[] fileBytes = new byte[byteLength]; fileStream.Read(fileBytes, 0, byteLength); fileStream.Close(); fileStream.Dispose(); httpListenerContext.Response.ContentLength64 = byteLength; httpListenerContext.Response.OutputStream.Write(fileBytes, 0, byteLength); //httpListenerContext.Response.OutputStream.Close(); } #endregion return; } if (reqData == null) throw new Exception("请求数据不可为空!"); httpListenerContext.Response.StatusCode = 200; JObject joReqData = JObject.Parse(reqData); string respText; JObject result = new JObject(); string sourceSessionId; switch (subUrls[0].ToLower()) { case "static": //上面已处理 break; case "test": HttpUtil.writeToHttpContext_text(httpListenerContext.Response, "测试回应!"); break; case "api": switch (subUrls[1].ToLower()) { //查询数据 case "query_table": #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = getTableList(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; //下载数据 case "get_defect_from_batch_reel"://读取缺陷文件名列表和JSON数组 #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = getDefectFromBatchReel(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; default: HttpUtil.writeToHttpContext_text(httpListenerContext.Response, "未知请求!"); break; } break; case "http_error": result.Add("code", -1); result.Add("msg", "不支持的请求协议!"); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{respText}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) { this.logEvent($"{sessionId} / http返回时连接已断开!"); //this.logEvent( id + " /http连接已断开," + (string.IsNullOrWhiteSpace(callback_url) ? "无法返回结果!" : "通过回调返回" + callback_url), 1); //if (callback_url != null && callback_url != "") // HttpUtil.post(callback_url, respText); } break; case "url_error": result.Add("code", -2); result.Add("msg", "URL地址错误!"); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{respText}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) { this.logEvent($"{sessionId} / http返回时连接已断开!"); //this.logEvent( id + " /http连接已断开," + (string.IsNullOrWhiteSpace(callback_url) ? "无法返回结果!" : "通过回调返回" + callback_url), 1); //if (callback_url != null && callback_url != "") // HttpUtil.post(callback_url, respText); } break; case "param_error": result.Add("code", -3); result.Add("msg", "参数错误!"); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{respText}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) { this.logEvent($"{sessionId} / http返回时连接已断开!"); //this.logEvent( id + " /http连接已断开," + (string.IsNullOrWhiteSpace(callback_url) ? "无法返回结果!" : "通过回调返回" + callback_url), 1); //if (callback_url != null && callback_url != "") // HttpUtil.post(callback_url, respText); } break; default: HttpUtil.writeToHttpContext_text(httpListenerContext.Response, "未知请求!"); break; } } catch (Exception ex) { this.logEvent($"{sessionId} / 异常:{ex.Message}\r\n{ex.StackTrace}", "错误"); httpListenerContext.Response.StatusCode = 500; } finally { try { httpListenerContext.Response.OutputStream.Close();//客户端断开时会异常 } catch { } } } /// /// 查询批号卷号数据 /// /// /// private JObject getTableList(JObject req) { JObject res = new JObject(); try { string model, batch = "", reel = "", order = ""; int totalCount = 0; if (req.ContainsKey("batch")) batch = req.Value("batch"); if (req.ContainsKey("reel")) reel = req.Value("reel"); var db = new SqlSugarClient(new ConnectionConfig() { DbType = SqlSugar.DbType.MySql, //InitKeyType = InitKeyType.Attribute, IsAutoCloseConnection = true, ConnectionString = dbConStr }); List datalist = db.Queryable() .Includes(m => m.DefectInfoList) .Includes(m => m.QualifiedLimitList) .Includes(m => m.GradeLimitList) .ToList(); List list = new List(); var Find = datalist.Where(d => d.BatchId == batch && d.ReelId.IndexOf(reel)>=0).ToList(); if (Find != null && Find.Count > 0) { totalCount = Find.Count; foreach (var d in Find) { list.Add($"PH:{d.BatchId},JH:{d.ReelId},FJH:{d.PartReelId}"); } } res.Add("code", 200); res.Add("data", JArray.FromObject(list)); res.Add("totalCount", totalCount); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } /// /// 获取并发送数据 /// /// /// private JObject getDefectFromBatchReel(JObject req) { int err = 0; JObject res = new JObject(); try { string batch = req.Value("batch"); string reel = req.Value("reel"); var db = new SqlSugarClient(new ConnectionConfig() { DbType = SqlSugar.DbType.MySql, //InitKeyType = InitKeyType.Attribute, IsAutoCloseConnection = true, ConnectionString = dbConStr }); var data = db.Queryable() .Includes(m => m.DefectInfoList) .Includes(m => m.QualifiedLimitList) .Includes(m => m.GradeLimitList) .First(m => m.BatchId == batch && m.ReelId == reel); err = 2; getReportEvent(data); string file_path = $"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\\temp.xlsx"; //--缺陷 if (!string.IsNullOrEmpty(file_path)) { if (!File.Exists(file_path)) throw new Exception(file_path + " 缺陷文件不存在!"); res.Add("code", 200); res.Add("data", Convert.ToBase64String(File.ReadAllBytes(file_path))); } else throw new Exception($"文件错误:file_name={file_path}"); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } } public static class HttpUtil { /// /// 获取本机IP地址列表 /// /// Wireless80211:本地所有IP(仅127.0.0.1);Ethernet:仅获取以太网接口的 IP 地址 public static List getLocalIPList(NetworkInterfaceType _type = NetworkInterfaceType.Unknown) { List output = new List(); foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces()) { if ((_type == NetworkInterfaceType.Unknown || item.NetworkInterfaceType == _type) && item.OperationalStatus == OperationalStatus.Up) { foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses) { if (ip.Address.AddressFamily == AddressFamily.InterNetwork) { //API.OutputDebugString($"{item.NetworkInterfaceType.ToString()}; {ip.Address.AddressFamily.ToString()}; {ip.Address.ToString()}"); output.Add(ip.Address.ToString()); } } } } return output; } //读取请求数据 public static string getPostData(HttpListenerRequest request) { if (!request.HasEntityBody) return null; string result; using (Stream inputStream = request.InputStream) { using (StreamReader streamReader = new StreamReader(inputStream, Encoding.UTF8)) result = streamReader.ReadToEnd(); } return result; } /// /// POST请求接口调用 /// /// /// /// public static void post(string url, string json, Action callBack = null) { System.Threading.ThreadPool.QueueUserWorkItem( new WaitCallback(o => { var data = (JObject)o; if (callBack == null) postSync(data["url"].ToString(), data["json"].ToString(), false); else callBack(postSync(data["url"].ToString(), data["json"].ToString())); }), JObject.FromObject(new { url, json }) ); } //HttpWebRequest方式 public static JObject postSync2(string url, string json, bool recvResp = true) { JObject resp = new JObject(); try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; //request.ContentType = "application/x-www-form-urlencoded"; request.ContentType = "application /json"; StreamWriter requestWriter = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.UTF8); requestWriter.Write(json); requestWriter.Flush(); requestWriter.Close(); if (recvResp) { WebResponse webResponse = request.GetResponse(); Stream webStream = webResponse.GetResponseStream(); StreamReader responseReader = new StreamReader(webStream); resp.Add("data", responseReader.ReadToEnd()); resp.Add("success", true); } else { request.GetResponse().Close();//必需调用此GetResponse后上面的write才会发送出去,操 resp.Add("data", ""); resp.Add("success", true); } } catch (Exception ex) { resp.Add("success", false); resp.Add("data", ex.Message); } return resp; } //HttpClient方式 public static JObject postSync(string url, string json, bool recvResp = true, bool isJson = false) { JObject resp = new JObject(); try { HttpClient http = new HttpClient(); StringContent dataContent; //第一种方式:data是json格式 if (isJson) dataContent = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); // {"PageNum":"1","PageSIze":"20","info":"311011500300661"} else { // 第二种方式:form表单提交 内容post 提交都在StringContent请求body中添加 string lsUrlEncodeStr = json2Params(JObject.Parse(json)); dataContent = new StringContent(lsUrlEncodeStr, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded"); //PageNum=1&PageSize=20&info=311011500300661 } http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "token"); var taskstr = http.PostAsync(url, dataContent).Result.Content.ReadAsStringAsync(); //API.OutputDebugString("wlq postSync:url=" + url + ";resp=" + taskstr.Result); //读取返回数据 //return taskstr.Result; if (recvResp) { resp.Add("data", taskstr.Result); resp.Add("success", true); } else { resp.Add("data", ""); resp.Add("success", true); } } catch (Exception ex) { resp.Add("success", false); resp.Add("data", ex.Message); } return resp; } /// /// 向HTTP连接写入数据 /// /// HttpListenerContext.Response /// /// 如果连接关闭返回 false public static bool writeToHttpContext(HttpListenerResponse resp, byte[] dataBuff) { try { resp.OutputStream.Write(dataBuff, 0, dataBuff.Length); resp.OutputStream.Flush(); return true; } catch (Exception ex) { return false; } } public static bool writeToHttpContext_json(HttpListenerResponse resp, string json) { byte[] buff = Encoding.UTF8.GetBytes(json); resp.ContentType = "application/json"; resp.ContentEncoding = Encoding.UTF8; return writeToHttpContext(resp, buff); } public static bool writeToHttpContext_text(HttpListenerResponse resp, string text) { byte[] buff = Encoding.UTF8.GetBytes(text); resp.ContentType = "application/text"; resp.ContentEncoding = Encoding.UTF8; return writeToHttpContext(resp, buff); } private static string json2Params(JObject json) { string result = ""; IEnumerable properties = json.Properties(); foreach (JProperty item in properties) { result += item.Name.ToString() + "=" + item.Value.ToString() + "&"; // item.Name 为 键 // item.Value 为 值 } result = result.Substring(0, result.Length - 1); //string result1 = WebUtility.UrlEncode(result);//转义字符大写 ////string result2 = HttpUtility.UrlEncode(result);//转义字符小写 return result; } /// /// 获取文件对应MIME类型 /// /// 文件扩展名,如.jpg /// public static string GetContentType(string fileExtention) { if (string.Compare(fileExtention, ".html", true) == 0 || string.Compare(fileExtention, ".htm", true) == 0) return "text/html;charset=utf-8"; else if (string.Compare(fileExtention, ".js", true) == 0) return "application/javascript"; else if (string.Compare(fileExtention, ".css", true) == 0) return "text/css"; else if (string.Compare(fileExtention, ".png", true) == 0) return "image/png"; else if (string.Compare(fileExtention, ".jpg", true) == 0 || string.Compare(fileExtention, ".jpeg", true) == 0) return "image/jpeg"; else if (string.Compare(fileExtention, ".gif", true) == 0) return "image/gif"; else if (string.Compare(fileExtention, ".swf", true) == 0) return "application/x-shockwave-flash"; else if (string.Compare(fileExtention, ".bcmap", true) == 0) return "image/svg+xml"; else if (string.Compare(fileExtention, ".properties", true) == 0) return "application/octet-stream"; else if (string.Compare(fileExtention, ".map", true) == 0) return "text/plain"; else if (string.Compare(fileExtention, ".svg", true) == 0) return "image/svg+xml"; else if (string.Compare(fileExtention, ".pdf", true) == 0) return "application/pdf"; else if (string.Compare(fileExtention, ".txt", true) == 0) return "text/*"; else if (string.Compare(fileExtention, ".dat", true) == 0) return "text/*"; else return "application/octet-stream";//application/octet-stream } } }