Reputation: 59
However, I'm going to ask: How to throw a [FaultException] in WCF with customized Headers and Body? Because when I use [FaultException] to throw [MessageContract], it always wraps my headers and body tags into body tag.
This is not what I want. Most of the SOAP clients do not understand WCF [FaultException].
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang="en-CH" />
<detail>
<CustomizedError xmlns="http://schemas.datacontract.org/2004/07/PlayWcfFault" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<BodyTag1>Hello BodyTag1</BodyTag1>
<HeaderTag1>Hello HeaderTag1</HeaderTag1>
</CustomizedError>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
[MessageContract]
public class CustomizedError
{
[MessageHeader] public string HeaderTag1;
[MessageBodyMember] public string BodyTag1;
}
[ServiceContract]
public interface IService1
{
[OperationContract]
[FaultContract(typeof(CustomizedError))]
CustomizedError GetData();
}
public class Service1 : IService1
{
public CustomizedError GetData()
{
CustomizedError fault = new CustomizedError
{
HeaderTag1 = "Hello HeaderTag1",
BodyTag1 = "Hello BodyTag1",
};
throw new FaultException<CustomizedError>(fault, "");
// return fault;
}
}
The soap message I want is
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<HeaderTag1>Hello HeaderTag1</HeaderTag1>
</s:Header >
<s:Body>
<s:Fault>
<BodyTag1>Hello BodyTag1</BodyTag1>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
Upvotes: 1
Views: 654
Reputation: 7532
I am confused that why you define the soap message structure in that format. But as far as I know, the IErrorHandler interface is able to custom the fault message when capturing the communication error. Here is an example used to capture the errors during communication.
Hadler Error EndPoint in my host - WCF - Behaviour
We are capable of adding the custom message header in the ProvideFault method. Please consider the below code.
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
FaultException faultException = new FaultException(error.Message);
MessageFault messageFault = faultException.CreateMessageFault();
fault = Message.CreateMessage(version, messageFault, error.Message);
MessageHeader mh = MessageHeader.CreateHeader("itemname", "apptest", "34");
fault.Headers.Add(mh);
}
Feel free to let me know if there is anything I can help with.
Updated.
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("http://localhost:4386");
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.None;
using (ServiceHost sh = new ServiceHost(typeof(TestService), uri))
{
sh.AddServiceEndpoint(typeof(ITestService), binding, "");
ServiceMetadataBehavior smb;
smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior()
{
HttpGetEnabled = true
};
sh.Description.Behaviors.Add(smb);
}
Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding();
sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
sh.Opened += delegate
{
Console.WriteLine("service is ready");
};
sh.Closed += delegate
{
Console.WriteLine("service is closed");
};
sh.Open();
Console.ReadLine();
sh.Close();
}
}
}
[ServiceContract]
public interface ITestService
{
[OperationContract]
int Div(int x, int y);
}
[ServiceBehavior]
public class TestService : ITestService
{
public int Div(int x, int y)
{
if (y == 0)
{
FaultReason reason = new FaultReason("The divisor cannot be Zero");
FaultCode code = new FaultCode("NotZero", "mynamespace",new FaultCode("mysubcode"));
throw new FaultException(reason,code);
}
return x / y;
}
}
In order to create ActivityID field, we should enable tracing and message logging on the server-side.
<system.diagnostics>
<sources>
<source name="System.ServiceModel" propagateActivity="true" switchValue="Information, ActivityTracing">
<listeners>
<add type="System.Diagnostics.XmlWriterTraceListener" name="xmlLog" initializeData="myLogs.svclog"/>
</listeners>
</source>
</sources>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="false"/>
</diagnostics>
</system.serviceModel>
Link.
About ActivityID field
Configure tracing and message logging
When the invocation on the client-side passes a parameter 0. We capture the http request by using fiddler.
Upvotes: 1