Asp. Net Core Lightweight Aop Solution: AspectCore

  • 2021-09-24 22:02:06
  • OfStack

What is AspectCore Project?

AspectCore Project is a lightweight Aop (Aspect-oriented programming) solution for Asp. Net Core platform, which better follows the modular development concept of Asp. Net Core, and it is easier to build Web applications with low coupling and easy scalability by using AspectCore. AspectCore uses Emit to implement efficient dynamic proxies that do not rely on any third-party Aop libraries.

Enable to use AspectCore

Start Visual Studio. From the File menu, select New > Project. Select the ASP. NET Core Web Application project template to create a new ASP. NET Core Web Application project.

Install AspectCore. Extensions. DependencyInjection package from Nuget: PM > Install-Package AspectCore.Extensions.DependencyInjection The abstract InterceptorAttribute custom attribute class, which implements the IInterceptor interface, can be used in one case. AspectCore implements the Attribute-based interceptor configuration by default. Our custom interceptor looks like this:

public class CustomInterceptorAttribute : InterceptorAttribute
{
  public async override Task Invoke(IAspectContext context, AspectDelegate next)
  {
    try
    {
      Console.WriteLine("Before service call");
      await next(context);
    }
    catch (Exception)
    {
      Console.WriteLine("Service threw an exception!");
      throw;
    }
    finally
    {
      Console.WriteLine("After service call");
    }
   }
 }

Define the ICustomService interface and its implementation class CustomService:


public interface ICustomService
{
  [CustomInterceptor]
  void Call();
}
public class CustomService : ICustomService
{
  public void Call()
  {
    Console.WriteLine("service calling...");
  }
}

Injecting ICustomService into HomeController:


public class HomeController : Controller
{
  private readonly ICustomService _service;
  public HomeController(ICustomService service)
  {
    _service = service;
  }
  public IActionResult Index()
  {
    _service.Call();
    return View();
  }
}

Register ICustomService, and then configure the container for creating proxy types in ConfigureServices:


public IServiceProvider ConfigureServices(IServiceCollection services)
{
  services.AddTransient<ICustomService, CustomService>();
  services.AddMvc();
  services.AddAspectCore();
  return services.BuildAspectCoreServiceProvider();
}

Interceptor configuration. First install AspectCore. Extensions. Configuration package:


PM> Install-Package AspectCore.Extensions.Configuration

Global interceptor. Use AddAspectCore(Action<AspectCoreOptions>) Where AspectCoreOptions provides an InterceptorFactories registered global interceptor:


 services.AddAspectCore(config =>
 {
   config.InterceptorFactories.AddTyped<CustomInterceptorAttribute>();
 });

Global interceptor with constructor parameters, in CustomInterceptorAttribute Add a constructor with parameters in:


public class CustomInterceptorAttribute : InterceptorAttribute
{
  private readonly string _name;
  public CustomInterceptorAttribute(string name)
  {
    _name = name;
  }
  public async override Task Invoke(AspectContext context, AspectDelegate next)
  {
    try
    {
      Console.WriteLine("Before service call");
      await next(context);
    }
    catch (Exception)
    {
      Console.WriteLine("Service threw an exception!");
      throw;
    }
    finally
    {
      Console.WriteLine("After service call");
    }
  }
}

Modify the global interceptor registration:


services.AddAspectCore(config =>
{
   config.InterceptorFactories.AddTyped<CustomInterceptorAttribute>(args: new object[] { "custom" });
});

As a global interceptor for the service. Add in ConfigureServices:


services.AddTransient<CustomInterceptorAttribute>(provider => new CustomInterceptorAttribute("service"));

Modify the global interceptor registration:


services.AddAspectCore(config =>
{
  config.InterceptorFactories.AddServiced<CustomInterceptorAttribute>();
});

A global interceptor acting on a specific Service or Method. The following code demonstrates a global interceptor acting on a class with an Service suffix:


public interface ICustomService
{
  [CustomInterceptor]
  void Call();
}
public class CustomService : ICustomService
{
  public void Call()
  {
    Console.WriteLine("service calling...");
  }
}
0

Specific global interceptors that use wildcards:


public interface ICustomService
{
  [CustomInterceptor]
  void Call();
}
public class CustomService : ICustomService
{
  public void Call()
  {
    Console.WriteLine("service calling...");
  }
}
1

NonAspectAttribute is provided in AspectCore so that Service or Method is not proxy:


public interface ICustomService
{
  [CustomInterceptor]
  void Call();
}
public class CustomService : ICustomService
{
  public void Call()
  {
    Console.WriteLine("service calling...");
  }
}
2

It also supports global ignorance configuration and wildcard characters:


 services.AddAspectCore(config =>
 {
   //App1 Namespace Service Will not be represented 
   config.NonAspectOptions.AddNamespace("App1");
   // Finally 1 Grade is App1 Under the namespace of Service Will not be represented 
   config.NonAspectOptions.AddNamespace("*.App1");
   //ICustomService Interface will not be proxy 
   config.NonAspectOptions.AddService("ICustomService");
   // Suffix is Service Interfaces and classes of will not be proxied 
   config.NonAspectOptions.AddService("*Service");
   // Named Query The method of will not be proxy 
   config.NonAspectOptions.AddMethod("Query");
   // Suffix is Query The method of will not be proxy 
   config.NonAspectOptions.AddMethod("*Query");
 });

Dependency injection in interceptors. Support attribute injection, constructor injection and service locator mode in interceptor.
Attribute injection, attribute token with public get and set privileges in the interceptor [ AspectCore.Abstractions.FromServices ] (Distinguished from Microsoft.AspNetCore.Mvc.FromServices ) property, you can automatically inject the property, such as:


public interface ICustomService
{
  [CustomInterceptor]
  void Call();
}
public class CustomService : ICustomService
{
  public void Call()
  {
    Console.WriteLine("service calling...");
  }
}
4

Constructor injection requires the interceptor to act as an Service, and ServiceInterceptor can still be used to activate the interceptor from DI in addition to the global interceptor:


public interface ICustomService
{
  [CustomInterceptor]
  void Call();
}
public class CustomService : ICustomService
{
  public void Call()
  {
    Console.WriteLine("service calling...");
  }
}
5

Service locator mode. The interceptor context AspectContext can get the ServiceProvider of the current Scoped:


public interface ICustomService
{
  [CustomInterceptor]
  void Call();
}
public class CustomService : ICustomService
{
  public void Call()
  {
    Console.WriteLine("service calling...");
  }
}
6

Use Autofac and AspectCore. AspectCore native supports integration with Autofac, we need to install the following two nuget packages:


public interface ICustomService
{
  [CustomInterceptor]
  void Call();
}
public class CustomService : ICustomService
{
  public void Call()
  {
    Console.WriteLine("service calling...");
  }
}
7

AspectCore provides the RegisterAspectCore extension method to register the services required by the dynamic proxy in Container of Autofac, and provides the AsInterfacesProxy and AsClassProxy extension methods to enable the proxy of interface and class. Modify the ConfigureServices method to:


public IServiceProvider ConfigureServices(IServiceCollection services)
{
  services.AddMvc();
  var container = new ContainerBuilder();
  container.RegisterAspectCore();
  container.Populate(services);
  container.RegisterType<CustomService>().As<ICustomService>().InstancePerDependency().AsInterfacesProxy();

  return new AutofacServiceProvider(container.Build());
}

Feedback with problems

If you have any questions, please submit Issue to us.

AspectCore Project Project Address: https://github.com/aspectcore


Related articles: