凌峰创科服务平台

C Winform如何上传文件到服务器?

我们将使用 HTTP POST 请求multipart/form-data 格式,这是上传文件最标准和可靠的方式。

C Winform如何上传文件到服务器?-图1
(图片来源网络,侵删)

整体架构

  1. 客户端: 一个 WinForms 应用程序,包含一个文件选择按钮和一个上传按钮。
  2. 服务器: 一个简单的 ASP.NET Web API 项目,它接收 HTTP 请求,保存文件到服务器的指定文件夹,并返回一个响应。

第一步:创建 WinForms 客户端项目

  1. 打开 Visual Studio,创建一个新的项目。
  2. 选择 "Windows Forms App (.NET Framework)" 或 "Windows Forms App" (.NET 6/7/8)。
  3. 给你的项目命名,WinFileUploader

设计窗体

打开 Form1.cs [Design],从工具箱中拖拽以下控件到窗体上:

  • Button (Name: btnSelectFile, Text: "选择文件")
  • TextBox (Name: txtFilePath, ReadOnly: True)
  • Button (Name: btnUpload, Text: "上传文件")
  • ProgressBar (Name: progressBar, Visible: False)
  • Label (Name: lblStatus, Text: "请选择文件...")

你的窗体设计应该看起来像这样:

编写客户端代码

双击 btnSelectFilebtnUpload 按钮,为它们生成 Click 事件处理程序。

Form1.cs 的代码文件中,添加以下 using 指令和代码:

C Winform如何上传文件到服务器?-图2
(图片来源网络,侵删)
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFileUploader
{
    public partial class Form1 : Form
    {
        // 创建一个静态的 HttpClient 实例,避免重复创建,提高性能
        private static readonly HttpClient client = new HttpClient();
        public Form1()
        {
            InitializeComponent();
        }
        private void btnSelectFile_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.InitialDirectory = "c:\\";
                openFileDialog.Filter = "所有文件 (*.*)|*.*|文本文件 (*.txt)|*.txt|图片文件 (*.jpg;*.png)|*.jpg;*.png";
                openFileDialog.FilterIndex = 1;
                openFileDialog.RestoreDirectory = true;
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    // 获取选中的文件路径
                    txtFilePath.Text = openFileDialog.FileName;
                    lblStatus.Text = "文件已选择,可以上传。";
                }
            }
        }
        private async void btnUpload_Click(object sender, EventArgs e)
        {
            // 检查是否选择了文件
            if (string.IsNullOrEmpty(txtFilePath.Text))
            {
                MessageBox.Show("请先选择一个文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            string filePath = txtFilePath.Text;
            string fileName = Path.GetFileName(filePath);
            // 检查文件是否存在
            if (!File.Exists(filePath))
            {
                MessageBox.Show("文件不存在!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            // 禁用上传按钮,防止重复点击
            btnUpload.Enabled = false;
            progressBar.Visible = true;
            progressBar.Value = 0;
            lblStatus.Text = "上传中...";
            try
            {
                // 创建一个 MultipartFormDataContent 对象
                using (var multipartFormContent = new MultipartFormDataContent())
                {
                    // 1. 将文件流添加到 multipart 内容中
                    // "file" 是服务器端用来识别这个字段的 key
                    // fileName 是上传给服务器的文件名
                    var fileStreamContent = new StreamContent(File.OpenRead(filePath));
                    multipartFormContent.Add(fileStreamContent, "file", fileName);
                    // 2. (可选)可以添加额外的文本字段
                    multipartFormContent.Add(new StringContent("This is a test upload"), "description");
                    // 3. 发送 HTTP POST 请求
                    // !!! 请将这里的 URL 替换为你自己的服务器 API 地址 !!!
                    var apiUrl = "http://localhost:5001/api/upload"; 
                    // 使用 HttpClient 发送请求并获取响应
                    using (var response = await client.PostAsync(apiUrl, multipartFormContent))
                    {
                        // 检查响应是否成功 (状态码 2xx)
                        response.EnsureSuccessStatusCode();
                        // 读取响应内容
                        string responseBody = await response.Content.ReadAsStringAsync();
                        MessageBox.Show("上传成功!服务器响应: " + responseBody, "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        lblStatus.Text = "上传完成。";
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("上传失败: " + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                lblStatus.Text = "上传失败。";
            }
            finally
            {
                // 无论成功失败,都重新启用按钮并隐藏进度条
                btnUpload.Enabled = true;
                progressBar.Visible = false;
            }
        }
    }
}

代码解释:

  • HttpClient: 用于发送 HTTP 请求,我们将其声明为 static readonly,因为它可以在整个应用中被复用,并且是线程安全的。
  • OpenFileDialog: 一个标准的 Windows 对话框,用于让用户选择文件。
  • MultipartFormDataContent: 这是构建 multipart/form-data 请求的核心类,你可以向它添加多个部分,包括文件流和文本数据。
  • StreamContent: 用于将文件流包装成一个可以发送的 HTTP 内容部分。
  • client.PostAsync: 异步发送 POST 请求,这是现代 .NET 推荐的做法,不会阻塞 UI 线程,从而保持应用程序的响应性。
  • EnsureSuccessStatusCode(): 如果服务器返回的状态码不是成功的(404 Not Found 或 500 Internal Server Error),它会抛出异常。
  • try...catch...finally: 用于优雅地处理可能发生的错误,并确保在操作完成后 UI 能恢复到正常状态。

第二步:创建服务器端项目 (ASP.NET Web API)

这个项目将接收客户端上传的文件。

  1. 在同一个 Visual Studio 解决方案中,右键点击 "解决方案资源管理器" -> "添加" -> "新项目"。
  2. 选择 "ASP.NET Core Web API"。
  3. 给项目命名,FileUploadServer
  4. 在 "其他信息" 页面,确保选中 "使用控制器"。

配置服务器

  1. 允许大文件上传 打开 Program.cs (对于 .NET 6+) 或 Startup.cs (对于 .NET 5 及更早版本),添加或修改以下代码来增加上传文件的大小限制。

    Program.cs 中 (.NET 6+):

    C Winform如何上传文件到服务器?-图3
    (图片来源网络,侵删)
    var builder = WebApplication.CreateBuilder(args);
    // 添加服务到容器。
    builder.Services.AddControllers();
    // --- 添加以下代码 ---
    // 配置 Kestrel 服务器允许更大的请求体
    builder.WebHost.ConfigureKestrel(options =>
    {
        options.Limits.MaxRequestBodySize = 64 * 1024 * 1024; // 64 MB
    });
    // --- 代码结束 ---
    var app = builder.Build();
    // ... 其余代码 ...
  2. 创建上传目录 在项目的根目录下,创建一个名为 Uploads 的文件夹,这个文件夹将用来保存上传的文件。

  3. 创建上传控制器 在 "Controllers" 文件夹中,右键点击 -> "添加" -> "控制器" -> "API 控制器 - 空"。 命名为 UploadController.cs

    然后用以下代码替换 UploadController.cs 的内容:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Http;
    using System.IO;
    using System.Threading.Tasks;
    using System;
    namespace FileUploadServer.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class UploadController : ControllerBase
        {
            // 定义一个静态变量来存储上传目录的路径
            // 在实际应用中,你可能需要从配置文件中读取
            private static readonly string _uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "Uploads");
            public UploadController()
            {
                // 确保上传目录存在
                if (!Directory.Exists(_uploadsFolder))
                {
                    Directory.CreateDirectory(_uploadsFolder);
                }
            }
            [HttpPost]
            public async Task<IActionResult> Upload(IFormFile file)
            {
                // 检查是否有文件被上传
                if (file == null || file.Length == 0)
                {
                    return BadRequest(new { message = "没有选择文件或文件为空。" });
                }
                try
                {
                    // 为文件生成一个唯一的文件名,防止覆盖
                    var fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);
                    var filePath = Path.Combine(_uploadsFolder, fileName);
                    // 将文件保存到服务器硬盘
                    using (var
分享:
扫描分享到社交APP
上一篇
下一篇