在 MD5 Encryption in .NET/.NET Core 中写了一个MD5加密模块,在使用中访问加载了此模块的页面会立即报错“InvalidOperationException: Unable to resolve service for type”。

原因是我在Controller代码中使用了依赖注入的写法,但是Startup.cs中没有注入该模块。

参考

步骤

  1. 我的Controller代码:
    public class LoginController : Controller
    {
            //加密模块
            private readonly Encryption encryption;
            private readonly FamilySysDbContext db;
    
            public LoginController(FamilySysDbContext _db, Encryption _encryption)
            {
                db = _db;
                encryption = _encryption;
            }
                ... ...
    }
  2. 需要在Startup.cs中依赖注入该模块:
    public void ConfigureServices(IServiceCollection services) {
                    ... ...
        //加密模块
        services.AddScoped<Encryption>();
    
        ... ...
    
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

有三种方法实现依赖注入,分别为AddTransient()AddSingleton()AddScoped()。关于它们的区别可见 asp.net core2.0 依赖注入 AddTransient与AddScoped的区别

Enviroment

  • .NET Core 2.1

References

Step

To acheive the encryption purpose, all we need to do is copy&paste. Usage is written in the MSDN page I posted above.

public class Encryption {
    private MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();

    public string Encrypt(string key)
    {
        byte[] data = md5.ComputeHash(Encoding.Default.GetBytes(key));
        StringBuilder sBuilder = new StringBuilder();
        for (int i = 0; i < data.Length; i++)
        {
            sBuilder.Append(data[i].ToString("x2"));
        }

        return sBuilder.ToString();
    }
}

I wrote it as a standalone module in my project, it’s easier to modify/add things in the future.

In many cases, we need to check whether the input(username, phone number, etc.) that users type in already exists in database. In .NET/.NET Core, we can use DataAnnotation(or FluentAPI) to complete validations. In DataAnnotation, there’s a Remote() method which can help us to reach the “instant validation” purpose.

References

Steps

  1. Let’s say we have a UserSignUpViewModel, this model has an attribute called Username.
    public class UserSignUpViewModel {
    
        [Required(ErrorMessage = "请填写用户名")]
        [DisplayName("用户名")]
        [StringLength(20, MinimumLength = 2, ErrorMessage = "用户名长度在2-20位之间")]
        public string Username { get; set; }
    
        //...other attr....
    }

    Now we need to know whether it already exists in our database.

  2. First thing we nend to do is open the controller file and add a validate action.
    public JsonResult UsernameValidationJsonResult(string username)
    {
        bool isExists = db.Users.Any(x => x.Username == username);
        return Json(!isExists);
    }

    The return type is JsonResult though the return value will be just a “ture” or “false”.

    Note that if the username already exists, we need to return “false” to make the whole validation works.

  3. Then return to the model file, add Remote() DataAnnotation before the username attribute. Now the username section should be like this:
    public class UserSignUpViewModel {
        [Required(ErrorMessage = "请填写用户名")]
        [DisplayName("用户名")]
        [StringLength(20, MinimumLength = 2, ErrorMessage = "用户名长度在2-20位之间")]
        [Remote("UsernameValidationJsonResult", "Login", ErrorMessage = "用户名已存在")]
        public string Username { get; set; }
                
                //...other attrs...
    }

    The Remote() validation method needs two parameters——the action name in controller and the controller name.

  4. Open the View file which contains the username form, add JQuery script files that Visual Studio prepared for us.
    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

    Then add the @Html.ValidationMessageFor() method in the form.

  5. It should work.