开发者

ASP.net render HTML nicely (Beautify)

开发者 https://www.devze.com 2023-02-15 19:41 出处:网络
When I generate my controls in ASP.net they come out like this: <div id=\"ctl00_mainContent_ApprovalSelectPanel\" class=\"discussWrapper\">

When I generate my controls in ASP.net they come out like this:

<div id="ctl00_mainContent_ApprovalSelectPanel" class="discussWrapper">

        <span class="cbox highlighted"><input id="ctl00_mainContent_ctl00" type="checkbox" name="ctl00$mainContent$ctl00" checked="checked" value="70" /><label for="ctl00_mainContent_ctl00">Buyer1</label></span><span class="cbox"&开发者_运维问答gt;<input id="ctl00_mainContent_ctl01" type="checkbox" name="ctl00$mainContent$ctl01" value="75" /><label for="ctl00_mainContent_ctl01">Buyer2</label></span><span class="cbox"><input id="ctl00_mainContent_ctl02" type="checkbox" name="ctl00$mainContent$ctl02" value="280" /><label for="ctl00_mainContent_ctl02">Client3</label></span><span class="cbox"><input id="ctl00_mainContent_ctl03" type="checkbox" name="ctl00$mainContent$ctl03" value="281" /><label for="ctl00_mainContent_ctl03">Client4</label></span><span class="cbox"><input id="ctl00_mainContent_ctl04" type="checkbox" name="ctl00$mainContent$ctl04" value="283" /><label for="ctl00_mainContent_ctl04">Client2</label></span><span class="cbox"><input id="ctl00_mainContent_ctl05" type="checkbox" name="ctl00$mainContent$ctl05" value="289" /><label for="ctl00_mainContent_ctl05">Client1</label></span><span class="cbox"><input id="ctl00_mainContent_ctl06" type="checkbox" name="ctl00$mainContent$ctl06" value="346" /><label for="ctl00_mainContent_ctl06">artworker1</label></span><span class="cbox"><input id="ctl00_mainContent_ctl07" type="checkbox" name="ctl00$mainContent$ctl07" value="362" /><label for="ctl00_mainContent_ctl07">buyer3</label></span><span class="cbox"><input id="ctl00_mainContent_ctl08" type="checkbox" name="ctl00$mainContent$ctl08" value="367" /><label for="ctl00_mainContent_ctl08">meeeee</label></span><span class="cbox"><input id="ctl00_mainContent_ctl09" type="checkbox" name="ctl00$mainContent$ctl09" value="368" /><label for="ctl00_mainContent_ctl09">stake</label></span>

    </div>  

Pretty ugly and hard to understand when you view the source. This isn't a problem usually, but my site is offering visitors resources and tutorials where looking at the source is part of the experience.

Is there any way to render these controls nicely? Indented properly, better id's and names etc?


In .NET 4.0 you can set the ClientIDMode to one of 4 options AutoID, Static, Predictable and Inherit. You're probably looking for Static as this will ensure that your controls render to the page with the IDs you've assigned to them.

You can set it at application level by adding:

<pages clientIDMode="Static">

To your web.config

There's more details on these changes here: http://beyondrelational.com/blogs/hima/archive/2010/07/16/all-about-client-id-mode-in-asp-net-4.aspx


ASP.NET WebForms HTML rendering and control markup have been improved in .NET 4.0 and this will help with the control IDs and structure of the HTML elements themselves (as mentioned in Rob Stone's answer to your question). However, the indents and line breaks might still be less than desirable for your needs.

If the HTML source truly is part of the user experience for your application, you might consider writing an HttpModule attached to the ReleaseRequestState event. This approach will address the actual line breaks and indentations of your HTML source. To avoid re-inventing the wheel you could use either the .NET port of HTML Tidy or a .NET Wrapper for HTML Tidy as part of your custom filter on the response.

There is a nice example of how you might write a custom filter in an HttpModule in this blog. The section of the code that I found most useful is as follows (slightly edited but you can get the full understanding from the blog itself):

public class CustomModule : IHttpModule
{
  public void Init(HttpApplication context)
  {
    context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState);
  }

  private void context_ReleaseRequestState(object sender, EventArgs e)
  {
    HttpResponse response = HttpContext.Current.Response;
    if (string.Compare(response.ContentType,"text/html",true) == 0)
    {
      response.Filter = new CustomFilter(response.Filter,response.ContentEncoding);
    }
  }
}

and inside your CustomFilter class...

public override void Write(byte[] buffer, int offset, int count)
{
  sb = new StringBuilder(count + 1024);
  sb.Append(enc.GetString(buffer,offset,count));

  // <---- Run the sb content through HTML Tidy here ---->

  byte[] buff = enc.GetBytes(sb.ToString());
  s.Write(buff,0,buff.Length);
  }
}


Getting pretty output is going to be a near impossibility, because the parser does not have any concept of context when rendering controls. Many controls render more than one HTML element, and they would need to know their context to do this... as well as be able to know what kind of formatting was desired (e.g. for list controls, when to start a new line, when to indent again).

Also, not all elements in markup are actually rendered, and the layout of your markup is not always directly related to the layout of the output. For example:

<asp:PlaceHolder runat="server" />
    <asp:Panel runat="server" />
        <asp:DropDownList runat="server" />
    </asp:Panel />
</asp:PlaceHolder />

Placeholder is not rendered, so would that cause an indent in the output or not? DropDownList renders multiple HTML controls, and there's no way for it to determine the desired way of being rendered: should it indent to the same level as the first control? Should it render with no inter-element spacing? From a practical standpoint, it's more efficient to render with no spacing at all (which is what most controls do) to minimize the amount of data that needs to be sent to the client.

Finally, even in the simple cases, the actual representation when you "view source" from a browser will probably be different between browsers. They can all choose to handle spacing, line breaks, indentation in any way they choose, since inter-element spacing does not affect rendering in any way.

If you are showing "before/after" examples on your web site you really don't have much choice except to manually format the output for presentation, if this is what you want. If people want to look at the source too, that's fine, but it would be very challenging to make the source consistently look as good as your markup.

If this was really important to you, you could intercept the output stream and reformat it before sending to the client, but it won't happen directly from asp.net's rendering engine. For an example of how to do this, google "asp.net response filter" - here's one. I'm sure it's not hard to find code that formats HTML that you could apply to this concept.


Late to the party here, but I faced a similar problem. We were generating some highly complex javascript that was getting way too mangled to reasonably debug with it all jumbled in line with the rest of the markup. So I came up with this class.

public class HtmlPrettyControl : HtmlGenericControl
{
    public bool Indent { get; set; }

    public HtmlPrettyControl(string tag) : this(tag, true) { }

    public HtmlPrettyControl(string tag, bool indent) : base(tag)
    {
        Indent = indent;
    }

    protected override void Render(HtmlTextWriter writer)
    {
        // Here you can check if you are running against a production environment
        // and just do base.Render to prevent extra code execution and space in
        // your response to the client

        if (Indent)
        {
            RenderBeginTag(writer);
            writer.WriteLine();
            writer.Indent++;
            base.RenderChildren(writer);
            writer.WriteLine();
            writer.Indent--;
            RenderEndTag(writer);
        }
        else
        {
            base.Render(writer);
        }
        writer.WriteLine();
    }
}

Usage example:

var myDiv = new HtmlPrettyControl("div");
var myLabel = new HtmlPrettyControl("label", false);
myLabel.InnerText = "I'm sorry, Dave.";
myDiv.Controls.Add(myLabel)

Generates markup:

<div>
    <label>I'm sorry, Dave.</label>
<div>

We use a similar Render method override for the controls that aren't simple Html tags (in a different base class/inheritance chain). The only downside is that the writer passed to the Render method does not seem to be informed of the current indentation level of an ascx that your control is living on (if any). So while the hierarchy of the control and its children is nicely indented and broken up, they will reset to an indentation level of 0, breaking the overall flow from surround markup on your ascx or aspx layout files.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号