AspNet Core Integration Test For SignalR - asp.net-core

Is there away to test SignalR using TestServer generated as part of integration tests (https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests view=aspnetcore-2.1)?
All my retries failed to perform handshake to the TestServer instance fail with Exception: System.Net.Sockets.SocketException : No connection could be made because the target machine actively refused it
Running in Debug/Console/IIS works perfectly
Server Code
public void Configure(...)
{
...
app.UseSignalR(router => router.MapHub<MockHub>("/ws"));
...
}
TestCode
...
var server = factory.Server;
var connection = new HubConnectionBuilder()
.WithUrl(server.BaseAddress)
.Build();
await connection.StartAsync();

Looks like TestServer requires you to use the HttpMessageHandler created by it, so change your code to
.WithUrl(new Uri(server.BaseAddress, "ws"), o =>
{
o.HttpMessageHandlerFactory = _ => server.CreateHandler();
})

It should work. The only thing I see obviously wrong is that you're passing just the test host address to WithUrl, whereas, it should be the full path to your hub, i.e. something like:
.WithUrl(new Uri(server.BaseAddress, Consts.TethysWebSocketPath))

Related

MQTTnet Connection Issue with HiveMQ Cloud

I am new to the MQTT world and I am trying to create a .Net 5.0 application that connects to a HiveMQ Cloud Broker.
I have created a free broker and I am able to connect to it with HiveMQ Websocket Client.
Here is a screenshot of my host.
I have created MQTT credentials for the host and I am able to connect over the sample client. Here is a screenshot of that client.
This works, I can publish and subscribe to the message queue.
However, now I am trying to translate this to c# and I am not able to connect. I am starting with this example project: https://github.com/rafiulgits/mqtt-client-dotnet-core
Then plugged the values from my cluster instance but I am a getting connection timeout on startup.
Here is what my service configuration looks like:
public static IServiceCollection AddMqttClientHostedService(this IServiceCollection services)
{
services.AddMqttClientServiceWithConfig(aspOptionBuilder =>
{
//var clientSettinigs = AppSettingsProvider.ClientSettings;
//var brokerHostSettings = AppSettingsProvider.BrokerHostSettings;
aspOptionBuilder
.WithCredentials("Test1", "xxxxx") //clientSettinigs.UserName, clientSettinigs.Password)
.WithClientId("clientId-jqE8uIw6Pp") //clientSettinigs.Id)
.WithTcpServer("xxxxxxxxxxxxxx.s2.eu.hivemq.cloud", 8884); //brokerHostSettings.Host, brokerHostSettings.Port);
});
return services;
}
private static IServiceCollection AddMqttClientServiceWithConfig(this IServiceCollection services, Action<AspCoreMqttClientOptionBuilder> configure)
{
services.AddSingleton<IMqttClientOptions>(serviceProvider =>
{
var optionBuilder = new AspCoreMqttClientOptionBuilder(serviceProvider);
configure(optionBuilder);
return optionBuilder.Build();
});
services.AddSingleton<MqttClientService>();
services.AddSingleton<IHostedService>(serviceProvider =>
{
return serviceProvider.GetService<MqttClientService>();
});
services.AddSingleton<MqttClientServiceProvider>(serviceProvider =>
{
var mqttClientService = serviceProvider.GetService<MqttClientService>();
var mqttClientServiceProvider = new MqttClientServiceProvider(mqttClientService);
return mqttClientServiceProvider;
});
return services;
}
I am not sure where I am going wrong, any help would be greatly appreciated.
You appear to be trying to connect to the WebSocket endpoint (port 8884) in your code, when I suspect you really should be using the normal TLS endpoint (port 8883)
Also you will need to use different clientid values if you want to have both clients connected at the same time as having matching will mean the clients will continuously kick each other off the broker.
(edit: on looking closer the client ids are actually different, but only in the last char)
I had this issue in two days ago and it seems coming form TLS confgurations/settings. By the way, my Startup.cs service injections and some configurations were same with yours. I have .NetCore app and I am trying to connect my own hivemq broker (cloud side).
In this case we need to add additional option to our mqtt client option build phase.
When I add this code, Auth problems gone.
.WithTls();
Here is part of the client option codes should like that
AddMqttClientServiceWithConfig(services,optionBuilder =>
{
var clientSettings = BrokerAppSettingsProvider.BrokerClientSettings;
var brokerHostSettings = BrokerAppSettingsProvider.BrokerHostSettings;
optionBuilder
.WithCredentials(clientSettings.UserName, clientSettings.Password)
.WithTls()
.WithTcpServer(brokerHostSettings.Host, brokerHostSettings.Port);
});
return services;
We can consider this as a different solution.

Integrationtest IHost TestServer won't shutdown

I wrote some integration tests for an aspnetcore 3.1 application using xunit.
Tests show successful, but process is still running. After some time I get:
The process dotnet:1234 has finished running tests assigned to it, but is still running. Possible reasons are incorrect asynchronous code or lengthy test resource disposal [...]
This behavior does even show with boilerplate code like:
[Fact]
public async Task TestServer()
{
var hostBuilder = new HostBuilder()
.ConfigureWebHost(webHost =>
{
// Add TestServer
webHost.UseTestServer();
webHost.Configure(app => app.Run(async ctx =>
await ctx.Response.WriteAsync("Hello World!")));
});
// Build and start the IHost
var host = await hostBuilder.StartAsync();
}
Same if I add await host.StopAsync()...
I am on an Ubuntu 18.04 machine.
Try to dispose the host at the end of the test. Most likely, the error is caused just because you don't dispose disposable resource.
I would recommend you to use WebApplicationFactory for testing instead of HostBuilder. You may find more in the docs
I had the same problem. Since i was working with NUnit the suggested change was not an option (it is based on xunit). So i was digging into it and the root cause of it was quite simple:
I created a long running task in the Startup.cs which was doing some monitoring throughout all the hosting's lifetime. So i had to stop this task, and then also the instance of the TestHost was disposed properly.

WebSockets not working when application is built

I have got to ASP.NET-Core 2.0 apps communicating via WebSockets.
App A is Server.
Application A is running on a remote server with Ubuntu.
App B is Client
Application B is running on a PC setup in my office.
When I test my applications locally in Debug everything works fine. Client connects to the server and they can exchange information.
However, when I build my Server app, Client can connect to it but when server tries to send a message to the client the message is not received by the client.
public async Task<RecievedResult> RecieveAsync(CancellationToken cancellationToken)
{
RecievedResult endResult;
var buffer = new byte[Connection.ReceiveChunkSize];
WebSocketReceiveResult result;
MemoryStream memoryStream = new MemoryStream();
do
{
if (cancellationToken.IsCancellationRequested)
{
throw new TaskCanceledException();
}
Console.WriteLine("Server Invoke");
// result never finishes when application is build. On debug it finishes and method returns the correct result
result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken);
if (result.MessageType == WebSocketMessageType.Close)
{
await CloseAsync(cancellationToken);
endResult = new RecievedResult(null, true);
return endResult;
}
memoryStream.Write(buffer, 0, result.Count);
} while (!result.EndOfMessage);
endResult = new RecievedResult(memoryStream, false);
return endResult;
}
This is the part of code where everything hangs.
What I tried was:
Build Server - Build Client => not working
Build Server - Debug Client => not working
Debug Server - Debug Client => working
I need any advice what might be wrong here and where I should look for issues.
Console if free of errors. Everything hangs on:
result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken);

easynetQ delayed respond/request resulting in timeout

I've run into a problem with using the request/respond pattern of EasyNetQ while using it on our server (Windows Server 2008). Not able to reproduce it locally at the moment.
The setup is we have 2 windows services (running as console applications for testing) which are connected through the request/respond pattern in EasyNetQ. This has been working as expected until recently on the server where the request side does not "consume" the responses until after the request timeouts.
I have included 2 links to pastebin which contain the console logging of EasyNetQ which will hopefully make my problem a bit more clear.
RequestSide
RespondSide
Besides that, my request code looks like this:
var request = new foobar();
var response = _bus.Request<foobar, foobar2>(request);
and on the respond side:
var response = new response();
_bus.Respond<foobar, foobar2>(request =>
{
try
{
....
return response;
}
catch (Exception e)
{
....
return response;
}
});
As I've said, the request side sends the request as expected and the respond side consumes/catches it. This works as it should, but when the respond side is done processing and responds (which it does, the messages can be seen in the RabbitMQ management thingy) the request doesn't consume/catch the response until after the request has timed out (default timeout is 10s, tried setting to 60s aswell, makes no difference). This is also evident in the logs linked above as you'll see on the RequestSide, with the 5 or so messages received from the response queue which previously timed out.
I've tried using RespondAsync in case the processing was taking too long and messing something up, didn't help. Tried using both RespondAsync & RequestAsync, just messed everything up even more (I was probably doing something wrong with the request :)).
I might be missing something, but I'm not sure what to try from here.
EDIT: Noticed I messed something up. As well as added more context below:
The IBus used for the request/response is created and injected with Ninject:
class FooModule : NinjectModule
{
public override void Load()
{
Bind<IBus>().ToMethod(ctx => RabbitHutch.CreateBus("host=localhost", x => x.Register<IEasyNetQLogger>(_ => logger))).InSingletonScope();
}
}
And it's all tied together by the service being constructed using Topshelf with Ninject like so:
static void Main(string[] args)
{
HostFactory.Run(x =>
{
x.UseNinject(new FooModule());
x.Service<FooService>(s =>
{
s.ConstructUsingNinject();
s.WhenStarted((service, control) => service.Start(control));
s.WhenStopped((service, control) => service.Stop(control));
});
x.RunAsLocalSystem();
});
}
The Topshelf setup has all been tested pretty thoroughly and it works as intended, and should not really be relevant for the request/respond problem, but I thought I would provide a bit more context.
I had this same issue, my problem was i set the timeout only in the response but not in the request side, after i set the timeoute in both side it worked fine
my connection for eg.
host=hostname;timeout=120;virtualHost=myhost;username=myusername;passw
ord=mypassword

SignalR WPF Client can't reach hub deployed on IIS when IIS runs on a different system

I just play a little bit with signalR. My application has only one simple hub which is stored in an ASP.NET Application and I wrote a WPF client, which interacts via the hubconnection and the created proxy with the ASP.NET Application. Everything works fine on my local PC. I deployed the ASP.NET Application on IIS.
Now I am getting to the point...
When I type the following into my browser on my own PC (pcthi-and)
http://pcthi-and:8080/signalr/hubs
I'll get what I want
When I type the same url into a browser of another pc I'll get the same response and everything looks fine.
But my Application only works on my pc and not on the other one. When I start the hubconnection on the other pc I don't get a connectionId.
I tried to change the url to my IP-Address without effect.
Browser call to hub works but the Application doesn't work.
The call looks like this:
private bool tryToConnectToCoffeService()
{
try
{
this.hubConnection = new HubConnection(ConfigurationManager.ConnectionStrings["coffeeConnection"].ConnectionString);
this.hubConnection.Credentials = CredentialCache.DefaultNetworkCredentials;
this.coffeeService = this.hubConnection.CreateHubProxy("coffee");
this.hubConnection.Start();
if (string.IsNullOrEmpty(hubConnection.ConnectionId))
{
return false;
}
return true;
}
catch(Exception ex)
{
return false;
}
}
The Global.asax:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHubs();
}
The hub like this
[HubName("coffee")]
public class CoffeeHub : Hub
{
My Hub Connection String is this:
"http://pcthi-and:8080/"
Or:
"http://My-Current-IP-Address:8080/"
I use SignalR 1.0 rc2.
Does anyone have an idea? Thanks for helping.
Cheers
Frank
I think you need to change
hubConnection.Start();
to
hubConnection.Start().Wait();
If you are running .NET 4.5 you could make the tryToConnectToCoffeService method async and then await when you start the hub connection.
await hubConnection.Start();
It likely works today on localhost because the client can finish connecting before if (string.IsNullOrEmpty(hubConnection.ConnectionId)) executes.
It is probably taking longer to connect from another machine which exposes the race condition present when you don't wait for HubConnection.Start() to complete.