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

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
}});
}});
</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:
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.
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.

Related

MVC6 new minification and bundling with Bower/NPM

I started getting up to date with the ASP.NET 5 and MVC 6, and I see a lot of internet posts about Bower VS NPM.
The default started MVC template however uses both, is this required for the taskrunner (gulp) to work or is there another reason?
Second question is about the resource path, in MVC < 6 you could declare a relative path to research the minified/bundled js/css. This way each MVC View would have its own path to its own specific js/css. How can I do this with gulp?
In MVC < 6 the js/css would NOT minify when debug enabled (as default setting), so it remains readable. I see the option to use an if-like statement on the environment variable like
environment names="Development">script path
and another one for production in the view. This seems very cumbersome, is there a simple solution for not minifying in debug instead of having to list all paths twice (one minified and one not)?
Have one version of watch minify your js files and one that doesn't. Either way all of your project paths can just point to the built js file to prevent having to switch back and forth for dev or prod. You would need to break the minify stuff out of the 'scripts' task below and create a task that just does that.
//Concatenate & Minify JS
gulp.task('minscripts', function () {
return gulp.src(config.alljs, { base: 'public/' })
.pipe($.concat('all.js'))
.pipe(gulp.dest('_build'))
.pipe($.rename('all.min.js'))
.pipe($.uglify())
.pipe(gulp.dest(config.build));
});
gulp.task('scripts', function () {
return gulp.src(config.alljs, { base: 'public/' })
.pipe($.concat('all.js'))
.pipe(gulp.dest('_build'))
.pipe($.rename('all.min.js'))
.pipe(gulp.dest(config.build));
});
gulp.task('watchWith', function () {
gulp.watch('public/app/views/*.js', ['lint', 'minscripts']); //<- runs 'scripts' here
gulp.watch('public/css/*.less', ['less']);
});
gulp.task('watchWithout', function () {
gulp.watch('public/app/views/*.js', ['lint', 'scripts']);
gulp.watch('public/css/*.less', ['less']);
});

Using Javascript for Google Maps API from WPF

I am creating an application that interfaces with Google's Maps API v3. My current approach is using a WebBrowser control by WebBrowser.Navigate("Map.html"). This is working correctly at the moment; however, I am also aware of WebBrowser.InvokeScript(). I have seen this used to execute a javascript function, but I would like to have something like the following structure:
APICalls.js - Contains different functions that can be called, or even separated out into a file for each function if necessary.
MapInterface.cs
WebBrowser.InvokeScript("APICalls.js", args) - Or control the javascript variables directly.
I have seen the InvokeScript method used, but none of the examples gave any detail to the source of the function, so I'm not sure if it was calling it from an html file or js file. Is it possible to have a structure like this, or a similarly organized structure, rather than creating an html file with javascript in each one and using Navigate()?
Additionally, are there any easier ways to use Google Maps with WPF. I checked around, but all of the resources I found were at least 2-3 years old, which I believe is older than the newest version of the maps API.
I can't suggest a better way of using Google Maps API with WPF (although I'm sure it exists), but I can try to answer the rest of the question.
First, make sure to enable FEATURE_BROWSER_EMULATION for your WebBrowser app, so Google Maps API recognizes is it as modern HTML5-capable browser.
Then, navigate to your "Map.html" page and let it finish loading. Here's how it can be done using async/await (the code is for the WinForms version of WebBrowser control, but the concept remains the same).
You can have your APICalls.js as a separate local file, but you'd need to create and populate a <script> element for it from C#. You do it once for the session.
Example:
var scriptText = File.ReadAllText("APICalls.js");
dynamic htmlDocument = webBrowser.Document;
var script = htmlDocument.createElement("script");
script.type = "text/javascript";
script.appendChild(htmlDocument.createTextNode(scriptText));
htmlDocument.body.appendChild(script);
Then you can call functions from this script in a few different ways.
For example, your JavaScript entry point function in APICalls.js may look like this:
(function() {
window.callMeFromCsharp = function(arg1, arg2) {
window.alert(arg1 + ", " +arg2);
}
})();
Which you could call from C# like this:
webBrowser.InvokeScript("callMeFromCsharp", "Hello", "World!");
[UPDATE] If you're looking for a bit more modular or object-oriented approach, you can utilize the dynamic feature of C#. Example:
JavaScript:
(function() {
window.apiObject = function() {
return {
property: "I'm a property",
Method1: function(arg) { alert("I'm method 1, " + arg); },
Method2: function() { return "I'm method 2"; }
};
}
})();
C#:
dynamic apiObject = webBrowser.InvokeScript("apiObject");
string property = apiObject.property;
MessageBox.Show(property);
apiObject.Method1("Hello!");
MessageBox.Show(apiObject.Method2());

How to register a client script resource at the bottom of webpage to enhance loading time

I really hate the way Extender controls, Asp.net script controls that emit javascript all at the top of the web page and just was rethinking of any other way to emit it at the bottom similar to what,
ClientScriptManager.RegisterStartupScript. On looking into this post by DanWahlin i think it is possible but i would have to handle all dirty work of seeing of script is included twice and making sure all necessary scripts are included in order. So my question boils down to this
"I am developing custom controls, Extender controls and i want all my scripts emitted to be at bottom of webpage, What options do you suggest and Why"
Note:
These scripts and also css are embedded as web resources
As long as we are talking about MS AJAX Toolkit there is an option in the Toolkit ScriptManager that is called "LoadScriptsBeforeUI". Setting this to "false" would allow you to get your UI loaded before the scripts, if this is your goal.
I am generally wondering why having scripts in the top of a webpage would bother you, for it is a general practice and you see any impact only if your connection is extremely slow.
AFAIK you have to handle the OnRender part of the page.
I was doing something similar but to move the viewstate of the page for SEO thing
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
System.IO.StringWriter stringWriter = new System.IO.StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
base.Render(htmlWriter);
string html = stringWriter.ToString();
int startPoint = -1;
int endPoint = -1;
startPoint = html.IndexOf("<input type=\"hidden\" name=\"__VIEWSTATE\"");
if (startPoint >= 0)
{
endPoint = html.IndexOf("/>", startPoint) + 2;
string viewstateInput = html.Substring(startPoint, endPoint - startPoint);
html = html.Remove(startPoint, endPoint - startPoint);
int FormEndStart = html.IndexOf("</form>") - 1;
if (FormEndStart >= 0)
html = html.Insert(FormEndStart + 1, viewstateInput);
}
}
Maybe you can do the same lokking for script tag. Other way I can thing of is to put a <%=MyVar%> at the end of the page, so you can set it from the code behind, but I guess is too much couplig with the page
Actually speaking you can't with the current implementation of the ajax extender controls. So i managed to rely on client script dependency framework like script.js instead. I did achieve that i wanted.

How to use ASP.NET MVC 3 and Stack Overflow's Markdown

I couldn't find any real sources for this. I'm building a site in ASP.NET MVC 3 and would like to take advantage of the Markdown editor that Stack Overflow uses. Does anybody have a good tutorial?
Where do you download the latest markdown? What language is it written in? Where would I start in integrating this into an MVC 3 project? Even after all the searching and reading I've done I'm still pretty confused.
I came across this site. But this seems outlandishly old and it would seem I would have to learn a little something about CGI and Perl which I have absolutely no experience with. A JavaScript/jQuery version would be splendid.
Update
I noticed this question is getting a fair amount of views so I decided to update it with some helpful references. I managed to get a Markdown editor working nicely on my website, and I wrote a few blogs about it.
MarkdownSharp and Encoded HTML
JQuery WMD Plugin
Finding and implementing the WMD editor
Stackoverflow open sourced their version of Markdown to the world. Its called MarkdownSharp and is written in C#.
Somebody wrote a HtmlHelper here:
http://blog.dantup.com/2011/03/an-asp-net-mvc-htmlhelper-extension-method-for-markdown-using-markdownsharp
If you are looking for how to implement a javascript editor there is an existing question:
Integrate Markitup text editor to ASP.NET MVC project
You are probably looking for MarkdownSharp
Open source C# implementation of Markdown processor, as featured on Stack Overflow.
To integrate it into an MVC app:
In a until or common controller, add the following action method
public ActionResult FormatMarkdown(string markdownText)
{
var md = new MarkdownSharp.Markdown();
string html = md.Transform(markdownText);
return Json(html, JsonRequestBehavior.AllowGet);
}
in your client side view:
#Html.TextArea("mdText", new { rows = 12, cols = 60 })
<div id="mdFormatted"></div>
and client side JS:
$(function () {
var mdText = $("#mdText");
var mdFormatted = $("#mdFormatted");
function setFormatted(data) {
mdFormatted.html(data);
};
mdText.toObservable("keypress")
.Throttle(200)
.Subscribe(function () {
$.getJSON("#VirtualPathUtility.ToAbsolute("~/Util/FormatMarkdown/")", {
markdownText: mdText.val()
}, setFormatted);
})
Download RxJs (from MSDN) and include the following two js files
<script src="#Url.Content("~/Scripts/rx.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/rx.jquery.js")" type="text/javascript"></script>
I know this question is old but I stumbled upon another solution markdowndeep which is very friendly with MVC
It can be installed through nuget PM> Install-Package MarkdownDeep.Full
Markdown in C#
// Create an instance of Markdown
var md = new MarkdownDeep.Markdown();
// Set options
md.ExtraMode = true;
md.SafeMode = false;
string output = md.Transform(input);
Editor
1.Copy the supplied js, css, png and htm files to your server. Depending where you place these files on your server, you might need to update the image urls in the css file.
2.Update your page to reference jQuery, the MarkdownDeep library and the MarkdownDeep css file (again, you might need to change the paths).
<link rel="stylesheet" href="mdd_styles.css"
<script type="text/javascript" src="jQuery-1.4.2.min.js">
<script type="text/javascript" src="MarkdownDeepLib.min.js">
NB: MarkdownDeepLib.min.js is a packaged, minified version of MarkdownDeep.js, MarkdownDeepEditor.js and MarkdownDeepEditorUI.js. For debugging, you can reference these three files instead.
3.Insert the Markdown editor into your page like this:
<div class="mdd_toolbar"></div>
<textarea cols=50 rows=10 class="mdd_editor"></textarea>
<div class="mdd_resizer"></div>
<div class="mdd_preview"></div>
Note: the associated divs are all optional and if missing, the plugin will create them. However... you might experience the page jumping around during load if you do this. ie: it's recommended to explicitly include them.
4.Called the MarkdownDeep jQuery plugin to convert the textarea to a MarkdownEditor
$("textarea.mdd_editor").MarkdownDeep({
help_location: "/Content/mdd_help.html",
disableTabHandling:true
});
Although I really like their product I am not affiliated with the makers of markdowndeep. I just thought they made a good product
This question is old, but I'm just leaving an answer here so that future readers can benefit from it.
I have used MarkdownSharp v1.13, It does NOT sanitize your html output. For example, if you type:
<script type="text/javascript">alert("Hacked");</script>
Into your input field, the output from MarkdownSharp contains the same script. Thus it exposes your website to XSS vulnerability.
Read this from Stackoverflow's article on PageDown:
It should be noted that Markdown is not safe as far as user-entered input goes. Pretty much anything is valid in Markdown, in particular something like <script>doEvil();</script>. This PageDown repository includes the two plugins that Stack Exchange uses to sanitize the user's input; see the description of Markdown.Sanitizer.js below.
So, from other point of view, maybe Markdown was not supposed to sanitize your input in the first place and MarkdownSharp implementation of it just conformed with those principles. I should mention that Stackoverflow does uses MarkdownSharp on their server side.

Generating JavaScript in C# and subsequent testing

We are currently developing an ASP.NET MVC application which makes heavy use of attribute-based metadata to drive the generation of JavaScript.
Below is a sample of the type of methods we are writing:
function string GetJavascript<T>(string javascriptPresentationFunctionName,
string inputId,
T model)
{
return #"function updateFormInputs(value){
$('#" + inputId + #"_SelectedItemState').val(value);
$('#" + inputId + #"_Presentation').val(value);
}
function clearInputs(){
" + helper.ClearHiddenInputs<T>(model) + #"
updateFormInputs('');
}
function handleJson(json){
clearInputs();
" + helper.UpdateHiddenInputsWithJson<T>("json", model) + #"
updateFormInputs(" + javascriptPresentationFunctionName + #"());
" + model.GetCallBackFunctionForJavascript("json") + #"
}";
}
This method generates some boilerplace and hands off to various other methods which return strings. The whole lot is then returned as a string and written to the output.
The question(s) I have are:
1) Is there a nicer way to do this other than using large string blocks?
We've considered using a StringBuilder or the Response Stream but it seems quite 'noisy'. Using string.format starts to become difficult to comprehend.
2) How would you go about unit testing this code? It seems a little amateur just doing a string comparison looking for particular output in the string.
3) What about actually testing the eventual JavaScript output?
Thanks for your input!
We created a library specifically for the purpose of embedding JavaScript in a fluent-like syntax into our C# code, and then made it open source.
Have a look at Adam.JSGenerator.
I typically try to create a separate .js file for most/all of my javascript code. Usually I will need to have common bahvior applied to many elements that are dynamically created by ASP controls or server-side code, so I may not be able to code everything into a .js file.
I've found that the main reason that you want to generate javascript on the server is because you won't know the IDs of elements until the page renders. Therefore, I try to condense that dependency down as much as possibly so that I'm generating as little javascript as possible. For example, in traditional ASP.Net (not MVC) if I were rendering a set of forms such as in the example, each with multiple fields, then I would probably have something in the code behind such as this:
protected void FormRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Control form = e.Item.FindControl("MyForm");
ClientScript.RegisterStartupScript(this.GetType(), "prepareForm_" + form.ClientID, #"prepareForm('" + form.ClientID + "');", true);
}
A separate .js file would include the definition of the prepareForm function, which would be something like this:
// define a formPresenter "class" that encapsulates the behavior for a given form
function formPresenter(formId) {
this.setFirstName = function(value) {
$("#" + formId + "_FirstName").val(value);
}
this.setLastName = function(value) {
$("#" + formId + "_LastName").val(value);
}
// create other functions to handle more complicated logic
// clear fields
this.clearInputs = function() {
this.setFirstName("");
this.setLastName("");
//...
}
// receive Json object
this.handleJson = function(json) {
this.clearInputs();
// populate fields with json object
this.setFirstName(json.FirstName);
this.setLastName(json.LastName);
//...
}
// "constructor" logic
}
function prepareForm(formId) {
// create a new formPresenter object and shove it onto the specified element as the "presenter"
document.getElementById(formId).presenter = new formPresenter(formId);
}
Now almost all of your actual logic is in its own .js file, which should be much easier to maintain. If you need to access the formPresenter object for a given form, then you just need to get a reference to whatever element is referenced by the formId parameter and access the presenter variable:
"document.getElementById(" + form.ClientID + ").presenter.handleJson(json);"
Note: Since I've been using JQuery, I've found less of a need to even include any javascript generated by the server. Typically I can find the elements that I need by looking for a specific CSS class name (or something to that effect) and perform whatever setup/initialization I need.
We're doing a lot of JS generation in our project as well, and we're using StringBuilder to do it.
StringBuilder sb = new StringBuilder();
sb.Append("some javascript stuff")
.Append("some more")
.AppendFormat("formatted stuff {0}", "here");
return sb.ToString();
It's not pretty, but no solution is going to be.
And concerning testing, we don't actually do any unit tests on the generated code. Before release people go and test all the features to make sure they work as expected.
If you don't care about super duper performance you could use a templating language to generate the javascript.
Then for unit testing you would just fill the templates with their appropriate bindings/variables and then run it through a Javascript evaluator like Rhino or whatever the .NET equivalent is to at least test the syntax if not the actual JS code.
Other than that I would seriously question the design of software that is generating Javascript like this. It also looks like you are using JQuery but are referencing the $ directly which may lead to some problems down the line.
If compilers generating Javascript is one thing (ala GWT) but I would separate your client side JS code as much as possible from your .NET code (not to mention your .NET code looks like server side JS talk about confusing).
This in vogue kind of design of separating the client crap from the server is known as SOFEA. I let you google that.

Categories

Resources