【问题标题】:WebForms Application_Error() to Azure Blob Storage - Site HangsWebForms Application_Error() 到 Azure Blob 存储 - 站点挂起
【发布时间】:2023-03-19 18:03:01
【问题描述】:

我在示例存储库中重现了一个问题,其中 WebForms 项目中的未处理异常被 Global.asax 中的 Application_Error 方法捕获。我需要该错误日志来写入 Azure Blob 存储。 Blob 存储代码适用于应用程序中已处理的错误以及拉入控制台应用程序时的错误。但是,未处理的异常将无限期挂起(不会失败)“containerClient.CreateIfNotExistsAsync()”方法(这是链中的第一个 http 调用)。

我相信 Blob 存储 SDK 在检查容器是否存在时确实会返回 http 409 [Conflict]。但是当我注释掉该行(并且容器存在)时,它会在尝试上传文件时显示相同的行为。

任何想法为什么会挂起?

可在 this repo 中重现,只需创建自己的存储帐户,将自己添加为 IAM 中的 blob 贡献者,使用帐户和容器名称更新 Web.Config。

一些代码sn-ps

    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);
    }

任何想法为什么会挂起?

【问题讨论】:

    标签: .net azure webforms azure-blob-storage


    【解决方案1】:

    .GetAwaiter().GetResult(); 会阻塞您的代码,并导致您的代码出现死锁。另见this blog post

    您应该让AddLog 返回一个任务,并让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);
            if (ex.InnerException != null) 
                await Logger.AddLogAsync(ex.InnerException, string.Empty);
    

    如果您想记录所有内部异常,请尝试

    while(ex != null)
    {
        await Logger.AddLogAsync(ex, string.Empty);
        ex = ex.InnerException
    }
    

    【讨论】:

      猜你喜欢
      • 2020-08-20
      • 2014-06-17
      • 2023-02-07
      • 1970-01-01
      • 2016-05-15
      • 1970-01-01
      • 2017-04-18
      • 2014-02-03
      • 2017-02-20
      相关资源
      最近更新 更多