Error Handling with WCF Service and Client Application - c#

In my case, I have a WCF Service (MyService.svc). I also have a client application that is instantiating and consuming the service contract.
What is the best way to handle exceptions at the service level and "transmit" them over to the client in an orderly and self-describing way?
If I have an unhandled exception on the WCF service, it seems as though that bubbles back to the client application as a CommunicationException.
But what's the best way to throw an exception at the service-level and have that same exception transmitted to the client-level? Or if I don't handle an exception at the service-level (or just re throw it at the service-level) how can that get explicitly directed to the client?
Or is that not typically how this SOA would work? What's the "right way" here?
Thanks!

First, if you want to pass the exception over the protocol, you have to wrap it in a faultexception, otherwise you will get a server error.
Use the FaultContract attribute over methods to enable faultContract and define the message you want to pass using creating a Message contract:
public interface IMyService
{
[OperationContract]
[FaultContract(typeof(Message))]
void WCFOperation();
}
[DataContract(Namespace = "http://www.mycompany.pt/myservice")]
public class Message
{
String _code;
[DataMember]
public String Code
{
get { return _code; }
set { _code = value; }
}
String _text;
[DataMember]
public String Text
{
get { return _text; }
set { _text = value; }
}
}
To convert exceptions to FaultExceptions, i use the following helper:
class Helper
{
internal static System.ServiceModel.FaultException<Message> ConvertToSoapFault(MyException ex)
{
FaultCode fc = new FaultCode(ex.Code);
return new FaultException<Message>(new Message(){ Text= ex.Message, Code= ex.Code});
}
internal static System.ServiceModel.FaultException ConvertToSoapFault(Exception ex)
{
return new FaultException(ex.Message);
}
}
Finally, at the operationContract implementation, simple do this:
public void WCFOperation()
{
try
{
...
}
catch (Exception ex)
{
Helpers.publishError(ex);
throw Helpers.ConvertToSoapFault(ex);
}
}

Related

Returning meaningful error messages from a .NET Core API

Scenario
I have a .NET Core 2.2 web API with an exception handling middleware. Whenever an exception occurs in the application (inside the MVC layer) it gets caught by the exception middleware and returned as an internal server error back to the frontend and logged to kibana.
The problem
This is all fine and well when things go wrong, but sometimes I want to notify the calling application of specifically what went wrong. I.e., "Could not find record in database!" or "Failed to convert this to that!"
My Solution
I've used application Exceptions (not great - I know) to piggy back off the error middleware to return this to the frontend. This has been working fine, but has created a lot of noise around the code by having to throw a whole bunch of exceptions. I'm not satisfied with this approach and convinced that there must be a better solution.
My application architecture: I'm following a traditional n-tier application layout being services (business logic) and repositories (DAL) all speaking to each other. I would preferably like to elegantly bubble up any issues back to the user in any of these layers.
I've been thinking about this for a while now and am not sure what the best way to go about it is. Any advice would be appreciated.
I use a kind of the operation result pattern (non-official pattern).
The principle is to return a new Type containing:
Whether the operation was a success.
The result of the operation if was successful.
Details about the Exception that caused the failure.
Consider the following class:
public class OperationResult
{
protected OperationResult()
{
this.Success = true;
}
protected OperationResult(string message)
{
this.Success = false;
this.FailureMessage = message;
}
protected OperationResult(Exception ex)
{
this.Success = false;
this.Exception = ex;
}
public bool Success { get; protected set; }
public string FailureMessage { get; protected set; }
public Exception Exception { get; protected set; }
public static OperationResult SuccessResult()
{
return new OperationResult();
}
public static OperationResult FailureResult(string message)
{
return new OperationResult(message);
}
public static OperationResult ExceptionResult(Exception ex)
{
return new OperationResult(ex);
}
public bool IsException()
{
return this.Exception != null;
}
}
Then you could easily adapt OperationResult or create a class that inherits from OperationResult, but uses a generic type parameter.
Some examples:
The Operation Result Pattern — A Simple Guide
Error Handling in SOLID C# .NET – The Operation Result Approach
As per the Microsoft's standards, it is ideal to use ProblemDetails object in case of 4xx/5xx exceptions -
Following is the customised RequestDelegate method which you can use in ApiExceptionHandler to handle exceptions.
public async Task RequestDelegate(HttpContext context)
{
var exception = context.Features.Get<IExceptionHandlerFeature>().Error;
var problemDetails = new ProblemDetails
{
Title = "An unexpected error occurred!",
Status = GetStatusCode(exception),
Detail = _env.IsDevelopment() ? exception.Message : "An unexpected error occurred!",
Instance = $"{Environment.MachineName}:{context.TraceIdentifier}:{Guid.NewGuid()}"
};
_logger.LogError($"Exception thrown. StatusCode: {problemDetails.Status}. Instance: {problemDetails.Instance}", exception);
context.Response.StatusCode = problemDetails.Status.Value;
context.Response.WriteJson(problemDetails, "application/problem + json");
await Task.CompletedTask;
}

Exception handling strategy - Catching exceptions from repository and passing into WebApi Controller

Forgive me for my ignorance but at the moment I'm struggling to figure out the best approach to catch an exception and display a message to the client based on an exception type.
My architecture:
Repository
Page IPageRepository.FindDefault()
{
try
{
return MapPageFromCategory.MapFromEntity(_context.tbl_Category.
FirstOrDefault(p =>
p.IsLandingPage == true
)
);
}
catch (Exception ex)
{
throw new ApplicationException("Error getting values from database :", ex);
}
}
With the above as you can see it just fetches data from the DB, but in some scenarios I could get a object not set to an instance of an object exception due to physically no data in the table or a Null exception depending on the data passed in.
Now in both scenario I would like to generate a 404 exception which passes to my controller.
Controller
public class PageController : ApiController
{
private IPageRepository _pageRepository;
public PageController(IPageRepository pageRepository)
{
this._pageRepository = pageRepository;
}
// GET
[HttpGet]
[Route("")]
public Page Get()
{
return this._pageRepository.FindDefault();
}
}
My Controller hit's the method and if any of those exceptions are hit, what would be the best approach to intercept those exceptions and pass to the end client (Calling app) ?
Again apologies for the question, really trying to create some sort of systematic approach to exception handling.
Thanks for your time!
You can either have a separate try/catch in the Controller class and handle the exception thrown from repository there or do something different.
You can create a class similiar to this:
public class Result
{
public bool Succeded { get; private set; }
protected Result(bool succeeded)
{
Succeded = succeeded;
}
}
public class Result<TData> : Result
{
public TData Data { get; private set; }
protected Result(bool succeeded, TData data) : base(succeeded)
{
Data = data;
}
}
Then, you can return this from your repository and check in the controller if the call has succeeded. If not, throw a desired exception, which will set StatusCode accordingly.

Providing failure status for WCF service

I have a WCF service that I call the following way:
MyService client = new MyService();
bool result = client.MyServiceMethod(param1, param2);
Variable result is set to true or false to indicate success or failure. In case of success it is clear but in case of failure I need to get some details on what failed.
From my service I use
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = HttpStatusCode.BadRequest;
response.StatusDescription = "Invalid parameter.";
return false;
My question is how do I retrieve the response description and is that the correct way to provide failure feedback?
IMO it is best to define a custom class that you then return from your method. This class would contain the details of any errors. You do this using DataContracts.
A simplified example might be something like this...
[ServiceContract]
public interface IMyContract
{
[OperationContract]
MyResult DoSomething();
}
[DataContract]
public class MyResult
{
[DataMember]
public bool IsSuccess { get; set; }
[DataMember]
public string ErrorDetails { get; set; }
}
public class MyService : IMyContract
{
public MyResult DoSomething()
{
try
{
return new MyResult { IsSuccess = true };
}
catch
{
return new MyResult { IsSuccess = false, ErrorDetails = "Bad things" };
}
}
}
EDIT: Including consuming code per comment.
var client = new MyService();
var results = client.DoSomething();
if (results.IsSuccess)
{
Console.WriteLine("It worked");
}
else
{
Console.WriteLine($"Oops: {results.ErrorDetails}");
}
Generally you communicate problems to the client(s) using SOAP MSDN:Faults. Special advantage of faults is that WCF will ensure that your channel stays open after receiving fault message. By default, the service does not send any information explaining what happened. WCF does not reveal details about what the service does internally. See MSDN:Specifying and Handling Faults in Contracts and Services for more details. Also see SO:What exception type should be thrown with a WCF Service?
For debugging purposes you can add ServiceDebug behavior and set IncludeExceptionDetailInFaults to true to get the stack trace (in non-production environments)

Wcf service exception good practices

I am developing a distributed application. In it, there are roles and sets of permissions that I must validate.
Is a good pratice to throw an exception, in per example, unauthorized access?
Or should I send some message back to the client?
On your service operation, you can specify a FaultContract that will serve both purposes like so:
[OperationContract]
[FaultContract(typeof(MyServiceFault))]
void MyServiceOperation();
Note that MyServiceFault must be marked with DataContract and DataMember attributes, in the same way you would a complex type:
[DataContract]
public class MyServiceFault
{
private string _message;
public MyServiceFault(string message)
{
_message = message;
}
[DataMember]
public string Message { get { return _message; } set { _message = value; } }
}
On the service-side, you are then able to:
throw new FaultException<MyServiceFault>(new MyServiceFault("Unauthorized Access"));
And on the client-side:
try
{
...
}
catch (FaultException<MyServiceFault> fault)
{
// fault.Detail.Message contains "Unauthorized Access"
}
Well, you can catch all exceptions in the WCF service implementations methods and rethrow them as FaultExceptions. By doing it this way, the exception will be rethrown on the client with a message of your choosing:
[OperationContract]
public List<Customer> GetAllCustomers()
{
try
{
... code to retrieve customers from datastore
}
catch (Exception ex)
{
// Log the exception including stacktrace
_log.Error(ex.ToString());
// No stacktrace to client, just message...
throw new FaultException(ex.Message);
}
}
To avoid having unexpected errors relayed back to the client, it's also a good practice to never throw Exception instances in code on the server-side. Instead create one or more of your own exception types and throw them. By doing so, you can distinguish between unexpected server processing errors and errors that are thrown due to invalid requests etc:
public List<Customer> GetAllCustomers()
{
try
{
... code to retrieve customers from datastore
}
catch (MyBaseException ex)
{
// This is an error thrown in code, don't bother logging it but relay
// the message to the client.
throw new FaultException(ex.Message);
}
catch (Exception ex)
{
// This is an unexpected error, we need log details for debugging
_log.Error(ex.ToString());
// and we don't want to reveal any details to the client
throw new FaultException("Server processing error!");
}
}
Throwing general Dot Net Exceptions would make the service client proxies and the server channel to go in faulted state if you are not using basicHTTPBinding ...To avoid that you should always throw FaultException from the service...
from you catch block just use:
throw new FaultException("Your message to the clients");

WCF service throwing weird exception

after 2 days of trying to find out why my service isn't working I finally find the cause. Everytime I try to throw a new FaultException<AuthenticationException>, the server isn't actually throwing this but catching it itself.
So what is happening is that when I throw the exception the server is crashing with an unhandled System.ServiceModel.FaultException1`.
Here is my custom exception class:
[DataContract]
public class AuthenticationException
{
private string validationError;
[DataMember]
public string ValidationError
{
set { validationError = value; }
get { return validationError; }
}
public AuthenticationException()
{
}
public AuthenticationException(string valError)
{
validationError = valError;
}
}
And my interface:
[ServiceContract]
public interface IAuthenticator
{
[OperationContract]
[FaultContract(typeof(AuthenticationException))]
Account authenticateApplication(string userName, string Password);
What can cause this?
Edit: This is how I am throwing the exception:
catch (Exception)
{
throw new FaultException<AuthenticationException>(new AuthenticationException("There was a general error during the process."), new FaultReason("Error"));
}
Maybe your IIS server is not configured to allow passing exception to the client.
Follow the step 2 "Enable detailed errors for remote clients." of this post

Categories