Port from old Flatwhite package (.NET 4.5.2) to support only .NET CORE 2.1.x and doesn't require any extra packages
In your .NET core app, you have a need to intercept method calls so you possibly have 2 quick options:
- Use Autofac.Extras and call EnableInterfaceInterceptor() on type registrations then create/register custom IInterceptor.
- Or use Flatwhite, implement an MethodFilterAttribute and decorate on the methods on your interfaces which you want to intercept.
Flatwhite works for any methods
[HandleAllMethodExceptions]
interface IOrderService
{
[FilterAttributeOnInterfaceMethod]
Order GetById(int id);
[FilterAttributeOnInterfaceMethod]
Task<Order> GetByIdAsync(int id);
}
var serviceCollection = new ServiceCollection();
serviceCollection.UseFlatwhiteFilters();
serviceCollection.RegisterWithMethodFilters<IOrderService, OrderService>(ServiceLifetime.Singleton);
Flatwhite is inspired by ASP.NET MVC ActionFilterAttribute, so it works quite similar. The base filter attribute has following methods. So simply implement your filter class and do whatever you want.
public abstract class MethodFilterAttribute : Attribute
{
public virtual void OnMethodExecuting(MethodExecutingContext methodExecutingContext);
public virtual Task OnMethodExecutingAsync(MethodExecutingContext methodExecutingContext);
public virtual void OnMethodExecuted(MethodExecutedContext methodExecutedContext);
public virtual Task OnMethodExecutedAsync(MethodExecutedContext methodExecutedContext);
}
If you decorate the filter on async methods, only OnMethodExecutingAsync and OnMethodExecutedAsync are called. During the filters are being executed, if the Result value is set to the MethodExecutingContext, the remaining filters will be ignored. However, all filters will be called OnMethodExecutedAsync or OnMethodExecuted unless there is an exception during invocation
Similar to MethodFilterAttribute, you can implement ExceptionFilterAttribute to provide custom error handling logic. If the property MethodExceptionContext.Handled is true, all remaining ExceptionFilter will be ignored.
public abstract class ExceptionFilterAttribute : Attribute
{
public virtual void OnException(MethodExceptionContext exceptionContext);
public virtual Task OnExceptionAsync(MethodExceptionContext exceptionContext);
}
You can either use ServiceFilterAttribute or TypeFilterAttribute which work similar to .NET MVC Core
public class FilterAttributeOnClassMethod : MethodFilterAttribute
{
private readonly ILogger _logger;
public FilterAttributeOnClassMethod(ILogger logger)
{
_logger = logger;
}
}
public class OrderService : IOrderService
{
[ServiceFilter(typeof(FilterAttributeOnClassMethod))]
public Order GetById(int id)
{
if (id <= 0) throw new ArgumentException("invalid order id");
return new Order {Id = id, TotalAmount = id * DateTime.Now.Ticks};
}
[TypeFilter(typeof(FilterAttributeOnClassMethod))]
public async Task<Order> GetByIdAsync(int id)
{
await Task.Delay(10);
return GetById(id);
}
}
var serviceCollection = new ServiceCollection();
serviceCollection.UseFlatwhiteFilters();
serviceCollection.RegisterWithMethodFilters<IOrderService, OrderService>(ServiceLifetime.Singleton);
// You must register the filter so ServiceProvider can resolve it later
serviceCollection.AddSingleton<FilterAttributeOnClassMethod>();
You can create an interface, have some method filters on its method and dont even need to implement the interface
public class FireProductDeletedEvent : MethodFilterAttribute
{
}
public class HandleAllException : ExceptionFilterAttribute
{
}
/// <summary>
/// This is the interface without any implementation, you can implement the main code in FireProductDeletedEvent and exception handling in HandleAllException
/// </summary>
[HandleAllException]
public interface IProductNotificationService
{
[FireProductDeletedEvent]
Task FireProductEvent(Guid sku);
}
var serviceCollection = new ServiceCollection();
serviceCollection.UseFlatwhiteFilters();
serviceCollection.AddProxyWithoutTarget<IProductNotificationService>(ServiceLifetime.Singleton);