3

关于ASP.NET MVC 和Codebehind-files 的讨论很多,其中大部分都指出这些Codebehind-files 是邪恶的

所以我的问题是,您如何处理特定于页面的逻辑

我们不想要的是内联代码中的意大利面条式代码,并且我们不希望页面特定的代码分散在辅助类中或 HTML 辅助类之上。

一个例子是:

<% for(int i = 0; i < companyList.Count; i++) { %>
    RenderCompanyNameWithRightCapsIfNotEmpty(company, i)
<% } %>

附带代码隐藏:

private string RenderCompanyNameWithRightCapsIfNotEmpty(string company, index)
{
    if (index == 0) {
        return string.Format("<div class=\"first\">{0}</div>", company);
    }
    // Add more conditional code here
    // - page specific HTML, like render a certain icon
    string divClass = (index % 2 == 0) ? "normal" : "alternate";
    return string.Format("<div class=\"{1}\">{0}</div>", company, divClass);
}

这只会在一页上使用,并且很可能会发生变化。

更新:我想到了几种方法:

1)页面上的内联代码隐藏 - 使用返回字符串的简单方法。

<script runat="server">
    private string RenderCompanyHtml(string companyName) ...
<script>

2)在控制器中放置一个返回字符串的方法。但这会将 View-logic 放入 Controller中。

public class SomeController : Controller 
{
    [NonAction] 
    private static string RenderCompanyHtml(string companyName) ...

    public ActionResult Index() ...
}
4

3 回答 3

3

You should put that code in the controlleraction where you prepare the viewdata.

I usually make a region "helper methods" in my controller class with a few [NonAction] methods to keep things clean.

So my (simplified) controller would look like this:

public class SomeController : Controller 
{
  #region Helper methods
  [NonAction] 
  private static string CompanyNameWithRightCapsIfNotEmpty(string company)
  {
    if (string.IsNullOrEmpty(company)) {
        return company;
    }
    return UpperCaseSpecificWords(company);
  }

  #endregion

  public ActionResult Companies()
  {
    var companies = GetCompanies();
    var companyNames = companies.Select(c =>  CompanyNameWithRightCapsIfNotEmpty(c.Name));
    ViewData["companyNames"] = companyNames;
    return view();
  }
}
于 2009-06-01T08:09:31.923 回答
2

Helper methods are one good way of handling page specific code, but I think it is a;ways preferable to get your model to show the data you need.

If you're going to go for the helper option, you would be better served by making the operation it perfroms a bit less page specific. If your method RenderCompanyNameWithRightCapsIfNotEmpty has to be so specific it would be better if your model provided it. One way would be to have the model provide a list with the text already formatted, and expose it as a public property (say an IEnumerable of formatted company names).

于 2009-06-01T08:18:59.720 回答
1

Use Html Helpers.

Like so create the helper methods in a static class:

    public static string Label(this HtmlHelper helper, string target, string text)
    {
        return String.Format("<label for='{0}'>{1}</label>", target, text);
    }

.. then use in your view:

<span><% =Html.Label("FinishDateTime.LocalDatetime", "Finish Time:")%><br />

You could create a helper method called maybe RenderCompanyName(string[] companies) that checked for nulls, did the caps manipulation and rendered the html in between - all in the same helper if you like.

Also: controller action methods should be light - ie. only getting the data and returning views. You should delegate things like manipulation of data for presentation to views and Html helpers.

EDIT: Here is a helper that you might be after:

This helper renders an IList<> to html in the form of an unordered list <ul>...</ul>. The useful thing about it is that it gives you control over how the list is rendered thru css AND it allows you to render additional html/content for each item. Take a look - this is the helper:

    public static string UnorderedList<TItem>(this HtmlHelper helper,
        IList<TItem> items, Func<TItem, string> renderItemHtml,
        string ulID, string ulClass, string liClass)
    {
        StringBuilder sb = new StringBuilder();

        // header
        if (!ulID.IsNullOrTrimEmpty()) sb.AppendFormat("<ul id='{0}'", helper.Encode(ulID.Trim()));
        else sb.AppendFormat("<ul");
        if (!ulClass.IsNullOrTrimEmpty()) sb.AppendFormat(" class='{0}'>", helper.Encode(ulClass.Trim()));
        else sb.AppendFormat(">");

        // items
        foreach (TItem i in items)
        {
            if (!liClass.IsNullOrTrimEmpty())
                sb.AppendFormat("<li class='{0}'>{1}</li>", helper.Encode(liClass.Trim()),
                    renderItemHtml(i));
            else
                sb.AppendFormat("<li>{0}</li>", renderItemHtml(i));
        }

        // footer
        sb.AppendFormat("</ul>");

        return sb.ToString();
    }

..using it is easy. here is a simple example to render a list of tags:

    <div id="tags">
        <h2>Tags</h2>
        <%=Html.UnorderedList<Tag>(Model.Tags.Tags,tag=>
            {
                return tag.Name;
            },null,null,null) %>
    </div>

..you can see in my usage example that i have chosen not to specify any css or id attribute and i simply return the name of the Tag item thru the use of the anonymous delegate. Anonymous delegates are way easy to use.. in your case maybe something like this would work:

    <div id="tags">
        <h2>Tags</h2>
        <%=Html.UnorderedList<string>(ViewData["companies"],company=>
            {
                if (someCondition) return company.ToUpper();
                else return company;
            },null,null,null) %>
    </div>

.. ViewData["companies"] is an IList<string> for simplicity.

于 2009-06-01T08:15:04.313 回答