Skip to content

Instantly share code, notes, and snippets.

@KatsuYuzu
Last active December 16, 2015 17:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KatsuYuzu/2a20697338eeabb93376 to your computer and use it in GitHub Desktop.
Save KatsuYuzu/2a20697338eeabb93376 to your computer and use it in GitHub Desktop.
ASP.NET MVC カスタムモデルバインダー
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using WebApplication.Common;
namespace WebApplication
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// モデルバインダーの登録
// グローバルで一括登録するならキー型は nullable も忘れずに!
// カスタムバインダー側は nullable でなくておk。
// コントローラーやアクションでの個別利用なら適宜どうぞ。
ModelBinders.Binders.Add(typeof(int), new ThousandsSeparatorNumberBinder<int>());
ModelBinders.Binders.Add(typeof(int?), new ThousandsSeparatorNumberBinder<int>());
}
}
}
using System.Web.Mvc;
using WebApplication.Models;
namespace WebApplication.Controllers
{
public class HomeController : Controller
{
public ActionResult Index(Test model)
{
ViewBag.message = string.Format("値: {0}", model.Number);
return View();
}
}
}
@model WebApplication4.Models.Test
<form>
<h2>数値を入力してください。</h2>
@Html.TextBoxFor(x => x.Number)
<input type="submit" value="送信" />
<h2>結果</h2>
<strong>@ViewBag.message</strong>
@Html.ValidationSummary()
</form>
using System.ComponentModel.DataAnnotations;
namespace WebApplication.Models
{
public class Test
{
[Display(Name = "数値")]
public int? Number { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Web.Mvc;
namespace WebApplication.Common
{
/// <summary>
/// 1000 の桁で区切られた数字のブラウザー要求を数値型に対応付けます。
/// </summary>
/// <typeparam name="T">対応付ける数値型。</typeparam>
public class ThousandsSeparatorNumberBinder<T>
: DefaultModelBinder
where T : struct, IConvertible
{
/// <summary>
/// 送信された文字列の変換に使うパーサー。
/// </summary>
private static readonly Func<string, object> Parser;
/// <summary>
/// パーサーを初期化します。
/// </summary>
static ThousandsSeparatorNumberBinder()
{
// short, long は int と同様、float, double は decimal と同様なので割愛
var parsers = new Dictionary<Type, Func<string, object>>
{
{
typeof(int),
(string value) => int.Parse(value, NumberStyles.Integer | NumberStyles.AllowThousands)
},
{
typeof(decimal),
(string value) => decimal.Parse(value, NumberStyles.Number)
}
};
Parser = parsers[typeof(T)];
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == null)
{
return base.BindModel(controllerContext, bindingContext);
}
// モデルステートの設定
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
// 値の文字列
var valueString = valueProviderResult.AttemptedValue;
// 以下、変換処理
if (string.IsNullOrWhiteSpace(valueString))
{
return null;
}
try
{
return Parser(valueString);
}
catch (Exception ex)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);
return null;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment