3

これがこれを尋ねる正しい場所であることを願っています。そうでない場合は、適切な場所を教えてください。

目的: ユーザーはドロップダウン リストから年と月を選択できます。フォームが送信されると、選択に基づいて情報を表示するチャートが生成されます。

実装: 私のコントローラーはIEnumerable<SelectListItem>ドロップダウン リストごとに作成し、ビューに渡されるモデルに格納されます。ビュー内には、チャート化アクションへの呼び出しがあります。

コード:

コントローラ:

public ActionResult Validate(int month = 0, int year = 0)
    {
        //Check if input is valid
        if (month != 0 && year != 0)
        {
            ViewBag.Valid = 1;
        }
        else
        {
            ViewBag.Valid = 0;
        }
        ValidateVM model = new ValidateVM();

                    //Populate years
        model.year = Enumerable.Range(2008, DateTime.Now.Year - 2007).Reverse()
                        .Select(r => new SelectListItem
                        {
                            Value = r.ToString(),
                            Text = r.ToString()
                        });
                    //Populate months
        string[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };

        model.month = months
                        .Select((r, index) => new SelectListItem { Text = r, Value = (index + 1).ToString() });

        return View(model);
    }

モデル:

public class ValidateVM
{
    public int[] Mdays { get; set; }
    public IEnumerable<SelectListItem> month { get; set; }
    public IEnumerable<SelectListItem> year { get; set; }
}

意見:

@using (Html.BeginForm("Mday", "Metrics", FormMethod.Get))
{
    @Html.DropDownListFor(model => model.month, Model.month)
    @Html.DropDownListFor(model => model.year, Model.year)

    <input type="submit" />
}
@if (ViewBag.Valid == 1)
{
    <img src="@Url.Action("ValidateChart", new { month = Request.QueryString["month"],
                                        year = Request.QueryString["year"]
  })" alt="Test"/>
}

質問: フォームが送信されると、すべてが正常に機能します。など、選択したアイテムの変数がモデルに含まれるメソッドを見てきましたint chosenMonth。どちらかの方法で物事を行う利点はありますか?

私がした方法でビューバッグを使用しても大丈夫ですか? これを使用して、入力が有効かどうかをビューに伝えます。これにより、チャートを表示するかどうかが決まります。ビューバッグは絶対に使わないと何度も聞いたことがあります。どうしてこれなの?説明した動作をエミュレートするためのベストプラクティスは何ですか?

ValidateChart(in view) 関数の呼び出しでは、を利用しquerystringて、グラフを生成する月と年をアクションに伝える必要があります。これはバッド プラクティスとも呼ばれますが、これを行うためのより良い方法は見つかりませんでした。スコープquerystringを経由せずに変数にアクセスする正しい方法は何ですか?request

このコードを動作状態にすることはできましたが、正しい方法で行う方法を学びたいと思っています。

4

3 に答える 3

3

まず、それが機能する場合、それは確かに間違った方法ではありません。最善の方法ではないかもしれませんが、間違っているわけではありません。

ここに私が変更したいことがいくつかあります。それらを使用するかどうかはあなたが決めることができます...

1) を使用しません。たとえばViewBag、ViewModel に追加のプロパティを追加するだけです。bool CanShowChart次に、ビューロジックで簡単にテストできます

string SelectedMonth2)とのプロパティをさらにいくつか追加しstring SelectedYearます。これらは、パラメータに基づいてコントローラで割り当てることができます。が true の場合にのみ使用するため、最初のロードでそれらが間違っていることを心配する必要はありませんCanShowChartRequest.QueryStringメソッドを使用する代わりに、ビューでこれらの 2 つの値を確認できます。

3) 利用可能な月と年のリストを ViewModel に渡し、ViewModel にオンデマンドで SelectList を作成させたいと考えています。

明確にするために、私の ViewModel は次のようになります。

public class ValidateViewModel
{
    public int[] Mdays { get; set; }
    public IEnumerable<string> AvailableMonths { get; set; }
    public IEnumerable<string> AvailableYears { get; set; }
    public string SelectedMonth { get; set; }
    public string SelectedYear { get; set; }
    public bool CanShowChart { get; set; }

    public List<SelectListItem> GetMonthsSelectList()
    {
        List<SelectListItem> list = new List<SelectListItem>();

        foreach(var month in AvailableMonths)
        {
            bool selected = month == SelectedMonth;
            list.Add(new SelectListItem() { Text = month, Value = month, Selected = selected });
        }

        return list;
    }

    public List<SelectListItem> GetYearsSelectList()
    {
        List<SelectListItem> list = new List<SelectListItem>();

        foreach(var year in AvailableYears)
        {
            bool selected = month == SelectedYear;
            list.Add(new SelectListItem() { Text = year, Value = year, Selected = selected });
        }

        return list;
    }

}

次に、ビューで次のように使用できます...

@using (Html.BeginForm("Mday", "Metrics", FormMethod.Get))
{
    @Html.DropDownListFor(x => x.SelectedMonth, Model.GetMonthsSelectList())
    @Html.DropDownListFor(x => x.SelectedYear, Model.GetYearsSelectList())

    <input type="submit" />
}
@if (Model.CanShowChart)
{
    <img src="@Url.Action("ValidateChart", new { month = Model.SelectedMonth, year = Model.SelectedYear })" alt="Test"/>
}

その後、コントローラーをこれに削減できます...

public ActionResult Validate(int month = 0, int year = 0)
{
    //Check if input is valid
    ValidateViewModel model = new ValidateViewModel();
    model.CanShowChart = month != 0 && year != 0;
    model.SelectedMonth = month.ToString();
    model.SelectedYear = year.ToString();

    //Populate years
    model.AvailableYears = Enumerable.Range(2008, DateTime.Now.Year - 2007).Reverse().Select(r => r.ToString());

    //Populate months
    model.AvailableMonths = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };

    return View(model);
}
于 2013-01-03T17:55:06.123 に答える
1

コードの検証の側面についてのみコメントします。全体の検証アプローチは本当に厄介です。モデルは、を使用して検証する必要がありますModelState。正しいパラダイムは、コントローラーに次のようなものを書き込むことです。

[HttpGet]
public ActionResult MyReport()
{
    ReportModel model = new ReportModel();
    // populate your model in order for all your inputs to show correctly (dropdowns data or whatever)
    return View("[pathToView]/ReportView.cshtml", model);
}

[HttpGet]
public ActionResult ShowMyReport(ReportModel model)
{
    if(ModelState.IsValid)
    {
        // inputs validated, show the report
        [get report data according to the input]
        return View(model);
    }
    // inputs didn't validate. Rerender view and show errors.
    return View("[pathToView]/ReportView.cshtml", model); // should be the same view
}

ここで、データアノテーションを使用するか、より適切な方法としてFluentValidationを使用してReportModelを検証します。つまり、ViewBagを使用した方法(モデルが有効かどうかを示すため)は、ベストプラクティスではありません。

ModelStateは、モデルに関するすべてのエラーを保持するオブジェクトです。このように手動でエラーを追加できます。ModelState.AddModelError("[propertyName]","Error Message")モデルが検証されていない場合@Html.ValidationSummary()、ビューまたはビューのいずれかにある場合は、すべてのエラーメッセージがビューに表示@Html.ValidationMessageFor(model => model.PropertyName)されます。それについての詳細はグーグルで。この主題をカバーするたくさんの情報があります。

のベストプラクティスは、コントローラー内のアクションを可能な限り薄くすることです。これは、現在のアクションとはかけ離れています。この正確な理由から、コントローラーのModelStateにエラーを追加することはお勧めしません。繰り返しになりますが、FluentValidationを使用すると、(1)検証の懸念が分離され、(2)データ注釈よりもはるかに柔軟になります。

于 2013-01-03T18:10:42.197 に答える
1

クエリ文字列と URL の変更は、リクエスト スコープからサーバーに変数を渡す際に非常に役立ちます。私はそれらを悪い習慣とは評価しません。これを使用する必要があるかどうかは、設計中のシステムによって解決される問題です。

IMO、次のような変数int ChosenMonthは、システムを正しく定義するのに役立つため、VM で役立ちます。の現在の定義はValidateVM、月と年を選択できるという機能を意味するものではありません。これは、定義されたシステムに反対する秘密のロジックと考えられます。また、選択機能に関するテストを作成する際にも役立ちます。選択機能、それが使用されている方法をテストすることができます。

また、次のように、月と年を SelectedItem に結合する必要があるかどうかを確認することも価値があります。

class SelectedItem { int year, int month }
于 2013-01-03T17:43:50.157 に答える