• .NET C# 使用System.Net.Http下HttpClient执行异步多文件上传任务


    1.前提

    System.Net.Http.HttpClient的使用及介绍,请参照此文档:https://www.cnblogs.com/jeff151013/p/14704576.html

    2.Tools工具代码(直接上工具代码,其他辅助参数、变量、请参考上面的文档链接)

    /// <summary>
            /// 执行多文件上传
            /// </summary>
            /// <param name="uri">请求的uri</param>
            /// <param name="methodType">暂时只支持POST方式</param>
            /// <param name="filePaths">多文件(全)路径列表</param>
            /// <param name="outputMediaType">期望服务器返回的结果数据类型,默认json</param>
            public static async Task<string> ExecuteFileUploadAsync(Uri uri, Enums.HttpMethodEnum methodType,
                List<string> filePaths, string outputMediaType = "json")
            {
                HttpResponseMessage result = null;
                HttpRequestMessage httpRequestMessage = null;
                MultipartFormDataContent multipartFormDataContent = null;
                try
                {
                    HttpClient client = CreateHttpClient(outputMediaType);
                    multipartFormDataContent = new MultipartFormDataContent();
                    filePaths.ForEach(filePath =>
                    {
                        var fileStream = new FileStream(filePath, FileMode.Open);
                        var fileName = Path.GetFileName(filePath);
                        multipartFormDataContent.Add(new StreamContent(fileStream), "file", fileName);
                    });
                    httpRequestMessage = new HttpRequestMessage()
                    {
                        Method = HttpMethod.Post,//TODO 后续如果支持更多中methodType,再放开
                        RequestUri = uri,
                        Content = multipartFormDataContent
                    };
                    result = await client.SendAsync(httpRequestMessage);
                }
                catch (AggregateException ex)
                {
                    #region 获取线程异常信息
                    Exception firstException = null;
                    if (ex.InnerExceptions != null && ex.InnerExceptions.Any())
                    {
                        firstException = ex.InnerExceptions.First();
                        if (firstException.InnerException != null)
                            firstException = firstException.InnerException;
                    }

                    //Logger.LogException(firstException);//Nlogger记录异常日志
                    #endregion 获取线程异常信息
                    result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
                    {
                        Content =
                            new StringContent(firstException != null
                                ? firstException.ToString()
                                : "Encountered an AggreggateException without any inner exceptions")
                    };
                }
                catch (Exception ex)
                {
                    //Logger.LogException(ex);//Nlogger记录异常日志
                    result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
                    {
                        Content =
                            new StringContent("Encountered an AggreggateException without any inner exceptions")
                    };
                }

                return await result.Content.ReadAsStringAsync();
            }

    3.客户端调用示例代码(以winform举例):

    public partial class Form1 : Form
        {
            /// <summary>
            /// 用于暂存待上传的文件全路径列表
            /// </summary>
            private List<string> _fullFilePaths = new List<string>();
            public Form1()
            {
                InitializeComponent();
            }

            private void Form1_Load(object sender, EventArgs e)
            {
            }

            /// <summary>
            /// 页面选择待上传文件按钮时间
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnSelectFile_Click(object sender, EventArgs e)
            {
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.Multiselect = true;
                ofd.Title = "请选择待上传的文件";
                ofd.Filter = "word文件|*.doc;*.docx|excel文件|*.xls;*.xlsx|pdf文件|*.pdf|所有文件(*.*)|*.*";
                ofd.RestoreDirectory = true;
                var result = ofd.ShowDialog();
                if (result == DialogResult.OK)
                {
                    _fullFilePaths = ofd.FileNames.ToList();
                    _fullFilePaths.ForEach(x=>rTxt.Text += System.Environment.NewLine + x);
                }
            }

            /// <summary>
            /// 上传按钮点击事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnUpload_Click(object sender, EventArgs e)
            {
                if (_fullFilePaths == null || !_fullFilePaths.Any()) return;

                Task.Run(async () =>
                {

    //上传URL来自app.config的配置
                    var r = await ApiHttpUtils.ExecuteFileUploadAsync(new Uri(SystemConfig.XbrlBackgroundInspectFileReceiveUrl),
                        HttpMethodEnum.Post, _fullFilePaths, "json");

    //DataTransferExtensions是包装的Newtonsoft的JSON序列化及反序列化的工具类

    //将服务端的响应信息反序列化为具体的业务实体数据
                    var response = DataTransferExtensions.GetTransferData<Response<object>>(r);
                    if (response.IsSuccess && response.ErrorCode == ((int) ResponseStatusEnum.Ok).ToString())
                    {

    //根据业务返回结果更新UI提示信息
                        this.Invoke(new Action(() =>
                        {
                            this.lblTips.Text = "上传成功";
                        }));
                    }
                });
            }

            /// <summary>
            /// 取消按钮点击事件,暂未实现
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnCancel_Click(object sender, EventArgs e)
            {
                MessageBox.Show("暂未实现");
            }
        }

    4.服务端接收示例代码(以ASP.NET WebAPI举例):

    using System.Net.Http;
    using System.Net.Http.Headers;

    using System.Threading.Tasks;
    using System.Web.Http;

    public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
        {

    //rootPath指定文件暂存的目录路径
            public CustomMultipartFormDataStreamProvider(string rootPath) : base(rootPath)
            {
            }

            public CustomMultipartFormDataStreamProvider(string rootPath, int bufferSize) : base(rootPath, bufferSize)
            {
            }

            public override string GetLocalFileName(HttpContentHeaders header)//重写此方法,主要为了解决当上传文件重名时可能出现的问题
            {
                var fileName = header.ContentDisposition.FileName.Replace(""", string.Empty);
                if (File.Exists(Path.Combine(base.RootPath, fileName)))
                {
                    //文件名如果已存在,则新文件名:yyyyMMddhhmmss_DateTimeTicks_原文件名(不含后缀名).后缀名
                    var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(Path.Combine(base.RootPath, fileName));
                    var extension = Path.GetExtension(Path.Combine(base.RootPath, fileName));
                    return $"{DateTime.Now.ToString("yyyyMMddhhmmss")}_{DateTime.Now.Ticks}_{fileNameWithoutExtension}{extension}";
                }
                return fileName;//文件名如果不存在,则文件名即上传文件名
            }
        }

    public class InspectSwitchController : ApiController
        {

            private readonly string _inspectSwitchFileImportTempPath =
                SystemConfig.InspectSwitchFileImportTempPath;//配置文件信息来自Web.config配置

    [HttpPost]
            public async Task<IHttpActionResult> UploadImportingFile()
            {
                //TODO 日志记录传参,可能因文件过大序列化到日志时发生报错

                var response = new Response<InspectSwitchViewModel<ForAddResultDto>>();
                if (!Request.Content.IsMimeMultipartContent())//不受支持的MimeMultipartContent类型
                {
                    response = new Response<InspectSwitchViewModel<ForAddResultDto>>()
                    {
                        ErrorMsg = "不受支持的文件类型",
                        ErrorCode = ((int)ResponseStatusEnum.ProgramExecuteOccurException).ToString()
                    };
                }

                try
                {
                    var streamProvider = new CustomMultipartFormDataStreamProvider(_inspectSwitchFileImportTempPath);
                    await Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith((t) =>
                    {
                        if (t.IsFaulted || t.IsCanceled)
                        {
                            response = new Response<InspectSwitchViewModel<ForAddResultDto>>
                            {
                                ErrorMsg = "上传过程中发生错误或上传任务被取消",
                                ErrorCode = ((int)ResponseStatusEnum.ProgramExecuteOccurException).ToString()
                            };
                        }

                        if (t.IsCompleted)
                        {
                            //上传已完成,将指定目录下的所有文件信息记录到数据库中
            //xxxx
                        }
                    });
                }
                catch (Exception ex)
                {
                    response = new Response<InspectSwitchViewModel<ForAddResultDto>>()
                    {
                        ErrorMsg = ex.Message,
                        ErrorCode = ((int)ResponseStatusEnum.ProgramExecuteOccurException).ToString()
                    };
                    //Logger.LogException(ex);//Nlogger日志记录异常信息
                }

                return Ok(response);
            }

     }

  • 相关阅读:
    [LC] 347. Top K Frequent Elements
    [LC] 659. Split Array into Consecutive Subsequences
    [LC] 430. Flatten a Multilevel Doubly Linked List
    [LC] 271. Encode and Decode Strings
    [LC] 373. Find K Pairs with Smallest Sums
    [LC] 1048. Longest String Chain
    [LC] 297. Serialize and Deserialize Binary Tree
    ubuntu 创建 PyCharm 桌面快捷方式 (或者叫 启动器 )
    scala private 和 private[this] 的区别
    %s %r 区别 转
  • 原文地址:https://www.cnblogs.com/jeff151013/p/14722569.html
Copyright © 2020-2023  润新知