Álvaro García
Álvaro García

Reputation: 19356

OperationContext is null in async methods

I have this service:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
    public class CalculadoraService : ICalculadoraService
    {
        public int Add(int num1, int num2)
        {
            if(OperationContext.Current == null)
            {
                return -2;
            }
            else if(OperationContext.Current.SessionId == null)
            {
                return -1;
            }

            return num1 + num2;
        }



        public async Task<int> AddAsync(int num1, int num2)
        {
            return await Task<int>.Run(() =>
            {
                if (OperationContext.Current == null)
                {
                    return -2;
                }
                else if (OperationContext.Current.SessionId == null)
                {
                    return -1;
                }

                return num1 + num2;
            });
        }
    }

And this is the app config file:

<system.serviceModel>
    <services>
      <service name="WCFCalculadoraService.CalculadoraService">
        <!--El endpoint correspondiente al contrato de la calculadora. ¿Se puede tener más para otros contratos y aplicaciones?-->
        <!--<endpoint address="" binding="basicHttpBinding" contract="WCFCalculadoraService.ICalculadoraService">-->
        <endpoint address="" binding="netHttpBinding" contract="WCFCalculadoraService.ICalculadoraService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <!--Esto sirve para poder intercambiar información-->
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8733/Design_Time_Addresses/WCFCalculadoraService/Service1/" />
          </baseAddresses>
        </host>
      </service>
    </services>


    <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="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

This is my proxy to consume the service from my client:

public class WCFCalculadoraServiceProxy : ClientBase<ICalculadoraService>
    {
        public int Add(int num1, int num2)
        {
            //Lo que hace es llamar al método del servicio.
            return base.Channel.Add(num1, num2);
        }

        public async Task<int> AddAsync(int num1, int num2)
        {
            //Lo que hace es llamar al método del servicio.
            return await base.Channel.AddAsync(num1, num2);
        }
    }

When I call the Add method, I get -1 as result, because OperationContext.SessionID is null. if I call to AddAsync then I get -2 because OperationContext is null.

I would like to know how can I get the SessionID in both cases, sync and async methods, because I would like to store the SessionID into an static variable.

Thanks so much.

Upvotes: 1

Views: 1375

Answers (2)

Dalibor Čarapić
Dalibor Čarapić

Reputation: 3122

For the OperationContext.Current.SessionOd not to be null you must configure your service interface to require session by using [ServiceContract(SessionMode=SessionMode.Required)] attribute on the interface definition.

OperationContext.Current is thread local which means that it is bound to the thread created by WCF. It will not be available to the thread-pool thread used by Task.Run. But it is pretty easy to store the session id to a variable before calling Task.Run:

public async Task<int> AddAsync(int num1, int num2)
{
    var context = OperationContext.Current
    var sessionId = OperationContext.Current.SessionId;
    return await Task<int>.Run(() =>
    {
        if (context == null)
        {
            return -2;
        }
        else if (sessionId == null)
        {
            return -1;
        }

        return num1 + num2;
    });
}

Upvotes: 2

Maximus
Maximus

Reputation: 3448

Firstly, there is no need to write async equivalents since VS can do it instead. All you need to do is Add Service reference -> Advanced -> Allow generation of asynchronous operations

Secondly, if OperationContext.Current.SessionId equals null that indicates that no session is supported. You may not have SessionMode set to either Allowed or Required.

Last but not least, if you do not have client's proxy class generated automatically then derive from either ClientBase or DuplexClientBase and then derive from T as well so that you have methods correctly defined.

Upvotes: 0

Related Questions