A good suggestion on how to handle errors within a Client can be found here.
Copying here for easy access:
MyServiceClient myServiceClient = new MyServiceClient();
try
{
documents = myServiceClient.GetDocuments();
// More code that isn't useful including here ...
myServiceClient.Close();
}
catch (TimeoutException exception)
{
MessageBox.Show(exception.Message, "Timeout error", MessageBoxButtons.OK, MessageBoxIcon.Error);
myServiceClient.Abort();
}
catch (FaultException<ServiceErrorDetails> error)
{
MessageBox.Show(error.Detail.Message, "Service error", MessageBoxButtons.OK, MessageBoxIcon.Error);
myServiceClient.Abort();
}
catch (CommunicationException exception)
{
MessageBox.Show(exception.Message, "Communication error", MessageBoxButtons.OK, MessageBoxIcon.Error);
myServiceClient.Abort();
}
Now the problem I am having with this solution is that my Proxy contains many many methods. Easy to understand I would rather not want to add this huge try/catch statement around all my method calls.
Instead, I thought it could be a good idea to add the error handling from within MyServiceClient() class.
But the question is how to do that without polluting all the Methods here again with this try/catch statement?
How would you approach that?
You could try encapsulating the try/catch logic in a handler class as follows:
public static class Example
{
public static void ExecuteExample()
{
var serviceClient = new ServiceClient();
var documents = ProxyErrorHandler.Execute(serviceClient, serviceClient.GetDocuments);
}
}
public static class ProxyErrorHandler
{
public static void Execute(ServiceClient serviceClient, Action actionToExecute)
{
Execute(serviceClient, () =>
{
actionToExecute();
return true;
});
}
public static T Execute<T>(ServiceClient serviceClient, Func<T> functionToExecute)
{
try
{
return functionToExecute();
}
catch (Exception exception)
{
ShowException(serviceClient, exception);
return default;
}
}
public static Task ExecuteAsync(ServiceClient serviceClient, Func<Task> actionToExecute)
{
return ExecuteAsync(serviceClient, async () =>
{
await actionToExecute();
return true;
});
}
public static async Task<T> ExecuteAsync<T>(ServiceClient serviceClient, Func<Task<T>> functionToExecute)
{
try
{
return await functionToExecute();
}
catch (Exception exception)
{
ShowException(serviceClient, exception);
return default;
}
}
private static void ShowException(ServiceClient serviceClient, Exception exception)
{
string title;
var message = exception.Message;
switch (exception)
{
case TimeoutException:
title = #"Timeout error";
break;
case FaultException<ServiceErrorDetails> faultException:
title = #"Service error";
message = faultException.Detail.Message;
break;
case CommunicationException:
title = #"Communication error";
break;
default:
ExceptionDispatchInfo.Throw(exception);
// Unreachable
throw new Exception();
}
MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error);
serviceClient.Abort();
}
}
Related
In Framework WebAPI 2, I have a controller that looks like this:
[Route("create-license/{licenseKey}")]
public async Task<LicenseDetails> CreateLicenseAsync(string licenseKey, CreateLicenseRequest license)
{
try
{
// ... controller-y stuff
return await _service.DoSomethingAsync(license).ConfigureAwait(false);
}
catch (Exception e)
{
_logger.Error(e);
const string msg = "Unable to PUT license creation request";
throw new HttpResponseException(HttpStatusCode.InternalServerError, msg);
}
}
Sure enough, I get back a 500 error with the message.
How can I do something similar in ASP.NET Core Web API?
HttpRequestException doesn't seem to exist. I would prefer to continue returning the object instead of HttpRequestMessage.
What about something like this. Create a middleware where you will expose certain exception messages:
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
public ExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
context.Response.ContentType = "text/plain";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
if (ex is ApplicationException)
{
await context.Response.WriteAsync(ex.Message);
}
}
}
}
Use it in your app:
app.UseMiddleware<ExceptionMiddleware>();
app.UseMvc();
And then in your action throw the exception:
[Route("create-license/{licenseKey}")]
public async Task<LicenseDetails> CreateLicenseAsync(string licenseKey, CreateLicenseRequest license)
{
try
{
// ... controller-y stuff
return await _service.DoSomethingAsync(license).ConfigureAwait(false);
}
catch (Exception e)
{
_logger.Error(e);
const string msg = "Unable to PUT license creation request";
throw new ApplicationException(msg);
}
}
A better approach is to return an IActionResult. That way you dont have to throw an exception around. Like this:
[Route("create-license/{licenseKey}")]
public async Task<IActionResult> CreateLicenseAsync(string licenseKey, CreateLicenseRequest license)
{
try
{
// ... controller-y stuff
return Ok(await _service.DoSomethingAsync(license).ConfigureAwait(false));
}
catch (Exception e)
{
_logger.Error(e);
const string msg = "Unable to PUT license creation request";
return StatusCode((int)HttpStatusCode.InternalServerError, msg)
}
}
It's better not to catch all exceptions in every action. Just catch exceptions you need to react specifically and catch (and wrap to HttpResponse) all the rest in Middleware.
I'm new to TPL.
I need to handle exception when the SendEmailAlert() method throws any error.Is the following code correct please?
public Task MyMethod()
{
DoSomething();
try
{
string emailBody = "TestBody";
string emailSubject = "TestSubject";
Task.Run(()=> SendEmailAlert(arrEmailInfo));
}
catch (AggregateException ex)
{
ex.Handle((e) =>
{
log.Error("Error occured while sending email...", e);
return true;
}
);
}
}
private void SendEmailAlert(string[] arrEmailInfo)
{
MyClassX.SendAlert(arrEmailnfo[0], arrEmailnfo[1]);
}
I forced an error from within SendEmailAlert() method.But the exception is not getting caught. Could someone advise?
Thanks.
Your Task.Run runs in a different context (you would need a try/catch inside it; or check if the task is done). You could change to use async/await.
Example:
public async void MyMethod()
{
try
{
await ExceptionMethod();
}
catch (Exception ex)
{
// got it
}
}
public async Task ExceptionMethod()
{
throw new Exception();
}
I have a series of methods that call wcf services and all of them have the same try catch code
Response Method1(Request request)
{
Response response = null;
using(ChannelFactory<IService1> factory = new ChannelFactory<IService1>(myEndpoint))
{
IService1 channel = factory.CreateChannel();
try
{
response = channel.Operation(request);
}
catch(CommunicationException ex)
{
// Handle Exception
}
catch(TimeoutException ex)
{
// Handle Exception
}
catch(Exception ex)
{
// Handle Exception
}
}
return response;
}
And so on (I have 6 methods like this for different services).. how can i encapsulate all the service calls and handle the exceptions in a single method
EDIT
Following Nathan A's advice I created a simple generic method:
protected TResult ExecuteAndCatch<TResult>(Func<T, TResult> serviceCall, T request)
where T : Request
where TResult : Response
{
try
{
return serviceCall(request);
}
catch (CommunicationException ex)
{
}
catch (TimeoutException ex)
{
}
catch (Exception ex)
{
}
return null;
}
The new methods would like this
Response NewMethod1(Request request)
{
Response response = null;
using(ChannelFactory<IService1> factory = new ChannelFactory<IService1>(myEndpoint))
{
IService1 channel = factory.CreateChannel();
response = channel.Operation(request);
}
return response;
}
and i'm trying to call it like
Response response = ExecuteAndCatch<Response>(NewMethod1, new Request())
What am I doing wrong?
Use a wrapper function.
Take a look at this article: http://mytenpennies.wikidot.com/blog:writing-wcf-wrapper-and-catching-common-exceptions
Here's an example from the article:
private void ExecuteAndCatch<T> (Action<T> action, T t) {
try {
action (t);
Success = true;
}
catch (TimeoutException) {
Success = false;
Message = "Timeout exception raised.";
}
catch (CommunicationException) {
Success = false;
Message = "Communication exception raised.";
}
}
If your client derives from ClientBase<T> e.g MyClient : ClientBase<IWCFService>
You could then create your own base class that provides methods that will wrap the common functionality.
The below sample code could be expanded to allow the final derived class to specify what to do when a particular method call fails. Here I just call HandleError
In specific client class
//method that returns a value
public int Ping()
{
return Protect(c => c.Ping());
}
//void method usage
public void Nothing(int stuff)
{
Protect(c => c.Nothing(stuff));
}
In client base class
protected void Protect(Action<IWCFService> action)
{
Protect(c => { action(c); return true; });
}
//add other exception handling
protected Protect<T>(Func<IWCFService, T> func)
{
try
{
return func(Channel);
}
catch (FaultException e)
{
HandleError(e);//up to you to implement this and any others
}
return default(T);
}
inject the various clients through an interface and then run the operation in a single place?
HttpResponse performOperation(IServiceClient injectedServiceClient)
{
IServiceClient client = injectedServiceClient;
try
{
client.Operation();
}
catch(CommunicationException ex)
{
// Handle Exception
}
catch(TimeoutException ex)
{
// Handle Exception
}
catch(Exception ex)
{
// Handle Exception
}
return httpResponse(httpStatusCode.OK);
}
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.
i have a plugin for an activity.
on pre create i check few conditions and if i get true so i throw OperationCanceledException for stop the create execution.
but the record was saved, why? how do i can to cancel the creation? also tried to throw InvalidPluginExecutionException, but it's stil executed..
the code:
public void Execute(IPluginExecutionContext context)
{
try
{
switch (context.MessageName)
{
case "Create":
if (context.Stage == MessageProcessingStage.BeforeMainOperationOutsideTransaction)
{
bool shouldnotcreateactivity = Create(context, service);
if (shouldnotcreateactivity)
throw new OperationCanceledException();
}
if (context.OutputParameters.Properties.Contains("id"))
{
//continue...
}
break;
}
}
catch (OperationCanceledException cancled)
{
}
catch (InvalidPluginExecutionException invalid)
{
}
catch (SoapException ex)
{
}
catch (Exception ex)
{
}
}
Sounds like you are doing something wrong. You should probably post some of your code realting to the pre-checking and saving of the activity
You should have some logic like the following...
if(ValidateActivity()){
CreateAndSaveActivity();
}
else
throw execption;