SoFunction
Updated on 2025-03-07

C# Custom HttpFilter module perfect example

This article describes the perfect method of C# custom HttpFilter module, and is shared with you for your reference. The specific implementation method is as follows:

1. Background

Recently, I have to do user operation logs for the project, but I don’t want to add code to each method and write it to the user log. Because such a specific method violates the principle of single responsibilities, if the format of the log content changes in the later period, or any other requirements, the code of this method is mainly changing, so the HttpModule module is used to complete this function. Interested friends can refer to:About the understanding and application methods of HttpHandler and HttpModule

After practical application and improvement, we can now summarize it again.

2. Intercept timing

In the current version, the basis for interception is that during each request, the controller class request is intercepted, the http output stream is redirected, and the Controller and Action are analyzed. Next, find out whether there is a method to monitor this controller. If so, the request input parameters are analyzed, and the output content of this request is stored in the FilterContext, and handed over to the method to complete the corresponding logic.

Since in the initial writing method, all requests were redirected for streams, under asmx, you will encounter problems. As long as the redirect is redirected, the client calling the service will prompt 400 Http Bad Request. The specific reason for this error is not clear, but it is precisely because of this error that I found that the timing of my previous interception was wrong, and it should be placed before the request to determine whether the interception rule is satisfied. If it is satisfied, the output stream will be redirected.

3. Read the user name

There will always be some problems in the Module module. Finally, I used a cookie to remember the username and directly defined it as a FilterContext property. Explain the reason for doing this: Since there are many ways to remember the username, such as Session and Cookies, that is, the way to read the username is variable, so try to solve the problem before, so as to listen to the controller method directly obtain the username based on this attribute. Otherwise, the time for reading the username is placed after each listening controller module. Once the reading method changes, all modules will need to be changed. Of course, you can also avoid such a big change by inheriting a base class.

What I want to express here is: We do things similar to the underlying library, as stable as possible, and concentrate the changes points on the library itself, so that the application of relying on the library can be stable. If the API is unstable during the .net version update, we probably won't be using it either.

4. Application writing log

Typical examples are as follows:

Copy the codeThe code is as follows:
[FilterMethod("Login", "Login")]
public void Login(FilterContext context)
{
//Analyze the output content, here is written for the controller and method to be monitored
    var arr = ('|');
    var log = ("userName:{0} password:{1}",arr);
    (log);
}

This method means to monitor the Login method of the LoginController. Since we need to analyze the result of the request output, the analysis rules are strongly dependent on the controller. How does the controller's method return data, we need to analyze it according to the rules here. I am using Json in my project, so the monitoring places require deserialization of Json, and here is just a demo.

Another method can listen to multiple methods under one controller, or multiple controllers. This is designed to solve many Actions, the input parameters and output parameters are the same, and may be different only in the method name and internal implementation due to different business.

5. Application update cache

First of all, you can read this article about the application of Cache.Advanced Cache Usage

Since I have not written an example here, I will first describe the situation I use in the project. The system has many data dictionaries. When requesting the data dictionary, the program first loads the dictionary data from the database and puts it into the cache. At this time, there is a trick to put the cache, set the expiration time and set the callback before removing the cache. Let's take a look at the specific method definition:

Copy the codeThe code is as follows:
//
// Summary:
//      Insert the object into the object along with dependencies, expiration policies, and delegates that can be used to notify the application before removing items from the cache.
//
// Parameters:
//   key:
//                                                              �
//
//   value:
//      Object to be inserted into the cache.
//
//   dependencies:
//      The file dependency or cache key dependency of this item. When any dependencies change, the object is invalid and removed from the cache. If there are no dependencies, this parameter contains null.
//
//   absoluteExpiration:
//      The time when the inserted object will expire and be removed from the cache. To avoid possible local time problems (such as changing from standard time to daylight saving time), use
//       Instead of as this parameter value. If absolute expiration is used, the slideExpiration parameter must be set to .
//
//   slidingExpiration:
//      The interval between the last access time of the cached object and the expiration time of the object. If the value is equivalent to 20 minutes, the object expires and is removed from the cache after the last access 20 minutes. If the adjustable expires,
//       The absoluteExpiration parameter must be set to .
//
//   onUpdateCallback:
//        Delegate that will be called before removing the object from the cache. You can use it to update cache items and make sure cache items are not removed from cache.
//
// Exception:
//   :
//       The key, value, or onUpdateCallback parameter is null.
//
//   :
//      Set the slideExpiration parameter to an equivalent value less than or greater than one year.
//
//   :
//      Set the absoluteExpiration and slideExpiration parameters for the items to be added to the Cache. -or -dependencies
//        The parameter is null, the absoluteExpiration parameter is set to
//      And the slidingExpiration parameter is set to .
public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemUpdateCallback onUpdateCallback);

Take a closer look at the description of the onUpdateCallback parameter: the delegate that will be called before removing the object from the cache. You can use it to update cache items and make sure cache items are not removed from cache.

I pass the delegate to read the cache while putting the data dictionary into the cache, so that this delegate will be called again when the cache is actively removed or the cache expires, and the data dictionary will be placed in the cache again. So once the data dictionary changes, such as adding, deleting and modifying, then actively remove the dictionary cache and it can be automatically updated. Isn't it very convenient?

Different from writing operation logs, it is just that the processing logic changes, and they all need the requested input and output.

VI. Others

1. Since HttpModule is used to complete this function, if you need to run normally, you need to register the module in WebConfig. See Demo for details.

2. Log4Net is used in the project to record text logs and can be classified according to functions. See:Log4Net log classification maintenance

Click here for the full example codeDownload this site

I hope this article will be helpful to everyone's C# programming.