I've found myself in need of finding a WCF Binding that uses HTTPS/SOAP and must be duplex. I was programmatically using NetTcpBinding before but the binding now has to be HTTPS/SOAP. I did some research and it seems like it's not possible without creating your own CustomBinding.
However I'm sort of at a lost in what to do (not very familiar with bindings and the setup). I can't seem to get correct binding elements for what I need:
public class CustomHttpsBinding : CustomBinding
{
public CustomHttpsBinding()
{
}
public override BindingElementCollection CreateBindingElements()
{
ReliableSessionBindingElement https = new ReliableSessionBindingElement();
SecurityBindingElement security = SecurityBindingElement.CreateCertificateOverTransportBindingElement();
CompositeDuplexBindingElement duplex = new CompositeDuplexBindingElement();
SslStreamSecurityBindingElement ssl = new SslStreamSecurityBindingElement();
MessageEncodingBindingElement encoding = new GZipMessageEncodingBindingElement((MessageEncodingBindingElement) new BinaryMessageEncodingBindingElement());
HttpsTransportBindingElement transport = new HttpsTransportBindingElement();
return new BindingElementCollection(new BindingElement[] { https, security, duplex, ssl, encoding, transport });
}
It gives me an invalid operation exception when checking soap over secure transport requirements saying my contract is configured with an authentication mode that requires integrity and confidentiality. However the transport cannot provide integrity and confidentiality.
Seems like my HttpsTransportBindingElement is not correct? I'm not sure.
Thanks
edit:
I did manage to get WSDualHttpBinding to work at one point, but it seems like HTTPS is not possible with it (as well as others on the internet which say it shouldn't even be used)
HTTP isn't duplex protocol - its request / response - that's why wsDualHttpBinding uses two connections - one in each direction. Silverlight achieves duplex over HTTP by polling for messages from the client under the covers
NetTcpBinding uses TCP which can quite happily be duplex
If you can wait until 4.5 is released later this year this has the NetHttpBinding which does duplex using the WebSocket protocol
Related
I am trying to implement a C# WCF server to the ONVIF specifications at http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl. I have generated the contract code using
SvcUtil.exe http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl
which generates Device and PTZ interfaces. I then created an implementation of the generated interfaces and expose that using a ServiceHost like this:
serviceHost = new ServiceHost(typeof(OnvifImpl), baseUri);
serviceHost.AddServiceEndpoint(typeof(Device), new WSHttpBinding(), "device_service");
serviceHost.AddServiceEndpoint(typeof(PTZ), new WSHttpBinding(), "ptz");
When I point Onvif Device Manager 2.2.250 (https://sourceforge.net/projects/onvifdm/) at my server, I get an exception in my server "The SOAP action specified on the message, '', does not match the HTTP SOAP Action, 'http://www.onvif.org/ver10/device/wsdl/GetScopes'.". Wireshark shows that the request does not have any SOAP header. However, as far as I can tell, the client was developed against the same WSDL files.
I am afraid I am completely new to ONVIF, SOAP, Web services and WCF, so I have no idea where the problem may be. I have seen various suggestions to modify the client, but that is not an option.
The answer is to use a custom binding to remove WS-Addressing. This is what the client code does, so I do the same to match. I am not entirely sure whether this is a "solution" or a "workaround" but it get the two talking.
var binding = new CustomBinding(new BindingElement[] {
new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8),
new HttpTransportBindingElement(),
});
serviceHost.AddServiceEndpoint(typeof(Device), binding, "device_service");
serviceHost.AddServiceEndpoint(typeof(PTZ), binding, "ptz");
The key difference is using MessageVersion.Soap12 instead of MessageVersion.Soap12WSAddressing10 which is the default.
I've looked at a bunch of threads like Detect if wcf service is activated but these solutions require the client to proactively detect if the WCF service is running. But what if I am in the middle of a transaction and the WCF service goes down or the connection is lost for some reason? In my testing there is no exception thrown; either nothing happens at all or that twirly circle thing just keeps going round and round. I want the client to detect if the service/connection is lost and gracefully tell the user it's down. I have timeouts set in my code:
NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
binding.OpenTimeout = TimeSpan.FromSeconds(15);
binding.SendTimeout = TimeSpan.FromSeconds(3000);
binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
this._engineChannel = new DuplexChannelFactory<IEngineApi>(this, binding, new EndpointAddress("net.pipe://localhost/Engine"));
But if I am in the middle of a transaction nothing actually happens; these timeouts don't seem to affect anything.
You can use one of the two approaches:
1
The two things I do are a telnet check to make sure the WCF process
has the socket open.
telnet host 8080 The second thing I do is always add an IsAlive method
to my WCF contract so that there is a simple method to call to check
that the service host is operating correctly.
public bool IsAlive() {
return true; }
Source: Pinging WCF Services
2
Use the Discovery/Announcement feature introduced in WCF 4.0
Discovery depends on the User Datagram Protocol (UDP). UDP is a connectionless protocol, and there is no direct connection required between the client and server. The client usages UDP to broadcast finding requests for any endpoint supporting a specified contract type. The discovery endpoints that support this contract will receive the request. The implementation of the discovery endpoint responds back to the client with the address of the service endpoints. Once the client determines the services, it invokes the service to set up call.
Simple usage example: http://www.codeproject.com/Articles/469549/WCF-Discovery
I'm attempting to set up a client (Web Application) and service (WCF Service) that will communicate using a WSHttpBinding. It appears that in order to use this binding the client sends preliminary messages to set up the channel.
Between the client and the service exists a service bus which is routing on a custom header. The message, when using BasicHttpBinding security, routes without issue.
My question is: Is there any way to add the same custom header to the preliminary RequestSecurityToken message?
Thank you in advance.
This has been resolved.
Unfortunately, according to the MSDN documentation, a service using WCF transport security cannot go through a router, nor should either, service nor client, be located on the internet (https://msdn.microsoft.com/en-us/library/ff648863.aspx#TransportSecurity).
We wanted to violate both 'principles'.
So in order to cut down the messages, from five calls and responses to one, we switched to Message Security and turned off EstablishSecurityContext and NegotiateServiceCredential. - This had to be done on both the Service and Client configuration settings.
In addition to this, a noteworthy tip may be that, in order to point the service to our service bus, we changed theClientViaBehavior of the service on the Client Side.
Turn off EstablishContext and NegotiateServiceCredential:
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = false;
Point client to Service Bus:
serviceClient.Endpoint.EndpointBehaviors.Add(new ClientViaBehavior(new Uri("http://url/WCFService/ServiceName.svc")));
I have encountered some troubles connecting some different machines of mine to a dedicated Windows service that runs WCF (a listener).
Those machines have an external modem connected to them, which probably disturb TCP connection to the outside, but the machines should establish a connection via WCF with the aforementioned listener service.
Since all the connection I need is inside my network (different machines tough), and it seems that Windows Sharing (copying files, etc') does work, (assuming I am not mistaking and it uses the SMB protocol), I would prefer, if possible, to use that protocol, or other protocols that don't run over TCP, to have a working connection.
I could not find on MSDN any help, but maybe someone has tried something like that before, or has encountered similar problems, and can help me with a solution to that.
Some code (pretty generic I guess):
private const string ServiceEndointURL = "net.tcp://localhost:6789/MyService";
used under: [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = true)]
public class MyApplication : IService
where IService is defined:
[ServiceContract(Name = "MyService")]
public interface IService
{
[OperationContract]
bool HandleMessage(Message message);
}
Other side ("client"):
string ListenerURL = "net.tcp://xx.xx.xx.xx:6789/MyService";
ChannelFactory<IService> factory = new ChannelFactory<IService>
(new MyNetBindings(), ListenerURL );
IService channel = l_oFactory.CreateChannel();
((IContextChannel)channel).OperationTimeout = new TimeSpan(0, 1, 1);
EDIT:
It seems that the external modem is taking the place of the default gateway on that machine, which is probably the cause for no connection.
When manually adding a persistent route, with the original gateway (with low metrics) - it seems to be working again. Any way to automatically work around it?
Thanks in advance!
So... SMB is not a transport protocol. SMB itself mostly uses TCP, but it can also run on UDP. If you want to use WCF over UDP you can (more info here), but i doubt that will work better for you.
My guess is that you have a specific problem with WCF or your network, and you should try to fix that instead.
I am just getting started with WCF and would like to set up a distributable networked system as follows: (but am not sure if it is possible.)
I have a .net client that has business logic. It will need various data from various sources so I would like to add a 'server' that contains an in-memory cache but also WCF capabilities to send/receive and publish/subscribe from data sources for data that is not cached. I think it should be possible for these server applications to be identical in terms of code, but highly configurable so that requests could be dealt with in a peer to peer fashion, or traditional client-server as required. I think it could be done so that essentially a server sends a request to wherever it has the endpoint configured and gets a response.
Essentially a server would be configured as below:
Server A
========
Operation 1 - Endpoint I
Operation 2 - Endpoint II
Server B
========
Operation 1 - Endpoint IV
Operation 2 - Endpoint III
The configuration would be stored for each server in app.config and loaded into memory at startup. So each WCF operation would have its own WCF config (in terms of endpoints etc.) and it would send particular requests to different places according to that configuration.
From what I have read of WCF I think this is possible. I don't know have enough experience to know if this is a standard WCF pattern that I am describing (if so please let me know). Otherwise, my main question is, how do I programatically configure each operation (as above) in WCF?
Please let me know if I have not explained myself clearly.
Thanks in advance for any help,
Will
I don't know if this exactly will get you what you are looking for, but I this is what I use to add my WCF endpoints to my Windows Service. This is the code that the service runs to load all the wcf services:
IDictionary<string, ServiceHost> hosts;
NetTcpBinding binding;
CustomBinding mexBinding;
private void AddService(Type serviceImp, Type serviceDef, string serviceName)
{
ServiceHost host = new ServiceHost(serviceImp);
string address = String.Format(baseAddress, wcfPort, serviceName);
string endAdd = address;
string mexAdd = address + "/mex";
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(behavior);
host.AddServiceEndpoint(serviceDef, binding, endAdd);
host.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, mexAdd);
host.Open();
hosts.Add(serviceDef.Name, host);
}
There's a baseAddress string that I didn't copy in, but it just has the net.tcp address for the endpoint. Likewise for the wcfPort. Different baseAddresses and ports are used for debug, testing and production.
Just in case it isn't clear, serviceImp is the service implementation and serviceDef is the interface that defines the contract. Hope this helps.
EDIT - Here are some references I used to help me figure all of this stuff out:
Creating WCF Service Host Programmatically
Net.Tcp Port Sharing Sample, Part 2
Service Station: WCF Addressing In Depth
As far as I know you can't specify configuration on per operation basis. The lowest level is the interface level. The simplest (ugly) solution would be to put each operation in a separate interface.
Putting each operation in a separate interface is a valid and good design approach. Agatha Request/Response Layer follows this approach. Have a look at this and this is pretty useful and extensible
http://code.google.com/p/agatha-rrsl/