Change return type of a function in WCF without changing interface return type












11















I'm working on an old WCF service with many interfaces and services for a new system. I want to change return type of functions without changing all service interfaces and implementations as follow:



interface OperationResult
{
ErrorInfo Error { get; set; }
}
interface OperationResult<TResult> : OperationResult
{
TResult Result { get; set; }
}

// old service
interface IService
{
int TestMethod1(TestMethod1Input input);
void TestMethod2(TestMethod2Input input);
}
// Interface that client should see
interface IService
{
OperationResult<int> TestMethod1(TestMethod1Input input);
OperationResult TestMethod2(TestMethod2Input input);
}


I think I can handle exceptions with IOperationInvoker but I don't know how change return value of actual service, and I wanted to change the return type of the function in the WSDL using IWsdlExportExtension. But I couldn't find any well documentation or sample for either of them.



Can anyone suggest any sample or documentation or any other way that can save me the trouble of changing too many already existing services?



NOTE: I have another way of doing this by creating a custom ServiceHost that create a dynamic wrapper for actual service and pass it as service type to constructor of ServiceHost. But this should be last solution since it will generate many dynamic types.










share|improve this question























  • Is it possible to add a proxy service(between client and server) to change type of returned values of services?!

    – isaeid
    Jan 2 at 9:51
















11















I'm working on an old WCF service with many interfaces and services for a new system. I want to change return type of functions without changing all service interfaces and implementations as follow:



interface OperationResult
{
ErrorInfo Error { get; set; }
}
interface OperationResult<TResult> : OperationResult
{
TResult Result { get; set; }
}

// old service
interface IService
{
int TestMethod1(TestMethod1Input input);
void TestMethod2(TestMethod2Input input);
}
// Interface that client should see
interface IService
{
OperationResult<int> TestMethod1(TestMethod1Input input);
OperationResult TestMethod2(TestMethod2Input input);
}


I think I can handle exceptions with IOperationInvoker but I don't know how change return value of actual service, and I wanted to change the return type of the function in the WSDL using IWsdlExportExtension. But I couldn't find any well documentation or sample for either of them.



Can anyone suggest any sample or documentation or any other way that can save me the trouble of changing too many already existing services?



NOTE: I have another way of doing this by creating a custom ServiceHost that create a dynamic wrapper for actual service and pass it as service type to constructor of ServiceHost. But this should be last solution since it will generate many dynamic types.










share|improve this question























  • Is it possible to add a proxy service(between client and server) to change type of returned values of services?!

    – isaeid
    Jan 2 at 9:51














11












11








11


2






I'm working on an old WCF service with many interfaces and services for a new system. I want to change return type of functions without changing all service interfaces and implementations as follow:



interface OperationResult
{
ErrorInfo Error { get; set; }
}
interface OperationResult<TResult> : OperationResult
{
TResult Result { get; set; }
}

// old service
interface IService
{
int TestMethod1(TestMethod1Input input);
void TestMethod2(TestMethod2Input input);
}
// Interface that client should see
interface IService
{
OperationResult<int> TestMethod1(TestMethod1Input input);
OperationResult TestMethod2(TestMethod2Input input);
}


I think I can handle exceptions with IOperationInvoker but I don't know how change return value of actual service, and I wanted to change the return type of the function in the WSDL using IWsdlExportExtension. But I couldn't find any well documentation or sample for either of them.



Can anyone suggest any sample or documentation or any other way that can save me the trouble of changing too many already existing services?



NOTE: I have another way of doing this by creating a custom ServiceHost that create a dynamic wrapper for actual service and pass it as service type to constructor of ServiceHost. But this should be last solution since it will generate many dynamic types.










share|improve this question














I'm working on an old WCF service with many interfaces and services for a new system. I want to change return type of functions without changing all service interfaces and implementations as follow:



interface OperationResult
{
ErrorInfo Error { get; set; }
}
interface OperationResult<TResult> : OperationResult
{
TResult Result { get; set; }
}

// old service
interface IService
{
int TestMethod1(TestMethod1Input input);
void TestMethod2(TestMethod2Input input);
}
// Interface that client should see
interface IService
{
OperationResult<int> TestMethod1(TestMethod1Input input);
OperationResult TestMethod2(TestMethod2Input input);
}


I think I can handle exceptions with IOperationInvoker but I don't know how change return value of actual service, and I wanted to change the return type of the function in the WSDL using IWsdlExportExtension. But I couldn't find any well documentation or sample for either of them.



Can anyone suggest any sample or documentation or any other way that can save me the trouble of changing too many already existing services?



NOTE: I have another way of doing this by creating a custom ServiceHost that create a dynamic wrapper for actual service and pass it as service type to constructor of ServiceHost. But this should be last solution since it will generate many dynamic types.







c# wcf






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 24 '18 at 16:52









BigBossBigBoss

6,09511437




6,09511437













  • Is it possible to add a proxy service(between client and server) to change type of returned values of services?!

    – isaeid
    Jan 2 at 9:51



















  • Is it possible to add a proxy service(between client and server) to change type of returned values of services?!

    – isaeid
    Jan 2 at 9:51

















Is it possible to add a proxy service(between client and server) to change type of returned values of services?!

– isaeid
Jan 2 at 9:51





Is it possible to add a proxy service(between client and server) to change type of returned values of services?!

– isaeid
Jan 2 at 9:51












4 Answers
4






active

oldest

votes


















6





+200









Maybe you could consider using IDataContractSurrogate.



It has three methods relating to serializing.





  • GetDataContractType is used to get the type to serialize or deserialize or get the datacontract to export and import.


  • GetObjectToSerialize is used to get the object to serialize before it is serialized.


  • GetDeserializedObject is used to get the object which has been serialized.


https://docs.microsoft.com/en-us/dotnet/framework/wcf/extending/data-contract-surrogates






share|improve this answer


























  • Your answer is pretty close and it could work if all return types are unique in the service. but if some function return a common type that can also accepted as argument(in my case I have so many of this functions), then it will change that parameters too.

    – BigBoss
    Jan 3 at 17:17











  • But since there is no other answer that can help me, and I learn something new from your answer, I'll give the bounty to you

    – BigBoss
    Jan 3 at 17:18











  • thank you very much

    – Ackelry Xu
    Jan 8 at 9:05



















1














First of all, if your return types are primitive then I think you can’t change the type dynamically. My approximation is above:





  • My client class



        var client = new ServiceReference1.Service1Client();

    WcfService1.OperationResult<int> resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = false });
    WcfService1.OperationResult<string> resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = false });

    WcfService1.IOperationResult resultKo1;
    WcfService1.OperationResult resultKo2;
    try
    {
    resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = true });
    }
    catch (FaultException<WcfService1.OperationResult<int>> ex)
    {
    resultKo1 = ex.Detail;
    }

    try
    {
    resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = true });
    }
    catch (FaultException<WcfService1.OperationResult<string>> ex)
    {
    resultKo2 = ex.Detail;
    }



  • My service



        [ErrorHandlerBehavior]
    public class Service1 : IService1
    {
    public TestMethod1Ouput TestMethod1(TestMethod1Input input)
    {
    if (input.Throws)
    {
    throw new Exception("a error message 1");
    }
    return new TestMethod1Ouput { OrginalResult = 123 };
    }

    public TestMethod2Ouput TestMethod2(TestMethod2Input input)
    {
    if (input.Throws)
    {
    throw new Exception("a error message 2");
    }
    return new TestMethod2Ouput { OrginalResult = "?"};
    }
    }

    [ServiceContract]
    [DataContractOperationResult]
    public interface IService1
    {
    [OperationContract]
    [FaultContract(typeof(OperationResult<int>))]
    TestMethod1Ouput TestMethod1(TestMethod1Input input);

    [OperationContract]
    [FaultContract(typeof(OperationResult<string>))]
    TestMethod2Ouput TestMethod2(TestMethod2Input input);
    }

    public interface IOperationResult
    {
    string Error { get; set; }
    }

    public interface IOperationResult<TResult> : IOperationResult
    {
    TResult Result { get; set; }
    }

    [DataContract]
    public class OperationResult : IOperationResult
    {
    [DataMember(Name = "Error")]
    public string Error { get; set; }
    }

    [DataContract]
    public class OperationResult<TResult> : OperationResult, IOperationResult<TResult>, IOperationResult
    {
    [DataMember(Name = "Result")]
    public TResult Result { get; set; }
    }

    public class TestMethod1Ouput
    {
    public int OrginalResult { get; set; }
    }

    public class TestMethod1Input
    {
    public bool Throws { get; set; }
    }

    public class TestMethod2Ouput
    {
    public string OrginalResult { get; set; }
    }

    public class TestMethod2Input
    {
    public bool Throws { get; set; }
    }



  • Classes to change de success responses:



      public sealed class DataContractOperationResultAttribute : Attribute, IContractBehavior, IOperationBehavior, IWsdlExportExtension, IDataContractSurrogate
    {
    #region IContractBehavior Members

    public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, BindingParameterCollection parameters)
    {
    }

    public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime proxy)
    {
    foreach (OperationDescription opDesc in description.Operations)
    {
    ApplyDataContractSurrogate(opDesc);
    }
    }

    public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatch)
    {
    foreach (OperationDescription opDesc in description.Operations)
    {
    ApplyDataContractSurrogate(opDesc);
    }
    }

    public void Validate(ContractDescription description, ServiceEndpoint endpoint)
    {
    }

    #endregion

    #region IWsdlExportExtension Members

    public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
    {
    if (exporter == null)
    throw new ArgumentNullException("exporter");

    object dataContractExporter;
    XsdDataContractExporter xsdDCExporter;
    if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out dataContractExporter))
    {
    xsdDCExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
    exporter.State.Add(typeof(XsdDataContractExporter), xsdDCExporter);
    }
    else
    {
    xsdDCExporter = (XsdDataContractExporter)dataContractExporter;
    }
    if (xsdDCExporter.Options == null)
    xsdDCExporter.Options = new ExportOptions();

    if (xsdDCExporter.Options.DataContractSurrogate == null)
    xsdDCExporter.Options.DataContractSurrogate = new DataContractOperationResultAttribute();
    }

    public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
    {
    }

    #endregion

    #region IOperationBehavior Members

    public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
    {
    ApplyDataContractSurrogate(description);
    }

    public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
    {
    ApplyDataContractSurrogate(description);
    }

    public void Validate(OperationDescription description)
    {
    }

    #endregion

    private static void ApplyDataContractSurrogate(OperationDescription description)
    {
    DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
    if (dcsOperationBehavior != null)
    {
    if (dcsOperationBehavior.DataContractSurrogate == null)
    dcsOperationBehavior.DataContractSurrogate = new DataContractOperationResultAttribute();
    }
    }

    #region IDataContractSurrogate Members

    public Type GetDataContractType(Type type)
    {
    // This method is called during serialization and schema export
    System.Diagnostics.Debug.WriteLine("GetDataContractType " + type.FullName);
    if (typeof(TestMethod1Ouput).IsAssignableFrom(type))
    {
    return typeof(OperationResult<int>);
    }
    if (typeof(TestMethod2Ouput).IsAssignableFrom(type))
    {
    return typeof(OperationResult<string>);
    }

    return type;
    }

    public object GetObjectToSerialize(object obj, Type targetType)
    {
    //This method is called on serialization.
    System.Diagnostics.Debug.WriteLine("GetObjectToSerialize " + targetType.FullName);
    if (obj is TestMethod1Ouput)
    {
    return new OperationResult<int> { Result = ((TestMethod1Ouput)obj).OrginalResult, Error = string.Empty };
    }
    if (obj is TestMethod2Ouput)
    {
    return new OperationResult<string> { Result = ((TestMethod2Ouput)obj).OrginalResult, Error = string.Empty };
    }
    return obj;
    }

    public object GetDeserializedObject(object obj, Type targetType)
    {
    return obj;
    }

    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
    {
    return null;
    }

    public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
    {
    return typeDeclaration;
    }

    public object GetCustomDataToExport(Type clrType, Type dataContractType)
    {
    return null;
    }

    public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
    {
    return null;
    }

    public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
    {

    }

    #endregion
    }



  • Classes to change de error responses:



      public class ErrorHandlerBehavior : Attribute, IErrorHandler, IServiceBehavior
    {
    #region Implementation of IErrorHandler

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
    ServiceEndpoint endpoint = OperationContext.Current.Host.Description.Endpoints.Find(OperationContext.Current.EndpointDispatcher.EndpointAddress.Uri);
    DispatchOperation dispatchOperation = OperationContext.Current.EndpointDispatcher.DispatchRuntime.Operations.Where(op => op.Action == OperationContext.Current.IncomingMessageHeaders.Action).First();
    OperationDescription operationDesc = endpoint.Contract.Operations.Find(dispatchOperation.Name);
    var attributes = operationDesc.SyncMethod.GetCustomAttributes(typeof(FaultContractAttribute), true);

    if (attributes.Any())
    {
    FaultContractAttribute attribute = (FaultContractAttribute)attributes[0];
    var type = attribute.DetailType;
    object faultDetail = Activator.CreateInstance(type);
    Type faultExceptionType = typeof(FaultException<>).MakeGenericType(type);
    FaultException faultException = (FaultException)Activator.CreateInstance(faultExceptionType, faultDetail, error.Message);
    MessageFault faultMessage = faultException.CreateMessageFault();
    fault = Message.CreateMessage(version, faultMessage, faultException.Action);
    }
    }

    public bool HandleError(Exception error)
    {
    return true;
    }

    #endregion

    #region Implementation of IServiceBehavior

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
    {
    ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;

    if (channelDispatcher != null)
    {
    channelDispatcher.ErrorHandlers.Add(this);
    }
    }
    }

    #endregion
    }



I hope my solution help you.






share|improve this answer

































    1














    Do different release number with expected method changes. Normally we not supposed to stop the delivered one. Clients/Interfaces needs to be updated the service with new changes if required.






    share|improve this answer































      0














      It's a bit of a hack but could you create a base class that has the old method implementations in it that call the newer overloaded methods? That way you'd just have to inherit from the base class and it shouldn't throw any errors.






      share|improve this answer























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53915910%2fchange-return-type-of-a-function-in-wcf-without-changing-interface-return-type%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        6





        +200









        Maybe you could consider using IDataContractSurrogate.



        It has three methods relating to serializing.





        • GetDataContractType is used to get the type to serialize or deserialize or get the datacontract to export and import.


        • GetObjectToSerialize is used to get the object to serialize before it is serialized.


        • GetDeserializedObject is used to get the object which has been serialized.


        https://docs.microsoft.com/en-us/dotnet/framework/wcf/extending/data-contract-surrogates






        share|improve this answer


























        • Your answer is pretty close and it could work if all return types are unique in the service. but if some function return a common type that can also accepted as argument(in my case I have so many of this functions), then it will change that parameters too.

          – BigBoss
          Jan 3 at 17:17











        • But since there is no other answer that can help me, and I learn something new from your answer, I'll give the bounty to you

          – BigBoss
          Jan 3 at 17:18











        • thank you very much

          – Ackelry Xu
          Jan 8 at 9:05
















        6





        +200









        Maybe you could consider using IDataContractSurrogate.



        It has three methods relating to serializing.





        • GetDataContractType is used to get the type to serialize or deserialize or get the datacontract to export and import.


        • GetObjectToSerialize is used to get the object to serialize before it is serialized.


        • GetDeserializedObject is used to get the object which has been serialized.


        https://docs.microsoft.com/en-us/dotnet/framework/wcf/extending/data-contract-surrogates






        share|improve this answer


























        • Your answer is pretty close and it could work if all return types are unique in the service. but if some function return a common type that can also accepted as argument(in my case I have so many of this functions), then it will change that parameters too.

          – BigBoss
          Jan 3 at 17:17











        • But since there is no other answer that can help me, and I learn something new from your answer, I'll give the bounty to you

          – BigBoss
          Jan 3 at 17:18











        • thank you very much

          – Ackelry Xu
          Jan 8 at 9:05














        6





        +200







        6





        +200



        6




        +200





        Maybe you could consider using IDataContractSurrogate.



        It has three methods relating to serializing.





        • GetDataContractType is used to get the type to serialize or deserialize or get the datacontract to export and import.


        • GetObjectToSerialize is used to get the object to serialize before it is serialized.


        • GetDeserializedObject is used to get the object which has been serialized.


        https://docs.microsoft.com/en-us/dotnet/framework/wcf/extending/data-contract-surrogates






        share|improve this answer















        Maybe you could consider using IDataContractSurrogate.



        It has three methods relating to serializing.





        • GetDataContractType is used to get the type to serialize or deserialize or get the datacontract to export and import.


        • GetObjectToSerialize is used to get the object to serialize before it is serialized.


        • GetDeserializedObject is used to get the object which has been serialized.


        https://docs.microsoft.com/en-us/dotnet/framework/wcf/extending/data-contract-surrogates







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 2 at 11:19









        Imantas

        1,103918




        1,103918










        answered Dec 27 '18 at 7:04









        Ackelry XuAckelry Xu

        5966




        5966













        • Your answer is pretty close and it could work if all return types are unique in the service. but if some function return a common type that can also accepted as argument(in my case I have so many of this functions), then it will change that parameters too.

          – BigBoss
          Jan 3 at 17:17











        • But since there is no other answer that can help me, and I learn something new from your answer, I'll give the bounty to you

          – BigBoss
          Jan 3 at 17:18











        • thank you very much

          – Ackelry Xu
          Jan 8 at 9:05



















        • Your answer is pretty close and it could work if all return types are unique in the service. but if some function return a common type that can also accepted as argument(in my case I have so many of this functions), then it will change that parameters too.

          – BigBoss
          Jan 3 at 17:17











        • But since there is no other answer that can help me, and I learn something new from your answer, I'll give the bounty to you

          – BigBoss
          Jan 3 at 17:18











        • thank you very much

          – Ackelry Xu
          Jan 8 at 9:05

















        Your answer is pretty close and it could work if all return types are unique in the service. but if some function return a common type that can also accepted as argument(in my case I have so many of this functions), then it will change that parameters too.

        – BigBoss
        Jan 3 at 17:17





        Your answer is pretty close and it could work if all return types are unique in the service. but if some function return a common type that can also accepted as argument(in my case I have so many of this functions), then it will change that parameters too.

        – BigBoss
        Jan 3 at 17:17













        But since there is no other answer that can help me, and I learn something new from your answer, I'll give the bounty to you

        – BigBoss
        Jan 3 at 17:18





        But since there is no other answer that can help me, and I learn something new from your answer, I'll give the bounty to you

        – BigBoss
        Jan 3 at 17:18













        thank you very much

        – Ackelry Xu
        Jan 8 at 9:05





        thank you very much

        – Ackelry Xu
        Jan 8 at 9:05













        1














        First of all, if your return types are primitive then I think you can’t change the type dynamically. My approximation is above:





        • My client class



              var client = new ServiceReference1.Service1Client();

          WcfService1.OperationResult<int> resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = false });
          WcfService1.OperationResult<string> resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = false });

          WcfService1.IOperationResult resultKo1;
          WcfService1.OperationResult resultKo2;
          try
          {
          resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = true });
          }
          catch (FaultException<WcfService1.OperationResult<int>> ex)
          {
          resultKo1 = ex.Detail;
          }

          try
          {
          resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = true });
          }
          catch (FaultException<WcfService1.OperationResult<string>> ex)
          {
          resultKo2 = ex.Detail;
          }



        • My service



              [ErrorHandlerBehavior]
          public class Service1 : IService1
          {
          public TestMethod1Ouput TestMethod1(TestMethod1Input input)
          {
          if (input.Throws)
          {
          throw new Exception("a error message 1");
          }
          return new TestMethod1Ouput { OrginalResult = 123 };
          }

          public TestMethod2Ouput TestMethod2(TestMethod2Input input)
          {
          if (input.Throws)
          {
          throw new Exception("a error message 2");
          }
          return new TestMethod2Ouput { OrginalResult = "?"};
          }
          }

          [ServiceContract]
          [DataContractOperationResult]
          public interface IService1
          {
          [OperationContract]
          [FaultContract(typeof(OperationResult<int>))]
          TestMethod1Ouput TestMethod1(TestMethod1Input input);

          [OperationContract]
          [FaultContract(typeof(OperationResult<string>))]
          TestMethod2Ouput TestMethod2(TestMethod2Input input);
          }

          public interface IOperationResult
          {
          string Error { get; set; }
          }

          public interface IOperationResult<TResult> : IOperationResult
          {
          TResult Result { get; set; }
          }

          [DataContract]
          public class OperationResult : IOperationResult
          {
          [DataMember(Name = "Error")]
          public string Error { get; set; }
          }

          [DataContract]
          public class OperationResult<TResult> : OperationResult, IOperationResult<TResult>, IOperationResult
          {
          [DataMember(Name = "Result")]
          public TResult Result { get; set; }
          }

          public class TestMethod1Ouput
          {
          public int OrginalResult { get; set; }
          }

          public class TestMethod1Input
          {
          public bool Throws { get; set; }
          }

          public class TestMethod2Ouput
          {
          public string OrginalResult { get; set; }
          }

          public class TestMethod2Input
          {
          public bool Throws { get; set; }
          }



        • Classes to change de success responses:



            public sealed class DataContractOperationResultAttribute : Attribute, IContractBehavior, IOperationBehavior, IWsdlExportExtension, IDataContractSurrogate
          {
          #region IContractBehavior Members

          public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, BindingParameterCollection parameters)
          {
          }

          public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime proxy)
          {
          foreach (OperationDescription opDesc in description.Operations)
          {
          ApplyDataContractSurrogate(opDesc);
          }
          }

          public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatch)
          {
          foreach (OperationDescription opDesc in description.Operations)
          {
          ApplyDataContractSurrogate(opDesc);
          }
          }

          public void Validate(ContractDescription description, ServiceEndpoint endpoint)
          {
          }

          #endregion

          #region IWsdlExportExtension Members

          public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
          {
          if (exporter == null)
          throw new ArgumentNullException("exporter");

          object dataContractExporter;
          XsdDataContractExporter xsdDCExporter;
          if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out dataContractExporter))
          {
          xsdDCExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
          exporter.State.Add(typeof(XsdDataContractExporter), xsdDCExporter);
          }
          else
          {
          xsdDCExporter = (XsdDataContractExporter)dataContractExporter;
          }
          if (xsdDCExporter.Options == null)
          xsdDCExporter.Options = new ExportOptions();

          if (xsdDCExporter.Options.DataContractSurrogate == null)
          xsdDCExporter.Options.DataContractSurrogate = new DataContractOperationResultAttribute();
          }

          public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
          {
          }

          #endregion

          #region IOperationBehavior Members

          public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
          {
          }

          public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
          {
          ApplyDataContractSurrogate(description);
          }

          public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
          {
          ApplyDataContractSurrogate(description);
          }

          public void Validate(OperationDescription description)
          {
          }

          #endregion

          private static void ApplyDataContractSurrogate(OperationDescription description)
          {
          DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
          if (dcsOperationBehavior != null)
          {
          if (dcsOperationBehavior.DataContractSurrogate == null)
          dcsOperationBehavior.DataContractSurrogate = new DataContractOperationResultAttribute();
          }
          }

          #region IDataContractSurrogate Members

          public Type GetDataContractType(Type type)
          {
          // This method is called during serialization and schema export
          System.Diagnostics.Debug.WriteLine("GetDataContractType " + type.FullName);
          if (typeof(TestMethod1Ouput).IsAssignableFrom(type))
          {
          return typeof(OperationResult<int>);
          }
          if (typeof(TestMethod2Ouput).IsAssignableFrom(type))
          {
          return typeof(OperationResult<string>);
          }

          return type;
          }

          public object GetObjectToSerialize(object obj, Type targetType)
          {
          //This method is called on serialization.
          System.Diagnostics.Debug.WriteLine("GetObjectToSerialize " + targetType.FullName);
          if (obj is TestMethod1Ouput)
          {
          return new OperationResult<int> { Result = ((TestMethod1Ouput)obj).OrginalResult, Error = string.Empty };
          }
          if (obj is TestMethod2Ouput)
          {
          return new OperationResult<string> { Result = ((TestMethod2Ouput)obj).OrginalResult, Error = string.Empty };
          }
          return obj;
          }

          public object GetDeserializedObject(object obj, Type targetType)
          {
          return obj;
          }

          public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
          {
          return null;
          }

          public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
          {
          return typeDeclaration;
          }

          public object GetCustomDataToExport(Type clrType, Type dataContractType)
          {
          return null;
          }

          public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
          {
          return null;
          }

          public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
          {

          }

          #endregion
          }



        • Classes to change de error responses:



            public class ErrorHandlerBehavior : Attribute, IErrorHandler, IServiceBehavior
          {
          #region Implementation of IErrorHandler

          public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
          {
          ServiceEndpoint endpoint = OperationContext.Current.Host.Description.Endpoints.Find(OperationContext.Current.EndpointDispatcher.EndpointAddress.Uri);
          DispatchOperation dispatchOperation = OperationContext.Current.EndpointDispatcher.DispatchRuntime.Operations.Where(op => op.Action == OperationContext.Current.IncomingMessageHeaders.Action).First();
          OperationDescription operationDesc = endpoint.Contract.Operations.Find(dispatchOperation.Name);
          var attributes = operationDesc.SyncMethod.GetCustomAttributes(typeof(FaultContractAttribute), true);

          if (attributes.Any())
          {
          FaultContractAttribute attribute = (FaultContractAttribute)attributes[0];
          var type = attribute.DetailType;
          object faultDetail = Activator.CreateInstance(type);
          Type faultExceptionType = typeof(FaultException<>).MakeGenericType(type);
          FaultException faultException = (FaultException)Activator.CreateInstance(faultExceptionType, faultDetail, error.Message);
          MessageFault faultMessage = faultException.CreateMessageFault();
          fault = Message.CreateMessage(version, faultMessage, faultException.Action);
          }
          }

          public bool HandleError(Exception error)
          {
          return true;
          }

          #endregion

          #region Implementation of IServiceBehavior

          public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
          {
          }

          public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
          {
          }

          public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
          {
          foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
          {
          ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;

          if (channelDispatcher != null)
          {
          channelDispatcher.ErrorHandlers.Add(this);
          }
          }
          }

          #endregion
          }



        I hope my solution help you.






        share|improve this answer






























          1














          First of all, if your return types are primitive then I think you can’t change the type dynamically. My approximation is above:





          • My client class



                var client = new ServiceReference1.Service1Client();

            WcfService1.OperationResult<int> resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = false });
            WcfService1.OperationResult<string> resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = false });

            WcfService1.IOperationResult resultKo1;
            WcfService1.OperationResult resultKo2;
            try
            {
            resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = true });
            }
            catch (FaultException<WcfService1.OperationResult<int>> ex)
            {
            resultKo1 = ex.Detail;
            }

            try
            {
            resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = true });
            }
            catch (FaultException<WcfService1.OperationResult<string>> ex)
            {
            resultKo2 = ex.Detail;
            }



          • My service



                [ErrorHandlerBehavior]
            public class Service1 : IService1
            {
            public TestMethod1Ouput TestMethod1(TestMethod1Input input)
            {
            if (input.Throws)
            {
            throw new Exception("a error message 1");
            }
            return new TestMethod1Ouput { OrginalResult = 123 };
            }

            public TestMethod2Ouput TestMethod2(TestMethod2Input input)
            {
            if (input.Throws)
            {
            throw new Exception("a error message 2");
            }
            return new TestMethod2Ouput { OrginalResult = "?"};
            }
            }

            [ServiceContract]
            [DataContractOperationResult]
            public interface IService1
            {
            [OperationContract]
            [FaultContract(typeof(OperationResult<int>))]
            TestMethod1Ouput TestMethod1(TestMethod1Input input);

            [OperationContract]
            [FaultContract(typeof(OperationResult<string>))]
            TestMethod2Ouput TestMethod2(TestMethod2Input input);
            }

            public interface IOperationResult
            {
            string Error { get; set; }
            }

            public interface IOperationResult<TResult> : IOperationResult
            {
            TResult Result { get; set; }
            }

            [DataContract]
            public class OperationResult : IOperationResult
            {
            [DataMember(Name = "Error")]
            public string Error { get; set; }
            }

            [DataContract]
            public class OperationResult<TResult> : OperationResult, IOperationResult<TResult>, IOperationResult
            {
            [DataMember(Name = "Result")]
            public TResult Result { get; set; }
            }

            public class TestMethod1Ouput
            {
            public int OrginalResult { get; set; }
            }

            public class TestMethod1Input
            {
            public bool Throws { get; set; }
            }

            public class TestMethod2Ouput
            {
            public string OrginalResult { get; set; }
            }

            public class TestMethod2Input
            {
            public bool Throws { get; set; }
            }



          • Classes to change de success responses:



              public sealed class DataContractOperationResultAttribute : Attribute, IContractBehavior, IOperationBehavior, IWsdlExportExtension, IDataContractSurrogate
            {
            #region IContractBehavior Members

            public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, BindingParameterCollection parameters)
            {
            }

            public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime proxy)
            {
            foreach (OperationDescription opDesc in description.Operations)
            {
            ApplyDataContractSurrogate(opDesc);
            }
            }

            public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatch)
            {
            foreach (OperationDescription opDesc in description.Operations)
            {
            ApplyDataContractSurrogate(opDesc);
            }
            }

            public void Validate(ContractDescription description, ServiceEndpoint endpoint)
            {
            }

            #endregion

            #region IWsdlExportExtension Members

            public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
            {
            if (exporter == null)
            throw new ArgumentNullException("exporter");

            object dataContractExporter;
            XsdDataContractExporter xsdDCExporter;
            if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out dataContractExporter))
            {
            xsdDCExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
            exporter.State.Add(typeof(XsdDataContractExporter), xsdDCExporter);
            }
            else
            {
            xsdDCExporter = (XsdDataContractExporter)dataContractExporter;
            }
            if (xsdDCExporter.Options == null)
            xsdDCExporter.Options = new ExportOptions();

            if (xsdDCExporter.Options.DataContractSurrogate == null)
            xsdDCExporter.Options.DataContractSurrogate = new DataContractOperationResultAttribute();
            }

            public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
            {
            }

            #endregion

            #region IOperationBehavior Members

            public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
            {
            }

            public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
            {
            ApplyDataContractSurrogate(description);
            }

            public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
            {
            ApplyDataContractSurrogate(description);
            }

            public void Validate(OperationDescription description)
            {
            }

            #endregion

            private static void ApplyDataContractSurrogate(OperationDescription description)
            {
            DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
            if (dcsOperationBehavior != null)
            {
            if (dcsOperationBehavior.DataContractSurrogate == null)
            dcsOperationBehavior.DataContractSurrogate = new DataContractOperationResultAttribute();
            }
            }

            #region IDataContractSurrogate Members

            public Type GetDataContractType(Type type)
            {
            // This method is called during serialization and schema export
            System.Diagnostics.Debug.WriteLine("GetDataContractType " + type.FullName);
            if (typeof(TestMethod1Ouput).IsAssignableFrom(type))
            {
            return typeof(OperationResult<int>);
            }
            if (typeof(TestMethod2Ouput).IsAssignableFrom(type))
            {
            return typeof(OperationResult<string>);
            }

            return type;
            }

            public object GetObjectToSerialize(object obj, Type targetType)
            {
            //This method is called on serialization.
            System.Diagnostics.Debug.WriteLine("GetObjectToSerialize " + targetType.FullName);
            if (obj is TestMethod1Ouput)
            {
            return new OperationResult<int> { Result = ((TestMethod1Ouput)obj).OrginalResult, Error = string.Empty };
            }
            if (obj is TestMethod2Ouput)
            {
            return new OperationResult<string> { Result = ((TestMethod2Ouput)obj).OrginalResult, Error = string.Empty };
            }
            return obj;
            }

            public object GetDeserializedObject(object obj, Type targetType)
            {
            return obj;
            }

            public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
            {
            return null;
            }

            public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
            {
            return typeDeclaration;
            }

            public object GetCustomDataToExport(Type clrType, Type dataContractType)
            {
            return null;
            }

            public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
            {
            return null;
            }

            public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
            {

            }

            #endregion
            }



          • Classes to change de error responses:



              public class ErrorHandlerBehavior : Attribute, IErrorHandler, IServiceBehavior
            {
            #region Implementation of IErrorHandler

            public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
            {
            ServiceEndpoint endpoint = OperationContext.Current.Host.Description.Endpoints.Find(OperationContext.Current.EndpointDispatcher.EndpointAddress.Uri);
            DispatchOperation dispatchOperation = OperationContext.Current.EndpointDispatcher.DispatchRuntime.Operations.Where(op => op.Action == OperationContext.Current.IncomingMessageHeaders.Action).First();
            OperationDescription operationDesc = endpoint.Contract.Operations.Find(dispatchOperation.Name);
            var attributes = operationDesc.SyncMethod.GetCustomAttributes(typeof(FaultContractAttribute), true);

            if (attributes.Any())
            {
            FaultContractAttribute attribute = (FaultContractAttribute)attributes[0];
            var type = attribute.DetailType;
            object faultDetail = Activator.CreateInstance(type);
            Type faultExceptionType = typeof(FaultException<>).MakeGenericType(type);
            FaultException faultException = (FaultException)Activator.CreateInstance(faultExceptionType, faultDetail, error.Message);
            MessageFault faultMessage = faultException.CreateMessageFault();
            fault = Message.CreateMessage(version, faultMessage, faultException.Action);
            }
            }

            public bool HandleError(Exception error)
            {
            return true;
            }

            #endregion

            #region Implementation of IServiceBehavior

            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
            }

            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
            {
            }

            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
            ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;

            if (channelDispatcher != null)
            {
            channelDispatcher.ErrorHandlers.Add(this);
            }
            }
            }

            #endregion
            }



          I hope my solution help you.






          share|improve this answer




























            1












            1








            1







            First of all, if your return types are primitive then I think you can’t change the type dynamically. My approximation is above:





            • My client class



                  var client = new ServiceReference1.Service1Client();

              WcfService1.OperationResult<int> resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = false });
              WcfService1.OperationResult<string> resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = false });

              WcfService1.IOperationResult resultKo1;
              WcfService1.OperationResult resultKo2;
              try
              {
              resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = true });
              }
              catch (FaultException<WcfService1.OperationResult<int>> ex)
              {
              resultKo1 = ex.Detail;
              }

              try
              {
              resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = true });
              }
              catch (FaultException<WcfService1.OperationResult<string>> ex)
              {
              resultKo2 = ex.Detail;
              }



            • My service



                  [ErrorHandlerBehavior]
              public class Service1 : IService1
              {
              public TestMethod1Ouput TestMethod1(TestMethod1Input input)
              {
              if (input.Throws)
              {
              throw new Exception("a error message 1");
              }
              return new TestMethod1Ouput { OrginalResult = 123 };
              }

              public TestMethod2Ouput TestMethod2(TestMethod2Input input)
              {
              if (input.Throws)
              {
              throw new Exception("a error message 2");
              }
              return new TestMethod2Ouput { OrginalResult = "?"};
              }
              }

              [ServiceContract]
              [DataContractOperationResult]
              public interface IService1
              {
              [OperationContract]
              [FaultContract(typeof(OperationResult<int>))]
              TestMethod1Ouput TestMethod1(TestMethod1Input input);

              [OperationContract]
              [FaultContract(typeof(OperationResult<string>))]
              TestMethod2Ouput TestMethod2(TestMethod2Input input);
              }

              public interface IOperationResult
              {
              string Error { get; set; }
              }

              public interface IOperationResult<TResult> : IOperationResult
              {
              TResult Result { get; set; }
              }

              [DataContract]
              public class OperationResult : IOperationResult
              {
              [DataMember(Name = "Error")]
              public string Error { get; set; }
              }

              [DataContract]
              public class OperationResult<TResult> : OperationResult, IOperationResult<TResult>, IOperationResult
              {
              [DataMember(Name = "Result")]
              public TResult Result { get; set; }
              }

              public class TestMethod1Ouput
              {
              public int OrginalResult { get; set; }
              }

              public class TestMethod1Input
              {
              public bool Throws { get; set; }
              }

              public class TestMethod2Ouput
              {
              public string OrginalResult { get; set; }
              }

              public class TestMethod2Input
              {
              public bool Throws { get; set; }
              }



            • Classes to change de success responses:



                public sealed class DataContractOperationResultAttribute : Attribute, IContractBehavior, IOperationBehavior, IWsdlExportExtension, IDataContractSurrogate
              {
              #region IContractBehavior Members

              public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, BindingParameterCollection parameters)
              {
              }

              public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime proxy)
              {
              foreach (OperationDescription opDesc in description.Operations)
              {
              ApplyDataContractSurrogate(opDesc);
              }
              }

              public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatch)
              {
              foreach (OperationDescription opDesc in description.Operations)
              {
              ApplyDataContractSurrogate(opDesc);
              }
              }

              public void Validate(ContractDescription description, ServiceEndpoint endpoint)
              {
              }

              #endregion

              #region IWsdlExportExtension Members

              public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
              {
              if (exporter == null)
              throw new ArgumentNullException("exporter");

              object dataContractExporter;
              XsdDataContractExporter xsdDCExporter;
              if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out dataContractExporter))
              {
              xsdDCExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
              exporter.State.Add(typeof(XsdDataContractExporter), xsdDCExporter);
              }
              else
              {
              xsdDCExporter = (XsdDataContractExporter)dataContractExporter;
              }
              if (xsdDCExporter.Options == null)
              xsdDCExporter.Options = new ExportOptions();

              if (xsdDCExporter.Options.DataContractSurrogate == null)
              xsdDCExporter.Options.DataContractSurrogate = new DataContractOperationResultAttribute();
              }

              public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
              {
              }

              #endregion

              #region IOperationBehavior Members

              public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
              {
              }

              public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
              {
              ApplyDataContractSurrogate(description);
              }

              public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
              {
              ApplyDataContractSurrogate(description);
              }

              public void Validate(OperationDescription description)
              {
              }

              #endregion

              private static void ApplyDataContractSurrogate(OperationDescription description)
              {
              DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
              if (dcsOperationBehavior != null)
              {
              if (dcsOperationBehavior.DataContractSurrogate == null)
              dcsOperationBehavior.DataContractSurrogate = new DataContractOperationResultAttribute();
              }
              }

              #region IDataContractSurrogate Members

              public Type GetDataContractType(Type type)
              {
              // This method is called during serialization and schema export
              System.Diagnostics.Debug.WriteLine("GetDataContractType " + type.FullName);
              if (typeof(TestMethod1Ouput).IsAssignableFrom(type))
              {
              return typeof(OperationResult<int>);
              }
              if (typeof(TestMethod2Ouput).IsAssignableFrom(type))
              {
              return typeof(OperationResult<string>);
              }

              return type;
              }

              public object GetObjectToSerialize(object obj, Type targetType)
              {
              //This method is called on serialization.
              System.Diagnostics.Debug.WriteLine("GetObjectToSerialize " + targetType.FullName);
              if (obj is TestMethod1Ouput)
              {
              return new OperationResult<int> { Result = ((TestMethod1Ouput)obj).OrginalResult, Error = string.Empty };
              }
              if (obj is TestMethod2Ouput)
              {
              return new OperationResult<string> { Result = ((TestMethod2Ouput)obj).OrginalResult, Error = string.Empty };
              }
              return obj;
              }

              public object GetDeserializedObject(object obj, Type targetType)
              {
              return obj;
              }

              public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
              {
              return null;
              }

              public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
              {
              return typeDeclaration;
              }

              public object GetCustomDataToExport(Type clrType, Type dataContractType)
              {
              return null;
              }

              public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
              {
              return null;
              }

              public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
              {

              }

              #endregion
              }



            • Classes to change de error responses:



                public class ErrorHandlerBehavior : Attribute, IErrorHandler, IServiceBehavior
              {
              #region Implementation of IErrorHandler

              public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
              {
              ServiceEndpoint endpoint = OperationContext.Current.Host.Description.Endpoints.Find(OperationContext.Current.EndpointDispatcher.EndpointAddress.Uri);
              DispatchOperation dispatchOperation = OperationContext.Current.EndpointDispatcher.DispatchRuntime.Operations.Where(op => op.Action == OperationContext.Current.IncomingMessageHeaders.Action).First();
              OperationDescription operationDesc = endpoint.Contract.Operations.Find(dispatchOperation.Name);
              var attributes = operationDesc.SyncMethod.GetCustomAttributes(typeof(FaultContractAttribute), true);

              if (attributes.Any())
              {
              FaultContractAttribute attribute = (FaultContractAttribute)attributes[0];
              var type = attribute.DetailType;
              object faultDetail = Activator.CreateInstance(type);
              Type faultExceptionType = typeof(FaultException<>).MakeGenericType(type);
              FaultException faultException = (FaultException)Activator.CreateInstance(faultExceptionType, faultDetail, error.Message);
              MessageFault faultMessage = faultException.CreateMessageFault();
              fault = Message.CreateMessage(version, faultMessage, faultException.Action);
              }
              }

              public bool HandleError(Exception error)
              {
              return true;
              }

              #endregion

              #region Implementation of IServiceBehavior

              public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
              {
              }

              public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
              {
              }

              public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
              {
              foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
              {
              ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;

              if (channelDispatcher != null)
              {
              channelDispatcher.ErrorHandlers.Add(this);
              }
              }
              }

              #endregion
              }



            I hope my solution help you.






            share|improve this answer















            First of all, if your return types are primitive then I think you can’t change the type dynamically. My approximation is above:





            • My client class



                  var client = new ServiceReference1.Service1Client();

              WcfService1.OperationResult<int> resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = false });
              WcfService1.OperationResult<string> resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = false });

              WcfService1.IOperationResult resultKo1;
              WcfService1.OperationResult resultKo2;
              try
              {
              resultOk1 = client.TestMethod1(new WcfService1.TestMethod1Input { Throws = true });
              }
              catch (FaultException<WcfService1.OperationResult<int>> ex)
              {
              resultKo1 = ex.Detail;
              }

              try
              {
              resultOk2 = client.TestMethod2(new WcfService1.TestMethod2Input { Throws = true });
              }
              catch (FaultException<WcfService1.OperationResult<string>> ex)
              {
              resultKo2 = ex.Detail;
              }



            • My service



                  [ErrorHandlerBehavior]
              public class Service1 : IService1
              {
              public TestMethod1Ouput TestMethod1(TestMethod1Input input)
              {
              if (input.Throws)
              {
              throw new Exception("a error message 1");
              }
              return new TestMethod1Ouput { OrginalResult = 123 };
              }

              public TestMethod2Ouput TestMethod2(TestMethod2Input input)
              {
              if (input.Throws)
              {
              throw new Exception("a error message 2");
              }
              return new TestMethod2Ouput { OrginalResult = "?"};
              }
              }

              [ServiceContract]
              [DataContractOperationResult]
              public interface IService1
              {
              [OperationContract]
              [FaultContract(typeof(OperationResult<int>))]
              TestMethod1Ouput TestMethod1(TestMethod1Input input);

              [OperationContract]
              [FaultContract(typeof(OperationResult<string>))]
              TestMethod2Ouput TestMethod2(TestMethod2Input input);
              }

              public interface IOperationResult
              {
              string Error { get; set; }
              }

              public interface IOperationResult<TResult> : IOperationResult
              {
              TResult Result { get; set; }
              }

              [DataContract]
              public class OperationResult : IOperationResult
              {
              [DataMember(Name = "Error")]
              public string Error { get; set; }
              }

              [DataContract]
              public class OperationResult<TResult> : OperationResult, IOperationResult<TResult>, IOperationResult
              {
              [DataMember(Name = "Result")]
              public TResult Result { get; set; }
              }

              public class TestMethod1Ouput
              {
              public int OrginalResult { get; set; }
              }

              public class TestMethod1Input
              {
              public bool Throws { get; set; }
              }

              public class TestMethod2Ouput
              {
              public string OrginalResult { get; set; }
              }

              public class TestMethod2Input
              {
              public bool Throws { get; set; }
              }



            • Classes to change de success responses:



                public sealed class DataContractOperationResultAttribute : Attribute, IContractBehavior, IOperationBehavior, IWsdlExportExtension, IDataContractSurrogate
              {
              #region IContractBehavior Members

              public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, BindingParameterCollection parameters)
              {
              }

              public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime proxy)
              {
              foreach (OperationDescription opDesc in description.Operations)
              {
              ApplyDataContractSurrogate(opDesc);
              }
              }

              public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatch)
              {
              foreach (OperationDescription opDesc in description.Operations)
              {
              ApplyDataContractSurrogate(opDesc);
              }
              }

              public void Validate(ContractDescription description, ServiceEndpoint endpoint)
              {
              }

              #endregion

              #region IWsdlExportExtension Members

              public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
              {
              if (exporter == null)
              throw new ArgumentNullException("exporter");

              object dataContractExporter;
              XsdDataContractExporter xsdDCExporter;
              if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out dataContractExporter))
              {
              xsdDCExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
              exporter.State.Add(typeof(XsdDataContractExporter), xsdDCExporter);
              }
              else
              {
              xsdDCExporter = (XsdDataContractExporter)dataContractExporter;
              }
              if (xsdDCExporter.Options == null)
              xsdDCExporter.Options = new ExportOptions();

              if (xsdDCExporter.Options.DataContractSurrogate == null)
              xsdDCExporter.Options.DataContractSurrogate = new DataContractOperationResultAttribute();
              }

              public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
              {
              }

              #endregion

              #region IOperationBehavior Members

              public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
              {
              }

              public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
              {
              ApplyDataContractSurrogate(description);
              }

              public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
              {
              ApplyDataContractSurrogate(description);
              }

              public void Validate(OperationDescription description)
              {
              }

              #endregion

              private static void ApplyDataContractSurrogate(OperationDescription description)
              {
              DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
              if (dcsOperationBehavior != null)
              {
              if (dcsOperationBehavior.DataContractSurrogate == null)
              dcsOperationBehavior.DataContractSurrogate = new DataContractOperationResultAttribute();
              }
              }

              #region IDataContractSurrogate Members

              public Type GetDataContractType(Type type)
              {
              // This method is called during serialization and schema export
              System.Diagnostics.Debug.WriteLine("GetDataContractType " + type.FullName);
              if (typeof(TestMethod1Ouput).IsAssignableFrom(type))
              {
              return typeof(OperationResult<int>);
              }
              if (typeof(TestMethod2Ouput).IsAssignableFrom(type))
              {
              return typeof(OperationResult<string>);
              }

              return type;
              }

              public object GetObjectToSerialize(object obj, Type targetType)
              {
              //This method is called on serialization.
              System.Diagnostics.Debug.WriteLine("GetObjectToSerialize " + targetType.FullName);
              if (obj is TestMethod1Ouput)
              {
              return new OperationResult<int> { Result = ((TestMethod1Ouput)obj).OrginalResult, Error = string.Empty };
              }
              if (obj is TestMethod2Ouput)
              {
              return new OperationResult<string> { Result = ((TestMethod2Ouput)obj).OrginalResult, Error = string.Empty };
              }
              return obj;
              }

              public object GetDeserializedObject(object obj, Type targetType)
              {
              return obj;
              }

              public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
              {
              return null;
              }

              public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
              {
              return typeDeclaration;
              }

              public object GetCustomDataToExport(Type clrType, Type dataContractType)
              {
              return null;
              }

              public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
              {
              return null;
              }

              public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
              {

              }

              #endregion
              }



            • Classes to change de error responses:



                public class ErrorHandlerBehavior : Attribute, IErrorHandler, IServiceBehavior
              {
              #region Implementation of IErrorHandler

              public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
              {
              ServiceEndpoint endpoint = OperationContext.Current.Host.Description.Endpoints.Find(OperationContext.Current.EndpointDispatcher.EndpointAddress.Uri);
              DispatchOperation dispatchOperation = OperationContext.Current.EndpointDispatcher.DispatchRuntime.Operations.Where(op => op.Action == OperationContext.Current.IncomingMessageHeaders.Action).First();
              OperationDescription operationDesc = endpoint.Contract.Operations.Find(dispatchOperation.Name);
              var attributes = operationDesc.SyncMethod.GetCustomAttributes(typeof(FaultContractAttribute), true);

              if (attributes.Any())
              {
              FaultContractAttribute attribute = (FaultContractAttribute)attributes[0];
              var type = attribute.DetailType;
              object faultDetail = Activator.CreateInstance(type);
              Type faultExceptionType = typeof(FaultException<>).MakeGenericType(type);
              FaultException faultException = (FaultException)Activator.CreateInstance(faultExceptionType, faultDetail, error.Message);
              MessageFault faultMessage = faultException.CreateMessageFault();
              fault = Message.CreateMessage(version, faultMessage, faultException.Action);
              }
              }

              public bool HandleError(Exception error)
              {
              return true;
              }

              #endregion

              #region Implementation of IServiceBehavior

              public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
              {
              }

              public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
              {
              }

              public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
              {
              foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
              {
              ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;

              if (channelDispatcher != null)
              {
              channelDispatcher.ErrorHandlers.Add(this);
              }
              }
              }

              #endregion
              }



            I hope my solution help you.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 27 '18 at 13:42

























            answered Dec 27 '18 at 13:35









            Jose M.Jose M.

            1,0581320




            1,0581320























                1














                Do different release number with expected method changes. Normally we not supposed to stop the delivered one. Clients/Interfaces needs to be updated the service with new changes if required.






                share|improve this answer




























                  1














                  Do different release number with expected method changes. Normally we not supposed to stop the delivered one. Clients/Interfaces needs to be updated the service with new changes if required.






                  share|improve this answer


























                    1












                    1








                    1







                    Do different release number with expected method changes. Normally we not supposed to stop the delivered one. Clients/Interfaces needs to be updated the service with new changes if required.






                    share|improve this answer













                    Do different release number with expected method changes. Normally we not supposed to stop the delivered one. Clients/Interfaces needs to be updated the service with new changes if required.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 2 at 10:08









                    A. SakthivelA. Sakthivel

                    211




                    211























                        0














                        It's a bit of a hack but could you create a base class that has the old method implementations in it that call the newer overloaded methods? That way you'd just have to inherit from the base class and it shouldn't throw any errors.






                        share|improve this answer




























                          0














                          It's a bit of a hack but could you create a base class that has the old method implementations in it that call the newer overloaded methods? That way you'd just have to inherit from the base class and it shouldn't throw any errors.






                          share|improve this answer


























                            0












                            0








                            0







                            It's a bit of a hack but could you create a base class that has the old method implementations in it that call the newer overloaded methods? That way you'd just have to inherit from the base class and it shouldn't throw any errors.






                            share|improve this answer













                            It's a bit of a hack but could you create a base class that has the old method implementations in it that call the newer overloaded methods? That way you'd just have to inherit from the base class and it shouldn't throw any errors.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jan 3 at 15:08









                            Edward GahanEdward Gahan

                            11




                            11






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53915910%2fchange-return-type-of-a-function-in-wcf-without-changing-interface-return-type%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                android studio warns about leanback feature tag usage required on manifest while using Unity exported app?

                                SQL update select statement

                                'app-layout' is not a known element: how to share Component with different Modules