none
Can set parameter to new value via IParameterInspector.BeforeCall, so why can’t I also set return value via AfterCall?

    Question

  • Hi

    I’ve implemented operation behavior attribute, which applies IParameterInspector implementation to any operation marked with this attribute. But while I’m able to inspect and change the value of operation’s parameter via BeginCall(), I’m not able to change the return value of an operation via AfterCall:

    public void AfterCall(string operationName, Object[] outputs, Object returnValue, Object correlationState)
    {
      returnValue = "AfterCall inspector ";     
    }
    
    

    Client should receive as a return value a string “AfterCall inspector” , but instead it receives original value returned by an operation. I also tried assigning value to outputs[0], but with no luck. So any ideas how I can change the return value of an operation within AfterCall?

    Thank you

    Wednesday, February 23, 2011 5:52 PM

Answers

  • Unfortunately you can't. IParameterInspector.AfterCall will allow you to change any ref/out parameters of your operation (since they're passed by reference via the array), but the return value is passed "by value", so you can't change it. If you can change your operation to use an out parameter instead of a return value, it may work:

      public class Post_2d18fcd4_1b0e_4b8d_b479_924ba580721
      {
        [ServiceContract]
        public interface ITest
        {
          [OperationContract]
          [MyParamInspector]
          int Add(int x, int y);
          [OperationContract]
          [MyParamInspector]
          void AddWithOut(int x, int y, out int result);
        }
        public class Service : ITest
        {
          public int Add(int x, int y)
          {
            return x + y;
          }
    
          public void AddWithOut(int x, int y, out int result)
          {
            result = x + y;
          }
        }
        public class MyParamInspectorAttribute : Attribute, IOperationBehavior, IParameterInspector
        {
          public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
          {
          }
    
          public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
          {
            clientOperation.ParameterInspectors.Add(this);
          }
    
          public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
          {
          }
    
          public void Validate(OperationDescription operationDescription)
          {
          }
    
          public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
          {
            Console.WriteLine("Operation {0}, return={1}, outputs.Length={2}", operationName, returnValue, outputs.Length);
            for (int i = 0; i < outputs.Length; i++)
            {
              if (outputs[i] is int)
              {
                outputs[i] = 100 + (int)outputs[i];
              }
            }
          }
    
          public object BeforeCall(string operationName, object[] inputs)
          {
            return null;
          }
        }
    
        public static void Test()
        {
          string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
          ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
          host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
          host.Open();
          Console.WriteLine("Host opened");
    
          ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
          ITest proxy = factory.CreateChannel();
    
          Console.WriteLine(proxy.Add(3, 5));
          int result;
          proxy.AddWithOut(3, 5, out result);
          Console.WriteLine(result);
    
          ((IClientChannel)proxy).Close();
          factory.Close();
    
          Console.Write("Press ENTER to close the host");
          Console.ReadLine();
          host.Close();
        }
      }
    
    
    • Marked as answer by KlemS100 Wednesday, February 23, 2011 9:06 PM
    Wednesday, February 23, 2011 8:22 PM

All replies

  • Unfortunately you can't. IParameterInspector.AfterCall will allow you to change any ref/out parameters of your operation (since they're passed by reference via the array), but the return value is passed "by value", so you can't change it. If you can change your operation to use an out parameter instead of a return value, it may work:

      public class Post_2d18fcd4_1b0e_4b8d_b479_924ba580721
      {
        [ServiceContract]
        public interface ITest
        {
          [OperationContract]
          [MyParamInspector]
          int Add(int x, int y);
          [OperationContract]
          [MyParamInspector]
          void AddWithOut(int x, int y, out int result);
        }
        public class Service : ITest
        {
          public int Add(int x, int y)
          {
            return x + y;
          }
    
          public void AddWithOut(int x, int y, out int result)
          {
            result = x + y;
          }
        }
        public class MyParamInspectorAttribute : Attribute, IOperationBehavior, IParameterInspector
        {
          public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
          {
          }
    
          public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
          {
            clientOperation.ParameterInspectors.Add(this);
          }
    
          public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
          {
          }
    
          public void Validate(OperationDescription operationDescription)
          {
          }
    
          public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
          {
            Console.WriteLine("Operation {0}, return={1}, outputs.Length={2}", operationName, returnValue, outputs.Length);
            for (int i = 0; i < outputs.Length; i++)
            {
              if (outputs[i] is int)
              {
                outputs[i] = 100 + (int)outputs[i];
              }
            }
          }
    
          public object BeforeCall(string operationName, object[] inputs)
          {
            return null;
          }
        }
    
        public static void Test()
        {
          string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
          ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
          host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
          host.Open();
          Console.WriteLine("Host opened");
    
          ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
          ITest proxy = factory.CreateChannel();
    
          Console.WriteLine(proxy.Add(3, 5));
          int result;
          proxy.AddWithOut(3, 5, out result);
          Console.WriteLine(result);
    
          ((IClientChannel)proxy).Close();
          factory.Close();
    
          Console.Write("Press ENTER to close the host");
          Console.ReadLine();
          host.Close();
        }
      }
    
    
    • Marked as answer by KlemS100 Wednesday, February 23, 2011 9:06 PM
    Wednesday, February 23, 2011 8:22 PM
  • much appreciated
    Wednesday, February 23, 2011 9:05 PM