C# 将空字符串绑定到Guid。空或避免模型状态错误

C# 将空字符串绑定到Guid。空或避免模型状态错误,c#,asp.net-mvc,asp.net-mvc-2,validation,model-binding,C#,Asp.net Mvc,Asp.net Mvc 2,Validation,Model Binding,当我为Guid字段发布带有空字符串“”的表单时,我会得到错误“MyGuid字段是必需的”。尽管我尚未设置“必需”属性 //NOT Required public Guid MyGuid { get; set; } 模型绑定后,Guid是00000000-0000-0000-0000-000000000000(因为它是默认值),这是正确的。但是ModelState有提到的错误 如何避免这个错误 其他信息: [必需(AllowEmptyStrings=true)]没有帮助 我不想让Guid为

当我为
Guid
字段发布带有空字符串“”的表单时,我会得到错误“MyGuid字段是必需的”。尽管我尚未设置“必需”属性

//NOT Required   
public Guid MyGuid { get; set; }
模型绑定后,Guid是
00000000-0000-0000-0000-000000000000
(因为它是默认值),这是正确的。但是ModelState有提到的错误

如何避免这个错误

其他信息:

[必需(AllowEmptyStrings=true)]
没有帮助

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

更新:

好的,我发现在我的视图模型中对
Guid?
的更改不会导致比我预期的多的更改(一些调用
MyGuid.GetValueOrDefault()
或一些检查
MyGuid.HasValue
和调用
MyGuid.Value

但是,如果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);

    }
}

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


你不想使用Nullable的理由毫无意义;无论您以何种方式编码“空”,您的代码都必须检查它。一般来说,我认为Nullable实际上使这更容易实现。

在应用程序启动事件集中:DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes=false

请记住,这将使所有值类型都不是必需的,除非显式设置为必需

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

在我关于 以下内容将返回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
    }
[HttpPost]
[ValidateAntiForgeryToken]
公共异步任务SelectAction(
[ModelBinder(typeof(NullableGuidBinder))]Guid?id)
{
//你的东西
}

谢谢您的回答。我的代码已经正确处理默认Guid(如果它必须处理它的话)。将其更改为其他类型需要进行大量更改。在各种ViewModels中,我有不止一个非必需的Guid。当试图绑定“GUID”时,难道没有一种方法告诉模型绑定器忽略错误吗?法比亚诺:如果您的代码将全零GUID处理为一个特殊的“null”值,尽管公认这可能是大范围的工作,我会认为它相当古怪和代码气味。代码的未来维护者无法从属性的类型判断它可能包含这个具有特殊意义的神奇值。另一方面,如果您使用
Guid?
,那么很明显它可能是
null
,这意味着什么。因此,我认为对代码进行必要的更改以适应可为null的类型是值得的?它似乎可以使用Guid对viewModel.MyGuid.GetValueOrDefault()的代码进行一些更改?意味着您现在有两个空值:null和Guid.empty。这意味着所有代码都应该检查这两个方面。这使得使用Guid比使用Guid更好吗?因为它使许多代码变得更容易:if(myGuid!=Guid.Empty)比if(myGuid!=null&&myGuid!=Guid.Empty)好,是否有代码检查Guid是否为
DefaultValue
?检查null/value比检查
DefaultValue
更有意义。存储
DefaultValue
而不是null只是让人困惑——这相当于存储“空字符串”而不是“”。是的,我的服务和DAO正在检查Guid.empty。我在这里使用的guid都是用于检索数据或设置引用的。我从不存储guidun的默认值幸运的是这没有帮助