I have a a SignalR client which seems to close straight after starting, the error message i get is:
"The server closed the connection with the following error: Connection closed with an error. InvalidOperationException: Sequence contains no elements"
The SignalR client is being used in a ASP.Net Core Web API project (within an API controller).
The Nuget package i am using is called Microsoft.AspNetCore.SignalR.Client (v 1.1.0)
My code looks like this:
try
{
//SEND MESSAGE TO HUB
var connection = new HubConnectionBuilder()
.WithUrl("https://sample.azurewebsites.net/ChatHub")
.Build();
connection.Closed += async (error) =>
{
//log error - this is getting called straight after StartAsync
};
await connection.StartAsync();
await connection.InvokeAsync("SendToATeam", "x", "y");
await connection.StopAsync();
}
catch (Exception ex)
{
//log error
}
On your server you can turn on detailed errors via:
services.AddSignalR(o =>
{
o.EnableDetailedErrors = true;
})
This will then give you a more detailed error message on the client
Related
I've been trying to setup an integration between an Angular 13 client-side app and a .NET Framework 4.8 API with an Azure Signal R Service. After much trial and error this week I have finally got my api to build without CORS errors and I can make a successful negotiate call using postman. I am using the #aspnet/signalr client-side package since that is the only signal R package that support Azure Signal R Services.
Below is the angular code I am using to make a connection to my signal R hub named DashboardHub
import { Injectable } from '#angular/core';
import * as signalR from '#aspnet/signalr';
#Injectable()
export class SignalrService {
public initializeSignalRConnection(): void {
let connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:58556/signalr/dashboardhub")
.configureLogging(signalR.LogLevel.Debug)
.build();
connection.start()
.then(() => {
console.log("connection.start");
//connection.invoke("send", "Hello")
})
.catch((error) => {
console.log("connection start error", error);
});
connection.on("send", data => {
console.log(data);
});
}
}
The problem I am having is within the connection.start which returns an error Cannot read properties of undefined (reading 'length'). Screenshot of that browser error below.
API Signal R mapping for context
And here is the DashboardHub for reference
in development, I have working .net core c# code that checks for a sink and creates it if not present:
var builder = new ConfigServiceV2ClientBuilder { JsonCredentials = key, QuotaProject = billingProjectId };
var sinkClient = await builder.BuildAsync(cancellationToken);
LogSink? sink;
try
{
sink = await sinkClient.GetSinkAsync(new LogSinkName(clientProjectId, sinkName), cancellationToken);
}
catch (Exception ex)
{
if (ex.Message.Contains("NotFound"))
{
sink = new LogSink
{
Name = "sink-test",
Disabled = true,
Description = "A sink",
Destination = $"bigquery.googleapis.com/projects/{clientProjectId}/datasets/bq_logs",
Filter = #"
protoPayload.methodName=""jobservice.jobcompleted""
resource.type=""bigquery_resource""
protoPayload.serviceData.jobCompletedEvent.job.jobStatistics.totalBilledBytes!=""0""
"
};
sink = await sinkClient.CreateSinkAsync(ProjectName.FromProject(clientProjectId), sink); // fails on production server
}
}
However, when I run it in production, the get works, but the create fails:
GetSinkAsync Status(StatusCode="NotFound", Detail="Sink sink-test does not exist")
CreateSink Failure after 10028.3424ms: Status(StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: The connection timed out from inactivity. (logging.googleapis.com:443) QuicException: The connection timed out from inactivity.", DebugException="System.Net.Http.HttpRequestException: The connection timed out from inactivity. (logging.googleapis.com:443)
We've tested for several days over several projects with no joy.
I had SignalR working with a HubConnection prior to .NET Core 6. Now the same code is generating an error when you try to start the connection that the builder is creating:
New-line characters are not allowed in header values.
I also think my other version was working with HTTP and this new project is using HTTPS. The Hub is up and working fine within the website itself. But my external app is having trouble establishing a connection using the following code:
var notifyConnection = new HubConnectionBuilder()
.WithUrl(baseUrl + "/notify", options =>
{
options.AccessTokenProvider = async () =>
{
var stringData = JsonConvert.SerializeObject(new { username = user, password = pass });
var content = new StringContent(stringData);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await httpClient.PostAsync(baseUrl + "/api/token", content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
};
})
.WithAutomaticReconnect()
.Build();
notifyConnection.Closed += async (error) =>
{
if (Debug) _logger.LogInformation("Hub connection closed: " + error.Message);
await Task.Delay(new Random().Next(0, 5) * 1000);
await notifyConnection.StartAsync();
};
try
{
var task = notifyConnection.StartAsync();
task.Wait();
}
catch (Exception ex)
{
if (Debug) _logger.LogInformation("Hub connection start error: " + ex.Message);
}
The exception happens when the connection is attempted to be started asynchronously. Anyone run into a similar issue? I have verified that stringData does not have new-line characters. SignalR client is 6.0.6. I am stumped. Any help is greatly appreciated.
UPDATE:
I had trouble with the token generator. I was able to get past this error. Now it is throwing the following error:
The SSL connection could not be established, see inner exception.
The inner exception says that the certificate is invalid. That is because the certificate is for an external connection rather than the server's IP address. The HttpClient is already ignoring certificate errors with the following code:
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ServerCertificateCustomValidationCallback =
(httpRequestMessage, cert, cetChain, policyErrors) =>
{
return true;
};
httpClient = new HttpClient(handler);
UPDATE 2:
It is now working. I had to also tell the web sockets to ignore certificate errors. Found the solution in another question:
https://stackoverflow.com/a/63973431/2022236
I'm looking at incorporating Azure SignalR functionality into my .net core Blazor web application. To this end i've been following this tutorial - Azure Signalr Serverless. This is working fine - i have a project running the Azure functions app and can start up two browsers and have a chat session. What i'm trying to do is add the ability to receive these message notifications from the Azure signalR hub that's been configured into my Blazor app. I've added the following code in Index.razor.cs that mimics the javascript code in the example client:
public class IndexComponent : ComponentBase
{
private HubConnection _connection;
public string Message;
protected override Task OnInitializedAsync()
{
_connection = new HubConnectionBuilder()
.WithUrl("http://localhost:7071/api")
.Build();
_connection.On<string, string>("ReceiveMessage", (user, message) =>
{
Message = $"Got message {message} from user {user}";
this.StateHasChanged();
});
_connection.StartAsync();
return base.OnInitializedAsync();
}
}
The example javascript code btw is:
const connection = new signalR.HubConnectionBuilder()
.withUrl(`${apiBaseUrl}/api`)
.configureLogging(signalR.LogLevel.Information)
.build();
connection.on('newMessage', newMessage);
connection.onclose(() => console.log('disconnected'));
console.log('connecting...');
connection.start()
.then(() => data.ready = true)
.catch(console.error);
So the problem is that my Blazor app never receives any message notifications sent from the javascript chat clients (so the _connection.On handler is never hit). What am i missing in my Blazor code ?
Ok so this is what i needed to do to get it to work in my Blazor app:
_connection.On<object>("newMessage", update =>
{
Console.WriteLine(update);
//Message = update;
});
I needed to subscribe to the 'newMessage' target (since that's the JS is sending on) and also the type that's being posted isn't a string but a JObject type which i would need to deserialize to the correct type.
I've created small module for website, which uses SignalR to detect if user needs to refresh the browser. Locally it works, but when code went into production, thousands of errors are produced:
request: (lots of pages from website)
referer: https://(website)/signalr/abort
error message: 403: Http Error 403
Server side: (mainProject/Hubs directory):
public class AppVersionNotifierHub : Hub<IAppVersionNotifierHub>
{
public void CheckAppVersion(string version)
{
// if client has diffrent version, invoke callback
if (Global.Version != version)
{
Clients.Caller.NewAppVersion(Global.Version);
}
}
}
Javascript (type script):
this.subscribeVersionChecker = () => {
var hub = (<any>$.connection).appVersionNotifierHub;
hub.client.newAppVersion = (version: string) => {
.. some logic
}
$.connection.hub.start(() => {
hub.server.checkAppVersion(customerVersion.text());
});
$.connection.hub.reconnected(() => {
setTimeout(() => {
hub.server.checkAppVersion(customerVersion.text());
}, 5000); // Restart connection after 5 seconds.
});
$.connection.hub.disconnected(() => {
setTimeout(() => {
$.connection.hub.start();
}, 10000); // Restart connection after 10 seconds.
});
};
Any ideas why some clients generates errors ?
Site is hosted on azure
To use bundles, I've copied dynamically generated signalr.js file into Scripts\signalrhub.js file
I have discovered the problem now.
Problem was with authentication, I've read this article: http://www.bitwisejourneys.com/signalr-authenticating-even-when-you-dont-think-it-is/ and after some thinking I was able to reproduce the problem.
Open site in one tab and log in
Open site in the other tab and log out
Restart the connection on server
Tab 1 is sending the same authentication token as Tab 2. Server denies Tab 1 but responds to Tab 2
My solution: when connection is lost, I'm not trying to reconnect, but to stop and restart the connection (note I've changed the event from Reconnected to Reconnecting !)
$.connection.hub.reconnecting(() => {
$.connection.hub.stop();
setTimeout(() => {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});