ASP.NET Directive Convention for Declaring Client-Side Includes
I am loading .aspx and 开发者_如何学Python.ascx files as StreamReader
.
I want each file to register it's javascript and stylesheet dependencies in some declaration like a <%@ ClientDependency path="~/Scripts/jquery-1.4.1.min.js" %>
.
Is there an existing convention for doing such a thing? I don't need an implementation, but I don't want to create a new syntax if there is already a way to do it.
Also, what are the guidelines for custom <%@
blocks in ASP.NET?
Also, please retag this question if you can think of a more appropriate description.
Have you considered Google Loader or something like this: Enabling the ASP.NET Ajax script loader for your own scripts
Basically...
Here's what I'm doing in my current MVC project:
Using Telerik's Web Asset Manager to register all of my common scripts and CSS in the Master Page that I know will be used on every page (There's an open source download, if like me, you didn't know).
I encapsulate all JS functionality (beyond a few lines) into functions stored in appropriate external JS files.
I encapsulate all of my extended UI functionality into HTML Helpers. They then use the StyleSheetRegistrar and ScriptsRegistrars to dynamically load any extra CSS or JS that are required for that particular helper. And rely on the Telerik manager not to load them more than once.
If I ever use inline styles, I specify the style tag manually inside the Helper method via the htmlAttributes object, but its rare.
In order to call my javascript functionality needed on the HTML element, I use ScriptRegistrar().OnDocumentReady()'s string overload to specify a javascript function to call for that element.
I've also defined a simple extension method for ScriptRegistrarBuilder in my HtmlHelpers class that allows me to provide a parameter list of arguments to pass to my javascript method call, when calling OnDocumentReady(), without a heap of string concatenation.
public static void OnDocumentReady(this ScriptRegistrarBuilder builder, string format, params string[] args) { builder.OnDocumentReady(String.Format(format, args)); }
And of course, I render all the JS at the bottom of the Master page.
You don't avoid all uses of inline JS here, but it keeps it pretty thin, if you do it right. Honestly, I can't really think of another way that wouldn't start to get pretty over complicated.
In the end I think you get something pretty flexible which at the same time allows you to be fairly specific about loading what you do and do not need on any given page.
The only caveat I've found with this method is in terms of CSS. In order to be able to dynamically load CSS files into the page when a helper needs them, I've had to render all the CSS includes at the bottom of the Master page, past any possible calls to add new files.
Haven't found a way around this yet, unfortunately.
A small example
Perhaps needlessly detailed for you... but this way someone searching can hopefully find a useful solution too! :)
In the master page:
<%
Html.Telerik().StyleSheetRegistrar().DefaultGroup(styles => styles
.Add("~/Content/Site.css")
.Add("~/Content/core.css")
);
Html.Telerik().ScriptsRegistrar().DefaultGroup(scripts => scripts
.Add("~/Scripts/common.js")
.Combine(true)
.Compress(true)
.CacheDurationInDays(30)
);
%>
Then somewhere just above the body closing tag:
<%:
Html.Telerik().ScriptsRegistrar().Render();
Html.Telerik().StyleSheetsRegistrar().Render();
%>
In your HTML helper:
public static MvcHtmlString AutoCompleteComboListFor<TModel, TProperty>(this HtmlHelper<TModel> Helper, Expression<Func<TModel, TProperty>> expression,
SelectList List, string DataSource)
{
MvcHtmlString dropDown = SelectExtensions.DropDownListFor<TModel, TProperty>(Helper, expression, List);
string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
string id = Helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName);
//Do whatever you want
helper.Telerik().ScriptRegistrar().DefaultGroup(scripts => scripts
.Add("~/Scripts/extended.js")
);
helper.Telerik().StyleSheetRegistrar().DefaultGroup(styles => styles
.Add("~/Content/extended.css")
);
helper.Telerik().ScriptRegistrar().OnDocumentReady(@"MyExtendedFunction('{0}');", id);
return dropDown;
}
Simply calling that helper (or any other) will end in a tidy block at the end of the page containing all JS code, files and CSS files.
<link type="text/css" href="/Content/Site.css" rel="stylesheet"/>
<script type="text/javascript" src="/asset.axd?id=kAAAAB-LCAAAAAAABADsvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee--997o7nU4n99__P1xmZAFs9s5K2smeIYCqyB8_fnwfPyJ-8Uezjx597xd_tPro0Uevp3WxapuPRh-d82dL-uynf9E6r6-3d8f79N9P47vqo0c7v2Qk3-bv2nw5y2f2m91f8v1f8v3RR9OWvmzp27s_nV1mDcOlBpf06d7O7s743nj33u4BfTKl3u99ep9--ehRW6_zX_L_BAAA___9S_3qkAAAAA%3d%3d"></script>
<script type="text/javascript">
//<![CDATA[
jQuery(document).ready(function(){
myFunction('Foo');});
//]]>
</script>
There is no existing convention for registering client includes with a directive. My solution was to create a custom server control instead and use the existing TemplateParser
functionality to get the include data (which ended up being preferable to loading the file as a stream and parsing it myself).
精彩评论