PipelineNet icon indicating copy to clipboard operation
PipelineNet copied to clipboard

Obsolete Finally

Open mariusz96 opened this issue 1 year ago • 0 comments

The Finally methods with Func parameters:

public interface IAsyncResponsibilityChain<TParameter, TReturn>
{
    IAsyncResponsibilityChain<TParameter, TReturn> Finally(Func<TParameter, Task<TReturn>> finallyFunc);
}
public interface IResponsibilityChain<TParameter, TReturn>
{
    IResponsibilityChain<TParameter, TReturn> Finally(Func<TParameter, TReturn> finallyFunc);
}

do not support DI. Also they might lead less knowledgeable developers to unintentionally capture DI services as variables in the function body:

.Finally(async (ctx) =>
{
    _dbContext.Logs.Add(new Log { Message = "Failed to process request with id: {ctx.Id}." }); // DbContext captured outside of DI.
    await _dbContext.SaveChangesAsync();
})

So I propose to refactor them into classes:

+   public interface ICancellableAsyncFinally<TParameter, TReturn>
+   {
+       Task<TReturn> Finally(TParameter parameter, CancellationToken cancellationToken);
+   }

+   public interface IAsyncFinally<TParameter, TReturn>
+   {
+       Task<TReturn> Finally(TParameter parameter);
+   }

public interface IAsyncResponsibilityChain<TParameter, TReturn>
{
+   IAsyncResponsibilityChain<TParameter, TReturn> Finally<TFinally>() where TFinally : IAsyncFinally<TParameter, TReturn>;
+   IAsyncResponsibilityChain<TParameter, TReturn> CancellableFinally<TCancellableFinally>() where TCancellableFinally : ICancellableAsyncFinally<TParameter, TReturn>;
+   IAsyncResponsibilityChain<TParameter, TReturn> Finally(Type finallyType);
}
+   public interface IFinally<TParameter, TReturn>
+   {
+       TReturn Finally(TParameter parameter);
+   }

public interface IResponsibilityChain<TParameter, TReturn>
{
+   IResponsibilityChain<TParameter, TReturn> Finally<TFinally>() where TFinally : IFinally<TParameter, TReturn>;
+   IResponsibilityChain<TParameter, TReturn> Finally(Type finallyType);
}

And obsolete overloads that use Func.

This would ensure that the old code still compiles while the new code can use DI and avoid "captured services" pitfall.

mariusz96 avatar Aug 23 '24 16:08 mariusz96