Cannot open signalr connection in silverlight client - c#

I am trying to implement SignalR in Silverlight based on this blog: SignalR and Silverlight.
When I try to .Invoke() I get a runtime error "System.InvalidOperationException: The Start method must be called before data can be sent. at Microsoft.AspNet.SignalR.Client.Connection.Send(String data) at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke[T](String method, Object[] args)..."
I have _conn.Start() on my connection. If I try to Start() it a second time, right before invoke, it throws an exception. Here is my code:
private IHubProxy _hub;
private HubConnection _conn;
public AddProductView()
{
InitializeComponent();
var url = Application.Current.Host.Source.GetComponents(UriComponents.Scheme | UriComponents.HostAndPort,
UriFormat.Unescaped);
_conn = new HubConnection(url);
_hub = _conn.CreateHubProxy("SilverlightPrism.Mvc.Services.ProductHub");
_hub.On<string>("NewMessage", message => Deployment.Current.Dispatcher.BeginInvoke(() => DoAddItem(message) ));
_conn.Start();
}
private void DoAddItem(string item)
{
var product = DeserializeToProduct(item);
ProductData.Products.Add(product);
}
private void buttonAdd_Click(object sender, RoutedEventArgs e)
{
Random random = new Random();
var id = Guid.NewGuid();
var product = new Product
{
Price = random.Next(1000,100000),
ProdId = id,
ProdName = "New prod."
};
var jsonMessage = SerializeToJsonString(product);
_hub.Invoke("SendMessage", jsonMessage);
}
It is throwing the exception on _hub.Invoke();
How do I correctly get the hub connect and send a message?

HubConnection.Start is asynchronous. You cannot call Start right before Invoke because your HubConnection is probably still in the Connecting state.
You need to wait for the Task returned from Start to complete before you can call IHubProxy.Invoke. You can use await (or Task.ContinueWith if you aren't running .NET 4.5) to ensure Start finishes before you enable buttonAdd.
You could also create your AddProductView object asynchronously in a factory method. Instead of calling HubConnection.Start in the constructor, you could do it in a static Task<AddProductView> CreateAddProductView() method.
Alternatively, if you don't care about the creation of your AddProductView being asynchronous, you can just call Start synchronously:
_conn.Start().Wait();

Related

Azure Event Hubs : QuotaExceededException : 4999 handles limit

I am using Azure Event Hub library for C# in WebApi App. And I got this exception on message sending:
"Message":"An error has occurred.",
"ExceptionMessage":"Cannot allocate more handles to the current session or connection. The maximum number of handles allowed is 4999. Please free up resources and try again., referenceId: d975f39c71a14ae5915c9adca322e110_G15"
"ExceptionType":"Microsoft.ServiceBus.Messaging.QuotaExceededException"
I thought that instantiantion of EventHubProducerClient one time and reusing it instead of creating its instance on each message sending (with IAsyncDisposable pattern) will help as mentioned here
EventHub Exception :Cannot allocate more handles to the current session or connection. But it did not.
I believe there might be some more global issue. Might be missing something.
I am using single event hub with 7 consumer groups each of which is used by separate web application (single); well actually there is additional consumer group ($Default) but it is not used;
For receiving messages I use EventProcessorClient;
I use Azure.Messaging.EventHubs 5.2.0 and Azure.Messaging.EventHubs.Processor 5.2.0 packages;
Here is the whole code (did everything according to quickstart):
public class EventHubService : SubscriberBase
{
private readonly Action<string> errorHandler;
private readonly BlobContainerClient blobContainerClient;
private readonly EventProcessorClient eventProcessorClient;
private readonly EventHubProducerClient eventHubProducerClient;
private readonly int eventsToCheckpoint;
private readonly Timer checkpointTimer;
private int eventsSinceLastCheckpoint;
private bool shouldUpdateCheckpoint;
public EventHubService(EventHubSettings settings, Action<string> errorHandler) : base()
{
this.errorHandler = errorHandler;
eventHubProducerClient = new EventHubProducerClient(settings.ConnectionString, settings.EventHubName);
if (!String.IsNullOrWhiteSpace(settings.GroupId))
{
eventManager = new EventManager();
blobContainerClient = new BlobContainerClient(settings.StorageConnectionString, settings.BlobContainerName);
eventProcessorClient = new EventProcessorClient(blobContainerClient, settings.GroupId, settings.ConnectionString, settings.EventHubName);
eventsToCheckpoint = settings.EventsToUpdateCheckpoint;
checkpointTimer = new Timer(settings.IntervalToUpdateCheckpoint.TotalMilliseconds);
checkpointTimer.Elapsed += (sender, eventArgs) => shouldUpdateCheckpoint = true;
}
}
public override void Start()
{
eventProcessorClient.ProcessErrorAsync += HandleError;
eventProcessorClient.ProcessEventAsync += ProcessEventData;
eventProcessorClient.StartProcessingAsync().Wait();
checkpointTimer.Start();
}
public override async Task Stop()
{
try
{
checkpointTimer.Stop();
await eventProcessorClient.StopProcessingAsync();
}
finally
{
eventProcessorClient.ProcessEventAsync -= ProcessEventData;
eventProcessorClient.ProcessErrorAsync -= HandleError;
}
}
public override async Task Publish(string topic, JObject message)
{
using (EventDataBatch eventBatch = await eventHubProducerClient.CreateBatchAsync())
{
var #event = new Event(topic, message);
string json = #event.ToString(Formatting.None);
byte[] bytes = Encoding.UTF8.GetBytes(json);
var eventData = new EventData(bytes);
eventBatch.TryAdd(eventData);
await eventHubProducerClient.SendAsync(eventBatch);
}
}
private async Task ProcessEventData(ProcessEventArgs eventArgs)
{
if (eventArgs.CancellationToken.IsCancellationRequested)
{
return;
}
if (++eventsSinceLastCheckpoint >= eventsToCheckpoint)
{
eventsSinceLastCheckpoint = 0;
shouldUpdateCheckpoint = true;
}
if (shouldUpdateCheckpoint)
{
await eventArgs.UpdateCheckpointAsync();
shouldUpdateCheckpoint = false;
}
string json = Encoding.UTF8.GetString(eventArgs.Data.Body.ToArray());
var #event = new Event(json);
eventManager.TryRaise(#event);
}
private Task HandleError(ProcessErrorEventArgs eventArgs)
{
if (!eventArgs.CancellationToken.IsCancellationRequested)
{
errorHandler.Invoke($"[P:{eventArgs.PartitionId}][O:{eventArgs.Operation}] {eventArgs.Exception.Message}");
}
return Task.CompletedTask;
}
}
I have found some info in Service Bus Quotas like:
Number of concurrent receive requests on a queue, topic, or subscription entity (5000).
Subsequent receive requests are rejected, and an exception is received
by the calling code. This quota applies to the combined number
of concurrent receive operations across all subscriptions on a topic.
But still can't figure how to deal with it.
Please help.
Thanks.
This is indeed the answer EventHub Exception :Cannot allocate more handles to the current session or connection.
I did similar "fix" for Azure Event Hub library for NET Core but I have forgotten that I am also using Azure Event Hub library for NET Framework!
So I have instantiated EventHubProducerClient one time and reusing it now.
Seems working fine.
My bad. Was not attentive enough.
In my case, except creating only one instance of Client, use only one instance of sender.
I used method CreateSender each time when send a messsage, it also generates an exception

Unable to return a value from SignalR Client from a different method

I'm working on a Winforms app that executes SQL Procedures through a SignalR client. I'm relatively new to using SignalR and am still wrapping my head around it.
I start off by running my connection method to establish a connection with my SignalR service. I have two addresses configured ready for when I puslish but the DEV configuration leads to the SignalR service I am hosting locally.
Connection to SignalR (ConnectHub)
private async Task ConnectHub()
{
string hubAddress = "";
#if DEBUG
HubAddress = ConfigurationManager.AppSettings["HubAddress_DEV"];
#else
HubAddress = ConfigurationManager.AppSettings["HubAddress_PROD"];
#endif
if (string.IsNullOrEmpty(hubAddress))
{
MessageBox.Show("Hub Address is missing from configuration.");
}
ConnectionHandler.Client = new HubClient(hubAddress, "MyHub");
ConnectionHandler.Client.MyAlert += ConnectionHandler.ClientOnMyAlert;
ConnectionHandler.Client.ServerErrorEvent += ConnectionHandler.ClientOnServerErrorEvent;
await ConnectionHandler.Client.Connect(new List<string>() {
VehicleInfo.ThisVehicle.WarehouseCode,
VehicleInfo.ThisVehicle.VehicleName
});
}
My client is stored globally in my ConnectionHandler class where my event handlers are also kept. (I have breakpoints on these as I have not implemented them yet)
ConnectionHandler Class
public static class ConnectionHandler
{
public static HubClient Client { get; set; }
public static void ClientOnServerErrorEvent(string error)
{
throw new NotImplementedException(); //Currently not implemented
}
public static async Task ClientOnMyAlert(EnumMyAlertType alerttype, string message, Exception exception)
{
await Task.Yield(); //Currently not implemented
}
}
When I call the code to Invoke the procedure in my SignalR client, it returns a DataTable to me which is the intended result.
Call to SignalR
await ConnectHub();
DataTable dt = await ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>(
"FetchStatuses",
new object[0]); //This call works as intended and returns a populated DataTable
StatusInfo = new CStatuses();
All the above code is currently done on the main form, however I wanted to move this call to SignalR into a constructor to try and tidy things up.
The problem comes when I try to move this call into another method, the program hangs as I don't think it has received the return value from SignalR, I have placed a breakpoint beneath it and it is not reached. A TryCatch reveals nothing as it hangs within the "Try" with no exception.
Calling from contructor
public CStatuses()
{
Statuses = new List<CStatus>();
var dataTable = ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>("FetchStatuses",
new object[0])
.Result; //My program hangs on this line and proceeds no further
I am at a loss as to why it is doing this when I can get a value from the client from the form and when other members of my team have tried to do the same thing they can make a call to SignalR also from a different method.
Does anyone have any ideas as to how I can make this work?
I realize this has gotten quite long but if I can elaborate on things please let me know
FIXED CODE THANKS TO SOLUTION:
I have moved the code from my CStatuses constructor into a new async method within the same class and called it after initialization. This removes the need for .Result and appears to solve the problem for me.
public async Task PopulateStatuses()
{
var dataTable = await ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>("FetchStatuses",
new object[0]);
Statuses = new List<CStatus>();
foreach (DataRow row in dataTable.Rows)
{
var status = new CStatus
{
StatusId = Common.Utility.GetInt16Value(row["StatusID"]),
StatusCode = Common.Utility.GetStringValue(row["StatusCode"]),
Description = Common.Utility.GetStringValue(row["Description"])
};
Statuses.Add(status);
}
}
You are running into a deadlock with the .Result call, I would suggest creating an async method in the CStatuses class and after you initialize your CStatuses class call the websocket for data.

How do I save result in string of executed command

As the title says how can I save in string the result of the executed command?
SendCommand("server.hostname");
My code:
public void SendCommand(string command)
{
PacketModel packet = new PacketModel()
{
Identifier = 1,
Message = command,
Name = "RustManager"
};
string packetString = JsonConvert.SerializeObject(packet);
_webSocket.SendAsync(packetString, null);
}
public void GetServerHostname()
{
SendCommand("server.hostname");
}
Due to my small reputation I cannot comment - which is what I would have done before that.
Normally methods that end on Async are async and return a Task<T> type.
Using the await keyword makes your method async which is why you have to mark it as async in the method head.
Link to C#-Documentation on the await keyword
It is really hard to say how to get your code running since I don't have alot of information but maybe this helps:
public async void SendCommand(string command)
{
PacketModel packet = new PacketModel()
{
Identifier = 1,
Message = command,
Name = "RustManager"
};
string packetString = JsonConvert.SerializeObject(packet);
var result = await _webSocket.SendAsync(packetString, null);
}
EDIT 1:
After getting some new information here is my new answer:
You use this class for your websocket. If you look at the signiture of the "SendAsync" method you can see, that it returns void (which means "nothing"). So you will not be able to "Store some kind of information" here.
The method looks like this:
public void SendAsync (string data, Action<bool> completed)
{ [...] }
You will have to listen to the WebSocket and wait for a server-side response. It seems, that the library supports that via events:
ws.OnMessage += (sender, e) => {
...
};
So you can define an eventhandler to process the server-response.
If you would like to get the message data, you should access e.Data or e.RawData property.
e.Data property returns a string, so it is mainly used to get the text message data.
(source (GitHub Readme))
So to fullfil your wishes try the following:
1.) At initialization of your _websocket instance subscribe to the .OnMessageevent with a corresponding event handler. (Some information about that)
2.) Send your message as you do it now with SendAsync
3.) If your server responds with a message to the network socket, the OnMessageevent will fire and you will be able to get the Data from the Eventargument e
(I did not test this - but it should work since it is used this way in the examples)

Discord bot running, but will not connect to server

I've been trying to swap over my code from the 0.9.6 Discord.NET API to the new 1.0.1 API, and it's basically calling for a complete restructure to my code. But I've been having some trouble actually getting the bot up and running first of all.
I set up the code body according to the guide linked here
And while it runs without error, the bot itself is not appearing online in my server.
And before you ask, I had in fact replaced "Bot token here" with the actual bot token.
namespace DiscordBot{
public class Program
{
private CommandService commands;
private DiscordSocketClient client;
private IServiceProvider services;
static void Main(string[] args) => new Program().Start().GetAwaiter().GetResult();
public async Task Start()
{
client = new DiscordSocketClient();
commands = new CommandService();
string token = "<token>";
services = new ServiceCollection()
.BuildServiceProvider();
await InstallCommands();
await client.LoginAsync(TokenType.Bot, token);
await client.StartAsync();
await Task.Delay(-1);
}
public async Task InstallCommands()
{
// Hook the MessageReceived Event into our Command Handler
client.MessageReceived += HandleCommand;
// Discover all of the commands in this assembly and load them.
await commands.AddModulesAsync(Assembly.GetEntryAssembly());
}
public async Task HandleCommand(SocketMessage messageParam)
{
// Don't process the command if it was a System Message
var message = messageParam as SocketUserMessage;
if (message == null) return;
// Create a number to track where the prefix ends and the command begins
int argPos = 0;
// Determine if the message is a command, based on if it starts with '!' or a mention prefix
if (!(message.HasCharPrefix('!', ref argPos) || message.HasMentionPrefix(client.CurrentUser, ref argPos))) return;
// Create a Command Context
var context = new CommandContext(client, message);
// Execute the command. (result does not indicate a return value,
// rather an object stating if the command executed successfully)
var result = await commands.ExecuteAsync(context, argPos, services);
if (!result.IsSuccess)
await context.Channel.SendMessageAsync(result.ErrorReason);
}
}
}
And then for the MyBot.cs class
namespace DiscordBot
{
class MyBot : ModuleBase
{
private CommandService _service;
public MyBot(CommandService service)
{
_service = service;
}
}
}
The first thing you might want to do is add some logging to your bot.
As your code might be correct, but discord could be rejecting your connection for any amount of reason.
After await client.StartAsync(); add
client.Log += (msg) => {return Console.WriteLine(${msg.ToString()}");};`
This will output the message your receive from your client to the console.
Now you also need to configure which message should be send to this event. This can be done when creating your DiscordClient(). So instead of client = new DiscordSocketClient(); You could use
client = new DiscordSocketClient(
new DiscordSocketConfig()
{
LogLevel = LogSeverity.Verbose
}
);
Verbose should give you all the information you need. However you could also use LogSeverity.Debug instead, which is the highest available logging, and therefore would give you all messages.
Now that you have some feedback in your console, go and see what concrete errors you are having.
Also I would recommend first completing the your first bot part of the linked tutorial, instead of stepping into the commands directly. Once you got this working, you can continue onwards

C# winform application with threaded WCF client

I'm building an application that uses a WCF client to retrieve data from my server.
I want my call to the service to be asynchronous because many of them need to change the UI and I don't want to lose responsiveness from my app.
I tried using *Completed and *Async:
ServiceUserClient client = new ServiceUserClient();
client.FindUserCompleted += delegate(object sender, FindUserCompletedEventArgs e)
{
// here e.Result always fails
};
client.FindUserAsync(text);
Inside the *Completed delegate I always get an error (Connection closed by remote host: I enabled every logging I could find but I still don't understand why I get these errors)
Synchronous calls always work.
I have a class that handles all the calls to the service.
Is there a way to have syncronous calls inside something like a threaded class?
Are you setting the client side bindings to match what the server accepts?
You should also try testing it with the WCF test client (normally under %Program Files%\Microsoft Visual Studio 10.0\Common7\IDE\WcfTestClient.exe). If the test client works then check the bindings.
Is your call even getting to the server? I've had similar errors happen when serializing the response from the server to the client, so you might want to check for that. If you get to your server then the bindings are not the problem but rather there is a serialization problem. Do you have "sets" on the data model properties that are trying to get deserialized on the server?
I know this is no answer but I haven't been here enough to be allowed comments...and I've been where you are, totally frustrating.
I ended up creating my own async methods using BackgroundWorker this way (probably not the best way but it works):
// this is the click event on my search button
private void FindUser_Click(object sender, EventArgs e)
{
this.UserListSearch.Enabled = false;
this.UserListSearch.Items.Clear();
Model.FindUser(FindText.Text.ToUpper(), userlist =>
{
foreach (User u in userlist)
{
ListViewItem item = new ListViewItem(u.UserName);
item.Name = u.UserName;
item.SubItems.Add(u.Description);
this.UserListSearch.Items.Add(item);
}
this.UserListSearch.Enabled = true;
});
}
// this is the function I call when I need async call
public void FindUser(string text, Action<User[]> callback)
{
CreateBackgroundWorker<User[]>(() =>
{
ServiceUsersClient client = new ServiceUsersClient();
var results = client.FindUser(text);
client.Close();
return results;
}, callback);
}
// this is my utility function to create a bgworker "on demand"
private void CreateBackgroundWorker<T>(Func<T> dowork, Action<T> callback)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (sender, args) =>
{
T result = dowork.Invoke();
(callback.Target as Form).Invoke(callback, result);
};
worker.RunWorkerAsync();
}

Categories

Resources