Run WCF ServiceHost with multiple contracts
Asked Answered
R

8

53

Running a ServiceHost with a single contract is working fine like this:

servicehost = new ServiceHost(typeof(MyService1));
servicehost.AddServiceEndpoint(typeof(IMyService1), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService1");
servicehost.Open();

Now I'd like to add a second (3rd, 4th, ...) contract. My first guess would be to just add more endpoints like this:

servicehost = new ServiceHost(typeof(MyService1));
servicehost.AddServiceEndpoint(typeof(IMyService1), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService1");
servicehost.AddServiceEndpoint(typeof(IMyService2), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService2");
servicehost.Open();

But of course this does not work, since in the creation of ServiceHost I can either pass MyService1 as parameter or MyService2 - so I can add a lot of endpoints to my service, but all have to use the same contract, since I only can provide one implementation?
I got the feeling I'm missing the point, here. Sure there must be some way to provide an implementation for every endpoint-contract I add, or not?

Rotarian answered 2/12, 2008 at 16:4 Comment(0)
S
63

You need to implement both services (interfaces) in the same class.

servicehost = new ServiceHost(typeof(WcfEntryPoint));
servicehost.Open(); 

public class WcfEntryPoint : IMyService1, IMyService2
{
    #region IMyService1
    #endregion

    #region IMyService2
    #endregion
}

FYI: I frequently use partial classes to make my host class code easier to read:

// WcfEntryPoint.IMyService1.cs
public partial class WcfEntryPoint : IMyService1
{
    // IMyService1 methods
}

// WcfEntryPoint.IMyService2.cs
public partial class WcfEntryPoint : IMyService2
{
    // IMyService2 methods
}
Sidnee answered 2/12, 2008 at 16:22 Comment(7)
Dang. I need more than just 2 service contracts, I guess 10-50, and for that number this approach is a bit cumbersome - it is not very helpful to have all that entry points in one single class :( Ain't there no other way?Rotarian
My solution would allow you to break out the contracts into different classes. You could also combine my solution with chill's to have say 5 classes, each with 2 end points. I am very curious though why you need 50 contracts. You should look over Juval's best practices at idesign.net.Diluent
I'll second Chris's comment. It sounds like you need to simplify your design.Sidnee
Uhm, guys, you are both talking about totally different stuff than me. I need 10-50 contracts because I try to reduce the members per contract to 3-5. You are confusing 'contracts' with 'members' I guess.Rotarian
You are talking about having a single service expose up to 250 members over WCF. I would think you should be able to reduce the total count quite a lot if you approach your solution from a different angle.Diluent
One reason why this might be a bad approach is that all possible contracts would have to be known at compile-time.Ingunna
this is just one service with all the methods combined, well in different files/partial classes. It does separate the contracts though, but you still can't have the same method names in both services, e.g. email messaging service and sms - where you have the method "send".Optics
S
17

I'm currently faced with the same problem, and have decided to go with the implementation below. I'm not sure if there are any performance issues with having this many service contracts, but in my final implementation I will probably have about 10 - 15 service contracts, thus about 10-15 ServiceHosts.

I am hosting all my WCF services inside a single Windows Service.

private void PublishWcfEndpoints()
{
    var mappings = new Dictionary<Type, Type>
    {
       {typeof (IAuthenticationService), typeof (AuthenticationService)},
       {typeof(IUserService), typeof(UserService)},
       {typeof(IClientService), typeof(ClientService)}
    };


    foreach (var type in mappings)
    {
        Type contractType = type.Key;
        Type implementationType = type.Value;

        ServiceHost serviceHost = new ServiceHost(implementationType);
        ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(contractType, ServiceHelper.GetDefaultBinding(),
                                                                  Properties.Settings.Default.ServiceUrl  + "/" + contractType.Name);
        endpoint.Behaviors.Add(new ServerSessionBehavior());

        ServiceDebugBehavior serviceDebugBehaviour =
            serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
        serviceDebugBehaviour.IncludeExceptionDetailInFaults = true;

        log.DebugFormat("Published Service endpoint: {0}", Properties.Settings.Default.ServiceUrl);

        serviceHost.Open();
        serviceHosts.Add(serviceHost);
    }

}

Feel free to comment on this type of set up, and if there are any issues with it, especially performance-related.

Sparoid answered 17/8, 2009 at 16:39 Comment(4)
here it goes complicatedSward
Would be even better if you used a dependency injection container to resolve the implementations =)Richia
Best solution allowing services to be isolated and individually attributed,Marelya
@Richia Interesting solution here: Can I automatically host all services in app.config when using SelfHosting?Marelya
D
10

This answer is a further response to the comment in the accepted answer from chilltemp.

Sam, You really should determine why you need 10-50 contracts and try to find another solution. I looked over Juval Lowy's WCF Coding Standards (found on http://www.idesign.net/) and found the following references:

3 Service Contracts

[...]

  1. Avoid contracts with one member.
  2. Strive to have three to five members per service contract.
  3. Do not have more than twenty members per service contract. Twelve is probably the practical limit.

He doesn't mention a limit on contract implementations (that I can find) but I can't imagine him viewing 50 contracts on a service as anything resembling a best practice. One solution I have found that works well is to use member sharing for similar functions.

For instance, if you are using the WCF service to perform mathematics on 2 values you might have 4 members on the service side: Add(x,y), Subtract(x,y), Multiply(x,y), Divide(x,y). If you combine these into a more generic member and use an object to pass the needed data you can easily reduce your member count and increase scalability. Example: PeformCalculation(obj) where obj has x, y, and action (add, subtract, multiply, divide) properties.

Hope this helps.

Diluent answered 3/12, 2008 at 17:37 Comment(2)
Juval is talking about 3-5 members on a contract. I'm talking about 10-50 contracts to a service (each contract containing 3-5 members). Maybe thats creating the confusion?Rotarian
Its not confusion, he doesn't mention a limit on contracts but I would not want to go down the road of having 50 contracts on a service. There should be some form of refactoring that could be done on your contracts to reduce the size/count of them. Its your app but I would look for other options.Diluent
R
9

I found another solution to for this issue by using a the RoutingService class. Each contract must still be hosted in it's own ServiceHost, but there can be a RoutingService sitting on top of all of them - and presenting them over an unified "endpoint". I've also written a codeproject article about it. The example code is also available on Bitbucket.

Raptorial answered 29/2, 2012 at 23:46 Comment(0)
D
6

chili's answer will work if you are ok with the contracts being shared by the service. If you want them to be separated try this:

host1 = new ServiceHost(typeof(MyService1));
host2 = new ServiceHost(typeof(MyService2));

host1.Open();
host2.Open();

public class MyService1 : IMyService1
{
    #region IMyService1
    #endregion
}

public class MyService2 : IMyService2
{
    #region IMyService2
    #endregion
}

Edit: As Matt posted, this would require multiple endpoints for each service/contract

Diluent answered 2/12, 2008 at 16:44 Comment(1)
This is perfect. It's exactly what I was looking for when I started reading this thread. Initially I thought that this would be impossibly judging from the gist of this thread, but it works fine.Neurologist
N
3

No-one documented enpoints. Whe used more than one (as a group, from common url, for example http) must use the same binding instance (not more), i.e.

Your sample:

servicehost = new ServiceHost(typeof(MyService1));
servicehost.AddServiceEndpoint(typeof(IMyService1), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService1");
servicehost.AddServiceEndpoint(typeof(IMyService2), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService2");
servicehost.Open();

should be only one new Binding(), I tested over http.

servicehost = new ServiceHost(typeof(MyService1));
 BasicHttpBinding binding = new BasicHttpBinding();
servicehost.AddServiceEndpoint(typeof(IMyService1),binding , "http://127.0.0.1:800/MyApp/MyService1");
servicehost.AddServiceEndpoint(typeof(IMyService2), binding, "http://127.0.0.1:800/MyApp/MyService2");
servicehost.Open();

I agree totally with partial class implementing few contracts in few files.

Nattie answered 19/9, 2015 at 8:5 Comment(0)
T
1

What about splitting it up with a base address and multiple services/contracts below it? I am not behind a developmachine right now but something like:

http://myserver/myservices/serviceA
http://myserver/myservices/serviceB
http://myserver/myservices/serviceC

Each service implementing its own ServiceContract.

You can change
public class WcfEntryPoint : IMyService1, IMyService2
to
public partial class WcfEntryPoint : IMyService1
public partial class WcfEntryPoint : IMyService2

Example

Therapsid answered 19/8, 2009 at 9:49 Comment(0)
L
1

Did I miss something, or is the simplest solution not mentioned here? The simplest solution is this: Don't use multiple interfaces for the Web Service.

But that doesn't mean you can still have your interfaces separated. This is why we have Interface inheritance.

[ServiceContract]
public interface IMetaSomeObjectService : ISomeObjectService1, ISomeObjectService2
{
}

The Meta interface inherits from all the other interfaces.

[ServiceContract]
public interface ISomeOjectService1
{
    [OperationContract]
    List<SomeOject> GetSomeObjects();
}

[ServiceContract]
public interface ISomeOjectService2
{
    [OperationContract]
    void DoSomethingElse();
}

Then the service just has the Meta interface.

public class SomeObjectService : IMetaSomeObjectService
{
   public List<SomeOject> GetSomeObjects()
   {
       // code here
   }

   public void DoSomethingElse()
   {
       // code here
   }
}
Lune answered 15/6, 2016 at 16:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.