简体   繁体   中英

Implement custom ModelBinder ASP.NET MVC

I am having the same problem many people already had - Model Binder doesn't accept localized decimal input. In all of the threads, here and other forums, the recommended solution is implementing a custom ModelBinder .

My problem is that those solutions somehow don't work for me. Let's use this solution for example: comma decimal seperator in asp.net mvc 5

When I reference all namespaces, two errors remain:

Error CS0115 'DecimalModelBinder.BindModel(ControllerContext, ModelBindingContext)': no suitable method found to override ...

and

Error CS0173 Type of conditional expression cannot be determined because there is no implicit conversion between 'bool' and 'decimal'

Where the second one references the entire return statement.

Did something change in the MVC Framework, so this code is outdated, or am I doing something wrong?

The code I ended up with is:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.ModelBinding;
using System.Web.Mvc;

namespace AetMuzickaOprema.App_Start
{
    public class DecimalModelBinder : System.Web.ModelBinding.DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, System.Web.ModelBinding.ModelBindingContext bindingContext) //first error
        {
            var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

            return valueProviderResult == null ? base.BindModel(controllerContext, bindingContext) : Convert.ToDecimal(valueProviderResult.AttemptedValue); //second error

        }
    }
}

Model property in question:

[Required]
[Range(typeof(decimal), "0", "999999999")]
public decimal Price { get; set; }

It seems ultimately what you are trying to achieve is property-level binding such as this?:

[PropertyBinder(typeof(PropertyBBinder))]
public IList<int> PropertyB {get; set;}

If that is correct, this post offers a solution: Custom model binder for a property

Thanks.

In ASP.NET Core 1.1 (Microsoft.AspNetCore.Mvc.Core.Abstraction, 1.0.1.0) you'll see the following interface

using System.Threading.Tasks;

namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
    //
    // Summary:
    //     Defines an interface for model binders.
    public interface IModelBinder
    {
        //
        // Summary:
        //     Attempts to bind a model.
        //
        // Parameters:
        //   bindingContext:
        //     The Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingContext.
        //
        // Returns:
        //     A System.Threading.Tasks.Task which will complete when the model binding process
        //     completes.
        //     If model binding was successful, the Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingContext.Result
        //     should have Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingResult.IsModelSet
        //     set to true.
        //     A model binder that completes successfully should set Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingContext.Result
        //     to a value returned from Microsoft.AspNetCore.Mvc.ModelBinding.ModelBindingResult.Success(System.Object).
        Task BindModelAsync(ModelBindingContext bindingContext);
    }
}

Model binders are defined in Microsoft.AspNetCore.Mvc.ModelBinding.Binders namespace, assembly Microsoft.AspNetCore.Mvc.Core, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 . None of them seem to expose BindModel() method, even less a virtual one. It looks like you are trying to override a non-existing method.

A better approach is to take an existing ModelBinder , one that best suits your needs, inherit from it, and override ModelBindAsync() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM