【发布时间】:2023-03-20 10:07:01
【问题描述】:
我有一个场景,我尝试从 UI 上传文件,然后在 .net 核心中我创建了一个端点,将文件推送到 azure blob 存储中,之后我编写了一个自动触发并生成一个 azure 函数调用另一个 API,该 API 进一步处理该文件并编写某种 SQL 查询,并在处理文件后生成一些数据,然后我再次将该生成的文件推送到 blob 到某个不同的容器。但是我面临一个问题,如果我上传单个文件,它对我来说很好,但是当我上传一个文件然后我上传另一个文件时,我的第二个文件丢弃了我的第一个数据处理并且在我的第二个容器中我只得到一个导出的文件用于第二个上传的文件。所以我希望尽可能多的用户可以上传文件,但所有进程都应该运行它不应该丢弃任何正在运行的进程。 如果你们建议我任何对我有帮助的方法。如果需要,我会分享我的代码
上传文件端点
[HttpPost]
[Route("uploadFileToBlob")]
public async Task<IActionResult> UploadFileToBlobStorage(IFormFile file)
{
var userId = HttpContext.User.Identity.Name;
var accessToken = Request.Headers[HeaderNames.Authorization];
_manageClaim.UploadExcelToBlob(file, accessToken, userId);
return Ok(new { Message = "Your file is uploaded and processing..."});
}
此端点的存储库
public void UploadExcelToBlob(IFormFile file, string accessToken, string userId)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(blobConnectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("infolder");
// Retrieve reference to a blob named "test.xlsx"
CloudBlockBlob blockBlobReference = container.GetBlockBlobReference(file.FileName);
container.Metadata.Clear();
container.Metadata.Add("bearerToken", accessToken);
container.SetMetadata();
Stream myBlob = file.OpenReadStream();
blockBlobReference.UploadFromStream(myBlob);
var currentUser = _automationUsers.GetUserById(int.Parse(userId));
BatchClaimStatus batchClaim = new BatchClaimStatus()
{
UserId = int.Parse(userId),
UserName = currentUser.FirstName + ' ' + currentUser.LastName,
InputFileName = file.FileName,
IsExported = false,
ErrorMessage = null,
OutputFileName = null,
UpdatedDate = DateTime.Now,
UploadedDate = DateTime.Now
};
_blobRepository.AddImportedFileToDb(batchClaim);
}
API 端点 当我从 UI 上传任何文件时,此端点会自动命中
[HttpPost]
[Route("getBatchClaimData")]
public async Task<IActionResult> ExportToCsv(List<CsvPropModel> model)
{
await _manageClaim.GetClaimData(model);
return Ok();
}
这是上述端点的存储库
public async Task<bool> GetClaimData(List<CsvPropModel> csvProps)
{
var dataRange = new List<ClaimsResponse>();
ClaimsResponse claims = new ClaimsResponse();
foreach (var item in csvProps)
{
InvoiceResult invoice = _manage.GetInvoiceDetailsByInvoiceId(item.InvoiceId, item.NickName);
EligiblePaymentStatusParameters eligibleParams = Converter.ConvertInvoiceToEligibleParams(invoice);
claims = await GetClaimDetails(eligibleParams, invoice);
claims.InvKey = invoice.InvKey;
claims.NickName = invoice.NickName;
claims.InvoiceNumber = invoice.InvNbrDisplay;
dataRange.Add(claims);
}
var csvRecord = ClaimDataHelper.ConvertToCsvReCord(dataRange);
var fileName = @$"{ DateTime.Now.ToShortDateString() }_ExportedBatchClaim_{ DateTime.Now.ToShortTimeString() }.csv";
MemoryStream ms = new MemoryStream();
using (var memoryStream = new MemoryStream())
{
using (var writer = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(csvRecord);
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(blobConnectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("outfolder");
// Retrieve reference to a blob named "test.xlsx"
CloudBlockBlob blockBlobReference = container.GetBlockBlobReference(fileName);
memoryStream.Position = 0;
memoryStream.CopyTo(ms);
ms.Position = 0;
await blockBlobReference.UploadFromStreamAsync(ms);
ms.Flush();
var importedData = _blobRepository.GetLastImportedData();
BatchClaimStatus batchClaim = new BatchClaimStatus()
{
ErrorMessage = null,
InputFileName = importedData.InputFileName,
IsExported = true,
OutputFileName = fileName,
UpdatedDate = DateTime.Now,
UploadedDate = importedData.UploadedDate,
UserId = importedData.UserId,
UserName = importedData.UserName
};
_blobRepository.UpdateExportedFileToDb(batchClaim, importedData.Id);
}
}
}
return true;
}
【问题讨论】:
-
根据您的流程,您应该将示例代码提交到此帖子中,因为您的代码中有不可见的东西。我更喜欢看看你是如何创建一个进程的,而这一行导致你的进程被丢弃了。
-
@JohnathanLe 我已经编辑了我的问题并添加了代码,所以每当我点击端点“uploadFileToBlob”时,都会自动调用端点“getBatchClaimData”的代码,但是当我连续上传两次时,它会丢弃第一个并处理第二个你能帮我吗,这将是很大的帮助
-
我看了一下这些代码没有发现任何问题,我真的不明白你这里的业务。您是否登录以确保已在第二个 api 中调用了第一个进程?这是帮助我们防止 UI 出现问题的标志(可能是 javascript)
-
好的,我明白了。所以问题可能出现在您的 Azure 函数中。记得您使用 Azure 函数由 Azure Blob 触发,它对并发和内存有限制here。通常情况下,Azure Function 不是由 Blob 触发的可靠性,而且它的机制如此繁重。我建议您使用 EventGrid 来触发您的 Azure 函数。在
UploadExcelToBlob方法结束时,只需向事件网格通知一条完成的消息。 -
另外,在旁注中,我看到你的一些代码有同步调用,例如_blobRepository.UpdateExportedFileToDb(batchClaim,importedData.Id);。虽然和这个问题没有直接关系,但是观察一下就可以改进。对于 IO 绑定操作,我们应该尝试在任何地方使用异步。
标签: asp.net-core .net-core file-upload asp.net-core-webapi azure-blob-storage