美文网首页
c# winform post文件上传案例代码

c# winform post文件上传案例代码

作者: 吉凶以情迁 | 来源:发表于2025-01-08 18:01 被阅读0次

首先起源于post form java 代码,
再给同事用c#的时候我发现ai给的答案有问题 用的using写法,这导致提示

HTTP 请求错误:将内容复制到流时出错。
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   在 WindowsFormsApp1.Form1.<UploadFilesAsync>d__3.MoveNext()
Inner Exception:无法访问已关闭的流。
Inner Exception StackTrace:   在 System.IO.__Error.StreamIsClosed()
   在 System.IO.MemoryStream.get_Position()
   在 System.Net.Http.StreamToStreamCopy.StartAsy

我直接改成try catch写法解决了此问题

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            textBox1.Text = "D:\\Users\\Downloads\\aaa.png"; // 设置初始文件路径
        }

        private async void btnUpload_Click(object sender, EventArgs e)
        {
            string url = "http://xxx/api/xxx/Upload";
            string machine = "xxx";
            string lineid = "1";
            string workOrder = "1";

            List<string> filePaths = new List<string>();

            if (!string.IsNullOrEmpty(textBox1.Text) && File.Exists(textBox1.Text)) {
                filePaths.Add(textBox1.Text);
            }

            using (OpenFileDialog openFileDialog = new OpenFileDialog()) {
                openFileDialog.Multiselect = true;
                if (openFileDialog.ShowDialog() == DialogResult.OK) {
                    filePaths.AddRange(openFileDialog.FileNames);
                }
            }

            if (filePaths.Count == 0) {
                MessageBox.Show("请选择要上传的文件。");
                return;
            }

            try {
                string result = await UploadFilesAsync(filePaths, url, machine, lineid, workOrder);
                MessageBox.Show("上传结果:\r\n" + result);
            }
            catch (Exception ex) {
                MessageBox.Show($"上传失败:\r\n{ex.Message}\r\nStackTrace:\r\n{ex.StackTrace}");
                Debug.WriteLine($"上传失败:{ex.Message}\r\n{ex.StackTrace}");
                if (ex.InnerException != null) {
                    MessageBox.Show($"内部异常:\r\n{ex.InnerException.Message}\r\nStackTrace:\r\n{ex.InnerException.StackTrace}");
                    Debug.WriteLine($"内部异常:{ex.InnerException.Message}\r\n{ex.InnerException.StackTrace}");
                }
            }
        }

        public async Task<string> UploadFilesAsync(List<string> filePaths, string url, string machine, string lineid, string workOrder)
        {
            using (var client = new HttpClient())
            using (var formData = new MultipartFormDataContent()) {
                client.Timeout = TimeSpan.FromMinutes(10);

                // 添加其他参数
                formData.Add(new StringContent("1"), "mid");
                formData.Add(new StringContent(""), "savePath");
                formData.Add(new StringContent("0"), "type");
                formData.Add(new StringContent("XXXX", Encoding.UTF8), "descript");
                formData.Add(new StringContent(machine, Encoding.UTF8), "machine");
                formData.Add(new StringContent(lineid, Encoding.UTF8), "lineid");
                formData.Add(new StringContent(workOrder, Encoding.UTF8), "workorder");
                formData.Add(new StringContent("luo", Encoding.UTF8), "username");

                foreach (string filePath in filePaths) {
                    if (!File.Exists(filePath)) {
                        string errorMessage = $"文件不存在:{filePath}";
                        Debug.WriteLine(errorMessage);
                        return errorMessage;
                    }

                    try {
                        byte[] fileBytes = File.ReadAllBytes(filePath); // 直接读取字节数组
                        Debug.WriteLine($"正在上传文件:{filePath},大小:{fileBytes.Length} 字节");

                        // 直接使用 ByteArrayContent
                        var fileContent = new ByteArrayContent(fileBytes);
                        fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
                            Name = "\"files\"", // 确保服务器端参数名正确
                            FileName = "\"" + Path.GetFileName(filePath) + "\""
                        };
                        formData.Add(fileContent);

                        Debug.WriteLine($"已将文件 {filePath} 添加到 FormDataContent");

                        // 重要:释放 byte[],避免长时间占用内存
                        fileBytes = null;
                        GC.Collect(); // 强制垃圾回收(谨慎使用,一般不需要)
                    }
                    catch (IOException ioEx) {
                        string errorMessage = $"读取文件 {filePath} 时发生错误:{ioEx.Message}";
                        Debug.WriteLine(errorMessage);
                        return errorMessage;
                    }
                }

                try {
                    Debug.WriteLine("开始发送 HTTP 请求...");
                    var response = await client.PostAsync(url, formData);
                    Debug.WriteLine($"HTTP 响应状态码:{response.StatusCode}");
                    response.EnsureSuccessStatusCode();
                    string responseContent = await response.Content.ReadAsStringAsync();
                    Debug.WriteLine($"HTTP 响应内容:{responseContent}");
                    return responseContent;
                }
                catch (HttpRequestException e) {
                    string errorMessage = $"HTTP 请求错误:{e.Message}\r\n{e.StackTrace}\r\nInner Exception:{e.InnerException?.Message}\r\nInner Exception StackTrace:{e.InnerException?.StackTrace}";
                    Debug.WriteLine(errorMessage);
                    return errorMessage;
                }
            }
        }
    }
}

解释:

完全移除了 MemoryStream 和 StreamContent 的使用,并直接使用 ByteArrayContent 来处理文件上传。这解决了之前所有与流关闭和异步操作竞争相关的问题。

移除 FileItem 类: ,直接使用 List<string> 来存储文件路径,不再需要 FileItem 类。这减少了代码的复杂性,并避免了不必要的对象创建。

直接使用 ByteArrayContent: 这是最关键的改动。之前的代码中使用 MemoryStream 将文件内容加载到内存中,然后使用 StreamContent 将 MemoryStream 包装成 HTTP 内容。虽然使用了 using 语句来释放 MemoryStream,但由于 HttpClient 的 PostAsync 方法是异步的,它可能会在 using 语句块结束后才真正开始读取 MemoryStream 的内容,导致“无法访问已关闭的流”的异常。

现在的代码直接使用 File.ReadAllBytes(filePath) 将文件内容读取到 byte[] 数组中,然后使用 ByteArrayContent(fileBytes) 直接创建 HTTP 内容。ByteArrayContent 内部会持有 byte[] 数组的副本,因此即使原始的 fileBytes 变量超出了作用域,ByteArrayContent 仍然可以安全地访问文件内容。这样就彻底避免了流关闭的问题。


byte[] fileBytes = File.ReadAllBytes(filePath); // 直接读取字节数组
var fileContent = new ByteArrayContent(fileBytes); // 直接使用 ByteArrayContent
移除 MemoryStream 和 StreamContent 的 using 语句: 由于不再使用 MemoryStream 和 StreamContent,因此相关的 using 语句也被移除了。

初始文本框文件处理: 修改了上传按钮事件,如果初始文本框有值且文件存在则加入上传列表。

释放 byte[]: 在将 ByteArrayContent 添加到 formData 之后,添加了以下代码:

C#

fileBytes = null;
GC.Collect();

将 fileBytes 设置为 null 可以解除对字节数组的引用,使其可以被垃圾回收器回收。调用 GC.Collect() 是一个强制垃圾回收的请求。但是,通常情况下,.NET 的垃圾回收器会自动管理内存,因此不需要显式调用 GC.Collect()。 只有在内存占用非常关键的情况下(例如上传非常多的超大文件),才应该考虑使用它。在大多数情况下,可以省略 GC.Collect()。

那之前有问题的代码是:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinFormsFileUpload
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private async void btnUpload_Click(object sender, EventArgs e)
        {
            string url = "http://111.11.11.11/api/Upload";
            string machine = txtMachine.Text; // 从文本框获取机器信息
            string lineid = txtLineId.Text;     // 从文本框获取线体 ID
            string workOrder = txtWorkOrder.Text; // 从文本框获取工单号

            List<FileItem> itemList = new List<FileItem>();
            // 添加要上传的文件路径,这里使用 OpenFileDialog 让用户选择文件
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Multiselect = true; // 允许选择多个文件
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    foreach (string filePath in openFileDialog.FileNames)
                    {
                        itemList.Add(new FileItem { Name = filePath });
                    }
                }
                else
                {
                    MessageBox.Show("请选择要上传的文件。");
                    return; // 用户取消选择
                }
            }
            if (itemList.Count == 0)
            {
                MessageBox.Show("请选择要上传的文件。");
                return;
            }

            try
            {
                string result = await UploadFilesAsync(itemList, url, machine, lineid, workOrder);
                MessageBox.Show("上传结果:\r\n" + result);
            }
            catch (Exception ex)
            {
                MessageBox.Show("上传失败:\r\n" + ex.Message);
            }
        }

        public async Task<string> UploadFilesAsync(List<FileItem> itemList, string url, string machine, string lineid, string workOrder)
        {
            using (var client = new HttpClient())
            using (var formData = new MultipartFormDataContent())
            {
                formData.Add(new StringContent("1"), "mid");
                formData.Add(new StringContent(""), "savePath");
                formData.Add(new StringContent("0"), "type");
                formData.Add(new StringContent("PDA上传"), "descript");
                formData.Add(new StringContent(machine,Encoding.UTF8), "machine");//解决中文乱码
                formData.Add(new StringContent(lineid,Encoding.UTF8), "lineid");//解决中文乱码
                formData.Add(new StringContent(workOrder,Encoding.UTF8), "workorder");//解决中文乱码
                formData.Add(new StringContent(SuperContext.getUserName(),Encoding.UTF8), "username");//解决中文乱码

                foreach (var fileItem in itemList)
                {
                    FileInfo fileCurrent = new FileInfo(fileItem.Name);
                    if (fileCurrent.Exists)
                    {
                        using (var fileStream = fileCurrent.OpenRead()){
                            var fileContent = new StreamContent(fileStream);
                            fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
                            {
                                Name = "\"files\"",
                                FileName = "\"" + fileCurrent.Name + "\""
                            };
                            formData.Add(fileContent);
                        }

                    }
                    else
                    {
                        Console.WriteLine($"文件不存在:{fileCurrent.FullName}");
                        return $"文件不存在:{fileCurrent.FullName}";//返回错误信息
                    }
                }

                try
                {
                    var response = await client.PostAsync(url, formData);
                    response.EnsureSuccessStatusCode();//如果请求不成功会抛出异常
                    return await response.Content.ReadAsStringAsync();
                }
                catch (HttpRequestException e)
                {
                    return $"请求错误:{e.Message}";
                }
            }
        }

        public class FileItem
        {
            public string Name { get; set; }
        }

        public static class SuperContext
        {
            public static string getUserName()
            {
                return "testuser"; // 你需要替换为实际的用户名获取逻辑
            }
        }
    }
}

相关文章

网友评论

      本文标题:c# winform post文件上传案例代码

      本文链接:https://www.haomeiwen.com/subject/alosyjtx.html