There are two problems I ran into last night which I have resolved now, but I am not 100% sure as to why what I have done has resolved them and was hoping maybe someone could offer some insight as I've been turning over a lot of rocks and have had no luck!
First Problem
The first issue is that I had two uniquely named pipes that were in two separate programs:
net.pipe://localhost/superuniquepipe1
net.pipe://localhost/superuniquepipe2
However, the second program to launch would throw an exception (I believe it was AddressAlreadyInUseException) when opening the ServiceHost due to the address already being in use.
The way I was instantiating these ServiceHosts was as follows:
Uri[] baseAddresses = new Uri[] { new Uri("net.pipe://localhost") };
this.host = new ServiceHost(this, baseAddresses);
this.host.AddServiceEndpoint(typeof(IHostType), new NetNamedPipeBinding(), "superuniquepipe1");
this.host.Open();
So I'd specify the base address of localhost first, and then specify the rest of it when adding the endpoint, the way I resolved this was to change the code as follows:
this.host = new ServiceHost(this);
this.host.AddServiceEndpoint(typeof(IHostType), new NetNamedPipeBinding(), "net.pipe://localhost/superuniquepipe2");
this.host.Open();
Am I correct in saying the reason this worked is because it was checking only the base addresses and not the endpoint I was trying to add? And is using the second code sample a valid / safe way to have multiple programs listening on "localhost"?
Second Problem:
In an attempt to fix the above, I had changed the base address from localhost to a number of different unique strings e.g. "net.pipe://rawrwhyisntthisworkingsadface", but when doing this I'd be presented with an InvalidCredentialException from the client trying to establish a connection (see below code)
I was under the impression a named pipe can literally be named anything, can anyone shed some light on this one?
ChannelFactory<IHostType> factory = new ChannelFactory<IHostType>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://rawrwhyisntthisworkingsadface/superuniquepipe2"));
IHostType proxy = factory.CreateChannel();
proxy.CallSomeMethodAndGetAnException();
Any input would be greatly appreciated, as I said I have resolved the issue and just want to know why my solution worked, but if you see a flaw in how I've resolved it and can suggest a better way of doing it please do so :)
Re problem 1:
The WCF NetNamedPipeBinding uses a named shared memory section to publish to its clients the actual name of the pipe over which the service can be called. The pipe name itself is a GUID, generated afresh each time the service host is opened. It is the name of the shared memory section used to publish the service which is dependant on the service URL. If a base address is defined, the base address is used to derive this name.
This means you can only ever have one WCF service application at a time running which uses a particular base address for its NetNamedPipe endpoints. If you try to start a second one, it fails with AddressAlreadyInUseException because it finds that the name WCF wants to use for the publishing location (derived from the base address) has already been taken by another application.
If you specify no base address, and give each service an absolute, unique service URL, then the name of the publishing location is now derived from the full absolute URL, and there is no name clash between the applications. This is an entirely valid and safe way to have multiple WCF named pipe services listening.
Re problem 2:
On the service side you can use anything for the host name part of the service URL. This is due to the HostNameComparisonMode setting applied by default in the NetNamePipeBinding, since the algorithm in WCF which derives the name for the shared memory publishing location substitutes a wildcard character for the host name see here to enable the configured host name comparison mode to be implemented.
On the client side, however, the service URL is constrained: the host part must genuinely resolve to localhost (i.e. it is localhost, the correct IP address, or the correct machine name).
Related
I'm using a DuplexChannelFactory to create a named pipe on net.pipe://localhost/test. However, when I run my program, I get an error: Cannot listen on pipe name "net.pipe://localhost/" because another pipe endpoint is already listening on that name.
So I tried to see whether this was actually the case, by opening a powershell and typing in [System.IO.Directory]::GetFiles("\\.\\pipe\\), but there is no mention of localhost.
I then also tried to change the address net.pipe://localhost/test to net.pipe://anything/test but it still didn't work.
Finally I restarted the computer and it worked. But restarting the computer is not optimal, and I restarted it again earlier today and it broke again.
Could there be any other reason why I would get this error?
WCF Named pipes operate on a different system to regular nameed pipes. When you open a regular named pipe on localhost, you will get a pipe at \.\pipe\localhost, but when you open a WCF pipe you will get \.\pipe\some-guid-xxxx-xxxx. This generated GUID is consistent for WCF named pipes of the same name, which is why it works seamlessly. (see Prevent Named Pipes Conflict)
Now, in my code, I wanted to create a named pipe on localhost. It didn't show up in [System.IO.Directory]::GetFiles("\\.\\pipe\\), because WCF uses a UUID.
The workaround I used in the end is to specify the pipe url as net.pipe\localhost\something_specific_to_me and have an additional AddServiceEndpoint(...,"something_else"), so that the final pipe could be connected to via net.pipe\localhost\something_specific_to_me\something_else.
So I am curious about people's solution to solve my problem. I work in different locations on one project and have different IP address (testing phase). Once completed I won't need this as I can throw to an exposed HTTP client endpoint.
My frustration is when I get to a new location and have to go through getting new addresses. Is there a simple pattern, solution to get the IP automatically and apply to my RESTSharp calls. ie
var client = new RestClient("http://192.168.0.0/API/getresult");
I would say this is common, but frustrating when you are showing a client progress but it crashes and need to re-apply corrections.
I have a remote WCF web service that I'm connecting to from my application.
The application may be running on a server with multiple IP addresses (or multiple physical network interfaces)
I need to make sure that I can control which IP address is being used for the outbound request, instead of just using the 'preferred' interface as per the normal metric rules.
The reason for this is that multiple copies of the software will be running on the same machine, each bound to a specific IP address for its own operations, and the remote service being connected to needs to know which one is being used to connect back to it at a later time (since getting the address wrong means connecting to the wrong service)
With legacy ASMX services this is done by overriding GetWebRequest(Uri uri) on the partial class generated for the service. But I cannot figure out at all how to do this with WCF.
On an unrelated SO post, MVP #JohnSaunders suggested this may be possible by taking over the entire transport mechanism used by WCF. But I've not yet figured out how to do this either.
This is a tricky problem, which WCF doesn't seem to cater for particularly well.
The only component in the .NET framework that seems to directly deal with the issue of the client address is the ServicePoint class. Specifically, it has a BindIPEndPointDelegate property which lets you control how it selects the client IP. The documentation for the property includes this:
Some load balancing techniques require a client to use a specific local IP address and port number, rather than IPAddress.Any (or IPAddress.IPv6Any for Internet Protocol Version 6) and an ephemeral port. Your BindIPEndPointDelegate can satisfy this requirement.
Thus, you should be able to modify the service point associated with your URL in code like this:
var servicePoint = ServicePointManager.FindServicePoint(
new Uri("http://contoso.com/service.svc"));
servicePoint.BindIPEndPointDelegate =
(sp, remote, retryCount) => new IPEndPoint(address, portNumber);
Obviously this kind of code requires your classes have awareness of the protocol and the endpoint address the client will be communicating with. It would likely be most appropriate to set up this logic as a client behaviour which can be applied to your client channel.
you can use a message property (HttpRequestMessageProperty) to add HTTP headers to any outgoing requests. You need to create a "scope" in which the property will be added to the current "operation context", and attach the property, with all headers you want, to the outgoing message properties of the context.
please look at this :
how-to-override-getwebrequest-method-using-service-reference-instead-of-web-reference-in-wcf
Use this:
New Class:
using System.Web.Services.Protocols;
using System.Windows.Forms;
using System;
public static class ExtensionMethods
{
public static string ApplyServerURL(this SoapHttpClientProtocol service)
{
try
{
string name = service.GetType().Name;
return string.Format("{0}{1}.svc", Settings.Instance.ServerAddress, name);
}
catch
{ return string.Empty; }
}
}
And now is something like this:
YourService us = new YourService();
us.Url = us.ApplyServerURL();
In my WCF service, I need to publish it in the Bonjour service. The reason for this is to make the customers that consume my service know which computer it is running.
This works well.
But when I have machines with special characters in HostName, customers of this service can not eat because an error occurs in time to resolve the url.
Example: "http://máchine:8888/service.svc"
One solution would be to use thought to solve here the IP of the machine in place of the hostname. But when the computer works only with IPv6, I can not publish the service because the following error occurs: "Inalid URI: Invalid port specified."
How can I solve this problem without changing the HostName?
In my experience, when mapping zeroconf services to URLs, it's best to not rely on the service's host name. Resolve the service to an IP address (for example, with avahi, using avahi_service_resolver_new) and use the IP address in the URL. This avoids all sorts of problems with fancy hostnames and system resolvers that can't resolve zeroconf names (often the case on embedded systems).
If you got an error like "Inalid URI: Invalid port specified.", it sounds like you might simply have neglected to enclose the IP address in [square brackets]. The pseudocode for forming your URL should be:
if IP address contains ":"
url = "http://[" + ip address + "]:port/whatever"
else
url = "http://" + ip address + ":port/whatever"
There are two additional complications:
If you are using HTTPS, certificate matching will probably fail because the common name on the certificate won't match. It's not clear what to do about this in general because the very nature of an autodiscovered service usually means you can't meaningfully authenticate the server anyway. So you might be able to get away with just turning off certificate verification in your HTTP client.
You might not be able to use IPv6 link local address because there is a deficiency in the standard (RFC) for URL syntax that means it is not possible to attach a % character and an interface name to the address in the URL. Some HTTP clients allow the obvious extension to the standard to support scoped addresses, but others don't (for example, all of the major web browsers don't!).
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/