简体   繁体   English

ASP.NET 核心 - ModelState.ValidationState 对于某些属性未经验证

[英]ASP.NET Core - ModelState.ValidationState is unvalidated for some properties

I have a controller that takes some model MyModel in a POST method.我有一个 controller 在 POST 方法中需要一些 model MyModel Inside of the controller method, there is a check:在 controller 方法内部,有一个检查:

[HttpPost("mymodel")]
public async Task<IActionResult> DoStuff(MyModel model)
{
   if (!ModelState.IsValid)
   {
     // early return with errors
   }

   // ...
}

With some specific data, ModelState.IsValid == false and ModelState.ErrorCount == 0 .对于一些特定的数据, ModelState.IsValid == falseModelState.ErrorCount == 0 The reason why it is invalid, is that some properties end up with ValidationState == Unvalidated , making the whole model Unvalidated , thus not valid.它无效的原因是某些属性以ValidationState == Unvalidated ,使整个 model Unvalidated ,因此无效。

How can I find out what happens?我怎样才能知道发生了什么? Why would some properties be just Unvalidated instead of having an error?为什么有些属性只是Unvalidated而不是有错误? Some of the Unvalidated properties have validation attributes, some don't, but other properties that end up as valid also follow the same pattern - some have attributes, some don't.有些Unvalidated属性有验证属性,有些没有,但其他最终有效的属性也遵循相同的模式——有些有属性,有些没有。

Any help with a digging direction would appreciated.任何有关挖掘方向的帮助将不胜感激。

It turns out, that in our case the properties in Unvalidated state were defined in base class, some of them were get-only.事实证明,在我们的例子中,未验证的 state 中的属性是在基础Unvalidated中定义的,其中一些是仅获取的。 When we called the endpoint, the POST data had values for the get only properties, because model came from GET endpoint.当我们调用端点时,POST 数据具有仅获取属性的值,因为 model 来自 GET 端点。

Now, in the UI we removed one element from a list, making the previously calculated values out of date.现在,在 UI 中,我们从列表中删除了一个元素,使之前计算的值过时。 The difference was cause of the error - it went away when stopped sending the properties.差异是错误的原因 - 当停止发送属性时它消失了。

I tried to create a repro, but it works on minimal example, and I wasted enough time on that.我试图创建一个复制品,但它适用于最小的例子,我浪费了足够的时间。 Maybe someone will find that helpful.也许有人会觉得这很有帮助。 Here is what I thought would recreate the problem:这是我认为会重现问题的方法:

public class Class1
{
    public List<Class2> Objects { get; set; } = new();
    public List<Class2> Objects2 => Objects.ToList();
    public IEnumerable<int> ObjectsIds => Objects.Select(x => x.Id);
}

public class Class2
{
    public int Id { get; set; }
}

public class SampleController : Controller
{
    [HttpPost("/post")]
    public ActionResult Post(Class1 arg)
    {
        if (!ModelState.IsValid) // in our code this was invalid
        {
            return ValidationProblem();
        }

        return Ok();
    }
}

    [Fact]
    public async Task Test1()
    {
        var application = new WebApplicationFactory<Program>();

        var client = application.CreateClient();

        var value = new
        {
            Objects = new[]
            {
                new { Id = 1 },
                new { Id = 2 },
                new { Id = 2 },
            },
            Objects2 = new[]
            {
                new { Id = 1 },
                new { Id = 2 },
            },
            ObjectsIds = new[] { 1, 2, 3 }
        };

        var response = await client.PostAsJsonAsync("/post", value);
        response.StatusCode.Should().Be(HttpStatusCode.OK);
    }

The test is green though, and I have no idea why it fails in our case.虽然测试是绿色的,但我不知道为什么在我们的案例中它会失败。 Both are dotnet 6. I tried putting the get-only properties in derived class, deeper nesting, minimal example still works.两者都是 dotnet 6。我尝试将 get-only 属性放在派生的 class 中,嵌套更深,最小示例仍然有效。

Have a nice day祝你今天过得愉快

I experienced this and tried to get a better understanding on why it was happening and whether there was a way I could resolve this without what I felt was a hack-like approach.我经历过这种情况,并试图更好地理解它发生的原因,以及是否有一种方法可以解决这个问题,而无需我认为是一种类似 hack 的方法。 But in the end due to time constraints for the time being, I just iterated through the unvalidated items and set them to valid as per below eg但最后由于暂时的时间限制,我只是迭代了未验证的项目并将它们设置为有效,如下所示

        foreach (var e in ModelState)
        {
            if (ModelState[e.Key].ValidationState == Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Unvalidated)
            {
                ModelState[e.Key].ValidationState = Microsoft.AspNetCore.Mvc.ModelBinding.ModelValidationState.Valid;
            }
        }

It does the job for the time being at least.它至少暂时完成了这项工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM