Cross domain policy file over net.tcp for WCF servicehost and Silverlight 5 - wcf

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

Related

Fail to connect to WCF Service on my Localhost

I got the below error when trying to connect to WCF service running on my localhost using the WCF Test Client tool. I entered the end-point address as "net.tcp://localhost:19998/MyWCFService". MyWCFService is launched within Visual Studio 2017 on my local PC.
"There was no endpoint listening at net.tcp://localhost:19998/MyWCFService that
could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details."
I can verify the port 19998 is listening on my PC using the netstat.
TCP 0.0.0.0:19998 LISTENING
I have disabled all the firewall on my PC.
It turns out that my WCF service has some runtime errors that prohibits any clients to connect to it.. I have fixed the errors and i can connect now. Thanks.
It seems that the error is caused by that the service address is wrong. How do you host the service on the server side? I would like you could post more details about the server side so that give you an effective reply.
Here is my example about using NetTCPBinding, wish it is useful to you.
Server
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("net.tcp://localhost:1500");
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
using (ServiceHost sh = new ServiceHost(typeof(Calculator), uri))
{
sh.AddServiceEndpoint(typeof(ICalculator), binding,"");
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior();
//smb.HttpGetEnabled = true;
sh.Description.Behaviors.Add(smb);
}
Binding mexbinding = MetadataExchangeBindings.CreateMexTcpBinding();
sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "MEX");
sh.Open();
Console.Write("Service is ready....");
Console.ReadLine();
sh.Close();
}
}
}
[ServiceContract]
public interface ICalculator
{
[OperationContract]
int Test(int a);
}
public class Calculator : ICalculator
{
public int Test(int a)
{
return a * 2;
}
}
Result.
Feel free to let me know if there is anything I can help with.

Spring Integration two way communication with gps devices

We are using spring integration application for data receiption from gps devices. For current configuration we are able to receive data from device also respose sent back to device through same connection
current configuration is as
#SpringBootApplication
#IntegrationComponentScan
public class SpringIntegrationApplication extends SpringBootServletInitializer{
private Integer TIMEOUT=1000*60*10;
#Value("${TCP_PORT}")
private Integer TCP_PORT;
public static void main(String[] args) throws IOException {
ConfigurableApplicationContext ctx = SpringApplication.run(SpringIntegrationApplication.class, args);
System.in.read();
ctx.close();
}
#Bean
TcpNetServerConnectionFactory cf(){
TcpNetServerConnectionFactory connectionFactory=new TcpNetServerConnectionFactory(TCP_PORT);
connectionFactory.setSerializer(new CustomSerializerDeserializer());
connectionFactory.setDeserializer(new CustomSerializerDeserializer());
connectionFactory.setSoTimeout(TIMEOUT);
return connectionFactory;
}
#Bean
TcpInboundGateway tcpGate(){
TcpInboundGateway gateway=new TcpInboundGateway();
gateway.setConnectionFactory(cf());
gateway.setRequestChannel(requestChannel());
gateway.setRequestTimeout(TIMEOUT);
return gateway;
}
#Bean
public MessageChannel requestChannel(){
return new DirectChannel();
}
}
and message end point
#MessageEndpoint
public class Echo {
#ServiceActivator(inputChannel="requestChannel")
public byte[] echo(byte[] in,#SuppressWarnings("deprecation") #Header("ip_address") String ip){
//here we receive packet data in bytes from gps device
return "".getBytes();//string will contains expected result for device.
}
Above configuartion works fine for one way communication. but we want to implement two way communication. What we want after connection established between server and device we want to send message explicitely.To send command through server we dont know ip and port of device, so how can we send command through server to connected device.
I am trying following solution
created oubound channel adapter
#Bean
public TcpSendingMessageHandler tcpSendingMessageHandler() {
System.out.println("Creating outbound adapter");
TcpSendingMessageHandler outbound = new TcpSendingMessageHandler();
return outbound;
}
then created gateway for explicite message send, this will be called from service where we want to send data explicitely
#MessagingGateway(defaultRequestChannel="toTcp")
public static interface tcpSendService {
public byte [] send(String string);
}
After calling gate way following service activator invoked where we are setting connection ip and port, these ip and ports will be from connection established while receiving data from device
#ServiceActivator(inputChannel="toTcp", outputChannel="fromTcp")
public String send(String in){
System.out.println(new String(in));
TcpNetClientConnectionFactory factory = new TcpNetClientConnectionFactory(ip_extracted_from_inbound_connection, port_extarcted_from_inbound_connection);
factory.start();
tcpSendingMessageHandler.setConnectionFactory(factory);
return in;
}
// for ip and port extraction i am using following service which is inbound sevice
#ServiceActivator(inputChannel="requestChannel")
public byte[] echo(byte[] in,#Header("ip_address") String ip){
System.out.println(new String(in)+ " ; IP : "+ip);
for (String connectionId : factory.getOpenConnectionIds()) {
if(!lastConection.contains(ip))
lastConection = connectionId;
}
return "hello".getBytes();
}
For service activator i am setting new TcpNetClientConnectionFactory every time service called. Ip and port are extracted from TcpNetServerConnectionFactory. whenever device connects with server i am saving its connection ip and port, using these ip and port for data transmission through server but i am getting connection timeout issue.
Kindly help me out and suggest me a solution over it.
Thank you.
Replace the gateway with a pair of Collaborating Outbound and Inbound Channel Adapters.
In order to send arbitrary messages to a connection, you must set the ip_connectionId header.
The challenge, though, is how to direct the reply to the gateway. You would need to capture the replyChannel header from the request and, when a reply is received for that ip_connectionId, set the replyChannel headers.
This will only work, though, if you have only one request/reply outstanding to each device at a time, unless there is some data in the reply that can be used to correlate it to a request.
Another challenge is race conditions, where the device and the server initiate a request at the same time. You would need to look at data in the inbound message to see if it's a request or reply.

How Can I stop a WCF Service (with net.MSMQ binding) Hosted on IIS from another Windows Application

I have a WCF Service Using MSMQ hosted on IIS. I want to create a windows application which can stop WCF Service from picking MSMQ message. Once I have seen the MSMQ message in the queue I need to click a button and Start the WCF service to pick the message in MSMQ. Code sample would be apperciated.
IIS is not an appropriate container to host a MSMQ client in. This is because when the app pool unloads during times of low traffic the queue client also unloads. This behaviour is automatic and you don't have any control over it.
It would be far better to host your client in a windows service. However, the kind of "consume-on-demand" functionality you require is not easy to achieve and certainly is not supported by the standard bindings.
The best I can suggest is consume the message as soon as it's received and persist it somewhere until the user clicks the button, upon which you do whatever you want as the data in the message is already available.
I was able to solve this problem by applying a workaround. I created another queue in a different machine. Changed the address of the WCF client endpoint address to this queue in config. I created another external application which moved the message from the alternate queue to the actual queue. Thus the behavior of stopping IIS hosted WCF service with MSMQ binding was achieved
Stopping the "Net.Msmq Listener Adapter" Windows service and the "Windows Process Activation Service" will stop the messages from being pulled out of the queue. Starting the services back up will causes the messages to be pulled from the queue again. I'm doing this manually, rather than through another application, but I'd assume you could do it through another application as well. I haven't tested this completely, but something like this would probably work:
Dictionary<string,List<string>> runningDependentServices = new Dictionary<string,List<string>>();
private void StartMsmqBinding()
{
StartService("WAS");
StartService("NetMsmqActivator");
}
private void StopMsmqBinding()
{
StopService("NetMsmqActivator");
StopService("WAS");
}
private void StartService(string serviceName)
{
List<string> previouslyRunningServices = null;
var sc = new ServiceController();
sc.ServiceName = serviceName;
if (runningDependentServices.ContainsKey(serviceName))
{
previouslyRunningServices = runningDependentServices[serviceName];
}
try
{
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running);
if(previouslyRunningServices != null)
{
previouslyRunningServices.ForEach(a =>
{
var serviceController = new System.ServiceProcess.ServiceController() { ServiceName = a };
serviceController.Start();
serviceController.WaitForStatus(ServiceControllerStatus.Running);
});
}
}
catch (InvalidOperationException)
{
}
}
private void StopService(string serviceName)
{
var sc = new System.ServiceProcess.ServiceController() { ServiceName = serviceName };
runningDependentServices[serviceName] = sc.DependentServices.Where(a => a.Status == System.ServiceProcess.ServiceControllerStatus.Running).Select(a => a.ServiceName).ToList();
if (sc.CanStop)
{
try
{
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped);
}
catch (InvalidOperationException)
{
}
}
}
I'd think a similar approach would work for Net.Tcp binding. You'd probably have to stop the "Net.Tcp Listener Adapter" Windows service (ServiceName: "NetTcpActivator") and the "Windows Process Activation Service" in that case.

UDP broadcast of WCF Service address

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?

WCF: Net.TCP multiple bindings, same port, different IP Addresses

I've run into a problem. I'm a little new at WCF so any help would be greatly appreaciated.
Here's my code:
public static void StartHosts()
{
try
{
// Create a new host
ServiceHost host = new ServiceHost(typeof(ServerTasks));
List<IPAddress> ips = new List<IPAddress>(Dns.GetHostAddresses(Dns.GetHostName()));
if (IPAddress.Loopback != null)
ips.Add(IPAddress.Loopback);
ips.RemoveAll(i => i.AddressFamily != AddressFamily.InterNetwork);
foreach (var ip in ips)
{
string uri = string.Empty;
// Formulate the uri for this host
uri = string.Format(
"net.tcp://{0}:{1}/ServerTasks",
ip.ToString(),
ServerSettings.Instance.TCPListeningPort
);
// Add the endpoint binding
host.AddServiceEndpoint(
typeof(ServerTasks),
new NetTcpBinding(SecurityMode.Transport) { TransferMode = TransferMode.Streamed },
uri
);
}
// Add the meta data publishing
var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
smb = new ServiceMetadataBehavior();
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
"net.tcp://localhost/ServerTasks/mex"
);
// Run the host
host.Open();
}
catch (Exception exc)
{
DebugLogger.WriteException(exc);
}
}
An exception is thrown on the line: 'host.Open();'
The exception is:
System.InvalidOperationException
A registration already exists for URI 'net.tcp://192.168.1.45:4329/ServerTasks'.
What I'm trying to do is bind to all the network addresses on the machine so that the client applications can reach the service from whatever network they see it on. When I run this code it finds and attempts to set up a binding for about 5 different IPs, including 127.0.0.1.
192.168.1.45 is the second IP that it attempts to bind to. At the point that it throws the exception I can see (using netstat) that the program has bound to the first IP in the list on port 4329. There isn't anything bound to port 4329 on the address mentioned in the exception.
Sorry there's not a lot of details, I wanted to give a concise post. If anyone needs any more info I'll be happy to supply it.
Note: I've tried setting PortSharingEnabled to true for the NetTcpBinding that gets created inside the foreach loop, but I still experienced the same error.
Any help or advise would be greatly appreaciated!
Thanks
Thanks for the info Corazza!
I've figured out how to accomplish this. I was going about this all the wrong way.
My ultimate goal was to have the service listening on every IP Address available on the machine. Trying to bind to each address individually is the wrong way of doing this.
Instead, I only needed to bind the service to the machine's Host Name (not 'localhost') and WCF automatically listens on all adapters.
Here's the corrected code:
public static void StartHosts()
{
try
{
// Formulate the uri for this host
string uri = string.Format(
"net.tcp://{0}:{1}/ServerTasks",
Dns.GetHostName(),
ServerSettings.Instance.TCPListeningPort
);
// Create a new host
ServiceHost host = new ServiceHost(typeof(ServerTasks), new Uri(uri));
// Add the endpoint binding
host.AddServiceEndpoint(
typeof(ServerTasks),
new NetTcpBinding(SecurityMode.Transport)
{
TransferMode = TransferMode.Streamed
},
uri
);
// Add the meta data publishing
var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
smb = new ServiceMetadataBehavior();
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
"net.tcp://localhost/ServerTasks/mex"
);
// Run the host
host.Open();
}
catch (Exception exc)
{
DebugLogger.WriteException(exc);
}
}
Mel,
While I've never tried this before myself, here's some samples to look at that I've heard before. You may want to create your binding object first and then add the same instance to the AddServiceEndpoint method, just a thought so you're not creating new bindings every time as I remember reading somewhere that netTCPBindings should be a 1:1 relationship with the address (even though you're using different addresses).
I don't think you have to worry about port sharing as your opening up multiple ports.
Here's a sample of what you may want to accomplish with multiple ports.
http://www.aspfree.com/c/a/Windows-Scripting/WCF-and-Bindings/2/
Here's a good sample for using portsharing on the NetTcpBinding.
http://blogs.msdn.com/drnick/archive/2006/08/08/690333.aspx
-Bryan
Looks like i'm bit late :). But anyway - there is quite simple way to make Wcf listen all available network interfaces "net.tcp://0.0.0.0:8523/WCFTestService".