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. 以任何一种方式做事都有好处吗?

可以像我那样使用 viewbag 吗?我用它来告诉视图输入是否有效,这决定了是否显示图表。我多次听说从不使用 viewbag。为什么是这样?模仿我描述的行为的最佳实践方式是什么?

在调用ValidateChart(in view) 函数时,我需要使用querystring来告诉操作生成图表的月份和年份。我也看到这被称为不好的做法,但还没有找到更好的方法来做到这一点。querystring在不通过范围的情况下访问变量的正确方法是什么request

我已经设法让这段代码进入工作状态,但我真的很想学习如何以正确的方式去做。

4

3 回答 3

3

首先,如果它有效,那么它肯定不是错误的方式。这可能不是最好的方法,但也没有错。

这是我要更改的一些内容,您可以决定是否要使用它们...

1)我不会使用ViewBag,只需向您的 ViewModel 添加一个附加属性bool CanShowChart,例如。然后你可以在你的视图逻辑中简单地测试它

string SelectedMonth2) 为和添加更多属性string SelectedYear,可以根据参数在控制器中分配这些属性。您无需担心它们在第一次加载时会出错,因为您只会在它们CanShowChart为真时使用它们。然后,您可以在 View 中检查这两个值,而不是使用该Request.QueryString方法

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

查询字符串和 URL 更改在将变量从请求范围传递到服务器时非常有用。我不会认为它们是不好的做法。如果有人使用它,这是一个正在设计的系统要回答的问题。

IMO,像这样的变量int ChosenMonth在 VM 中很有用,因为它们有助于正确定义系统。当前的定义ValidateVM并不意味着能够选择月份和年份的功能,我认为这是与已定义系统相对的隐蔽逻辑。此外,在围绕选择功能编写测试时会更有帮助。一个人将能够测试选择功能,它的使用方式。

此外,值得看看是否需要将月份和年份放入 SelectedItem 中,例如

class SelectedItem { int year, int month }
于 2013-01-03T17:43:50.157 回答
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
}

现在,您可以通过 Data Annotations 或更好的方法 - 使用 FluentValidation 来验证您的ReportModel。所以不,您使用 ViewBag 的方式 - 指示模型在哪里有效或无效 - 根本不是最佳实践。

ModelState 是一个包含有关模型的所有错误的对象。您可以像这样手动向其中添加错误ModelState.AddModelError("[propertyName]","Error Message"),然后如果未验证模型,则所有错误消息都将显示在视图中,如果您有@Html.ValidationSummary()某个地方是视图或@Html.ValidationMessageFor(model => model.PropertyName)视图。谷歌周围的更多信息。有很多关于这个主题的信息。

最佳实践是让控制器中的操作尽可能薄,这与您所拥有的相去甚远。出于这个确切原因,不鼓励在控制器中向 ModelState 添加错误。同样,使用 FluentValidation,因为它 (1) 分离了验证的关注点,并且 (2) 比 Data Annotations 灵活得多。

于 2013-01-03T18:10:42.197 回答