5

オプションのユーザー ID を受け取り、ユーザー編集画面を表示する Manage User イベントがあります。この画面に対応する manageUserViewModel があります。

私の管理ページにはいくつかの依存関係があります。たとえば、PageTitle、送信先のメソッドなどです。

検証に失敗した場合は、もう一度管理画面を表示する必要がありますが、今回は同じメソッドに渡されたビューモデルを使用します。

失敗のシナリオでこれらの依存関係を提供することは、あまり DRY ではありません。

依存関係を繰り返すにはどうすればよいですか? それらを別のメソッドに入れてみましたが、それは正しくありません。

public ActionResult Manage(Guid? UserID)
    {
        User user = this._UserLogic.GetUser(UserID);

        ViewBag.Title = "User List";
        ViewBag.OnSubmit = "Save";
        ManageUserViewModel uvm = Mapper.Map<User, ManageUserViewModel>(user);

        return View("Manage", uvm);
    }


    [AcceptVerbs("POST")]
    public ActionResult Save(ManageUserViewModel uvm)
    {
        User user = this._UserLogic.GetUser(uvm.UserID);


        if (!ModelState.IsValid)

            // This is not very DRY!!!
            ViewBag.Title = "Manage User";
            ViewBag.OnSubmit = "Save";
            return View("Manage", uvm);
        }

        Mapper.Map<ManageUserViewModel, User>(uvm, user );

        this._UserLogic.SaveUser(user);

        return RedirectToAction("Manage", new { UserID = user.ID });

    }
4

5 に答える 5

2

あなたはDRYを誤解していると思います。DRY は「NEVER repeat yourself」という意味ではなく、繰り返さないのが理にかなっているときは繰り返してはいけないという意味です。

ビューごとに異なる要件があり、繰り返しを避けるためだけに複雑な構造を作成することは、KISS や SRP などの他のベスト プラクティスに違反します。

SOLID が興味深いのは、Single Responsibility Principle が Don't Repeat Yourself と対立することが多く、バランスを取る必要があるからです。ほとんどの場合、SRP の方がはるかに重要であるため、DRY は負けます。

複数の責任を処理するコードがここにあるように見えるので、同様のコードを複数回書くことを避けることができます。各ビューには異なる責任と異なる要件があるため、私はそうすることに同意しません。

特に検証要件が異なる場合は、アクションごとに個別のコントローラー アクション、ビュー、およびモデルを作成することをお勧めします。繰り返しを減らすためにできること (部分ビューやエディター テンプレートの使用など) がいくつかあるかもしれませんが、通常、繰り返しを避けるためだけに多くの複雑さを追加しないでください。

于 2013-08-24T19:42:22.610 に答える
1

ManageUserViewModel のプロパティとして、「Manager User」タイトルと「Save」OnSubmit 文字列を追加できます。これは、Save を呼び出すたびにそれらを ViewBag に追加する必要がないことを意味します。

AutoMapper マッピングとユーザーの保存を担当する ManageUserService を作成することもできます。

コードは次のようになります。

public ActionResult Manage(Guid? UserID)
{
    var uvm = _userService.GetById(UserId);

    return View("Manage", uvm);
}


[AcceptVerbs("POST")]
public ActionResult Save(ManageUserViewModel uvm)
{
    if (!ModelState.IsValid)
    {
        return View("Save", uvm);
    }

    _userService.Save(uvm);

    return RedirectToAction("Manage", new { UserID = uvm.ID });

}

CRUD ロジックと AutoMapping 機能を UserService というクラスに配置するだけで、そのインスタンスを Inversion of Control を使用してコントローラーに挿入できます。

文字列値をビュー モデル自体にハードコードしたくない場合は、値を ApplicationResources ファイルに追加して、ビュー モデルからそれらを参照できます。

于 2013-08-20T21:20:11.413 に答える
0

別の解決策を思いついたので、共有したいと思います。

これは、実行できるアクションに関する情報を含むビューモデルに基づいていますが、ビューモデルがアクション間で再利用される場合があるため、コントローラーがこれらを指定する (つまり、異なるリンクがルーティングするアクションを制御する) 必要があると考えています。 . たとえば、編集時にテンプレートまたは何かのインスタンスを編集できる場合 - UI は同じですが、唯一の違いは投稿先/キャンセル元のアクションです。

データ バインドされたプロパティを含むビュー モデルの一部と、ビューをレンダリングするために必要なその他のものを含むビュー モデルを抽象化しました。プロパティのみのオブジェクトを DTO と呼びますが、検証属性が含まれているため、真の dto ではありません。

将来、これらの DTO を ajax や XML リクエストに再利用できる可能性があると考えています。これにより、検証を DRY に保つことができます。

とにかく、これはコードの例です。(今のところ)満足しており、他の人に役立つことを願っています。

 [HttpGet]
    [ValidateInput(false)]
    public virtual ActionResult ManageUser(ManageUserDTO dto, bool PopulateFromObject = true)
    {
        User user = this._UserLogic.GetUser(dto.UserID);

        if (PopulateFromObject)
            Mapper.Map<User, ManageUserDTO>(user, dto);

        ManageUserViewModel vm = new ManageUserViewModel()
        {
            DTO = dto,
            PageTitle = Captions.GetCaption("pageTitle_EditUser"),
            OnSubmit = GetSubmitEventData(this.ControllerName, "SaveUser"),
            OnCancel = GetCancelEventData(this.ControllerName, "ListUsers"),
        };

        return View("ManageUser", vm); 
    }


    [HttpPost]
    public virtual ActionResult SaveUser(ManageUserViewModel vm)
    {
        User user = this._UserLogic.GetUser(vm.DTO.UserID);

        if (!ModelState.IsValid)
        {
            return ManageUser(vm.DTO, false);
        }

        Mapper.Map<ManageUserDTO, User>(vm.DTO, user);

        this._UserLogic.SaveUser(user);

        TempData.AddSuccess(Captions.GetCaption("message_UserSavedSuccessfuly"));
        return RedirectToAction("ManageUser", new { UserID = user.ID });
    }

モデル バインダーは、get アクションで URI 変数を dto に設定します。getUserByID(null) への呼び出しが行われると、ロジック レイヤーは新しい User オブジェクトを返します。

于 2013-08-24T19:13:15.097 に答える