I'm developing an application in C#. I have created ServiceHost app which will host the wcf service.
client will call ServiceHost.exe by passing some argument.
I have tried by below way.
static class ServiceHost
{
private static ITest channel = null;
static void Main(string[] args)
{
if (String.Compare(args[0], "dooperation", true) == 0)
{
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
binding.ReceiveTimeout = TimeSpan.MaxValue;
EndpointAddress ep = new EndpointAddress(address);
channel = ChannelFactory<ITest>.CreateChannel(binding, ep);
channel.DoOpertion1();
channel.Close() // close service
// Make sure the application runs!
Application.Run();
GC.KeepAlive(m_singleInstance);
}
else if (String.Compare(args[0], "stop", true) == 0)
{
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
binding.ReceiveTimeout = TimeSpan.MaxValue;
EndpointAddress ep = new EndpointAddress(address);
channel = ChannelFactory<ITest>.CreateChannel(binding, ep);
channel.DoOpertion2();
channel.Close() // close service
// Exit Appli
Application.Exit();
}
}
}
So here I'm creating communication channel, calling method and closing the channel.
but creating namepipe, then communication channel and service channel consuming more time, so i want to optimize the call so that it will create single instance of WCF service communication channel whenever client calls ServiceHost.exe.
is there any way to create single instance of channel?
is there any side effect if we keep open the namepine/communication channel.
Reusing a WCF channel is an anti pattern, the channel is not thread safe and you have to handle the fault state. The creation of the channel is not time consuming, the creation of the factory is. So you should reuse your ChannelFactory.
MSDN Middle-Tier Client Applications
Related
I have this method that calls and tries to open a service host to listen for request. It is able to create the service host and enable metadata publishing but it fails when it tries to open the service host.
When it reaches to host.Open() to is not able to open the service host so that i send my messages from a client.
why is my service not starting?
public void startOperator()
{
Uri baseAddress = new Uri("net.tcp://localhost/Test");
// Create the ServiceHost.
using (ServiceHost host = new ServiceHost(typeof(Operator), baseAddress))
{
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since
// no endpoints are explicitly configured, the runtime will create
// one endpoint per base address for each service contract implemented
// by the service.
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
// Close the ServiceHost.
host.Close();
}
any help is appreciated ..thanks
Don't use smb.HttpGetEnabled = true option as it conflicts with your net.tcp binding. After commenting it out, code works for me.
I have a locally hosted WCF service and a silverlight 5 app that communicates with it. By default silverlight tries to obtain the cross domain policy file over HTTP when making calls to the WCF service. I need to change this so that the policy file is served over net.tcp port 943 instead.
I have setup a local tcp listener that serves up the policy file over port 943 and i have followed this technique whereby i make a dummy socket connection in order to obtain the policy file over tcp as it is only retrieved once per application lifetime. The tcp server is being hit as expected and i am getting SocketError property value as Success (though i must note, the first time i hit the tcp server after starting the listener, the result is always access denied).
From what i can tell, the policy file is either invalid as the silverlight application as still unable to connect or the above mentioned technique does not work with silverlight 5.
What i would like to know is if what i am doing is possible & im doing it correctly, otherwise if there is an alternative means to have the policy file successfully downloaded over tcp and removing the need for retrieving it over HTTP.
Thanks
I wrote a long post about hosting silverlight in WPF - and using WCF with a http listener here:
How can I host a Silverlight 4 application in a WPF 4 application?
Now while not directly answering your question, it does show how to create a http version of the policy file.
I have also written something that serves up a policy listener over port 943, but I can't find where I posted the source - so I'll keep digging. As far as I remember though, silverlight does a cascade find of the policy file, if it doesn't get a connection on port 80, it'll then look on port 943.
I hope this is of some help somewhere.
Ok, here is the policy listener I had for net.TCP transport i.e. not HTTP based. I presume you have sorted this by now, sorry for the delay. It may well be of use to someone else now.
I was looking for the MS thing that said they cascade from HTTP to TCP, however, I can't, and therefore have to assume it was bunk and then changed.
Either way, if you call using a net.TCP service, and want a listener for it, this code should help:
#region "Policy Listener"
// This is a simple policy listener
// that provides the cross domain policy file for silverlight applications
// this provides them with a network access policy
public class SocketPolicyListener
{
private TcpListener listener = null;
private TcpClient Client = null;
byte[] Data;
private NetworkStream netStream = null;
private string listenaddress = "";
// This could be read from a file on the disk, but for now, this gives the silverlight application
// the ability to access any domain, and all the silverlight ports 4502-4534
string policyfile = "<?xml version='1.0' encoding='utf-8'?><access-policy><cross-domain-access><policy><allow-from><domain uri='*' /></allow-from><grant-to><socket-resource port='4502-4534' protocol='tcp' /></grant-to></policy></cross-domain-access></access-policy>";
// the request that we're expecting from the client
private string _policyRequestString = "<policy-file-request/>";
// Listen for our clients to connect
public void Listen(string ListenIPAddress)
{
listenaddress = ListenIPAddress;
if (listener == null)
{
listener = new TcpListener(IPAddress.Parse(ListenIPAddress), 943);
// Try and stop our clients from lingering, keeping the socket open:
LingerOption lo = new LingerOption(true, 1);
listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger,lo);
}
listener.Start();
WaitForClientConnect();
}
private void WaitForClientConnect()
{
listener.BeginAcceptTcpClient(new AsyncCallback(OnClientConnected), listener);
}
public void StopPolicyListener()
{
if (Client.Connected)
{
// Should never reach this point, as clients
// are closed if they request the policy
// only clients that open the connection and
// do not submit a policy request will remain unclosed
Client.Close();
}
listener.Stop();
}
public void RestartPolicyListener()
{
listener.Start();
}
// When a client connects:
private void OnClientConnected(IAsyncResult ar)
{
if (ar.IsCompleted)
{
// Get the listener that handles the client request.
TcpListener listener = (TcpListener)ar.AsyncState;
// End the operation and display the received data on
// the console.
Client = listener.EndAcceptTcpClient(ar);
// Try and stop our clients from lingering, keeping the socket open:
LingerOption lo = new LingerOption(true, 1);
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);
// Set our receive callback
Data = new byte[1024];
netStream = Client.GetStream();
netStream.BeginRead(Data, 0, 1024, ReceiveMessage, null);
}
WaitForClientConnect();
}
// Read from clients.
public void ReceiveMessage(IAsyncResult ar)
{
int bufferLength;
try
{
bufferLength = Client.GetStream().EndRead(ar);
// Receive the message from client side.
string messageReceived = Encoding.ASCII.GetString(Data, 0, bufferLength);
if (messageReceived == _policyRequestString)
{
// Send our policy file, as it's been requested
SendMessage(policyfile);
// Have to close the connection or the
// silverlight client will wait around.
Client.Close();
}
else
{
// Continue reading from client.
Client.GetStream().BeginRead(Data, 0, Data.Length, ReceiveMessage, null);
}
}
catch (Exception ex)
{
throw new Exception(Client.Client.RemoteEndPoint.ToString() + " is disconnected.");
}
}
// Send the message.
public void SendMessage(string message)
{
try
{
byte[] bytesToSend = System.Text.Encoding.ASCII.GetBytes(message);
//Client.Client.Send(bytesToSend,SocketFlags.None);
Client.GetStream().Write(bytesToSend,0, bytesToSend.Length);
Client.GetStream().Flush();
}
catch (Exception ex)
{
throw ex;
}
}
}
#endregion
I'm fairly recent to WCF and trying to figure out the best way to accomplish my requirements.
I have an application hosting a WCF service with the following code:
Uri u1 = new
Uri("http://localhost:8732/Client1/WcfServiceLibrary1/Service1/"); Uri
u2 = new
Uri("http://localhost:8732/Client1/WcfServiceLibrary1/Service1/mex");
WSHttpBinding binding = new WSHttpBinding();
sHost = new ServiceHost(typeof(WcfServiceLibrary1.Service1), u1);
ServiceMetadataBehavior meta = new ServiceMetadataBehavior();
meta.HttpGetEnabled = true;
sHost.AddServiceEndpoint(typeof(WcfServiceLibrary1.IService1), binding, u1);
sHost.Description.Behaviors.Add(meta); sHost.Open();
I can create a service reference on a client application and call methods on this service no problems. using the code below.
remoteService.Service1Client client = new remoteService.Service1Client();
remote.Text = client.GetData(3);
I can also call a method without a service reference.
EndpointAddress myEndpoint = new EndpointAddress("http://localhost:8732/Client1/WcfServiceLibrary1/Service1/");
WSHttpBinding myBinding = new WSHttpBinding();
ChannelFactory<IService1> ServiceConnectionFactory = new ChannelFactory<IService1>(myBinding, myEndpoint);
IService1 serviceConnection = ServiceConnectionFactory.CreateChannel();
If I try to execute the same code in the host application it get the error below.
The request channel timed out while waiting for a reply after
00:01:00. Increase the timeout value passed to the call to Request or
increase the SendTimeout value on the Binding. The time allotted to
this operation may have been a portion of a longer timeout.
How can a application consume and use a WCF service that it is currently hosting? Do I need to open the service in a thread of its own?
The idea is for the host to trigger some initialization before clients connect.
Im have a lab-environment in VMware with a WS2008R2-server and a W7-client. Im trying to broadcast a WCF-service-address from the server and receive this in the client. Im using System.Net.Sockets in C# .NET and I can successfuly send data from the server. I looks okay with WinDump at least. But when I try to receive this on the client it fails. I cant understand where the problem is..? The client can communicate with the server in other ways and with my WCF-service if I manually enter its address. I have turned of my firewalls in the lab-environment just in case.
[Update]
I checked WinDump on my client-vm and the same udp-message showes up here as well so it seem to be able to receive the broadcast. But why arent the ReceieveFrom-method returning anything? Have I setup the client socket wrong? Should it bind to the Any-address or to its local ip? Neither works...
[/Update]
Heres the server-code:
public static class MulticastServer
{
static Socket socket;
static IPEndPoint ep = new IPEndPoint(IPAddress.Broadcast, 9050);
public static void Open()
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
}
public static void Send(string message)
{
socket.SendTo(Encoding.ASCII.GetBytes(message), ep);
}
public static void Close()
{
socket.Close();
}
}
And the client:
public static class MulticastClient
{
public static string ReceiveOne()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 9050);
socket.Bind(ep);
byte[] data = new byte[1024];
EndPoint e = (EndPoint)ep;
int i = socket.ReceiveFrom(data, ref e);
socket.Close();
return Encoding.ASCII.GetString(data, 0, i);
}
}
I'm not sure where your current problem is but by reading your question I immediately knew that you are reinventing a wheel. Upgrade to .NET 4.0 and use WCF Discovery which is exactly for this purpose - UDP based searching for service with given contract and UDP based announcements about services. Moreover it is based on WS-Discovery protocol so I guess it should be interoperable. Isn't it better than custom solution?
How do I test the state of my proxy before making calls to my WCF service.
I have a duplex channel created using a duplex channel factory.
Before making any calls to the server I want to check the state of the proxy object created from the channel factory.
I saw this in a book... (to be used in immediate window)
? ((ICommunicationObject)flsProxy).State
But it gave this exception...
Cannot obtain fields or call methods on the instance of type 'System.ServiceModel.ICommunicationObject' because it is a proxy to a
remote object.
Is it better to just catch exceptions?
If you create your client proxy using a DuplexChannelFactory<T>, you should get back a regular old WCF channel:
Callbacks myCallbacks = new Callbacks();
DuplexChannelFactory<IMyService> factory =
new DuplexChannelFactory<IMyService>(myCallbacks,
new NetTcpBinding(), new EndpointAddress(.....));
IMyService proxy = factory.CreateChannel();
and you should be able to cast that to a ICommunicationObject and check its state:
ICommunicationObject comobj = (ICommunicationObject)proy;
if(comobj.State != CommunicationState.Faulted)
{
// call the service method
}
Where in this chain of statements does it no longer work for you??