Azure API 调用在控制台应用程序中工作,而不是在 MVC 中工作
Azure API call working in Console App & not in MVC
我有一个 asp.net MVC 应用程序,允许用户将 PDF/image 上传到系统。然后我想将此 PDF 发送到 Azure Read API 并将返回的文本存储在系统上的 .text 文件中(这样我可以稍后将一些数据输入数据库)。
我在控制台应用程序中测试它时,它工作得很好,尽管当我尝试将它实现到我的 MVC 网络应用程序中时,它无法工作;当我上传 PDF 时,文件被上传,但没有其他任何事情发生,即没有使用返回的数据创建文本文件。当我在控制台应用程序中使用相同的 Azure API 方法尝试此操作时,它工作正常(文件是使用返回的文本创建的)
我的控制器:
public ActionResult Upload()
{
return View();
}
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
string filename = Guid.NewGuid() + Path.GetExtension(file.FileName);
string filepath = @"C:\Users385\source\repos\BookingSystem\BookingSystem\Surveys\" + filename;
file.SaveAs(Path.Combine(Server.MapPath("/Surveys"), filename));
AzureVisionAPI.ExtractToTextFile(filepath);
return View();
}
我的 Azure API 调用辅助方法:
namespace BookingSystem.Helpers
{
static class AzureVisionAPI
{
static string subscriptionKey = ("SUBSCRIPTON_KEY");
static string endpoint = ("END_POINT");
public static ComputerVisionClient Authenticate(string endpoint, string key)
{
ComputerVisionClient client =
new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{ Endpoint = endpoint };
return client;
}
public static void ExtractToTextFile(string filename)
{
ComputerVisionClient client = Authenticate(endpoint, subscriptionKey);
ExtractTextLocal(client, filename).Wait();
}
public static async Task ExtractTextLocal(ComputerVisionClient client, string localImage)
{
// Helps calucalte starting index to retrieve operation ID
const int numberOfCharsInOperationId = 36;
using (Stream imageStream = File.OpenRead(localImage))
{
// Read the text from the local image
BatchReadFileInStreamHeaders localFileTextHeaders = await client.BatchReadFileInStreamAsync(imageStream);
// Get the operation location (operation ID)
string operationLocation = localFileTextHeaders.OperationLocation;
// Retrieve the URI where the recognized text will be stored from the Operation-Location header.
string operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId);
// Extract text, wait for it to complete.
int i = 0;
int maxRetries = 10;
ReadOperationResult results;
do
{
results = await client.GetReadOperationResultAsync(operationId);
await Task.Delay(1000);
if (maxRetries == 9)
{
throw new Exception("Azure API timed out");
}
}
while ((results.Status == TextOperationStatusCodes.Running ||
results.Status == TextOperationStatusCodes.NotStarted) && i++ < maxRetries);
// Display the found text.
var textRecognitionLocalFileResults = results.RecognitionResults;
foreach (TextRecognitionResult recResult in textRecognitionLocalFileResults)
{
using (StreamWriter sw = new StreamWriter(@"C:\Users385\source\repos\BookingSystem\BookingSystem\surveytest.txt"))
{
foreach (Line line in recResult.Lines)
{
sw.WriteLine(line.Text);
}
}
}
}
}
}
}
您可能会在此处看到异步死锁。而不是使用 .Wait()
你应该等待 Task
return 从你的异步方法中编辑。
发生的事情是你的第一个 await
方法 returns,然后调用 .Wait()
的方法,这会阻塞线程并独占访问你当前的 SynchronizationContext
,当内部等待的事情完成时,下面的代码在同一个 SynchronizationContext
上排队,它被阻塞了。 .Wait()
永远不会停止阻塞,因为 Task
永远无法完成。这被称为异步死锁。
这里处理它的最佳方法是使您的控制器异步并 return Task<ActionResult>
,然后使用 async/await 自上而下。另一种处理方法是将 .ConfigureAwait(false)
分散到所有 Task
和 await
,但是在处理异步工作时最好不要阻塞。
您的代码可能如下所示:
控制器:
public ActionResult Upload()
{
return View();
}
[HttpPost]
public async Task<ActionResult> Upload(HttpPostedFileBase file)
{
string filename = Guid.NewGuid() + Path.GetExtension(file.FileName);
string filepath = @"C:\Users385\source\repos\BookingSystem\BookingSystem\Surveys\" + filename;
file.SaveAs(Path.Combine(Server.MapPath("/Surveys"), filename));
await AzureVisionAPI.ExtractToTextFile(filepath);
return View();
}
AzureVisionAPI:
namespace BookingSystem.Helpers
{
static class AzureVisionAPI
{
static string subscriptionKey = ("SUBSCRIPTON_KEY");
static string endpoint = ("END_POINT");
public static ComputerVisionClient Authenticate(string endpoint, string key)
{
ComputerVisionClient client =
new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{ Endpoint = endpoint };
return client;
}
public static async Task ExtractToTextFile(string filename)
{
ComputerVisionClient client = Authenticate(endpoint, subscriptionKey);
await ExtractTextLocal(client, filename);
}
public static async Task ExtractTextLocal(ComputerVisionClient client, string localImage)
{
// Helps calucalte starting index to retrieve operation ID
const int numberOfCharsInOperationId = 36;
using (Stream imageStream = File.OpenRead(localImage))
{
// Read the text from the local image
BatchReadFileInStreamHeaders localFileTextHeaders = await client.BatchReadFileInStreamAsync(imageStream);
// Get the operation location (operation ID)
string operationLocation = localFileTextHeaders.OperationLocation;
// Retrieve the URI where the recognized text will be stored from the Operation-Location header.
string operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId);
// Extract text, wait for it to complete.
int i = 0;
int maxRetries = 10;
ReadOperationResult results;
do
{
results = await client.GetReadOperationResultAsync(operationId);
await Task.Delay(1000);
if (maxRetries == 9)
{
throw new Exception("Azure API timed out");
}
}
while ((results.Status == TextOperationStatusCodes.Running ||
results.Status == TextOperationStatusCodes.NotStarted) && i++ < maxRetries);
// Display the found text.
var textRecognitionLocalFileResults = results.RecognitionResults;
foreach (TextRecognitionResult recResult in textRecognitionLocalFileResults)
{
using (StreamWriter sw = new StreamWriter(@"C:\Users385\source\repos\BookingSystem\BookingSystem\surveytest.txt"))
{
foreach (Line line in recResult.Lines)
{
sw.WriteLine(line.Text);
}
}
}
}
}
}
}
我有一个 asp.net MVC 应用程序,允许用户将 PDF/image 上传到系统。然后我想将此 PDF 发送到 Azure Read API 并将返回的文本存储在系统上的 .text 文件中(这样我可以稍后将一些数据输入数据库)。
我在控制台应用程序中测试它时,它工作得很好,尽管当我尝试将它实现到我的 MVC 网络应用程序中时,它无法工作;当我上传 PDF 时,文件被上传,但没有其他任何事情发生,即没有使用返回的数据创建文本文件。当我在控制台应用程序中使用相同的 Azure API 方法尝试此操作时,它工作正常(文件是使用返回的文本创建的)
我的控制器:
public ActionResult Upload()
{
return View();
}
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
string filename = Guid.NewGuid() + Path.GetExtension(file.FileName);
string filepath = @"C:\Users385\source\repos\BookingSystem\BookingSystem\Surveys\" + filename;
file.SaveAs(Path.Combine(Server.MapPath("/Surveys"), filename));
AzureVisionAPI.ExtractToTextFile(filepath);
return View();
}
我的 Azure API 调用辅助方法:
namespace BookingSystem.Helpers
{
static class AzureVisionAPI
{
static string subscriptionKey = ("SUBSCRIPTON_KEY");
static string endpoint = ("END_POINT");
public static ComputerVisionClient Authenticate(string endpoint, string key)
{
ComputerVisionClient client =
new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{ Endpoint = endpoint };
return client;
}
public static void ExtractToTextFile(string filename)
{
ComputerVisionClient client = Authenticate(endpoint, subscriptionKey);
ExtractTextLocal(client, filename).Wait();
}
public static async Task ExtractTextLocal(ComputerVisionClient client, string localImage)
{
// Helps calucalte starting index to retrieve operation ID
const int numberOfCharsInOperationId = 36;
using (Stream imageStream = File.OpenRead(localImage))
{
// Read the text from the local image
BatchReadFileInStreamHeaders localFileTextHeaders = await client.BatchReadFileInStreamAsync(imageStream);
// Get the operation location (operation ID)
string operationLocation = localFileTextHeaders.OperationLocation;
// Retrieve the URI where the recognized text will be stored from the Operation-Location header.
string operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId);
// Extract text, wait for it to complete.
int i = 0;
int maxRetries = 10;
ReadOperationResult results;
do
{
results = await client.GetReadOperationResultAsync(operationId);
await Task.Delay(1000);
if (maxRetries == 9)
{
throw new Exception("Azure API timed out");
}
}
while ((results.Status == TextOperationStatusCodes.Running ||
results.Status == TextOperationStatusCodes.NotStarted) && i++ < maxRetries);
// Display the found text.
var textRecognitionLocalFileResults = results.RecognitionResults;
foreach (TextRecognitionResult recResult in textRecognitionLocalFileResults)
{
using (StreamWriter sw = new StreamWriter(@"C:\Users385\source\repos\BookingSystem\BookingSystem\surveytest.txt"))
{
foreach (Line line in recResult.Lines)
{
sw.WriteLine(line.Text);
}
}
}
}
}
}
}
您可能会在此处看到异步死锁。而不是使用 .Wait()
你应该等待 Task
return 从你的异步方法中编辑。
发生的事情是你的第一个 await
方法 returns,然后调用 .Wait()
的方法,这会阻塞线程并独占访问你当前的 SynchronizationContext
,当内部等待的事情完成时,下面的代码在同一个 SynchronizationContext
上排队,它被阻塞了。 .Wait()
永远不会停止阻塞,因为 Task
永远无法完成。这被称为异步死锁。
这里处理它的最佳方法是使您的控制器异步并 return Task<ActionResult>
,然后使用 async/await 自上而下。另一种处理方法是将 .ConfigureAwait(false)
分散到所有 Task
和 await
,但是在处理异步工作时最好不要阻塞。
您的代码可能如下所示:
控制器:
public ActionResult Upload()
{
return View();
}
[HttpPost]
public async Task<ActionResult> Upload(HttpPostedFileBase file)
{
string filename = Guid.NewGuid() + Path.GetExtension(file.FileName);
string filepath = @"C:\Users385\source\repos\BookingSystem\BookingSystem\Surveys\" + filename;
file.SaveAs(Path.Combine(Server.MapPath("/Surveys"), filename));
await AzureVisionAPI.ExtractToTextFile(filepath);
return View();
}
AzureVisionAPI:
namespace BookingSystem.Helpers
{
static class AzureVisionAPI
{
static string subscriptionKey = ("SUBSCRIPTON_KEY");
static string endpoint = ("END_POINT");
public static ComputerVisionClient Authenticate(string endpoint, string key)
{
ComputerVisionClient client =
new ComputerVisionClient(new ApiKeyServiceClientCredentials(key))
{ Endpoint = endpoint };
return client;
}
public static async Task ExtractToTextFile(string filename)
{
ComputerVisionClient client = Authenticate(endpoint, subscriptionKey);
await ExtractTextLocal(client, filename);
}
public static async Task ExtractTextLocal(ComputerVisionClient client, string localImage)
{
// Helps calucalte starting index to retrieve operation ID
const int numberOfCharsInOperationId = 36;
using (Stream imageStream = File.OpenRead(localImage))
{
// Read the text from the local image
BatchReadFileInStreamHeaders localFileTextHeaders = await client.BatchReadFileInStreamAsync(imageStream);
// Get the operation location (operation ID)
string operationLocation = localFileTextHeaders.OperationLocation;
// Retrieve the URI where the recognized text will be stored from the Operation-Location header.
string operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId);
// Extract text, wait for it to complete.
int i = 0;
int maxRetries = 10;
ReadOperationResult results;
do
{
results = await client.GetReadOperationResultAsync(operationId);
await Task.Delay(1000);
if (maxRetries == 9)
{
throw new Exception("Azure API timed out");
}
}
while ((results.Status == TextOperationStatusCodes.Running ||
results.Status == TextOperationStatusCodes.NotStarted) && i++ < maxRetries);
// Display the found text.
var textRecognitionLocalFileResults = results.RecognitionResults;
foreach (TextRecognitionResult recResult in textRecognitionLocalFileResults)
{
using (StreamWriter sw = new StreamWriter(@"C:\Users385\source\repos\BookingSystem\BookingSystem\surveytest.txt"))
{
foreach (Line line in recResult.Lines)
{
sw.WriteLine(line.Text);
}
}
}
}
}
}
}