Asp.net MVC のカスタム DateTime モデル バインダー
-
23-09-2019 - |
質問
独自のモデル バインダーを作成したいと考えています。 DateTime
タイプ。まず最初に、次のようにモデル プロパティにアタッチできる新しい属性を作成したいと思います。
[DateTimeFormat("d.M.yyyy")]
public DateTime Birth { get; set,}
これは簡単な部分です。ただし、バインダーの部分は少し難しいです。タイプ用の新しいモデル バインダーを追加したい DateTime
. 。どちらでもできます
- 埋め込む
IModelBinder
インターフェイスを作成し、独自のインターフェイスを作成するBindModel()
方法 - から継承する
DefaultModelBinder
そしてオーバーライドBindModel()
方法
私のモデルには上記のようなプロパティがあります(Birth
)。したがって、モデルがリクエスト データをこのプロパティにバインドしようとすると、モデル バインダーの BindModel(controllerContext, bindingContext)
呼び出されます。大丈夫だけど。 日付を正しく解析するには、controller/bindingContext からプロパティ属性を取得するにはどうすればよいですか?どうすればそこに着くことができますか PropertyDesciptor
財産の Birth
?
編集
関心事の分離のため、私のモデル クラスは System.Web.MVC アセンブリを参照しない (そして参照すべきではない) アセンブリで定義されています。カスタム バインディングの設定 ( スコット・ハンセルマンの例) 属性はここでは使用できません。
解決
ロケール固有の属性をモデルに設定すべきではないと思います。
この問題に対する他の 2 つの解決策は次のとおりです。
- ページで日付をロケール固有の形式から JavaScript の yyyy-mm-dd などの汎用形式に音訳します。(動作しますが、JavaScript が必要です。)
- 日付を解析するときに現在の UI カルチャを考慮するモデル バインダーを作成します。
実際の質問に答えると、(MVC 2 の) カスタム属性を取得する方法は次のとおりです。 AssociatedMetadataProvider を書きます.
他のヒント
あなたはIModelBinder
を使用して、ユーザーのcultureを使用するデフォルトのモデルバインダーを変更することができますpublic class DateTimeBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
return value.ConvertTo(typeof(DateTime), CultureInfo.CurrentCulture);
}
}
public class NullableDateTimeBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
return value == null
? null
: value.ConvertTo(typeof(DateTime), CultureInfo.CurrentCulture);
}
}
そしてGlobal.asaxの中のApplication_Start()に以下を追加します:
ModelBinders.Binders.Add(typeof(DateTime), new DateTimeBinder());
ModelBinders.Binders.Add(typeof(DateTime?), new NullableDateTimeBinder());
そのもっと読むでこの素晴らしいブログでMVCフレームワークのチームは、すべてのユーザーにデフォルトの文化を実装する理由について説明します。
私はこの非常に大きな問題を自分で持っていたし、試してみるの時間後と失敗し、私はあなたのような作業溶液を尋ねました。
ただプロパティにバインダーを持っ以来、まず第一にpossibile yuoフルModelBinderを実装する必要はありません。
:あなたは、バインドすべての単一のプロパティがありますが、あなたがDefaultModelBinderを継承して、単一のプロパティをバインドすることができます気に一つだけを望んでいないので、public class DateFiexedCultureModelBinder : DefaultModelBinder
{
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
{
if (propertyDescriptor.PropertyType == typeof(DateTime?))
{
try
{
var model = bindingContext.Model;
PropertyInfo property = model.GetType().GetProperty(propertyDescriptor.Name);
var value = bindingContext.ValueProvider.GetValue(propertyDescriptor.Name);
if (value != null)
{
System.Globalization.CultureInfo cultureinfo = new System.Globalization.CultureInfo("it-CH");
var date = DateTime.Parse(value.AttemptedValue, cultureinfo);
property.SetValue(model, date, null);
}
}
catch
{
//If something wrong, validation should take care
}
}
else
{
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
}
}
私の例では、私はfiexed文化と日付の解析が、何がやりたいことは可能ですよ。あなたは(DateTimeFormatAttributeのような)CustomAttributeを作成し、あなたの上にプロパティをそれを置く必要があります:
[DateTimeFormat("d.M.yyyy")]
public DateTime Birth { get; set,}
これは、bindProperty方法では、代わりにDateTimeプロパティを探しているのあなたは、コンストラクタで指定されたフォーマットを取得し、その後、DateTime.ParseExact
と日付を解析、あなたDateTimeFormatAttributeを持つプロパティを探すことができます私はそれがこのソリューションに付属しているために非常に長い連れて行ってくれた、このことができます願っています。私はそれを検索する方法を知っていたら、それはこのソリューションを持っていることは容易で実際にした:(
あなたはそうのようなカスタムのDateTimeバインダーを実装することができていますが、実際のクライアント要求から想定文化や価値について世話をする必要があります。あなたはあなたに、その後、EN-USでYYYY / MM / DDのような日付を取得し、私たちが行うように、それは、EN-GB(それはDD / MM / YYYYのようになります)システム培養又は不変の文化に変換することもできます前とその行動でそれを変更するには、静的なファサードの変換を使用してそれを解析する必要があります。
public class DateTimeModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var valueResult = bindingContext.ValueProvider
.GetValue(bindingContext.ModelName);
var modelState = new ModelState {Value = valueResult};
var resDateTime = new DateTime();
if (valueResult == null) return null;
if ((bindingContext.ModelType == typeof(DateTime)||
bindingContext.ModelType == typeof(DateTime?)))
{
if (bindingContext.ModelName != "Version")
{
try
{
resDateTime =
Convert.ToDateTime(
DateTime.Parse(valueResult.AttemptedValue, valueResult.Culture,
DateTimeStyles.AdjustToUniversal).ToUniversalTime(), CultureInfo.InvariantCulture);
}
catch (Exception e)
{
modelState.Errors.Add(EnterpriseLibraryHelper.HandleDataLayerException(e));
}
}
else
{
resDateTime =
Convert.ToDateTime(
DateTime.Parse(valueResult.AttemptedValue, valueResult.Culture), CultureInfo.InvariantCulture);
}
}
bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
return resDateTime;
}
}
あなたはjavascriptのクライアント側と後方にJSONで動作し、特に残酷により、ステートレスアプリケーション缶でとにかく、文化dependend DateTimeの構文解析...。