如何避免使用MVC标记汤?

joh*_*nny 14 model-view-controller asp.net-mvc

我正在阅读这篇文章是为了证明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>".

示例: 处理ASP.NET MVC"标签汤"

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

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

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

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

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

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

Con*_*ell 19

看看使用Razor视图引擎,它包含在MVC 3中.还要尝试将所有逻辑保留在Controller类中,并根据View中显示的内容构建模型.

  • Razor是避免标记汤的一种显而易见的方法,因为不需要任何<%%>标记 - 只需@在代码之前和视图引擎处理C#结束和HTML开始的地方.

    <span class="name">@Model.Name</span>
    
    Run Code Online (Sandbox Code Playgroud)

    甚至循环和if语句在.cshtml使用Razor和魔法@角色的文件中仍然看起来很性感.

    @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>
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

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

  • 部分视图可以很好地分离视图的不同部分(但尽量不要使用它们太多).您还可以将不同的模型对象传递给每个局部视图,我发现这对于某些大型循环或某种类似天赋的东西都很方便.

  • HTML助手也非常有用(感谢subkamran).这里有与上面提到的部分视图类似的概念,但是HtmlHelpers略有不同,因为您指定了方法的参数(及其类型),而不是您可以传递单个Model对象的部分视图.这是一个如何实现它们好例子.同样,这些在您的cshtml代码中看起来非常整洁.

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

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

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

  • 同意; 剃刀让我四处乱窜.我已经看到了一些复杂的Razor视图,它们看起来仍然很好看,具体取决于它们的表现如何.除了Razor Helpers之外,部分视图使事情变得更好(例如,带有`@helper`语法的`App_Code\Helpers.cshtml`). (2认同)

uad*_*ive 5

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

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

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

我有7年的ASP.NET Forms应用程序编写经验.一旦我切换到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的比较:

网格视图:

<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>
Run Code Online (Sandbox Code Playgroud)

剃刀:

<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>
Run Code Online (Sandbox Code Playgroud)

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

你还提到没有必要进行单元测试.我会重新考虑这个想法.单元测试对于在生产站点上发现问题之前发现问题非常有用.


rad*_*bob 2

那里又回来了。一次又一次。原始 HTML。梦衣者。ASP。微软Word。ASP.NET、MVC.NET。我们似乎能够触及光谱的两端,但中间没有最佳位置。

归根结底,我们最希望说的是“好吧,至少所有的疯狂都被隔离在视野中”。我说“希望”是因为根据我的经验,说“面向对象”比用 OO 所暗示的所有软件原则优点来实现面向对象要容易得多。

从长远来看,标签汤不是问题。这绝对不是 MVC 上下文中的问题。问题在于令人震惊的编码。MVC 部件像连体三胞胎一样融合在一起,清楚地表明了软件设计和编码原则的无能,这是迄今为止更大的犯罪。

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