如何解决WebForms Application_Error() 到 Azure Blob 存储 - 站点挂起
我在示例存储库中重现了一个问题,其中 WebForms 项目中未处理的异常在 Global.asax 中的 Application_Error 方法中被捕获。我需要该错误日志才能写入 Azure Blob 存储。 Blob 存储代码适用于应用程序中处理的错误以及拉入控制台应用程序时的错误。但是,未处理的异常将在“containerClient.CreateIfNotExistsAsync()”方法(这是链中的第一个 http 调用)上无限期挂起(不会失败)。
我相信 Blob 存储 SDK 在检查容器是否存在时确实会返回 http 409 [Conflict]。但是当我注释掉该行(并且容器存在)时,它在尝试上传文件时显示相同的行为。
知道为什么会挂起吗?
可在 this repo 中重现,只需创建您自己的存储帐户,将自己添加为 IAM 中的 blob 贡献者,使用帐户和容器名称更新 Web.Config。
一些代码片段
protected void Page_Load(object sender,EventArgs e) // Default.aspx
{
throw new Exception("is this the exception you are looking for?");
}
protected void Application_Error(object sender,EventArgs e) //Global.asax
{
Exception ex = Server.GetLastError();
Logger.AddLog(ex,string.Empty);
if (ex.InnerException != null) Logger.AddLog(ex.InnerException,string.Empty);
this.Response.Redirect("Error.aspx",true);
}
internal static void AddLog(Exception ex,string empty) // static class in Logger.cs
{
byte[] byteArray = Encoding.ASCII.GetBytes(ex.Message);
string fileName = Guid.NewGuid().ToString() + ".txt";
string storageAccountName = ConfigurationManager.AppSettings["storageAccountName"].ToString();
string storageContainerName = ConfigurationManager.AppSettings["storageContainerName"].ToString();
using (MemoryStream stream = new MemoryStream(byteArray))
{
StreamToCloudStorageAsync(storageAccountName,storageContainerName,stream,fileName).GetAwaiter().GetResult();
}
}
async static Task StreamToCloudStorageAsync(string accountName,string containerName,Stream sourceStream,string destinationFileName) // static class in Logger.cs
{
// Construct the blob container endpoint from the arguments.
string containerEndpoint = string.Format("https://{0}.blob.core.windows.net/{1}",accountName,containerName);
// Get a credential and create a client object for the blob container.
BlobContainerClient containerClient = new BlobContainerClient(new Uri(containerEndpoint),new DefaultAzureCredential());
// Create the container if it does not exist.
await containerClient.CreateIfNotExistsAsync();
var blobClient = containerClient.GetBlobClient(destinationFileName);
// Upload text to a new block blob.
var blob = await blobClient.UploadAsync(sourceStream);
}
知道为什么会挂起吗?
解决方法
.GetAwaiter().GetResult();
会阻塞您的代码并导致您的代码死锁。另见this blog post。
您应该让 AddLog
返回一个 Task 并await
调用 StreamToCloudStorageAsync
:
internal static Task AddLogAsync(Exception ex,string empty) // static class in Logger.cs
{
byte[] byteArray = Encoding.ASCII.GetBytes(ex.Message);
string fileName = Guid.NewGuid().ToString() + ".txt";
string storageAccountName = ConfigurationManager.AppSettings["storageAccountName"].ToString();
string storageContainerName = ConfigurationManager.AppSettings["storageContainerName"].ToString();
using (MemoryStream stream = new MemoryStream(byteArray))
{
await StreamToCloudStorageAsync(storageAccountName,storageContainerName,stream,fileName);
}
}
然后重构 Application_Error
事件处理程序以正确等待异步调用:
protected async void Application_Error(object sender,EventArgs e) //Global.asax
{
Exception ex = Server.GetLastError();
await Logger.AddLogAsync(ex,string.Empty);
if (ex.InnerException != null)
await Logger.AddLogAsync(ex.InnerException,string.Empty);
this.Response.Redirect("Error.aspx",true);
}
通常应该避免使用 async void
,但事件处理程序是一个例外。
奖金
您的代码仅记录异常和第一个内部异常(如果可用)。
await Logger.AddLogAsync(ex,string.Empty);
如果您想记录所有内部异常,请尝试
while(ex != null)
{
await Logger.AddLogAsync(ex,string.Empty);
ex = ex.InnerException
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。