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;
}
}
Related
In the configuration file I have made it so that the property Name of the class Series IsUnique() so whenever I try to add another entity with the same name, I get a DbUpdateException. I can access the message of this exception everywhere except for the UIController.
Here we have the code in my service where I check if the series is valid and if not I throw an exception (I know this is not best practice put at this point I just want it to work first)
public void Add(SeriesDTO series)
{
if (series.Name != null && series.Startdate < series.Enddate)
{
_unitOfWork.Series.AddAsync(_mapper.Map<SeriesDTO, Series>(series));
_unitOfWork.CommitAsync();
}
else
throw new Exception("Series data is not valid");
}
Then I have my controller where I check for the DbUpdateException and if I find it I throw another exception this I prefer not to do because at this point I can access this exception message with the right message.
[HttpPost("add")]
//POST: series/add
public IActionResult Add(SeriesDTO series)
{
try
{
_seriesService.Add(series);
}
catch (DbUpdateException E)
{
throw new Exception("Series with this name already exists.");
}
return Ok(series);
}
Up until this point I can always access the exception error but when I get to my UI controller then this exception turns into a 500 internal server error and thus I can not differentiate between an invalid entity exception and a DbUpdateException and thus cannot access the right message.
public IActionResult Add(SeriesDTO serie)
{
if(serie.Enddate < DateTime.Today || serie.Enddate.Equals(null))
{
serie.Active = false;
}
else
{
serie.Active = true;
}
try
{
string data = JsonConvert.SerializeObject(serie);
var result = _client.UploadString("series/add", data);
}
catch(Exception E)
{
ExceptionModel Exception = new ExceptionModel("Something went wrong with the series data.");
return View("Exception", Exception);
//return View("Create");
}
return Redirect("Index");
}
Does anyone know how to properly send the exception through to the UI controller?
You can do that.
In you Controller method :
public IActionResult Add(SeriesDTO serie)
{
//...
ModelState.AddModelError("CustomError", "You error message as string.");
//...
}
And in you view you need that :
<span asp-validation-for="CustomError" class="text-danger"></span>
If something doesn't work, tell me and edit you post with the code of you View.
I am trying to send the proper response from Web API i.e. If any error send error else send the content. The code flow for the same is as follow.
[HttpPost]
public IActionResult GetInfo([FromBody] InfoModel info)
{
try
{
var result = new Info().ProcessInfoResponse(info);
if (result==null)
return BadRequest();
else
return Ok(result);
}
catch (Exception e)
{
Log.Error("some exception", e);
return StatusCode(500, e.Message);
}
}
and from middle layer i.e. from Info class we are having different method with there own returning type and from here we are calling the third party APIs which are in another class.
public InfoResponse ProcessInfoResponse(InfoModel info)
{
try
{
var result = serviceLayer.Post<InfoModel>(info);
if (result != null)
{
// Do Something
}
else
{
Log.Error("some error");
return null;
}
}
catch (Exception ex)
{
Log.Error("some error");
return null;
}
}
public InfoRequest ProcessInfoRequest()
{
}
And in service layer we are calling the third party api like below
public HttpResponseMessage Post<T>(T parm) where T : class
{
try
{
_client.DefaultRequestHeaders.Clear();
var postTask = _client.PostAsync("some third party url", Serialize<T>(parm));
postTask.Wait();
if (postTask.Result.IsSuccessStatusCode)
{
return postTask.Result;
}
else
{
Log.Error("some error in service layer");
}
}
catch (Exception ex)
{
Log.Error("some error in service layer");
}
return default(HttpResponseMessage);
}
So my question is how can return exceptions/errors if there are any and if there is no exceptions/error then send the response as it is. This is possible by keeping middle layer returning type as is
Right now if there are no errors then I am able to send the response properly, as my middle layer is getting the expected returning type.
The issue is my middle layer methods has own returning type which is causing me to send the exception/error as is. Because I am not able to map it to proper class OR same class.
I was thinking will add new Property under all returning classes/types which will refer to the exception class, then will bind the exception/error details to that class. This will save doing lot of code changes in all places.
Any help on this appreciated !
Why not create a custom response object so that:
public IActionResult<MyCustomResponseObject> GetInfo([FromBody] InfoModel info)
public class MyCustomResponseObject
{
public string Message { get; set; }
public object Content { get; set; }
public enum State { get; set; }
}
I am new to Web Api 2 , I want to show some message if i hit Exception , I know that VOID is a non return type, I tried with HttpResponseMessage but it is not working or showing the "Error Message" , is that any way to show message ?
My code is as below
public void Post(int id)
{
string result = string.Empty;
try
{
//some code
}
catch (Exception ex)
{
HttpResponseMessage response2 = Request.CreateResponse(HttpStatusCode.BadRequest, "Error message");
ErrId = 999;
}
}
If you are using web api 2, then I would use IHttpActionResult as the return type, which allows you to do something like:
public IHttpActionResult Post(int id)
{
string result = string.Empty;
try
{
//some code
return Ok();
}
catch (Exception ex)
{
return BadRequest("Error message");
}
}
However, it must be noted that by default Web API has a built-in exception handler and logger that will automatically return a 500 response code for any exception, so the code above is potentially redundant unless you are catching a custom exception. Lastly the code above does not log the exception.
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.
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: