我需要 XUnit 测试下一个端点:
/// <summary>
/// Cease all account in csv file
/// </summary>
/// <param name="dispatcher"></param>
/// <param name="csvFile">CSV file with format (Id,Name,SID,CeaseDate,Note)</param>
/// <param name="ct"></param>
/// <returns></returns>
[HttpPost("cease/bulk")]
[Authorize(Roles = VdcSecurity.Role.ManagementAdmin)]
[AllowAnonymous]
public async Task<ActionResult<bool>> CeaseBulkAccountAsync(
[FromServices][IsSensitive] ICommandDispatcher dispatcher,
[FromForm] IFormFile csvFile,
[IsSensitive] CancellationToken ct = default
)
{
var identity = Vdc.Libs.AspNet.Controller.HttpContextExtensions.GetIdentity(HttpContext);
var ipAddress = HttpContext.GetIpAddress();
var command = new CeaseBulkCommand(identity, HttpContext.TraceIdentifier)
{
Stream = csvFile.OpenReadStream(),
IpAddress = ipAddress
};
var result = await dispatcher.DispatchAsync(_provider, command, ct);
return result.ToActionResult(this);
}
我的问题是无论我如何创建 IFormFile 对象,它总是被接收为 null。
这是我的尝试之一:
const string filePath = "CeaseBulkAccount.csv";
using (var httpClient = ApiClient.HttpClient)
{
var form = new MultipartFormDataContent();
byte[] fileData = File.ReadAllBytes(filePath);
ByteArrayContent byteContent = new ByteArrayContent(fileData);
byteContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(byteContent, "file", Path.GetFileName(filePath));
var result = await httpClient.PostAsync("/api/accounts/cease/bulk", form);
}
我到达控制器,但收到的 csvFile 为空。
ApiClient.HttpClient 是我们自己的客户端,但我不介意使用通用客户端。
我不得不说我们的 httpClient“PostAsync”收到了 HttpContent。
第二次尝试:
var httpClient = ApiClient.HttpClient;
var fileContent = new ByteArrayContent(ReadFully(file));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "CeaseBulkAccount.csv"
};
var response = await httpClient.PostAsync("/api/accounts/cease/bulk", fileContent, ct);
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
再次,csvFile 为空。
我们的 PostAsync:
//
// Summary:
// Send a POST request with a cancellation token as an asynchronous operation.
//
// Parameters:
// requestUri:
// The Uri the request is sent to.
//
// content:
// The HTTP request content sent to the server.
//
// cancellationToken:
// A cancellation token that can be used by other objects or threads to receive
// notice of cancellation.
//
// Returns:
// The task object representing the asynchronous operation.
//
// Exceptions:
// T:System.InvalidOperationException:
// The requestUri must be an absolute URI or System.Net.Http.HttpClient.BaseAddress
// must be set.
//
// T:System.Net.Http.HttpRequestException:
// The request failed due to an underlying issue such as network connectivity, DNS
// failure, server certificate validation or timeout.
//
// T:System.Threading.Tasks.TaskCanceledException:
// .NET Core and .NET 5 and later only: The request failed due to timeout.
//
// T:System.UriFormatException:
// The provided request URI is not valid relative or absolute URI.
public Task<HttpResponseMessage> PostAsync([StringSyntax("Uri")] string? requestUri, HttpContent? content, CancellationToken cancellationToken);
传递给
form.Add
的名称必须与控制器的action方法中的名称匹配; [FromForm] IFormFile csvFile
。
因为那个是
csvFile
,所以你必须添加如下文件。
form.Add(byteContent, "csvFile", Path.GetFileName(filePath));
通过上述更改,您的第一次尝试效果很好。