SignalR Self Hosting With WCF Service and Clients Would be Desktop Users - wcf

My Scenerio is that i need a SignalR self Hosted WCF Service that response and sends message to all connected users that came from Winform or WPF.
I have tried alot as follows:
I have Created WCF service with SignalR Self Hosting code as below which contains 3 Classes and 1 Interface.
namespace SignalRServiceClass
{
[ServiceContract]
public interface ISignalRServiceClass
{
[OperationContract]
string GetsMessage(string name);
[OperationContract]
void Configuration(IAppBuilder app);
[OperationContract]
void Send(string name, string message);
}
}
namespace SignalRServiceClass
{
public class SignalRServiceClass : ISignalRServiceClass
{
public string GetsMessage(string name)
{
return "Message From Service " + name + "!";
}
}
}
namespace SignalRServiceClass
{
class ClassHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
}
}
namespace SignalRServiceClass
{
class Startup
{
public void Configuration(IAppBuilder app)
{
// app.UseCors(CorsOptions.AllowAll);
// app.MapSignalR();
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration= new HubConfiguration
{
EnableDetailedErrors=true,
EnableJSONP= true
};
map.RunSignalR(hubConfiguration);
});
}
}
}
And Secondly Winform Client. I am confused here that how to manage the client code here but i put some code for testing as below.
private void button1_Click(object sender, EventArgs e)
{
//MessageBox.Show(test.GetsMessage("This is the Test Message"));
var hubConnection = new HubConnection("http://localhost:50172/");
var serverHub = hubConnection.CreateHubProxy("MessageRecievingHub");
serverHub.On("broadCastToClients", message => MessageBox.Show(message));
hubConnection.Start().Wait();
}
Please guide me in this manner.
Your Help will be appreciated. I have tried and googled alot but in vain.
Thanks alot in Advance.

You do not want SignalR, you need XSockets WCF sample

SignalR and WCF don't interoperate in this way, and don't really need to. If you're using SignalR, there's no reason to use WCF- you can publish your hub on IIS or self-hosted (see the Getting Started tutorial and the Self-Host tutorial at asp.net/signalr), and connect to it with desktop or JavaScript/HTML clients.

You can easily create a .NET client application to communicate with your SignalR server - below is a simple WinForm .NET C# client that sends and receives a SignalR message:
namespace SignalrTestClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
async void Form1_Load(object sender, EventArgs e)
{
var hubConnection = new HubConnection("http://localhost:8080/");
IHubProxy hubProxy = hubConnection.CreateHubProxy("MyHub");
await hubConnection.Start();
hubProxy.On("addMessage", message => onData(message));
await hubProxy.Invoke("Send", "Hello SignalR Server!");
}
private void onData(string msg)
{
Console.WriteLine(msg);
}
}
}
In your SignalR server you just need the following hub class:
public class MyHub : Hub
{
public void Send(string message)
{
Console.WriteLine("Received a message from a client");
if (message.Contains("Hello")) {
Clients.All.addMessage("Well hello there client!");
}
}
}
It is also possible to create a C++ client for SignalR

Related

Host a SOAP service within a BackgroundService using .Net Core 5

I'm new to .NET Core. I currently have a WCF host service that hosts another service that I'm trying to convert to .NET core. Using .NET 5, I created a worker service that handles the host background tasks and setup another service w/ an endpoint to handle incoming responses from another client. I'm having trouble using the EndpointAddress and ChannelFactory approach to create the endpoint and channel so the endpoint can be accessible via the outside world for response messages, but in doing so, I get the following error:
"No connection could be made because the target machine actively refused it. (localhost:8000)"
Maybe I'm going about this in the wrong way to host the service, not sure. Does anyone know?
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
return;
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<JLinkHostService>();
});
}
}
[ServiceContractAttribute]
public interface IResponseService
{
[OperationContractAttribute]
bool ResponseMessage(string sTermID, string sRespMsg);
}
public class ResponseService : IResponseService
{
public bool ResponseMessage(string sTermID, string sRespMsg)
{
string filePath = $"{c:\test"}\\{DateTime.Now.ToString("yyyy -MM-dd_HHmmssfff")}.txt";
System.IO.File.WriteAllText(filePath, $"{sTermID}\n\n{sRespMsg}");
return true;
}
}
public class HostService : BackgroundService
{
public override Task StartAsync(CancellationToken cancellationToken)
{
return base.StartAsync(cancellationToken);
}
public override Task StopAsync(CancellationToken cancellationToken)
{
return base.StopAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
ChannelFactory<IResponseService> factory = null;
try
{
Binding binding = new BasicHttpBinding();
EndpointAddress respAddress = new EndpointAddress("http://localhost:8000/response.svc");
factory = new ChannelFactory<IResponseService>(binding, respAddress);
IResponseService channel = factory.CreateChannel();
// Test service proxy
channel.ResponseMessage("test", "test");
while (!stoppingToken.IsCancellationRequested)
{
// Host background tasks happen here
await Task.Delay(Int32.Parse(GetCfgValue("AppSettings:pollingIntervalMilli")), stoppingToken);
}
}
catch (Exception ex)
{
Log.Fatal(ex.ToString());
}
finally
{
if(factory != null)
factory.Close();
}
}
}
}

Using the new signalR for DotNet core to send messages from console App to web page

I am using this example from https://blogs.msdn.microsoft.com/webdev/2017/09/14/announcing-signalr-for-asp-net-core-2-0/ to create a console app that can send messages from a simple console app to a web page.
Below is the simple example for console application which reads the user input and prints that input on the screen, I want to send the same user input also to the web page.
static void Main(string[] args)
{
while (true)
{
Console.WriteLine("Enter input:");
string line = Console.ReadLine();
if (line == "exit")
{
break;
}
sendSignalToClient(line);
Console.Write("Message Sent To Client: " + line);
}
}
private static void sendSignalToClient(string line)
{
//Send a message from this app to web client using signalR
}
I have just started learning about this. Any material or suggestions related to this is appreciated. -Thanks
Edit: I am using a sample signalR chat application.
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.InvokeAsync("broadcastMessage", name, message);
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseFileServer();
app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("chat");
});
}
Below is the code for the console application that is sending messages to web page
class Program : Hub
{
static void Main(string[] args)
{
Task.Run(Run).Wait();
}
static async Task Run()
{
var connection = new HubConnectionBuilder()
.WithUrl("http://localhost:59768/chat")
.WithConsoleLogger()
.WithMessagePackProtocol()
.WithTransport(TransportType.WebSockets)
.Build();
await connection.StartAsync();
Console.WriteLine("Starting connection. Press Ctrl-C to close.");
var cts = new CancellationTokenSource();
Console.CancelKeyPress += (sender, a) =>
{
a.Cancel = true;
cts.Cancel();
};
connection.Closed += e =>
{
Console.WriteLine("Connection closed with error: {0}", e);
cts.Cancel();
return Task.CompletedTask;
};
connection.On("broadcastMessage", async () =>
{
});
while (true)
{
Thread.Sleep(2000);
await connection.SendAsync("send", "alex", "hello");
}
}
All the code is working but on the console application i am receiving this exception:
Microsoft.AspNetCore.Sockets.Client.HttpConnection[19]
09/17/2017 13:47:17: Connection Id 40da6d4b-9c47-4831-802f-628bbb172e10: An exception was thrown from the 'Received' event handler.
System.FormatException: Target method expects 0 arguments(s) but invocation has 2 argument(s).
at Microsoft.AspNetCore.SignalR.Internal.Protocol.MessagePackHubProtocol.CreateInvocationMessage(Unpacker unpacker, IInvocationBinder binder)
at Microsoft.AspNetCore.SignalR.Internal.Protocol.MessagePackHubProtocol.TryParseMessages(ReadOnlyBuffer`1 input, IInvocationBinder binder, IList`1& messages)
at Microsoft.AspNetCore.SignalR.Internal.HubProtocolReaderWriter.ReadMessages(Byte[] input, IInvocationBinder binder, IList`1& messages)
at Microsoft.AspNetCore.SignalR.Client.HubConnection.<OnDataReceivedAsync>d__31.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Sockets.Client.HttpConnection.<>c__DisplayClass49_0.<<ReceiveAsync>b__0>d.MoveNext()
Your event handler should take a string argument, it should look like this:
connection.On<string>("broadcastMessage", data =>
{
});
Take a look at this tutorial because although it is bit old it would give you good advices:
https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-getting-started-with-signalr
On the one hand you web page needs to connect to a SignalR Hub and on the other your console should connect to a service, probably in you web project, to send the message to the hub and from there to all the registered clients. The key is that the hub executes JavaScript functions in client side but it has to know the clients, due to a registration, and that hub instance had to be called to execute is methods. What makes me sense is to inject the hub in an API controller and, using httpclient, post the inputs to your controller.
Another good tutorial but this one is very recent:
https://spontifixus.github.io/ASPNET-Core-SignalR-with-Aurelia-and-Webpack/
I hope it helps.
Juan
EDIT:
I've just found an answer (may 2017) to the same question here:
SignalR Console app example
In server side:
[HubName("MyHub")]
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
}
And in client side:
var myHub = connection.CreateHubProxy("MyHub");
...
// To write received messages:
myHub.On<string, string>("addMessage", (s1, s2) => {
Console.WriteLine(s1 + ": " + s2);
});
...
// To send messages:
myHub.Invoke<string>("Send", name, message).ContinueWith(task1 => {
if (task1.IsFaulted)
{
Console.WriteLine("There was an error calling send: {0}", task1.Exception.GetBaseException());
}
else
{
Console.WriteLine(task1.Result);
}
});
This might work for you too Alexander.
I hope it helps.
Juan

Delphi - How to consume a WCF Service with netHTTPBindings

I have a WCF Service written in Visual Studio 2015 (c#) that uses web sockets, this means the endpoint is configured with netHTTPBindings. I have a Delphi application that I have currently written in XE and would like to consume the WCF Service, what is the best way for a Delphi application to consume a web socket WCF Service?
// Edit ---------------------------------------------------------------------------
I am now using wsDualHttpBindings, here is some prototype code:
WCF Service interface
[ServiceContract(CallbackContract = typeof(IStatusCallback))]
public interface IStatusService
{
[OperationContract(IsOneWay = true)]
Task StartSendingStatus();
}
[ServiceContract]
public interface IStatusCallback
{
[OperationContract(IsOneWay = true)]
Task SendStatus(string aValue);
}
Implementation
public class StatusService : IStatusService
{
public async Task StartSendingStatus()
{
var callback = OperationContext.Current.GetCallbackChannel<IStatusCallback>();
while (((IChannel)callback).State == CommunicationState.Opened)
{
await callback.SendStatus(GetStatus());
await Task.Delay(1000);
}
}
private string GetStatus()
{
// For now return datetime
string dt = DateTime.UtcNow.ToString();
return Convert.ToString(dt);
}
}
Here is how I consume it in a C# application, I put the result into list box.
public partial class ClientForm : Form
{
private StatusServiceReference.StatusServiceClient StatusService;
private class CallbackHandler : StatusServiceReference.IStatusServiceCallback
{
private ListBox _listbox;
public CallbackHandler(ListBox aListBox)
{
_listbox = aListBox;
}
public void SendStatus(string aValue)
{
_listbox.Items.Add(aValue);
_listbox.SelectedIndex = _listbox.Items.Count - 1;
}
}
public ClientForm()
{
InitializeComponent();
var context = new InstanceContext(new CallbackHandler(StatusListBox));
StatusService = new StatusServiceReference.StatusServiceClient(context);
}
private void StatusBtn_Click(object sender, EventArgs e)
{
StatusService.StartSendingStatus();
}
}
This works fine, I would like to know the best way to do the above client code in Delphi. When I import the WSDL file it does not have the IStatusServiceCallback interface.

WCF application don't working in my home network

i create a small wcf apps when i am testing this apps in my machine then it is working but when i run the wcf server end on another pc at my home in same network then i am getting error
A remote side security requirement was not fulfilled during authentication.Try increasing the ProtectionLevel and/or ImpersonationLevel.
both the pc at my home in same work group and they can access each other. i try to find out the answer but people say this is firewall issue. so i disable firewall at both the pc but still getting the problem. here is my sample code. please guide me how can i run this wcf apps in two pc at my home network. thanks
Service end
namespace WCFSample
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string MyName(string name);
}
}
namespace WCFSample
{
public class Service1 : IService1
{
public string MyName(string name)
{
return string.Format("My Name... {0}", name);
}
}
}
namespace ConsoleApplication1
{
class Program
{
static ServiceHost customerHost = null;
static void Main(string[] args)
{
try
{
HostCustomerService();
Console.WriteLine();
Console.WriteLine("Press any key to stop the services.");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
customerHost.Close();
}
}
private static void HostCustomerService()
{
customerHost = new ServiceHost(typeof
(Service1));
ServiceEndpoint tcpEndpoint = customerHost.AddServiceEndpoint(
typeof(IService1), new NetTcpBinding(),
"net.tcp://192.168.1.103:9020/Service1");
customerHost.Open();
Console.WriteLine("{0} {1}", tcpEndpoint.Address, tcpEndpoint.Name);
Console.WriteLine();
}
}
}
client end
namespace Client1
{
class Program
{
static void Main(string[] args)
{
IService1 channel = null;
var endPoint = new EndpointAddress(
"net.tcp://192.168.1.103:9020/Service1");
channel = ChannelFactory<IService1>.CreateChannel(new NetTcpBinding(), endPoint);
Console.WriteLine("Enter Name");
string line = Console.ReadLine();
Console.WriteLine(channel.MyName(line));
Console.ReadKey();
}
}
}
I think by default, NetTcpBinding requires a secure channel.
When you create your binding (on client and server), instead of:
new NetTcpBinding()
Try:
new NetTcpBinding(SecurityMode.None)

How can I send a data from WCF host to connected client?

I want to send a data from WCF host (not service proxy) to the connected client with the service.
How can I achieve this?
You'll need to create a Duplex service. See this article for more information: http://msdn.microsoft.com/en-us/library/ms731064.aspx
Here's an example:
[ServiceContract(
SessionMode=SessionMode.Required,
CallbackContract=typeof(INotificationServiceCallback))]
public interface INotificationService
{
[OperationContract(IsOneWay = true)]
void Connect();
}
public interface INotificationServiceCallback
{
[OperationContract(IsOneWay = true)]
void SendNotification(string notification);
}
public class NotificationService : INotificationService
{
public static List<INotificationServiceCallback> Clients =
new List<INotificationServiceCallback>();
public void Connect()
{
Clients.Add(
OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>());
}
}
public class Notifier
{
void HandleReceivedNotification(string notification)
{
foreach (var client in NotificationService.Clients)
{
client.SendNotification(notification);
}
}
}