Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/wordpress/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 自定义DecimalModelBinder和IValidatableObject.Validate之间的集成_Asp.net Mvc_Asp.net Mvc Validation_Custom Model Binder - Fatal编程技术网

Asp.net mvc 自定义DecimalModelBinder和IValidatableObject.Validate之间的集成

Asp.net mvc 自定义DecimalModelBinder和IValidatableObject.Validate之间的集成,asp.net-mvc,asp.net-mvc-validation,custom-model-binder,Asp.net Mvc,Asp.net Mvc Validation,Custom Model Binder,我正在使用MVC自定义验证服务器端,因为我必须使用几个自定义属性。 我想实现接口ValidatableObject,因为我认为这比编写几个自定义属性更简单 为了强制使用ValidationContext,我必须使用一个定制的模型绑定器,并遵循David Haney在其文章中的说明 所以我加入了global.asax ModelBinderProviders.BinderProviders.Clear(); ModelBinderProviders.BinderProviders.Add(n

我正在使用MVC自定义验证服务器端,因为我必须使用几个自定义属性。 我想实现接口ValidatableObject,因为我认为这比编写几个自定义属性更简单

为了强制使用ValidationContext,我必须使用一个定制的模型绑定器,并遵循David Haney在其文章中的说明

所以我加入了global.asax

 ModelBinderProviders.BinderProviders.Clear();
 ModelBinderProviders.BinderProviders.Add(new ForceValidationModelBinderProvider());
然后在课堂上

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Web.Mvc;


/// <summary>
/// A custom model binder to force an IValidatableObject to execute the Validate method, even when the ModelState is not valid.
/// </summary>
public class ForceValidationModelBinder : DefaultModelBinder
{


    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {

        base.OnModelUpdated(controllerContext, bindingContext);

        ForceModelValidation(bindingContext);
    }



    private static void ForceModelValidation(ModelBindingContext bindingContext)
    {
        // Only run this code for an IValidatableObject model
        IValidatableObject model = bindingContext.Model as IValidatableObject;
        if (model == null)
        {
            // Nothing to do
            return;
        }

        // Get the model state
        ModelStateDictionary modelState = bindingContext.ModelState;

        // Get the errors
        IEnumerable<ValidationResult> errors = model.Validate(new ValidationContext(model, null, null));

        // Define the keys and values of the model state
        List<string> modelStateKeys = modelState.Keys.ToList();
        List<ModelState> modelStateValues = modelState.Values.ToList();

        foreach (ValidationResult error in errors)
        {
            // Account for errors that are not specific to a member name
            List<string> errorMemberNames = error.MemberNames.ToList();
            if (errorMemberNames.Count == 0)
            {
                // Add empty string for errors that are not specific to a member name
                errorMemberNames.Add(string.Empty);
            }

            foreach (string memberName in errorMemberNames)
            {
                // Only add errors that haven't already been added.
                // (This can happen if the model's Validate(...) method is called more than once, which will happen when there are no property-level validation failures)
                int index = modelStateKeys.IndexOf(memberName);

                // Try and find an already existing error in the model state
                if (index == -1 || !modelStateValues[index].Errors.Any(i => i.ErrorMessage == error.ErrorMessage))
                {
                    // Add error
                    modelState.AddModelError(memberName, error.ErrorMessage);
                }
            }
        }
    }



}

/// <summary>
/// A custom model binder provider to provide a binder that forces an IValidatableObject to execute the Validate method, even when the ModelState is not valid.
/// </summary>
public class ForceValidationModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(Type modelType)
    {

        return new ForceValidationModelBinder();
    }
}
然后,正如Haney在评论中所建议的那样,我用global.asax中的CustomModelBinder替换了默认的DecimalModelBinder

  ModelBinders.Binders.Remove(typeof(double));
  ModelBinders.Binders.Remove(typeof(double?));

  ModelBinders.Binders.Add(typeof(double?), new CustomDecimalModelBinder());
  ModelBinders.Binders.Add(typeof(double), new CustomDecimalModelBinder());
但我不明白为什么。。CustomDecimalModelBinder无法启动。。。 因此,目前我的解决方法是在global.asax中评论上面的4行 在自定义ModelBinder类中添加BindModel的覆盖,以接受double和double?在it文化中

 public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {

        //if (bindingContext.ModelName == "commercialQty")
        if (bindingContext.ModelType == typeof(double?) || bindingContext.ModelType == typeof(double))
        {
            ValueProviderResult valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            ModelState modelState = new ModelState { Value = valueResult };
            object actualValue = null;
            try
            {
                //Check if this is a nullable decimal and a null or empty string has been passed
                var isNullableAndNull = (bindingContext.ModelMetadata.IsNullableValueType &&
                string.IsNullOrEmpty(valueResult.AttemptedValue));

                //If not nullable and null then we should try and parse the decimal
                if (!isNullableAndNull)
                {
                    actualValue = double.Parse(valueResult.AttemptedValue, NumberStyles.Any, CultureInfo.CurrentCulture);
                }
            }
            catch (FormatException e)
            {
                modelState.Errors.Add(e);
            }

            bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
            return actualValue;
        }
        else
        {
            return base.BindModel(controllerContext, bindingContext);


        }


    }
通过这种方式,ValidationContext与customValidation一起工作,我还以自定义方式验证了双类型

  public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
       {
           var results = new List<ValidationResult>();


           var fieldPreliminaryCostNum = new[] { "preliminaryCostNum" };
           var fieldPreliminaryCostAmount = new[] { "preliminaryCostAmount" };
           var fieldPreliminaryVoucherNum = new[] { "preliminaryVoucherNum" };
           var fieldCodiceIva = new[] { "codiceIva" };
           var fieldContoRicavi = new[] { "contoRicavi" };
           var fieldContoAnticipi = new[] { "contoAnticipi" };

           //per la obbligatorietà di preliminary cost num, preliminary voucher num e preliminary cost amount è sufficiente
           //il flag additional oppure occorre anche verificare che il voucher type code sia final?
           if (flagAdditional == BLCostanti.fAdditional && preliminaryCostNum == null)
           {
               results.Add(new ValidationResult(BLCostanti.labelCosto + "preliminaryCostNum ", fieldPreliminaryCostNum));

           }

           if (flagAdditional == BLCostanti.fAdditional && preliminaryCostAmount == null)
           {
               results.Add(new ValidationResult(BLCostanti.labelCosto + "preliminaryCostAmount ", fieldPreliminaryCostAmount));

           }

           if (flagAdditional == BLCostanti.fAdditional && preliminaryVoucherNum == null)
           {

               results.Add(new ValidationResult(BLCostanti.labelCosto + "preliminaryVoucherNum ", fieldPreliminaryVoucherNum));
               //inoltre il preliminary deve essere approvato!
               if (! BLUpdateQueries.CheckPreliminaryVoucherApproved(preliminaryVoucherNum) )
               {
                   results.Add(new ValidationResult(BLCostanti.labelCosto + "preliminaryVoucherNum non approvato", fieldPreliminaryVoucherNum));
               }
           }

           if (costPayReceiveInd == BLCostanti.attivo && String.IsNullOrWhiteSpace(codiceIva))
           {
               //yield return new ValidationResult("codiceIva obbligatorio", fieldCodiceIva); 
               results.Add(new ValidationResult(BLCostanti.labelEditableFields + "codiceIva ", fieldCodiceIva));

           }

           if ((sapFlowType == BLCostanti.girocontoAcquisto || sapFlowType == BLCostanti.girocontiVendita) 
               && String.IsNullOrWhiteSpace(contoRicavi))
           {

               results.Add(new ValidationResult(BLCostanti.labelEditableFields + "conto Ricavi ", fieldContoRicavi));

           }

           if ((sapFlowType == BLCostanti.girocontoAcquisto || sapFlowType == BLCostanti.girocontiVendita)
          && String.IsNullOrWhiteSpace(contoAnticipi))
           {

               results.Add(new ValidationResult(BLCostanti.labelEditableFields + "conto Anticipi ", fieldContoAnticipi));

           }

           return results;

       }
公共IEnumerable验证(ValidationContext ValidationContext) { var results=新列表(); var fieldPreliminaryCostNum=new[]{“preliminaryCostNum”}; var FIELDPRIMINARYCOSTAMOUNT=新[]{“preliminaryCostAmount”}; var fieldPreliminaryVoucherNum=new[]{“preliminaryVoucherNum”}; var fieldCodiceIva=new[]{“codiceIva”}; var fieldContoRicavi=new[]{“contoRicavi”}; var fieldContoAnticipi=new[]{“contoAnticipi”}; //根据初步成本数量,初步凭证数量和初步成本金额足够 //il标志附加机会occorre anche验证il凭证类型代码sia final? 如果(flagAdditional==BLCostanti.fAdditional&&preliminaryCostNum==null) { 结果.添加(新的验证结果(BLCostanti.labelCosto+“preliminaryCostNum”,fieldPreliminaryCostNum)); } 如果(flagAdditional==BLCostanti.fAdditional&&preliminaryCostAmount==null) { 结果。添加(新的验证结果(BLCostanti.labelCosto+“preliminaryCostAmount”,fieldPreliminaryCostAmount)); } 如果(flagAdditional==BLCostanti.fAdditional&&preliminaryVoucherNum==null) { 结果.添加(新的验证结果(BLCostanti.labelCosto+“preliminaryVoucherNum”,fieldPreliminaryVoucherNum)); //我将通过初步开发! 如果(!blupdatequerys.CheckPreliminaryVoucherApproved(preliminaryVoucherNum)) { 结果.添加(新的验证结果(BLCostanti.labelCosto+“preliminaryVoucherNum非认可”,fieldPreliminaryVoucherNum)); } } if(costPayReceiveInd==BLCostanti.attivo&&String.IsNullOrWhiteSpace(codiceIva)) { //返回新的验证结果(“codiceIva obbligatorio”,fieldCodiceIva); 结果.添加(新的验证结果(BLCostanti.labelEditableFields+“codiceIva”,fieldCodiceIva)); } 如果((SAPFOWTYPE==BLCostanti.girocontoAcquisto | | SAPFOWTYPE==BLCostanti.girocontiVendita) &&String.IsNullOrWhiteSpace(contoRicavi)) { 结果.添加(新的验证结果(BLCostanti.labelEditableFields+“conto Ricavi”,fieldContoRicavi)); } 如果((SAPFOWTYPE==BLCostanti.girocontoAcquisto | | SAPFOWTYPE==BLCostanti.girocontiVendita) &&String.IsNullOrWhiteSpace(contoAnticipi)) { 结果.添加(新的验证结果(BLCostanti.labelEditableFields+“conto Anticipi”,fieldconto Anticipi)); } 返回结果; }
欢迎有更好的主意

您是否调试了ModelBinders.Binders并查看了集合中包含的内容?我猜是默认的活页夹在起作用。您可能需要删除
double
double?
键上的条目,然后添加自定义活页夹。谢谢!调试正如您所猜测的,double type的默认绑定器是DecimalModelBinder。。所以现在我必须删除这个默认的活页夹并添加新的。。我试试看!请原谅,执行此替换的正确位置可能是OnModelUpdated函数?我想您可能只想执行一次,因此在启动时,请通过
Global.asax.cs
再次打扰。。现在,在替换之后,我可以在ModelBinders.Binders中看到我的CustomDecimalModelBinder。问题是CustomDecimalModelBinder中的BindModel从未被命中(如果我设置了断点)。而如果注释ModelBinderProviders.BinderProviders.Clear();ModelBinderProviders.BinderProviders.Add(新的ForceValidationModelBinderProvider());它开火了。你能帮我弄明白怎么了吗?
  public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
       {
           var results = new List<ValidationResult>();


           var fieldPreliminaryCostNum = new[] { "preliminaryCostNum" };
           var fieldPreliminaryCostAmount = new[] { "preliminaryCostAmount" };
           var fieldPreliminaryVoucherNum = new[] { "preliminaryVoucherNum" };
           var fieldCodiceIva = new[] { "codiceIva" };
           var fieldContoRicavi = new[] { "contoRicavi" };
           var fieldContoAnticipi = new[] { "contoAnticipi" };

           //per la obbligatorietà di preliminary cost num, preliminary voucher num e preliminary cost amount è sufficiente
           //il flag additional oppure occorre anche verificare che il voucher type code sia final?
           if (flagAdditional == BLCostanti.fAdditional && preliminaryCostNum == null)
           {
               results.Add(new ValidationResult(BLCostanti.labelCosto + "preliminaryCostNum ", fieldPreliminaryCostNum));

           }

           if (flagAdditional == BLCostanti.fAdditional && preliminaryCostAmount == null)
           {
               results.Add(new ValidationResult(BLCostanti.labelCosto + "preliminaryCostAmount ", fieldPreliminaryCostAmount));

           }

           if (flagAdditional == BLCostanti.fAdditional && preliminaryVoucherNum == null)
           {

               results.Add(new ValidationResult(BLCostanti.labelCosto + "preliminaryVoucherNum ", fieldPreliminaryVoucherNum));
               //inoltre il preliminary deve essere approvato!
               if (! BLUpdateQueries.CheckPreliminaryVoucherApproved(preliminaryVoucherNum) )
               {
                   results.Add(new ValidationResult(BLCostanti.labelCosto + "preliminaryVoucherNum non approvato", fieldPreliminaryVoucherNum));
               }
           }

           if (costPayReceiveInd == BLCostanti.attivo && String.IsNullOrWhiteSpace(codiceIva))
           {
               //yield return new ValidationResult("codiceIva obbligatorio", fieldCodiceIva); 
               results.Add(new ValidationResult(BLCostanti.labelEditableFields + "codiceIva ", fieldCodiceIva));

           }

           if ((sapFlowType == BLCostanti.girocontoAcquisto || sapFlowType == BLCostanti.girocontiVendita) 
               && String.IsNullOrWhiteSpace(contoRicavi))
           {

               results.Add(new ValidationResult(BLCostanti.labelEditableFields + "conto Ricavi ", fieldContoRicavi));

           }

           if ((sapFlowType == BLCostanti.girocontoAcquisto || sapFlowType == BLCostanti.girocontiVendita)
          && String.IsNullOrWhiteSpace(contoAnticipi))
           {

               results.Add(new ValidationResult(BLCostanti.labelEditableFields + "conto Anticipi ", fieldContoAnticipi));

           }

           return results;

       }