【问题标题】:How to use a constructor from a Action model?如何使用 Action 模型中的构造函数?
【发布时间】:2021-01-09 05:25:27
【问题描述】:

我正在学习依赖注入。 如何使我的“UserCreate”模型使用我设置的自定义构造函数,当它被用作控制器操作的参数时?我想将 UserContext 传递给我的 UserCreate 模型。

我的行动:

[HttpPost]
    public JsonResult Post(UserCreate model)
    {
        var user = _repository.GetByUserName(model.Email);
        if (user != null)
        {
            this.ModelState.AddModelError(nameof(model.Email), "Email already registered!");
        }
        else
        {
            if (ModelState.IsValid)
            {
                var userModel = _mapper.Map<User>(model);
                _repository.Add(userModel);
                _repository.SaveChanges();
                return Json(new { success = "true" });
            }
        }
        return Json(new { success = "false", errors = this.ModelErrors(this.ModelState) });
    }

我的模特

public class UserCreate : BaseModel
{
    private readonly IUserRepo repo;

    public UserCreate(UserContext context) : base(context){
        repo = new UserRepository(context);
    }

    public UserCreate():base() { }


    [Required]
    [MaxLength(100)]
    public string Email { get; set; }

    [Required]
    [MaxLength(30)]
    public string Password { get; set; }

    [Required]
    [MaxLength(30)]
    public string FirstName { get; set; }

    [Required]
    [MaxLength(30)]
    public string MiddleName { get; set; }

    [Required]
    [MaxLength(30)]
    public string LastName { get; set; }

    [Required]
    public int Age { get; set; }

    [Required]
    public DateTime Birthday { get; set; }

    [Required]
    [MaxLength(250)]
    public string Adddress { get; set; }

    public DateTime Created { get { return DateTime.Now; } }


}

我已经在启动时设置了:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<UserContext>(opt => opt.UseSqlServer
            (Configuration.GetConnectionString("Dev")));
        services.AddControllers();
        services.AddScoped<IUserRepo, UserRepository>();
        services.AddScoped<ICardRepo, CardRepository>();
        services.AddScoped<IUserContext, UserContext>();
        services.AddScoped<TransactCreate, TransactCreate>();

        services.AddSingleton<UserCreate>(x =>
            new UserCreate(x.GetRequiredService<UserContext>()));

我已经在启动时设置了 Addsingleton,但是当我测试我的 API 时,会调用 public UserCreate():base() { } 构造函数而不是带有 UserContext 参数的构造函数。我正在使用 netcore 3.1

我想要这样做的原因是我将验证转移到模型,我需要从那里使用 UserContext。

谢谢!

【问题讨论】:

    标签: c# dependency-injection asp.net-core-webapi


    【解决方案1】:

    我了解您的要求,但请理解您解决此问题的方法存在很大缺陷。您的视图模型应该绝对对您的存储库一无所知。

    在 MVC 中,控制器负责处理 HTTP 请求(以及模型验证),并将操作委托给应用程序的其余部分。模型 (UserCreate) 应该是一个简单的 poco,只存在将数据从客户端传输回控制器。然后,控制器应将处理数据的责任委托给存储库。

    相反,您的控制器应该通过 DI 接受存储库,然后在验证后发送 UserCreate 模型。而您的模型UserCreate 应该 100% 具有无参数构造函数,因为 ModelBinder 将从请求中构建它。

    【讨论】:

    • 您好琼斯,感谢您的回复。我的控制器目前通过 DI 接受存储库并验证数据。但是我想要实现的是,如果我有多个需要从数据库中验证的属性,我不想将它们全部写入我的控制器操作中。您能推荐处理自定义验证的正确方法吗?谢谢!
    【解决方案2】:

    但是我想要实现的是如果我有多个属性 需要从数据库中验证,我不想把它们都写进去 我的控制器动作。你能推荐处理自定义的正确方法吗 验证?

    根据你的代码和前面的讨论,我假设你想验证输入的值是否存在于数据库中,如果值存在,则显示错误消息,例如“电子邮件已注册”。如果是这种情况,最好使用[Remote] 属性:

    代码如下:

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; }
    

    [AcceptVerbs("GET", "POST")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userService.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    

    另外,如果要创建自定义验证,可以查看this thread,然后,在自定义验证IsValid方法中,可以获取当前的dbcontext,检查输入的数据是否有效。代码如下:

    模型中的代码:

    [Required(ErrorMessage ="Country is Required")]
    public string Country { get; set; }
    [RequiredIfHasState("Country", ErrorMessage ="State is Required")]
    public string State { get; set; }
    

    自定义验证中的代码:

    public class RequiredIfHasStateAttribute : ValidationAttribute
    {
        private readonly string _comparisonProperty;
    
        public RequiredIfHasStateAttribute(string comparisonProperty)
        {
            _comparisonProperty = comparisonProperty;
        }
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            ErrorMessage = ErrorMessageString;
    
            //get entered state value
            var stateValue = (string)value;
            var property = validationContext.ObjectType.GetProperty(_comparisonProperty);
            if (property == null)
                throw new ArgumentException("Property with this name not found");
            //get the country value
            var countryValue = (string)property.GetValue(validationContext.ObjectInstance);
            //get the current dbcontext
            var _context = (MvcMovieContext)validationContext.GetService(typeof(MvcMovieContext));
            //query the database and check whether the country has state.
            if (_context.Countries.Where(c => c.CountryCode == countryValue).Select(c => c).FirstOrDefault().HasState)
            {
                if(stateValue == null)
                { 
                    //if country has state and the state is null. return error message
                    return new ValidationResult(ErrorMessage);
                }
                else
                {
                    //if country has state and the state is not found.
                    if(!_context.Countries.Where(c => c.CountryCode == countryValue).Any(c => c.States.Any(e => e.StateName == stateValue)))
                    {
                        return new ValidationResult("State not found");
                    }
                }
            }   
            return ValidationResult.Success;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-02
      • 1970-01-01
      • 2022-06-25
      • 2015-08-15
      • 1970-01-01
      相关资源
      最近更新 更多