【问题标题】:set c# mvc session variable via hard-coded html select通过硬编码的 html 选择设置 c# mvc 会话变量
【发布时间】:2014-07-27 23:22:50
【问题描述】:

我有一个 C# MVC 视图,它依赖于传递的模型数据 - 数字表 - 这需要视图设置视图开始呈现数据的阈值,即

@for (var value = ["threshold"]; value <= 5; value++){
    ...
}

我目前的想法是处理这个问题的最好方法是拥有一个 html select 来更改会话变量:

<select id="thresholdSelect">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
    <option value="4">4</option>
    <option value="5">5</option>
</select>

不幸的是,我对 C# MVC 的了解意味着我不知道如何以这种方式设置会话变量,而且我对 DropDownListFor 的阅读让我大吃一惊。

这似乎过于复杂,因为要求硬编码值仅限于单个页面,这意味着我希望理想的答案是视图中的几行触发选择元素的更改事件。相比之下,DropDownListFor 的示例显示它围绕相关的控制器和模型弹跳,并从数据库中获取存储的数据,这对于我的需要来说是多余的。

我该怎么做?我一直在控制器级别设置会话变量,但现在需要在视图级别设置一个。

我需要实现的基本步骤是:

  1. 如果未设置,则使用默认会话变量显示页面(在返回视图之前很容易在控制器中完成)
  2. 显示一个带有阈值的选择元素(很容易完成,因为我已经把代码 在问题中)
  3. When the select element changes, fire an event that sets the session variable to the selected value.

【问题讨论】:

    标签: c# html session model-view-controller


    【解决方案1】:

    MVC 不一定具有网络表单意义上的“事件”(尽管您可以使用它们),但通常不建议这样做。 MVC 对应于从服务器发送/接收数据的 HTTP 模型。当您想与服务器交互时,您需要控制器类上的其他操作方法。

    您的控制器可以通过多种方式接受来自客户端的输入,但其中最基本的是通过为您的操作方法指定参数,MVC 将尝试绑定到请求数据(表单、查询字符串等)。这是一个示例控制器:

    //Controller class
    public class ReportController : Controller {
    
        public ActionResult Index() {
            ActionResult result = null;
            ReportSelectionViewModel viewModel = this.BuildViewModel();
    
            result = View("Index", viewModel);
            return result;
        } // end action Index
    
        [HttpPost()]
        public ActionResult ChangeReport(ChangeReportRequest changeRequest) {
            ActionResult result = null;
            ReportSelectionViewModel viewModel = this.BuildViewModel();
    
            Session["ReportOptions"] = changeRequest;
            viewModel.Messages.Add("Selection was changed.");
            viewModel.ReportRequest = changeRequest;
    
            result = View("Index", viewModel);
    
            return result;
        } // end action ChangeReport
    
        //Method that encapsulates the logic needed to build a view model for actions on this controller
        protected ReportSelectionViewModel BuildViewModel() {
            ReportSelectionViewModel viewModel = null;
            viewModel = new ReportSelectionViewModel();
            viewModel.AvailableThresholds.AddRange(new int[] { 1, 2, 3, 4 });
            //Set the value to whatever the user previously selected if available
            if (Session["ReportOptions"] != null) {
                viewModel.ReportRequest.ThresholdSelect = ((ChangeReportRequest)Session["ReportOptions"]).ThresholdSelect;
            } // end if
            return viewModel;
        } // end function BuildViewModel
    
    } // end class ReportController
    

    在上面的控制器中,默认的Index() 操作不接受任何参数,因为它不需要任何第一次访问。 ChangeReport() 操作接受 ChangeReportRequest 类型的参数,称为模型。这告诉 MVC 这个动作是 EXPECTING 来自客户端的一个值(或一系列值)并导致 MVC 深入挖掘以找出客户端提供哪些值来满足控制器的参数参数并返回一个完全填充的模型对象。

    这是模型类的样子:

    //Model class that gets built by the DefaultModelBinder
    public class ChangeReportRequest {
    
        private int _reportId;
        private int _thresholdSelect;
    
        public ChangeReportRequest() {
            _reportId = 1; // Meaningful default value here
            _thresholdSelect = 0;
        } // end constructor
    
        public int ReportId {
            get {
                return _reportId;
            } set {
                _reportId = value;
            }
        } // end property ReportId
    
        public int ThresholdSelect {
            get {
                return _thresholdSelect;
            } set {
                _thresholdSelect = value;
            }
        } // end property ThresholdSelect
    
    } // end class ChangeReportRequest
    

    拥有一个专门用于显示目的的不同类型的模型(ViewModel)也是一个好主意(这与用于保存事务数据的普通模型不同)。 ViewModel 在视图中添加编译时支持,可以在视图中显示这些内容。一个示例ViewModel 如下所示:

    //Strongly typed view model class passed to the view to add intellisense support in the view and avoid the ViewBag.
    using System.Collections.Generic;
    public class ReportSelectionViewModel {
    
        private List<int> _availableThresholds;
        private List<string> _messages;
        private ChangeReportRequest _reportRequest;
    
        public ReportSelectionViewModel() {
            _availableThresholds = new List<int>();
            _messages = new List<string>();
            _reportRequest = new ChangeReportRequest();
        } // end constructor
    
    
        public List<int> AvailableThresholds {
            get {
                return _availableThresholds;
            }
        } // end property AvailableThresholds
    
        public List<string> Messages {
            get {
                return _messages;
            }
        } // end property Messages
    
        public ChangeReportRequest ReportRequest {
            get {
                return _reportRequest;
            } set {
                if (value != null) {
                    _reportRequest = value;
                } // end if
            }
        } // end property ReportRequest
    
    } // end class ReportSelectionViewModel
    

    MVC 具有内置模型绑定,它将尝试将表单字段映射到控制器操作方法上的输入值。通过将控制器方法参数命名为与选择列表相同的名称(除了 ID 之外,您还必须为选择列表命名),您可以简单地在选择列表周围创建一个表单包装器:

    下面是与上述代码一起使用的视图:

    @model ReportSelectionViewModel
    
    <h2>Index</h2>
    <div class="message-wrapper">
        <ul class="messages">
        @foreach(string message in Model.Messages) {
            <li>@message</li>
        }
        </ul>
    </div>
    <form method="post" action="@Url.Action("ChangeReport")">
        <select id="ThresholdSelect" name="ThresholdSelect">
        @foreach(int item in Model.AvailableThresholds) {
            <option value="@item" @(Model.ReportRequest.ThresholdSelect == item ? "selected" : "")>@item</option>
        }
        </select>
        <!--Later this can be made into a text box or drop down or whatever, as long as the name matches the model-->
        <input type="hidden" name="ReportId" value="@Model.ReportRequest.ReportId" />
        <input id="submit" type="submit" name="submit" value="Select" />
    </form>
    

    默认的 MVC ModelBinder 是智能的。它通过ModelMetaDataProvider 使用反射来迭代方法中的参数,并尝试从HTTP 请求中根据名称匹配的字段(这就是为什么命名表单字段很重要的原因)。它也可以做比 int 或 string 更复杂的事情。

    这里有一些资源:

    【讨论】:

    • 感谢您的回答;不幸的是,我不理解您使用的 表示法;我在视图中使用 @ 表示 C# 代码,这是否等效?
    • @DavidSmithson 我已经编辑了我的答案,并且以一些代码复杂性为代价,我引入了一个强类型视图模型。是的,@ 是在 Razor 视图引擎而不是 WebForms 视图引擎中访问模型的语法:dotnet-tricks.com/Tutorial/mvc/…
    • 自从我发布了我的 cmets 后,我发现将报告编号作为命名隐藏字段添加到表单中可以让我使用控制器中的报告编号作为您早期解决方案的一部分,但我知道这是一个便宜的选择,你的代码是一个更好的实现。再次感谢!
    • 如果满足您的要求,您的解决方案不一定是便宜的解决方案。我在上面的答案中引入了模型/视图模型,因为这些允许以后进行更改,而无需修改您的控制器操作签名,这就是为什么我非常喜欢创建一个(或多个)模型来保存所有项目需要提交而不是参数列表。
    猜你喜欢
    • 2011-12-07
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 1970-01-01
    • 2014-12-11
    • 2016-03-20
    • 1970-01-01
    • 2015-03-11
    相关资源
    最近更新 更多