Send Custom response from ProvideFault() method in WCF - wcf

I am using IErrorHandler to catch the exceptions for handling and logging purpose in my WCF service. I catch exception in ProvideFault(.....) method and from here I send Fault Exception to the client.
Below is the sample code for it..
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
FaultException<MyResponse> fe = new FaultException<MyResponse>(
new ErrorResponse
{
MessageCode = "ERR001",
MessageDetail = "Error Occured at server Side"
});
MessageFault faultMsg = fe.CreateMessageFault();
fault = Message.CreateMessage(version, faultMsg, fe.Action);
}
Where MyResponse is the custom type.
Now due to some requirement change, I donot want to send FaultMessage from service. Can I send the MyResponse object from ProvideFault method? Something like as..
MyResponse response = new MyResponse();
response.MessageCode = "ERR001";
response.MessageDetail = "Error Occured at server Side";
Message.CreateMessage(version, response, response.Action);
So this can be handled at the client for all scenarios. The reason for this change is that all the client may not handling FaultException.
I do not want to use try catch in my service and send response from catch, instead I want to use IErrorHandler for this.
Any suggestions would be highly appreciated.

Related

wsHttpBinding, catch FaultException from custom UserNamePasswordValidator

I have a WCF service with wsHttpBinding. Everything works just fine, but I have got problem with catching faults on my client, sent from my custom Authenticator.
I use custom Authenticator code from msdn:
https://msdn.microsoft.com/en-us/library/aa702565(v=vs.110).aspx
// This throws an informative fault to the client.
throw new FaultException("Unknown Username or Incorrect Password");
this comment says that we are throwing an informative fault to the client, but i can't catch it on the client side:
bool isReachable = false;
try {
isReachable = client.agentIsReachable();
}
catch(FaultException faultException){
MessageBox.Show(faultException.Message);
}
While debugging I can see, that a fault is thrown, but my clients catch code does not work. My communication channel faults, but without fault exception. Then i catch a .NET ex, saying that I am trying to use faulted proxy.
Everything works great when i throw faults from any of my service methods. I can catch them on my client.
Is it really possible to catch faults, sent from Authenticator. And what is the best way to pass an informative message to the client when authentication fails?
Client-side, the exception you have to catch is not a FaultException but a MessageSecurityException (using System.ServiceModel.Security).
Then you can retrieve your FaultException with the InnerException attribute of the MessagSecurityException you caught. In your case, you'll end up with something similar to this:
catch (MessageSecurityException e)
{
FaultException fault = (FaultException) e.InnerException;
MessageBox.Show(faultException.Message);
}
I hope it will help.

WCF Service rest error handling using WebFaultException

I need to handle the exception in WCF Service application.
But in the windows application I can't get the error message. It's only display as Bad Request.
In the WCF Service throw the following exception.
throw new WebFaultException<string>(string.Format("Invalid Client ID.", clientID), HttpStatusCode.BadRequest);
In your windows application (client), you have to catch the exception and get the detail of the error
try
{
client.YourServiceMethod();
}
catch (FaultException<string> ex)
{
MessageFault messageFault = ex.CreateMessageFault();
Console.WriteLine(messageFault.GetDetail<string>());
}

Silverlight fault propagation and UserNamePasswordValidator

Scenario is a Silverlight client using Wcf service & custom authentication. To mitigate the 500/200 status code problem (avoid EndPointNotFound exception) I've applied the SilverLightFaultBehaviour. However, this does not work with UserNamePasswordValidator - When a FaultException is thrown from Validate(), it is not caught by the SilverLightFaultMessageInspector's implementation of BeforeSendReply.
So far, the only workaround I've found is using the alternative client stack instead ( WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);), but there are complications with using it which can no longer be ignored as a lot of our clients are on virtual machines, the silverlight client keeps crashing ( Silverlight 5 - Debugging npctrl.dll crash , http://communities.vmware.com/thread/394306?tstart=0 ).
My primary motivation is that I want to be able to distinguish a failed login from a connection error (the following code is from a client-side async callback method, and only works with the Client stack):
if (e.Error is MessageSecurityException)
{
this.HasLoginFailed.Value = Captions.Login_FailedLogin;
}
else
{
this.HasLoginFailed.Value = Captions.Login_FailedConnection;
}
Is there any other way of modifying the message sent when throwing a FaultException from UserNamePasswordValidator? Or any conceptually different way of doing custom authentication rather than what I am using which enables me to modify the message status or to keep it 200, or just to be able to distinguish a connection failure from bad credentials?
my server-side code for usernamepassword reg:
var serviceCredential = host.Description.Behaviors.Find<ServiceCredentials>();
serviceCredential.UserNameAuthentication.UserNamePasswordValidationMode =
UserNamePasswordValidationMode.Custom;
serviceCredential.UserNameAuthentication.CustomUserNamePasswordValidator =
new MyValidator();
When you throw a FaultException from MyValidator, it is wrapped as the InnerException of a MessageSecurityException, that's probably why you weren't able to catch it directly as a FaultException.
To add some information to the fault you are throwing, what you can do is adding a FaultCode:
throw new FaultException(
"Invalid user name or bad password.",
new FaultCode("BadUserNameOrPassword")
);
Then, catch the exception client-side and retrieve your FaultCode:
try { ... }
catch (MessageSecurityException e)
{
FaultException fault = (FaultException) e.InnerException;
String faultCode = fault.Code.Name;
// you can now display a meaningful error with the faultCode
}
I hope it will help!

Retrieve WCF Rest Response in Client

I'm using the WebChannelFactory<> to create a channel and interact with a WCF REST Service.
When there is an error, I want to retrieve the response from the channel to read the error message from the body of the response. But I cannot figure out how to get the response stream.
Here is my code:
using (var cf = new WebChannelFactory<T>(new Uri(url)))
{
var channel = cf.CreateChannel();
using (new OperationContextScope(channel as IContextChannel))
{
WebOperationContext.Current.OutgoingRequest.Headers
.Add("x-st-authtoken", HttpUtility.UrlDecode(Constants.General_AuthorizedToken));
WebOperationContext.Current.OutgoingRequest.Headers
.Add("x-st-tesskey", HttpUtility.UrlDecode(Constants.General_SessionKey));
try
{
a(channel);
}
catch (Exception ex)
{
throw new Exception("Status: " + ((int)WebOperationContext.Current.IncomingResponse.StatusCode).ToString());
}
}
}
In the catch statement, I want to include the data from the Response body...
It seems like an obvious thing, but I can't seem to find any information on the internet or anything.
Is there any specific reason for you to use ChannelFactory to interact with the REST service. I think it is easier to use HttpWebRequest object to invoke the REST service and there you can get the respone stream when an error is throw on the server.
Also check out RestSharp API through which you can achieve your task to read the response stream.
I believe it will throw a WebException.
so if you explicitly catch that type you can get use the WebException.Response property (which is an HttpWebReponse) on the exception and you can get the content from its stream.

WCF FaultException - crashes App Pool when "re-throwing" from internal WCF call

I have a WCF service that's hosted in IIS, and uses a WS HTTP binding (the external service). This service ends up calling a second WCF service that's hosted in a Windows service, over Net TCP (the internal service). When the internal service throws a FaultException, the external service crashes rather than throwing it to the client. All the client sees is the connection being forcibly closed.
The internal service uses the Enterprise Library Validation Application Block to validate the incoming messages. When validation errors occur, the service throws a FaultException<ValidationFault>.
Both the internal and external service have a [FaultContract(typeof(ValidationFault)] attribute in the service contract. If I change the external service to just immediately throw a new FaultException<ValidaitonFault>, this gets back to the client fine. I can catch the exception from the internal service in the external service, but if I try to re-throw it, or even wrap it in a new exception and throw that, the whole Application Pool in IIS crashses. I can't see anything useful in the event log, so I'm not sure exactly what the problem is.
The client object the external service uses to communicate with the internal service is definitely being closed and disposed of correctly. How can I get the internal service's faults to propagate out to the client?
updated:
Below is a simplified version of the external service code. I can catch the validation fault from the internal service call. If I throw a brand new FaultException<ValidationFault>, everything is fine. If I use the caught exception, the connection to the external client is broken. The only difference I can see is when debugging the service - trying to use the caught exception results in a message box appearing when exiting the method, which says
An unhandled exception of type
'System.ServiceModel.FaultException`1'
occurred in mscorlib.dll
This doesn't appear if I throw a brand new exception. Maybe the answer is to manually copy the details of the validation fault into a new object, but this seems crazy.
public class ExternalService : IExternalService
{
public ExternalResponse DoSomething(ExternalRequest)
{
try
{
var response = new ExternalResponse();
using (var internalClient = new InternalClient())
{
response.Data = internalClient.DoSomething().Data;
}
return response;
}
catch (FaultException<ValidationFault> fEx)
{
// throw fEx; <- crashes
// throw new FaultException<ValidationFault>(
// fEx.Detail as ValidationFault); <- crashses
throw new FaultException<ValidationFault>(
new ValidationFault(new List<ValidationDetail> {
new ValidationDetail("message", "key", "tag") }),
"fault message", new FaultCode("faultCode"))); // works fine!
}
}
}
I have almost the exact design as you and hit a similar issue (not sure about a crash, though!).
If I remember correctly, even though the ValidationFault is a common class when the Fault travels over the wire the type is specific to the WCF interface. I think this is because of the namespace qualifiers on the web services (but this was a while back so I could be mistaken).
It's not terribly elegant, but what I did was to manually re-throw the exceptions:
try
{
DoStuff();
}
catch (FaultException<ValidationFault> fe)
{
HandleFault(fe);
throw;
}
...
private void HandleFault(FaultException<ValidationFault> fe)
{
throw new FaultException<ValidationFault>(fe.Detail as ValidationFault);
}
Well, it works if I do this, but there must be a better way...
This only seems to be a problem for FaultException<ValidationFault>. I can re-throw FaultException and FaultException<SomethingElse> objects with no problems.
try
{
DoStuff();
}
catch (FaultException<ValidationFault> fe)
{
throw this.HandleFault(fe);
}
...
private FaultException<ValidationFault> HandleFault(
FaultException<ValidationFault> fex)
{
var validationDetails = new List<ValidationDetail>();
foreach (ValidationDetail detail in fex.Detail.Details)
{
validationDetails.Add(detail);
}
return new FaultException<ValidationFault>(
new ValidationFault(validationDetails));
}