Change return type of a function in WCF without changing interface return type
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
add a comment |
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
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
add a comment |
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
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
c# wcf
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
add a comment |
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
add a comment |
4 Answers
4
active
oldest
votes
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
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
add a comment |
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.
add a comment |
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.
add a comment |
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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
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
add a comment |
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
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
add a comment |
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
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
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
add a comment |
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
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
edited Dec 27 '18 at 13:42
answered Dec 27 '18 at 13:35
Jose M.Jose M.
1,0581320
1,0581320
add a comment |
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered Jan 2 at 10:08
A. SakthivelA. Sakthivel
211
211
add a comment |
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered Jan 3 at 15:08
Edward GahanEdward Gahan
11
11
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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