Проблема с десятичным разделителем в привязке данных для Asp Net Core - PullRequest
0 голосов
/ 02 ноября 2018

Я пытаюсь создать объект в AspNet.Core MVC с помощью атрибута [FromForm].

[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
[Route("[action]")]
public async Task<IActionResult> Payments([FromForm]IncomingPayment dataPayment)

Моя проблема : Мое свойство Amount никогда не устанавливается успешно, т. Е. Всегда равно нулю.

/// <summary>
/// Объект данных запроса уведомления о поступившем платеже
/// </summary>
public class IncomingPayment
{
    /// <summary>
    /// Сумма поступившего платежа
    /// </summary>
    [Required]
    [BindProperty(Name = "amount", SupportsGet = false)]
    public decimal Amount { get; set; }

}

Как считать Преобразование в формат десятичного значения (680.37) Желательно использовать атрибуты?

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

Таможенные переплеты - путь сюда. Это будет гораздо более общее решение.

Пользовательские Binder

using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System;
using System.Globalization;
using System.Threading.Tasks;

namespace CustomBinders
{
    public class DecimalBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.Metadata.ModelType == typeof(decimal))
            {
                return new BinderTypeModelBinder(typeof(DecimalBinder));
            }
            if (context.Metadata.ModelType == typeof(decimal?))
            {
                return new BinderTypeModelBinder(typeof(DecimalBinder));
            }

            return null;
        }
    }

    public class DecimalBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));

            }
            var valueResult = bindingContext.ValueProvider
                 .GetValue(bindingContext.ModelName);

            if (valueResult == ValueProviderResult.None)
            {
                return Task.CompletedTask;
            }

            object actualValue = null;
            var culture = CultureInfo.CurrentCulture;

            if (valueResult.FirstValue != string.Empty)
            {
                try
                {
                    // Try with your local culture
                    actualValue = Convert.ToDecimal(valueResult.FirstValue, culture);
                }
                catch (FormatException)
                {
                    try
                    {
                        // Try with your invariant culture
                        actualValue = Convert.ToDecimal(valueResult.FirstValue, CultureInfo.InvariantCulture);
                    }
                    catch (FormatException)
                    {
                        bindingContext.ModelState.TryAddModelError(
                                    bindingContext.ModelName,
                                    "You should provide a valid decimal value");

                        return Task.CompletedTask;
                    }
                }
            }

            bindingContext.Result = ModelBindingResult.Success(actualValue);

            return Task.CompletedTask;
        }
    }
}

И используйте это так

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // ... rest of configuration
        services.AddMvc( options=>
        {
            // ... rest of configuration
            options.ModelBinderProviders.Insert(0, new DecimalBinderProvider());
        }
    );
}
0 голосов
/ 02 ноября 2018

Решил мою проблему таким образом

/// <summary>
/// Объект данных запроса уведомления о поступившем платеже
/// </summary>
public class IncomingPayment
{
    /// <summary>
    /// Сумма поступившего платежа
    /// </summary>
    public decimal Amount { get; set; }

    /// <summary>
    /// Сумма поступившего платежа в строковом формате
    /// </summary>
    private string _amountAsString;

    /// <summary>
    /// Обертка суммы поступившего платежа в строковом формате
    /// </summary>
    [Required]
    [BindProperty(Name = "amount", SupportsGet = false)]
    public string AmountAsString
    {
        get => _amountAsString;
        set
        {
            _amountAsString = value;

            if (!decimal.TryParse(_amountAsString.Replace('.', Program.PointChar), out var doubleAmount)) return;

            Amount = doubleAmount;
        }
    }
}

Хорошо, когда я запускаю приложение, я получаю системный разделитель

 PointChar = double.TryParse("1,2", out _) ? ',' : '.';
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...