views:

509

answers:

5

I was working on an ASP.NET MVC template today, and after staring at all those fluorescent yellow % tags for long enough, I basically decided I had had enough, so I painstakingly modified my ascx file to look like this:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl"         %>

<%  if (Model == null)
    {                                                                       %>
<%=     ViewData.ModelMetadata.NullDisplayText                              %>
<%  }
    else if (ViewData.TemplateInfo.TemplateDepth > 1)
    {                                                                       %>
<%=     ViewData.ModelMetadata.SimpleDisplayText                            %>
<%  }
    else
    {                                                                       %>
<%      foreach (var prop in ViewData.ModelMetadata.Properties.Where(
            pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
        {                                                                   %>
<%          if (prop.HideSurroundingHtml)
            {                                                               %>
<%=             Html.Display(prop.PropertyName)                             %>
<%          }
            else
            {                                                               %>
<%              if (!String.IsNullOrEmpty(prop.GetDisplayName()))
                {                                                           %>
                    <span class="display-label">
<%=                     prop.GetDisplayName()                               %>
                    </span>
<%              }                                                           %>
                <span class="display-field">
<%=                 Html.Display(prop.PropertyName)                         %>
                </span>
<%          }                                                               %>
<%      }                                                                   %>
<%  }                                                                       %>

Ahh readability at last. The only problem is, it takes way to long to do this by hand. I need a way to automate this. Some kind of code formatting solution. Perhaps a macro or a Visual Studio add-in or ...? What do you advise?

Update

I'm now planning to refactor out most of the logic from my markup (see Mike's answer below), but in the mean time, I came up with a more manageable way to format ascx files that have a mixture of code and html. The code is a little more spread out this way, but it's much easier to format the code like this in the first place, and it's much easier to work with as well.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<% 
    if (Model == null)
    {
%>
        <%= ViewData.ModelMetadata.NullDisplayText %>
<%
    }
    else if (ViewData.TemplateInfo.TemplateDepth > 1)
    {
%>
        <%= ViewData.ModelMetadata.SimpleDisplayText %>
<%
    }
    else
    {
%>
<%
        foreach (var prop in ViewData.ModelMetadata.Properties.Where(
            pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
        {
            if (prop.HideSurroundingHtml)
            {
%>
                <%= Html.Display(prop.PropertyName) %>
<%
            }
            else
            {
%>
                <div class="display-row">   
<%
                if (!String.IsNullOrEmpty(prop.GetDisplayName()))
                    {
%>
                        <div class="display-label">
                            <%= prop.GetDisplayName() %>
                        </div>
<%
                }
%>
                    <div class="display-field">
                        <%= Html.Display(prop.PropertyName) %>
                    </div>
            </div>
<%
            }
        }
    }
%>
A: 

Write your own.

Daniel Coffman
Hey! He asked what I advised! That's my advice.
Daniel Coffman
and apparently somebody thought your advice was not useful -shrug-
qntmfred
A: 

For our current project, we cleaned up all the if-elses somewhat by writing an HTML helper:

public static void WriteIf(this HtmlHelper helper, bool condition, string truePart, string falsePart)
{
     helper.ViewContext.HttpContext.Response.Write(condition ? truePart : falsePart);
}

and then in the HTML, you would say:

<% Html.WriteIf(Model.IsTrue(), "TrueText", "FalseText"); %>
The Matt
That's a cool idea, Matt, but it doesn't really seem like it would help much when you have nested or multi-line `if` statements, as in this example. I'm looking for a code formatting solution.
DanM
Yep, agreed. Wish I had something better for ya.
The Matt
+3  A: 

With proper view model (and optionally, with spark view engine), there is no tag soup.

Particularly, if templates are used.

Can't tell much about this example (even less - to sort it out), but for me - usually it's all about sense of tidiness and ability to structure things properly.


"I'm looking for a code formatting solution." => then you must check out spark. It 'htmlifies' your views even if they do contain logic.

Your example in it (without restructuring anything) =>

<var nullText="ViewData.ModelMetadata.NullDisplayText"
     templateDepth="ViewData.TemplateInfo.TemplateDepth"
     simpleDisplayText="ViewData.ModelMetadata.SimpleDisplayText"
     props="ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm))" 
     m="ViewData.Model"/>
<if condition="m==null">
  ${nullText}
</if>
<elseif condition="templateDepth>1">
  ${simpleDisplayText}
</elseif>
<else>
  <for each="var prop in props">
    <if condition="prop.HideSurroundingHtml">
      ${Html.Display(prop.PropertyName)}
    </if>
    <else>
      <span if="!string.IsNullOrEmpty(prop.GetDisplayName()" class="display-field">
        ${prop.GetDisplayName()}
      </span>
      <span class="display-field">
        ${Html.Display(prop.ProperyName)}
      </span>
    </else>
  </for>
</else>

Might be wrong somewhere, but you got the idea.

Arnis L.
+12  A: 

I believe your "tag soup" pain is actually a symptom of a different problem: you're feeling it because you've got logic in your view. Views should be very lightweight, with little or no logic. Your logic should be in your controllers, which can decide to render different views depending on the logic. Or you can put the logic into helpers.

See this article by Rob Conery

Mike Scott
Interesting point, thanks. The example I used was honestly just a slight modification on the standard ASP.NET MVC Object.ascx template. I could write helpers for all the templates I want to modify, but wouldn't that just be inverting the problem (i.e., putting html code in C# files instead of C# code in html files)?
DanM
Another point: I'm doing a lot of trial and error with my templates right now, and having the code in an ascx file (as opposed to a C# file), I can just make a change, save the file, and refresh the browser. If I had to rerun the app every time, it would be a lot more time consuming. Maybe once I find a solution I like, I could write a helper for the sake of maintainability, but for now, working with an ascx file is my preference (as long as it's formatted the way I have it in my question).
DanM
A lot of the "official" sample code isn't perhaps best practice, unfortunately.You can generally put your HTML code in partials and have helpers render them. The helpers can implement the C# logic which, for example, decides *which* partial to render, and/or passes the appropriate model to a partial.
Mike Scott
@Mike, thanks again, I think I'm coming around to your way of thinking, especially the idea of using a combination of helpers and partials.
DanM
Dan, just another couple more tips. You don't have to rerun your site every time you change the code. Just run your site once then open another browser tab/window to the site and keep it open. When you change code, just do a build and refresh the browser window. You don't have to be running. Secondly, on the project options, web tab, change the start option to "Don't open a page..." When you debug, just hit run and refresh your page. First time around, run then right click on the ASP.NET Development Server and select, "Show in web browser".
Mike Scott
+3  A: 

Actually you can remove all your <%= %> by Response.Write . So instead having

<% foreach(var obj in anyEnumerable) 
   {
%>
<%= Html.TextBox(...) %>
<% } %>

you can have

<% 
    foreach(var obj in anyEnumerable) 
    {
        Response.Write(Html.TextBox(...));
    } 
%>

IMO it is more readable

Gregoire
Thanks, I like that idea.
DanM
Awful idea - only do this if you have to.
Dan
@Dan: your explanation is awful, please elaborate...
Gregoire