radu-matei / websocket-manager Goto Github PK
View Code? Open in Web Editor NEWReal-Time library for ASP .NET Core
Home Page: https://radu-matei.com/blog/real-time-aspnet-core/
License: MIT License
Real-Time library for ASP .NET Core
Home Page: https://radu-matei.com/blog/real-time-aspnet-core/
License: MIT License
(Probably exception on the server, see how to handle that)
Hello,
I would like to host my web page which uses your WebSocketmanager Api in IIS on my Windows 10 machiene.
Could you please show this in a tutorial.
Hi, one question... Can I manage a Chat Room with this library? Is possible? Thanks!
Hi, I'm trying to access my websockets from outside in another service. Is there a way similar to how SignalR allow you to access Hubs via IHubContext?
Thanks!
Is it possible to get the same id to the client even when the user reloads the web page? I would like to send notifications even though the user has navigated away from the initial page.
Consider the situation:
10 connected clients -> SendToAllAsync is invoked -> Last Socket Disconnects -> attempt to send message to the removed client. I'm almost sure that this will cause an exception. Could you comment on this, @radu-matei ?
Hi,
it is possible to inject dependencies in the websocket handler ?
I've been struggling to find this problem for the past 24 hours.
In the WebSocketManagerMiddleware class, the awaitable Receive Task will throw an unhandled Websocket Exception that will break the application in the case of a socket not being properly closed. The ExceptionHandlerMiddleware was unable to catch it as well, not sure why.
The exact message is something like "The remote party closed the WebSocket connection without completing the close handshake."
This can probably be replicated using the mvc sample, then using a cellphone to connect to the websocket and then switching back to another process so the browser will be in background.
because the subclass inherits from WebSocketHandler will be injected as singleton, so I can't initialize some other services inside the constructor.
so how can I access to other service e.g. in the onConnected method?
from debug console:
Sending through HTTP to a controller:test
VM117:1 Uncaught SyntaxError: Unexpected token o in JSON at position 1
at JSON.parse ()
at WebSocket.socket.onmessage (WebSocketManager.js:106)
socket.onmessage @ WebSocketManager.js:106
Hi,
When client lost connection because crash or modem shutdown, server continue with socket in memory and OnDisconnected event in websockethandler is never executed.
In statup have configuration to keepaliveinterval = 60 seconds, but after this time, socket continue in memory and OnDisconnected event is never executed.
Anyhere have solution to detect when socket client crash to remove socket from memory or make other actions ?
Thank you,
I try to send message in websocket from other soft, wich must send only string.
I intercept string in demo chat and have this:
{
"$type": "WebSocketManager.Common.Message",
"messageType": 1,
"data": {
"$type": "WebSocketManager.Common.InvocationDescriptor",
"methodName": "SendMessage",
"arguments": {
"$type": "System.Object[]",
"$values": [
{
"$type": "System.String",
"$value": "test"
}
]
},
"identifier": {
"$type": "System.Guid",
"$value": "00000000-0000-0000-0000-000000000000"
}
}
}
When i send this string to websocket, i get error:
Newtonsoft.Json.JsonSerializationException: "Type specified in JSON 'WebSocketManager.Common.InvocationDescriptor, WebSocketManager.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with 'System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'. Path 'data.$type', line 5, position 59."
Please, how the string to send to server must be?
Since the middleware is scoped differently in the service registration - it won't allow something to either be injected (obviously) or created inside that scope that is not scoped the same. For instance, I have a manager that I am using a special factory to instantiate - inside a method on the WebSocketHandler...
I tried scoping my factory in different ways - but because the handler (acting as the controller) is scoped differently then my manager... it won't allow it - in dotnetcore 2+
I don't see a nice way around this... because to do method injection on the invoke method would require me to either override and recode the invoke method or do something else wonky to get the classes that I need... any advice would be appreciated.
Right now, this library only supports sending messages as JSON - it would be a great addition if we supported protobuf.
Hello,
I would like to access my User Identity from any Handler, any ideas to do that?
Hey there!
Your middleware has been really beneficial for me and a friend. My friend is also blogging and will be crediting you as he's used your code - however, he saw you had a NuGet package but it's not been updated recently.
Are there plans to update it soon?
Layla
Tests need to be written for:
Then, they need to be integrated with continuous integration with Travis.
Then client is disconnected (net error or else), server down with error;
System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake.
I use NuGet package, hoe to process this errors and drop sockets from disconnected clients withoun server down?
Hi,
I have implemented this approach on my web application but I want to extend it by using a distributed cache (redis).
Is there a way to save the dictionary in redis just like I could do with session variables?
I am using .net core 2.
connection.connectionMethods.onConnected = () =>
this line syntal error
Hi,
I suppose, Web manager could send periodically messages to client, to verify its connection.
Client could send a REST request only for verification (maybe to include also in its request a timestamp, provided by the manager's initiated message). Then the controller to send message to web manager to update a "keep alive" list with clients responses. Web manager periodically could clean the connections without "keep alive" responses.
Unfortunately, I don't have time, for a while, to help your excellent effort.
When hanlder ReceiveAsync method is doing something take a long time,the websocket cannot receive any message, even the websocket client has closed,the server can't observe too
When this is the last middleware in the pipeline, Kestrel throws an unhandled exception
Hi,
Any reason to set the WebSocketHandler service as a Singleton and WebSocketConnectionManager service as transient?
From my point of view WebSocketConnectionManager should be a Singleton and WebSocketHandler a transient or scoped service as the entry point for the websocket is the handler, we don't have to keep it as a singleton but allow other scoped DI to be used inside the handler (like for EF #68 - #72)
To be able to keep mapped route to specific handler, I tried to give to the middleware the handler type (like app.MapWebSocketManager<ConnectionHandler>("/connection");
) and calling var webSocketHandler = (WebSocketHandler)serviceProvider.GetService(_handlerType);
directly in the middleware Invoke
function.
This is working fine but I don't know if it's the best way to do runtime dependency injection setup.
Regards
I tried this but no success.
InvocationDescriptor invocation = new InvocationDescriptor();
invocation.Identifier = Guid.Parse(_clientId);
invocation.MethodName = "CallServer";
await _connection.SendAsync(invocation);
on the server:
public async Task CallServer()
{
}
As I understand right now, SignalR will be supported for versions >= .NET Core 2.1 (and I assume .NET Standard 2.1), so I believe it is worth exploring and investigating issues that limit the use of this library in real workloads that will target .NET Core 1.x
Below is a set topics taken from the various issues and pull-requests here on GitHub, as well as additional features that might benefit users and should be updated according to work done in the repo (issues and pull-requests).
User Context and Identity
Distributed caching, Redis integration
Full Framework target
Dependency registration
Encoding
Logging
Groups
Performance
Serialization
Binary data transfer
Connection state / Reconnection
Samples
Tests
Investigate and merge existing pull-requests
Documentation and contributing guidelines
Automated release of NuGet
Update Travis CI
TypeScript / JavaScript client package release
Other clients (Go, Java, others)
Please feel free to add any other issues, feature requests or suggestions and let's try to create a schedule (and discussion) for rational versioning of the packages (right now the versioning does not make much sense)
I already sent contributor invitation to some of you, please let me know if anybody else is interested.
CC @skorunka @discostu105 @RobSchoenaker @miker1423 @CodeGlitch0 @mikaelbr @ryanwersal @trydis
(Please add other people in case I missed anyone)
Decide if a class that encapsulates the socketId
and the socket itself is needed
Not really an issue but I wanted to submit back two possible enhancements that I made:
return await Task.Run(() => method.Invoke(Controller, args.ToArray()));
var result = await Task.Run(() => method.Invoke(Controller, args.ToArray()));
if (result == null) return null;
var resultType = result.GetType();
if (resultType == typeof(Task)) return null;
if (resultType.IsGenericType && resultType.GetGenericTypeDefinition() == typeof(Task<>))
return resultType.GetProperty("Result")?.GetValue(result);
return result;
public static class EndpointRouteBuilderExtensions
{
/// <summary>
/// Add a WebSocketManager Handler that listens to a specific path.
/// </summary>
/// <typeparam name="THandler">Handler Type</typeparam>
/// <param name="builder">Endpoint Builder</param>
/// <param name="path">Path</param>
/// <returns>Endpoint Convention Builder</returns>
public static IEndpointConventionBuilder MapWebSocketManager<THandler>(this IEndpointRouteBuilder builder, string path)
where THandler : WebSocketHandler
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
return builder.MapWebSocketManager(path, builder.ServiceProvider.GetRequiredService<THandler>());
}
/// <summary>
/// Add a WebSocketManager Handler that listens to a specific path.
/// </summary>
/// <typeparam name="THandler">Handler Type</typeparam>
/// <param name="builder">Endpoint Builder</param>
/// <param name="path">Path</param>
/// <param name="handlerFunc">Function that creates the Web Socket Handler</param>
/// <returns>Endpoint Convention Builder</returns>
public static IEndpointConventionBuilder MapWebSocketManager<THandler>(this IEndpointRouteBuilder builder, string path, Func<IServiceProvider,THandler> handlerFunc)
where THandler : WebSocketHandler
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
return builder.MapWebSocketManager(path, handlerFunc(builder.ServiceProvider));
}
/// <summary>
/// Add a WebSocketManager Handler that listens to a specific path.
/// </summary>
/// <typeparam name="THandler">Handler Type</typeparam>
/// <param name="builder">Endpoint Builder</param>
/// <param name="path">Path</param>
/// <param name="handler">Web Socket Handler</param>
/// <returns>Endpoint Convention Builder</returns>
public static IEndpointConventionBuilder MapWebSocketManager<THandler>(this IEndpointRouteBuilder builder, string path, THandler handler)
where THandler : WebSocketHandler
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
if (string.IsNullOrEmpty(path)) throw new ArgumentNullException(nameof(path));
if (handler == null) throw new ArgumentNullException(nameof(handler));
return builder.Map(path, builder
.CreateApplicationBuilder()
.UseWebSockets()
.UseMiddleware<WebSocketManagerMiddleware>(handler)
.Build()
);
}
/// <summary>
/// Add a WebSocketManager Handler that listens to a specific path.
/// </summary>
/// <typeparam name="THandler">Handler Type</typeparam>
/// <param name="builder">Endpoint Builder</param>
/// <param name="routePattern">Route Pattern</param>
/// <returns>Endpoint Convention Builder</returns>
public static IEndpointConventionBuilder MapWebSocketManager<THandler>(this IEndpointRouteBuilder builder, RoutePattern routePattern)
where THandler : WebSocketHandler
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
return builder.MapWebSocketManager(routePattern, builder.ServiceProvider.GetRequiredService<THandler>());
}
/// <summary>
/// Add a WebSocketManager Handler that listens to a specific path.
/// </summary>
/// <typeparam name="THandler">Handler Type</typeparam>
/// <param name="builder">Endpoint Builder</param>
/// <param name="routePattern">Route Pattern</param>
/// <param name="handlerFunc">Function that creates the Web Socket Handler</param>
/// <returns>Endpoint Convention Builder</returns>
public static IEndpointConventionBuilder MapWebSocketManager<THandler>(this IEndpointRouteBuilder builder, RoutePattern routePattern, Func<IServiceProvider, THandler> handlerFunc)
where THandler : WebSocketHandler
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
return builder.MapWebSocketManager(routePattern, handlerFunc(builder.ServiceProvider));
}
/// <summary>
/// Add a WebSocketManager Handler that listens to a specific path.
/// </summary>
/// <typeparam name="THandler">Handler Type</typeparam>
/// <param name="builder">Endpoint Builder</param>
/// <param name="routePattern">Route Pattern</param>
/// <param name="handler">Web Socket Handler</param>
/// <returns>Endpoint Convention Builder</returns>
public static IEndpointConventionBuilder MapWebSocketManager<THandler>(this IEndpointRouteBuilder builder, RoutePattern routePattern, THandler handler)
where THandler : WebSocketHandler
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
if (routePattern == null) throw new ArgumentNullException(nameof(routePattern));
if (handler == null) throw new ArgumentNullException(nameof(handler));
return builder.Map(routePattern, builder
.CreateApplicationBuilder()
.UseWebSockets()
.UseMiddleware<WebSocketManagerMiddleware>(handler)
.Build()
);
}
}
Should be the WebSocketConnectionManager
registered as singleton instead of user defined WebSocketHandlers
?
Imagine the situation where you want to resolve some resources in your WebSocketHandler
which are dependent on the request context = so they differ per request.
I think the better implementation is:
public static IServiceCollection AddWebSocketManager(this IServiceCollection services)
{
services.AddSingleton<WebSocketConnectionManager>();
foreach (var type in Assembly.GetEntryAssembly().ExportedTypes)
{
if (type.GetTypeInfo().BaseType == typeof(WebSocketHandler))
{
services.AddScoped(type);
}
}
return services;
}
websocket-manager/src/WebSocketManager/WebSocketConnectionManager.cs
Lines 50 to 52 in 623d2b2
It's a minor issue but I think that line 52 is unnecessary (List is referenced type and does not need to be reassigned to itself)
_groups[groupID].Add(socketID);
Hey,
Im very interested in WebTerm and I want to test it.
But I have a Problem to start it.
I cant run it with the arguments: "dotnet run".
It cant find the project file (But I have the file already in the same directory).
Can someone help me out. Thanks
So when I try passing a complex type into or recieving one back from the library - I get json serialization errors... So basically, if I am wanting to send a list of type user - I have to serialize before sending and deserialize on the other end with known types - is this by design?
So I realize this is somewhat new-ish project, are there any mechanisms to facilitate scaling (say if site took off and I wanted to run this stuff across 10 web servers?)
May I know what is the json format to sent message? I want to sendmessage from desktop application. The example only has javascript library.
Very good work, any explantion how examples working would be good. Not sure how to run the example's.
Satya
Is the invocation of server methods from a client currently supported? If so, is there an example available?
Edit: To clarify, I'm referring to a C# client like a console application.
How do I keep a long connection?
My android app is easy to disconnect
In one sample, a dependency needed for the handler is newed-up rather than injected using dependency injection. This should not be handled by the user of the library, but rather by the library itself:
public ChatHandler(WebSocketConnectionManager webSocketConnectionManager) : base(webSocketConnectionManager, new ControllerMethodInvocationStrategy())
{
((ControllerMethodInvocationStrategy)MethodInvocationStrategy).Controller = this;
}
cc @Henry00IS
When trying to use your package with latest .NET Core I am receiving this error
Message "A suitable constructor for type 'WebSocketManager.WebSocketManagerMiddleware' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor." string
on this line
public static IApplicationBuilder MapWebSocketManager(this IApplicationBuilder app,
PathString path,
WebSocketHandler handler)
{
return app.Map(path, (_app) => _app.UseMiddleware<WebSocketManagerMiddleware>(handler)); // here
}
I got this error
Could not decode a text frame as UTF-8.
when I try to send text in UTF-8 encoding.
First of all, thank you for all the great work and time you spent developing the WebSocketManager.
I was wondering if you will consider publishing a new version of the NuGet package, there's a lot of good features that are not in the current version of the NuGet Package and it will be nice to have them there.
Thank you.
There should be the possibility of having separate arguments in the lambda for a client method (unlike right now, where you only pass object[]
as parameter for the client method).
Can any one please help on this. I am getting OutOfMemoryException on array initialization. It happens in live only and not in local. It happens sometimes.
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown. at WebSocketManager.WebSocketManagerMiddleware.Receive(WebSocket socket, Action`2 handleMessage) in C:\Research\GIT\SP.Core\WebSocket-Manager\src\WebSocketManager\WebSocketManagerMiddleware.cs:line 102 at WebSocketManager.WebSocketManagerMiddleware.Invoke(HttpContext context) in C:\Research\GIT\SP.Core\WebSocket-Manager\src\WebSocketManager\WebSocketManagerMiddleware.cs:line 47 at Microsoft.AspNetCore.Builder.Extensions.MapMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at
Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context) at NetCoreApp.Handler.CustomExceptionMiddleware.Invoke(HttpContext context) in
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.