I've got an assembly containing several WCF services, each with its own contract. It all works nicely. The service config in the app.config for the service looks like this:
<services>
<service behaviorConfiguration="WcfService.AlyzaServiceBehavior"
name="Sam.Alyza.WcfService.ServiceWebsites">
<endpoint address="" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceWebsites">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/Websites/" />
</baseAddresses>
</host>
</service>
<service behaviorConfiguration="Sam.Alyza.WcfService.LogReaderServiceBehavior"
name="Sam.Alyza.WcfService.ServiceLogReader">
<endpoint address="" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceLogReader">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/LogReader/" />
</baseAddresses>
</host>
</service>
<service behaviorConfiguration="Sam.Alyza.WcfService.ServiceSystemverwaltungBehavior"
name="Sam.Alyza.WcfService.ServiceSystemverwaltung">
<endpoint address="" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceSystemverwaltung">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/Systemverwaltung/" />
</baseAddresses>
</host>
</service>
[...]
</services>
Since I've got a bigger project in mind, with more contracts, I'd like to have a way to share the BaseAddress between the different service contracts.
If this would just be one service with different contracts and endpoints, I could set a ommon baseaddress, but how do I set a common baseaddress for more than one service?
Of course I'd need something similar for the client.
You can combine all contracts in one class, so you have one service with a baseaddress and one (or more) endpoint(s) per contract.
To avoid having one large class-file you can use the partial-keyword (asuming you use c#) to split the class across multiple files. Each file can implement one contract, that makes maintaining the individual interfaces much easier.
In C++ you can use #includes or multiple inheritance, but that imply a large amount of discipline...
Your config would look like this:
<services>
<service behaviorConfiguration="WcfService.AlyzaServiceBehavior"
name="Sam.Alyza.WcfService.ServiceAll">
<endpoint address="Websites/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceWebsites">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="LogReader/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceLogReader">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="Systemverwaltung/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceSystemverwaltung">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/" />
</baseAddresses>
</host>
</service>
</services>
Services can share BaseAddress values (including port #'s, if the Net.Tcp Port Sharing Service is running). It's the endpoint addresses that must be unique. Notice in your config file that the MEX endpoints for each ServiceHost have an address of "mex". Your other endpoints have an address of empty string. When you provide a relative address for an endpoint to WCF (in the config file at least), the base address is prepended to it. Therefore, the MEX endpoint address for the LogReader service is "net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/LogReader/mex".
Since a relative address was not set on the main service endpoint, the base address of the ServiceHost is used as the actual address for the main service endpoint. Because no two endpoints can have overlapping Uri.AbsolutePath values, your example would lead you to believe that base address values cannot be shared. The ServiceHost class that hosts WCF services does not have a built-in endpoint, whereas the ServiceEndpoint class has a ListenUri property that will be populated based on the settings you provide.
If you change the baseAddress values in your example to all match, as long as you set unique relative address values on the Endpoint elements, everything should work. However, it appears that you may run into some challenges with the MEX endpoints, since they all have the address "mex" currently. Make those unique and you should be fine.
Now, I must ask, are you sure that you are not simply wanting these services to share a namespace, rather than base addresses?
You can also set the base addresses in code if you use a custom ServiceHostFactory.
In config you can have some app setting:
<configuration>
<appSettings>
<add key="BaseAddress" value="http://localhost:1234" />
</appSettings>
<configuration>
Then make a custom ServiceHostFactory:
public sealed class MyServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var baseAddy = ConfigurationManager.AppSettings["BaseAddress"];
baseAddresses.Add(new Uri(baseAddy));
return new ServiceHost(serviceType, baseAddresses);
}
}
Then you also have to change your .svc files to use that factory:
<%# ServiceHost Language="C#" Debug="true" Service="MyApp.MyService" CodeBehind="MyService.svc.cs" Factory="MyApp.MyServiceHostFactory" %>
Related
I want to expose two contracts in my server. The app config file of the service is:
<services>
<service name="Interface1Service">
<endpoint address="" binding ="customBinding" contract="Interface1"
bindingName="binding_Interface1" bindingConfiguration="CustomBinding_Interface1" name="epInterface1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Interface1/" />
</baseAddresses>
</host>
</service>
<service name="Interface2Service">
<endpoint address="" binding ="customBinding" contract="Interface2"
bindingName="binding_Interface2" bindingConfiguration="CustomBinding_Interface1"
name="epInterface2Service">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Interface2/" />
</baseAddresses>
</host>
</service>
</services>
And in my console application to host the service I have:
ServiceHost miHost = new ServiceHost(typeof(Interface1Service));
miHost.Open();
ServiceHost miHost2 = new ServiceHost(typeof(Interface2Service));
miHost2.Open();
Console.ReadKey();
miHost.Close();
miHost2.Close();
My doubt if this is the correct way to expose the two services or there is any way to use only one serviceHost to do that.
Because I have seen that is very common to have many contracts for related operations, such as one interface for modify product, other to modify persons, other for orders... etc.
Thank you so much.
..is any way to use only one serviceHost to do that?
It is certainly possible to expose multiple service contracts in a single hosting container. You simply need to create a class which implements all the service interfaces:
public class MyService : Interface1, Interface2
{
// implement your operations here...
}
// then create service host:
var miHost = new ServiceHost(typeof(MyService));
My doubt if this is the correct way to expose the two services..
Even though WCF lets you do this, whether you should do this is another question.
If the operations exposed by the services were deemed different enough that they were placed into separate service contracts, then this is a clear signal that these are in fact different services, and should therefore be treated as such.
Having a common concrete implementation for all these different services introduces coupling and should probably not be done.
suppose my wcf has many end point with different binding.so when user / client add service ref from VS IDE at then multiple endpoint related data expose & added in client config file at client side.
Can we design service in such a way as a result only one endpoint related address will be revealed at client side?
Suppose I have one service with HTTP & TCP related endpoint and I want when external customer will add our service from their VS IDE then they will see our HTTP endpoint address not TCP. So guide me how could I do this? How to design service end config file for my requirement?
here i am attaching a small sample code for multiple endpoint related in config file.
<services>
<service behaviorConfiguration="MulContractService" name="MyWCFLibrary.MultipleContract">
<clear />
<endpoint binding="basicHttpBinding" bindingConfiguration="MulContractBasicBinding"
name="MulContractBasicEndPoint" contract="MyWCFLibrary.IMultipleContract"
listenUriMode="Explicit">
<identity>
<dns value="localhost" />
<certificateReference storeName="My" storeLocation="LocalMachine"
x509FindType="FindBySubjectDistinguishedName" />
</identity>
</endpoint>
<endpoint address="test1" binding="wsHttpBinding" bindingConfiguration="MulContractWsHttpBinding"
name="MulContractWsHttp" contract="MyWCFLibrary.IByeWorld"
listenUriMode="Explicit">
<identity>
<dns value="localhost" />
<certificateReference storeName="My" storeLocation="LocalMachine"
x509FindType="FindBySubjectDistinguishedName" />
</identity>
</endpoint>
<endpoint address="test1" binding="wsHttpBinding" bindingConfiguration="MulContractWsHttpBinding"
name="MulContractWsHttp" contract="MyWCFLibrary.IHelloWorld"
listenUriMode="Explicit">
<identity>
<dns value="localhost" />
<certificateReference storeName="My" storeLocation="LocalMachine"
x509FindType="FindBySubjectDistinguishedName" />
</identity>
</endpoint>
<endpoint address="net.tcp://localhost:8733/Design_Time_Addresses/MyWCFLibrary/MultipleContract/"
binding="netTcpBinding" bindingConfiguration="MulContractTCPBinding"
name="MulContractTCPEndPoint" contract="MyWCFLibrary.IMultipleContract" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/MyWCFLibrary/MultipleContract/" />
</baseAddresses>
</host>
</service>
</services>
EDIT
here i am giving my new full code and just guide me does it work?
namespace CustomService
{
[ServiceContract]
public interface IEmp
{
[OperationContract]
string GetEmp();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class BusinessLayer : IEmp
{
public BusinessLayer()
{
}
public string GetEmp()
{
return "Casino";
}
}
}
Config code at service end
<services>
<service name="CustomService.BusinessLayer">
<endpoint address="CustomerFactory" binding="basicHttpBinding"
bindingConfiguration="HTTPBindingConfig" name="CustomerFactoryHTTP"
contract="CustomService.IEmp" listenUriMode="Explicit" />
</service>
<service name="CustomService.BusinessLayer">
<endpoint binding="basicHttpBinding" bindingConfiguration="HTTPBindingConfig"
name="CustomerMasterHTTP2" bindingName="CustomerMaster" contract="CustomService.IEmp" />
</service>
</services>
just tell me the above config will work?
in the above config i define two service tag with same name because my service full name with namespace is CustomService.BusinessLayer
is it ok or do i need to give unique name for each service tag?
my intention is i will have same service but with multiple service tag and when customer will add my service ref at their end then they will not be able to see all the endpoint.
my intention is not expose all endpoint & address to every client.
so guide me what i have done does it work or not....if not then rectify my config entry and tell me how could i restrict my endpoint not to expose each binding & address before all client. thanks
Maybe not what you are looking for but you could easily add another service to your project and give it the endpoints you want your client to see. Then the existing service could be just for TCP or for both types. Under the covers of course both services would run the same code.
Adding a service is just like adding any other file, right click, add New Item, WCF service. Then you can use the WCF configuration Editor to configure it if you dont want to do it by hand.
For what it is worth here is a config with two services. You can see that the first service has two endpoints, an Http and a TCP while the second service exposes just the http endpoint. Your two services would then each implement IService and would delegate to a common class or library.
<services>
<service name="Mynamespace.Service1">
<endpoint binding="basicHttpBinding"
bindingConfiguration="HTTPBindingConfig" name="MyserviceHTTP"
contract="Mynamespace.IService" listenUriMode="Explicit">
</endpoint>
<endpoint binding="netTcpBinding"
bindingConfiguration="TCPSecured" name="MyserviceHTTP"
contract="Mynamespace.IService" />
</service>
<service name="Mynamespace.Service2">
<endpoint binding="basicHttpBinding"
bindingConfiguration="HTTPBindingConfig" name="MyserviceHTTP"
contract="Mynamespace.IService" listenUriMode="Explicit">
</endpoint>
</service>
</services>
I have 3 service contract interfaces in my WCF library like this:
public interface ServiceContract1{}
public interface ServiceContract2{}
public interface ServiceContract3 : ServiceContract1, ServiceContract2 {}
Also I have a service which implements ServiceContract3. I can have different endpoints by setting different contracts for each like this:
<endpoint address="net.tcp://localhost:5556/ServiceContract1"
binding="netTcpBinding" name="netTcpBinding1"
contract="WcfServiceLibrary.IServiceContract1">
<endpoint address="net.tcp://localhost:5556/ServiceContract2"
binding="netTcpBinding" name="netTcpBinding2"
contract="WcfServiceLibrary.IServiceContract2">
These endpoints seem to work very well but there is only one mexHttpBinding endpoint automatically generated. Thus, although a client needs to use one of the endpoints, it will have whole classes after adding Service Reference.
Can i have different mexHttpBinding endpoints for different contracts? Is there any approach can i follow? Thanks for your help.
Edit #1: ServiceModel configuration
<system.serviceModel>
<services>
<service name="WcfServiceLibrary.Service">
<endpoint address="net.tcp://localhost:5556/Service1"
binding="netTcpBinding" name="netTcpBinding"
contract="WcfServiceLibrary.IServiceContract1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="net.tcp://localhost:5556/Service2"
binding="netTcpBinding" name="netTcpBinding"
contract="WcfServiceLibrary.IServiceContract2">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding"
name="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:5555/ConsoleHost" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
I have only one service hosted in my console application:
ServiceHost host = new ServiceHost(typeof(WcfServiceLibrary.Service));
host.Faulted += new EventHandler(Host_Faulted);
// Start listening for messages
host.Open();
First off I'll apologise as this is probably a duplicate but everything I read seems to be either incomplete or confusing as I'm very new to WCF.
I basically am looking to deploy a WCF service in IIS with 2 endpoints accessible and have been going around in circles all day :(
I have a service library WCF dll with the following structure
App.config
TestSvc1.cs
ITestSvc1.cs
TestSvc2.cs
ITestSvc2.cs
This works fine in the VS WCF test client and now im deploying to IIS so I created a WCF Service Application and referenced the dll. This project has the following structure
Service1.svc
Web.config
Service1.svc contains this
<%# ServiceHost Language="C#" Debug="true"
Service="WCFServices.TestServices.ITestSvc1" CodeBehind="Service1.svc.cs" %>
and my web.config has the following
<services>
<service name="WCFServices.TestServices.TestSvc2">
<endpoint
address=""
binding="wsHttpBinding" bindingConfiguration="LargeSizeMessages"
contract="WCFServices.TestServices.ITestSvc2">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/wcf2/TestServices/TestSvc2/" />
</baseAddresses>
</host>
</service>
<service name="WCFServices.TestServices.TestSvc1">
<endpoint
address=""
binding="wsHttpBinding" bindingConfiguration="LargeSizeMessages"
contract="WCFServices.TestServices.ITestSvc1"
listenUri="http://localhost:8080/wcf2/service1.svc">
<identity>
<dns value="" />
</identity>
</endpoint>
<endpoint
address=""
binding="wsHttpBinding" bindingConfiguration="LargeSizeMessages"
contract="WCFServices.TestServices.ITestSvc2"
listenUri="http://localhost:8080/wcf2/service1.svc">
<identity>
<dns value="" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/wcf2/TestServices/TestSvc1/" />
</baseAddresses>
</host>
</service>
</services>
Any help would be greatly appreciated. As you can see I've tried to add an additional endpoint in the web.config but this doesn't work, I get an error saying that TestSvc2 calls can't be found in TestSvc1 which I guess relates to the entry in Service1.svc
I also read about creating a class that inherits these interfaces but I am not sure exactly how to implement it based on what I have above. Do I need to modify the Service1.svc?
public interface MultipleSvc : ITestSvc1, ITestSvc2
{
// What exactly do I put here? I have no idea, do I leave it blank? This didn't work for me
}
Any help would be greatly appreciated guys thanks :)
Golden rule: one .svc = one service (or more specifically: one service implementation class)
So if you do have two separate, distinct services (in classes WCFServices.TestServices.TestSvc1 and WCFServices.TestServices.TestSvc2), then you need two .svc files (one each, for each service)
What you could do is have one service implementation class that implements both service contracts:
public class MultipleServices : ITestSvc1, ITestSvc2
{
// implement the service logic here, for both contracts
}
In that case, one svc file will be enough (the .svc file is per implementation class and can host multiple service contracts). But then you'd need to change your config, too - since you really only have one service class (therefore: one <service> tag) and multiple contracts hosted inside it:
<services>
<service name="WCFServices.TestServices.MultipleServices">
<endpoint
address="Service1"
binding="wsHttpBinding" bindingConfiguration="LargeSizeMessages"
contract="WCFServices.TestServices.ITestSvc1">
<identity>
<dns value="" />
</identity>
</endpoint>
<endpoint
address="Service2"
binding="wsHttpBinding" bindingConfiguration="LargeSizeMessages"
contract="WCFServices.TestServices.ITestSvc2">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
Also: since you seem to be hosting your WCF service in IIS, there's no point in defining any <baseAddress> values - the "base" address of your service is the location (URI) where the *.svc file lives.
You do'nt need two svc file. Choose ServiceReference1.Service1Client or ServiceReference1.Service2Client.
I have a custom username-password WCF service that needs to be called by Windows client (Winforms application) as well as by Web client (html/aspx page). I have two endpoints declarations in web.config but, to make it work, I have to comment one of them and so, only the client type, associated with that un-commented endpoint, can access the service. If I un-commment that, and comment the other one, other client can access it. I can't keep both of them and so I can't access it with both types of clients.
<service behaviorConfiguration="Behavior1" name="BeST.Service.Service">
<endpoint address="" binding="webHttpBinding" contract="BeST.Service.IService" behaviorConfiguration="EndpBehavior"></endpoint>
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1"
contract="BeST.Service.IService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/" />
</baseAddresses>
</host>
</service>
just as the code shows, I need to use both endpoints (above two endpoints) if I want to make this service work for both clients OR, if there's another way to have it done, please help!
The problem is that you are giving the same address to both endpoints. Try to give another relative address to one of your endpoints and it should work.
<service behaviorConfiguration="Behavior1" name="BeST.Service.Service">
<endpoint address="web" binding="webHttpBinding" contract="BeST.Service.IService" behaviorConfiguration="EndpBehavior"></endpoint>
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1"
contract="BeST.Service.IService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/" />
</baseAddresses>
</host>
</service>