カスタムモデルバインダー内からupdatemodelを呼び出すにはどうすればよいですか? (MVC)
-
02-10-2019 - |
質問
モデルで複雑なタイプ用のいくつかのカスタムバインダーを作成しています。私のモデルは、独自のバインダーを持つオブジェクトで構成されています。ベースオブジェクトに汚い作業を行い、標準のModelBinderルーティングに渡すことでカプセル化する複雑なオブジェクトを入力してもらいたいです。どうすればいいですか?
イラストのために、私は非常に簡単な例を作成しました。
私のモデルにはこれらのオブジェクトが含まれているとします。
public class Person
{
public string Name {get; set;}
public PhoneNumber PhoneNumber {get; set;}
}
public class PhoneNumber
{
public string AreaCode {get; set;}
public string LocalNumber {get; set;}
}
また、これらのモデルごとに次のバインダーがあります。 PersonBinderがPhoneNumberを入力する必要があるが、PhoneNumberバインダーのコードを複製したくないというわけではありません。スターダードバインダールーティングにどのように委任しますか?
public class PersonBinder: IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
Person person = new Person();
person.Name = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "Name")).AttemptedValue
// This is where I'd like to have the PhoneNumber object use binding from another customer ModelBinder.
// Of course the bindingContext.ModelName should be updated to its current value + "PhoneNumber"
person.PhoneNumber = ???; // I don't want to explicitly call the PhoneNumberBinder it should go through standard Binding routing. (ie. ModelBinders.Binders[typeof(PhoneNumber)] = new PhoneNumberBinder();)
return person;
}
}
public class PhoneNumberBinder: IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
PhoneNumber phoneNumber = new PhoneNumber();
phoneNumber.AreaCode = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "AreaCode")).AttemptedValue
phoneNumber.LocalNumber = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "LocalNumber")).AttemptedValue
return phoneNumber;
}
}
そしてもちろん、ModelBindersをGlobal.asax.csファイルに登録しました。
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders[typeof(Person)] = new PersonBinder();
ModelBinders.Binders[typeof(PhoneNumber)] = new PhoneNumberBinder();
}
ありがとう、
ジャスティン
解決
さて、私はなんとか解決策を考え出しました。その有効性についてお気軽にコメントしてください。
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
Person person = new Person();
person.Name = bindingContext.ValueProvider.GetValue("Name").AttemptedValue
if (bindingContext.ModelName == String.Empty)
{
bindingContext.ModelName = "PhoneNumber";
}
else
{
bindingContext.ModelName = bindingContext.ModelName + ".PhoneNumber";
}
PhoneNumber phoneNumber = new PhoneNumber();
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => phoneNumber, phoneNumber.GetType());
IModelBinder binder = ModelBinders.Binders[typeof(PhoneNumber)];
if (binder == null)
{
binder = ModelBinders.Binders.DefaultBinder;
}
person.PhoneNumber = binder.BindModel(controllerContext, bindingContext) as PhoneNumber;
return person;
}
これが私がしたことの要約です。
- グローバルにアクセス可能なmodelbinders.bindersコレクションを使用してモデルバインダーを検索します(登録されていない場合はデフォルトへのフォールバック)
- 私が拘束するモデルのModelMeTadataproviderを作成します。
- BindingContextのModelNameプロパティを、私が埋め込もうとしているモデルプロパティ(「PhoneNumber」)に設定します。
他のヒント
バインダーを書くのではなく、ユーザーオートマを承認し、アクションで複雑なモデル構造を処理できます。
所属していません StackOverflow