Search
Categories
Navigation
Twitter Updates

Twitter Updates

    follow me on Twitter

    Entries in visual studio (2)

    Friday
    Oct092009

    Empty ASP.NET MVC 1.0 Project Template

    Empty stadium seats - Photo by: laffy4k (Flickr)The project template that ships with ASP.NET MVC 1.0 is nice when you first start using the framework and want to see how things work together. Unfortunately, it can be annoying once you actually start using the framework for real projects. This is because the first thing you typically need to do is delete all the extra stuff the template creates, but you don’t want in your project.

    After having done this more than a few times, I decided to create my own empty ASP.NET MVC project template with all the stuff I rip out and change already done. This empty MVC template has a few substantive changes:

    • There are no default controllers or views, just folders for their locations.
    • There are no included JavaScript libraries, jQuery or otherwise.
    • All the Web.config settings dealing with ASP.NET Ajax have been removed
    • All the Web.config settings dealing with the profile, role and membership services have been removed
    • The folder structure for images, Javascript and CSS has been changed to Assets/img/, Assets/js/, and Assets/style/, respectively.

    The guiding principle here is that every project tends to be a bit different, so starting from scratch is often easiest. The stock Web.config files have a lot of extra stuff in them that may not be all that relevant for a lot of projects, and I’d rather add stuff back in than have a bunch of unused boilerplate all the time. Plus, I just don’t see much purpose for ASP.NET Ajax at this point in time.

    The image, script and style folder change is just personal preference; I don’t like having Content and Scripts folders like the standard MVC project template does.

    A quick note about testing projects: This template won’t prompt you to create a testing project like the standard MVC template does. This is not because I think unit testing is dumb (quite the contrary) but because I tend to use my own project structure for testing projects as well, so I don’t have a need for it.

    Installation

    I’ve posted my Empty ASP.NET MVC 1.0 project template, if you’re interested in using it.

    If you’ve never installed a custom template before, it’s as easy as copying the zip file to \My Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#\. Alternatively, if you want the project to show up under the Web sub-category you can place the zip file in \My Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#\Web\.

    After copying the file to the correct location, you should see the new project template when you go to create projects within VS:

    proj-template

    Creation

    If you’d like to have a similar project template, but don’t like some of the changes I’ve made, it’s fairly simple to create your own Visual Studio project templates. In fact, all the documentation I used is available on MSDN:

    Additionally, if you’d like to look at the standard ASP.NET MVC project template (MvcWebApplicationProjectTemplatev1.cs.zip) you can find it installed to <VisualStudioInstallDirectory>\Common7\IDE\ProjectTemplates\CSharp\Web\<Locale>\.

    I’m sure I’ll keep tweaking things about my empty MVC project template (I’m already considering deleting the Models directory since I tend to use a separate assembly for them) but I’m happy with it as a first iteration. It’s a pretty simple process to create one, so if you’ve been annoyed at the stock MVC template, it’s worth the minimal time investment.

    This post targets Visual Studio 2008 and ASP.NET MVC 1.0 using C#. The content may not be relevant for other product, framework or language versions.

    Wednesday
    Feb132008

    JS IntelliSense with Namespaces in VS 2008

    When ASP.NET AJAX came out and my interest in the UpdatePanel had waned, I really dug into the client-side library. I'd never gone very deep into JavaScript until then, so the structure of the library was intriguing and, over time, became a pattern that I began adopting in my own work.

    A corner-stone to this structure is partitioning your JavaScript into namespaces (using Type.registerNamespace), which are split up in a manner similar to .NET itself, and also avoid naming conflicts with third-party components and non-global page functions.

    Of course, with my increased adoption of JavaScript, I was excited to hear of JavaScript IntelliSense support in VS2008. I had assumed that namespace support for IntelliSense would work as expected, since so much of the ASP.NET AJAX library uses it and that I would soon be reveling in all the contextual help provided by my diligent use of JavaScript doc comments. After converting my current project to VS2008, I was confused by the seemingly utter lack of IntelliSense when using namespaces. So, as with most things that confuse me, I searched around on the 'net to see if anybody else had solved this problem. To my chagrin, I found a disturbing post stating that a bug had been submitted to Microsoft for this issue, and that the response was, effectively, that the namespace pattern would not be supported in VS2008.

    Dejected, I continued on with my project, having conceded that my namespaced script wouldn't be quite as easy to work with as I had hoped. It wasn't long, however, that I noticed that the namespaces worked properly when they were defined in a different file from the active document, which is the expected behavior as stated in the Microsoft Feedback report. In fact, this is the same functionality that provides us with IntelliSense for the ASP.NET AJAX client-side framework itself.

    Add all of this together and you can, in fact, get JavaScript IntelliSense for script that uses namespaces (through Type.registerNamespace) by doing a few tricks within your application. Read on for more details.

    Step 1: Add a Namespace definition file

    Since any Type.registerNamespace calls in the active document aren't parsed, we need to add a new file to the project for storing namespace registration calls. This file is also the root JS file that will reference the MircrosoftAjax.js file for client-side library IntelliSense support. For the example, we'll refer to this as SampleApp-Namespaces.js:

    /// <reference name="MicrosoftAjax.js" />
    Type.registerNamespace("Coderoni.JsSampleApp.Utility");

    Step 2: Reference this Namespace definition file

    In order to get proper IntelliSense support in the files where we would normally define namespaces and then use them, we now need to reference this namespace definition file. It's important to point out that nothing else in this your existing JavaScript code has to change. The Type.registerNamespace() call does nothing if the namespace already exists, so you can (and should, more later) leave your standard Type.registerNamespace() calls alongside the object definitions they correspond to. Here's what SampleApp-Core.js might look like:

    /// <reference path="~/Scripts/SampleApp-Namespaces.js" />

    /*
    * Coderoni.JsSampleApp.Utility.RandomGenerator
    /*--------------------------------------------------------------------------*/
    Type.registerNamespace("Coderoni.JsSampleApp.Utility");
    Coderoni.JsSampleApp.Utility._RandomGenerator = function()
    {
    /// <summary>
    /// Provides convenience utility methods for generating random values.
    /// </summary>
    Coderoni.JsSampleApp.Utility._RandomGenerator.initializeBase(this);
    }

    Coderoni.JsSampleApp.Utility._RandomGenerator.prototype =
    {
    generateRandomString: function(length)
    {
    /// <summary>
    /// Generates a random string of the specified length.
    /// </summary>
    /// <param name="length" integer="true" optional="false">
    /// Length of the string to generate.
    /// </param>
    /// <returns type="String">
    /// Randomly generated string of the specified length.
    /// </returns>
    var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    var randomString = "";

    for (var i = 0; i < length; i++)
    {
    var randomNum = Math.floor(Math.random() * chars.length);
    randomString += chars.substring(randomNum, randomNum + 1);
    }
    return randomString;
    }
    }
    Coderoni.JsSampleApp.Utility._RandomGenerator.registerClass(
    "Coderoni.JsSampleApp.Utility._RandomGenerator");
    Coderoni.JsSampleApp.Utility.RandomGenerator =
    new Coderoni.JsSampleApp.Utility._RandomGenerator();

    The important parts of this code is the call to registerNamespace() with the same namespace information as that found in SampleApp-Namespaces.js. After making the reference to the namespace file, you should find that your namespaces appear and work as expected in IntelliSense. This is because the parser that analyzes references does realize that registerNamespace() creates objects, and therefore, everything works.

    Step 3: Don't reference the namespace definition

    Of course, we all know that the fewer requests the browser needs to send when loading a page, the better off our users are, so adding a JavaScript file to the application for design-time IntelliSense is not a smart move. Fortunately, the work-around relies on the reference hints you give to Visual Studio in JS comments, so you shouldn't add a script link to the namespace definition file within your application; it's simply not necessary. This is also the reason you leave the duplicate registerNamespace() calls in the SampleApp-Core.js file; these calls are the ones that actually register your namespaces at runtime.

    <asp:ScriptManager runat="server" ID="ScriptManager">
    <Scripts>
    <asp:ScriptReference Path="~/Scripts/SampleApp-Core.js" />
    <asp:ScriptReference Path="~/Scripts/Default-Script.js" />
    </Scripts>
    </asp:ScriptManager>

    Everything also works right if you reference the objects defined in SampleApp-Core.js from a third script file, such as Default-Script.js:

    /// <reference path="~/Scripts/SampleApp-Core.js" />

    function ShowRandomString()
    {
    str = Coderoni.JsSampleApp.Utility.RandomGenerator.generateRandomString(10);
    element = $get("MessageDiv");
    element.innerHTML = str;
    }

    Again, this is because the multiple calls to registerNamespace() do nothing if the namespace already exists.

    Summing Up

    While it's not the prettiest work-around that ever existed, it's relatively painless and allows those of us that have adopted the namespace structure in their JavaScript to enjoy the many benefits of VS-based IntelliSense. Hopefully a future release or update for VS will allow the parsers to work without this extra bit of effort, but until then, at least it's possible with just a bit of extra code and no real impact on your application. Now all those JavaScript doc comments weren't a complete waste of time after all.