Home > OS >  HostedService blocks UI Thread?
HostedService blocks UI Thread?

Time:05-17

I have the following code for a MQTT Subscriber in a Background Task:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using PickByLight.BackgroundTask.Models;
using PickByLight.Database.Wrapper.Interfaces;
using PickByLight.Logic;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;

namespace PickByLight.BackgroundTask
{
    /// <summary>
    /// Hosted MQTT Background Service
    /// </summary>
    public class HostedMQTTService : IHostedService, IDisposable
    {


        private readonly Task _executingTask;
        private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
        /// <summary>
        /// MQTT Client
        /// </summary>
        private MqttClient MqttClient { get; set; }

        /// <summary>
        /// Name of the Pick by Light
        /// </summary>
        private string PickByLight_Name { get; set; }

        /// <summary>
        /// MQTT is activated
        /// </summary>
        private bool MqttIsActive { get; set; }

        /// <summary>
        /// IP Adress of the MQTT URL
        /// </summary>
        private string MqttURL { get; set; }


        /// <summary>
        /// Storage Process for an material
        /// </summary>
        private MaterialStorageProcess StorageProcess { get; set; }

        /// <summary>
        /// Service Scope Factory
        /// </summary>
        private IServiceScopeFactory ServiceScopeFactory { get; set; }

        /// <summary>
        /// Configuration
        /// </summary>
        private IConfiguration Configuration { get; set; }

        /// <summary>
        /// Logger
        /// </summary>
        private readonly ILogger<HostedMQTTService> _logger;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="configuration"></param>
        public HostedMQTTService(IConfiguration configuration, ILogger<HostedMQTTService> logger, IServiceScopeFactory serviceScopeFactory)
        {
            this.PickByLight_Name = configuration.GetValue<string>("PickByLight_Name");
            this.MqttURL = configuration.GetValue<string>("MQTTUrl");
            this.MqttIsActive = configuration.GetValue<bool>("MQTTConnection");
            this.ServiceScopeFactory = serviceScopeFactory;
            this.Configuration = configuration;
            this._logger = logger;
        }

        /// <summary>
        /// Start the Task of the Background Service
        /// </summary>
        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Background-Service started...");
            while (true)
            {
                try
                {
                    //No Object is created
                    if (this.MqttClient == null)
                    {
                        _logger.LogInformation("Try to establishe new MQTT Client");
                        this.MqttClient = CreateNewMqttConnection();
                    }
                    else if (this.MqttClient.IsConnected == false)
                    {
                        _logger.LogInformation("MQTT Client is disconnected... Try to reconnect!");
                        this.MqttClient = CreateNewMqttConnection();
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Ein schwerwiegender Fehler im MQTT Background-Service ist aufgetreten.");
                }
            }
        }

        /// <summary>
        /// Prints out all received messages
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Mqtt_Message_Received(object sender, MqttMsgPublishEventArgs e)
        {
            try
            {
                var agcMessage = Encoding.UTF8.GetString(e.Message);
                _logger.LogInformation("Topic: "   e.Topic   " | Nachricht: "   agcMessage   " | QOS: "   e.QosLevel);

                var resultString = Encoding.UTF8.GetString(e.Message);
                MqttReadTopicClass mqttContent = JsonConvert.DeserializeObject<MqttReadTopicClass>(resultString);

                using (var scope = this.ServiceScopeFactory.CreateScope())
                {
                    var storageConfigurationManager = scope.ServiceProvider.GetService<IStorageConfigurationManager>();
                    var storageElementManager = scope.ServiceProvider.GetService<IStorageElementManager>();
                    this.StorageProcess = new MaterialStorageProcess(storageConfigurationManager, storageElementManager, this.Configuration);


                    StorageProcess.Remove(mqttContent.storageLocation);
                }

            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Schwerwiegender Fehler beim Lesen von MQTT Nachrichten");
            }
        }




        /// <summary>
        /// Create new MQTT connection if connection is lost or doesn't exist
        /// </summary>
        private MqttClient CreateNewMqttConnection()
        {
            _logger.LogInformation("Create MQTT Client");
            MqttClient client = new MqttClient(this.MqttURL, 32005, false, null, null, MqttSslProtocols.None);
            string clientId = Guid.NewGuid().ToString();
            client.MqttMsgPublishReceived  = Mqtt_Message_Received;
            client.Connect(clientId);
            client.Subscribe(new string[] { "buttonpress_sepioo_pdi/"   this.PickByLight_Name }, new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
            _logger.LogInformation("MQTT Client created");
            return client;
        }

        /// <summary>
        /// Stop the Task of the Background Service
        /// </summary>
        public async Task StopAsync(CancellationToken cancellationToken)
        {
            //Stop called without start
            if (_executingTask == null)
            {
                return;
            }

            try
            {
                //Signal cancellation to the executing method
                _stoppingCts.Cancel();
            }
            finally
            {
                //wait until the task completes or the stop token triggers
                await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
            }
        }

        /// <summary>
        /// Dispose the Background Service
        /// </summary>
        public void Dispose()
        {
            _stoppingCts.Cancel();
        }

    }
}

In my startup.cs File i am doing the following:

//Register Background Task
services.AddHostedService<HostedMQTTService>();

The problem is, that it seems to me that the hosted service is blocking the user-interface/webserver threads because i can not access the url of the .net 6 mvc application.

Could you give me a hint or a solution to this problem?

Thanks.

CodePudding user response:

You are blocking the process, because your hosted service never starts.

  1. Remove the while(true) loop from the Start method.
  2. Ensure base.StartAsync(cancellationToken); is always called.

Edit: I saw you implement the IHostedService interface. Try to inherits from the BackgroundService class

CodePudding user response:

You will need to change your StartAsync-method to something like this:

   public Task StartAsync(CancellationToken cancellationToken)
    {
        return Task.Run(() => 
        {
            _logger.LogInformation("Background-Service started...");

            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    //No Object is created
                    if (this.MqttClient == null)
                    {
                        _logger.LogInformation("Try to establish new MQTT Client");
                        this.MqttClient = CreateNewMqttConnection();
                    }
                    else if (this.MqttClient.IsConnected == false)
                    {
                        _logger.LogInformation("MQTT Client is disconnected... Try to reconnect!");
                        this.MqttClient = CreateNewMqttConnection();
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Ein schwerwiegender Fehler im MQTT Background-Service ist aufgetreten.");
                }
            }
        });
    }
  • Related