Azure函数执行后出现未处理主机错误的问题排查
问题:Azure函数返回Blob后抛出未处理主机错误
问题背景
我编写了一个基于HTTP触发的Azure函数,用于下载Blob。本地调试时,代码完整执行完毕并返回结果后,会抛出模糊错误,导致返回无法送达测试应用。
原函数代码
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; } }
补充说明
- 使用
HttpResponseMessage是为了替代旧API,适配原有代码 AuthenticationHelper和UpgradeDataRepository已在其他正常函数中验证,问题应与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.
可见函数执行成功的日志出现后,随即抛出错误。猜测可能是版本不兼容,附上项目文件:
项目文件内容
<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>
更新尝试:切换到Azure.Storage.Blobs
将Microsoft.Windows.Azure替换为Azure.Storage.Blobs,修改后的Blob操作代码如下:
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').
内容的提问来源于stack exchange,提问作者Kenbo
相关产品推荐
相关产品推荐

