【问题标题】:ASP.net core field of viewmodel is required despite the fact that it is nullableviewmodel 的 ASP.net 核心字段是必需的,尽管它可以为空
【发布时间】:2017-11-29 14:31:22
【问题描述】:

我正在使用 Asp.net 核心构建一个网络应用程序。我正在使用内置的核心验证方法。我有一个表单,我想使用数据注释应用客户端验证。我的模型如下所示:

[Display(Name= "Address")] 
[Required]
[StringLength(80, MinimumLength = 5)]
public string Address { get; set; }

[Display(Name = "When it is needed")]
[Required]
[DataType(DataType.Date)]
public DateTime TakeDownDate { get; set; }

[Display(Name = "Exact time")]
[Required]
[DataType(DataType.Time)]
public TimeSpan ExactTimeToTakeDown { get; set; }

[Display(Name = "Content of container")]
public ContainerContentEnum? Content { get; set; }

[Display(Name = "When to take up")]
[DataType(DataType.Date)]
public DateTime? TakeUpDate { get; set; }   

[Display(Name= "Other comment")]
[StringLength(250)]
public string Other { get; set; }

[Display(Name = "Multiple round")]
public bool MaybeMoreRound { get; set; }

让我们看看 TakeUpDate 属性。它可以为空,因此我允许用户不要在字段中输入任何内容来提交表单。表单提交后,由相应的控制器方法处理:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult SaveNewClaim(NewClaimViewModel newClaim)
{
    if (ModelState.IsValid)
    {
        _claimsRepository.Insert(_newClaimViewModelToClaimConverterService.Convert(newClaim));
        return CreateJsonResult(true, "Az igény sikeresen lementésre került");
    }

    return CreateJsonResult(false, GetErrorMessages());
}

private JsonResult CreateJsonResult(bool isSuccess, string responseMessage)
{
    return Json(new
        {
            success = isSuccess,
            responseText = responseMessage
        }
    );
}

private string GetErrorMessages()
{
    return string.Join(";\n", ModelState.Values
        .SelectMany(x => x.Errors)
        .Select(x => x.ErrorMessage));
}

对于视图,.cshtml 文件如下所示:

@using App.ViewModels.ClaimViewModels.ClaimModels
@model App.ViewModels.ClaimViewModels.ClaimModels.NewClaimViewModel

<div id="calendarModal" class="modal fade">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true"></span> <span class="sr-only">close</span></button>
                <h3><b>Új igény felvétele</b></h3>
            </div>
            <div id="modalBody" class="modal-body">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                <form asp-action="SaveNewClaim" id="EventForm" class="well">
                    <input type="hidden" id="eventID" class="form-control">
                    <div class="form-group">
                        <label asp-for="Address" class=""></label>
                        <div class="">
                            <input asp-for="Address" class="form-control">
                            <span asp-validation-for="Address" class="text-danger"> </span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label asp-for="TakeDownDate" class=""></label>
                        <div class="">
                            <input asp-for="TakeDownDate" class="form-control" />
                            <span asp-validation-for="TakeDownDate" class="text-danger"> </span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label asp-for="ExactTimeToTakeDown" class=""></label>
                        <div class="">
                            <input asp-for="ExactTimeToTakeDown" class="form-control" />
                            <span asp-validation-for="ExactTimeToTakeDown" class="text-danger"> </span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label asp-for="Content" class=""></label>
                        <div class="">
                            <select asp-for="Content" asp-items="@Html.GetEnumSelectList<MokaKukaMap.Domain.Model.ContainerContentEnum>()" class="form-control">
                                <option selected="selected" value="">Kérem válassz</option>
                            </select>
                            <span asp-validation-for="Content" class="text-danger"> </span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label asp-for="TakeUpDate" class=""></label>
                        <div class="">
                            <input asp-for="TakeUpDate" class="form-control" />
                            <span asp-validation-for="TakeUpDate" class="text-danger"> </span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label asp-for="Other" class=""></label>
                        <div class="">
                            <input asp-for="Other" class="form-control" />
                            <span asp-validation-for="Other" class="text-danger"> </span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label asp-for="MaybeMoreRound" class=""></label>
                        <div class="">
                            <input asp-for="MaybeMoreRound" type="checkbox" class="form-control" />
                            <span asp-validation-for="MaybeMoreRound" class="text-danger"> </span>
                        </div>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" id="btnPopupCancel" data-dismiss="modal" class="btn">Vissza</button>
                <button type="button" id="btnPopupSave" class="btn btn-primary">Igény mentése</button>
            </div>
        </div>
    </div>
</div>

最后但并非最不重要的是我在提交按钮上的 ajax 帖子(点击事件):

$('#btnPopupSave').click(function () {
    var dataRow = {
        Address: $('#Address').val(),
        TakeDownDate: $('#TakeDownDate').val(),
        ExactTimeToTakeDown: $('#ExactTimeToTakeDown').val(),
        Content: $('#Content').val(),
        TakeUpDate: $('#TakeUpDate').val(),
        Other: $('#Other').val(),
        MaybeMoreRound: $('#MaybeMoreRound').val()
    }

    console.log('Submitting form...');
    $.ajax({
        type: 'POST',
        url: 'SaveNewClaim',
        data: dataRow,
        headers:
        {
            "RequestVerificationToken": '@GetAntiXsrfRequestToken()'
        },
        dataType: 'json',
        success: function (response) {
            if (response.success) {
                $('#calendarModal').modal('hide');
                $('#calendar').fullCalendar('refetchEvents');
                alert(response.responseText);
            }
            else {
                alert(response.responseText);
            }
        },
        error: function(xMlHttpRequest, textStatus, errorThrown) {
            console.log(XMLHttpRequest.responseText);
            console.log(textStatus);
            console.log(errorThrown);
        }
    });
});

尽管我将 TakeUpDate 设置为可为空,但我的模型仍然无效,并且收到以下错误消息: “何时使用”值无效。

老实说,我在 stackoverflow 和其他论坛中检查了所有相关的 Q/As,他们都说这是将字段设置为可空的正确方法。

如果您需要更多代码,我会立即将其添加到此问题中...

【问题讨论】:

  • 什么类型被传递给 TakeUpDate 的控制器?如果您的表单上只有一个空白文本框,那么控制器将收到一个空字符串;不是可以为空的 DateTime。
  • 错误消息The value 'When to take up' is invalid 告诉我它正在尝试将“何时占用”解析为字符串。你可以发布你的标记(剃刀)
  • @melkisadek 传递的类型是:“System.Date.DateTime?”它的值为null。
  • @Alex 我更新了我的问题
  • 所以您的表单传递的是一个空字符串,而不是可为空的 DateTime 类型。您需要在 ModelState.IsValid 调用之前捕获它并将其更改为 null。 2天前的建议应该有效。在控制器的 SaveNewClaim 操作中,在 if (ModelState.IsValid) 行上方写入 newClaim.TakeUpDate = null;。然后再次检查调试属性 Attempted Value。

标签: c# asp.net asp.net-mvc validation asp.net-core


【解决方案1】:

根本问题是您将空字符串传回控制器。

您需要在模型绑定发生之前捕获该空字符串并将其转换为 null,或者您需要解决已知的“错误”并处理此时验证总是会失败的事实。

您可以更改 Ajax POST 以显式发送空值。

或者(可能是我会做的)只是在控制器中检查您的日期。如果它是一个空字符串,则将其从 ModelState 中删除,这样它就不会被标记为无效(因为您已经知道它是什么以及为什么)。 ModelState 仍将正常验证其他字段。

类似于以下内容:

public IActionResult SaveNewClaim(NewClaimViewModel newClaim)
{
    if (newClaim.TakeUpDate == "")
    {
        ModelState.Remove("TakeUpDate");
    }

    if (ModelState.IsValid)
    {
        newClaim.TakeUpDate = null;

        _claimsRepository.Insert(_newClaimViewModelToClaimConverterService.Convert(newClaim));
        return CreateJsonResult(true, "Az igény sikeresen lementésre került");
    }

    return CreateJsonResult(false, GetErrorMessages());
}

【讨论】:

    猜你喜欢
    • 2017-06-26
    • 2022-12-14
    • 1970-01-01
    • 1970-01-01
    • 2016-11-27
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    • 2019-01-22
    相关资源
    最近更新 更多