在C#开发中,实现文件上传功能的核心是通过Post请求将文件的二进制数据发送到服务端,整个过程需要正确处理请求头、数据格式和流读取逻辑,下面介绍两种常用的实现方案。

方案一:使用HttpClient实现文件上传
HttpClient是.NET Framework 4.5及以上版本和.NET Core中推荐的HTTP请求类,使用它实现文件上传代码更简洁,维护成本更低。
核心实现步骤
- 创建HttpClient实例,配置请求的基础地址
- 读取本地文件的二进制流,构造MultipartFormDataContent类型的请求内容
- 发送Post请求并获取服务端响应结果
完整代码示例
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
class FileUploadHelper
{
/// <summary>
/// 使用HttpClient上传文件
/// </summary>
/// <param name="filePath">本地文件路径</param>
/// <param name="uploadUrl">服务端上传接口地址</param>
/// <returns>上传结果</returns>
public static async Task<string> UploadFileWithHttpClient(string filePath, string uploadUrl)
{
// 创建HttpClient实例
using (HttpClient client = new HttpClient())
{
// 读取文件流
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
// 构造multipart表单内容
MultipartFormDataContent formData = new MultipartFormDataContent();
// 添加文件内容,参数名根据服务端要求调整
formData.Add(new StreamContent(fileStream), "file", Path.GetFileName(filePath));
// 发送Post请求
HttpResponseMessage response = await client.PostAsync(uploadUrl, formData);
// 确保请求成功
response.EnsureSuccessStatusCode();
// 读取响应内容
return await response.Content.ReadAsStringAsync();
}
}
}
}
// 调用示例
class Program
{
static async Task Main(string[] args)
{
string localFilePath = @"D:testexample.jpg";
string serverUploadUrl = "http://ipipp.com/api/upload";
try
{
string result = await FileUploadHelper.UploadFileWithHttpClient(localFilePath, serverUploadUrl);
Console.WriteLine($"上传成功,响应结果:{result}");
}
catch (Exception ex)
{
Console.WriteLine($"上传失败,错误信息:{ex.Message}");
}
}
}
方案二:使用HttpWebRequest实现文件上传
如果需要兼容更早的.NET Framework版本,可以使用HttpWebRequest类实现文件上传,这种方式需要手动处理请求头和二进制数据的拼接。
核心实现步骤
- 创建HttpWebRequest实例,设置请求方法为POST,配置Content-Type为multipart/form-data并生成边界标识
- 拼接请求头、边界、文件内容和结束边界的二进制数据
- 将拼接好的数据写入请求流,获取服务端响应
完整代码示例
using System;
using System.IO;
using System.Net;
using System.Text;
class FileUploadHelper
{
/// <summary>
/// 使用HttpWebRequest上传文件
/// </summary>
/// <param name="filePath">本地文件路径</param>
<param name="uploadUrl">服务端上传接口地址</param>
/// <returns>上传结果</returns>
public static string UploadFileWithHttpWebRequest(string filePath, string uploadUrl)
{
// 生成multipart边界标识
string boundary = "----" + DateTime.Now.Ticks.ToString("x");
// 创建请求实例
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uploadUrl);
request.Method = "POST";
// 设置Content-Type,包含边界
request.ContentType = $"multipart/form-data; boundary={boundary}";
request.KeepAlive = true;
// 拼接请求数据
using (Stream requestStream = request.GetRequestStream())
{
// 写入边界开始标识
string boundaryStart = $"--{boundary}rn";
byte[] boundaryStartBytes = Encoding.UTF8.GetBytes(boundaryStart);
requestStream.Write(boundaryStartBytes, 0, boundaryStartBytes.Length);
// 写入文件头信息,参数名根据服务端要求调整
string fileHeader = $"Content-Disposition: form-data; name="file"; filename="{Path.GetFileName(filePath)}"rnContent-Type: application/octet-streamrnrn";
byte[] fileHeaderBytes = Encoding.UTF8.GetBytes(fileHeader);
requestStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);
// 写入文件二进制内容
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
requestStream.Write(buffer, 0, bytesRead);
}
}
// 写入边界结束标识
string boundaryEnd = $"rn--{boundary}--rn";
byte[] boundaryEndBytes = Encoding.UTF8.GetBytes(boundaryEnd);
requestStream.Write(boundaryEndBytes, 0, boundaryEndBytes.Length);
}
// 获取响应
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
return reader.ReadToEnd();
}
}
}
}
}
// 调用示例
class Program
{
static void Main(string[] args)
{
string localFilePath = @"D:testexample.jpg";
string serverUploadUrl = "http://ipipp.com/api/upload";
try
{
string result = FileUploadHelper.UploadFileWithHttpWebRequest(localFilePath, serverUploadUrl);
Console.WriteLine($"上传成功,响应结果:{result}");
}
catch (Exception ex)
{
Console.WriteLine($"上传失败,错误信息:{ex.Message}");
}
}
}
两种方案对比
两种实现方式的核心差异如下,开发者可以根据项目需求选择:
| 对比项 | HttpClient方案 | HttpWebRequest方案 |
|---|---|---|
| 适用框架 | .NET Framework 4.5+、.NET Core、.NET 5+ | 所有.NET Framework版本 |
| 代码复杂度 | 低,无需手动拼接二进制数据 | 高,需要手动处理边界和数据拼接 |
| 维护成本 | 低,API设计更友好 | 高,需要自行处理更多细节 |
| 异步支持 | 原生支持异步,性能更好 | 需要手动实现异步逻辑 |
注意事项
- 上传大文件时需要调整服务端的请求大小限制,避免请求被拦截
- 文件参数名需要和后端接口的接收参数名保持一致,否则会导致后端无法获取文件
- 如果上传需要携带认证信息,可以在请求头中添加对应的认证字段,比如Authorization头
- 实际应用中建议添加上传进度监控、断点续传等扩展功能,提升用户体验