I`m developing wpf client-server app. Now i communicate with the server via Web Socket protocol by using SocketIOClient library. Now I declare on the On events like that:
private void DeclareGetDataEvents()
{
_socket.On("UpdateRivalPoints", (data) =>
{
RivalPoints++;
});
_socket.On("WinGame", (data) =>
{
this.IsUserWin = true;
});
_socket.On("OnlineFreeUsers", (users) =>
{
UsersNames = JsonConvert.DeserializeObject<ObservableCollection<string>>($"[{users.ToString().Trim(new Char[] {'[', ']', '\\'})}]");
});
_socket.On("WantedPlay", (rivalName) =>
{
IsRequestReceived = true;
RivalName = rivalName.ToString().Trim(new Char[] { '[', ']', '\"' });
PlayRequestString = $"{RivalName} want to play!";
});
_socket.On("StartPlay", (data) =>
{
IsGameOnline = true;
RivalPoints = 0;
IsUserWin = false;
App.Current.Dispatcher.Invoke(() =>
{
var window = new GameView();
window.ShowDialog();
});
});
_socket.On("RefusedPlay", (data) =>
{
PlayRequestString = $"{RivalName} refused to play against you";
});
}
Now the problem is that the callback inside the UpdateRivalPoints evnet and inside WinGame event happens only after i close the program and not immediately when the event arrived.
I tried to make the callback with BeginInvoke like that:
_socket.On("UpdateRivalPoints", async(data) => await App.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Send,new
UpdateRivalPointsDelegate(UpdateRivalPointsMethod)));
But it still doesnt work.
The On function requires the following as arguments: string eventName and Action<SocketIORespone callback
It seems that the issue here is that the UI is not updated immediately after the event arrives (this can only be done on the UI thread), so what you need to do is to wrap all the updates to the UI elements in App.Current.Dispatcher.Invoke, to ensure that the updates are made on the UI thread.
Something like this:
_socket.On("UpdateRivalPoints", (data) =>
{
App.Current.Dispatcher.Invoke(() =>
{
RivalPoints++;
});
});
For all of the UI updates.
Related
I am working on one react app where I have one component which is calling multiple api's in use effects. I want that component to work in background and call the api's according to the useeffect conditions even if we move to the another pages of application.
useEffect(() => {
if (props.success1) {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
//api call
}
else if(props.failed1){
setStepContents(getStepContent(activeStep, props));
setShowCancel(true);
}
}, [props.success1, props.failed1])
useEffect(() => {
if(props.success2 ){
const timer = setTimeout(() => {
// api call
}, 1000);
return () => clearTimeout(timer);
}
else if (props.success2) {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
//api calls
}
else if(props.failed2){
props.toggleLoader(false)
setStepContents(getStepContent(activeStep, props));
setShowCancel(true);
}
}, [props.success2, props.failed2])
Please let me know how to make it possible
In the example blow you can see I'm executing a batch request on a button click. After that I need to use the information provided in the callback, but without freezing the WebForms page. I have thought that the callback is asynchronous by itself, but obviously I'm wrong, because until the callback is not processed the page stays frozen.
batchRequest.Queue<Google.Apis.Calendar.v3.Data.Event>(
addRequest,
(content, error, i, message) => // callback
{
using (dbContext)
{
Event eventToUpdate = dbContextNewInstance.Events.FirstOrDefault(x => x.Id == dbObj.Id);
if (eventToUpdate != null)
{
eventToUpdate.GoogleCalendarMappingId = content.Id;
dbContextNewInstance.SubmitChanges();
}
}
});
batchRequest.ExecuteAsync();
*UPDATE:
I have made this implementation and its worked! So far I am worried is it everything going the correct way and no thread or DB connection is left unmanaged, guys?
batchRequest.Queue<Google.Apis.Calendar.v3.Data.Event>(
addRequest,
(content, error, i, message) => // callback
{
idsToMap[dbObj.Id] = content.Id; // A dictionary for my dbObj Id and the Id I receive from the remote API in the CALLBACK
});
Thread batchThread = new Thread(() => SubmitBatchRequest(batchRequest, idsToMap, connectionString));
batchThread.Start();
And the method with the Thread:
private static void SubmitBatchRequest(BatchRequest batchRequest, Dictionary<Guid, string> ids, string connectionString)
{
Thread.CurrentThread.IsBackground = true;
batchRequest.ExecuteAsync().GetAwaiter().GetResult(); // Send the batch request asynchronous
using (DataContext db = new DataContext(connectionString))
{
foreach (Guid dbObjId in ids.Keys)
{
Event eventToUpdate = db.Events.FirstOrDefault(x => x.Id == dbObjId);
if (eventToUpdate != null)
{
eventToUpdate.GoogleCalendarMappingId = ids[dbObjId];
}
}
// Thread.Sleep(50000);
db.SubmitChanges();
}
}
I am working on a C# Xamarin project. In the project, I have used the ZXing.Net.Mobile class library in order to implement a QR code Scanner.
After the user scans the QR code, a url is revealed. Which is used to send data to a webservice. My issue is: midway during the execution of the method connectToBackend the thread BeginInvokeOnMainThread expires. As a consequence the execution of connectToBackend never finishes. I need help about how to handle this thread scenario so that I can process my server request.
public void ShowScannerPage() {
ZXingScannerPage scanPage = new ZXingScannerPage();
scanPage.OnScanResult += (result) => {
// stop scanning
scanPage.IsScanning = false;
ZXing.BarcodeFormat barcodeFormat = result.BarcodeFormat;
string type = barcodeFormat.ToString();
// This thread finishes before the method, connectToBackend, inside has time to finish
Xamarin.Forms.Device.BeginInvokeOnMainThread(() => {
//_pageService.PopAsync();
_pageService.PopAsync();
App.UserDialogManager.ShowAlertDialog("The Barcode type is : " + type, "The text is : " + result.Text, " OK");
// problem here
connectToBackend(result.Text);
});
// If I put connectToBackend here there is still a problem
};
_pageService.PushAsync(scanPage);
}
To provide more information, I am using the MVVM approach. I have a page and when the users clicks on the scan button, the method ShowScannerPage opens up the scanner view on their mobile using the ZXing.Net Mobile library. I have a pasted my class below.
public class WorkoutViewModel {
public ICommand ScanCommand { get; private set; }
public readonly IPageService _pageService;
public WorkoutViewModel(IPageService pageService) {
this._pageService = pageService;
ScanCommand = new Command(ShowScannerPage);
}
public void ShowScannerPage() {
ZXingScannerPage scanPage = new ZXingScannerPage();
scanPage.OnScanResult += (result) => {
// stop scanning
scanPage.IsScanning = false;
ZXing.BarcodeFormat barcodeFormat = result.BarcodeFormat;
string type = barcodeFormat.ToString();
// This thread finishes before the method, connectToBackend, inside has time to finish
Xamarin.Forms.Device.BeginInvokeOnMainThread(() => {
//_pageService.PopAsync();
_pageService.PopAsync();
App.UserDialogManager.ShowAlertDialog("The Barcode type is : " + type, "The text is : " + result.Text, " OK");
// problem here
connectToBackend(result.Text);
});
// If I put connectToBackend here there is still a problem
};
_pageService.PushAsync(scanPage);
}
public async void connectToBackend(String nodes) {
// call api ...
}
}
You are calling an async function (async void connectToBackend(String nodes)) without the await keyword.
I think you can define "async" the event scanPage.OnScanResult += (result) => { so you can async the connectToBackend function.
I think BeginInvokeOnMainThread is not necessary
I am using SocketIoClientDotNet - Socket.IO Client Library for .Net, and i am trying to Emit two events one after one. Sometimes it emits both the events and sometimes it emits only first one. Below is my code:
socketModel sm = new socketModel();
sm.CHANNEL = "channel_" + cHAT_MESSAGES.SENDER_ID + cHAT_MESSAGES.RECEIVER_ID;
sm.DATA = chatMessageModelObj;
string serializedData = Newtonsoft.Json.JsonConvert.SerializeObject(sm);
var socket = IO.Socket(ConfigurationManager.AppSettings["socketlink"].ToString());
socket.On(Socket.EVENT_CONNECT, () =>
{
socket.Emit("apimessage", serializedData);
});
socket.On("apimessage", (data) =>
{
Console.WriteLine(data);
socket.Disconnect();
});
socketModel smSecond = new socketModel();
smSecond.CHANNEL = "messagecount_" + userID;
if (updateCount == null)
{
smSecond.DATA = 0;
}
else
{
smSecond.DATA = updateCount.Count();
}
string serializedDataSecond = Newtonsoft.Json.JsonConvert.SerializeObject(smSecond);
socket.On(Socket.EVENT_CONNECT, () =>
{
socket.Emit("apimessage", serializedDataSecond);
});
socket.On("apimessage", (data) =>
{
Console.WriteLine(data);
socket.Disconnect();
});
When i restart my nodejs server, All the second events which were not emitted before are sent after restart. Any help would be greatly appreciated.
I have faced similar type of issue, this is because of the instance created for the socket object. First i used singleton pattern for getting the instance of the socket object which caused me problem, when i open the same application in two different browsers. So i gave a try of using session to keep my socket object instead of having multiple socket object. Try using session for the object instead of creating two different instances. Hope it helps!
I solved this issue by Emitting both the events once EVENT_CONNECT() is successfully connected.
socketModel sm = new socketModel();
sm.CHANNEL = "channel_" + cHAT_MESSAGES.SENDER_ID + cHAT_MESSAGES.RECEIVER_ID;
sm.DATA = chatMessageModelObj;
string serializedData = Newtonsoft.Json.JsonConvert.SerializeObject(sm);
socketModel smSecond = new socketModel();
smSecond.CHANNEL = "messagecount_" + cHAT_MESSAGES.RECEIVER_ID;
if (updateCount == null)
{
smSecond.DATA = 0;
}
else
{
smSecond.DATA = updateCount.Count();
}
string serializedDataSecond = Newtonsoft.Json.JsonConvert.SerializeObject(smSecond);
var socket = IO.Socket(ConfigurationManager.AppSettings["socketlink"].ToString());
socket.Once(Socket.EVENT_CONNECT, () =>
{
socket.Emit("apimessage", serializedData);
socket.Emit("apimessage", serializedDataSecond);
});
socket.Once("apimessage", () =>
{
socket.Disconnect();
});
Still, i have a question is there any delay in events.
I am working out how best to consume my C# dlls using Edgejs for Node.
One proxy function in Node looks like this (a class method in Typescript):
readSettings(args: ReadSettingsParams) : Promise<response> {
let $engine = this;
var proxy = edge.func({
assemblyFile: "C:\\Development\\IAStash\\GLReport\\GLReport\\bin\\x64\\Debug\\GLReportEngine.dll",
typeName: "GLReportEngine.edgeGLReport",
methodName: "readSettings"
});
return new Promise<response>(function (resolve, reject) {
args.instance = $engine.instance;
proxy(args, function(error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
When my complex task in c# is synchronous, everything works as expected, but when I move the core of the c# function into a task:
return await Task.Run<object>( () => { do some stuff });
When I use the above pattern, the resolve(result) line is hit, the result is correct in the watch window, but any .then or Q.all structures that are composed do not respond to resolve(result) having been executed.
I have found that if I console.log("x"); before the proxy callback returns, then my composed .then and Q.all structures fire as expected. i.e. this version works:
readSettings(args: ReadSettingsParams) : Promise<response> {
let $engine = this;
var proxy = edge.func({
assemblyFile: "C:\\Development\\IAStash\\GLReport\\GLReport\\bin\\x64\\Debug\\GLReportEngine.dll",
typeName: "GLReportEngine.edgeGLReport",
methodName: "readSettings"
});
return new Promise<response>(function (resolve, reject) {
args.instance = $engine.instance;
proxy(args, function(error, result) {
console.log("GLReportProxy.readSettings proxy returns, Err = " + (!!error));
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
My c# routine in this case reads an xml file, deserializes it and returns it:
public Task<object> readSettings(object args)
{
if (args != null && typeof(System.Dynamic.ExpandoObject).IsAssignableFrom(args.GetType()))
{
var argdict = (IDictionary<string, object>)args;
if (argdict.ContainsKey("report"))
{
reportsettingsfile = argdict["report"].ToString();
}
return Task.Run<object>(
() => {
if (File.Exists(reportsettingsfile))
{
var xser = new XmlSerializer(typeof(ReportSettings.report));
string settingstext = File.ReadAllText(reportsettingsfile);
using (var tre = new StringReader(settingstext))
{
reportSettings = (ReportSettings.report)xser.Deserialize(tre);
}
return new { result = true, model = reportSettings };
}
else
{
return new { result = false, error = "File not found" };
}
});
} else
{
return Task.FromResult<object>(new { result = false, error = "Expected (input) object but can't read it." });
}
}
This is fairly simple. I figure that I've got problems in my use of async/await, that causes problems in Node. To be fair though, I had expected promises to be robust. There could be issues with my use of Typescript, Node, Edge, Promises, Q.
If anybody knows what's happening, and why logging to the console fixes the problem. I'd appreciate any help!
Mark
I found that this is an issue when there is a http.listener and a c# edge proxy callback in the same process. There could be other combinations, but some interplay between libraries is the root cause.
Since this issue is unresolved according to edgejs, the console.log method is a good workaround, particularly if you don't mind writing some helpful message to the log window.
console.log is a good workaround, but I wanted something silent. I notice that console internally has _stdout. If you execute console._stdout.write(''); you get a silent unlock. in Typescript you have to do (console as any)._stdout.write('');.
I do this on entry to the edge proxy callback. e.g.
readSettings(args: ReadSettingsParams) : Promise<response> {
let $engine = this;
var proxy = edge.func({
assemblyFile: "C:\\Development\\IAStash\\GLReport\\GLReport\\bin\\x64\\Debug\\GLReportEngine.dll",
typeName: "GLReportEngine.edgeGLReport",
methodName: "readSettings"
});
return new Promise<response>(function (resolve, reject) {
args.instance = $engine.instance;
proxy(args, function(error, result) {
(console as any)._stdout.write('');
//console.log("GLReportProxy.readSettings proxy returns, Err = " + (!!error));
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
Clearly you could log something as indicated in the comment.