WCF HTTP and NamedPipe service - c#

I'm creating a WCF service which, at the moment, exposing a number of contracts using a basicHttpBinding. However, I now want to use the service locally on the same machine, and a netNamedPipeBinding seems more appropriate in terms of performance. For that reason, I want to expose the service using a named pipe and HTTP.
At the moment I'm doing this with the following configuration:
<service name="WCFService.MyService" behaviorConfiguration="serviceBehaviour">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/MyService" />
<add baseAddress="net.pipe://localhost/MyService" />
</baseAddresses>
</host>
<endpoint address="calculator" binding="basicHttpBinding" contract="WCFService.ICalculatorService" />
<endpoint address="database" binding="basicHttpBinding" contract="WCFService.IDatabaseService" />
</service>
This appears to work fine, but on closer inspection the endpoints are still using the basicHttpBinding. This works, but I get the impression it's creating unnecessary overhead.
Do I need to create an endpoint for each contract, and each binding type (i.e. basicHttpBinding and netNamedPipeBinding) or am I going about this completely wrong?
(If it's not clear, I'm fairly new to WCF!)

Yes, you need to specify multiple endpoints (1 endpoint per binding):
<endpoint address="calculator" binding="basicHttpBinding" contract="WCFService.ICalculatorService" />
<endpoint address="database" binding="basicHttpBinding" contract="WCFService.IDatabaseService" />
<endpoint address="calculator" binding="netNamedPipeBinding" contract="WCFService.ICalculatorService" />
<endpoint address="database" binding="netNamedPipeBinding" contract="WCFService.IDatabaseService" />

Related

Service metadata may not be accessible

I am trying to run my project.I am getting this error "Failed to add a service. Service metadata may not be accessible. Make sure your service is running and exposing metadata".
add this endpoint to your application.config file:
<services>
<service .....>
<endpoint binding="mexHttpBinding" bindingConfiguration="" name="mexService" contract="IMetadataExchange" />
<endpoint ...... the usual endpoints />
</service>
</services>

Construct Solution with Multiple WCF Applications

We currently have a solution with only one WCF application, during the next two years the solution grows a lot.
It's around 70 different services.
We are using Windows Identity Foundation for security for majority, others use SSL and some don't have
I'm looking to restructure the application, I'am thinking about having multiple WCF application (one for business services, and other for backend services, etc...),
I think it can help for a lot for testing.
My question is:
Is there a way to construct a solution with multiple WCF applications without having to create and deploy multiple packages (not very usefull for deployments)
If I restucture the application, I will have 4 or 5 different services projects and also need an app.config file for each(not easy to maintain or upgrade in production environments)
You can have as many service assemblies in a WCF host as you like just make sure they have unique names. Every service dll gets its own project and the host stays at one project in the solution. Then create an app.config like this:
<services>
<service behaviorConfiguration="serviceBehaviour" name="DLSService.DLSService">
<endpoint address="DLSService" binding="basicHttpBinding" bindingConfiguration=""
name="basicHttpDLS" contract="DLSService.IDLSService" />
<endpoint binding="mexHttpBinding" bindingConfiguration="" name="mexDLS"
contract="IMetadataExchange" />
<endpoint address="DLSService" binding="netTcpBinding" bindingConfiguration=""
name="netTcpDLS" contract="DLSService.IDLSService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/ServicesHost/DLSService" />
</baseAddresses>
</host>
</service>
<service behaviorConfiguration="serviceBehaviour" name="RopsPreorderService.RopsPreorderService">
<endpoint address="RopsPreorderService" binding="basicHttpBinding" bindingConfiguration=""
name="basicHttpPreorderService" contract="PreorderService.IPreorderService" />
<endpoint binding="mexHttpBinding" bindingConfiguration="" name="mexRopsPreorderService"
contract="IMetadataExchange" />
<endpoint address="PreorderService" binding="netTcpBinding" bindingConfiguration=""
name="netTcpPreorderService" contract="RopsPreorderService.IPreorderService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/ServicesHost/PreorderService" />
<add baseAddress="net.tcp://localhost:9000/PreorderService" />
</baseAddresses>
</host>
</service>
</services>

Multiple contracts with same bindings..How?

How do I use multiple contracts with the same binding on the same port through C# code?
Would appreciate any simple code snipplet...
Thanks so much
What about this:
public class Service : IServiceContract1, IServiceContract2
{
...
}
Configuration (can be easily rewritten to code if you add Endpoint instances to ServiceHost by calling AddServiceEndpoint)
<services>
<service name="Service">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8888/Service" />
</baseAddresses>
</host>
<endpoint address="first" binding="basicHttpBinding" contract="IServiceContract1" />
<endpoint address="second" binding="basicHttpBinding" contract="IServiceContract2" />
</service>
</services>
I'm afraid there is no "simple code snippet" for this. Use the following article to get started and just add more ServiceHost objects: http://msdn.microsoft.com/en-us/library/ms733069.aspx
If you haven't already, it would be wise to get a book on WCF.

How to disable auto-generated WCF configuration

Every time my program runs vs adds the default configuration to my app.config file. At that run it works fine, but at the next run it actually tries to read the config.
The problem is that the default configuration has errors, it adds the attribute "Address", but attritbutes are not allowed to have capitals so it throws an exception.
This means I have to remove the bad section every run!
I've tried to configure the .config but it gives errors.
Here is the code that I use to host the server:
private static System.Threading.AutoResetEvent stopFlag = new System.Threading.AutoResetEvent(false);
ServiceHost host = new ServiceHost(typeof(Service), new Uri("http://localhost:8000"));
host.AddServiceEndpoint(typeof(IService), new BasicHttpBinding(), "ChessServer");
host.Open();
stopFlag.WaitOne();
host.Close();
Here is the client code that calls the server:
ChannelFactory<IChessServer> scf;
scf = new ChannelFactory<IService>
(new BasicHttpBinding(), "http://localhost:8000");
IService service = scf.CreateChannel();
Thanks for any help.
Edit: Sorry it took me so long, I've been trying to use DualWSHttpBinding instead (since I actually need the server to call client methods to anyway) but still generates the config file. Here's the entire auto-generated config file:
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup><system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Chess.ChessService">
<endpoint Address="" binding="wsHttpBinding" contract="Chess.IChessServer">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint Address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<Add baseAddress="http://localhost:8732/Design_Time_Addresses/Chess/ChessService/" />
</baseAddresses>
</host>
</service>
<service name="Chess.ChessClient">
<endpoint Address="" binding="wsHttpBinding" contract="Chess.IChessClient">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint Address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<Add baseAddress="http://localhost:8732/Design_Time_Addresses/Chess/ChessClient/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
Visual Studio does not re-create the WCF configuration on every run. It will re-create the WCF configuration every time you do an Update Service Reference on your service reference in the project - but it definitely doesn't automatically do that before every run - there must be something else causing you grief here.
Furthermore, you're not connecting to the correct address - your server defines it here:
ServiceHost host = new ServiceHost(..., new Uri("http://localhost:8000"));
host.AddServiceEndpoint(..., .., "ChessServer");
and this results in your endpoint address on the server being
http://localhost:8000/ChessServer
However, you're client appears to attempt to connect to
http://localhost:8000/
and there's no service there.
A last point: if you set up all your things like endpoints, bindings etc. in code, any changes to the config shouldn't even bother you at all - there must be something else causing your problems.
You're quite mistaken. Attribute and element names may be upper or lower case.
What makes you think that the case of the attribute is the problem? And what makes you think that the app.config is changed on every run?

Indexing ServiceEndpointElementCollection

In the following config file excerpt, the WCF service has two endpoints.
<service behaviorConfiguration="AtomTcpHub.Behavior"
name="AtomTcpHub.HubTcp">
<endpoint address="" binding="netTcpBinding"
name="AtomHubEndpoint" contract="AtomLib.IAtomPublisher">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding"
name="" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8731/AtomTcpHub/" />
<add baseAddress="net.tcp://dv-pw/AtomTcpHub/" />
</baseAddresses>
</host>
</service>
In my code there is discovery logic, which responds to a UDP request by replying with the connection Uri for the WCF service. Obtaining a collection of endpoints is straightforward.
System.Configuration.Configuration config = System.Configuration
.ConfigurationManager
.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None);
ServicesSection section = config.SectionGroups["system.serviceModel"]
.Sections["services"] as ServicesSection;
ServiceEndpointElementCollection seec =
section.Services["AtomTcpHub.HubTcp"].Endpoints;
The problem is extracting the ServiceEndpointElement. We can have it by index:
ServiceEndpointElement see = seec[0];
but this is brittle; if the order of nodes changes it will break. Visual Studio tells me there is another indexer permitting an object value, but there is no further indication. Experimentation tells me that it isn't the value of the name attribute.
The following code works, but it's just hideous.
string serviceEndpointUri;
foreach(ServiceEndpointElement serviceEndpointElement in seec)
if (serviceEndpointElement.Name == "AtomHubEndpoint")
{
_serviceEndpointUri = serviceEndpointElement.Address.AbsoluteUri;
break;
}
Is there a more direct or more elegant way to do this?
You could always use some Linq to accomplish this, to simply shorten things a bit.
ServiceEndpointElement element =
seec.OfType<ServiceEndpointElement>()
.FirstOrDefault(s => s.Name == "AtomHubEndpoint");

Categories