Can't send exceptions from my WCF application - c#

Following the tutorial here
http://beyondrelational.com/modules/2/blogs/79/posts/11543/throwing-exceptions-from-wcf-service-faultexception.aspx
I ended up wit the following code:
Interface:
[ServiceContract]
public interface IAuthenticator
{
[OperationContract]
[FaultContract(typeof(AuthenticationException))]
Account authenticateApplication(string userName, string Password);
}
Exception:
[DataContract]
public class AuthenticationException
{
private string validationError;
[DataMember]
public string ValidationError
{
set { validationError = value; }
get { return validationError; }
}
public AuthenticationException(string valError)
{
validationError = valError;
}
}
And finally this is how I throw errors in my implementation of authenticateApplication:
catch (InvalidUsernameException)
{
throw new FaultException<AuthenticationException>(new AuthenticationException("The username you entered could not be found in our database."), new FaultReason("Error"));
}
The problem with this is that instead of sending the error back to the client, the app WCF app is crashing saying I didn't handle the exception.
If it matters, here is how I call from my client:
try
{
myAcc = httpProxy.authenticateApplication("some text", "some other text");
}
catch (FaultException<AuthenticationException> ex)
{
MessageBox.Show(ex.Detail.ValidationError);
return;
}
Edit: Here is my stack trace:
at AuthenticatorService.Authenticator.authenticateApplication(String userName, String Password) in E:\Miscellaneous\Applications\Web 2.0 Creator\AuthenticatorService\AuthenticatorService\AuthenticatorService\Authenticator.cs:line 109
at SyncInvokeauthenticateApplication(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
Edit Edit:
Here is the full try catch block:
try
{
using (myConnection)
{
using (myCommand)
{
//Tell it to execute the stored procedure on the database
myCommand.CommandText = "findUsername";
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.Parameters.Add("#userName", SqlDbType.NVarChar, 20);
myCommand.Parameters["#userName"].Value = userName;
//If the reader returns 0 rows, that means the username doesn't exist in the database, so step there and return an exception
using (myReader)
{
myReader = myCommand.ExecuteReader();
if (myReader.HasRows == false)
{
InvalidUsernameException iue = new InvalidUsernameException();
throw iue;
}
else //Else we store the fields
{
myAcc.Password = myReader[1].ToString();
isActive = Convert.ToBoolean(myReader[2]);
myAcc.Key = myReader[3].ToString();
myAcc.ExpiryDate = myReader[4].ToString();
}
}
}
}
}
catch (SqlException)
{
throw new FaultException<AuthenticationException>(new AuthenticationException("There was an error while connecting the database, please contact support."), new FaultReason("Error"));
}
catch (InvalidOperationException)
{
throw new FaultException<AuthenticationException>(new AuthenticationException("An error in the program while connecting to the database."), new FaultReason("Error"));
}
catch (InvalidUsernameException)
{
throw new FaultException<AuthenticationException>(new AuthenticationException("The username you entered could not be found in our database."), new FaultReason("Error"));
}
catch (Exception)
{
throw new FaultException<AuthenticationException>(new AuthenticationException("There was a general error during the process."), new FaultReason("Error"));
}

Try adding a parameterless constructor to the AuthenticationException class. Or:
[DataContract]
public class AuthenticationException
{
[DataMember]
public string ValidationError { get; set; }
}
and in your service:
throw new FaultException<AuthenticationException>(
new AuthenticationException
{
ValidationError = "The username you entered could not be found in our database."
},
new FaultReason("Error")
);
Also bare in mind that this works only for exceptions that are occuring inside the try/catch block. If there's some other exception occurring in some other part of the service that is not translated to a FaultContract you won't catch it as FaultException<T> on the client.
Also it is recommended to centralize the exception handling of your WCF service at a single location by using a custom IErrorHandler that will propagate the faults instead of putting try/catch blocks all around your code.

Looks like you need to call myReader.Read before accessing its fields.

I found the answer to my problem at this page:
http://sergecalderara.wordpress.com/2008/11/25/systemservicemodelfaultexception1-was-unhandled-by-user-code/
You need to disable these visual studio options:

Related

Catch Actual Error details from SOAP API in C#

Accessing SoapAPI in C# i have WSDL File Added as SeriviceRefrence in my c# classLinrery some how i am unable to catch actual Exception thrown by that API
I am getting ErrorMessage :-"An exception has been raised as a result of client data".
InnerException:-Null,
For Catching Actual Exception I tried below code:-
public RegisterResponse1 RegisterAccount()
{
try
{
var upss = CreateAccessRequest();
//Process Request
var responce = regService.ProcessRegister(CreateRegisterWebServiceRequest(shipment));
return responce;
}
catch (SoapException ex)
{
//I never go here
return null;
}
catch (FaultException ex)
{
//always go there
return null;
}
catch (Exception ex)
{
return null;
}
}
In Above exception handling i always fouling to FaultException (ex) the above errorMessaeg from FaultException
When i try to request this API from SoapUI(readyAPI) tool manually i got below Error details which is actual error from API side that error I want in my c# Library See the below actual ERROR DETAILS
"Invalid access License Number" is Actual Message that i want to fetch
Please help me to catch that Actual Error Details "Invalid access License Number" in c# instead error-exception has been raised as a result of client data
Thank you in Advance
Yes, I fought this issue for quite a while on my own project, and finally found the solution. The WSDL generator has a problem where it mis-generates the fault object, which is why you can't access it.
To diagnose what's going on under the covers, you can use a tool like Fiddler, and monitor the traffic. UPS is returning a fault detail that has a message that will tell you what's wrong, but you can't see it because of the badly generated object.
To fix this problem in any of the UPS APIs, go into the generated Reference.cs, and just after the namespace declaration, add this class:
// The WSDL generator doesn't properly generate the Errors Class. This was taken from the UPS Samples. The FaultContractAttribute was also updated to use this class instead.
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.7.2612.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1")]
public partial class Errors : object, System.ComponentModel.INotifyPropertyChanged
{
private ErrorDetailType[] errorDetailField;
private string testElementField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("ErrorDetail", Order = 0)]
public ErrorDetailType[] ErrorDetail
{
get
{
return this.errorDetailField;
}
set
{
this.errorDetailField = value;
this.RaisePropertyChanged("ErrorDetail");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order = 1)]
public string TestElement
{
get
{
return this.testElementField;
}
set
{
this.testElementField = value;
this.RaisePropertyChanged("TestElement");
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null))
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
Then search in the file for for FaultContractAttribute. Change it to:
[System.ServiceModel.FaultContractAttribute(typeof(Errors), Action="http://onlinetools.ups.com/webservices/ShipBinding/v1.1", Name="Errors", Namespace="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1")]
You may need to adjust the namespace in the typeof() statement.
Then a block like this will catch/return the error messages:
catch (FaultException<Errors> ex)
{
return new MyResult
{
ErrorMessage =
$"UPS returned the following errors: {string.Join(", ", ex.Detail.ErrorDetail.Select(ed => ed.PrimaryErrorCode.Description))}"
};
}
That will give you the full error from the UPS API call, and you can read the API docs from there to know what's wrong.
In my case the real error description was:
Hard9264030The state is not supported in the Customer Integration
Environment.
I realized that just NY and CA states in US are valid using my current sandbox credentials. So I suggest you change the code this way to check which error show up for you.
public RegisterResponse1 RegisterAccount()
{
try
{
var upss = CreateAccessRequest();
//Process Request
var responce = regService.ProcessRegister(CreateRegisterWebServiceRequest(shipment));
return responce;
}
catch (SoapException ex)
{
//=====================================================================
//put this code here and you will see the correct description of the error
var error = ex.Detail.InnerText;
Console.WriteLine(error);
return null;
}
catch (FaultException ex)
{
//always go there
return null;
}
catch (Exception ex)
{
return null;
}
}

Exceptions in WCF services

I have the following code in my ServiceBase abstract class:
internal ServiceResponse ExecuteNonQuery(Action action)
{
try
{
action();
return new ServiceResponse() { IsFaulty = false };
}
catch (DbEntityValidationException e)
{
OnDbEntityValidationException(e);
return new ServiceResponse() { IsFaulty = true, Exception = e};
}
catch (Exception e)
{
_logger.Log(e);
return new ServiceResponse() {IsFaulty = true, Exception = e};
}
}
All my services derives from this class and my WCF service endpoint looks like this:
public ServiceResponse Add(Client client)
{
_logger.LogInformation($"ClientService.Add()");
return ExecuteNonQuery(() =>
{
using (var context = _contextFactory.Build())
{
context.Clients.Add(_serviceToDalMapper.Map(client));
context.SaveChanges();
}
});
}
On the client side I have similar Try/Catch method when calling my service.
What I don't understand is that when an exception is thrown on the service side, the exception is catch, but I still get an System.ServiceModel.CommunicationException on the client side. Why ? I catched my exception, shouldn't my service just return the ServiceResponse?
Add a try-catch inside your current catch, looks like the call is generating an exception, possibly generated inside the catch.
catch (DbEntityValidationException e)
{
try
{
OnDbEntityValidationException(e);
return new ServiceResponse() { IsFaulty = true, Excepetion = e};
}
catch
{
return new ServiceResponse() { IsFaulty = true, Excepetion = new Exception("Error handling the error")};
}
}
WCF can't serialize the Exception object (which makes sense in a way).
So an exception was thrown in my catch block, that's the fault here.
According to WCF best practices, I should be using FaultContract to communicate exception to the client.

What is the best practice for handling Try Catch when writing automated testing?

I'm currently writing test automation for a web based application for my company. I am utilising C#, Visual Studio test suite, and Selenium to perform testing.
Today I asked the question to my colleague of 'Is there any time where there is too many Try Catch blocks in code?'. His reply was to not work as I am at the minute (see example 1), but to just get the lower level try-catch to throw to the upper level try-catch so that the exception can be written there and the test failed (see example 2).
Example 1:
TestCase.cs
[TestMethod]
public void TestLogin()
{
Assert.IsTrue(FW_Shared.Perform_Login(FW_Shared.OrgCode, FW_Shared.Username, FW_Shared.Password));
Console.WriteLine(#"Login Successful");
}
FW_Shared.cs
public static class FW_Shared
{
public static string OrgCode = "Test123";
public static string Username = "Tester";
public static string Password = "Password";
public static void Perform_Login(string OrgCode, string Username, string Password)
{
try
{
Driver.Url = "http://test.app.com/";
Driver.FindElement(By.Id("org_code")).SendKeys(OrgCode);
Driver.FindElement(By.Id("username")).SendKeys(Username);
Driver.FindElement(By.Id("password")).SendKeys(Password);
Driver.FindElemenet(By.Id("btnsubmit)).Click();
}
catch (Exception ex)
{
Console.WriteLine(#"Error occurred logging on: " + ex.ToString());
return false;
}
return true;
}
}
Example 2
TestCase.cs
[TestMethod]
public void TestLogin()
{
try
{
Assert.IsTrue(FW_Shared.Perform_Login(FW_Shared.OrgCode, FW_Shared.Username, FW_Shared.Password));
Console.WriteLine(#"Login Successful");
}
catch (Exception ex)
{
Console.WriteLine(#"Exception caught, test failed: " + ex.ToString());
Assert.Fail();
}
}
FW_Shared.cs
public static class FW_Shared
{
public static string OrgCode = "Test123";
public static string Username = "Tester";
public static string Password = "Password";
public static void Perform_Login(string OrgCode, string Username, string Password)
{
try
{
Driver.Url = "http://test.app.com/";
Driver.FindElement(By.Id("org_code")).SendKeys(OrgCode);
Driver.FindElement(By.Id("username")).SendKeys(Username);
Driver.FindElement(By.Id("password")).SendKeys(Password);
Driver.FindElemenet(By.Id("btnsubmit)).Click();
}
catch (Exception)
{
throw;
}
return true;
}
}
Now I know that throwing the Exception to be caught is generally useless in typical coding as you want to handle specific exceptions that are returned, but I want to be able to catch any general web page or element issues so the test can fail on a general issue with the web application. For instance:
If the web page returns 503 or 404 issues
If an element is not present on the current web page
If an elements name has changed.
There is points in testing other, more complicated parts of the application that I handle unaccessible parts/elements with true/false bool returns and assert that, but since I am referencing multiple function across different classes would sticking with what I have be best, moving to top-level catching of all lower exceptions, or should I be doing something else?
I normally like to create a test helper method in its own class called "TestRunner.cs" which has a method in I use for all the tests which might throw an exception and I want to test the results of e.g.
public static Exception RunCodeThatMayThrowException(Action action)
{
try
{
action.Invoke();
return null;
}
catch (Exception ex)
{
return ex;
}
}
I can then just use the method like:
// Act
var actualException = TestRunner.RunCodeThatMayThrowExeption(() => {//some code});
// Assert
//Do some asserts
Your original Perform_Login method states no return parameter (‘void’) and always returns ‘true’ (unless there’s a crash) – these both hint that the method needs some re-factoring.
I would re-factor as follows, which isolates the calling code from the exception, makes the caller agnostic to any errors in the called method, and avoids a series of try-catches passing up the call stack (if your test had a try-catch in it then the production code that calls the method may well require the same):
Public Static Class FW_Shared
{
public static string OrgCode = "Test123";
public static string Username = "Tester";
public static string Password = "Password";
public static bool Perform_Login(string OrgCode, string Username, string Password)
{
Try
{
Driver.Url = "http://test.app.com/";
Driver.FindElement(By.Id("org_code")).SendKeys(OrgCode);
Driver.FindElement(By.Id("username")).SendKeys(Username);
Driver.FindElement(By.Id("password")).SendKeys(Password);
Driver.FindElemenet(By.Id("btnsubmit)).Click();
}
Catch (Exception ex)
{
Console.WriteLine(#"Error occurred logging on: " + ex.ToString());
return false;
}
return true;
}
}
[TestMethod]
Public Void TestLoginSuccess()
{
Assert.IsTrue(FW_Shared.Perform_Login(FW_Shared.OrgCode, FW_Shared.Username, FW_Shared.Password));
Console.WriteLine(#"Login Successful");
}
[TestMethod]
Public Void TestLoginFailure()
{
Assert.IsFalse(FW_Shared.Perform_Login(FW_Shared.OrgCode, “foo”, “bar”));
Console.WriteLine(#"Login Failed");
}

Handling custom exception classes

I am developing a MVC application.
I am trying to define my own exception classes. I am making this structure first time...
What else I have to add in my exception classes , like constructor or something , so it work well... ?
public ActionResult Edit(EmployeeVM employeeVM)
{
EmployeeService employeeService = new PartyService();
try
{
PartyService partyService = new PartyService();
partyService.Update(PartyVM);
}
catch (DuplicateEntityExcpetion e)
{
TempData["error"] = e + "Party you are trying to add is already exist.";
}
catch (InvalidDataException e)
{
TempData["error"] = e + "Data which you are trying to add is not valid.";
}
public class InvalidDataException : Exception
{
}
public class DuplicateEntityExcpetion : Exception
{
}
}
You must throw these exceptions from your service so that they get catched here.
throw new DuplicateEntityExcpetion("Your Query or Message");
throw new InvalidDataException ("Your Query or Message");
Also, it is a good practice to have a generic exception handled so that you have taken care of all exceptions.
catch (Exception e)
{
TempData["error"] = e + "Data which you are trying to add is not valid.";
}

Best practice for throwing exceptions in an utility class

I am creating a utility class that will be used in my Facebook application for tasks that are commonly done, such as retrieving a Facebook Page ID from a URL. I am unsure if the below code is the correct way to throw and catch exceptions. Could someone please advise, thanks.
Utility Class:
public static class FacebookUtilities
{
public static string GetPageIDFromGraph(string pageUri, string accessToken)
{
try
{
FacebookClient client = new FacebookClient(accessToken);
dynamic result = client.Get(GetPageIDFromUri(pageUri), new { fields = "id" });
return result.ToString();
}
catch (FacebookOAuthException)
{
throw;
}
catch (FacebookApiException)
{
throw;
}
}
public static string GetPageIDFromUri(string pageUri)
{
if (pageUri.Contains('/'))
pageUri = pageUri.Substring(pageUri.LastIndexOf('/') + 1);
if (pageUri.Contains('?'))
return pageUri.Substring(0, pageUri.IndexOf('?'));
else
return pageUri;
}
}
Program class, just testing:
- Note "input" and "output" are just textboxes.
private void btnGetPageID_Click(object sender, EventArgs e)
{
try
{
output.Text = FacebookUtilities.GetPageIDFromGraph(input.Text, "Some Access Token Goes Here");
}
catch (FacebookOAuthException ex)
{
if (ex.ErrorCode == 803)
{
output.Text = "This page does not exist";
}
}
catch (FacebookApiException ex)
{
if (ex.ErrorCode == 100)
{
output.Text = "The request was not supported. The most likely cause for this is supplying an empty page ID.";
}
}
}
Is it correct to simply rethrow the exception from the utility class so that the calling class can catch it and do what needs to be done?
It seems that you do nothing with catched exceptions - so dont catch them. There are a lot of discussions about exception handling, but in general you should catch exceptions when you have something to do with them, or at least using finally to clean up resourses.
Since you aren't handling the exceptions in any way, your code can just be:
public static string GetPageIDFromGraph(string pageUri, string accessToken)
{
FacebookClient client = new FacebookClient(accessToken);
dynamic result = client.Get(GetPageIDFromUri(pageUri), new { fields = "id" });
return result.ToString();
}
You should only catch exceptions when you can meaningfully handle them, and it doesn't look like you can in your GetPageIDFromGraph method, so you should just propagate them.

Categories