首页 > 解决方案 > 尝试使用 IBackgroundTaskQueue 时未设置对象引用

问题描述

我正在尝试在基于 .NET Core 的 c# WebApi 2 项目中使用 IHostingService。

IHostingService 应该通过 SMPT 在每个通过队列后台任务确认的订单上发送电子邮件,我正在关注Microsoft 文档和在另一个问题中建议这种方式的用户的回答,问题是当我尝试运行 _taskQueue 我得到以下错误:

System.NullReferenceException:“对象引用未设置为对象的实例。”

虽然我无法理解我必须如何正确启动 IBackgroundTaskQueue 才能正确运行任务而不会出现 null ref 错误......

我的代码如下所示:

背景任务队列.cs:

 public interface IBackgroundTaskQueue
    {
        void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem);

        Task<Func<CancellationToken, Task>> DequeueAsync(
            CancellationToken cancellationToken);
    }

    public class BackgroundTaskQueue : IBackgroundTaskQueue
    {
        private ConcurrentQueue<Func<CancellationToken, Task>> _workItems =
            new ConcurrentQueue<Func<CancellationToken, Task>>();
        private SemaphoreSlim _signal = new SemaphoreSlim(0);

        public void QueueBackgroundWorkItem(
            Func<CancellationToken, Task> workItem)
        {
            if (workItem == null)
            {
                throw new ArgumentNullException(nameof(workItem));
            }

            _workItems.Enqueue(workItem);
            _signal.Release();
        }

        public async Task<Func<CancellationToken, Task>> DequeueAsync(
            CancellationToken cancellationToken)
        {
            await _signal.WaitAsync(cancellationToken);
            _workItems.TryDequeue(out var workItem);

            return workItem;
        }
    }

队列托管服务:

public class QueuedHostedService : BackgroundService
    {
        private readonly ILogger<QueuedHostedService> _logger;
        public QueuedHostedService(IBackgroundTaskQueue taskQueue,
            ILogger<QueuedHostedService> logger)
        {
            TaskQueue = taskQueue;
            _logger = logger;
        }

        public IBackgroundTaskQueue TaskQueue { get; }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation(
                $"Queued Hosted Service is running.{Environment.NewLine}");

            await BackgroundProcessing(stoppingToken);
        }

        private async Task BackgroundProcessing(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                var workItem =
                    await TaskQueue.DequeueAsync(stoppingToken);

                try
                {
                    await workItem(stoppingToken);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex,
                        "Error occurred executing {WorkItem}.", nameof(workItem));
                }
            }
        }

        public override async Task StopAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Queued Hosted Service is stopping.");

            await base.StopAsync(stoppingToken);
        }
    }

程序.cs

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) =>
        {
            services.AddSingleton<OrdineHelper>();
            services.AddHostedService<QueuedHostedService>();
            services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
        })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

这是OrdineHelper.cs我有几个静态函数的类,其中有ConfirmOrder函数,我必须在其中运行EmailHelper.SendRiepilogoAsync它返回一个 Task 为QueueBackgroundWorkItem

public class OrdineHelper
    {
        private static IBackgroundTaskQueue _taskQueue;

        public OrdineHelper(IBackgroundTaskQueue taskQueue)
        {
            _taskQueue = taskQueue;
        }

... // LOTS OF STATIC FUNCTIONS

            public static void ConfirmOrder(string piva, string orderID, double importo = 0, string transazione = "", string paymentID = "", string tipo = "MENU")
            {
                string connectionString = getConnectionString(piva);
                using var connection = new MySqlConnection(connectionString);
    
                string query_menu = "XXX;";
                string query_pagamenti = "XXX";
                using var cmd = new MySqlCommand(query_pagamenti, connection);
                connection.Open();
                ...
                cmd.ExecuteNonQuery();
    
                if (!tipo.Equals("MENU"))
                {
                    _taskQueue.QueueBackgroundWorkItem(ct => EmailHelper.SendRiepilogoAsync(piva, int.Parse(orderID))); // HERE I MUST RUN QueueBackgroundWorkItem but i get null ref error
                }
    
            }
    
    
    }

ConfirmOrder 在其他静态函数中被调用,如下所示:

public static IActionResult InsertOrdineTakeaway(string piva, string idNegozio, RiepilogoTakeaway ordine, HttpResponse Response)
    {
        ...
        if (pagamento.type.Equals("CO"))
        {
            ConfirmOrder(piva, idOrdine, 0, "", pagamento.id.ToString(), ordine.tipo.ToUpper());
        }
        Response.Cookies.Append("IDORDER", JsonConvert.SerializeObject(new { idOrdine, piva, payment = pagamento.type }), option);
        return new OkObjectResult(new { idOrdine });
    }

标签: c#asp.net-web-api2

解决方案


推荐阅读