C# : WCF client doesn't connect to same machine - c#

I am trying to make my first WCF program. It should be very simple but I can't manage to get it working.
Steps I have done so far:
Create C# windows forms application
Adding a button
Added a WCF Service to project.
Changed the codes according to this and this page tutorials.
IWCF.cs code :
using System;
...etc
namespace WCF_Application
{
[ServiceContract]
public interface IWCF
{
[OperationContract]
string DoWork();
}
}
WCF.cs code :
using System;
...
namespace WCF_Application
{
public class WCF : IWCF
{
public string DoWork()
{
return " Hello There! ";
}
}
}
Button code:
private void btnConnect_Click(object sender, EventArgs e)
{
// Starting the Server
ServiceHost svh = new ServiceHost(typeof(WCF));
svh.AddServiceEndpoint(
typeof(IWCF),
new NetTcpBinding(),
"net.tcp://localhost:8000");
svh.Open();
MessageBox.Show("Connected");
// Connecting Client to the server
ChannelFactory<IWCF> scf;
scf = new ChannelFactory<IWCF>(
new NetTcpBinding(),
"net.tcp://localhost:8000");
IWCF s = scf.CreateChannel();
string response = s.DoWork();
MessageBox.Show(response);
svh.Close();
}
I don't get the response message. The program justs freezes. When I trace the code, the program gets stuck at the strong response = s.DoWork(); line.
I also checked netstat -a in cmd. and it seems the port 8000 does open in listening mode. So the problem should be with the client part.
OS Windows 7 /
VS 2010 /
C#

You are running into a deadlock issue here because your WCF service is hosted on the same thread as your UI. You could try the following to host the service on another thread.
[ServiceBehavior(UseSynchronizationContext = false)]
public class WCF : IWCF
{
public string DoWork()
{
return " Hello There! ";
}
}
Here is some background on the WPF threading model and UseSynchronizationContext. Alternatively, you could thread off the client calls to your service, but that will likely have other UI updating consequences as well.

Related

0xC0000008: An invalid handle was specified in Hololens 2 using NetQM

I'm trying to send some data to a Python server through a ZMQ Socket. The Python server creates a socket using ZMQ as well.
```lang-python
print("Connecting with Unity Toolkit...")
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind('tcp://*:5555')
while True:
request = socket.recv_multipart()
print("Somethings received");
req = json.loads(request[1])
print("Received from Unity Toolkit: ", req)
```
I've tried to communicate with that server using a Python ZMQ client and it works, but when I try to do it with the .NET ZMQ library inside of an Unity 3D project, there is an exception that I don't know how to handle. The NETQMClient I was given (this is legacy code from an older project, but I'm allowed to change it) does something like this:
```lang-csharp
//this lines are executed using a Thread()
AsyncIO.ForceDotNet.Force();
requestSocket = new RequestSocket();
requestSocket.Connect("tcp://192.162.0.104:5555");
isAvailable = true;
while (!clientStopped){
//Debug.Log("Continuing");
}
requestSocket.Close();
NetMQConfig.Cleanup();
//end of the function running on a thread
//...
//later, when a button is pressed
try {
//endpoint is a one-character string that
//the server uses as a cue for something
requestSocket.SendMoreFrame(endpoint);
requestSocket.SendFrame(request); //this a class turned into a JSON using JsonUtility.ToJson
} catch (System.Exception) {
Debug.Log("Something went wrong");
throw;
}
```
Later the C# script waits for a response and I handle that response and use it. The thing is that I've tested it running the client and the server in the same computer and it works. HOWEVER, when I deploy the project into the real Hololens 2 (where the NETQM client runs), I get this error in Visual Studio.
I added the try catch block to see if there was some strange behaviour but there is no Exception in that point. Any hints on the right directions are appreciated.
EDIT: Whole Scripts used in this project for replicating the bug.
This class holds the data that will later be converted to JSON
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class Serialization {
public int numPanels;
public bool colorHarmony;
public float colorfulness;
[Serializable]
public Request(int numPanels, bool colorHarmony, float colorfulness) {
this.numPanels = numPanels;;
this.colorHarmony = colorHarmony;
this.colorfulness = colorfulness;
}
}
This is the script with the ZMQ logic
using System.Collections.Generic;
using System.Threading;
using NetMQ;
using NetMQ.Sockets;
using UnityEngine;
public class PythonNetworking {
private bool clientStopped;
private RequestSocket requestSocket;
private byte[] frame;
// for now only one request at a time is supported
public string requestResult;
private bool isAvailable;
public PythonNetworking() {
clientStopped = false;
var clientThread = new Thread(NetMQClient);
clientThread.Start();
}
public void StopClient() {
clientStopped = true;
}
// ReSharper disable once InconsistentNaming
private void NetMQClient() {
AsyncIO.ForceDotNet.Force();
requestSocket = new RequestSocket();
// Computer running the server which must receive the info
requestSocket.Connect("tcp://192.168.0.104:5555");
isAvailable = true;
while (!clientStopped)
{
//Debug.Log("Continuing");
}
requestSocket.Close();
NetMQConfig.Cleanup();
}
public void SetFrame(byte[] currFrame) {
frame = currFrame;
}
// Create queue of requests in case multiple have to be handled
private void SimpleRequest(string endpoint, string request) {
// wait until socket is available
while (!isAvailable) {
//Debug.Log("Socket unavailable");
}
isAvailable = false;
if (request == null) {
requestSocket.SendFrame(endpoint);
} else {
Debug.Log("Sending to Python server: " + request);
try
{
requestSocket.SendMoreFrame(endpoint);
Debug.Log("SendMoreFrame called");
requestSocket.SendFrame(request);
Debug.Log("SendFrame called");
}
catch (System.Exception)
{
Debug.Log("Something went wrong");
throw;
}
}
var msg = requestSocket.ReceiveFrameBytes();
Debug.Log("ReceiveFrameBytes returned a value");
isAvailable = true;
requestResult = System.Text.Encoding.UTF8.GetString(msg);
}
public void PerformRequest(string endpoint, string request) {
requestResult = null;
var requestThread = new Thread(() => SimpleRequest(endpoint, request));
requestThread.Start();
}
}
This is the script making the request when an event is triggered:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.UI;
using Newtonsoft.Json;
public class MyTool: MonoBehaviour {
private PythonNetworking pythonNetworking;
public struct PanelConstraints {
public string name;
public float height;
public float width;
}
public void Start() {
pythonNetworking = new PythonNetworking();
Debug.Log("Tool initialized!");
//called here for debugging purposes, this method is called when a button is pressed
SubmitConstraints();
}
//When a button is pressed
public void SubmitConstraints() {
Debug.Log("Submitting constraints...");
StartCoroutine(CreateRequest("P"));
}
private IEnumerator CreateRequest(string type) {
Serialization.Request request = new Serialization.Request(1, false, 1.0f);
var requestJson = JsonUtility.ToJson(request);
pythonNetworking.PerformRequest(type, requestJson);
yield return new WaitUntil(() => pythonNetworking.requestResult != null);
if (type == "P") {
panelData = JsonConvert.DeserializeObject<List<string>>(pythonNetworking.requestResult);
}
}
}
Finally, the Python server code is:
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind('tcp://*:5555')
while True:
request = socket.recv_multipart()
print("Somethings received");
req = json.loads(request[1])
#Data is processed
As per the setup, I'm using Unity 2019.4.26f1, I create a 3D scene, I add a GameObject to it, I attach the script MyTool.cs to it and I attach a button under the previous GameObject. On clicking the button, the SubmitContrainst() method is called (now called automatically in Start() for debugging purposes). This scene is deployed in the Hololens 2 using Visual Studio 2019 (although I've tried to run it in the Game Mode, communicating with a different computer to recreate the deployment environment, that is, with the client and the server in different devices and with different implementations of the library). When the application is about to start in the Hololens, the exception I introduced previously (see screenshot) is thrown. The Python server, running with Python version 3.10.4, doesn't receive anything. TCP communication seems to work, since when I run two Python scripts in different hosts performing client/server communication with ZMQ (using REQ and REP), it works, but I get the feeling this communication doesn't work on the Hololens 2. But this feels very strange because I've managed to communicate the Hololens 2 with another device (using another library, Windows.Networking.Socket).
Would you navigate to [Unity] -> [Player Settings] -> [Publishing Settings] to check the Capability of your project and make sure Internet Client or Internet Client Server is enabled according to the purpose. It can also be reviewed and modified in the manifest file of C# project.
The code around the thrown exception is more like Unity generated, you need to add break point to see if this issue is caused by a failed socket connection.
In addtion, you may also refer to the discussion on Web Socket Client Disconnecting Exception Being Thrown in UWP Builds - Unity Forum.

Detect pipe server with same name in global namespace

Question: Is there a way how to quickly check whether particular pipename is being hosted in session 0 - preferabely during the ServiceHost.Open call?
Scenario:
Two processes PipeHost and PipeUser are trying to communicate on the system via pipe with name PeacePipe. They are not required to be started with special privileges.
PipeHost is started and hosts the PeacePipe without any problem.
PipeUser is started and connects to PeacePipe without any problem.
PipeUser tries to comunicate to PipeHost via PeacePipe, it sends messages but PipeHost doesn't see anything.
In fact PipeUser connected to DifferentPipeHostInSession0 that is hosting pipe with same name (but OS creates different pipe) in an elevated (or service) process.
Background:
ServiceHost.Open should throw AddressAlreadyInUseException when the selected pipename is already being hosted.
However it's not thrown if the pipe is hosted in session 0 and you are attempting to host the same pipe in different sessions. As windows named pipes are normally not te be used accross sessions. With the exception of pipe hosted in session 0. Any process can connect to such a pipe. This can lead to the above sceanrio.
Code:
[ServiceContract]
public interface IService
{
[OperationContract]
void Ping();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults = true)]
public class Service: IService
{
public void Ping()
{
Console.WriteLine("Client Pinged me");
}
}
private static readonly Uri _pipeUri = new Uri("net.pipe://localhost/aaa");
private static readonly Binding _pipeBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
static void PipeHostTest()
{
ServiceHost serviceHost = new ServiceHost(new Service(), _pipeUri);
serviceHost.AddServiceEndpoint(typeof(IService), _pipeBinding, "");
try
{
//Fail here if same pipe already opened - even in Global space
serviceHost.Open();
Console.WriteLine("OPENED");
}
catch (AddressAlreadyInUseException e)
{
Console.WriteLine(e);
throw;
}
Console.ReadKey();
}
static void PipeClient()
{
ChannelFactory<IService> channelFactory =
new ChannelFactory<IService>(_pipeBinding, new EndpointAddress(_pipeUri));
var proxy = channelFactory.CreateChannel();
proxy.Ping();
}
static void Main(string[] args)
{
if (args.Any())
{
PipeClient();
}
else
{
PipeHostTest();
}
}
Run once without parameters elevated, once without parameters non-elevated. Both processes will host pipe with same name - but those are different pipes.
Then run once with any parameter. Client process will conect to the pipe hosted by elevated process.
Possible Solution:
Use a named mutex in global session new Mutex(true, "Global\\MutexForMyPipeName", out createdNew) to see if there is another process trying to do the same.
This however disqualifies even scenarios where the pipes are in 2 different sessions that do not colide.
Preferabely the ServiceHost.Open would take care about this for me as I'm using multiple bindings types (net.tcp, net.pipe, net.udp) and have single code for creating and hosting the ServiceHost. NamedPipes are the only ones that can allow creation of new host without AddressAlreadyInUseException exception while the address is actuall already in use.

Self-Hosted SignalR service won't work (start)

I have SignalR server as Class Library Project and i referenced it in Console application (to simulate Windows service)
Here is code for SignalR
public void Start()
{
try
{
string url = #"http://*:8081";
using (WebApp.Start<Startup>(url))
{
Logger.Info(string.Format("Server running at {0}", url));
}
}
catch (Exception ex)
{
Logger.Exception(ex, "Signalr start");
}
Run = true;
Logger.Info("Starting Worker");
workerThread = new Thread(() =>
{
Worker();
});
workerThread.Start();
}
And here is Startup class
public class Startup
{
Microsoft.AspNet.SignalR.HubConfiguration hubconfiguration = null;
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
hubconfiguration = new HubConfiguration();
hubconfiguration.EnableDetailedErrors = true;
app.MapSignalR(hubconfiguration);
}
}
So, it is in one thread, and worker is in another. That seems fine since i did it in other project where it works. Worker thread isn't problem, it's just empty loop, not related to server in any way.
Problem is that server seems to "stop" - when i look with Netstat, nobody is listening on port 8081. There is no exception, it just silently fails.
I referenced Owin.Cors (and Owin.Host.HttpListener) in console project that actually runs this server but as I said, server just stops.
When I try to connect, client says "connection actively refused" and Putty (telnet) also says "can't connect".
Where is the problem? In a nutshell, i have Class Library with SignalR server that is referenced in Console project that runs it but server just wont work.
[edit]
And there is code of Console app that starts service
static void Main(string[] args)
{
ServiceEngine Engine = new ServiceEngine();
Engine.Start();
Console.ReadKey();
Engine.Stop();
}
P.S. Sorry for my bad English.
Well, i solved it. Here was a problem:
public static void Start()
{
try
{
string url = #"http://127.0.0.1:8081";
WebApp.Start<Startup>(url);
Logger.Info(string.Format("Server running at {0}", url));
}
catch (Exception ex)
{
Logger.Exception(ex, "signalr start");
}
Run = true;
Logger.Info("Starting Worker");
workerThread = new Thread(() =>
{
Worker();
});
workerThread.Start();
}
As you can see, using statement was removed and now it works fine! Interesting note - you can also make Singleton implementation of this "Engine", and it will also work.
I got Solution after doing lot of R & D. And Its a Simple change related to Account and Access Rights.
Use LocalSystem Account instead of LocalService Account in Service Installer.
You can do this either from doing below change in design view of your service installer:
Properties of Service Process Installer -> Set Account to LocalSystem.
or by doing below change in in designer.cs file of your service installer:
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;

XSockets Client Connecting But Not Receiving Messages

I'm trying to set up a specific scenario but, obviously, I'm having problems. My server is a site that primarily hosts a WCF service but I want to add an XSockets host there as well. I have the standard code in the bootstrap code file as per the instructions in the readme.txt. Upon a client connection, I am starting a worker thread which is basically a heartbeat that the client will monitor. The relevant code from the controller is as follows:
public class HeartbeatController : XSocketController
{
public void AddMessage(string message)
{
this.SendToAll(message, "addMessage");
}
}
Within my worker thread I am calling this:
string message = String.Format("pump", Math.Round(cpuCounter.NextValue());
ClientPool connection = ClientPool.GetInstance("ws://mywebsite:4502/HeartbeatController", "*");
connection.Send(message, "addMessage");
Currently I'm testing this with a console client which looks like this:
class Program
{
static XSocketClient socketClient;
static void Main(string[] args)
{
Console.WriteLine("Starting client...");
string url = "ws://mywebsite:4502/HeartbeatController";
socketClient = new XSocketClient(url, "*");
socketClient.OnOpen += socketClient_OnOpen;
socketClient.Open();
while (true)
{
// let it sit and display the "pump" messages
string input = Console.ReadLine();
if (input.Equals("Q", StringComparison.Ordinal))
{
break;
}
}
}
static void socketClient_OnOpen(object sender, EventArgs e)
{
Console.WriteLine("socketClient Opened");
socketClient.Bind("addMessage", OnAddMessage);
}
private static void OnAddMessage(ITextArgs textArgs)
{
Console.WriteLine("AddMessage :: {0}", textArgs.data);
}
}
On the client, if I put a breakpoint in the socketClient_OnOpen method it gets hit so I think it is connecting. But the pump message never makes it to the client.
Two Questions:
Is there anything obvious that I'm missing?
(Unrelated) Since many enterprises really don't like punching holes in their firewalls, is there any way to use port 80 with this setup (so that the client connection would look like "ws://mywebsite/HeartbeatController")?
Thanks for any help!
So to see what your pump actually was sending in to the server I added a custom pipeline.
public class MyPipeline : XSocketPipeline
{
//Incomming textmessage
public override void OnMessage(IXSocketController controller, ITextArgs e)
{
Console.WriteLine("IN " + e.data);
//Let the message continue into the server
base.OnMessage(controller, e);
}
//Outgoing textmessage
public override ITextArgs OnSend(IXSocketProtocol protocol, ITextArgs e)
{
Console.WriteLine("OUT " + e.data);
return base.OnSend(protocol, e);
}
}
Since I then saw that you was sending in a string that actually did not have a property named "message". The actionmethod "AddMessage" expects you to pass in a property message of type string. So you can solve this in two ways, both of them are simple.
Just replace the string parameter in the AddMessage with ITextArgs
public void AddMessage(ITextArgs message)
or...
Pass in a object from your worker thread instead of a string like this
connection.Send(new {message}, "addMessage");
So all you need to do to get it to work is to change this row
connection.Send(message, "addMessage");
with this row
connection.Send(new {message}, "addMessage");
EDIT: Btw, 4.0 is on the way and the client will be very much improved as well as the serverside stuff.

Duplex named pipes - maximum number of clients on a single pipe

Using the code from this answer - Async two-way communication with Windows Named Pipes (.Net) - I'm finding the maximum number of connections/clients at any one time is 10.
In the crude example below (this uses multiple threads - same thing happens if multiple processes are used) clients 1 to 10 will start and run as normal. However clients 11 and 12 will block when 'ProcessData' is called, eventually throwing a TimeoutException.
public static void Start()
{
// Start Server
new Thread(new ThreadStart(Server.MainRun)).Start();
// Start Clients
for (int i = 1; i <= 12; i++)
{
Thread.Sleep(500);
Client c = new Client(i.ToString());
new Thread(new ThreadStart(c.Run)).Start();
}
}
// Create a contract that can be used as a callback
public interface IMyCallbackService
{
[OperationContract(IsOneWay = true)]
void NotifyClient();
}
// Define your service contract and specify the callback contract
[ServiceContract(CallbackContract = typeof(IMyCallbackService))]
public interface ISimpleService
{
[OperationContract]
string ProcessData();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class SimpleService : ISimpleService
{
public string ProcessData()
{
// Get a handle to the call back channel
var callback = OperationContext.Current.GetCallbackChannel<IMyCallbackService>();
callback.NotifyClient();
return DateTime.Now.ToString();
}
}
class Server
{
public static void MainRun()
{
// Create a service host with an named pipe endpoint
using (var host = new ServiceHost(typeof(SimpleService), new Uri("net.pipe://localhost")))
{
host.AddServiceEndpoint(typeof(ISimpleService), new NetNamedPipeBinding(), "SimpleService");
host.Open();
Console.WriteLine("Simple Service Running...");
Console.ReadLine();
host.Close();
}
}
}
class Client : IMyCallbackService
{
string _id;
public Client(string ID)
{
_id = ID;
}
public void Run()
{
Console.WriteLine("Starting client : " + _id);
// Consume the service
var factory = new DuplexChannelFactory<ISimpleService>(new InstanceContext(this), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/SimpleService"));
var proxy = factory.CreateChannel();
Console.WriteLine(proxy.ProcessData());
Console.WriteLine("Client finished : " + _id);
}
public void NotifyClient()
{
Console.WriteLine("Notification from Server");
}
}
If the client closes the channel when done (factory.Close()) then all clients will be able to run.
I understand this question - Number of Clients that can connect to a Named Pipe - is very similar but suggests there is no low limit.
This suggests the limit is 10 on Windows XP and 2000 machines - http://msdn.microsoft.com/en-us/library/system.io.pipes.namedpipeclientstream.aspx - except this is happening on a Windows 8 machine and Windows 2008 server.
Is there a way to change this limit? Am I missing something obvious?
Google brought me here a year after this question was asked. I figure I may as well post to help anyone else who ends up here. I think I know why the limit of 10.
Are you aware of the NetNamedPipeBinding.MaxConnections property?
Gets or sets the maximum number of connections, both inbound and outbound, that are allowed to endpoints configured with the named pipe binding. ... The maximum number of named pipe connections that are allowed with this binding. The default value is 10.
"guest" is correct and an old blog post from MSDN corroborates this as still being applicable in current .net releases.
It also suggests that the default setting was defined for use with development environments and "small" deployments.
From the other settings (eg, the buffer size) I'd suggest that >8kb per connection overhead would be expected.
I have not yet found any information on what issues may arise if the value is tuned for larger values (eg, >1000): the API appears tuned for shorter, burstier requests and I suspect for large values it may simply be inefficient (not so much for memory but just internal implementation) -
I'd welcome evidence either way on performance/issues (or success) with significant numbers of clients attaching to an endpoint.

Categories

Resources