4

実行時に取得されるサブクラスにUpdateModelメソッドを使用することを検討しています。誰かがそれの完全なハッシュを作成しているかどうか、および/または私がしようとしていることを明らかにすることができれば素晴らしいでしょう。することは可能です。

一連の部分ビューの検証を制御するために、一般的なアクションを使用しています。部分ビューごとに特定のアクションを実行しないようにしようとしています。

各部分ビューには、基本モデルから派生した一意のモデルがあります。

public class ModelA : ModelBase{
     [Required]
     public string SomeStringProperty{get;set;}
...
}
public class ModelB : ModelBase{
     [Required]
     public DateTime? SomeDateProperty{get;set;}
...
}
public class ModelBase{
     public Guid InstanceId{get;set;}
}

アクションでFormCollectionを使用して、送信されたフォーム要素とその値を取得しています。これには、ビューがリクエストを検証するために使用する必要があるモデルのタイプが含まれます。この例では、これがセキュリティに与える影響を無視してください。私はそれらを認識しており、これは内部的な唯一の概念実証です。

    [HttpPost]
    public ActionResult ChangeCaseState(int id, FormCollection formCollection)
    {
        Guid instanceId = new Guid(formCollection["instanceId"]);
        string modelType = formCollection["modelType"];
        //Return a specific Model class based on the event/modelType
        var args = GetStateModelClass(modelType, instanceId);

        try
        {
            UpdateModel(args);
            if(Model.IsValid){
             ...
        }
        catch (Exception)
        {
            return View("~/Views/Shared/StateForms/" + modelType + ".ascx", args);
        }...

これが、コントローラーに渡されたmodelTypeに基づいてサブクラスを返すために使用しているコードです。

private static ModelBase StateModelClassFactory(string stateModelTypeName, Guid instanceId)
        {
            switch (stateModelTypeName)
            {
                case "modelTypeA":
                    return new ModelA(workflowInstanceId);
                case "modelTypeB":
                    return new ModelB(workflowInstanceId);
    ...
    }

StateModelClassFactoryメソッドの戻り型は基本クラスであるため、実際にはサブクラスを返していますが、UpdateModelメソッドで使用されるモデルバインダーは、基本クラス内の値に対してのみバインドします。

この問題を解決する方法について何かアイデアはありますか?

アップデート:

カスタマーモデルバインダーを作成しました。

public class CustomModelBinder : DefaultModelBinder
    {
      public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {

そして、新しいモデルバインダーを正しい基本クラスに割り当てて、内部で何が起こっているかを確認します。

ModelBinders.Binders.Add(typeof(ModelBase), new CaseController.CustomModelBinder());

モデルバインダーをデバッグしてbindingContextを調べると、Modelプロパティは正しいサブクラスを再プリセットしますが、ModelTypeプロパティは基本クラスのプロパティです。BindModelメソッド内でModelTypeを変更することを検討する必要がありますか?もしそうなら、これを行う方法についてのポインタは、ModelTypeのセッターが冗​​長になっているようです。また、サブクラスのSomeDatePropertyが実際にはPropertyMetadataプロパティにあることに気づきました。...私が望むように動作するのに非常に近いようです。

4

3 に答える 3

5

dynamic私はちょうどこの特定の問題に遭遇しました、そしてより良い一般的なアプローチはそれをに渡す間にあなたのモデルをキャストすることであることがわかりましたUpdateModel

[HttpPost]
public ActionResult ChangeCaseState(int id, FormCollection formCollection)
{
    ...try
    {
        UpdateModel((dynamic)args);//!!notice cast to dynamic here
        if(Model.IsValid){
         ...
    }
    catch...

これは、変数が基本型で削除されているかどうかに関係なく、私の型で使用可能なすべてのプロパティを設定しているように見えます。

この問題についてCodePlexに提出された作業項目があります:http ://aspnet.codeplex.com/workitem/8277?ProjectName = aspnet

于 2011-05-27T18:25:03.203 に答える
2

だから私は自分の問題を解決したと思います。基本的に、UpdateModelを呼び出す前にModelクラスを取得する方法のため、ModelがSubClassのモデルであったとしても、Model BinderはBaseClassをバインドしています。これは、特定の問題を解決するために使用したコードです。

  public class SubClassModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var model = bindingContext.Model;
        var metaDataType = ModelMetadataProviders.Current.GetMetadataForType(null, model.GetType());
        bindingContext.ModelMetadata = metaDataType;
        bindingContext.ModelMetadata.Model = model;

        return base.BindModel(controllerContext, bindingContext);
    }
}

そしてGlobal.asaxで:

ModelBinders.Binders.Add(typeof(ModelBase), new SubClassModelBinder ());

最初のポインタをくれたDarinに感謝します。

于 2010-11-29T10:28:56.973 に答える
0

この問題を解決するために、文字列プロパティの値に基づいて正しい子インスタンスを返す基本型のカスタムモデルバインダーを作成できます。

于 2010-11-26T17:08:22.500 に答える