I'm using C# to build a service operation. When something goes wrong, I want to throw an exception that could be catch client side.
However, when an exception is thrown the client is only able to get a generic error like "400: bad request" and the exception message is not accessible.
In my service operation, I have enabled verbose errors with this:
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
and
config.useVerboseErrors = true;
I also unpack the TargetInvocationException and instead return a DataServiceException with this function:
protected override void HandleException(HandleExceptionArgs args)
{
// Handle exceptions raised in service operations.
if (args.Exception.GetType() == typeof(TargetInvocationException)
&& args.Exception.InnerException != null)
{
if (args.Exception.InnerException.GetType() == typeof(DataServiceException))
{
// Unpack the DataServiceException.
args.UseVerboseErrors = true;
args.Exception = args.Exception.InnerException as DataServiceException;
}
else
{
// Return a new DataServiceException as "400: bad request."
args.UseVerboseErrors = true;
args.Exception = new DataServiceException(400, args.Exception.InnerException.Message);
}
}
}
When I use the browser, I can see the verbose exception message, but when I try programmatically, the inner exception is null and I only see the generic error message "400: bad request".
Strangely, if I return a code 200 instead of 400, I can see the exception message in the answer body. But obviously I don't want to do this.
So, is there a way to get the exception message client side, when you throw an exception from a service operation?
Have you had a look at end to end tracing? Furthermore, this MSDN page isn't as daunting as it may first seem, and i think the "Provide Additional Information When an Exception Occurs" section would be useful to you. Have a lovely read.
Related
I have the following code:
finally
{
if (!isDnsSet)
{
var exception = new Exception(<DNS-INFORMATION>);
localLog.TraceException(exception);
throw exception;
}
}
As it stands, this exception throws too much information to the user that is not particularly needed for them to see. I want to be able to log exception using my localLog class but also throw another exception with a more concise message.
I was thinking to just create another exception with the shortened message and still log the original, more verbose one using my class.
Is there a more elegant way of doing this or would I just do something like:
var shortException = new Exception(<short and sweet message>);
var longException = new Exception(<not so short and sweet but still useful for other devs>);
localLog.TraceException(longException);
throw shortException;
I think a cleaner method would be to make the longer exception an inner exception:
finally
{
if (!isDnsSet)
{
var innerException = new Exception(<not so short and sweet but still useful for other devs>);
var exception = new Exception(<short and sweet message>, innerException);
localLog.TraceException(exception);
throw exception;
}
}
That way you have consistency between the exception that's thrown and the exception that's logged, making diagnosis easier.
One approach is to create a custom exception that carries both a long and a short message. Users who get the exception outside your library would access the short message through Exception's Message property, while your TraceException method would access the long version through an additional property provided by your custom exception:
public class DetailedException : Exception {
public string DetailedMessage { get; }
public DetailedException(string longMessage, string shortMessage) : base(shortMessage) {
DetailedMessage = longMessage;
}
}
Inside TraceException method:
var message = (exception as DetailedException)?.DetailedMessage ?? exception.Message;
Couldn't the exception handler receive and process the longException and, as part of its function, throw the shortException?
I am trialling the FirstChangeException event handler for the service layer of my WCF. The aim is to capture the exception from any method and throw it as a new FaultException so it can pass back to the client.
For example below is a test server class
private static bool thrown;
public class EchoService : _BaseService, IEchoService
{
public EchoService()
{
AppDomain.CurrentDomain.FirstChanceException += HandleFirstChanceException;
}
private void HandleFirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
if (thrown == false)
{
thrown = true;
throw new FaultException<Exception>(e.Exception);
}
}
public DTO_Echo_Response SendEcho(DTO_Echo_Request request)
{
DTO_Echo_Response response = new DTO_Echo_Response();
//SO note: AppError inherits from Exception.
if (request.ThrowTestException) throw new AppError("Throwing test exception");
return response;
}
}
However, on exiting the function on the return line because the previous call was from the throwing the new exception, I get the following error.
The runtime has encountered a fatal error. The address of the error was at 0x750916ed, on thread 0x1d5c. The error code is 0x80131506. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
I must be doing something stupid. How can I achieve my aim of a catch all exception handler?
You are using the FirstChanceException Event here, which is just a notification, not a place to handle exceptions.
What you probably want is both of
Application.ThreadException
AppDomain.CurrentDomain.UnhandledException
There are already lots of questions on that topic.
Just have a look here on ThreadException
Also investigate on
Application.SetUnhandledExceptionMode
Exception handling in WCF is explained here:
handling exceptions in WCF right
WCF exceptionn handling
I have the following code courtesy of an answer posted by Jean-Michel Bezeau
bool isAlive = false;
string fixedAddress = "http://localhost:8732/Design_Time_Addresses/WCFService/mex";
System.ServiceModel.Description.ServiceEndpointCollection availableBindings = System.ServiceModel.Description.MetadataResolver.Resolve(typeof(WCFService.IAlive), new EndpointAddress(fixedAddress));
ChannelFactory<WCFService.IAlive> factoryService = new ChannelFactory<WCFService.IAlive>(availableBindings[0]);
WCFService.IAlive accesService = factoryService.CreateChannel();
isAlive = accesService.IsAlive();
I would like my program to continue even if the WCF Service can't be reached so that I can notify someone via email and add it to a log. I thought of doing it like this:
bool isAlive = false;
try
{
string fixedAddress = "http://localhost:8732/Design_Time_Addresses/WCFService/mex";
System.ServiceModel.Description.ServiceEndpointCollection availableBindings = System.ServiceModel.Description.MetadataResolver.Resolve(typeof(WCFService.IAlive), new EndpointAddress(fixedAddress));
ChannelFactory<WCFService.IAlive> factoryService = new ChannelFactory<WCFService.IAlive>(availableBindings[0]);
WCFService.IAlive accesService = factoryService.CreateChannel();
isAlive = accesService.IsAlive();
}
catch {}
finally
{
if (isAlive)
{
//add success message to log
}
else
{
//add warning message to log
//send email notification
}
}
However, I don't like catching all exceptions like that (I know it's bad practice). What's the best way to go about this?
Are there particular exceptions I should be catching? Or, is this a good time to implement a using statement (if so can I have some help with how)?
The exception could be lots of things - it might be just a timeout, or a 404 error, a 500 error, a connection reset error... so there's probably a bunch of exceptions that can be thrown. In this particular case I wouldn't have a problem with a global catch.
You might want to consider retries as well, if it fails the first time try again, in case it was just a timeout.
Alternatively if you already have global error handling on your app, you might not want to swallow the exception, so you could just use the finally block without the catch:
try
{
....
}
finally
{
....
}
But you'd only want to do this if it was a genuine error that the app couldn't handle or resolve by itself.
How do you catch exceptions from a Web Service that is returning a custom object?
I've seen this post but it doesn't seem to show how to get the exception that was thrown by the service.
I can pull the SOAP Exception, but I want to be able to get the original exception that the web service returned. I've looked at the variables that are set at this time and can't seem to see the exception anywhere, I just see:
"Server was unable to process request. ---> Exception of type
'RestoreCommon.ConsignmentNotFoundException' was thrown."
try
{
Consignment cons = WebServiceRequest.Instance.Service
.getConsignmentDetails(txtConsignmentNumber.Text);
lblReceiverName.Text = cons.Receiver.Name;
}
catch (ConsignmentNotFoundException)
{
MessageBox.Show("Consignment could not be found!");
}
Is this possible?
In short, no.
Web services will always throw SOAP fault. In your code,
MessageBox meant to be used in Windows forms and nowhere else.
You can throw this exception and in the client application, you will have to handle a SOAP fault.
Edit: If you do not want to send exceptions across to the client, this what you could do:
class BaseResponse
{
public bool HasErrors
{
get;
set;
}
public Collection<String> Errors
{
get;
set;
}
}
Each WebMethod response must inherit from this class. Now, this is how your WebMethod blocks would look like:
public ConcreteResponse SomeWebMethod()
{
ConcreteResponse response = new ConcreteResponse();
try
{
// Processing here
}
catch (Exception exception)
{
// Log the actual exception details somewhere
// Replace the exception with user friendly message
response.HasErrors = true;
response.Errors = new Collection<string>();
response.Errors[0] = exception.Message;
}
finally
{
// Clean ups here
}
return response;
}
This is just an example. You may need to write proper exception handling code rather than simply using generic catch block.
Note: This will take care of exceptions occurring in your application only. Any exceptions occurring during communication between client and service, will still be thrown to the client application.
An exception occurs on line
ModifyProfileResp resp = BFGlobal.modifyProfile(req);
INTERNAL_ERROR, SoapHeaderException was unhandled
Error: System.Exception._COMPlusExceptionCode -532462766,
This code basically updates the users information on a web service through a call I made.
public ModifyProfileResp ModifyProfile(string n_homeTelephone)
{
try
{
// Get Login Resp
LoginResp loginResp = LoginToBetfair("username", "password");
// Make a BFGS instance
BFGlobal = new BFGlobalService();
// Set up the request in [req]
ModifyProfileReq req = new ModifyProfileReq();
req.header = new APIRequestHeader();
req.header.sessionToken = loginResp.header.sessionToken;
req.homeTelephone = n_homeTelephone;
// Set up the response in [resp]
// Here is where Im getting thrown an exception..
ModifyProfileResp resp = BFGlobal.modifyProfile(req); // <-- Here Im getting thrown an exception
// return [resp] - which is the response from the call
// Just trying to print out errror codes
string mec = resp.minorErrorCode.ToString();
string ec = resp.errorCode.ToString();
return resp;
}
catch (Exception)
{
throw;
}
Pretty straightforward, make the request header, call the response, pass in the req and I should get some data back, but I keep getting thrown a exception on this line.
Any ideas on how to go about this?
First,
don't do this:
catch (Exception)
{
throw;
}
It's pointless. If you don't have the catch the exception will automatically get thrown up a level, which is what you're doing with throw. Further, if you can't do something with the exception (like retry the request) you're probably better off letting the exception bubble up.
Second, try something like this:
catch (SoapHeaderException ex)
{
Debug.WriteLine(ex.Message);
}
This will catch the specific exception that you're dealing with. Further, set a breakpoint here on the Debug statement. You can then browse the details of the exception. You'll be able to see the stacktrace, inner exceptions and any other data that the thrower of the SoapHeaderException might want you to see.
This information can often be useful when you're debugging, for example, it could say "You forgot to initialize the flux capacitor."
You're seeing an exception from the remote web service.
SoapHeaderException Class
The exception that is thrown when an XML Web service method is called over SOAP and an exception occurs during processing of the SOAP header.
Likely you're not setting up your headers as the remote service requires. Try to acquire help from the remote side.
Try viewing the .InnerException for more details.