Automatic BUG detection and BUG detection

Source: Internet
Author: User

Automatic BUG detection and BUG detection

I am a little lazy, and I will never do anything that can be done automatically. Recently I am using ASP.. NET Core writes a project and will accumulate some convenient tool classes or frameworks during the process.

If I have time in the future, I plan to write a series of [automatic BUG detection]. This article will be the first one.


If you have used ASP. NET Core, you must be familiar with dependency injection.
The procedure is as follows:
1. register the Service first. There are three methods: AddTransient, AddScoped, and AddSingleton.
2. Use the Service again. It is usually declared in the constructor.

 

First, let's talk about scenarios that generate bugs.
BUG scenario 1:
Sometimes you may forget to register a Service and use it directly. If you use that Service, an exception is reported. In this case, the project can be compiled and approved. It is a BUG that is not easily discovered. if the Service does not cover this BUG during testing, it will be taken to the production environment.

BUG Scenario 2:
There are usually some services that we only want to be used in the request scope. For example, services that hold database connections on the server end are usually at the request scope level, that is: when a database is used for the first time in a request, a database connection is created. The connection is reused in the request, and the request ends.
The registration method in ASP. NET Core is as follows:
Services. AddScoped <IDbContext, DbContext> ();

Services registered with AddScoped in ASP. NET Core are destroyed at the end of the request.
If you directly reference IDbContext In the controller, everything works normally. Now, we need to encapsulate a user management class UserManager, which is a singleton. The registration code is as follows:
Services. AddScoped <IUserManager, UserManager> ();

When writing the UserManager class, you need to access the database, and the IDbContext is easily referenced (normally it should not be referenced but forgotten). Because UserManager is a regular meeting, the IDbContext will never be released, in this case, a database connection is used for a long time. During compilation, no errors are reported during runtime, which is a hidden BUG.


Now, the scenario is complete. The main character of this article will be on the stage. The solution is as follows:
Add the following code at the end of the ConfigureServices method of the Startup class:

Public void ConfigureServices (IServiceCollection services) {// some code is omitted here... // ensure that the service dependency is correct. Put it in all the registered service code and call if (_ env. isDevelopment () services. assertDependencyValid ();}

For scenario 1, an exception is thrown:
Throw new InvalidProgramException ($ "the constructor of the Service {svceType. FullName} references the unregistered Service {paramType. FullName }");

This method of "scenario 2" throws an exception:
Throw new InvalidProgramException ($ "the construction method of Singleton's Service {svceType. FullName} references the Scoped Service {paramType. FullName }");

You can locate and modify the problematic Class Based on the exception prompt.

The complete code is as follows:

Using System; using System. collections. generic; using System. linq; using System. reflection; using System. resources; using System. text. regularExpressions; using System. threading. tasks; using Microsoft. extensions. dependencyInjection; namespace Microsoft. extensions. dependencyInjection {public static class MondolServiceCollectionExtensions {// <summary> // DUMP service list /// </summary> public static string Dump (t His IServiceCollection services) {var sevList = new List <Tuple <string, string> (); foreach (var sev in services) {sevList. add (new Tuple <string, string> (sev. lifetime. toString (), sev. serviceType. fullName);} sevList. sort (x, y) => {var cRs = string. compareOrdinal (x. item1, y. item1); return cRs! = 0? CRs: string. compareOrdinal (x. item2, y. item2) ;}); return string. join ("\ r \ n", sevList. select (p => $ "{p. item2}-{p. item1 }"));} /// <summary> /// ensure that the dependency of the currently registered service is correct /// </summary> public static void AssertDependencyValid (this IServiceCollection services) {var ignoreTypes = new [] {"Microsoft. aspNetCore. mvc. internal. mvcRouteHandler "," Microsoft. aspNetCore. razor. runtime. tagHelpers. tagHelperDescripto RResolver "}; foreach (var svce in services) {if (svce. lifetime = ServiceLifetime. singleton) {// ensure that Singleton's service cannot depend on Scoped's service if (svce. implementationType! = Null) {var svceType = svce. implementationType; if (ignoreTypes. contains (svceType. fullName) continue; var ctors = svceType. getConstructors (); foreach (var ctor in ctors) {var paramLst = ctor. getParameters (); foreach (var param in paramLst) {var paramType = param. parameterType; var paramTypeInfo = paramType. getTypeInfo (); if (paramTypeInfo. isGenericType) {if (paramType. toString (). startsWith ("System. collections. generic. IEnumerable '1 ") {paramType = paramTypeInfo. getGenericArguments (). first (); paramTypeInfo = paramType. getTypeInfo () ;}} if (paramType = typeof (IServiceProvider) continue; ServiceDescriptor pSvce; if (paramTypeInfo. isGenericType) {// fuzzy identification is used for generics. var prefix = Regex may be missing. match (paramType. toString (), @ "^ [^ '] +' \ d + \["). value; pSvce = services. firstOrDefault (p => p. serviceType. toString (). startsWith (prefix);} else {pSvce = services. firstOrDefault (p => p. serviceType = paramType);} if (pSvce = null) throw new InvalidProgramException ($ "Service {svceType. the FullName} constructor references the unregistered Service {paramType. fullName} "); if (pSvce. lifetime = ServiceLifetime. scoped) throw new InvalidProgramException ($ "Singleton Service {svceType. the FullName} constructor references the Scoped Service {paramType. fullName }");}}}}}}}}

  

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.