Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help with ASP.NET MVC HtmlHelper API Design

Tags:

c#

asp.net-mvc

I am working on a runtime composite resource library for ASP.NET WebForms/MVC. I support both standard ASP.NET WebForms via WebControls and have also recently added support for ASP MVC Html Helpers. One feature that I currently support with the WebForms WebControls is the concept of "Partial" resource definitions where a resource can be combined over the Master/View pages etc.

When implementing the MVC equivalent, I am not sure what the best practise is? I am currently leaning towards a design something like:

Master Page

<% using (Html.CreateCompositeResourcePartContext())
   {
     Html.CompositeCssResourcePart(
       "ResourceName", 
       new[] { "/Styles/SharedStyle1.css", "/Styles/SharedStyle2.css" }
     );
     %>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
<% } %>

Which will create a "context" wrapper around the head ContentPlaceholder.

View Page

<asp:Content ID="HeadContentPlaceholder" ContentPlaceHolderID="head" runat="server">
  <% Html.CompositeCssResourcePart(
     "ResourceName", 
     new[] 
     {
       "/Styles/PageStyle5.css",
       "/Styles/PageStyle6.css",
       "/Styles/PageStyle7.css"
     }) %>
</asp:Content>

So any view pages can extend the partial resource definition as seen above.

The questions I have:

1) Unlike all my other HtmlHelpers, these extensions do not immediately write out the HTML fragment but rather wait until the context is disposed. Should these extensions be off the ViewContext instead (or some other object)?

2) I personally think the concept of a "using" makes sense to wrap a block of code rather than separate BeginCompositeResourcePartContext/EndCompositeResourcePartContext calls, would you agree? If no, what is better about separate method calls?

Any feedback on the above would be greatly appreciated. If more detail is required, please let me know.

Edit

To clarify... the block inside the head of the Master page and the subsequent reference in side a view page will be combined together in to a single resource. So when the context of CompositeResourcePartContext is disposed, all SIX files are combined in to only ONE css file and written out as a single link TAG (or script, css sprite etc)

<link rel="stylesheet" type="text/css" href="/MyMergedStyleSheet.css" />
like image 279
Chris Baxter Avatar asked Nov 02 '10 00:11

Chris Baxter


People also ask

What is MVC HtmlHelper?

HTML Helpers are managed within View to execute HTML content. We can use HTML Helpers to implement a method that returns a string. This tutorial discusses how you can define or create custom HTML Helpers that you can use within your MVC views.


2 Answers

After giving it some more thought (and consulting a colleague) I feel that the best option is to stick with my original plan of not polluting my ASP.NET MVC API with the concept of "partial" resource definitions (works for WebControls, but not as nice with MVC in my opinion). Prior to considering an explicit HtmlHelper extension for this case in my library, I suggested that the issue can be handled by defining a custom extension method as follows:

public static class CustomXpediteExtensions
{
    private static readonly IEnumerable<String> SharedCss = new[]
    {
        "/Styles/SharedStyle1.css",
        "/Styles/SharedStyle2.css",
        "/Styles/SharedStyle3.css"
    };

    public static MvcHtmlString CustomCompositeCssResource(this HtmlHelper htmlHelper, params String[] resources)
    {
        return htmlHelper.CompositeCssResource(SharedCss.Concat(resources));
    }
}

And then simply referencing that custom extension (or constant, etc.) in the view page.

<asp:Content ID="Content2" ContentPlaceHolderID="head" runat="server">
  <%= Html.CustomCompositeCssResource(
        "/Styles/PageStyle5.css",
        "/Styles/PageStyle6.css",
        "/Styles/PageStyle7.css"
      ) %>
</asp:Content>

This will allow you to not repeat yourself when combining shared resources (i.e., ensuring consistency) and ultimately handle the case.

I will leave this open for a while to see if there is any feedback on this; but unless a good case is made for why this is not acceptable, I think it is the answer.

like image 134
Chris Baxter Avatar answered Oct 01 '22 06:10

Chris Baxter


It seems like a great idea, but it might be better served as a part of the build process. You could easily create merged CSS for individual pages using a T4 template, and perhaps a naming convention for adding that CSS reference to your page. Something like:

<%: Html.MergedStyleSheet() %>

could output:

<link rel="stylesheet" type="text/css" href="/Content/ControllerName/ActionName.css" />
like image 45
John Nelson Avatar answered Oct 01 '22 06:10

John Nelson