如何避免使用MVC标记汤?

时间:2011-12-28 21:11:09

标签: asp.net-mvc model-view-controller

我正在阅读这篇文章,以寻求证明MVC胜过非mvc就像普通的老式php(不使用MVC,即使是经典的asp也可以使用,虽然很痛苦):

http://www.codinghorror.com/blog/2008/07/web-development-as-tag-soup.html

我找不到答案。我认为获得标签汤是不可避免的。是的,我知道MVC将模型和控制器分开,但是当你进入视图时,一切都变得丑陋。我可以阅读发出的html与标记汤一样好或更好。

我不会使用单元测试,所以它不是一个重要的优势。我不确定我怎么能避免一个丑陋的观点,现在重要的是我如何让它枯萎mvc或只是发出html。

我认为使用所有奇怪的编码(而且是代码)维护视图比使用response.write "<table>"更容易。

示例:Dealing with ASP.NET MVC "tag soup"

Arnis的答案(对他或其他任何人都没有冒犯),修复了问题中可怕的代码,但对我来说仍然看起来很糟糕或者至少不是我所期待的。对我来说,这些尖括号也可能是<% %><?php ?>

我喜欢codeigniter这样的东西,它确实是我见过的最干净但它仍然不是我所期望的。我想我希望在MVC中出现一些让一切变得美丽的魔力。显然,除非一个人真的非常小心,否则没有比经典asp更好的了,因为它与视图有关。

这主要是关于观点。不是哪种语言更适合什么或哪个模板引擎最好(它们都具有相同的标记混合倾向)。

相信我。我希望让MVC与我的合作开发人员一起工作,所以我不会反对它作为一个范例。我不能让他们同意某些事情只是因为每个人都在这样做或类似的东西。

感谢您的任何评论。我必须能够证明这些事情是正确的,虽然我理解MVC和我得到的东西,但是这个观点使得它看起来像是浪费时间。

编辑:一切似乎都是针对特定的框架而不是计划。我看到了一些见解,但最终似乎除了纪律之外别无他法。谢谢大家的答案。

7 个答案:

答案 0 :(得分:19)

请查看使用{strong> MVC 3 中包含的Razor视图引擎。还要尝试将所有逻辑保留在 Controller 类中,并根据 View 中显示的内容构建 Model

  • Razor 是一种避免标记汤的明显方法,因为不需要任何<%%>标记 - 只需@代码和视图引擎解决了C#结束和HTML开始的问题。

    <span class="name">@Model.Name</span>
    

    偶数循环和if语句在带有Razor和.cshtml字符的@文件中看起来仍然很性感。

    @if(shouldDisplayDiv) {
        <div id="mydiv">Div is displayed!</div>
    }
    
    
    @foreach(User user in Model.Friends) {
        <a href="@user.Url"><img src="@user.ImageUrl" title="@user.Name" /></a>
    }
    

    默认情况下,Razor还会为您处理HTML编码,因此您的视图不会充满Html.Encode次调用。 (注意:如果您需要输出HTML,可以使用Html.Raw辅助方法。)

  • 将您的逻辑放入Controller 将理想地消除视图中对大型代码块的需求。尝试让模型对象包含视图的所有动态数据,就像它将在视图中显示一样。目标是在你的视图中没有任何 C#代码(毫无意义,但如果这是目标,请看你有多接近它!)。

  • 部分观看可以很好地分隔您视图的不同部分(但尽量不要使用它们太多)。您还可以将不同的模型对象传递给每个局部视图,我发现这对于某些大型循环可能很方便,或者像flair这样的东西。

  • HTML帮助也非常有用(感谢subkamran)。这里有与上面提到的部分视图类似的概念,但是HtmlHelpers略有不同,因为您指定了方法的参数(及其类型),而不是您可以传递单个Model对象的部分视图。这是一个good example of how to implement them。同样,这些代码在cshtml代码中看起来非常整洁。

     <div class="specialdiv">@Html.SomeMethod(Model, "String", 5)</div>
    
  • 客户端MVC 是另一种选择,如果您正在开发支持AJAX的Web应用程序,那么这是一个强烈的建议。遵循控制器中的逻辑,您将使用像Backbone.js这样的客户端MVC框架以整齐的方式模板化HTML,并使用jQuery .ajax()来回与之交谈你的控制器。分离您的表示层是一个很好的做法,为您留下一些漂亮的View标记!

我坚持这些小指南,它对我来说就像一个魅力。漂亮,干净的HTML标记,偶尔有@个字符。很容易维护(至少是视图!)。

编辑: 请注意,所有这些要点都包含在ASP.NET MVC 3中,所有“最佳做法”都与微软有关。无需安装任何额外的框架,插件或插件即可遵守这些准则。

答案 1 :(得分:5)

MVC正在获得牵引力的原因。虽然确实有一些标签被添加到视图中,但如果逻辑在它应该属于的控制器中正确处理,那么它就更清晰了。

理解MVC的真正含义也很重要:http://en.wikipedia.org/wiki/Model-view-controller。您从中获得的优势是清洁分离和易于替换。

考虑一下。您的客户希望您编写支持传统浏览器和移动浏览器的应用程序。使用MVC模式,控制器检测平台并更改呈现的视图非常容易。如果正确完成,将一个视图换成另一个视图应该是一个非常简单的过程。

我在ASP.NET Forms中编写应用程序有7年的经验。一旦我切换到MVC并开始理解MVC,我意识到我永远不会回去。视图更清晰,调试更简单,逻辑更明显。我编写的最后一个应用程序使用MVC和jQuery,每天有3000个用户,并且已经成为我们现在编写所有站点的模型站点。

我们的客户要求我们为我们的网站添加移动支持。因为我们在实施中选择了MVC,所以花了我们一周的时间来为移动设备添加全面的支持。如果我们在ASP.NET Forms中完成它,我们就无法快速完成它并且如此有效地利用代码。

虽然来自http://www.codinghorror.com/blog/2008/07/web-development-as-tag-soup.html的示例代码确实看起来很糟糕,但你有没有看过ASP.NET GridView? HTML非常糟糕。您提供的示例还显示了可以执行某些工作来清理其视图的人员。这是gridview与MVC与Razor的比较:

GridView的:

<asp:datagrid id="voucherGrid" runat="server" CssClass="dg" CellPadding="2" AutoGenerateColumns="False" DataKeyField="cx_nbr" 
        Width="800px" AllowPaging="True" AllowSorting="True" PageSize="20" OnPageIndexChanged="voucherGrid_PageIndexChanged" 
        OnSortCommand="voucherGrid_SortCommand" OnItemDataBound="voucherGrid_ItemDataBound">
        <SelectedItemStyle CssClass="dgSelectItem"></SelectedItemStyle>
        <AlternatingItemStyle CssClass="dgAlternateItem"></AlternatingItemStyle>
        <ItemStyle CssClass="dgNormalItem"></ItemStyle>
        <HeaderStyle ForeColor="White" CssClass="dgHeader"></HeaderStyle>

        <Columns>
            <asp:TemplateColumn HeaderText="Image">
                <ItemStyle HorizontalAlign="Center"></ItemStyle>
                <ItemTemplate>
                    <asp:HyperLink id="voucherImageLink" Target="_blank" runat="server">Image</asp:HyperLink>                                               
                </ItemTemplate>
            </asp:TemplateColumn>
            <asp:BoundColumn DataField="cx_voucher_nbr" SortExpression="cx_voucher_nbr" HeaderText="Call #">
                <ItemStyle HorizontalAlign="Center"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_pkup_datetime" SortExpression="cx_pkup_datetime" HeaderText="Date" DataFormatString="{0:MM/dd/yyyy}">
                <ItemStyle HorizontalAlign="Center"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_pass_name" SortExpression="cx_pass_name" HeaderText="Passenger">
                <ItemStyle Wrap="False"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_pkup_address" SortExpression="cx_pkup_address" HeaderText="Pick-Up">
                <ItemStyle Wrap="False"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_dest_address" SortExpression="cx_dest_address" HeaderText="Destination">
                <ItemStyle Wrap="False"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_trip_miles" SortExpression="cx_trip_miles" HeaderText="Miles" DataFormatString="{0:N2}">
                <ItemStyle HorizontalAlign="Right"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_pkup_datetime" SortExpression="cx_pkup_datetime" HeaderText="Time" DataFormatString="{0:t}">
                <ItemStyle HorizontalAlign="Center"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_vch_wait_time_amt" SortExpression="cx_vch_wait_time_amt" HeaderText="Wait" DataFormatString="{0:C}">
                <ItemStyle HorizontalAlign="Right"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_vch_other_amt" SortExpression="cx_vch_other_amt" HeaderText="Other" DataFormatString="{0:C}">
                <ItemStyle HorizontalAlign="Right"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_vch_admin_charge_amt" SortExpression="cx_vch_admin_charge_amt" HeaderText="Admin Charge" DataFormatString="{0:C}">
                <ItemStyle HorizontalAlign="Right"></ItemStyle>
            </asp:BoundColumn>
            <asp:BoundColumn DataField="cx_vch_fare_amt" SortExpression="cx_vch_fare_amt" HeaderText="Rate" DataFormatString="{0:C}">
                <ItemStyle HorizontalAlign="Right"></ItemStyle>
            </asp:BoundColumn>
        </Columns>

        <PagerStyle ForeColor="White" CssClass="dgPager" Mode="NumericPages"></PagerStyle>
    </asp:datagrid>

剃刀:

<table id="voucherGrid" class="dg" style="width: 800px;">
   <th class="dgHeader">
      <td>Image</td>
      <td>Call #</td>
      <td>Date</td>
      <td>Passenger</td>
      <td>Pick-Up</td>
      <td>Destination</td>
      <td>Miles</td>
      <td>Time</td>
      <td>Wait</td>
      <td>Other</td>
      <td>Admin Charge</td>
      <td>Rate</td>
   </th>
   @foreach(var voucher in Model.Vouchers) {
   <tr>
      <td>@voucher.Image</td>
      <td>@voucher.CallNum</td>
      <td>@voucher.Date</td>
      <td>@voucher.Passenger</td>
      <td>@voucher.PickUp</td>
      <td>@voucher.Destination</td>
      <td>@voucher.Miles</td>
      <td>@voucher.Time</td>
      <td>@voucher.Wait</td>
      <td>@voucher.Other</td>
      <td>@voucher.AdminCharge</td>
      <td>@voucher.Rate</td>
   </tr>
   }
</table>

你告诉我哪个看起来更容易理解?对我而言,处理html标签和一些额外的@或&lt;%标签会更加清晰。

您还提到不需要进行单元测试。我会重新考虑这个想法。在生产现场发生问题之前,单元测试非常有用。

答案 2 :(得分:2)

又回来了。一次又一次。原始HTML。 Dreamwearver。 ASP。 MS Word。 ASP.NET,MVC.NET。我们似乎能够击中光谱的任何一端,但中间没有最佳位置。

归根结底,也许我们最希望说的是“好吧,至少所有的疯狂都是孤立的。”我说“希望”,因为根据我的经验,说“面向对象”比面向对象要容易得多,而OO暗示的所有软件都是原则性的好。

从长远来看,标签汤不是问题。它绝对不是MVC环境中的问题。令人震惊的编码是问题所在。与Siamese三胞胎融合在一起的MVC部分,清楚地表明软件设计和编码原则的无能是迄今为止更大的犯罪。

像Ruby on Rails或MVC.NET这样的MVC框架将有助于在MVC范例中编码时的编码效率;它本身不会让你的代码更快。如果你不知道你到底在做什么,它肯定不会阻止代码维护的噩梦。

答案 3 :(得分:1)

  1. 使用razr视图引擎(我的偏好,我觉得它看起来更整洁)。 response.write "<table>"很容易写。但是你是在一个只控制视图的文件/类中做到这一点,并且可以轻松交换或更改而不触及任何服务逻辑?这让我想到了#2。
  2. 讨论与小组分离的问题并决定每个逻辑的存在位置。依赖接触点在哪里,你的所有逻辑都是在DLL中分组的,它们不知道视图/控制器?决定从开始并在某处写下来。
  3. 将观看次数视为观点!
  4. 不要在视图中做任何事情!
  5. 一旦你正在观看视频!
  6. 我是否曾提到意见只是那个?
  7. 我不吝惜任何人使用MVP或任何其他范例。但是如果你想尝试MVC,那就做对了,你会发现重构和维护代码要容易得多。

    我的2cents

答案 4 :(得分:1)

视图层优于标记汤的优势在于视图层应该将错误的逻辑与错误数据隔离开来,从而使根本原因更容易被追踪。这不会自动发生,必须将其烘焙到视图的代码约束中。我见过的关于使用MVC的HTML视图的最佳方法如下(来自Tony Marston):

  • 将数据转换为HTML的代码是显示逻辑。
  • 创建或获取随后转换为HTML的数据的代码不是显示逻辑。

知道是成功的一半,一致的实施是另一回事。强大的功能带来了巨大的责任,因此使用有限的命令子集有助于实现更清晰的代码。最小的陈述将是印刷和包含。用于生成表,列表或表单的循环和数据绑定可以由JavaScript库或XSLT处理。变量赋值,条件逻辑和字符串操作可以在本地或全局包含中完成。其他任何东西都可以由模型或控制器处理。

答案 5 :(得分:1)

不要在模板代码中进行任何计算。

看看Django中允许的内容:https://docs.djangoproject.com/en/1.3/topics/templates/

没算术。没有传递参数到方法。没有任何类型的定义(除了循环)。这会强制您在视图方法中执行几乎所有操作,并传入所需的任何对象和列表,这样可以保持其清洁。

答案 6 :(得分:1)

您可以使用GWT,ZK,Vaadin,JSF 2或隐藏HTML的内容。我不知道MVC是什么意思。 Django / RoR / CakePHP Model-View-Presenter模式有时称为MV​​C或真正的MVC。如果你坚持使用MVC,你应该在视图代码中只有数据绑定和事件触发器。

我认为这是一个设计问题,而不是技术。