Home > Software engineering >  WCF single instance of service for VB (COM) client
WCF single instance of service for VB (COM) client

Time:07-26

I created a WCF service, and want to be used by multiple VB clients.

I need only a single instance of the service, even if multiple clients start, use it, or stop.

But the result seems to be against my expectation. My code is:

WCF service:

namespace xComm
{
    [ServiceBehavior(
        InstanceContextMode = InstanceContextMode.Single,
            ConcurrencyMode = ConcurrencyMode.Single)]
    public class SvcACS : ISvcACS
    {
        private int m_nCounter = 0;

        public int CounterUp()
        {
            m_nCounter  ;
            return m_nCounter;
        }
        public int CounterGet()
        {
            return m_nCounter;
        }

    }
}

After building the WCF service, I can use it by COM reference from VB application, as the following one, a simple form application calling CountUp method and checking return value:

Option Explicit

Dim svcAcs As xComm.ISvcACS

Private Sub btnCmd_Click(Index As Integer)
    Dim nW1 As Integer
    
    nW1 = svcAcs.CounterUp()
    lblCounter.Caption = CStr(nW1)
End Sub

Private Sub Form_Load()
    Set svcAcs = New xComm.svcAcs                   
End Sub

I started for example 2 VB clients and press the btnCmd button respectively. What I want is:

  1. client 1's btnCmd is clicked: client 1's lblCount shows 1
  2. client 2's btnCmd is clicked: client 2's lblCount shows 2
  3. client 1's btnCmd is clicked: client 1's lblCount shows 3 ...

But the result turned out that clients are serviced independently, instead of by using a single instance of service, which the counter would have been shared.

I have used InstanceContextMode.Single, is this not enough?

Thanks in advance.

Ting

some new findings(2022/7/26):

Instead of using COM reference directly, I tried the following VB code:

    Dim Client As New MSSOAPLib30.SoapClient30
    
    
    Set Client = CreateObject("MSSOAP.SoapClient30")    'xcomm.svcACS")
    Call Client.mssoapinit("http://localhost:8733/SvcACS?wsdl")
                    'localhost:8733/SvcACS" binding="basicHttpBinding"
    MsgBox (Client.CounterUp())

The result shows that several VB application instances consume a same service instance.

And I also tested C# clients by using SvcUtilexe generated client code, which shows the same result.

But in both the cases, changing InstanceContextMode to PerCall or PerSession makes not difference.

I guess, maybe it is the behavior of self hosting service, in which the active service works for all.

But still I dont understand how COM interface works. Seemingly by using COM interface, each time, a new service instance is created.

CodePudding user response:

This is just a speculation on my part, but the Instancing article notes, that

Single: A single instance of the service class handles all client requests for the lifetime of the application.

(Emphasis mine)

Which to me sounds that because you are using two applications, each creating its own instance of the service, you experience the expected behavior. So I assume you need to persist & restore the return value between calls and share it between the service instances.

CodePudding user response:

You can check the documentation, there are a few things to note:
https://www.c-sharpcorner.com/UploadFile/de41d6/instance-context-mode-in-wcf/

Note: BasicHttpBinding doesn't support sessions. If the binding in a WCF service is set to basichttpbinding then per session mode will not work and the service will be considered to be per call.

https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.instancecontextmode?view=netframework-4.8

The Single value specifies that a single InstanceContext object should be used for the lifetime of the service. Several caveats are associated with the Single value:

  • If the ServiceBehaviorAttribute.InstanceContextMode value is set to Single, your service can only process one message at a time unless you also set the ConcurrencyMode value to ConcurrencyMode.Multiple.
  • For singleton lifetime behavior (for example, if the host application calls the ServiceHost.ServiceHost constructor and passes an object to use as the service), the service class must set ServiceBehaviorAttribute.InstanceContextMode to Single, or an exception is thrown when the service host is opened.
  • Related