Exception handling on Tasks without Wait() - wcf

What is the best approach to handle exception of a Task that does not Wait()? I read a couple of blogs which spoke about using ContinueWith because regular try/catch cannot handle Task exception. Below code does not validate that.
Method 1:
public class Service1 : IService1
{
public string GetData(int value)
{
var a = Task.Factory.StartNew(ThrowException);
return string.Format("You entered: {0}", value);
}
private void ThrowException()
{
try
{
Thread.Sleep(6000);
throw new ArgumentException("Hello from exception");
}
catch (Exception)
{
Trace.WriteLine("Log it");
}
}
}
Method 2:
public class Service1 : IService1
{
public string GetData(int value)
{
var a = Task.Factory.StartNew(ThrowException);
a.ContinueWith(c => { Trace.WriteLine("Log it"); },
TaskContinuationOptions.OnlyOnFaulted);
return string.Format("You entered: {0}", value);
}
private void ThrowException()
{
Thread.Sleep(6000);
throw new ArgumentException("Hello from exception");
}
}
Are Method 1 and Method 2 doing the same thing? Is there a better way to implement this.
Edit: Added code snippet for continuewith.

Both methods work and they are equivalent. Choose what you like most. The continuation based one has the advantage that you can make the error handling into an extension method (or some other central helper).
Are you aware that IIS worker processes can suddenly disappear for many reasons? In that case background work is lost. Or, the work faults but the error handler disappears.

It looks like it will work if all you need is to call methods on the Trace class. However, if you need custom exception handling, I would recommend injecting an exception handler:
private void ThrowException(Action<Exception> handleExceptionDelegate)
{
try
{
// do stuff that may throw an exception
}
catch (Exception ex)
{
if (handler != null)
handleExceptionDelegate(ex);
}
}
Then you could do
Task.Factory.StartNew(() =>
{
ThrowException((ex) =>
{
// Handle Exception
});
});

Related

ASP.NET Core Interception with Castle.DinamicProxy doesn't throw Exception with Async Methods !!! How can I solve this?

I have been creating a project with Aspect Oriented Programming paradigm and
I have an "ExceptionLogAspect" class attribute which is used on business methods to log the errors throwing from them.
public class ExceptionLogAspect : MethodInterception
{
private readonly LoggerServiceBase _loggerServiceBase;
private static byte _risk;
public ExceptionLogAspect(Type loggerService, byte risk)
{
if (loggerService.BaseType != typeof(LoggerServiceBase))
{
throw new System.Exception(AspectMessages.WrongLoggerType);
}
_loggerServiceBase = (LoggerServiceBase)Activator.CreateInstance(loggerService);
_risk = risk;
}
protected override void OnException(IInvocation invocation, System.Exception e)
{
var logDetailWithException = GetLogDetail(invocation);
logDetailWithException.ExceptionMessage = e.Message;
_loggerServiceBase.Error(logDetailWithException);
}
}
This Aspect migrates MethodInterception class that I created with Castle.DinamicProxy package. And OnException method included by MethodInterception logs the exception data.
public abstract class MethodInterception:MethodInterceptionBaseAttribute
{
protected virtual void OnBefore(IInvocation invocation){}
protected virtual void OnAfter(IInvocation invocation){}
protected virtual void OnException(IInvocation invocation, System.Exception e){}
protected virtual void OnSuccess(IInvocation invocation){}
public override void Intercept(IInvocation invocation)
{
var isSuccess = true;
OnBefore(invocation);
try
{
invocation.Proceed();//Business Method works here.
}
catch (Exception e)
{
isSuccess = false;
OnException(invocation, e);
throw;
}
finally
{
if(isSuccess)
OnSuccess(invocation);
}
OnAfter(invocation);
}
}
When I run the code and try-catch block doesn't work for Exception. So catch block isn't called and no messages are logged.
If I turn the business method into a syncronous method, exception will be thrown and data will be logged.
How can I solve this asynchronous method problem?
I tried this solution, it works properly.
Intercept method has to be like this to make this process asynchronous.
Otherwise, this method doesn't work properly for async.
There are some other ways, for example Castle CoreAsync Interceptor, you can find it on Github or NuGet.
https://github.com/JSkimming/Castle.Core.AsyncInterceptor
public override void Intercept(IInvocation invocation)
{
var isSuccess = true;
OnBefore(invocation);
try
{
invocation.Proceed(); //Metodu çalıştır
if (invocation.ReturnValue is Task returnValueTask)
{
returnValueTask.GetAwaiter().GetResult();
}
if (invocation.ReturnValue is Task task && task.Exception != null)
{
throw task.Exception;
}
}
catch (Exception e)
{
isSuccess = false;
OnException(invocation, e);
throw;
}
finally
{
if (isSuccess)
OnSuccess(invocation);
}
OnAfter(invocation);
}

How to use FaultException with details without specifying FaultContractAttribute

I'm well aware of how to use FaultException with details. I know I can declare details contract, then I need to decorate the method which is expected to throw this kind of exceptions with [FaultContract(type(DetailsContractType))] and then I do throw FaultException in that method. All that is understood and worked. What I need is to be able to throw FaultException from all methods of all contracts in my WCF host. Adding [FaultContract(type(DetailsContractType))] to each method of each operation contract seems to much to me. Is there another way to allow this kind of exceptions without decorating methods with that attribute? If I just remove that attribute everything stops working and the exception becomes just FaultException on the client side. I was thinking about DataContractResolver but it looks like it is not involved in DetailsContractType resolution. Any ideas, hints, solutions?
Using IErrorHandler does not relieve you from decorating contract operations with the FaultContractAttribute what I'm trying to avoid. It is even stated in the example you referred, there is a comment there
// This behavior requires that the contract have a SOAP fault with a detail type of
GreetingFault.
and
throw new InvalidOperationException(String.Format(
"EnforceGreetingFaultBehavior requires a "
+ "FaultContractAttribute(typeof(GreetingFault)) in each operation contract. "
+ "The \"{0}\" operation contains no FaultContractAttribute.",
opDesc.Name)
);
You can implement the IErrorHandler interface to uniformly handle errors in WCF,here is a Demo:
[ServiceContract]
public interface IDemo {
[OperationContract]
void DeleteData(int dataId);
}
class DemoService : IDemo
{
public void DeleteData(int dataId)
{
if (dataId<0) {
throw new ArgumentException("error");
}
}
}
The above code is the interface and implementation class of WCF service.
class MyCustErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
FaultException faultException = new FaultException(error.Message);
MessageFault messageFault = faultException.CreateMessageFault();
fault = Message.CreateMessage(version,messageFault,"my-test-error");
}
}
The above code is the implementation class of the IErrorHandler interface.
class MyEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
return;
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
MyCustErrorHandler handler = new MyCustErrorHandler();
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(handler);
}
public void Validate(ServiceEndpoint endpoint)
{
return;
}
}
We add a custom error handling class by extending the Behavior method of the endpoint.
ServiceEndpoint ep = selfHost.AddServiceEndpoint(typeof(IDemo), new BasicHttpBinding(), "CalculatorService");
MyEndpointBehavior myEndpointBehavior = new MyEndpointBehavior();
ep.EndpointBehaviors.Add(myEndpointBehavior);
The client executes the following code will print "error" in the console:
try {
demoClient.DeleteData(-3);
}
catch (FaultException fault) {
string err = fault.Reason.GetMatchingTranslation().Text;
Console.WriteLine(err);
}
For more information about IErrorhandler,Please refer to the following link:
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.dispatcher.ierrorhandler?view=netframework-4.8
UPDATE
If you don’t want to use IErrorhandler, you can also use FaultReason:
public string SayHello(string name) {
if (name.Length<2) {
FaultReasonText faultReasonText = new FaultReasonText("name length cannot be less than 2");
FaultReason reason = new FaultReason(faultReasonText);
throw new FaultException(reason);
}
return "hello";
}
The client needs to catch exceptions when calling:
try {
string res = channnel.Sayhello("B");
}
catch (FaultException fex) {
if (fex.Reason != null) {
FaultReason reason = fex.Reason;
//Get error information
FaultReasonText txt = reason.GetMatchingTranslation();
Console.WriteLine(txt.Text);
}
}

Show custom message without breaking page using exception filter

I am using one MVC application where i have to handle all exception occurs in the code. I have found about exception filter and implemented there. Below is the created exception filter code:
public class HandleException : HandleErrorAttribute
{
#region Log Initialization
FileLogService logService = new
FileLogService(typeof(HandleException));
#endregion
public override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
Log(filterContext.Exception);
base.OnException(filterContext);
}
private void Log(Exception exception)
{
logService.Error(exception.ToString());
}
}
Now i used this filter as attribute in my controller like below:
[AuthSession]
[HandleException]
public class OrganizationalController : BaseController
{
public ActionResult OrgSummary()
{
try
{
int a = 1, b = 0;
int result = a / b;
}
catch (Exception ex)
{
throw ex;
}
ViewData["ShowGrid"] = false;
return View();
}
}
As you can see in above code i am trying to generate exception in the code. In catch exception block when i used throw keyword then exception filter getting executed else not.
Now i need here when any exception occurs in the application i need to show a custom popup message for user. In popup message once user click on ok button then user should be available on the same page. The page should not break or get blank.
How could i implement this functionality?
Try this code. May be it helps
public class MyExceptionFilter: FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
// below code will redirect to the error view
filterContext.Result = new RedirectResult("ErrorPage.html");
filterContext.ExceptionHandled = true;
}
}
and then you need to apply the above as an attribute to your action methods like:
[MyExceptionFilter]
public ActionResult XYZ()
{
}

Retrofit Rxjava error handler

I have a service class which is used to call api requset
here is an example method:
public Observable<List<Category>> test(Location location, int radius) {
Observable<CategoryListResponse> observable = api.test();
return observable
.doOnNext(new Action1<CategoryListResponse>() {
#Override
public void call(CategoryListResponse categoryListResponse) {
//handle error
}
})
.flatMap(new Func1<CategoryListResponse, Observable<Category>>() {
#Override
public Observable<Category> call(CategoryListResponse categoryListResponse) {
return Observable.from(categoryListResponse.getCategories());
}
})
.map(new Func1<Category, Category>() {
#Override
public Category call(Category category) {
//do something...
return category;
}
})
.toList();
}
And subscribe() will be called in another class.
observable.subscribe(new Action1<List<Category>>() {
#Override
public void call(List<Category> categories) {
//on success
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
//on error
}
});
I was thinking to do error handling in the doOnNext() before it is returned back. but how can I trigger onError()?
You should throw a runtime exception and control the exception in onError operator in case that happens
Observable<CategoryListResponse> observable = api.test();
return observable
.doOnNext(list -> {
try{
request(list);
catch(Exception e){
throw new RuntimeException(e);
}
}).onError(t->//Here you control your errors otherwise it will be passed to OnError callback in your subscriber)
.flatMap(item -> Observable.from(item.getCategories()))
.map(category-> category)
.toList();
}
Try to use lambdas, make your code much more clear and readable
You can see some RxJava examples here https://github.com/politrons/reactive

NServiceBus retrying message even though no exception

I got a wierd problem with NServiceBus retying the message X number of times although no exception is thrown in the handler. There is some information out there dealing with the NHibernate session and the NSB ambiant transaction. Since no error is thrown I'm not 100% sure of the problem and thus can't really decide on what to do.
I got NSB configured with Castle Windsor like so:
IWindsorContainer container = new WindsorContainer(new XmlInterpreter());
container.Install(new ContainerInstaller());
container.Install(new UnitOfWorkInstaller(AppDomain.CurrentDomain.BaseDirectory, Castle.Core.LifestyleType.Scoped));
container.Install(new FactoryInstaller(AppDomain.CurrentDomain.BaseDirectory));
container.Install(new RepositoryInstaller(AppDomain.CurrentDomain.BaseDirectory));
Configure.With()
.CastleWindsorBuilder(container)
.FileShareDataBus(Properties.Settings.Default.DataBusFileSharePath)
.MsmqTransport()
.IsTransactional(true)
.PurgeOnStartup(false)
.UnicastBus()
.LoadMessageHandlers()
.ImpersonateSender(false)
.JsonSerializer();
The UnitOfWorkInstaller registers the unit of work (the NHibernate session) like so:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
var fromAssemblyDescriptor = AllTypes.FromAssemblyInDirectory(new AssemblyFilter(_installationPath));
container.Register(fromAssemblyDescriptor
.IncludeNonPublicTypes()
.Pick()
.If(t => t.GetInterfaces().Any(i => i == typeof(IUnitOfWork)) && t.Namespace.StartsWith("Magma"))
.WithService.AllInterfaces()
.Configure(con => con.LifeStyle.Is(_lifeStyleType).UsingFactoryMethod(k => k.Resolve<IUnitOfWorkFactory>().Create())));
}
So each time a message arrives the same unit of work is used for all the repositories. I read that manually rolling back the current transaction results in an error (I don't really know why) and I also know that NSB creates a child container for every transport message and that this child container is disposed after the processing of the message. The problem is that when the child container is disposed the unit of work is disposed this way:
public void Dispose()
{
if (!_isDisposed)
{
DiscardSession();
_isDisposed = true;
}
}
private void DiscardSession()
{
if (_transaction != null && _transaction.IsActive)
{
_transaction.Dispose();
}
if (Session != null)
{
Session.Dispose();
}
}
My handlers are structured like this: (the _unitOfWork is passed as a constructor dependency)
public void Handle(<MessageType> message)
{
using (_unitOfWork)
{
try
{
// do stuff
_unitOfWork.Commit();
}
catch (Exception ex)
{
_unitOfWork.Rollback();
// rethrow so the message stays in the queue
throw;
}
}
}
I found out that if I don't commit the unit of work (which flushes the session and commit the transaction) I got an error saying that the message has retried beyond the max retry count bla bla bla...
So it seems to be linked with the NHibernate session and the way it's created and disposed of but since it's created within the unit of work I can't really use the session factory. I read that I could use the IMessageModule to create and dispose the session but again I don't know if this is the right way to go since I don't understand what's causing the error in the first place.
So to recap:
I'm using a scoped unit of work so that all the handler dependencies using it will share the same instance (thx to the child container, BTW: I've setup the unit of work as transient thinking that the child container will treat all transient object as singleton within that container but I saw that the unit of work wasn't shared so this is why it's setup as scoped)
I'm wrapping my handler in a using(_unitOfWork) { } statement to dispose the unit of work after each processing.
When the unit of work get's disposed, the NHibernate session is also disposed
If I don't explicitly call Commit on the _unitOfWork, the message retries beyond the max retry count and then an error is thrown.
What is causing this behavior? and is the IMessageModule is the answer for this?
I think I narrowed it down a bit... I removed all of the using(_unitOfWork), the _unitOfWork.Commit() and the _unitOfWork.Rollback() and let the NSB TransactionScope do the work of commit or rollback the transaction since the NHibernate's Session was enlisting in the NSB transaction scope.
I also started to use the NHibernate session's transaction (Session.Transaction) instead of grabbing a reference to it through Session.BeginTransaction() and using this one. I've copy/pasted my UoW implementation so you can see the differences (the old code is in comments).
I don't know if my changes account for anything but using the Session's transaction and removing the flushes since it's taking care of within the transaction commit seems to have solved the problem... I don't have to explicitly call the Commit method in order for the message to be successfully processed anymore. Here is my UoW implementation:
public class NHibernateUnitOfWork : INHibernateUnitOfWork
{
//private ITransaction _transaction;
private bool _isDisposed;
private bool _isInError;
public ISession Session { get; protected set; }
public NHibernateUnitOfWork(ISession session)
{
Contract.Requires(session != null, "session");
Session = session;
//_transaction = Session.BeginTransaction();
// create a new transaction as soon as the session is available
Session.BeginTransaction();
_isDisposed = false;
_isInError = false;
}
public void MarkCreated(Object entity)
{
// assert stuff
try
{
Session.SaveOrUpdate(entity);
//Session.Flush();
}
catch (HibernateException ex)
{
HandleError();
throw;
}
}
public void MarkUpdated(Object entity)
{
// assert stuff
try
{
Session.Update(entity);
//Session.Flush();
}
catch (HibernateException ex)
{
HandleError();
throw;
}
}
public void MarkSavedOrUpdated(Object entity)
{
// assert stuff
try
{
Session.SaveOrUpdate(entity);
//Session.Flush();
}
catch (HibernateException)
{
HandleError();
throw;
}
}
public void MarkDeleted(Object entity)
{
// assert stuff
try
{
Session.Delete(entity);
//Session.Flush();
}
catch (HibernateException ex)
{
HandleError();
throw;
}
}
public void Commit()
{
// assert stuff
try
{
//Session.Flush();
//_transaction.Commit();
Session.Transaction.Commit();
}
catch (HibernateException ex)
{
HandleError();
throw;
}
}
public void Rollback()
{
// assert stuff
try
{
//if (!_transaction.WasRolledBack)
//{
// _transaction.Rollback();
//}
Session.Transaction.Rollback();
}
catch (HibernateException ex)
{
HandleError();
throw;
}
}
public void Dispose()
{
if (!_isDisposed)
{
DiscardSession();
_isDisposed = true;
}
}
private void DiscardSession()
{
//if (_transaction != null && _transaction.IsActive)
//{
// _transaction.Dispose();
//}
if (Session != null)
{
try
{
// rollback all uncommitted changes
if (Session.Transaction != null && Session.Transaction.IsActive)
{
Session.Transaction.Rollback();
}
//Session.Clear();
Session.Close();
}
catch (Exception)
{ }
finally
{
Session.Dispose();
}
}
}
private void HandleError()
{
_isInError = true;
//if (_transaction != null && _transaction.IsActive)
//{
// _transaction.Rollback();
//}
if (Session.Transaction != null && Session.Transaction.IsActive)
{
Session.Transaction.Rollback();
}
}
// assert methods
}
Does any of this makes sense? I still don't know what caused the error in the first place but it seems to have to do with disposing the NHibernate Session before the transaction scope finishes.