Необработанная ошибка хоста возникает после выполнения функции

Я написал функцию Azure, которая загружает большой двоичный объект по триггеру HTTP. Когда я отлаживаю эту функцию локально, выполнение кода проходит через всю функцию, после возврата, а затем выдает неопределенную ошибку перед фактической отправкой возврата.

Вот функция:

public class GetBlob
    {
        private readonly IUpgradeDataRepositoryFactory _upgradeDataRepository;
        private readonly IAuthorizationHelper _authorizationHelper;

        public GetBlob(IUpgradeDataRepositoryFactory upgradeDataRepository, IAuthorizationHelper authorizationHelper){
            _upgradeDataRepository = upgradeDataRepository;
            _authorizationHelper = authorizationHelper;
        }

        [FunctionName("GetBlob")]
        public HttpResponseMessage Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = "GetBlob/{id}")] HttpRequest req,
            string id, ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
            var clientIp = (req.Headers["X-Forwarded-For"].FirstOrDefault() ?? "").Split(new char[] { ':' }).FirstOrDefault();

            try{
                _authorizationHelper.AssertRequestIsAuthorized(req);

                var blobInfo = _upgradeDataRepository.UpdateDataItemRepository.Query(q => q.BlobName == id).FirstOrDefault();
                if (blobInfo != null){
                    using (var blobStream = GetBlobStream(id))
                    {
                        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
                        result.Content = new StreamContent(blobStream);
                        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
                        result.Content.Headers.ContentDisposition.FileName = blobInfo.BlobFriendlyName;
                        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                        log.LogInformation(string.Format("Returning Update Blob: {0} to ip: {1}", id, clientIp));
                        return result;
                    }
                }
                else
                {
                    log.LogInformation(string.Format("Could not find update item record for blob id: {0} Ip: {1}", id, clientIp));
                    return new HttpResponseMessage(HttpStatusCode.NotFound);
                }
            }
            catch (AuthorizationException){
                log.LogInformation("Authorization failed");
                var message = new HttpResponseMessage()
                {
                    StatusCode = HttpStatusCode.Unauthorized
                };
                throw new HttpResponseException(message);
            }
            catch (Exception ex){
                log.LogError(string.Format("Error getting update blob: {0} for IP: {1}", id, clientIp));
                log.LogError(ex.ToString());
                throw new HttpResponseException(HttpStatusCode.BadRequest);
            }
            finally{
                log.LogInformation(string.Format("Exiting Get Update Blob: {0} for ip: {1}", id, clientIp));
            }
        }

        private static CloudStorageAccount GetStorageAccount()
        {
            var connParameter= "StorageAccountConnectionString";
            var connectionString = System.Environment.GetEnvironmentVariable($"{connParameter}");
            return CloudStorageAccount.Parse(connectionString);       
        }

        private static string GetContainerName(){
            var containerParameter= "UpdateBlobContainerName";
            var containerName = System.Environment.GetEnvironmentVariable($"{containerParameter}");
            return containerName;
        }


        private static Stream GetBlobStream(string id)
        {
            CloudStorageAccount account = GetStorageAccount();
            CloudBlobClient blobClient = account.CreateCloudBlobClient();
            CloudBlobContainer container = blobClient.GetContainerReference(GetContainerName());
            var blob = container.GetBlobReference(id);

            return blob.OpenReadAsync().Result;
        }
    }

(Примечание 1. Здесь используется HttpResponseMessage, поскольку он заменяет старый API и требует интеграции со старым кодом)

(Примечание 2. Хотя я не поделился кодом для AuthenticationHelper или UpgradeDataRepository, оба этих объекта были успешно использованы и протестированы в отдельной рабочей функции. UpgradeDataRepository подключается к базе данных SQL Azure и запрашивает некоторую информацию — это происходит успешно. как в рабочей функции, так и в этой функции. Однако рабочая функция не имеет доступа к хранилищу BLOB-объектов, поэтому ошибка должна быть связана с использованием хранилища BLOB-объектов.)

Вот вывод терминала:

[2024-03-27T19:04:34.288Z] Executing 'GetBlob' (Reason='This function was programmatically called via the host APIs.', Id=5b3af3ef-c61e-4ad7-a582-4982ba9d6b3e)
[2024-03-27T19:04:34.300Z] C# HTTP trigger function processed a request.
[2024-03-27T19:04:41.904Z] Returning Update Blob: 729ee33f-e283-420a-b898-648718139e3a to ip: 
[2024-03-27T19:04:41.906Z] Exiting Get Update Blob: 729ee33f-e283-420a-b898-648718139e3a for ip:
[2024-03-27T19:04:41.907Z] Executed 'GetBlob' (Succeeded, Id=5b3af3ef-c61e-4ad7-a582-4982ba9d6b3e, Duration=7650ms)
[2024-03-27T19:04:41.915Z] An unhandled host error has occurred.
[2024-03-27T19:04:41.916Z] Microsoft.WindowsAzure.Storage: Object reference not set to an instance of an object.

Обратите внимание, что сообщение «Выполнено 'GetBlob' (Успешно)» появляется вне/после выполнения моей функции, за которым следует сообщение об ошибке. Возврат не доходит до приложения, которое я тестирую.

Сообщение об ошибке расплывчато, и мой отладчик не улавливает шаг, на котором возникает эта ошибка, но это определенно происходит после того, как выполняется все остальное, что показано. Я даже проверил, что блоб успешно загружен и прикреплен к ответу.

Единственное, что я могу предположить на данный момент, это несоответствие версий? На всякий случай вот мой файл проекта:

<Project Sdk = "Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include = "Microsoft.Azure.Functions.Extensions" Version = "1.1.0" />
    <PackageReference Include = "Microsoft.EntityFrameworkCore.Design" Version = "6.0.14">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include = "Microsoft.EntityFrameworkCore.SqlServer" Version = "6.0.14" />
    <PackageReference Include = "Microsoft.EntityFrameworkCore.Tools" Version = "6.0.14">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include = "Microsoft.NET.Sdk.Functions" Version = "4.2.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update = "host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update = "local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

ОБНОВЛЕНИЕ: я попробовал заменить Microsoft.Windows.Azure на Azure.Storage.Blobs:

private static BlobServiceClient GetStorageAccount()
        {
            var connParameter= "StorageAccountConnectionString";
            var connectionString = System.Environment.GetEnvironmentVariable($"{connParameter}");
            return new BlobServiceClient(connectionString);           
        }

private static Stream GetBlobStream(string id)
        {
            BlobServiceClient account = GetStorageAccount();
            BlobContainerClient container = account.GetBlobContainerClient(GetContainerName());
            var blob = container.GetBlobClient(id);

            return blob.OpenReadAsync().Result;
        }

Теперь я получаю немного другую ошибку в терминале после того, как кажется, что все выполняется успешно:

[2024-03-28T12:09:20.144Z] Executed 'GetBlob' (Succeeded, Id=08567df1-e23f-4973-a9e5-a9750f0ff9ee, Duration=4304ms)
[2024-03-28T12:09:20.322Z] An unhandled host error has occurred.
[2024-03-28T12:09:20.323Z] System.Private.CoreLib: Value cannot be null. (Parameter 'buffer').
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
89
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Удивительно, но виновником в этом случае стал оператор using.

Я изменил метод для синхронного запуска и удалил оператор using. Я не уверен, почему это работает, но теперь функция загружается без проблем. Я могу только догадываться о том, что здесь происходит под капотом, но я думаю, что это заставляет загрузку большого двоичного объекта перейти к операции блокировки, гарантируя, что объект доступен для использования объектом ответа. Мне было бы любопытно, если кто-нибудь знает, почему это сработало.

                if (blobInfo != null){
                    var blob = GetBlobClient(id);
                    var blobStream = blob.OpenReadAsync().Result;
                    HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
                    result.Content = new StreamContent(blobStream);
                    result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
                    result.Content.Headers.ContentDisposition.FileName = blobInfo.BlobFriendlyName;
                    result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                    log.LogInformation(string.Format("Returning Update Blob: {0} to ip: {1}", id, clientIp));
                    return result;
                }

Другие вопросы по теме