.NET4.7.5中如何通过POST请求同时发送文件与自定义类?
.NET4.7.5下通过WebRequest同时上传STL文件与自定义类的实现问题
- 需求:通过
WebRequest发起HttpPost请求,同时发送固定路径(C:/Temp/Part.stl)的.stl文件和一个自定义类对象,期望请求为多部分表单格式,同时包含文件流与自定义类的结构化数据。 - 限制:必须使用.NET4.7.5框架,无法切换到其他版本。
- 现状:已知.NET6的WebApi中可通过
FileContentResult及ControllerBase.File()实现类似功能,但未找到.NET4.7.5的对应实现方式,当前编写的代码无法满足需求。
当前.NET4.7.5实现代码(结合NLogger)
private static bool PingServer(string server, object seDocument) { HttpWebRequest webRequest = WebRequest.CreateHttp($"http://{server}//stl"); webRequest.Timeout = 5000; //Default is 100.000 (100 seconds)... webRequest.Method = WebRequestMethods.Http.Post; Byte[] stlFile = System.IO.File.ReadAllBytes($@"{listTempFiles[0]}"); String base64String = Convert.ToBase64String(stlFile); //Note to future me, this doesn't need to be jsonified var json = JsonConvert.SerializeObject(seDocument); byte[] b = Encoding.UTF8.GetBytes(json); switch (System.IO.Path.GetExtension(listTempFiles[0])) { case ".stl": case ".STL": webRequest.ContentType = "application/sla"; break; case ".jt": case ".JT": webRequest.ContentType = "."; break; default: webRequest.ContentType = "application/json"; break; } webRequest.ContentLength = b.Length; using (var stream = webRequest.GetRequestStream()) { stream.Write(b, 0, b.Length); } HttpWebResponse response; try { response = webRequest.GetResponse() as HttpWebResponse; } catch (Exception e) { LogManager.GetCurrentClassLogger().Info(e.Message); return false; } if (response != null) { LogManager.GetCurrentClassLogger() .Info($"'{server}' responded with status '{response.StatusCode.ToString()}'"); } return response == null || response.StatusCode == HttpStatusCode.OK; }
.NET6 WebApi参考实现代码
[HttpGet("{mainpath}/{true}")] public List<MendixFile> GetAll(string mainpath) { List<MendixFile> mendixFiles = new List<MendixFile>(); string[] files = Directory.GetFiles(mainpath, "*", searchOption: SearchOption.AllDirectories); foreach (string file in files) { Byte[] b = System.IO.File.ReadAllBytes($@"{file}"); string path = Path.GetDirectoryName(file); string name= Path.GetFileName(file); MendixFile mendixFile = new MendixFile(path, name, b); File(b, "image/jpg"); mendixFiles.Add(mendixFile); } return mendixFiles; }
解决方案(.NET4.7.5下实现多部分表单上传)
要同时发送文件和自定义类,需要构造multipart/form-data格式的请求,这是上传混合数据的标准格式,.NET4.7.5可通过手动拼接边界符、表单字段和文件流实现:
private static bool PingServer(string server, object seDocument) { var boundary = $"----WebKitFormBoundary{Guid.NewGuid():N}"; HttpWebRequest webRequest = WebRequest.CreateHttp($"http://{server}/stl"); webRequest.Timeout = 5000; webRequest.Method = WebRequestMethods.Http.Post; webRequest.ContentType = $"multipart/form-data; boundary={boundary}"; // 读取固定路径的STL文件 byte[] stlFileBytes = System.IO.File.ReadAllBytes(@"C:/Temp/Part.stl"); // 序列化自定义类为JSON string seDocJson = JsonConvert.SerializeObject(seDocument); using (var requestStream = webRequest.GetRequestStream()) using (var writer = new StreamWriter(requestStream, Encoding.UTF8)) { // 写入自定义类表单字段 writer.WriteLine($"--{boundary}"); writer.WriteLine("Content-Disposition: form-data; name=\"seDocument\""); writer.WriteLine("Content-Type: application/json"); writer.WriteLine(); writer.Write(seDocJson); writer.WriteLine(); // 写入STL文件字段 writer.WriteLine($"--{boundary}"); writer.WriteLine("Content-Disposition: form-data; name=\"stlFile\"; filename=\"Part.stl\""); writer.WriteLine("Content-Type: application/sla"); writer.WriteLine(); writer.Flush(); // 确保文本内容写入流 requestStream.Write(stlFileBytes, 0, stlFileBytes.Length); writer.WriteLine(); // 写入结束边界 writer.WriteLine($"--{boundary}--"); writer.Flush(); } HttpWebResponse response; try { response = webRequest.GetResponse() as HttpWebResponse; } catch (Exception e) { LogManager.GetCurrentClassLogger().Info(e.Message); return false; } if (response != null) { LogManager.GetCurrentClassLogger() .Info($"'{server}' responded with status '{response.StatusCode.ToString()}'"); response.Close(); } return response != null && response.StatusCode == HttpStatusCode.OK; }
关键说明
- 原代码仅发送了自定义类的JSON数据,未包含STL文件,且ContentType设置错误(需用
multipart/form-data而非单一的application/sla或application/json) - 构造multipart/form-data时需严格遵循格式:每个数据块以边界符开头,包含
Content-Disposition和Content-Type头,最后以--边界符--结束 - 写入流时需先Flush文本内容,再写入二进制文件流,避免编码冲突
内容的提问来源于stack exchange,提问作者Wilkret
相关产品推荐
相关产品推荐

