No overload for method error on client server sockets application - c#

I am creating a client/server WPF application, where the server application adds new client information to a listview item if the client has not already connected, or updates that particular client's information OnDataReceived if they had already connected. I'm getting the 'No overload for -- matches delegate -- error', but I am really not understanding why. Can someone tell me what I am doing wrong?
By the way i'm pretty new to server/client socket communication, so if anyone can point me to some resources I would really appreciate it.
(updated with bkribbs answer)
// Error is here:
private void UpdateClientListControl()
{
if (Dispatcher.CheckAccess())
{
var lv = listBoxClientList;
listBoxClientList.Dispatcher.BeginInvoke(new UpdateClientListCallback(UpdateClientList), new object[] { this.listBoxClientList, false, null });
//No overload for 'UpdateClientList' matches delegate 'UpdateClientListCallback'
//I think the error is in how i added these additional parameters, but I tried using 'bool AlreadyConnected' and 'ClientInfo CurrentClient' and
//I get more errors 'Only assignment, call, incriment, ... can be used as a statement'
}
else
{
UpdateClientList(this.listBoxClientList);
}
}
and
// This worked fine until I added bool Alreadyconnected and CurrentClient
void UpdateClientList(ListView lv, bool AlreadyConnected=false, ClientInfo CurrentClient = null)
{
if (AlreadyConnected)
{
//Updates listview with CurrentClient information that has changed
}
else
{
//Updates listview with new client information
}
}
How I'm trying to use it in OnDataReceived:
public void OnDataReceived(IAsyncResult asyn)
{
//after receiving data and parsing message:
if(recieved data indicates already connected)
{
UpdateClientList(this.listBoxClientList, true, clientInfo);
}
else
{
UpdateClientList(this.listBoxClientList);
}
}

You're close. There are two problems.
The one you mention right now is because you haven't updated the delegate declaration for UpdateClientListCallback since you added two extra parameters.
Right now it looks like:
delegate void UpdateClientListCallback(ListView lvi);
You need to change it to:
delegate void UpdateClientListCallback(ListView lvi, bool AlreadyConnected, ClientInfo CurrentClient);
Your other problem that you would quickly discover is that you have the parameters a bit wrong. You are using Dispatcher.BeginInvoke(Deletegate, Object[])
So to fix your problem replace:
listBoxClientList.Dispatcher.BeginInvoke(new UpdateClientListCallback(UpdateClientList), this.listBoxClientList, false, null);
with:
object[] parameters = new object[] { this.listBoxClientList, false, null };
listBoxClientList.Dispatcher.BeginInvoke(new UpdateClientListCallback(UpdateClientList), parameters);
or for a nice one liner:
listBoxClientList.Dispatcher.BeginInvoke(new UpdateClientListCallback(UpdateClientList), new object[] { this.listBoxClientList, false, null });

Related

How to resolve this error with Unity's AsyncGPUReadback?

I am trying to read back from the GPU a compute buffer inside of which there is an array of structs that I have defined and previously set.
var req = AsyncGPUReadback.Request(myBuffer);
if(req.hasError == false)
{
var readback = req.GetData<myStruct>();
print(readback);
}
When I put this in the code I get this error: InvalidOperationException: Cannot access the data as it is not available. The problem is that the data should be available because when I use the normal GetData method everything works just fine.
myBuffer.GetData(data);
Does anyone have an idea where I should be looking to get this error solved? Thanks!
------------------------Edit-------------------------------
I found a solution here https://github.com/keijiro/AsyncCaptureTest/blob/master/Assets/AsyncCapture.cs , but It's not very clear to me why it is working now and not before.
void Update()
{
AsyncGPUReadback.Request(myBuffer, OnCompleteReadBack);
}
void OnCompleteReadBack(AsyncGPUReadBackRequest request)
{
if(request.hasError == false)
{
var data = request.GetData<myStruct>();
}
}

SignalR version 1.2.2 client side method not being called, nor is console logging being made

I am using this tutorial: https://learn.microsoft.com/en-us/aspnet/signalr/overview/older-versions/tutorial-server-broadcast-with-aspnet-signalr to broadcast a message from Conext stored in singleton. I have a few issues.
First, there doesn't seem to be any issues from assigning the hub and making a connection from the client side. This is my code:
$(function () {
var transactionHub = $.connection.TransactPtHub; // the generated client-side hub proxy
transactionHub.client.broadcastDmrUpdate = function (test) {
alert("Yo-Yo Ma!!" + test);
};
console.log('test');
$.connection.hub.logging = true;
$.connection.hub.start()
.done(function () { console.log('Now connected, connection ID=' + $.connection.hub.id); })
.fail(function () { console.log('Could not Connect!'); });
if ($.connection.hub.state === $.signalR.connectionState.disconnected) {
alert("connected");
}
else {
alert("not connected");
}
});
My alert, "connected" does display on page load. The function in this part of the code, "transactionHub.client.broadcastDmrUpdate = function (test) {..." never gets called from the server side.
This is my singleton:
public class TransactPtSingleton
{
private readonly static Lazy<TransactPtSingleton> _instance = new Lazy<TransactPtSingleton>(() => new TransactPtSingleton(GlobalHost.ConnectionManager.GetHubContext<TransactPtHub>().Clients));
private TransactPtSingleton(IHubConnectionContext clients)
{
Clients = clients;
}
private IHubConnectionContext Clients
{
get;
set;
}
public static TransactPtSingleton Instance
{
get
{
return _instance.Value;
}
}
public void BroadcastDmrUpdate(string dmr)
{
Clients.All.broadcastDmrUpdate(dmr);
}
}
and this is my hub,
[HubName("TransactPtHub")]
public class TransactPtHub : Hub
{
public void UpdateDailyTransactionTable()
{
}
}
So, I don't get a call back to the client function on broadcast, and even though I set my logging to true, I am not seeing any logs inside of my browser console. Where do I begin to troubleshoot? Or what am I doing wrong? Thank you.
UPDATE: I misread my own diagnostics.
if ($.connection.hub.state === $.signalR.connectionState.disconnected) {
is triggering, so the connection is not starting for some reason. Also, the .done and .fail never get entered, and I never get any console messages.
Update 2: Combing through the SignalR.js it seems to have something to do with,
// Check to see if start is being called prior to page load
// If waitForPageLoad is true we then want to re-direct function call to the window load event
if (!_pageLoaded && config.waitForPageLoad === true) {
connection._.deferredStartHandler = function () {
connection.start(options, callback);
};
_pageWindow.bind("load", connection._.deferredStartHandler);
return deferred.promise();
}
as on return deferred.promise() it leaves the SignalR.js and comes back to the calling script in UI.
Figured it out. So this basically stems back to my original question here: Question Which initially stemmed from using SignalR 1.2.2 with JQuery version 3
From my "Update 2"
if (!_pageLoaded && config.waitForPageLoad === true) {....
That are was having issues because with the deprecation of .load in Jquery > 3 I needed to change .load to .on as per:
Breaking change: .load(), .unload(), and .error() removed
These methods are shortcuts for event operations, but had several API limitations. The event .load() method conflicted with the ajax .load() method. The .error() method could not be used with window.onerror because of the way the DOM method is defined. If you need to attach events by these names, use the .on() method, e.g. change $("img").load(fn) to $("img").on("load", fn).
From: JQuery Guide
But I goofed up and inside jquery.signalR-1.2.2js, instead of changing,
_pageWindow.load(function () { _pageLoaded = true; });
To
_pageWindow.on("load", function () { _pageLoaded = true; });
I did,
_pageWindow.on(function () { _pageLoaded = true; });
No console errors were being displayed so it made things tougher. But, SignalR connection now is established from the client side, and also SignalR logging is now working.
So if you are using an older version of SignalR with a newer version of JQuery, this may be your problem and solution.

What is the inline syntax for returning a value from an anonymous function?

I've looked up numerous similar posts on StackOverflow, but they don't seem to come close to my issue as my lambda is within a Coroutine.
My code :
public string FetchInternetItems()
{
WWW www = new WWW(someURL);
StartCoroutine(WaitForRequest(www, callback => {
if(!string.IsNullOrEmpty(callback))
{
Debug.Log("Successfully worked..");
}
else
{
return "Did not connect to remote server.";
}
}));
Excerpt from WaitForRequest :
IEnumerator WaitForRequest(WWW www, Action<string> callback)
{
yield return www;
if (string.IsNullOrEmpty(www.error))
{
if (callback != null)
{
callback(www.text);
}
}
else
{
Debug.Log("WWW Error: " + www.error);
}
}
Coroutine class can be found here : https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html
Which returns the error :
Anonymous function converted to a void returning delegate cannot return a value
Ideally, I would like it to return the callback, unless nothing came through, and instead return the Did not connect to remote server. message.
Your WaitForRequest-method has a parameter of type Action<string> callback. Action is just a delegate for a method returning nothing (void), thus you can´t call return ... in such a delegate. However your design seems to be broken anyway. In case of an error you return a string, if everything runs correct you want to return the WWW-instance which seems kind of contradictory, doesn´t it?
You could just throw an exception in case of an error instead of returning a string:
IEnumerator WaitForRequest(WWW www, Action<string> callback)
Which you can now call like this:
StartCoroutine(WaitForRequest(www, callback =>
{
if(!string.IsNullOrEmpty(callback))
{
Debug.Log("Successfully worked..");
}
else
{
throw new Exception("Did not connect to remote server.");
}
}
The idea here is that if you can´t connect to the server there is no way for your application to continue working appropriately, so you can leave with an exception.
Have a look at your method signature:
public string FetchInternetItems()
it expects you to return a string.
Instead of returning a string from method scope, you are returning it from an anonymous method.
return "Did not connect to remote server.";
The above line says that you are trying to return a string from anonymous method which doesn't allow it causing following error:
Anonymous function converted to a void returning delegate cannot
return a value
FetchInternetItems() would end its execution without waiting for coroutine WaitForRequest to finish. So both executions are not related to each other. Having said that you won't be able to use response string that you are returning in FetchInternetItems().
To work around this problem, a simple solution is to change the signature to
public void FetchInternetItems(Action<string> callBack);
This is how you would call this method:
FetchInternerItems( result => { Debug.Log("This is response text from www : " + result);});
OR like this:
FetchInternerItems(OnCompleted);
void OnCompleted(string response)
{
Debug.Log("This is response text from www: " + response);
// You can do other stuff here...
}
If there is more to know. please ask in comment sections. Hope this helps.

(Azure) BrokeredMessage.GetBody<xxx>

I'm trying to put together a 'generic' subscriber that I can (re)use with Azure ServiceBus.
But I'm stuck as follows;
my code once stripped of non essential parts looks like this.
Subscribing.Client.OnMessage((recdMessage =>
{
var msgBody = recdMessage.GetBody<myClass>();
}, options);
I want my msgBody to be of the type that has been serialised into the body of the message.
Indeed if myClass were to be something like TelephonyEventMessage and the message received was of that type then my msgBody would be a correctly instantiated/rehydrated object of that type.
But although I can use recdMessage. ContentType to get the string name of the class in that message.... I just cant figure what I need to put in myClass above.
I'm at the end of my knowledge now and no amount of searches seems to look like an answer for me. Do I need to add a specific version for every type that may exist in my messages?
You can use this to receive messages from a subscription if you are expecting a number of different object types:
public void ReceiveMessageFromSubscription<T>(string topicPath, string subscriptionName, Action<T> action)
{
var client = SubscriptionClient.CreateFromConnectionString(ConnectionString, topicPath, subscriptionName);
client.OnMessage((message) =>
{
try
{
_logger.Information("Processing message");
action(message.GetBody<T>());
message.Complete();
}
catch(Exception ex)
{
_logger.Error(ex, "Error processing message");
message.Abandon();
}
} );
}
And then pass in a method which knows how to handle the object, as below. You could have a number of these methods, all calling ReceiveMessageFromSubscription.
public void ProcessObject()
{
_serviceBusService.ReceiveMessageFromSubscription<MyObject>(mytopic, mysubscription, _myobjectService.ProcessObject);
}

WPF Browser throws error

I am calling javascript functions from C# using the WPF variant of the browser control via InvokeScript.
I can call my function once without any problems. But when I call it a second time, it throws the following error :
Unknown name. (Exception from HRESULT: 0x80020006
(DISP_E_UNKNOWNNAME))
The Code I am using is the following :
this.browser.LoadCompleted += (sender, args) =>
{
this.browser.InvokeScript("WriteFromExternal", new object[] { "firstCall" }); // works
this.browser.InvokeScript("WriteFromExternal", new object[] { "secondCall" }); // throws error
};
The javascript function is :
function WriteFromExternal(message) {
document.write("Message : " + message);
}
I can call C# functions from the page via javascript just fine and invoke from C#, just can't invoke a second time. Regardless of what function I call.
I do not understand why it would fail the second time.
Thank you
Edit :
Did the following test (javascript) :
function pageLoaded() {
window.external.tick();
window.external.tick();
window.external.tick();
}
window.onload = pageLoaded;
function WriteFromExternal(message) {
document.write("Message : " + message);
}
And this is the C# side :
private int i = 0;
public void tick()
{
invoke("WriteFromExternal", new object[] { "ticked"+ i++ });
}
public static void invoke(string method, object[] parameters)
{
mainInterface.browser.InvokeScript(method, parameters);
}
And still throws the same error (after the first call), this suggests that it does not matter from where it is called, invoking the function from C# will throw this error if done more than once.
I assume you did the same as me and put your scripts in the body. For some reason when you call document.write from wpf it completely overwrites the document. If instead of using document.write you append a child it works fine. So change your JavaScript function to be:
window.WriteFromExternal = function (message) {
var d = document.createElement("div")
d.innerHTML= "Message : " + message;
document.body.appendChild(d);
}
// call from c#
WriteFromExternal("test")
It's been a while since I did something similar, but from what I remember your code looks correct. However, I do remember using a slightly different pattern in my project. Instead of delegating back to a JS method on the page I would make my ScriptingHost methods return values
EX:
C#:
public string tick()
{
return "some stuff";
}
var msg = window.external.tick();
document.write(msg);
If you have more complex objects than simple strings you can serialize them to JSON and parse them into an object on the JS side.
var jsonObj = JSON.parse(window.external.someMethod());
Not sure if you have the luxury of being able to change your method signatures in your scripting object, but it's at least an alternative approach.
Also, in your current implementation, have you tried to do something other than document.write? Do you get the same error if you display an alert box?

Categories