SignalR Server to Client call in parallel (c#) - c#

I'm working on a SignalR scenario where the server needs to call clients methods in parallel.
In my tests, the calls to the same client seem sequentials.
I've seen, with the .Net5 was added a new property on the server, MaximumParallelInvocationsPerClient but this property seems to work only on the client to server calls.
There is any option to call client methods in parallel?
Edit:
Testing with net core 2.1 on the c# client I Saw the calls to the client are sended in parallel, for this reason, the problem isn't on the server but it is on the client.
Thanks,

Since I can't find any property to indicate to process requests in parallel, the best option is run the action as a task without await:
con.On("ClientCommandName", () =>
{
Task.Run(() =>
{
//Code of the action....
});
});

Related

How to achieve .NET 6 WEB API Server side timeout?

.NET 6 WEB API Server side timeout?
I don't want client side task cancellation. Along with client, Should need to cancel server call also (Httpclient/DB call).
I will explain the scenario with example,
I have one console application and inside that I am calling one HttpAPI.
Like:
Static Void Main(){
try {
var res = client.GetAsync("url", cancellationToken);
}
catch(OperationCancellation ex){
}
}
After some period of time I need to stop console app and as well as GetAPI call also. Should stop the GetAPI call is my ultimate goal.
With cancellation token I can able to reject the request only from client side.
Please help me how to do it!!!
}

C# ASP.NET, testing websocket with Microsoft.AspNetCore.Mvc.Testing

I am currently writing an integration test for a websocket connection. I want to test a ClientWebSocket connection against a server instantiated by Microsoft.AspNetCore.Mvc.Testing. This does not seem to work. Does anybody have an idea how to get this to work?
My setup is as follows:
I have an API application, which offers some normal http endpoints and one websocket
I have some application code, which establishes a websocket connection
I have integration tests, which instantiate the API application using Microsoft.AspNetCore.Mvc.Testing and use my application code against it
I general am following https://learn.microsoft.com/de-de/aspnet/core/test/integration-tests?view=aspnetcore-6.0 . This works great for normal HTTP(S) endpoints. My Code looks like this:
_application = new WebApplicationFactory<Program>().WithWebHostBuilder(builder => { });
//HttpClient for http endpoints
_client = _application.CreateClient();
The WebSocket endpoint is created as described here: https://learn.microsoft.com/de-de/aspnet/core/fundamentals/websockets?view=aspnetcore-6.0
app.Use(async (context, next) =>
{
if (context.Request.Path == "/"+nameof(TestModel.WebsocketEvent))
{
if (context.WebSockets.IsWebSocketRequest)
{
TestModel.Instance.WebsocketEvent = await context.WebSockets.AcceptWebSocketAsync();
await ListenForClose(TestModel.Instance.WebsocketEvent);
}
}
}
For the connection to the endpoint I am using ClientWebsocket in the code I want to test.
var ws = new ClientWebSocket();
await ws.ConnectAsync(_href, cancellation);
When I run my API application manually and execute my code against that instance, everything works as expected. The WebSocket connection is established.
When I try to run it with Microsoft.AspNetCore.Mvc.Testing I get an exception that the server refused the connection.
To some degree it makes sense to me, since the ClientWebSocket is not using anything generated by the WebApplicationFactory.(e.g. _application.Server.CreateWebSocketClient.
On the other Hand I do want to use ClientWebSocket in my code and not inject the WebSocketClient of Microsoft.AspNetCore.Mvc.Testing into my production code. In Contrast to http where I actually get a regular HttpClient which I am fine with to inject.
Does anybody have an idea, how I can make the integration test working with ClientWebSocket?
Is there the possiblity to reuse the server Microsoft.AspNetCore.Mvc.Testing starts for requests other than what the WebApplicationFactory generates?
Is Microsoft.AspNetCore.Mvc.Testing running the API application at all as a server? Or is there some black magic in the background?
What I checked so far:
_href is correct
_application.Server.BaseAddress does not seem to have an impact
What I want to do is simply not possible. The answer of the following thread pushed me in the right direction.
Inject HttpClient from WebApplicationFactory
This matches the official documentation if you know what you are looking for:https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0
Hence I can only access the instance of my Web API application using what WebApplicationFactory offers me.
I can't access the instance of the Web API application over my local network.
Thanks to everybody taking the time to read and think about my question.

ASP.NET Web Api, Database connection in Threads

I have an issue with using a Database in a thread in my asp.net Application.
When I want to start my application I want to start a thread called "BackgroundWorker" with it, which runs in the background till the whole application is stopped.
The problem is that I have massive problems with the dbContext in the thread.
I I try to start the walker in my Startup.cs in the methods "ConfigureServices" or "Configure" and then initialize the dbContext in the constructor in the Walker like this "dbContext = new ApplicationContext()" it tells me that the connection is not configured, when I try to operate in the while(true) queue on the database.
If I write an own Controller for the Walker which receives a ApplicationContext in his constructor and then starts a Thread like this, if i call this controller once with a GET Request:
public BackgroundWorker(ChronicusContext dbContext)
{
_dbContext = dbContext;
_messageService = new MailMessageService();
}
// GET: api/backgroundworker
[HttpGet]
[Route("start")]
public void StartWorker()
{
//Thread thread = new Thread(this.DoBackGroundWork);
Thread thread = new Thread(() => DoBackGroundWork(this._dbContext));
thread.Start();
}
public void DoBackGroundWork(ChronicusContext _dbContext)
{
while (true)
{
if (_dbContext.PollModels.Any()) //Here is the exception
{
...
}
}
}
Then I receive an System.ObjectDisposedException that the object is already disposed inside the while (true) queue.
I tried those and similar things in many different ways but allways receive exceptions like these two or that the database connection is closed.
Can somebody help me and tell me, how this works?
Thank you!
Generally, server side multithreading for Web Applications does not happen often and is, most times, a huge no no.
Conceptually, your server is "multithreaded", it handles many HTTP requests from clients/users/other servers. For mobile and web architecture/design, your server(s) process multiple requests and your clients are handling asynchronous calls and dealing with waiting for responses from long running calls like your API method StartWorker.
Think of this scenario, you make a request to your WebAPI method StartWorker, the client, making the request is waiting for a response, putting the work on another thread does nothing as the client is still waiting for a response.
For example, let's consider your client an HTML web page with an Ajax call. You call StartWorker via Ajax, you will be loading data into a HTML table. You will desire, from a UX perspective, to put up a progress spinner while that long running StartWorker responds to your HTML Page Ajax call request. When StartWorker responds, the Ajax call loads the HTML table with the StartWorker response. StartWorker has to respond with the data. If StartWorker responds beforehand than you will have to send a push notification, via SignalR, for example, when the other thread completes and has the data you need for the HTML table.
Hopefully, you see, the call to the WebAPI method, takes the same amount of time from a Ajax request/response perspective, so multithreading becomes pointless in this scenario, a most common web application scenario.
You can have your client UI load other UI elements, showing a progress spinner in HTML table UI area, until your database call is complete and responds with the data to your Ajax call. This way your users know things are happening and something is still loading.
If you still need your additional thread in your API for your project needs, I believe you have to be using Entity Framework 6 or greater to support asynchronous queries, see this tutorial:
http://www.codeproject.com/Tips/805923/Asynchronous-programming-in-Web-API-ASP-NET-MVC
UPDATE
Now that I know you need to run a SQL query on a repeating frequency of time, and you have an Azure Web App, what you want to use is Azure Automation if you are using Sql Azure or create a Sql Server Job if you are using a Sql Server instance as your backend
DbContext is not thread safe. You need to create a new context from inside your thread.
public void DoBackGroundWork()
{
ChronicusContext anotherContext= new ChronicusContext();
while (true)
{
if (anotherContext.PollModels.Any())
{
...
}
}
}

Calling async methods from a WCF service

I want to call asynchronous methods from a WCF service, something like:
[ServiceContract]
interface IService
{
[OperationContract]
int SomeMethod(int data);
}
int SomeMethod(int data)
{
var query = ... build LINQ query;
var response = await query.ToListAsync();
return response.Length;
}
I don't want to add async to the IService interface or SomeMethod method. Using asynchronous methods is an internal issue that shouldn't be reflected in the interface.
How can I do that?
CLARIFICATION:
My problem here is using await in a non-async method. I don't want the service contract to change (the client doesn't necessarily know what async is), and I don't want to split the method into BeginSomeMethod and EndSomeMethod. I want one method that uses await internally.
Whether the server is using sync or async code does not matter for the client. Client and server are separated by a well-specified wire-protocol (often SOAP). SOAP has no notion of asynchronous completion.
You can have a sync server and an async client, or vice versa. The client cannot even detect whether the server is sync or async. This is an implementation detail. The server could be a wrist watch running Linux and you still couldn't tell.
The style of IO you use is an implementation detail and does not influence the bytes that go over the network.
So pick what you like. The client can still use async IO to access the server.
I'm not sure why this is such a surprise to people. In other contexts this seems very intuitive: You can have a asynchronous TCP server and a synchronous client. I can say new WebClient().DownloadString(url) and download a string synchronously from a web-server that is implemented in an asynchronous way. I cannot even tell what server software is running.
Use Fiddler to look at what goes over the wire when you make a WCF call. There is no notion of synchronous or asynchronous calls.
Under the hood, when you invoke a service asynchronously, the WCF client library using TCP sockets in an asynchronous way. When you invoke synchronously, TCP sockets are being used with blocking calls. That's the entire difference.
WCF generated clients can be made to have asynchronous methods in addition to the synchronous methods. Select the "Generate asynchronous operations" option in the UI. Now you have both versions. Both fully functional.
Here's how you can convince yourself of this with an experiment: Write a sync server, and call it both sync and async from the same .NET client. Now write a 2nd server asynchronously (in any style you like) and use the exact same client code to call it.
Task and IAsyncResult are not serializable over SOAP anyway so it cannot possibly be the case that a Task is transmitted to the client.

Asynchronous callback from web api controller

I'm very new to Web API and I have an unusual pattern that I need to implement. In the Post method of my controller, it is to take an object which includes a CallbackURL. It will then immediately return an HTTP response to the caller. Afterwards, it will use a 3rd party, off-site API to perform some work with the object. Once that work is done, the controller is to post the results of that work to the CallbackURL.
However, I do not know how to implement this in Web API. Once I return the HTTP response, the controller's lifecycle is over, correct? If so, how do I perform the work I need to do after I return the response?
If you only need to post results to a url and not to the client that initiated the call, you could possibly do something as easy as this:
public string MyAPIMethod(object input)
{
Task.Factory.StartNew(() =>
{
//call third-party service and post result to callback url here.
});
return "Success!";
}
The api call will return right away, and the Task you created will continue the processing in a different thread.
Creating a task to finish up the request (as suggested by Jason P above) will most likely solve the problem, thread-safety provided. However that approach might hurt the performance of your Web service if calls to the 3rd party API take a significant amount of time to complete and/or you are expecting many concurrent clients. If that was the case, your problem seems to be the perfect candidate for a service pattern called "Request/Acknowledge/Callback" (also "Request/Acknowledge/Relay"). Using that pattern, your Web API method will just store each request (including the callback URL) into a queue/database and return quickly. A separate module (possibly running on more than one machine, depending on the number and complexity of the tasks) will take care of completing the tasks, and subsequently notifying completion through the callback URL (please see http://servicedesignpatterns.com/ClientServiceInteractions/RequestAcknowledge).
This is presuming you want to return the results of your 3rd-party query to the caller.
You're correct, this is outside of what's possible with WebAPI. Once you return the HTTP Response, the client also has no connection to your server.
You should look into Asp.Net SignalR, which allows a persistent connection between the client and server, working in modern browsers, and even back to IE7 (though officially unsupported), as well as supporting non-browser clients.
You can then do a couple of things, all of which require the client to connect to SignalR first.
Option 1: You can call your WebApi controller, which can return, but not before launching a task. This task can query the 3rd party api, then invoke a function on the caller via SignalR with the results that you want to provide.
Option 2: You can call a SignalR Hub action, which can talk back to your client. You can tell your client the immediate response, query the 3rd-party api, then return the results you want to provide.

Categories