开发者

ASP.NET MVC Html Helper Extensions and Rendering Their Required "include"s

I have build a custom Html Helper extension as follows:

public static string DatePicker(this HtmlHelper helper, string name, string value)
{
        return string.Format(@"<script type='text/javascript'>
$(document).ready(function(){{
    $('#{0}').datepicker({{ 
        changeMonth: true, 
        changeYear:true, 
        dateFormat: 'd-M-yy', 
        firstDay: 1, showButtonPanel: 
        true, 
        showWeek: true 
    }});
}});
</开发者_C百科script>
<input type='text' name='{0}' id='{0}' value='{1}'>", name, value);
}

The problem is that this now requires the page to "include" the following:

<script src="/Scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.ui.datepicker.min.js" type="text/javascript"></script>

And a few other items. The questions are as follows:

  1. Is there a serious processing overhead if I were to include these items in EVERY page (like in the Site.Master for example) thus negating the need for the HtmlHelper to organise the "includes" - considering there would end up being about 20 includes for all the different types of jQuery UI widgets used throughout the site.

  2. If the HtmlHelper sorts out the "includes", it will add one every time this DatePicker is used (often there are two on a page) Does anyone have a way of determining whether or not the user has already rendered the same type of control on the page, thus not re-including the same jquery libraries when multiple instances of the DatePicker (for example) are used?


Direct Answer

1) Yes 20 requests for scripts on each page will reduce performance for clients considerably - see Yahoo / Google's docs on web optimisation for more info

Browser Caching helps, but its so easy to do better.

2) Why roll your own solution to dependencies?

There are numerous excellent libraries out there that do this very well already - with advantages?

In depth :

Similar to the suggestion from @Mare , but with I think some decent advantages - I would recommend changing your approach slightly. Refactor !

Consider these core questions :

1) Why write HTML in .cs files?

=> much better to keep your HTML in aspx / ascx (or other view engine) files check out editor and display templates e.g.

Brad Wilson's Intro to templates

i.e. comment from @admsteck above

2) why write Javascript in .cs files?

=> much better to keep your Javascript in .js files

3) Also note - Why use HtmlHelper extension methods when you are not using any of the state information from the HtmlHelper class?

=> For a simple solution why not instead just use a static helper class (not an extension of HtmlHelper) see this answer here

But mainly :

4) If you a concerned about performance, why not minify and combine all your scripts (and CSS while you're at it).

=>Then you can have a single little CSS file and a single JS file for your whole app.

However, 4) then leads to some further questions :

a) How do you debug combined + minified JS

b) How do you work effectively with combined + "minified" CSS?

c) To focus back in on your original request for a clean way to handle dependencies, how do you ensure its clear what code depends on what code, and how do you ensure code is requested only once when its needed?

I have found that this open source library Client Dependency Framework an excellent addition to my toolbox for MVC, when you debug you get individual files, when you run you get combined files (for massive performance gains in production).

It also provides an excellent way for your UI components to "register" their dependencies, so its clear to developers what is needed where, and so the correct js + the correct css gets down to the client (and only gets requested once) !


Maybe something of these code pieces will help you to get an idea or two about it:

private static readonly SortedList<int, string> _registeredScriptIncludes = new SortedList<int, string>();

    public static void RegisterScriptInclude(this HtmlHelper htmlhelper, string script)
    {
        if (!_registeredScriptIncludes.ContainsValue(script))
        {
            _registeredScriptIncludes.Add(_registeredScriptIncludes.Count, script);
        }
    }

    public static string RenderScript(this HtmlHelper htmlhelper, string script)
    {
        var scripts = new StringBuilder();
        scripts.AppendLine("<script src='" + script + "' type='text/javascript'></script>");
        return scripts.ToString();
    }

    public static string RenderScripts(this HtmlHelper htmlhelper)
    {
        var scripts = new StringBuilder();
        scripts.AppendLine("<!-- Rendering registered script includes -->");
        foreach (string script in _registeredScriptIncludes.Values)
        {
            scripts.AppendLine("<script src='" + script + "' type='text/javascript'></script>");
        }
        return scripts.ToString();
    }


To answer number 2, you could do something like the following

<script type='text/javascript'>
    if (typeof jQuery == 'undefined') // test to see if the jQuery function is defined
        document.write("<script type='text/javascript' src='jquery.js'></script>");
</script>


Regarding:

1: no processing overhead at all, and no significant size overhead (as in: the files are normally loaded only first time by the browser). I normally would go this approach.

2: no idea, sorry ;) Someone else will pick that up, i think.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜