将空字符串绑定到 Guid.Empty 或避免模型状态错误

发布于 2024-10-11 22:36:42 字数 1318 浏览 8 评论 0原文

当我发布一个 Guid 字段包含空字符串“”的表单时,我收到错误“MyGuid 字段是必需的”。虽然我还没有设置“必需”属性。

//NOT Required   
public Guid MyGuid { get; set; }

模型绑定后,Guid 为 00000000-0000-0000-0000-000000000000 (因为它是默认值),这是正确的。但 ModelState 有上述错误。

我怎样才能避免这个错误?

其他信息

[Required(AllowEmptyStrings = true)]没有帮助

我不想使Guid可为空(Guid?),因为这会导致很多额外的代码(检查它是否有值、映射等)

更新:

好的,我发现我的Guid?发生了变化视图模型不会导致比我预期的更多更改(对 MyGuid.GetValueOrDefault() 的一些调用或对 MyGuid.HasValue 的一些检查以及对 MyGuid 的调用.值)。

但是,如果 post 请求中未提供有效的 Guid,则会添加模型错误,原因是 DefaultModelBinder 尝试将 null 绑定到 Guid.解决方案是重写 DefaultModelBinder。并且不会将任何错误添加到模型状态中

public class MyModelBinder : DefaultModelBinder
{
    protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
    {
        if (propertyDescriptor.PropertyType == typeof(Guid) && value == null)
        {
            value = Guid.Empty;
        }
        base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);

    }
}

When I post a form with an empty string "" for a Guid field I get the error "The MyGuid field is required." although I haven't set the "Required" attribute.

//NOT Required   
public Guid MyGuid { get; set; }

after model binding the Guid is 00000000-0000-0000-0000-000000000000 (because it's the default value) and that's correct. But the ModelState has the mentioned error.

How can I avoid this error?

Additional Info:

[Required(AllowEmptyStrings = true)] does not help

I don't want to make the Guid nullable (Guid?) because this would lead to a lot additional code (checking if it has a value, mapping and so on)

Update:

OK, I figured out that a change to Guid? in my view models doesn't result in that many changes than I expected (some calls to MyGuid.GetValueOrDefault() or some checks for MyGuid.HasValue and calls to MyGuid.Value).

However, the reason that a model error is added if no valid Guid is provided with the post request, is that the DefaultModelBinder tries to bind null to Guid. The solution would be to override the DefaultModelBinder. And no errors will be added to the model state

public class MyModelBinder : DefaultModelBinder
{
    protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)
    {
        if (propertyDescriptor.PropertyType == typeof(Guid) && value == null)
        {
            value = Guid.Empty;
        }
        base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);

    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无可置疑 2024-10-18 22:36:42

如果字段的类型是Guid(它是值类型),那么它必须包含一个值(即使它全为零)。拥有非必需 GUID 的正确解决方案是使用 Guid? (Nullable Guid)。

您不想使用 Nullable 的理由没有意义;无论您采用哪种方式编码“空”,您的代码都必须检查它。我认为通常来说 Nullable 实际上使这变得更容易。

If the type of the field is Guid (which is a value type), then it must contain a value (even if it’s all zeros). The correct solution to have a non-required GUID is to use Guid? (Nullable Guid).

Your reasons for not wanting to use Nullable don’t make sense; no matter which way you are going to encode “emptiness”, your code will have to check for it. I’d argue that Nullable actually makes this easier, generally.

一身骄傲 2024-10-18 22:36:42

从我的回答https://stackoverflow.com/a/31268941/4985705的意义上来说ASP.NET MVC:模型绑定中的类型转换
如果需要,以下内容将返回 Guid.Empty 值或 Guid 参数。

public class NullableGuidBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(Guid?))
        {
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

            string input = valueResult.AttemptedValue;
            if (string.IsNullOrEmpty(input) || input == "0")
            {
                // return null, even if input = 0
                // however, that is dropdowns' "guid.empty")
                // base.BindModel(...) would fail converting string to guid, 
                // Guid.Parse and Guid.TryParse would fail since they expect 000-... format

                // add the property to modelstate dictionary
                var modelState = new ModelState { Value = valueResult };
                bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
                return Guid.Empty;
            }
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

在您的控制器中进行如下绑定

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> SelectAction(
        [ModelBinder(typeof(NullableGuidBinder))] Guid? id)
    {
        // your stuff
    }

in the sense of my answer https://stackoverflow.com/a/31268941/4985705 on ASP.NET MVC: types cast in model binding
the following will return the Guid.Empty values or the Guid parameter, if it is desired.

public class NullableGuidBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(Guid?))
        {
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

            string input = valueResult.AttemptedValue;
            if (string.IsNullOrEmpty(input) || input == "0")
            {
                // return null, even if input = 0
                // however, that is dropdowns' "guid.empty")
                // base.BindModel(...) would fail converting string to guid, 
                // Guid.Parse and Guid.TryParse would fail since they expect 000-... format

                // add the property to modelstate dictionary
                var modelState = new ModelState { Value = valueResult };
                bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
                return Guid.Empty;
            }
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

binding as follows in your controller

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> SelectAction(
        [ModelBinder(typeof(NullableGuidBinder))] Guid? id)
    {
        // your stuff
    }
等风来 2024-10-18 22:36:42

在您的应用程序启动事件中设置: DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

请记住,除非明确设置,否则所有值类型都不需要。

不过我同意法比亚诺的观点。 Guid 有点奇怪,它是 Guid.Empty。

In your application start event set: DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

Keeping in mind this will make all value types not required unless explicitly set so.

I agree with Fabiano though. Guid is a bit of a freak with it's Guid.Empty.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文