WCF Multiple channels for one service instance

2019-07-18 15:51发布

This is my code for server application:

[ServiceContract]
public interface IFirst
{
    [OperationContract]
    void First();
}

[ServiceContract]
public interface ISecond
{
    [OperationContract]
    void Second();
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
class Service : IFirst, ISecond
{
    static int count = 0;
    int serviceID;

    public Service()
    {
        serviceID = ++count;

        Console.WriteLine("Service {0} created.", serviceID);
    }

    public void First()
    {
        Console.WriteLine("First function. ServiceID: {0}", serviceID);
    }

    public void Second()
    {
        Console.WriteLine("Second function. ServiceID: {0}", serviceID);
    }
}

class Server
{
    static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(Service), new Uri("net.tcp://localhost:8000"));
        NetTcpBinding binding = new NetTcpBinding();
        host.AddServiceEndpoint(typeof(IFirst), binding, "");
        host.AddServiceEndpoint(typeof(ISecond), binding, "");
        host.Open();

        Console.WriteLine("Successfully opened port 8000.");
        Console.ReadLine();          
        host.Close();
    }
}

and client:

class Client
{
    static void Main(string[] args)
    {
        ChannelFactory<IFirst> firstFactory = new ChannelFactory<IFirst>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8000"));
        IFirst iForst = firstFactory.CreateChannel();
        iForst.First();

        ChannelFactory<ISecond> secondFactory = new ChannelFactory<ISecond>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8000"));
        ISecond iSecond = secondFactory.CreateChannel();
        iSecond.Second();

        Console.ReadLine();

    }
}

When I run it I get output:

Successfully opened port 8000.
Service 1 created.
First function. ServiceID: 1
Service 2 created.
Second function. ServiceID: 2

In my case server creates two instances of Service. What I want to do is call Second function for the same Service instance that First did.

3条回答
甜甜的少女心
2楼-- · 2019-07-18 16:34

I know the post is old, but for others.

What you can do is combine your IFirst and ISecond into ICombinedService. Then you would create a single channel in your client - meaning a single instance of your service host session would be created.

In your current code you are creating a connection for IFirst, and ISecond [These are the two session instances you created.]

IFirst iForst = firstFactory.CreateChannel(); // First Session Created!

ISecond iSecond = secondFactory.CreateChannel(); // Second Session Created!

To change that behavior you will need to combine the services into one service; and can make per session calls on that.

class Client
{
    static void Main(string[] args)
    {
        ChannelFactory<ICombinedFirstSecond> combinedFactory = new ChannelFactory<ICombinedFirstSecond>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8000"));
        ICombinedFirstSecond iCombinedFirstSecond = combinedFactory.CreateChannel();
        iCombinedFirstSecond.First();
        iCombinedFirstSecond.Second();

        Console.ReadLine();

    }
}

This is what I think you really are looking for and not a singleton service.

查看更多
时光不老,我们不散
3楼-- · 2019-07-18 16:38

Change your behaviour to single

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

As you are using InstanceContextMode.PerSession that means service creates a session for each client as You are trying to connect to service from two clients thats why it is creating two instances of Service

by changing it to InstanceContextMode.Single only one instance of Service will serve both of your clients.

From MSDN

The System.ServiceModel.InstanceContext manages the association between the channel and the user-defined service objects. Use the InstanceContextMode enumeration with the ServiceBehaviorAttribute.InstanceContextMode property to specify the lifetime of the InstanceContext object. can create a new InstanceContext object for every call, every session or specify that the InstanceContext object is bound to a single service object. The Single value specifies that a single InstanceContext object should be used for the lifetime of the service.

查看更多
来,给爷笑一个
4楼-- · 2019-07-18 16:48

You can do two things:

Move Second to IFirst so

public interface IFirst
{
    [OperationContract]
    void First();

    [OperationContract]
    void Second();
}

Or use a Singleton for the service instance

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
class Service : IFirst, ISecond
{
...
}
查看更多
登录 后发表回答