Best Practice in OData for exceptions - c#

We are consuming OData service using dot-net.
When any exception throws in the odata service code or any business logic problem fails, service code handles that exception or error and return dotnet consumer a new error object with that error details.
Is it good way of doing as I am thinking it should throw an exception and at consuming end I should handle it in my own way.
What are your suggestions ?

Both are OK. In both cases you need a specific manner to transfer the service status and error info:
// First case - the returned object contains status and error info.
IResponse response = OData.Serve();
if (response.Status == Status.Ok)
ManageResponse(response );
else
ManageError(response.Status, response.Error);
// Second case - service rises an exception.
IResponse response;
try
{
response = OData.Serve();
ManageResponse(response);
}
catch (ODataException e)
{
ManageError(e.Status, e.Error);
}
// Third case: Service returns correct response or null.
// In case of error Service contains error info.
IResponse response = OData.Serve();
if (response != null)
ManageResponse(response);
else
ManageError(OData.LastError);

You can also try something like this also :
try
{
//your Odata query and response code
}
catch (DataServiceClientException dsce)
{
logger.WarnFormat("Client Exception, Status Code - {0}", dsce.StatusCode.ToString());
}
catch (DataServiceRequestException dsre)
{
logger.WarnFormat("Request Exception - {0}", dsre.Message);
}
catch (DataServiceQueryException dsqe)
{
logger.WarnFormat("Query Exception, Status code - {0}", dsqe.Response.StatusCode.ToString());
}
Hope it helps :)

Related

How to catch a web service exception

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.

how to make sure a variable is set to a value and it can if tested in catch block

I am writing a proof of concept with a simple requirement where I load an account, make a webservice call to initiate payment and if it is successful update the account balance.
The intention of following code is to make sure some reversal is done if web service call was successful in taking money out of customer' bank but account could not be saved due to concurrency issue. However, I have this strange issue that even if response is successful, the if test in catch block returns false and the exception is re thrown?
edit begin:
if response.IsSuccessful is true and ConcurrencyException occurs at accountService.Save(account) line, shouldn't currentStatus be equal to WEBSERVICE_SUCCESSFUL ?
edit end:
This is a web application and call to Process() is triggered by front end. Am I missing anything obvious? Any help would be really appreciated.
function void Process(Account account, string param1, decimal param2) {
string currentStatus = "START";
try
{
log("Begin web service call");
var response = webservice.Call(param, param2);
log("End web service call");
if(response.IsSuccessful)
{
currentStatus = "WEBSERVICE_SUCCESSFUL";
//update account balance
accountService.Save(account);
}
else
{
// do something else
}
}
catch (ConcurrencyException ex)
{
log("Error concurrency..");
if( currentStatus == "WEBSERVICE_SUCCESSFUL")
//do reversal
else
throw ex;
}
}
Essentially you are looking for a Transaction. You should take a look at the System.Transactions() namespace which has been designed specifically for problems like this.
For example what would happen in the scenario when you server crashes at the exact point between taking payment and updating the balance?
Using the TransactionScope class not only are you abstracting away dealing with transactions yourself but it will automatically escalate to be managed by the MSDTC (if available) which will deal with server crashes such as this.
Everything below (such as Exceptions) will also automatically rollback the transaction.
Take a look at Writing a Transactional Application for more details.
accountService.Save(account) function may throw another exception which the catch block doesn't catch them. In this case try to replace ConcurrencyException by Exception
In addition to Ta Quans answer - it might be worth having both levels of exceptions caught as it seems your exception handler is specific to concurrency issues:
e.g.
try
{
some code....
}
catch (ConcurrencyException ex)
{
log("Error concurrency..");
if( currentStatus == "WEBSERVICE_SUCCESSFUL")
//do reversal
else
throw;
}
catch (Exception ex)
{
log("Some other error: " + ex.Message);
if( currentStatus == "WEBSERVICE_SUCCESSFUL")
//do reversal
else
throw;
}

Verbose exception with service operation

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.

SoapHeaderException was unhandled when calling web service

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.

Invoke operation 'myMethod' failed in RIA Services in Silverlight

I have a server-side WCF RIA Service that is intentionally throwing an exception because the user entered an invalid value. This exception comes across the wire, however, I can't figure out how to catch it. I currently have the following code:
try
{
DomainContext.CalculateRequest(OnCalculateCompleted, null);
}
catch (Exception ex)
{
MessageBox.Show("here");
}
...
private void OnCalculateCompleted(InvokeOperation response)
{
try
{
if (response.HasError == false)
{
// Do stuff with result
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
How do I handle exceptions thrown by a server-side operation on the client side? None of my catch statements are being triggered. Thank you!
On the client side the InvokeOperation.HasErrors will be true and you can get the Exception object from the InvokeOperation.Error. Note, if you handled the error you should also call MarkErrorAsHandled().
Your OnCalculateCompleted might looks something like this.
private void OnCalculateCompleted(InvokeOperation response)
{
if (response.HasError == false)
{
// Do stuff with result
}
else
{
MessageBox.Show(response.Error.Message);
response.MarkErrorAsHandled();
}
}
Yes, because in the callback (OnCalculateCompleted), exception will not be marshalled. The exception will reside in the response.Error property.
But take care, because your server-side thrown exception will NOT be found in the response.Error!
You should override your DomainService's OnError method, package your server-side exception via errorcodes or something, and on the client (SL) side, you have to unpack it again.

Categories