C# 以百分比表示的十进制数据批注

C# 以百分比表示的十进制数据批注,c#,razor,C#,Razor,我对c#.netcore razor pages应用程序中数据对象上的字段使用以下DataAnnotation: [Display(Name = "Markup For Profit")] [Required] [DisplayFormat(DataFormatString = "{0:P0}", ApplyFormatInEditMode = true)] public double ProfitMarkup { get;

我对c#.netcore razor pages应用程序中数据对象上的字段使用以下DataAnnotation:

    [Display(Name = "Markup For Profit")]
    [Required]
    [DisplayFormat(DataFormatString = "{0:P0}", ApplyFormatInEditMode = true)]
    public double ProfitMarkup { get; set; }
在Razor页面上,我在输入中使用此字段:

<input asp-for="ProfitMarkup" class="form-control" autocomplete="off" />

ProfitMarkup的十进制值正确显示(即0.2显示为20%),这是好的。但是,当我提交表单时,客户端验证会引发错误:

“利润的字段标记必须是数字。”

我很确定这是因为“%”符号是由显示格式添加的


允许20%页面上的输入进入对象并将小数点设置为0.2的最佳方法是什么?

当您在输入框中有百分比符号作为DataAnnotation的一部分时,默认ModelBinder将无法获得正确的发布值。您可以创建自定义ModelBinder。使用ASP.Net MVC的示例:

// The ViewModel
    public class HomeViewModel
    {
        [Display(Name = "Markup For Profit")]
        [Required]
        [DisplayFormat(DataFormatString = "{0:P2}", ApplyFormatInEditMode =true)]
        public double ProfitMarkup { get; set; }
    }

// Two Classes to implement custom ModelBinder
    public class DoublePercentDataBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(HomeViewModel))
            {
                HttpRequestBase request = controllerContext.HttpContext.Request;
                string pMarkup = request.Form.Get("ProfitMarkup").TrimEnd('%');
                return new HomeViewModel
                {
                    ProfitMarkup = Double.Parse(pMarkup)/100
                };
            }
            else
            {
                return base.BindModel(controllerContext, bindingContext);
            }
        }
    }

    public class DoublePercentBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            HttpRequestBase request = controllerContext.HttpContext.Request;
            string pMarkup = request.Form.Get("ProfitMarkup").TrimEnd('%');
            return new HomeViewModel
            {
                ProfitMarkup = Double.Parse(pMarkup)/100
            };

        }
    }

// Attach it in Application_Start in Global.asax
       protected void Application_Start()
        {
            ModelBinders.Binders.Add(typeof(HomeViewModel), new DoublePercentBinder());
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }

// HomeController Get and Post
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            HomeViewModel vm = new HomeViewModel();
            vm.ProfitMarkup = 1.2;
            return View(vm);
    }

        [HttpPost]
        public ActionResult Index([ModelBinder(typeof(DoublePercentBinder))] HomeViewModel hvm)
        {
            return View(hvm);
        }

// The Razor View
@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
    <div>
        @Html.EditorFor(x => x.ProfitMarkup)
        @Html.ValidationMessageFor(x => x.ProfitMarkup)
    </div>
    <br />
    <input type="submit" value="Submit" />
}
//视图模型
公共类HomeViewModel
{
[显示(Name=“利润标记”)]
[必需]
[DisplayFormat(DataFormatString=“{0:P2}”,ApplyFormatInEditMode=true)]
公共双利润标记{get;set;}
}
//实现自定义ModelBinder的两个类
公共类DoublePercentDataBinder:DefaultModelBinder
{
公共重写对象BindModel(ControllerContext ControllerContext,ModelBindingContext bindingContext)
{
if(bindingContext.ModelType==typeof(HomeViewModel))
{
HttpRequestBase请求=controllerContext.HttpContext.request;
字符串pMarkup=request.Form.Get(“ProfitMarkup”).TrimEnd(“%”);
返回新的HomeViewModel
{
ProfitMarkup=Double.Parse(pMarkup)/100
};
}
其他的
{
返回base.BindModel(controllerContext、bindingContext);
}
}
}
公共类绑定器:IModelBinder
{
公共对象绑定模型(ControllerContext ControllerContext,ModelBindingContext bindingContext)
{
HttpRequestBase请求=controllerContext.HttpContext.request;
字符串pMarkup=request.Form.Get(“ProfitMarkup”).TrimEnd(“%”);
返回新的HomeViewModel
{
ProfitMarkup=Double.Parse(pMarkup)/100
};
}
}
//将其附加到Global.asax中的应用程序_Start中
受保护的无效应用程序\u Start()
{
添加(typeof(HomeViewModel),新的DoublePercentBinder());
RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
//HomeController获取和发布
公共类HomeController:控制器
{
公共行动结果索引()
{
HomeViewModel vm=新的HomeViewModel();
vm.ProfitMarkup=1.2;
返回视图(vm);
}
[HttpPost]
公共行动结果索引([ModelBinder(typeof(DoublePercentBinder))]HomeViewModel hvm)
{
返回视图(hvm);
}
//剃刀视野
@使用(Html.BeginForm(“Index”,“Home”,FormMethod.Post))
{
@EditorFor(x=>x.ProfitMarkup)
@Html.ValidationMessageFor(x=>x.ProfitMarkup)

}
添加新的百分比类型和百分比转换器TypeConverter为我解决了这个问题

我声明了一个新属性,它读取double ProfitMarkup属性,如下所示:

    [Display(Name = "Markup For Profit")]
    [Required]
    [NotMapped]
    public Percentage ProfitMarkupPercentage { get { return new Percentage(ProfitMarkup); } set { ProfitMarkup = value; } }
<input asp-for="ProfitMarkupPercentage" class="form-control" autocomplete="off" />
ProfitMarkup以双精度形式写入数据库或从数据库写入,ProfitMarkupCentage显示在razor页面上,如下所示:

    [Display(Name = "Markup For Profit")]
    [Required]
    [NotMapped]
    public Percentage ProfitMarkupPercentage { get { return new Percentage(ProfitMarkup); } set { ProfitMarkup = value; } }
<input asp-for="ProfitMarkupPercentage" class="form-control" autocomplete="off" />
默认的模型绑定器现在可以正确地在razor页面上的属性之间填充

还可以使用正则表达式将验证数据注释添加到ProfitMarkupPercentage属性:

[RegularExpression(@"^(0*100{1,1}\.?((?<=\.)0*)?%?$)|(^0*\d{0,2}\.?((?<=\.)\d*)?%?)$", ErrorMessage = "Invalid percentage")]

[RegularExpression(@“^(0*100{1,1}\)(?您可以使用字符串而不是双精度和RegularExpression属性来仅获取数字和%