1 つのカスタム モデル バインダーを CreateModel に、もう 1 つを BindModel にしますか?
-
27-10-2019 - |
質問
背景:MVC ポストバック アクション メソッドで受信している 指示 ビューモデルではなくオブジェクト。考え方としては、これらのコマンド オブジェクト (トランザクション スクリプトにほぼ相当) がセットアップされ、アクション メソッドに入るとすぐに実行できるようになり、モデル バインダーには実行プロセス中に使用されるパラメータが設定されているということです。
public class MyCommand : IMyCommand
{
// In this case Value1 and Value2 are being set by the default model binder from posted form values - wonderful :)
public String Value1 { get; set; }
public String Value2 { get; set; }
public CommandResult ExecuteCommand()
{
// Does something awesome...
}
}
物事をもう少し複雑にするために、コマンド オブジェクトには、それぞれのコンストラクターで必要な依存関係 (サービス、リポジトリなど) があります。そのため、デフォルトのDependencyResolver(IoCコンテナですでに設定されている)を使用してモデルオブジェクトを構築するカスタムモデルバインダーを作成する必要がありました。
public class DependencyModelBinder : DefaultModelBinder
{
protected override Object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return DependencyResolver.Current.GetService(modelType);
}
}
そしてセットアップ Global.asax.cs
そのようです:
ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();
これもすべて正常に動作し、依存関係がコンストラクターに挿入され、デフォルトのモデル バインダーが通常どおりプロパティを設定します。
問題:私が抱えている問題は、すべてのコマンド オブジェクトに 'SessionId' GUID パラメーター (Cookie から取得) があり、最初に行うことは、挿入されたサービスを使用してこの ID からセッション オブジェクトを解決しようとすることです。
public class MyCommand : IMyCommand
{
public MyCommand (ISessionRepository sessionRepository) { ... }
public Guid SessionId { get; set; } // Set by model binder from a cookie...
public CommandResult Execute()
{
Session session = SessionRepository.Get(SessionId);
if (session == null)
// Do something not so awesome...
}
}
この繰り返しを削除したかったので、リポジトリ内でのこの検索を処理する 2 番目のモデル バインダーを作成しました。つまり、コマンド オブジェクトには Session
プロパティを直接削除します (セッション リポジトリのコンストラクターの依存関係を削除します)。
public class SessionModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var sessionRepository = DependencyResolver.Current.GetService<ISessionRepository>();
return sessionRepository.Get((Guid)controllerContext.HttpContext.Request["SessionId"]);
}
}
私の Global.asax.cs
ファイルは次のようになりました。
ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();
ModelBinders.Binders.Add(typeof(Session), new SessionModelBinder());
SessionModelBinder を単独でテストしたところ、それが機能することがわかりました。ただし、DependencyModelBinder と組み合わせて使用する場合、呼び出されることはありません。モデル オブジェクトを構築するときに MVC で dependencyModelBinder を使用し、セッション プロパティをバインドするときに MVC に SessionModelBinder を使用させるにはどうすればよいですか?それとも、これに対するより良いアプローチを知っている人はいますか?
解決
元のモデル バインダーで GetPropertyValue メソッドを使用して、Session プロパティの値を指定できます。
public class DependencyModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return DependencyResolver.Current.GetService(modelType);
}
protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
{
if (propertyDescriptor.Name == "Session")
{
var sessionRepository = DependencyResolver.Current.GetService<ISessionRepository>();
return sessionRepository.Get(controllerContext.HttpContext.Request["SessionId"]);
}
return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
}
}