【C#】使用HttpClient上传文件到网站服务器和解决出错问题

第一次使用HttpClient上传文件到网站服务器时,尤其是如果长时间未进行操作,使用Https加密传输协议可能会遇到一些错误。针对这些潜在的问题,以下是一些解决方案,以帮助您顺利上传文件。

选择文件

例如,点击上传文件按钮,通过打开文件对话框来选择文件, 代码如下

var dialog = new Microsoft.Win32.OpenFileDialog();
dialog.Title = "选择上传的文件";
dialog.CheckFileExists = true;
dialog.Filter = "*.zip(压缩文件)|*.zip";
dialog.Multiselect = false;
if (dialog.ShowDialog() == true)
{
    DoUploadFileAsync(dialog.FileName).ContinueWith(res => {
        Debug.WriteLine($"responseText: {res.Result}");
    });
}

接下来实现上传文件的异步方法DoUploadFileAsync,输出返回响应的结果res.Result

上传文件

实现异步方法DoUploadFileAsync,使用HttpClient上传文件, 代码如下

internal async Task<string> DoUploadFileAsync(string filePath)
{
    try
    {
        var url = API_BASE_URL + "/Default.aspx?type=uploadfile";
		//System.Net.ServicePointManager.Expect100Continue = true;
        //System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls;
        using (var client = new HttpClient())
        {
            //client.Timeout = TimeSpan.FromSeconds(10);
            //client.DefaultRequestHeaders.Add("Referer", API_BASE_URL + "/");
			using (var formData = new MultipartFormDataContent())
			{
			    using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
			    {
			        var fileName = System.IO.Path.GetFileName(filePath);
			        using (var streamContent = new StreamContent(fileStream, (int)fileStream.Length))
			        {
			            //上传文件处理方式省略...
			
			            using (var response = await client.PostAsync(url, formData))
			            {
			                if (response.IsSuccessStatusCode)
			                {
			                    return await response.Content.ReadAsStringAsync();
			                }
			                else
			                {
			                    throw new Exception(">>> DoUploadFileAsync NoSuccessStatusCode");
			                }
			            }
			        }
			    }
			}
        }
    }
    catch(Exception ex)
    {
        Debug.WriteLine($">>>> DoUploadFileAsync Error:{ex.Message} \nStackTrace:{ex.StackTrace}");//发生一个或多个错误。
    }
    return string.Empty;
}

上传地址若是加密传输https协议, 就要设置 System.Net.ServicePointManager.SecurityProtocol 使用安全证书

ContentType

在上传文件处理方式中,使用不同的文件内容类型,

multipart/form-data

当使用内容类型为"multipart/form-data",代码如下

var fileContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
fileContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data");
formData.Add(fileContent, "file", fileName);

// 如果需要添加其他表单字段,可以继续添加,注意key与value对应
// form.Add(new StringContent("value"), "key");

上传文件时,后台服务器可能响应错误消息,提示路径包含非法字符,

大致可能是文件名有包含中文时乱码引起的,因此以上方法不适用,

application/octet-stream

当使用内容类型为application/octet-stream,改成如下

streamContent.Headers.Add("Content-Type", "application/octet-stream");
var bytes = Encoding.UTF8.GetBytes($"form-data; name=\"file\"; filename=\"{fileName}\"");

var headerValue = ;
foreach (var b in bytes) headerValue += (Char)b;
streamContent.Headers.Add("Content-Disposition", headerValue);

formData.Add(streamContent, "file", fileName);

以上方法,可防止中文的文件名乱码

报错问题

关于上传出现报错的问题收集

无法访问对象

报错:无法访问已释放的对象。

看对象名是什么,可能是“System.Net.Http.MultipartFormDataContent”,

这是因为在调用异步时,又调用了一次,调用之前就已自动释放了被引用的对象,

适当使用using () {} 可管理对象在不用时被释放

未同步执行异常

报错:System.Threading.Tasks.Task 1.GetResultCore(Boolean waitCompletionNotification)

可能是执行以下同步代码造成的,

var responseText = client.PostAsync(url, formData).GetAwaiter().GetResult().Content.ReadAsStringAsync().Result;

试试改成asyncawait调用方式,保证同步执行

建立安全通道

报错:基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系。

当请求地址API_BASE_URL是带https协议,那可能会报错安全通道信任问题的异常,

在新建的HttpClientHandler实例设置一个事件,信任所有证书

var hander = new HttpClientHandler();
hander.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => {
    // 在这里添加你的证书验证逻辑
    // 返回true来表示允许所有证书(不推荐用于生产环境)
    return true;
};

用于生产环境这会不安全,要改使用 System.Net.ServicePointManager.SecurityProtocol,

可能还会报错, 就试试改成如下代码

var hander = new HttpClientHandler();
hander.AllowAutoRedirect = true;
hander.UseCookies = true;
hander.CookieContainer = cookies;
hander.ClientCertificateOptions = ClientCertificateOption.Automatic;

通过设置ClientCertificateOptions 使用安全认证…

最后,将hander传给client即可

var client = new HttpClient(hander);
//...

接收文件

如果还没有实现接收文件, 这里就在本地服务器上实现一下, 方便测试

后台服务器的开发语言种类繁多, 这里使用一种开发语言C#,

写一个例子, 实现接收文件

.Net Aspx

例如,在Default.aspx页面里实现上传文件,再到后台处理请求接收文件,

上传文件页面内容如下,

<form>
 	<h1>上传文件</h1>
        <hr />
        <div>
            <input type="file" name="file"/>
        </div>
    <hr />
</form>
<script>
	$(function () {
        $('input[type=file]:last').on('change', onChange);
    })

    function onChange(e) {
        var btn = $('form:last');
        var file = btn[0];
        var data = new FormData(file);
        $.ajax({
            url:'/Default.aspx?type=uploadfile',
            type: 'POST',
            data: data,
            cache: false,
            processData: false,
            contentType: false,//改变默认string类型'application/json; charset=utf-8'
            success: function (res) {
                console.log('ajax success', res);
            },
            error: function (err) {
                console.error('ajax error', err)
            }
        })
    }
</script>

这里使用怀旧主流的前端框架jQuery, 它的网上免费学习文档丰富

在后台的处理接收文件,调用方法UploadFile(),代码如下

private string UploadFile()
{
    if (Request.Files.Count > 0)
    {
        var file = Request.Files[0];
        var fileName = System.IO.Path.GetFileName(file.FileName);
        var path = System.IO.Path.Combine(Server.MapPath("~/Uploads/"), fileName);
        file.SaveAs(path);
        return "ok";
    }
    return "fail";
}

写到这里为止,期待下次再见!

在这里插入图片描述

  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TA远方

谢谢!收到你的爱╮(╯▽╰)╭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值