ComputerVisionClient Microsoft.azure.cognitiveservices.vision.computervision

Luca Tassi 0 Punti di reputazione
2025-06-16T08:30:38.9066667+00:00

I'm having issues when calling my computer vision endpoint multiple times concurrently.
I get the following error:

ERROR: System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Net.Http.HttpConnection.WriteAsciiString(String s)
   at System.Net.Http.HttpConnection.WriteHeaderCollection(HttpHeaders headers, String cookiesFromContainer)
   at System.Net.Http.HttpConnection.WriteHeaders(HttpRequestMessage request)
   at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.<SendCoreAsync>g__Core|4_0(HttpRequestMessage request, Boolean useAsync, CancellationToken cancellationToken)
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.<SendCoreAsync>g__Core|4_0(HttpRequestMessage request, Boolean useAsync, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
   at Microsoft.Azure.CognitiveServices.Vision.ComputerVision.ComputerVisionClient.ReadInStreamWithHttpMessagesAsync(Stream image, String language, IList1 pages, String modelVersion, String readingOrder, Dictionary2 customHeaders, CancellationToken cancellationToken)
   at Microsoft.Azure.CognitiveServices.Vision.ComputerVision.ComputerVisionClientExtensions.ReadInStreamAsync(IComputerVisionClient operations, Stream image, String language, IList1 pages, String modelVersion, String readingOrder, CancellationToken cancellationToken).

I thought the issue was the initialization of my http client in my .net core 9 project but now after all the improvement I developed to correctly inject the httpclient as follows

        service.AddHttpClient<IHttpCaller, HttpCaller>()
                .ConfigurePrimaryHttpMessageHandler(() =>
                {
                    var handler = new SocketsHttpHandler
                    {
                        // Explicitly set connection lifetime to refresh regularly.
                        PooledConnectionLifetime = TimeSpan.FromMinutes(10),
                        // Explicit idle connection management.
                        PooledConnectionIdleTimeout = TimeSpan.FromMinutes(5),
                        // Enable TCP KeepAlive to detect broken connections earlier
                        KeepAlivePingPolicy = HttpKeepAlivePingPolicy.Always,
                        KeepAlivePingDelay = TimeSpan.FromSeconds(30),
                        KeepAlivePingTimeout = TimeSpan.FromSeconds(10),
                        // Configure proxy if needed.
                        Proxy = proxy != null && !string.IsNullOrWhiteSpace(proxy.Url)
                ? new WebProxy(proxy.Url, true)
                {
                    Credentials = !string.IsNullOrWhiteSpace(proxy.Username)
                          ? new NetworkCredential(proxy.Username, proxy.Password, proxy.Domain)
                          : null
                }
                : null,
                        UseProxy = proxy != null && !string.IsNullOrWhiteSpace(proxy.Url),
                        // Control maximum simultaneous connections per server if necessary.
                        MaxConnectionsPerServer = 1000,
                        // Add connect timeout for faster failure detection
                        ConnectTimeout = TimeSpan.FromSeconds(30),
                    };
                    return handler;
                })
                .SetHandlerLifetime(Timeout.InfiniteTimeSpan)
                .ConfigureHttpClient(client =>
                {
                    client.Timeout = TimeSpan.FromMinutes(10);
                    client.DefaultRequestVersion = HttpVersion.Version20;
                    client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower;
                    // Add connection establishment
                    client.DefaultRequestHeaders.ConnectionClose = false; 
                });

the error is still happening.

This is the code calling the ocr computer vision

using Microsoft.Azure.CognitiveServices.Vision.ComputerVision;
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models;
using PolarisAI.Common.Contracts.Building;
using PolarisAI.Common.Contracts.Reading;
using PolarisAI.ImageReader.App;
using PolarisAI.ImageReader.Conversion;
using PolarisAI.ImageReader.OutputReaders;
namespace PolarisAI.ImageReader
{
    /// <summary>
    /// Provides OCR (Optical Character Recognition) functionality using Azure Cognitive Services Computer Vision API.
    /// Handles document conversion and communication with Azure OCR endpoints.
    /// </summary>
    public class AzureOcrReader : IOcrReader
    {
        /// <summary>
        /// Parameters for configuring the AzureOcrReader.
        /// </summary>
        /// <param name="IsConversionToImageDisabled">Disables conversion to image if true.</param>
        /// <param name="TiffConversionResolution">Resolution to use for TIFF conversion.</param>
        public record Parameters(bool IsConversionToImageDisabled, int TiffConversionResolution = 150);
        private readonly HttpClient _httpClient;
        private readonly string? _ocrEndpoint;
        private readonly string? _key;
        private const int MaxPollingIterations = 300;
        private const int PollingInterval = 2000;
        
        /// <summary>
        /// Gets the TIFF conversion resolution.
        /// </summary>
        public int TiffConversionResolution { get; }
        /// <summary>
        /// Gets a value indicating whether conversion to image is disabled.
        /// </summary>
        public bool IsConversionToImageDisabledDefault { get; }
        /// <summary>
        /// Initializes a new instance of the <see cref="AzureOcrReader"/> class.
        /// </summary>
        /// <param name="httpClient">The HTTP client to use for requests.</param>
        /// <param name="description">A description for the reader instance.</param>
        /// <param name="ocrEndpoint">The Azure OCR endpoint URL.</param>
        /// <param name="key">The Azure OCR API key.</param>
        /// <param name="parameters">Parameters for conversion and resolution.</param>
        public AzureOcrReader(HttpClient httpClient, string description, string? ocrEndpoint, string? key, Parameters parameters)
        {
            _httpClient = httpClient;
            _ocrEndpoint = ocrEndpoint;
            _key = key;
            IsConversionToImageDisabledDefault = parameters.IsConversionToImageDisabled;
            TiffConversionResolution = parameters.TiffConversionResolution;
        }
        /// <summary>
        /// Authenticates and creates a ComputerVisionClient for Azure OCR.
        /// </summary>
        /// <param name="httpClient">The HTTP client to use.</param>
        /// <param name="key">The API key.</param>
        /// <param name="ocrEndpoint">The endpoint URL.</param>
        /// <returns>A configured ComputerVisionClient instance.</returns>
        private static ComputerVisionClient Authenticate(HttpClient httpClient, string key, string ocrEndpoint)
        {
            ComputerVisionClient client = new ComputerVisionClient(new ApiKeyServiceClientCredentials(key), httpClient, false) { Endpoint = ocrEndpoint };
            return client;
        }
        /// <summary>
        /// Reads a document asynchronously and performs OCR, optionally converting to image.
        /// </summary>
        /// <param name="documentName">The name of the document.</param>
        /// <param name="buffer">The document content as a byte array.</param>
        /// <param name="isConversionToImageDisabled">Optional override for image conversion.</param>
        /// <returns>The OCR output result.</returns>
        public async Task<IOcrOutput> ReadDocAsync(string documentName, byte[] buffer, bool? isConversionToImageDisabled = null)
        {
            var isConversionDisabled = isConversionToImageDisabled ?? IsConversionToImageDisabledDefault;
            try
            {
                byte[] newBuffer = !isConversionDisabled ? FormatConverter.ToImage(documentName, buffer, PdfEvaluator.HasToBeConvertedToImage, TiffConversionResolution) : buffer;
                return await ReadImageAsync(documentName, newBuffer);
            }
            catch (Exception e)
            {
                return OcrOutput.ReadingFailure(documentName, e.ToString());
            }
        }
        /// <summary>
        /// Logs the current parameters for the reader.
        /// </summary>
        /// <returns>A string representing the parameters.</returns>
        public string LogParameters() => $"{nameof(IsConversionToImageDisabledDefault)}: {IsConversionToImageDisabledDefault}, {nameof(TiffConversionResolution)}: {TiffConversionResolution}";
        /// <summary>
        /// Reads an image asynchronously and performs OCR using Azure Computer Vision.
        /// </summary>
        /// <param name="documentName">The name of the document.</param>
        /// <param name="buffer">The image content as a byte array.</param>
        /// <returns>The OCR output result.</returns>
        private async Task<IOcrOutput> ReadImageAsync(string documentName, byte[] buffer)
        {
            MemoryStream inputStream = new MemoryStream(buffer);
            LogWriter logger = new LogWriter();
            try
            {
                var key = _key ?? Environment.GetEnvironmentVariable(Constants.AzureOcrEnvKey) ?? throw new EmptyCredentialException($"Empty environment variable {nameof(Constants.AzureOcrEnvKey)}");
                var url = _ocrEndpoint ?? Environment.GetEnvironmentVariable(Constants.AzureOcrEnvUrl) ?? throw new EmptyCredentialException($"Empty environment variable {nameof(Constants.AzureOcrEnvUrl)}");
                using var client = Authenticate(_httpClient, key, url);
                logger.LogStart(documentName, buffer, $"{nameof(IsConversionToImageDisabledDefault)}: {IsConversionToImageDisabledDefault}");
                IReaderRawOutputStructure results = await CallOcrService(client, inputStream);
                logger.LogSummary($"Ocr result: {results.Status}");
                return new OcrOutput(results, logger.ToString());
            }
            catch (Exception e)
            {
                logger.LogError("ERROR: " + e);
                return OcrOutput.ReadingFailure(documentName, logger.ToString());
            }
            finally
            {
                inputStream.Dispose();
            }
        }
        /// <summary>
        /// Calls the Azure OCR service and polls for the result.
        /// </summary>
        /// <param name="client">The ComputerVisionClient instance.</param>
        /// <param name="inputStream">The input stream containing the image data.</param>
        /// <returns>The raw OCR output structure.</returns>
        private static async Task<IReaderRawOutputStructure> CallOcrService(ComputerVisionClient client, MemoryStream inputStream)
        {
            var textHeaders = await client.ReadInStreamAsync(inputStream);
            // After the request, get the operation location (operation ID)
            string operationLocation = textHeaders.OperationLocation;
            await Task.Delay(PollingInterval);
            // <snippet_extract_response>
            // Retrieve the URI where the recognized text will be stored from the Operation-Location header.
            // We only need the ID and not the full URL
            const int numberOfCharsInOperationId = 36;
            string operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId);
            // Extract the text
            int cyclesCounter = 0;
            ReadOperationResult results;
            do
            {
                results = await client.GetReadResultAsync(Guid.Parse(operationId));
                await Task.Delay(PollingInterval);
                cyclesCounter++;
            } while ((results.Status == OperationStatusCodes.Running || results.Status == OperationStatusCodes.NotStarted) && cyclesCounter < MaxPollingIterations);
            return new AzureRawOutputStructure(results);
        }
    }
}

Can you help me understand what could be the issue?
Thanks

Tecnologie per sviluppatori | C#
0 commenti Nessun commento
{count} voti

Risposta

Le risposte possono essere contrassegnate come risposte accettate dall'autore della domanda. Ciò consente agli utenti di sapere che la risposta ha risolto il problema dell'autore.