Couple of days ago I ran into some kind of a problem that I can't seem to solve. So that's why I'm posting it on StackOverflow.
I'm running a .NET CORE website that can run a task in the background. Such a task has 3 events (OnCompleted, OnStarted, TaskProgress). What I need is that if any of these events fire, he will send data to the connected clients. For simplicity, I want to return the "event fired" string.
What I have done for the moment is the following:
added app.UseWebSockets() to my startup.cs file
added a new function to the pipeline to catch the websocket calls
app.Use(async (context, next) =>
{
if (context.Request.Path == "/socket")
{
if (context.WebSockets.IsWebSocketRequest)
{
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
//HERE IS MY PROBLEM
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next();
}
});
I created a SocketListener class that receives all 3 events when fired.
private void _taskManager_TaskExecuting(object sender, GenericEventArgs<IScheduledTaskWorker> e)
{
SendData();
}
private void _taskManager_TaskCompleted(object sender, TaskCompletionEventArgs e)
{
SendData();
}
private void Argument_TaskProgress(object sender, GenericEventArgs<double> e)
{
SendData();
}
So what I would need now is that in the pipeline function (//HERE IS MY PROBLEM line) I somehow wait for unlimited time for any of the events to fire. If they fire, the SocketListener class needs to be aware of the connections and send data back over the WebSocket connection.
The `SendData()' function will need to check for open connections and send the "event fired" string to all of them.
The connection also needs to be closed when navigating away from the page. I think I can manage that with some angular NavigationStart event and then call the socket api with a close message.
I searched on the internet for a good solution but most of the blogpost/tutorials/... are talking about 2-way communication (chat programs,...)
Anyone got an idea how I could fix this problem? If more information is needed I let me know.
Thanks in advance!
Helo Reggi,
I've open sourced an WebSocket application that I built in .NET Core.
I've built it to process generic messages, not only focused on chats.
My idea is use two way communication within the client (WebPage) and the websocket to perform any kind of task.
WebSocket communication works slightly different from what you say on you question, but the code I've written is going to be a good guide.
What you want to do with SendData is going to be like the method 'NotifyAllConnectedSockets' on the controller NotificationController that I've created.
Please take a look to see if it suits to what you want.
BackEnd - https://github.com/asiilva/WSMessageHandler
Front-end - https://github.com/asiilva/ws-message-handler-front
Note: It is a work in progres, either front and back-end.
Feel free to ask any question
Best Regards
Related
I was refactoring some of my code into a service and I was going to roll async all the way through down to my EmailService's Send() method.
I was about to replace Send() with SendAsync() and noticed the extra callback parameter.
Well decided to dig in and read about it a little more in depth here:
https://learn.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient.sendasync?view=netcore-3.1#definition
I think this would be useful to set up logging to database on an error:
if (e.Error != null)
{
Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
// TODO: Log error to DB
}
e.Cancel would never happen.
The only thing I would be concerned about is logging errors and message sent.
Because the example console program says message sent even though if I have say a port wrong and the message doesn't go through.
The only time it would report the error is for an ArgumentNullException or InvalidOperationException.
So logging message sent could be erroneous.
But there is no way to check for sure if a message goes since it returns void and not a success bool. I guess this is better than putting the Send() in a try/catch which would be more expensive.
One alternative is to setup the callback to an empty SendCompletedCallback() and just have this:
private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
// Do nothing
}
Then we get the benefit of Async non blocking in our emails and have the infrastructure set up for a callback if we ever need it.
But we are not forced to add any funtionality at the moment.
Am I right in thinking this through here.
I think I am going with this approach.
I found the
SendMailAsync()
method works best.
You don't need a callback or a user token.
Easy to implement and non-blocking.
Hello all who read this,
We have written a router function on azure in an app plan that receives messages from iothub
and depending the message type we route our message to another eventhub.
Previously we had 6 out bindings to eventhubs in this function
Recently we added 3 more message type so 3 more out binding to 3 more eventhubs
No processing of the messages happen in this function but what we see now is that we spend 16 times more time in the routing function.
Is there a performance issue about having multiple output bindings.
We don't see an increase in load of the incoming messages.
We are running on azure functions 1.0 (Runtime version: 1.0.12205.0 (~1))
Regards Ben
Simplified Sample code of the routing function
public static class IotHubRouterFunction
{
[FunctionName("IotHubRouterFunction")]
public static void Run([EventHubTrigger("%iothub%", Connection = "IothubRouterListen")]EventData myEventHubData,
[EventHub("%msg1-eventhub%", Connection = "msg1event")] ICollector<EventData> eventHub4Dmsg1Event,
[EventHub("%msg2-eventhub%", Connection = "msg2event")] ICollector<EventData> eventHub4Dmsg2Event,
[EventHub("%msg3-eventhub%", Connection = "msg3event")] ICollector<EventData> eventHub4Dmsg3Event,
//... like 6 more bindings like this
ILogger logger
)
{
try
{
var messageType = GetValue(myEventHubData.Properties, "type");
// routing
switch (messageType)
{
case "msg1event":
{
eventHub4DevicesStatusChanged.Add(eventHub4Dmsg1Event);
break;
}
case "msg2event":
{
eventHub4MeasurementLog.Add(eventHub4Dmsg2Event);
break;
}
case "msg3event":
{
eventHub4DeviceDiscovered.Add(eventHub4Dmsg3Event);
break;
}
//6 more cases like this
default:
{
logger.LogError("Unrouteable message of type: {messageType}", messageType);
break;
}
}
}
catch (Exception ex)
{
//removed
}
}
}
With 6 bindings the message fly through the router function at 50ms
With 9 bindings the message crawl through the router function at 800ms
CPU raised with 30% as well on the applan (we scaled extra so we have it under control but why so much what is causing this)
A little late with the follow up of what happened
In the end we found out what was going on
We have several instances of our app plan
but the old monitoring solution showed the average of the cpu and memory overall the instances of the applan.
Basically with switching to the newer metrics and azure monitoring we were able to drill down in the separate instances of the app plan and the instances of the functions.
We found out that one instance of a function which was running three times two of them norammly but the third function had crashed it's internal apppool and consumed all cpu power it got hold off and did absolutely nothing.
We restarted the function and all issues were gone.
Still wondering if it was something in our code that made it go through the roof
or that something happened in azure that made it go crazy.
:-s
When you are using Azure Function under App service plan then you have to watch out for performance parameters like scaling. Have you investigated your function is not getting overloaded ?
On the other hand , As part of your design this approach is wrong to me. With this many bindings there could be potential performance issues , and what if you are supposed to add more bindings in future ? If you are not performing any operation then you shouldn't be taking overhead of redirecting messages.
Event Grid
We can use event grids for that. Based on topic the IoT hub publishes the event to a topic and events are consumed by subscribers in your case other event hubs. You also get advantage of micro billing (serverless) and auto scaling as well. https://learn.microsoft.com/en-us/azure/event-grid/overview
I'm trying to integrate the schedule component from Syncfusion. The component has a URL adaptor to connect to the controller; GetData() and Batch() for Crud Operations. Batch has a payload indicating what actions to perform. At the end, the Batch method would requery the database and send data identical to GetData() back.
Unfortunately, there is no built-in method to notify clients of anything going wrong - whether there is an exception, server-side validation kicks in or similar.
What I'd like to do is to add a placeholder outside the compentent to receive and display server messages (be it a notification popup, a or whatever.
Since I can't influence the Ajax call itself, I was wondering if I had to get started with SignalR (still in beta for .Net Core 2 as far as I know), or if I may have missed something more obvious? I have read a lot about push notifications etc - but these are not quite what I'm after, it'd be slightly over the top I think.
To summarise, let's say I have
<div id="messages"></div>
<div id="component">HereGoesTheScheduleWhichICantDoMuchWith</div>
Now in the Batch() method, it would be great to call a SendMessage("Sorry,you can't do this") - the text of which would ideally then appear in the messages-div.
How would you go about this?
I have now solved this, using SignalR (currently 1.0.0-alpha2-final) and for a nice view on the Client, PNotify.
Presently, it only works if the client is authenticated, if it needs to work anonymously you'd need to figure out a way to track SignalR's connection id.
On the page with the Syncfusion Schedule component, I connect to SignalR.
let connection = new signalR.HubConnection("/signalr", { transport: signalR.TransportType.ServerSentEvents });
connection.on("Notify",
(title, message) => {
new PNotify({
title: title,
text: message
});
});
connection.start();
The Hub (SignalRHub : Hub) creates a notification group for the user connecting:
public override Task OnConnectedAsync()
{
Groups.AddAsync(Context.ConnectionId, Context.User.Identity.Name);
return base.OnConnectedAsync();
}
The associated controller gets IHubContext<SignalRHub> signalRHub injected.
Now in the Batch-Method for the Syncfusion component, which returns Json and can't itself carry messages or notifications, you can notify the user:
_signalRHub.Clients.Group(User.Identity.Name).InvokeAsync("Notify", "A title", "A message");
In my particular case, I'm sending over an object to control layout, animation and popup duration for PNotify (e.g. longer for an exception to allow copy/paste etc) - as you please. Returning an object could be done using:
_signalRHub.Clients.Group(User.Identity.Name).InvokeAsync("Notify", JsonConvert.SerializeObject(new { title = "Some Title", message = "notification", type = "notice"}););
Obviously, connection.on("Notify"... needs to be changed accordingly.
I hope this is clear enough and might help someone else.
I am develping an app which load some url, parse them, keep them into sqlite db and the UI will read the saved data and show them in controls. This progress should be done in almost an infinit loop. For having fast response i plan to read the data from db in main thread and have an other thread (background worker) to load the data and insert it into db. Is it logical and possible to run read and write process in dispatchertimer, one timer in main thread and the other inside the background worker? and how? Or does anyone have better idea?
main thread:
DispatcherTimer _Timer1 = new DispatcherTimer();
_Timer1.Interval = _Interval;
_Timer1.Tick += _Timer1_Tick;
void _Timer1_Tick(object sender, EventArgs e)
{
// read data from db and show in controls
}
secondary thread:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
DispatcherTimer _Timer2 = new DispatcherTimer();
_Timer2.Interval = _Interval;
_Timer2.Tick += _Timer2_Tick;
}
void _Timer2_Tick(object sender, EventArgs e)
{
// write data into db
}
}
What you're planning to do wont work.
Both your _Timer1_Tick and _Timer2_Tick will run in the UI thread. If you perform some long-running operations there, it'll hang the UI.
I don't get it, why do you need timers at all? Using timers for anything else but measuring time intervals is rarely a good strategy. You could e.g. run your update process in the infinite loop in background, as soon as it put new data in the DB you call Dispatcher.BeginInvoke (passing any data you want) to notify your UI thread it should update itself with the newly available data.
And by the way, for the tasks like "send HTTP request, wait response, parse, store, repeat", the new async/await feature is a natural choice. For WP7 the functionality is available as "Async CTP" redistributable package for Visual Studio 2010, for WP8 it's already integrated into the framework. There're some compatibility issues between the 2, though.
load some url, parse them, keep them into sqlite db and the UI will read the saved data and show them in controls
Please don't do that. Don't create your own thread management system, just don't. I'm not saying it won't work, but it'll most likely backfire in the most horrendous and inexplicable ways. Like for example using a DisptacherTImer completely exploding in your face since it runs on the UI thread. If you really want to use threading considering ThreadPool.QueueUserWorkItem() or Task.Run() to start fire-and-forget actions.
Your workflow is also just strange, I don't get why you need to write data you already have to a DB, then read it back and only then use it. Won't it make more sense to use the deserialized data to sequentially write it to the DB and present it to the UI? Instead of doing the needless loop of involving Disk I/O considering you already have the data?
Have you considered using Messaging in your app? It's a pretty well known MVVM pattern implemented both in MVVM Light as the Messenger class and in PRISM as the EventAggregator. It seems to me that your system has a Message for "new data available from service" and that message has two subscribers: writing to a DB and updating the UI.
I'm trying to simulate a ping operation to find out if a remote host is reachable. I could not find any conclusive code samples to do this for WP7 so I figured I'd try out the following.
What I'm looking for is confirmation of whether this is the appropriate way to do this.
Socket socket =
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.RemoteEndPoint = new DnsEndPoint (someIP, 80); // use HTTP port 80
args.Completed += (obj, eva) =>
{
if (eva.SocketError != SocketError.Success)
{
//raise an error or set a view model property indicating error
}
socket.Close();
};
socket.ConnectAsync(args);
Unless things have changed in Mango, you can only really reach other hosts with HTTP or HTTPS anyway - so "reachable" really means "is listening for web requests on a known URL"... so the simplest approach would be to make some harmless web request to the relevant server. WebClient is probably the simplest way of doing that, although in my experience it does more work on the UI thread than you'd really expect, so I've ended up using the lower-level HttpWebRequest. For a single ping-like request, you may be okay to use WebClient.