none
OperationContext is null in async methods. How can I get the SessionID? RRS feed

  • Question

  • I have this service in WCF 4.5.

    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;
                });
            }
        }

    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 the proxy used by the clients:

    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.

    Tuesday, December 8, 2015 10:51 AM

Answers

  • Hi ComptonAlvaro,

    According to your code and description, I create a project about this case,

    I was modify some code and configuration, then it works fine.

    Here is my web.config file:

    <system.serviceModel>
        <services>
          <service name="WcfService5.Service1">      
            <endpoint address="" binding="wsHttpBinding" contract="WcfService5.IService1">
              <identity>
                <dns value="localhost" />
              </identity>
            </endpoint>              
          </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>
       <protocolMapping>
            <add binding="wsHttpBinding"  scheme="https" />
        </protocolMapping>    
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
     </system.serviceModel> 


    My WCF code where has changed:

    public async Task<int> AddAsync123(int num1, int num2)
            {
                OperationContext ctx = OperationContext.Current;
                await Task.Delay(100);
                if (ctx == null)
                {
                    return -2;
                }
                else if (ctx.SessionId == null)
                {
                    return -1;
                }
                return num1 + num2;                         
            }

    When we used the Task.Run() method, it will create a new thread form thread pool.

    So,  the OperationContext.Current has no content. Because, the OperationContext.Current can’t

    get any OperationContext in new thread.

    If we want to get the OperationContext.Current content,  we need to execute it in main thread.

    In my code, I execute it in main thread, so it works fine.

    My client code:

    static void Main(string[] args)
            {
                ServiceReference1.Service1Client proxy = new ServiceReference1.Service1Client();
                proxy.Open();
                Console.WriteLine("{0}", proxy.Add(1, 2));
                string sessionid = proxy.InnerChannel.SessionId;
                Console.WriteLine("Session ID=" + sessionid);
                proxy.Close();
                ServiceReference1.Service1Client proxy1 = new ServiceReference1.Service1Client();
                proxy1.Open();
                Console.WriteLine("{0}", proxy1.AddAsync123(1, 2));
                string sessionId1 = proxy1.InnerChannel.SessionId;
                Console.WriteLine("sessionId1 ID=" + sessionId1);
                proxy1.Close();         
                Console.ReadLine();
            }  

    The result as shown below:

    I hope that will be helpful to you.

    Best Regards,

    Wanjun Dong


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place. Click HERE to participate the survey.

    • Marked as answer by ComptonAlvaro Thursday, December 10, 2015 12:11 PM
    Thursday, December 10, 2015 8:30 AM
    Moderator

All replies

  • Hi ComptonAlvaro,

    According to your code and description, I create a project about this case,

    I was modify some code and configuration, then it works fine.

    Here is my web.config file:

    <system.serviceModel>
        <services>
          <service name="WcfService5.Service1">      
            <endpoint address="" binding="wsHttpBinding" contract="WcfService5.IService1">
              <identity>
                <dns value="localhost" />
              </identity>
            </endpoint>              
          </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>
       <protocolMapping>
            <add binding="wsHttpBinding"  scheme="https" />
        </protocolMapping>    
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
     </system.serviceModel> 


    My WCF code where has changed:

    public async Task<int> AddAsync123(int num1, int num2)
            {
                OperationContext ctx = OperationContext.Current;
                await Task.Delay(100);
                if (ctx == null)
                {
                    return -2;
                }
                else if (ctx.SessionId == null)
                {
                    return -1;
                }
                return num1 + num2;                         
            }

    When we used the Task.Run() method, it will create a new thread form thread pool.

    So,  the OperationContext.Current has no content. Because, the OperationContext.Current can’t

    get any OperationContext in new thread.

    If we want to get the OperationContext.Current content,  we need to execute it in main thread.

    In my code, I execute it in main thread, so it works fine.

    My client code:

    static void Main(string[] args)
            {
                ServiceReference1.Service1Client proxy = new ServiceReference1.Service1Client();
                proxy.Open();
                Console.WriteLine("{0}", proxy.Add(1, 2));
                string sessionid = proxy.InnerChannel.SessionId;
                Console.WriteLine("Session ID=" + sessionid);
                proxy.Close();
                ServiceReference1.Service1Client proxy1 = new ServiceReference1.Service1Client();
                proxy1.Open();
                Console.WriteLine("{0}", proxy1.AddAsync123(1, 2));
                string sessionId1 = proxy1.InnerChannel.SessionId;
                Console.WriteLine("sessionId1 ID=" + sessionId1);
                proxy1.Close();         
                Console.ReadLine();
            }  

    The result as shown below:

    I hope that will be helpful to you.

    Best Regards,

    Wanjun Dong


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place. Click HERE to participate the survey.

    • Marked as answer by ComptonAlvaro Thursday, December 10, 2015 12:11 PM
    Thursday, December 10, 2015 8:30 AM
    Moderator
  • Thank you so much. Your example help me to understand some things.

    Thursday, December 10, 2015 12:12 PM