1

We currently have multiple WCF services which are using the default ServiceBehavior. Due to issues with scalability, we are looking at applying the ConcurrencyMode = ConcurrencyMode.Multiple attribute to improve throughput. All of our service calls are completely stateless, for example:

PersonService.cs:

public class PersonService : IPersonService
{
  public GetPersonResponse GetPerson(GetPersonRequest request)
  {
    GetPersonResponse response = new GetPersonResponse();

    try
    {
      response.Person = Person.GetPerson(request.PersonID);

      return response;
    }
    catch (Exception ex)
    {
      return (GetPersonResponse) response.SetException(ex);
    }
  }
}

Person.cs:

public static class Person
{
  public static PersonDataContract GetPerson(int personID)
  {
    PersonDataContract pdc = null;

    // load contract from db...
    pdc = Database.Load<PersonDataContract>(personID);

    // Address is another static class in the same pattern as Person
    pdc.Addresses = Address.GetAddressesForPerson(personID);

    return pdc;
  }
}

All methods in the Person class are static to help performance, and stateless for thread safety. The Database class is also static, but its methods reference static variables.

In this context, what needs to be made thread-safe in order for ConcurrencyMode.Multiple to not cause multithreading issues? I'm thinking only the Database class, but does the Person class (and all other classes that follow the same pattern) need to be locked as well?

I know that all classes should be bulletproofed for maximum safety, but unfortunately time constraints don't allow this... we need to get code delivered ASAP.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138

2 Answers2

3

If your service is stateless and thread safe it is better to use InstanceContextMode.Single combined with ConcurrencyMode.Multiple.

This will avoid the creation of instances of the service, reduce the memory footprint, reduce GC activity.

Almost every service I develop is done in this way....

Unless there was the need to keep separate instances per call or session I would got his way.

Other answers mention "singleton WCF service - but this is highly discouraged, since it's a) a big hindrance for scalability, and b) extremely tricky to program properly."

It is NOT highly discouraged, has no impact on scalability ( as a matter of fact can be benefitial ), and there is NOTHIN tricky about it.

UPDATE: There seems to be confusion about what InstanceContextMode.Single does. This setting will force the WCF engine to create only ONE instance of the service.

Some people have WRONGLY stated it does not work with basicHttpBinding.

So I am posting an example to clear this once and for all.

Here is my Service class:

using System.ServiceModel;

namespace WcfService1
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class Service1 : IService1
    {
        private int _singleCounter = 0;//this field will be shared across all requests
        public Service1() 
        {
            //this executes only ONCE
        }
        public string GetData()
        {
            //this will increment with each request 
            //because it is a SINGLE instance the count
            //will be preserved
            _singleCounter++;
            return string.Format("Requests on this instance: {0}", _singleCounter);
        }
    }
}

Here is my service contract:

using System.ServiceModel;

namespace WcfService1
{    
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData();
    }
}

This is my config file:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

And now some screen shots of the results: This is the first request as you can see the count is 1: enter image description here

Now I click again and you can see the count is 2: enter image description here

A few clicks later: enter image description here

As you can see it is a SINGLE instance keeping a variable across many requests.

Jonathan Alfaro
  • 4,013
  • 3
  • 29
  • 32
  • but InstanceContextMode.Single is not available for stateless WCF (basicHttpBinding) – Alexan Mar 19 '20 at 18:27
  • @Alexan you are wrong.... It is totally available. Please post documentation where it is stated otherwise... You might be confusing sessions with instances. – Jonathan Alfaro Mar 19 '20 at 19:44
  • Same like Per Session this will work with all bindings except basicHttpBinding: https://www.codeproject.com/Articles/443576/Implementing-WCF-Service-Behaviors – Alexan Mar 19 '20 at 19:57
  • Nope that article clearly states that InstanceContextMode.Single does work with basicHttpBinding. You are confused with sessions.. If you use PerSession it will default to PerCall... But if you use Single... a single instance will be created even with basicHttpBinding. I do it all the time. – Jonathan Alfaro Mar 19 '20 at 19:59
  • InstanceContextMode can be PerSession or PerCall or Single. Because basicHttpBinding doesn't have sessions it can be only PerCall. I tried to set it Single on WCF service and tests failed. – Alexan Mar 19 '20 at 20:08
  • maybe you confuse with Concurrency? It can be Single for basicHttpBinding – Alexan Mar 19 '20 at 20:12
  • Nope you are confused... How did "failed" I am running a basic http binding right now with InstanceContextMode to Single and it works as expected it only calls the constructor once. – Jonathan Alfaro Mar 19 '20 at 20:15
  • still don't understand. if Single works with all bindings except basicHttpBinding, then it doesn't work with basicHttpBinding, correct? – Alexan Mar 19 '20 at 20:24
  • also read this https://social.msdn.microsoft.com/Forums/vstudio/en-US/92c3fc85-18d3-4b1e-9c0b-fe00d868d771/instancecontextmodesingle-with-basichttpbinding but still not clear for me – Alexan Mar 19 '20 at 20:31
  • @Alexan Please see my updated answer so that is clear to you. I created a service that keeps a variable at the class level and increments on every request to prove that it is a single instance. So you are wrong. – Jonathan Alfaro Mar 19 '20 at 20:33
  • okay, I asked the same question, maybe you can move your answer there? https://stackoverflow.com/q/60764883/240564 – Alexan Mar 19 '20 at 20:54
3

If you use the default "per call" activation mechanism (which works great if your services are completely stateless), there's absolutely no point in adding the ConcurrencyMode.Multiple since each incoming request will get its own instance of the service class to handle its request. This is the preferred and recommended setting for InstanceContextMode.

Read more about instance management in WCF at MSDN Magazine: Discover Mighty Instance Management Techniques For Developing WCF Apps

The only time when you benefit from using ConcurrencyMode.Multiple is when you have a singleton WCF service - but this is highly discouraged, since it's a) a big hindrance for scalability, and b) extremely tricky to program properly.

My recommendation would be: try to narrow down more in detail what really causes the performance problems. Just jumping into ConcurrencyMode.Multiple seems like the wrong approach - it's very messy, very labor-intensive, lots of code, lots of chance of getting it wrong......

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 2
    Thanks marc - we managed to convince the client that this was going to cause more problems for everyone and after further discussion discovered they didn't actually need all the data returned at once, just thought it would be "useful to have" without considering the implications. We now return a much smaller subset of the data which has nullified the performance issue. – Ian Kemp Jan 12 '11 at 07:08
  • 2
    You say that singleton is "highly discouraged"... By whom? Why? Then you say it is a "hindrance for scalability".... Why? Whats the proof? It is actually better in my opinion..... Then you say "it's very messy, labor intensive, lots of code".... Again says who? What code? What labor? It is much simpler actually. Specially if you are using STATELESS serices. – Jonathan Alfaro Jul 03 '16 at 14:19