title: .Net Core 3.1 SignalR - Unable to read messages on server from client using .NET Client Package
body: <p>I am trying to create a client connection to the SignalR HUB with an IHosted background service on the .net core server. I want to be able to read/process the data that is received from a signalR Client once it arrives at the server. Imagine it as a way of intercepting and reading the messages as they are passed through the server hub.</p>
  
  <p>It seems that I could attach some further logic to the methods that are being called on the server in the SignalR Hub Class, but I don't think this would ensure a thread safe situation, given i want to read the messages received across the various SignalR connections and add the message content to a static list that can be indexed. The message content would be a collection of items like you'd have in an IList, something that I can run queries on add/remove etc..</p>
  
  <p>The docs on Microsoft are not helping me so far, but it appears using the latest SignalR package with .NET Core 3, creating a .NET SignalR client should be possible, but the examples they give are based on a separate C# console project. </p>
  
  <p>I think the issue I may be having is partly to do with the way I'm implementing the IHosted background service i.e. once the SignalR connection has started, the background service Task finishes execution. It appears to the part/logic I'm missing is a thread process that sits and wait until a message arrives, then sucks the content out and does whatever I decide to do from there.</p>
  
  <p>The SignalR hub itself and the client-side browser chat example I used from Microsoft is working fine using a test razor page, so the issue unlikely to be the hub.</p>
  
  <p>In the IHosted Service code section below, I see the first log event "STARTING SIGNALR at..." generated when the background service has first started, but looking at the Debug console, it looks like the service task completes once SignalR connection has been established, then nothing more is done. I realize my approach to this is likely incorrect, i'm comfortable with SignalR when all i'm doing is passing data between client end points through the browser client using javascript, but this requirement requires a different approach and not well documented. </p>
  
  <pre><code> namespace MyProjectNamespace.Classes.Events
   {
    public class SystemEventsService : IHostedService
    {
      // Create an instance of a CancellationTokenSource that will be used to stop the system mappings from running.
      public static CancellationTokenSource cancelSource;
  
      private readonly ILogger&lt;SystemEventsService&gt; _logger;
  
      public SystemEventsService(ILogger&lt;SystemEventsService&gt; logger)
      {
          _logger = logger;
      }
  
      HubConnection connection;
  
      public async Task StartAsync(CancellationToken cancellationToken)
      {
          connection = new HubConnectionBuilder()
              .WithUrl("http://localhost:44372/dataHub")
              .WithAutomaticReconnect()
              .Build();
  
          _logger.LogInformation("STARTING SIGNALR at {Time}", DateTime.UtcNow);
  
          connection.On&lt;string, string&gt;("ReceiveMessage", (user, message) =&gt;
          {
              _logger.LogInformation("String [" + message + "] received on server side at {Time}", DateTime.UtcNow);
          });
  
          connection.Closed += async (error) =&gt;
          {
              await Task.Delay(new Random().Next(0, 5) * 1000);
              await connection.StartAsync();
          };
  
          try
          {
              await connection.StartAsync();
          }
          catch (Exception ex)
          {
              _logger.LogInformation(ex.Message, DateTime.UtcNow);
          }
      }
  
      public Task StopAsync(CancellationToken cancellationToken)
      {
          return Task.CompletedTask;
      }
    }
  }
  </code></pre>
  
  <p>Program.CS file where I start the background service:</p>
  
  <pre><code> public static IHostBuilder CreateHostBuilder(string[] args) =&gt;
          Host.CreateDefaultBuilder(args)
          .ConfigureLogging((context, logging) =&gt;
          {
              logging.ClearProviders();
              logging.AddConfiguration(context.Configuration.GetSection("Logging"));
              logging.AddDebug();
              logging.AddConsole();
              // EventSource, EventLog, TraceSource, AzureAppServicesFile, AzureAppServicesBlob, ApplicatioInsights
          })
          .ConfigureWebHostDefaults(webBuilder =&gt;
          {
              webBuilder.UseStartup&lt;Startup&gt;();
          })
          .ConfigureServices(services =&gt;
          {
              services.AddHostedService&lt;SystemEventsService&gt;(); // This the service
          });
  </code></pre>
  
  <p>Razor Page - Javascript Client (which is working fine)</p>
  
  <pre><code>    &lt;div class="container"&gt;
      &lt;div class="row"&gt;&amp;nbsp;&lt;/div&gt;
      &lt;div class="row"&gt;
          &lt;div class="col-2"&gt;User&lt;/div&gt;
          &lt;div class="col-4"&gt;&lt;input type="text" id="userInput" /&gt;&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="row"&gt;
          &lt;div class="col-2"&gt;Message&lt;/div&gt;
          &lt;div class="col-4"&gt;&lt;input type="text" id="messageInput" /&gt;&lt;/div&gt;
      &lt;/div&gt;
      &lt;div class="row"&gt;&amp;nbsp;&lt;/div&gt;
      &lt;div class="row"&gt;
          &lt;div class="col-6"&gt;
              &lt;input type="button" id="sendButton" value="Send Message" /&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="row"&gt;
      &lt;div class="col-12"&gt;
          &lt;hr /&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="row"&gt;
      &lt;div class="col-6"&gt;
          &lt;ul id="messagesList"&gt;&lt;/ul&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  
  &lt;script src="~/js/signalr/dist/browser/signalr.js"&gt;&lt;/script&gt;
  
      &lt;script&gt;
      var connection = new signalR.HubConnectionBuilder().withUrl("/dataHub").build();
  
      //Disable send button until connection is established
      document.getElementById("sendButton").disabled = true;
  
      connection.on("ReceiveMessage", function (user, message) {
          var msg = message.replace(/&amp;/g, "&amp;amp;").replace(/&lt;/g, "&amp;lt;").replace(/&gt;/g, "&amp;gt;");
          var encodedMsg = user + " says " + msg;
          var li = document.createElement("li");
          li.textContent = encodedMsg;
          document.getElementById("messagesList").appendChild(li);
      });
  
      connection.start().then(function () {
          document.getElementById("sendButton").disabled = false;
      }).catch(function (err) {
          return console.error(err.toString());
      });
  
      document.getElementById("sendButton").addEventListener("click", function (event) {
          var user = document.getElementById("userInput").value;
          var message = document.getElementById("messageInput").value;
          connection.invoke("SendMessage", user, message).catch(function (err) {
              return console.error(err.toString());
          });
          event.preventDefault();
      });
  &lt;/script&gt;
  </code></pre>
  
  <p>SignalR Hub Class:</p>
  
  <pre><code>public class DataHub : Hub
  {
  
      private readonly ILogger&lt;DataHub&gt; _logger;
  
      public DataHub(ILogger&lt;DataHub&gt; logger)
      {
          _logger = logger;
      }
  
  
      public async Task SendMessage(string user, string message)
      {
          await Clients.All.SendAsync("ReceiveMessage", user, message);
          _logger.LogInformation("String [" + message + "] received on server hub at {Time}", DateTime.UtcNow);
      }
  }
  </code></pre>