[Asp.netCore Series) 10 ActionFilter s

Keywords: Programming Attribute

0. Preface

In the previous article, we mentioned how to create a UnitOfWork and enable it through the ActionFilter setting.In this post, we'll give you a brief introduction to ActionFilter and how to use it to complement the tool classes in the previous article.

1. Introduction to ActionFilter

The full name of ActionFilter is ActionFilterAttribute. We can see from Microsoft's naming conventions that this is a feature class. Take a look at its declaration:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public abstract class ActionFilterAttribute : Attribute, IActionFilter, IFilterMetadata, IAsyncActionFilter, IAsyncResultFilter, IOrderedFilter, IResultFilter

This is an attribute class that allows labeling on classes and methods, allows multiple tags, after which the subclass inherits the attributes of the parent class.This class is then an abstract class, so we can write our own ActionFilter by inheriting the ActionFilterAttribute.

Four methods of 1.1 ActionFilter

For an ActionFilter, the most important are its four methods:

public virtual void OnActionExecuted(ActionExecutedContext context);
public virtual void OnActionExecuting(ActionExecutingContext context);

public virtual void OnResultExecuted(ResultExecutedContext context);
public virtual void OnResultExecuting(ResultExecutingContext context);

The figure above shows the order in which the four methods are executed in one request.OnActionExecuting should be used to intercept a request before it is actually executed.

Why say this alone?This method is used most of the time for request filtering because of its high rate of appearance.

1.2 What can we do in ActionFilter

Let's take a brief look at the four contextual types of the four methods to see what we can use:

1.2.1 ActionExecutingContext

This is a pre-Action context indicating that the Action has not started execution, but a controller instance has been obtained:

public class ActionExecutingContext : FilterContext
{
    public virtual IDictionary<string, object> ActionArguments { get; }
    public virtual object Controller { get; }
    public virtual IActionResult Result { get; set; }
}

The ActionExecutingContext inherits from the FilterContext, and for the time being we don't care about its parent class, just look at its own properties.

  • ActionArguments represents a list of the parameters of an Action that are added by various user-received request parameters and other intermediate handlers.
  • Controller represents the controller that executes the request, as we mentioned earlier,Asp.netCore has very small limitations on the controller, so any type of controller is possible, so object is used here as the controller type
  • Result executes the result, and normally it makes no sense to get the value of this property here.But we can allow us to intercept requests by modifying the value of this property

1.2.2 ActionExecutedContext

The ActionExecutedContext represents the context in which the Action has been executed and from which we can obtain the results of the Action execution:

public class ActionExecutedContext : FilterContext
{
    public virtual bool Canceled { get; set; }
    public virtual object Controller { get; }
    public virtual Exception Exception { get; set; }
    public virtual ExceptionDispatchInfo ExceptionDispatchInfo { get; set; }
    public virtual bool ExceptionHandled { get; set; }
    public virtual IActionResult Result { get; set; }
}

Similarly, it inherits from the FilterContext and is ignored for the time being.

  • Canceled indicates whether a short circuit is set
  • Controller Handles Request Controller
  • Whether exceptions occur during Exception execution and have values if there are exceptions, otherwise Null
  • Is ExceptionHandled exception handled
  • Result Modification of Result here does not block the executing ActionResult, but it can hide the corresponding implementation from the user

1.2.3 ResultExecutingContext

This is the context that was executed before the Result rendering, when the Action has been executed and is ready to render the Result:

public class ResultExecutingContext : FilterContext
{
    public virtual bool Cancel { get; set; }
    public virtual object Controller { get; }
    public virtual IActionResult Result { get; set; }
}
  • Cancel cancels current result execution and subsequent filter execution
  • Controller controller
  • Result processing results

1.2.4 ResultExecutedContext

Result has been executed to get the execution result context:

public class ResultExecutedContext : FilterContext
{
    public virtual bool Canceled { get; set; }
    public virtual object Controller { get; }
    public virtual Exception Exception { get; set; }
    public virtual ExceptionDispatchInfo ExceptionDispatchInfo { get; set; }
    public virtual bool ExceptionHandled { get; set; }
    public virtual IActionResult Result { get; }
}

This class is similar to ActionExecutedContext and is not introduced.

1.2.5 FilterContext

The four contexts above all inherit from the FilterContext, so let's see what attributes or methods are in the FilterContext:

public abstract class FilterContext : ActionContext
{
    public virtual IList<IFilterMetadata> Filters { get; }
    public TMetadata FindEffectivePolicy<TMetadata>() where TMetadata : IFilterMetadata;
}

You can see that FilterContext inherits a class from another ActionContext.Partners should have some idea of this class, which is the context class for Action.It exists entirely within the life cycle of an Action, so it is sometimes possible to transfer data at the Action level through an ActionContext (not recommended).

So let's go back and see what's in the ActionContext:

public class ActionContext
{
    public ActionDescriptor ActionDescriptor { get; set; }
    public HttpContext HttpContext { get; set; }
    public ModelStateDictionary ModelState { get; }
    public RouteData RouteData { get; set; }
}
  • ActionDescriptor executes ActionDescription information, including the display name of the Action, some parameters, etc. When used, and then details for the group
  • HttpContext can get the Request and Response objects for this request through this property
  • ModelState Model Check Information, which will be detailed later for the small partners
  • RouteData routing information,Asp.netThe routing information that core parses when processing requests, including modified routing information in the program

2. Use ActionFilter

In "Asp.netCore Series) 9 UnitOfWork and Custom Code Generation, the last article introduced that ActionFilter is consistent with generic feature classes and can be enabled by labeling controllers.

Because in most cases, an ActionFilter is not limited to just one controller, but is applied to multiple controllers.So at this point, we usually set up an underlying controller, label it, and let the subclasses inherit it.This way you can achieve multiple uses of a declaration at a time.

Of course, inAsp.netAnother way to use ActionFilter is added to core.Setup.cs in

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
}

By default, we can add a globally applied Filter by setting parameters, such as the UnitOfWorkFilterAttribute we created in the last article:

services.AddControllersWithViews(options=>
{
    options.Filters.Add<UnitOfWorkFilterAttribute>();
});

This enables a global ActionFilter.If neededAsp.netThe default dependency injection for core can be configured using AddService.(Dependent injections will be explained later).

3. Tool class generation

Continue with the previous legacy:

public static void CreateEntityTypeConfig(Type type)
{
    var targetNamespace = type.Namespace.Replace("Data.Models", "");
    if (targetNamespace.StartsWith("."))
    {
        targetNamespace = targetNamespace.Remove(0);
    }
    var targetDir = Path.Combine(new[] { CurrentDirect, "Domain.Implements", "EntityConfigures" }.Concat(
        targetNamespace.Split('.')).ToArray());

    if (!Directory.Exists(targetDir))
    {
        Directory.CreateDirectory(targetDir);
    }
    var baseName = type.Name.Replace("Entity", "");
    if (!string.IsNullOrEmpty(targetNamespace))
    {
        targetNamespace = $".{targetNamespace}";
    }

    var file = $"using {type.Namespace};" +
        $"\r\nusing Microsoft.EntityFrameworkCore;" +
        $"\r\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;" +
        $"\r\nnamespace Domain.Implements.EntityConfigures{targetNamespace}" +
        "\r\n{" +
        $"\r\n\tpublic class {baseName}Config : IEntityTypeConfiguration<{type.Name}>" +
        "\r\n\t{" +
        "\r\n\t\tpublic void Configure(EntityTypeBuilder<SysUser> builder)" +
        "\r\n\t\t{" +
        $"\r\n\t\t\tbuilder.ToTable(\"{baseName}\");" +
        $"\r\n\t\t\tbuilder.HasKey(p => p.Id);" +
        "\r\n\t\t}\r\n\t}\r\n}";
    File.WriteAllText(Path.Combine(targetDir, $"{baseName}Config.cs"), file);
}

A tool class is essentially a method of writing a file at a time, and it is not difficult.

However, there is a small problem here, each call will overwrite the original file, and there are many areas that can be optimized, small partners can try to optimize themselves to make the code look better.

4 Summary

So far, there are also several articles in the real-world series, many little partners ask me if I can provide the source code?Of course, yes.But not now, let me leave a puzzle.When the main framework functionality is complete, I will send code to my little partners.

In fact, it is also because there is not a complete one yet, and opening it to small partners does not make any sense.Of course, following a knock is also achievable.There is code in key places.

Please pay attention to more content My blog, Mr. Gao's Cabin

Posted by blankextacy on Wed, 17 Jun 2020 15:03:01 -0700