经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
.Net Web API 005 Controller上传小文件
来源:cnblogs  作者:mytudousi  时间:2023/8/7 9:15:32  对本文有异议

1、附属文件对象定义

一般情况下,系统里面的文件都会附属一个对象存在,例如用户的头像文件,会附属用户对象存在。邮件中的文件会附属邮件存在。所以在系统里面,我们会创建一个附属文件对象,命名为AttachedFileEntity。其定义如下所示。

  1. /// <summary>
  2. /// 附属文件实体对象
  3. /// </summary>
  4. public class AttachedFileEntity
  5. {
  6. /// <summary>
  7. /// 实体对象GUID
  8. /// </summary>
  9. public string GUID { get; set; } = "";
  10. /// <summary>
  11. /// 所属对象的GUID
  12. /// </summary>
  13. public string EntityGUID { get; set; } = "";
  14. /// <summary>
  15. /// 名称
  16. /// </summary>
  17. public string Name { get; set; } = "";
  18. /// <summary>
  19. /// 关键字
  20. /// </summary>
  21. public string KeyWord { get; set; } = "";
  22. /// <summary>
  23. /// 文件大小
  24. /// </summary>
  25. public int FileSize { get; set; } = 0;
  26. /// <summary>
  27. /// 服务器存储路径
  28. /// </summary>
  29. public string ServerPath { get; set; } = "";
  30. /// <summary>
  31. /// 描述信息
  32. /// </summary>
  33. public string Description { get; set; } = "";
  34. }

EntityGUID属性的作用是,定义该文件属于哪个实体对象,例如某个用户的头像文件,该属性就是这个用户对象的GUID值。

KeyWord属性用来标识文件。例如UserEntity有两个文件,头像和一个自我介绍的视频文件。这两个文件的EntityGUID都是UserEntity的GUID,那么就可以通过KeyWord来区分两个文件是做什么用的。

2、小文件上传服务

如果一个文件比较小,例如3M以内,那么我们就可以一次性把文件上传上来,上传的时候,要把AttachedFileEntity对象传进来,并添加到数据库中。

代码如下所示。

  1. /// <summary>
  2. /// 上传文件
  3. /// </summary>
  4. /// <param name="pEntity"></param>
  5. /// <returns></returns>
  6. [HttpPost]
  7. [Route("UploadFile")]
  8. public IActionResult UploadFile()
  9. {
  10. //获取客户端传来的数据
  11. var myEntityJosnString = Request.Form["pEntity"].ToString();
  12. var myEntity = JsonSerializer.Deserialize<AttachedFileEntity>(myEntityJosnString);
  13. var myFile = Request.Form.Files[0];
  14. //设置新的文件路径
  15. string myFileEx = Path.GetExtension(myFile.FileName);
  16. string myServerFilePath = DateTime.Now.ToString("yyyy_MM_dd") + "\\" + Guid.NewGuid().ToString() + myFileEx;
  17. myEntity!.ServerPath = myServerFilePath;
  18. //创建目录
  19. string myFullServerPath = AppDomain.CurrentDomain.BaseDirectory + "\\Files\\" + myServerFilePath;
  20. string myFullFolder = Path.GetDirectoryName(myFullServerPath)!;
  21. if (Directory.Exists(myFullFolder) == false)
  22. {
  23. Directory.CreateDirectory(myFullFolder);
  24. }
  25. Stream? myStream = null;
  26. FileStream? myFileStream = null;
  27. BinaryWriter? myBinaryWriter = null;
  28. try
  29. {
  30. myStream = myFile.OpenReadStream();
  31. byte[] myBytes = new byte[myStream.Length];
  32. myStream.Read(myBytes, 0, myBytes.Length);
  33. myStream.Seek(0, SeekOrigin.Begin);
  34. myFileStream = new FileStream(myFullServerPath, FileMode.Create);
  35. myBinaryWriter = new BinaryWriter(myFileStream);
  36. myBinaryWriter.Write(myBytes);
  37. }
  38. finally
  39. {
  40. myBinaryWriter?.Close();
  41. myFileStream?.Close();
  42. myStream?.Close();
  43. }
  44. //把附属文件对象保存到数据库中
  45. //代码略
  46.  
  47. return this.Ok(myEntity);
  48. }

因为我们要传入两个复杂的对象AttachedFileEntity和File,所以就不能用参数接了,就需要用代码从Request里面读取。文件其本质就是二进制数据,我们获取这个二进制之后,把数据保存成文件就可以了。然后把pEntity写入到数据库中。

3、前端调用

先用桌面端测试,界面是用C#写的WPF桌面软件,入下图所示。

截图.png

调用代码入下所示。

  1. var myFilePath = this.UI_SmallFile_TextBox.Text.Trim();
  2. if (myFilePath.Length == 0)
  3. {
  4. MessageBox.Show("请选择一个文件。");
  5. return;
  6. }
  7. if (File.Exists(myFilePath) == false)
  8. {
  9. MessageBox.Show("文件不存在,请重新选择。");
  10. return;
  11. }
  12. //定义AttachedFileEntity
  13. var myAttachedFileEntity = new AttachedFileEntity()
  14. {
  15. GUID = Guid.NewGuid().ToString(),
  16. Name = "用户头像",
  17. KeyWord = "UserProfilePhoto",
  18. Description = "",
  19. EntityGUID = "AAAA"
  20. };
  21. //定义请求内容
  22. var myFileStream = new FileStream(myFilePath, FileMode.Open);
  23. myAttachedFileEntity.FileSize = (int)myFileStream.Length;
  24. var myFileName = Path.GetFileName(myFilePath);
  25. var myFileStreamContent = new StreamContent(myFileStream);
  26. var myMultipartFormDataContent = new MultipartFormDataContent
  27. {
  28. { JsonContent.Create(myAttachedFileEntity), "pEntity" },
  29. { myFileStreamContent, "pFormFile", myFileName }
  30. };
  31. //请求服务
  32. var myHttpClientEx = new HttpClientEx(new HttpClient())
  33. {
  34. Url = "http://localhost:5000/api/AttachedFile/UploadFile",
  35. HttpContent = myMultipartFormDataContent
  36. };
  37. await myHttpClientEx.PostAsync();
  38. myFileStream.Close();
  39. //解析结果
  40. if (myHttpClientEx.IsSuccess == false)
  41. {
  42. MessageBox.Show(("上传文件失败," + myHttpClientEx.ResponseContenString));
  43. return;
  44. }
  45. var myEntity = myHttpClientEx.GetResponseObject<AttachedFileEntity>();
  46. var myEntityJosnString = JsonSerializer.Serialize(myEntity);
  47. MessageBox.Show(myEntityJosnString);

HttpClientEx是对.Net定义的HttpClient一些功能的扩展,这样用起来会比较方便,代码定义如下。

  1. /// <summary>
  2. /// HttpClient的自定义扩展类
  3. /// </summary>
  4. public class HttpClientEx
  5. {
  6. /// <summary>
  7. /// HttpClient的自定义扩展类
  8. /// </summary>
  9. /// <param name="pHttpClient"></param>
  10. public HttpClientEx(HttpClient? pHttpClient)
  11. {
  12. this.HttpClient = pHttpClient;
  13. this.ParameterDictionary = new Dictionary<string, string>();
  14. }
  15. /// <summary>
  16. /// HttpClient对象
  17. /// </summary>
  18. public HttpClient? HttpClient { get; private set; }
  19. /// <summary>
  20. /// 服务地址
  21. /// </summary>
  22. public string Url { get; set; } = "";
  23. /// <summary>
  24. /// 参数字典
  25. /// </summary>
  26. public Dictionary<string, string> ParameterDictionary { get; private set; }
  27. /// <summary>
  28. /// 请求内容
  29. /// </summary>
  30. public HttpContent? HttpContent { get; set; }
  31. /// <summary>
  32. /// 请求返回的消息
  33. /// </summary>
  34. public HttpResponseMessage? ResponseMessage { get; private set; }
  35. /// <summary>
  36. /// 是否执行成功
  37. /// </summary>
  38. public bool IsSuccess { get; private set; }
  39. /// <summary>
  40. /// 返回的内容字符串
  41. /// </summary>
  42. public string ResponseContenString { get; private set; } = "";
  43. /// <summary>
  44. /// Get
  45. /// </summary>
  46. /// <returns></returns>
  47. public async Task GetAsync()
  48. {
  49. var myUrlWithParameters = this.GetUrlWithParameters();
  50. this.ResponseMessage = await this.HttpClient!.GetAsync(myUrlWithParameters);
  51. this.IsSuccess = this.ResponseMessage.IsSuccessStatusCode;
  52. this.ResponseContenString = await this.ResponseMessage.Content.ReadAsStringAsync();
  53. }
  54. /// <summary>
  55. /// Get
  56. /// </summary>
  57. /// <returns></returns>
  58. public async Task PostAsync()
  59. {
  60. var myUrlWithParameters = this.GetUrlWithParameters();
  61. this.ResponseMessage = await this.HttpClient!.PostAsync(myUrlWithParameters, this.HttpContent);
  62. this.IsSuccess = this.ResponseMessage.IsSuccessStatusCode;
  63. this.ResponseContenString = await this.ResponseMessage.Content.ReadAsStringAsync();
  64. }
  65. /// <summary>
  66. /// 得到返回的对象
  67. /// </summary>
  68. /// <typeparam name="T"></typeparam>
  69. /// <returns></returns>
  70. public T? GetResponseObject<T>()
  71. {
  72. if (this.ResponseContenString == "")
  73. {
  74. return default;
  75. }
  76. var myJsonSerializerOptions = new JsonSerializerOptions()
  77. {
  78. PropertyNameCaseInsensitive = true
  79. };
  80. return JsonSerializer.Deserialize<T>(this.ResponseContenString, myJsonSerializerOptions);
  81. }
  82. /// <summary>
  83. /// 得到带参数的Url
  84. /// </summary>
  85. /// <returns></returns>
  86. private string GetUrlWithParameters()
  87. {
  88. if (this.ParameterDictionary == null)
  89. {
  90. return this.Url;
  91. }
  92. if (this.ParameterDictionary.Count == 0)
  93. {
  94. return this.Url;
  95. }
  96. var myParameterList = new List<string>();
  97. foreach (var myItem in this.ParameterDictionary)
  98. {
  99. myParameterList.Add(myItem.Key + "=" + myItem.Value);
  100. }
  101. return this.Url + "?" + string.Join("&", myParameterList);
  102. }
  103. }

如果客户端是Js,就需要自己组织服务需要的数据了。代码入下所示。

  1. var myFileReader = new FileReader();
  2. var myFileName = "";
  3. myFileReader.onloadend = function () {
  4. var myFileResult = myFileReader.result;
  5. var myFileLength = myFileResult.byteLength;
  6. var myFileEntity = new Object()
  7. {
  8. ServerPath: ""
  9. };
  10. Upload();
  11. function Upload() {
  12. var myByteArray = myFileResult.slice(0, myFileLength);
  13. var myBlob = new Blob([myByteArray]);
  14. var myFile = new File([myBlob], myFileName);
  15. var myFormData = new FormData();
  16. myFormData.append("file", myFile)
  17. myFormData.append("pEntity", json.stringify(myFileEntity));
  18. request.post(myUrl, {
  19. data: myFormData
  20. }).then(function (data) {
  21. myFileEntity = json.parse(data);
  22. alert("上传文件结束。");
  23. alert(json.stringify(myFileEntity));
  24. }, function (err) {
  25. alert(err);
  26. return;
  27. });
  28. }
  29. }
  30. myFileName = this.files[0].name;
  31. myFileReader.readAsArrayBuffer(this.files[0]);

原文链接:https://www.cnblogs.com/mytudousi/p/17608801.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号