如何从 OnActionExecuting 中的模型获取 属性 值

How to get a property value from model in OnActionExecuting

我正在开展一个 Asp.Net core 5 项目,目标是 .Net 5

在很多情况下,我在视图中使用了 select 列表,并且从列表中选择的值将受到 model properties.

之一的影响

我熟悉 Action filters 但在我的水平上是初学者,所以我尝试创建一个自定义过滤器来检查 model 中是否有任何 property 的值相等default_option我将添加一个错误 model state,所有这些代码都应该发生在 OnActionExecuting 方法中。

我试过的:

public class CheckDefaultOptionFromSelect : ActionFilterAttribute
    {

        /// <inheritdoc />
        public override void OnActionExecuting( ActionExecutingContext context )
        {
            var model = ( (Controller) context.Controller ).ViewData.Model;

            if ( model is not null )
            {
                foreach ( var property in model.GetType().GetProperties() )
                {

                        if ( (string) model.GetType().GetProperty( property.Name ).GetValue( model ).ToString() == "default_option" )
                        {
                            context.ModelState.AddModelError( "" , "Please select an option" );

                            base.OnActionExecuting( context );
                            break;
                        }
                }
            }
        }

    }

在那些动作视图中会有这样一块:

<div class="col-lg-4 col-sm-6">
                            <div class="form-group">
                                <div class="form-control-wrap">
                                    <select asp-for="PropertyName" asp-items="@(new SelectList(myCollection,"Id","Title") )" class="form-select form-control form-control-lg form-control-outlined" data-ui="lg" data-search="on">
                                        <option value="default_option">Default Option</option>
                                    </select>
                                    <label asp-for="PropertyName" class="form-label-outlined"></label>
                                    <span asp-validation-for="PropertyName" class="text-danger"></span>
                                </div>
                            </div>
                        </div>

最重要的一点是:

                                    <select asp-for="PropertyName" asp-items="@(new SelectList(myCollection,"Id","Title") )" class="form-select form-control form-control-lg form-control-outlined" data-ui="lg" data-search="on">
                                        <option value="default_option">Default Option</option>
                                    </select>

问题: 当我使用 break points 调试时,我看到 ( (Controller) context.Controller ).ViewData.Model 总是 null.

问题: 请问如何迭代所有 model 属性并检查值是否不等于 default_option

您需要获取如下模型数据:

public class CheckDefaultOptionFromSelect : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        context.ActionArguments.TryGetValue("model", out object model);

        if (model is not null)
        {
            foreach (var property in model.GetType().GetProperties())
            {
                if ((string)model.GetType().GetProperty(property.Name).GetValue(model).ToString() == "default_option")
                {
                    context.ModelState.AddModelError("", "Please select an option");
                    base.OnActionExecuting(context);
                    break;
                }
            }
        }
    }
}

整个测试代码:

型号:

public class Test2
{
    public int Id { get; set; }
    public string Title { get; set; }
}
public class TestViewModel
{
    public string PropertyName { get; set; }
}

查看:

注意:因为你添加的modelstate是空键,所以asp-validation-for="PropertyName"不会显示错误。务必添加<div asp-validation-summary="ModelOnly" class="text-danger"></div>以显示所有模型错误。

@model TestViewModel 
@{ 
    var myCollection = new List<Test2>()
    {
        new Test2(){ Id=1,Title="aaa"},
        new Test2(){Id=2,Title="bbb"},
        new Test2(){Id=3,Title="ccc"}
    };
}
<form method="post" asp-action="Index">
    <div class="col-lg-4 col-sm-6">
        <div class="form-group"> 

            <div asp-validation-summary="ModelOnly" class="text-danger"></div> 

            <div class="form-control-wrap">
                <select asp-for="PropertyName" asp-items="@(new SelectList(myCollection,"Id","Title") )" class="form-select form-control form-control-lg form-control-outlined" data-ui="lg" data-search="on">
                    <option value="default_option">Default Option</option>
                </select>
                <label asp-for="PropertyName" class="form-label-outlined"></label>
                <span asp-validation-for="PropertyName" class="text-danger"></span>
            </div>
        </div>
    </div>
    <input value="Create" type="submit" />
</form>

控制器:

public IActionResult Index()
{
    return View();
}

[HttpPost]
[ServiceFilter(typeof(CheckDefaultOptionFromSelect))]

public IActionResult Index(TestViewModel model)
{
    if (ModelState.IsValid)
    {
        return View();
    }
    else
    {
        return View(model);
    }
}

在Startup.cs中注册ActionFilterAttribute:

services.AddScoped<CheckDefaultOptionFromSelect>();