【问题标题】:Passing object (with KeyValuePair) back into controller将对象(使用 KeyValuePair)传回控制器
【发布时间】:2013-05-19 06:32:24
【问题描述】:

我试图四处寻找答案,但我被困了一天的大部分时间,所以我认为这里的好人可能能够帮助我!

我有一个我在索引页面上列出的 Monitor 对象列表。每个监视器都有更多信息显示在详细信息页面上。我遇到的问题是

public List<KeyValuePair<int, int>> FaxcomMonitorData { get; set; }

如下所示。

监控类:

[DataContract]
public class Monitor
{
    [DataMember]
    public string MonitorType { get; set; }

    [DataMember]
    public string AtlasMonitorHeader { get; set; }

    [DataMember]
    public string AtlasMonitorData { get; set; }

    [DataMember]
    public List<KeyValuePair<int, int>> FaxcomMonitorData { get; set; }

    (...other attributes here...)

}

显示器有两种类型:ATLAS 和 FAXCOM。根据它们的不同,相应的数据属性将使用适当的值进行更新,而另一个则为空。 (即 Atlas 有 AtlasMonitorHeader 和 Data 不为空但 FaxcomMonitorData 为空)

索引操作结果:

public ActionResult Index() 
    {
        MonitorServiceClient client = null;
        List<Monitor> monitors = null;
        try
        {
            client = new MonitorServiceClient("BasicHttpBinding_IMonitorService");
            monitors = new List<Monitor>(client.GetMonitors());
            if (monitors.Any(x => x.Status.Equals("red")))
                ViewData["OverallStatus"] = "red";
            else
                ViewData["OverallStatus"] = "green";
        }
        catch (Exception ex)
        {
            if (null != client)
                client.Abort();
        }
        return View(monitors);
    }

当监视器列表出现在此处时,列表中的监视器看起来很棒! KeyValuePair 具有正确的值,一切都很好。

索引视图:

<div id="overallstatus">
    <table style="border-style:none">
        <tr>
            <td style="vertical-align:middle; font-size:30px; color:Black; border-style:none" >Overall Status:</td>
            <td style="border-style:none" >
                <% if (ViewData["OverallStatus"].Equals("red")) { %>
                    <img src="../../../Content/Images/RedStoplightRG.png" alt="" height="60px" width="140px"/>
                <% } %>
                <% else if (ViewData["OverallStatus"].Equals("green")) { %>
                    <img src="../../../Content/Images/GreenStoplightRG.png" alt="" height="60px" width="140px"/>
                <% } %>
            </td>
        </tr> 
    </table>
</div>

<br />
<br />

<table>
    <tr>
        <th></th>
        <th>
            Monitor
        </th>
        <th>
            Current Status
        </th>
        <th>
            Last Update
        </th>
    </tr>

<% foreach (var item in Model) { %>
    <tr>
        <td>
            <%: Html.ActionLink("Details", "Details", item)%>
        </td>
        <td>
            <%: item.MonitorName %>
        </td>
        <td>
            <% if (item.Status.Equals("green")) { %>
                <img alt="" src="../../../Content/Images/GreenStoplightRG.png" height="40px" width="95px"/> 
            <% } %>
            <%-- <% else if (Model.CurrentStatus.Equals("red")) { %>
                <img alt="" src="../../../Content/Images/RedStoplightRG.png" />
            <% } %> --%>
            <% else { %>
                <img alt="" src="../../../Content/Images/RedStoplightRG.png" height="40px" width="95px"/>
            <% } %>
        </td>
        <td>
            <%: String.Format("{0:g}", item.LastUpdated) %>
        </td>
    </tr>

<% } %>

</table>

此处的底部表格显示了每个监视器和一些数据。当我单击详细信息超链接时,我会转到此控制器方法。

详细操作结果:

public ActionResult Details(Monitor monitor)
    {
        if (monitor.MonitorType.Equals("ATLAS"))
            return RedirectToAction("AtlasDetails", monitor);
        if (monitor.MonitorType.Equals("FAXCOM"))
            return RedirectToAction("FaxcomDetails", monitor);

        return RedirectToAction("Index");
    }

如果我单击 ATLAS 类型的监视器(没有 KeyValuePair),所有属性都很好。

FAXCOM 类型虽然具有正确设置的大多数属性,但 KeyValuePair 除外。现在它为 null,即使最初接收对象时不是(在 Index ActionResult 中)。

我不相信我正在做任何事情导致 KeyValuePair 在视图中变为 null,但我之前没有使用过它,因此我可能需要以与我现在不同的方式传递信息。

如果其他代码或解释有帮助,请告诉我。谢谢!

编辑:我根本没有使用数据库,我在索引页面中使用的服务只会给我一个 Monitor 对象列表。我不希望再次调用(并等待)该服务,因为如果有很多监视器会花费很长时间。

编辑: 感谢 fan711 对为什么我们尝试的方法不起作用的解释,由于时间限制,我们决定采用不同的(有些丑陋的)解决方法。如果您有更多时间,您应该使用 Jonathan 的回答并尽可能遵循这些良好的编码实践。我想我至少会在这里发布我们所做的,以防其他人想要使用它。

我们最终使 FaxcomMonitorData 成为一个由逗号和胡萝卜(和 ^)分隔的字符串,以将键与其值分开,并将键值与其他键值分开。然后我们解析这个字符串并将数据存储在 List> 中。

List<KeyValuePair<int,int>> FaxcomData = new List<KeyValuePair<int,int>>();

        List<string> keyvaluepairs = monitor.FaxcomMonitorData.Split('^').ToList();
        foreach (var pair in keyvaluepairs)
        {
            List<string> stringData = pair.Split(',').ToList();
            FaxcomData.Add(new KeyValuePair<int,int>(Convert.ToInt32(stringData[0]), Convert.ToInt32(stringData[1])));
        }

感谢您的帮助!

【问题讨论】:

    标签: c# asp.net-mvc key-value


    【解决方案1】:

    与其传递整个“监视器”对象,不如传递一个 Id,然后在 Details 操作中重建对象?

    【讨论】:

    • 我不太清楚你的意思。您的建议是否类似于如何使用 Id(主键)搜索数据库以再次获取对象?我没有数据库,我使用的服务只给了我整个监视器列表。除非我有列表,否则我不能使用 Id 搜索特定对象。除非我再次访问该服务,否则我将无法访问该列表,但我希望仅在“索引”页面上填充列表时才这样做。这有意义吗?
    • 我实际上并没有选择这个选项,但我相信对于那些比我有更多时间重做程序的人来说,这是最好的选择。我将确保在未来实施这些编码实践。
    • 如果服务调用很昂贵,您应该将其缓存在某个地方,然后继续对缓存的数据使用这种方法。数据是否经常变化?如果没有,您可以在应用程序启动时进行初始服务调用,并将其存储在本地数据库(或文件系统)或服务器缓存中(小心!)。如果数据以某种频率更改,则还必须以某种频率(每 10 分钟或其他任何时间)使您的缓存过期
    【解决方案2】:

    ActionLink() 的第三个参数在您的情况下是 RouteValues。您不能将复杂对象传递给此参数;它是路由值的键/值集合。您可以在第一个视图的结果 html 中看到 .ToString 在您的项目对象的每个属性上返回。

    正如 Jonathan 所说,首选方法是从您的服务重新加载监控对象。如果这不可能,您可能希望将整个对象包装在一个表单中,并将每个属性作为隐藏字段传递。比如:

    <% for (item = 0; item<Model.Count; item++) { %>
        <% using(Html.BeginForm("Details",Nothing, FormMethod.Post)) { %>
            <%= Html.HiddenFor(m => m(item).MonitorType) %>
            <%= Html.HiddenFor(m => m(item).AtlasMonitor) %>
            <%= Html.HiddenFor(m => m(item).AtlasMonitorData) %>
            <% for (var i = 0; i<item.FaxcomMonitorData.Count; i++) { %>
                <% Html.HiddenFor(Function(m) m(item).Data(i).Key) %>
                <% Html.HiddenFor(Function(m) m(item).Data(i).Value) %>
            <% } %>
            <input type="submit" value="Search" />
        <% } %>
    <% } %>
    

    您可能需要将项目放在局部视图中(未测试此代码)。这听起来可能很复杂,但 MVC 并非旨在将对象从控制器动作传递到控制器动作。

    我能想到的另一个解决方案是将监控项存储在会话状态中。然后仅将索引传递给“详细信息”操作方法。从会话状态中检索它。这当然会添加通常也不推荐的状态。

    【讨论】:

    • 好的。我会尽快尝试并告诉你。谢谢!
    • 感谢您的回复。我从来没有机会实现你的代码,但你的回答极大地帮助了我向老板解释我遇到的问题。我们最终采用了不同的解决方法(有问题的编辑),但如果没有你的回应,我很难说服他按照我们计划的方式去做。我将 Jonathan 的答案标记为正确,因为它是首选方法(在我的情况下它不是一个选项)。谢谢!
    • 如果有办法我也可以将您的答案标记为答案或建议它有帮助(除了 +1),请告诉我。
    • 没有但没关系。我很高兴能帮上忙
    猜你喜欢
    • 2021-01-07
    • 1970-01-01
    • 2016-01-04
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    • 2019-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多