研究了幾天的 WebAPI 多文件批量上傳功能,也終於找到了無法先驗證再存盤的解決方法,以下是本次的測試代碼,希望能對大家有幫助!~
-
首先上服務端多文件接收的接口代碼
public class FileController : ServiceBase
{
///
/// 服務端文件上傳接口
///
[Route("~/upload")]
[HttpPost, HttpGet]
public async Task<string> Upload()
{
System.Diagnostics.Debugger.Launch(); //喚起調試器
if (!Request.Content.IsMimeMultipartContent())
return "缺少附件。";
var savePath = $@"D:\ReceiveUpload\{DateTime.Now.ToString("yyyy-MM-dd")}"; //定義一個用於存儲接收文件的目錄
//確保目錄存在
if (!Directory.Exists(savePath))
Directory.CreateDirectory(savePath);
//使用異步接收客戶端上傳的多個文件信息
var multi = await Request.Content.ReadAsMultipartAsync();
var fileCount = 0;
//遍歷全部文件
foreach (var content in multi.Contents)
{
var contentType = content.Headers.ContentType; //客戶端定義的Content-Type
var name = content.Headers.ContentDisposition.Name; //客戶端定義的Name參數
var fileName = content.Headers.ContentDisposition.FileName?.Trim('"'); //客戶端上傳的文件名稱
var fileType = Path.GetExtension(fileName)?.TrimStart('.'); //獲取文件擴展名
if (string.IsNullOrWhiteSpace(fileName))
continue;//非文件則跳過
++fileCount;
//獲取文件流數據(根據自己需求2選1即可)
var fileBytes = await content.ReadAsByteArrayAsync();
var fileStream = await content.ReadAsStreamAsync();
var fileLength = fileStream.Length; //獲取文件大小
switch (fileType.ToLower())
{
case "jpg":
case "png":
#region 驗證圖片文件
{
var image = new Bitmap(fileStream); //獲取圖片信息
var imgWidth = image.Width; //獲取圖片寬度
var imgHeight = image.Height; //獲取圖片高度
var imgLength = fileStream.Length; //獲取圖片大小
//PS:可在此處對圖片大小與分辨率大小進行驗證
//將此圖片保存到磁盤
image.Save($@"{savePath}\{fileName}");
//釋放資源
image.Dispose();
}
#endregion
break;
default:
//return $"不允許的文件格式“{fileType}”。";
//將文件保存到磁盤中
File.WriteAllBytes($@"{savePath}\{fileName}", fileBytes);
break;
}
//釋放資源
fileStream.Dispose();
}
return $"已接收到{fileCount}個文件。";
}
}
-
其次是客戶端程序的文件上傳代碼
/// <summary>
/// 客戶端批量上傳文件
/// </summary>
[TestMethod]
public void TestUpload()
{
var url = "http://127.0.0.1:8080/upload";
var filesPath = new List<string>();
{
filesPath.Add(@"D:\測試文件\17,443KB (9088x3776).jpg");
filesPath.Add(@"D:\測試文件\829KB.7z");
filesPath.Add(@"D:\測試文件\107MB.zip");
filesPath.Add(@"D:\測試文件\812MB.rar");
}
using (var client = new System.Net.Http.HttpClient())
using (var content = new System.Net.Http.MultipartFormDataContent())
{
foreach (string filePath in filesPath)
#region 添加文件
{
var fileName = filePath.Substring(filePath.LastIndexOf('\\') + 1);
var fileBytes = File.ReadAllBytes(filePath);
var fileContent = new System.Net.Http.ByteArrayContent(fileBytes);
{
//定義內容標頭,使用 attachment 附件上傳模式
fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
//定義一個Name參數 (非必填項,根據個人需求即可)
Name = $"文件{++i}",
//告訴服務端當前文件的名稱
FileName = fileName
};
}
content.Add(fileContent);
}
#endregion
var responseMessage = client.PostAsync(url, content).Result;
var status = responseMessage.StatusCode;
var result = responseMessage.Content.ReadAsStringAsync().Result; //返回的頁面內容
//測試結果返回:"已接收到4個文件。"
}
}
-
以上,如出現 Request 內容超過限制的長度異常,注意配置 Web.config
<!--修改限制Request數據大小(單位:KB)-->
<system.web>
<httpRuntime targetFramework="4.6.1" maxRequestLength="4194304"/>
</system.web>
<!--修改限制Request數據大小(單位:Byte)-->
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="4294967295" />
</requestFiltering>
</security>
</system.webServer>
-
若上一步配置後還沒能解決的,可再嘗試修改 App_Start/WebApiConfig.cs
此處是在 https://www.cnblogs.com/dopeter/p/4675174.html 這篇文章中看到的,因實際測試時已通過上一步的配置 Web.config 已解決,所以還沒能用上這段 ~ :-)
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// 重寫上傳文件的內容存入內存的動作,爲解決無法通過流上傳大文件問題
GlobalConfiguration.Configuration.Services.Replace(typeof(System.Web.Http.Hosting.IHostBufferPolicySelector), new NoBufferPolicySelector());
}
}
/// <summary>
/// 重寫上傳文件的內容存入內存的動作,爲解決無法通過流上傳大文件問題
/// </summary>
public class NoBufferPolicySelector : System.Web.Http.WebHost.WebHostBufferPolicySelector
{
public override bool UseBufferedInputStream(object hostContext)
{
var context = hostContext as System.Web.HttpContextBase;
if (context != null)
{
if (context.Request.HttpMethod == System.Net.Http.HttpMethod.Post.ToString() && context.Request.ContentLength > 200000)
return false;
}
return true;
}
}