Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

October 09 2013

17:30

Maintainable Automated UI Tests

A few years ago I was very skeptical about automated UI testing and this skepticism was born out of a few failed attempts. I would write some automated UI tests for desktop or web applications and a few weeks later I would rip them out of the codebase because the cost of maintaining them was too high. So I thought that UI testing was hard and that, while it provided a lot of benefit, it was best to keep it to a minimum and only test the most complex workflows in a system through UI testing and leave the rest to unit tests. I remember telling my team about Mike Cohn’s testing pyramid, and that in a typical system over 70% of the tests should be unit tests, around 5% UI tests and the rest integration tests.

So I thought that UI testing was hard and that, while it provided a lot of benefit, it was best to keep it to a minimum…

I was wrong! Sure, UI testing can be hard. It takes a fair bit of time to write UI tests properly. They are much slower and more brittle than unit tests because they cross class and process boundaries, they hit the browser, they involve UI elements (e.g. HTML, JavaScript) which are constantly changing, they hit the database, file system and potentially network services. If any of these moving parts don’t play nicely you have a broken test; but that’s also the beauty of UI tests: they test your system end-to-end. No other test gives you as much or as thorough coverage. Automated UI tests, if done right, could be the best elements in your regression suite.

So in the past few projects my UI tests have formed over 80% of my tests! I should also mention that these projects have mostly been CRUD applications with not much business logic and let’s face it – the vast majority of software projects fall into this category. The business logic should still be unit tested; but the rest of the application can be thoroughly tested through UI automation.


UI Testing Gone Wrong

I would like to touch on what I did wrong, which also seems to be very typical amongst developers and testers starting with UI automation.

So what goes wrong and why? A lot of teams start UI automation with screen recorders. If you are doing web automation with Selenium you have most likely used Selenium IDE. From the Selenium IDE home page:

The Selenium-IDE (Integrated Development Environment) is the tool you use to develop your Selenium test cases.

This is actually one of the reasons UI testing turns into a horrible experience: you download and fire up a screen recorder and navigate to your website and go click, click, type, click, type, tab, type, tab, type, click and assert. Then you replay the recording and it works. Sweet!! So you export the actions as a test script, put it into your code, wrap it in a test and execute the test and see the browser come alive before your eyes and your tests run very smoothly. You get very excited, share your findings with your colleagues and show it off to your boss and they get very excited and go: “Automate ALL THE THINGS

A week later and you have 10 automated UI tests and everything seems great. Then the business asks you to replace the username with email address as it has caused some confusion amongst users, and so you do. Then like any other great programmer you run your UI test suite, only to find 90% of your tests are broken because for each test you are logging the user in with username and the field name has changed and it takes you two hours to replace all the references to username in your tests with email and to get the tests green again. The same thing happens over and over again and at some point you find yourself spending hours a day fixing broken tests: tests that didn’t break because something went wrong with your code; but because you changed a field name in your database/model or you restructured your page slightly. A few weeks later you stop running your tests because of this huge maintenance cost, and you conclude that UI testing sucks.

You should NOT use Selenium IDE or any other screen recorder to develop your test cases. That said, it’s not the screen recorder itself that leads to a brittle test suite; it’s the code they generate that has inherent maintainability issues. Many developers still end up with a brittle UI test suite even without using screen recorders just because their tests exhibit the same attributes.

All the tests in this article are written against the Mvc Music Store website. The website as is has some issues that makes UI testing rather hard so I ported the code and fixed the issues. You can find the actual code I am writing these tests against on the GitHub repo for this article here

So what does a brittle test look like? It looks something like this:

class BrittleTest
{
    [Test]
    public void Can_buy_an_Album_when_registered()
    {
        var driver = Host.Instance.Application.Browser;
        driver.Navigate().GoToUrl(driver.Url);
        driver.FindElement(By.LinkText("Admin")).Click();
        driver.FindElement(By.LinkText("Register")).Click();
        driver.FindElement(By.Id("UserName")).Clear();
        driver.FindElement(By.Id("UserName")).SendKeys("HJSimpson");
        driver.FindElement(By.Id("Password")).Clear();
        driver.FindElement(By.Id("Password")).SendKeys("!2345Qwert");
        driver.FindElement(By.Id("ConfirmPassword")).Clear();
        driver.FindElement(By.Id("ConfirmPassword")).SendKeys("!2345Qwert");
        driver.FindElement(By.CssSelector("input[type=\"submit\"]")).Click();
        driver.FindElement(By.LinkText("Disco")).Click();
        driver.FindElement(By.CssSelector("img[alt=\"Le Freak\"]")).Click();
        driver.FindElement(By.LinkText("Add to cart")).Click();
        driver.FindElement(By.LinkText("Checkout >>")).Click();
        driver.FindElement(By.Id("FirstName")).Clear();
        driver.FindElement(By.Id("FirstName")).SendKeys("Homer");
        driver.FindElement(By.Id("LastName")).Clear();
        driver.FindElement(By.Id("LastName")).SendKeys("Simpson");
        driver.FindElement(By.Id("Address")).Clear();
        driver.FindElement(By.Id("Address")).SendKeys("742 Evergreen Terrace");
        driver.FindElement(By.Id("City")).Clear();
        driver.FindElement(By.Id("City")).SendKeys("Springfield");
        driver.FindElement(By.Id("State")).Clear();
        driver.FindElement(By.Id("State")).SendKeys("Kentucky");
        driver.FindElement(By.Id("PostalCode")).Clear();
        driver.FindElement(By.Id("PostalCode")).SendKeys("123456");
        driver.FindElement(By.Id("Country")).Clear();
        driver.FindElement(By.Id("Country")).SendKeys("United States");
        driver.FindElement(By.Id("Phone")).Clear();
        driver.FindElement(By.Id("Phone")).SendKeys("2341231241");
        driver.FindElement(By.Id("Email")).Clear();
        driver.FindElement(By.Id("Email")).SendKeys("chunkylover53@aol.com");
        driver.FindElement(By.Id("PromoCode")).Clear();
        driver.FindElement(By.Id("PromoCode")).SendKeys("FREE");
        driver.FindElement(By.CssSelector("input[type=\"submit\"]")).Click();

        Assert.IsTrue(driver.PageSource.Contains("Checkout Complete"));
    }
}

You can find the BrittleTest class here.

Host is a static class, with a single static property: Instance, which upon instantiation fires up IIS Express on the website under test and binds Firefox WebDriver to the browser instance. When the test is finished, it then closes the browser and IIS Express automatically.

This test fires up a web browser, goes to the home page of the Mvc Music Store website, registers a new user, browses to an album, adds it to the cart, and checks out.

One might argue this test is doing too much and that’s why it’s brittle; but the size of this test is not the reason it’s brittle – it’s how it’s written that makes it a nightmare to maintain.

There are different schools of thought on UI testing and how much each test should cover. Some believe this test is doing too much and some think a test should cover a real scenario, end to end, and consider this a perfect test (maintainability aside).

So what is wrong with this test?

  • This is procedural code. One of the main issues of this style of coding is readability, or lack thereof. If you want to change the test, or if it breaks because one of the involved pages has changed, you will have a hard time figuring out what to change and to draw a line between functionality sections; because it’s all a big pile of code where we get the ‘driver’ to find an element on the page and to do something with it. No modularity.
  • This one test by itself might not have much duplication but a few more tests like this and you will have a lot of duplicated selector and logic to interact with web pages from different tests. For example By.Id("UserName") selector will be duplicated in all tests that require registration, and driver.FindElement(By.Id("UserName")).Clear() and driver.FindElement(By.Id("UserName")).SendKeys("") are duplicated anywhere you want to interact with UserName textbox. Then there is the whole registration form, and checkout form etc. that will be repeated in all tests needing to interact with them! Duplicated code leads to maintainability nightmares.
  • There is a lot of magic strings everywhere, which again is a maintainability issue.

Test Code Is Code!

There are also patterns that allow you to write more maintainable UI tests.

Much like your actual code, you are going to have to maintain your tests. So give them the same treatment.

What is it about tests that makes us think we can forego quality in them? If anything, a bad test suite in my opinion is a lot harder to maintain than bad code. I have had bad pieces of working code in production for years which never broke and I never had to touch them. Sure it was ugly and hard to read and maintain but it worked and it didn’t need change so the real maintenance cost was zero. The situation is not quite the same for bad tests though: because bad tests are going to break and fixing them is going to be hard. I cannot count the number of times I have seen developers avoid testing because they think writing tests is a huge waste of time because it takes too much time to maintain.

Test code is code: Do you apply SRP on your code? Then you should apply it on your tests too. Is your code DRY? Then DRY up your tests too. If you don’t write good tests (UI or otherwise) you will waste a lot of time maintaining them.

There are also patterns that allow you to write more maintainable UI tests. These patterns are platform agnostic: I have used these very same ideas and patterns to write UI tests for WPF applications and web applications written in ASP.Net and Ruby on Rails. So regardless of your technology stack you should be able to make your UI tests a lot more maintainable by following a few simple steps.

Introducing the Page Object Pattern

A lot of the above mentioned issues are rooted in the procedural nature of the test script and the solution is easy: Object Orientation.

Page Object is a pattern used to apply object orientation to UI tests. From the Selenium wiki:

Within your web app’s UI there are areas that your tests interact with. A Page Object simply models these as objects within the test code. This reduces the amount of duplicated code and means that if the UI changes, the fix need only be applied in one place.

The idea is that for each page in your application/website you want to create one Page Object. Page Objects are basically the UI automation equivalent of your web pages.

I have gone ahead and refactored the logic and interactions out of the BrittleTest into a few page objects and created a new test that uses them instead of hitting the web driver directly. You can find the new test here. The code is copied here for your reference:

public class TestWithPageObject
{
    [Test]
    public void Can_buy_an_Album_when_registered()
    {
        var registerPage = HomePage.Initiate()
            .GoToAdminForAnonymousUser()
            .GoToRegisterPage();

        registerPage.Username = "HJSimpson";
        registerPage.Email = "chunkylover53@aol.com";
        registerPage.Password = "!2345Qwert";
        registerPage.ConfirmPassword = "!2345Qwert";

        var shippingPage = registerPage
            .SubmitRegistration()
            .SelectGenreByName("Disco")
            .SelectAlbumByName("Le Freak")
            .AddToCart()
            .Checkout();

        shippingPage.FirstName = "Homer";
        shippingPage.LastName = "Simpson";
        shippingPage.Address = "742 Evergreen Terrace";
        shippingPage.City = "Springfield";
        shippingPage.State = "Kentucky";
        shippingPage.PostalCode = "123456";
        shippingPage.Country = "United States";
        shippingPage.Phone = "2341231241";
        shippingPage.Email = "chunkylover53@aol.com";
        shippingPage.PromoCode = "FREE";
        var orderPage = shippingPage.SubmitOrder();
        Assert.AreEqual(orderPage.Title, "Checkout Complete");
    }
}

Admittedly, the test body hasn’t decreased much in size and in fact I had to create seven new classes to support this test. Despite the more lines of code required, we just fixed a lot of issues the original brittle test had (more on this further down). For now, let’s dive a bit deeper into the page object pattern and what we did here.

With the Page Object pattern you typically create a page object class per web page under test where the class models and encapsulates interactions with the page. So a textbox in your web page becomes a string property on the Page Object and to fill that textbox you just set that text property to the desired value, instead of:

driver.FindElement(By.Id("Email")).Clear();
driver.FindElement(By.Id("Email")).SendKeys("chunkylover53@aol.com");

we can write:

registerPage.Email = "chunkylover53@aol.com";

where registerPage is an instance of the RegisterPage class. A checkbox on the page becomes a bool property on the Page Object and ticking and unticking the checkbox is just a matter of setting that boolean property to true or false. Likewise, a link on the web page becomes a method on the Page Object and clicking the link turns into calling the method on the Page Object. So instead of:

driver.FindElement(By.LinkText("Admin")).Click();

we can write:

homepage.GoToAdminForAnonymousUser();

In fact, any action on our web page becomes a method in our page object and in response to taking that action (i.e. calling the method on the page object) you get an instance of another page object back that points at the web page you just navigated to by taking the action (e.g. submitting a form or clicking a link). This way you can easily chain your view interactions in your test script:

var shippingPage = registerPage
            .SubmitRegistration()
            .SelectGenreByName("Disco")
            .SelectAlbumByName("Le Freak")
            .AddToCart()
            .Checkout();

Here, after registering the user I get taken to the home page (an instance of its page object is returned by SubmitRegistration method). So on the HomePage instance I call SelectGenreByName which clicks on a ‘Disco’ link on the page which returns an instance of AlbumBrowsePage and then on that page I call SelectAlbumByName which clicks on the ‘Le Freak’ album and returns an instance of AlbumDetailsPage and so on and so forth.

I admit it: it is a lot of classes for what used to be no class at all; but we gained a lot of benefits from this practice. Firstly the code is no longer procedural. We have a well contained testing model where each object provides nice encapsulation of interaction with a page. So for example if something changes in your registration logic the only place you have to change is your RegisterPage class instead of having to go through your entire test suite and change every single interaction with the registration view. This modularity also provides for nice reusability: you can reuse your ShoppingCartPage everywhere you need to interact with the shopping cart. So in a simple practice of moving from procedural to object oriented test code we almost eliminated three of the four issues with the initial brittle test which were procedural code, and logic and selector duplication. We still have a little bit of duplication though which we will fix shortly.

How did we actually implement those page objects? A page object in its root is nothing but a wrapper around the interactions you have with the page. Here I just extracted UI interactions our of the brittle tests and put them into their own page objects. For example the registration logic was extracted into its own class called RegisterPage that looked like this:

public class RegisterPage : Page
{
    public HomePage SubmitRegistration()
    {
        return NavigateTo<HomePage>(By.CssSelector("input[type='submit']"));
    }

    public string Username          { set { Execute(By.Name("UserName"), e => { e.Clear(); e.SendKeys(value);}); } }
    public string Email             { set { Execute(By.Name("Email"), e => { e.Clear(); e.SendKeys(value);}); } }
    public string ConfirmPassword   { set { Execute(By.Name("ConfirmPassword"), e => { e.Clear(); e.SendKeys(value);}); } }
    public string Password          { set { Execute(By.Name("Password"), e => { e.Clear(); e.SendKeys(value);}); } }
}

I have created a Page superclass that takes care of a few things, like NavigateTo which helps navigate to a new page by taking an action and Execute that executes some actions on an element. The Page class looked like:

public class Page
{
    protected RemoteWebDriver WebDriver
    {
        get { return Host.Instance.WebDriver; }
    }

    public string Title { get { return WebDriver.Title; }}

    public TPage NavigateTo<TPage>(By by) where TPage:Page, new()
    {
        WebDriver.FindElement(by).Click();
        return Activator.CreateInstance<TPage>();
    }

    public void Execute(By by, Action<IWebElement> action)
    {
        var element = WebDriver.FindElement(by);
        action(element);
    }
}

In the BrittleTest, to interact with an element we did FindElement once per action. The Execute method, apart from abstracting web driver’s interaction, has an added benefit that allows selecting an element, which could be an expensive action, once and taking multiple actions on it:

driver.FindElement(By.Id("Password")).Clear();
driver.FindElement(By.Id("Password")).SendKeys("!2345Qwert");

was replaced with:

Execute(By.Name("Password"), e => { e.Clear(); e.SendKeys("!2345Qwert");})

Taking a second look at the RegisterPage page object above we still have a bit of duplication in there. Test code is code and we don’t want duplication in our code; so let’s refactor that. We can extract the code required to fill in a textbox into a method on the Page class and just call that from page objects. The method could be implemented as:

public void SetText(string elementName, string newText)
{
    Execute(By.Name(elementName), e =>
        {
            e.Clear();
            e.SendKeys(newText);
        } );
}

And now the properties on RegisterPage can be shrunk to:

public string Username { set { SetText("UserName", value); } }

You could also make a fluent API for it to make the setter read better (e.g. Fill("UserName").With(value)) but I’ll leave that to you.

We’re not doing anything extraordinary here. Just simple refactoring on our test code like we’ve always done for our, errrr, “other” code!!

You can see the complete code for Page and RegisterPage classes here and here.

Strongly Typed Page Object

We resolved procedural issues with the brittle test which made the test more readable, modular, DRYer and effectively maintainable. There is one last issue we didn’t fix: there are still a lot of magic strings everywhere. Not quite a nightmare but still an issue we could fix. Enter strongly typed Page Objects!

This approach is practical if you’re using an MV* framework for your UI. In our case we are using ASP.Net MVC.

Let’s take another look at the RegisterPage:

public class RegisterPage : Page
{
    public HomePage SubmitRegistration()
    {
        return NavigateTo<HomePage>(By.CssSelector("input[type='submit']"));
    }

    public string Username          { set { SetText("UserName", value); } }
    public string Email             { set { SetText("Email", value); } }
    public string ConfirmPassword   { set { SetText("ConfirmPassword", value); } }
    public string Password          { set { SetText("Password", value); } }
}

This page models the Register view in our web app (just copying the top bit here for your convenience):

@model MvcMusicStore.Models.RegisterModel

@{
    ViewBag.Title = "Register";
}

Hmmm, what’s that RegisterModel there? It’s the View Model for the page: the M in the MVC. Here is the code (I removed the attributes to reduce the noise):

public class RegisterModel
{
    public string UserName { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public string ConfirmPassword { get; set; }
}

That looks very familiar, doesn’t it? It has the same properties as the RegisterPage class which is not surprising considering RegisterPage was created based on this view and view model. Let’s see if we can take advantage of view models to simplify our page objects.

I have created a new Page superclass; but a generic one. You can see the code here:

public class Page<TViewModel> : Page where TViewModel: class, new()
{
    public void FillWith(TViewModel viewModel, IDictionary<Type, Func<object, string>> propertyTypeHandling = null)
    {   
      // removed for brevity
    }
}

The Page<TViewModel> class subclasses the old Page class and provides all its functionality; but it also has one extra method called FillWith which fills in the page with provided view model instance! So now my RegisterPage class looks like:

public class RegisterPage : Page<RegisterModel>
{
    public HomePage CreateValidUser(RegisterModel model)
    {
        FillWith(model);
        return NavigateTo<HomePage>(By.CssSelector("input[type='submit']"));
    }
}

I duplicated all page objects to show both variations and also to make the codebase easier to follow for you; but in reality you will need one class for each page object.

After converting my page objects to generic ones now the test looks like:

public class StronglyTypedPageObjectWithComponent
{
    [Test]
    public void Can_buy_an_Album_when_registered()
    {
        var orderedPage = HomePage.Initiate()
            .GoToAdminForAnonymousUser()
            .GoToRegisterPage()
            .CreateValidUser(ObjectMother.CreateRegisterModel())
            .SelectGenreByName("Disco")
            .SelectAlbumByName("Le Freak")
            .AddAlbumToCart()
            .Checkout()
            .SubmitShippingInfo(ObjectMother.CreateShippingInfo(), "Free");

        Assert.AreEqual("Checkout Complete", orderedPage.Title);
    }
}

That’s it – the entire test! A lot more readable, DRY and maintainable, isn’t it?

The ObjectMother class that I am using in the test is an Object Mother that provides test data (code can be found here), nothing fancy:

public class ObjectMother
{
    public static Order CreateShippingInfo()
    {
        var shippingInfo = new Order
        {
            FirstName = "Homer",
            LastName = "Simpson",
            Address = "742 Evergreen Terrace",
            City = "Springfield",
            State = "Kentucky",
            PostalCode = "123456",
            Country = "United States",
            Phone = "2341231241",
            Email = "chunkylover53@aol.com"
        };

        return shippingInfo;
    }

    public static RegisterModel CreateRegisterModel()
    {
        var model = new RegisterModel
        {
            UserName = "HJSimpson",
            Email = "chunkylover53@aol.com",
            Password = "!2345Qwert",
            ConfirmPassword = "!2345Qwert"
        };

        return model;
    }
}

Don’t Stop at the Page Object

Some web pages are very big and complex. Earlier I said test code is code and we should treat it as such. We normally break big and complex web pages into smaller and, in some cases, reusable (partial) components. This allows us to compose a web page from smaller, more manageable components. We should do the same for our tests. To do this we can use Page Components.

A Page Component is pretty much like a Page Object: it’s a class that encapsulates interaction with some elements on a page. The difference is that it interacts with a small part of a web page: it models a user control or a partial view, if you will. A good example for a page component is a menu bar. A menu bar usually appears on all pages of a web application. You don’t really want to keep repeating the code required to interact with the menu in every single page object. Instead you can create a menu page component and use it from your page objects. You could also use page components to deal with grids of data on your pages, and to take it a step further the grid page component itself could be composed of grid row page components. In the case of Mvc Music Store we could have a TopMenuComponent and a SideMenuComponent and use them from our HomePage.

Like in your web application, you could also create a, say, LayoutPage page object which models your layout/master page and use that as a superclass for all your other page objects. The layout page would then be composed of menu page components so all pages can hit the menus. I guess a good rule of thumb would be to have a page component per partial view, a layout page object per layout and a page object per web page. That way you know your test code is as granualar and well composed as your code.

Some Frameworks for UI Testing

What I showed above was a very simple and contrived sample with a few supporting classes as infrastructure for tests. In reality the requirements for UI testing are a lot more complex than that: there are complex controls and interactions, you have to write to and read from your pages, you have to deal with network latencies and have control over AJAX and other Javascript interactions, need to fire off different browsers and so on which I didn’t explain in this article. Although it’s possible to code around all these, using some frameworks could save you a lot of time. Here are the frameworks that I highly recommend:

Frameworks for .Net:

  • Seleno is an open source project from TestStack which helps you write automated UI tests with Selenium. It focuses on the use of Page Objects and Page Components and by reading from and writing to web pages using strongly typed view models. If you liked what I did in this article, then you will also like Seleno as most of the code shown here was borrowed from the Seleno codebase.
  • White is an open source framework from TestStack for automating rich client applications based on Win32, WinForms, WPF, Silverlight and SWT (Java) platforms.

Disclosure: I am a co-founder and a member of the development team in the TestStack organization.

Frameworks for Ruby:

  • Capybara is an acceptance test framework for web applications that helps you test web applications by simulating how a real user would interact with your app.
  • Poltergeist is a driver for Capybara. It allows you to run your Capybara tests on a headless WebKit browser, provided by PhantomJS.
  • page-object (I haven’t personally used this gem) is a simple gem that assists in creating flexible page objects for testing browser based applications. The goal is to facilitate creating abstraction layers in your tests to decouple the tests from the item they are testing and to provide a simple interface to the elements on a page. It works with both watir-webdriver and selenium-webdriver.

Conclusion

We started with a typical UI automation experience, explained why UI testing fails, provided an example of a brittle test and discussed its issues and resolved them using a few ideas and patterns.

If you want to take one point from this article it should be: Test Code Is Code. If you think about it, all I did in this article was to apply the good coding and object oriented practices you already know to a UI test.

There is still a lot to learn about UI testing and I will try to discuss some of the more advanced tips in a future article.

Happy Testing!

August 07 2013

18:55

Understanding Cross-Site Request Forgery in .NET

You can only produce secure web applications by taking security into account, from the start. This requires thinking of the potential ways someone could attack your site as you create each page, form, and action. It also requires understanding the most common types of security problems and how to address them.

The most common type of security hole in a webpage allows an attacker to execute commands on behalf of a user, but unknown to the user. The cross-site request forgery attack exploits the trust a website has already established with a user’s web browser.

In this tutorial, we’ll discuss what a cross-site request forgery attack is and how it’s executed. Then we’ll build a simple ASP.NET MVC application that is vulnerable to this attack and fix the application to prevent it from happening again.


What Is Cross-Site Request Forgery?

The cross-site request forgery attack first assumes that the victim has already authenticated on a target website, such as a banking site, Paypal, or other site to be attacked. This authentication must be stored in a way so that if the user leaves the site and returns, they are still seen as logged in by the target website. The attacker must then get the victim to access a page or link that will execute a request or post to the target website. If the attack works, then the target website will see a request coming from the victim and execute the request as that user. This, in effect, lets the attacker execute any action desired on the targeted website as the victim. The potential result could transfer money, reset a password, or change an email address at the targeted website.

How the Attack Works

The act of getting the victim to use a link does not require them clicking on a link. A simple image link could be enough:

<img src="http://www.examplebank.com/movemoney.aspx?from=myaccount&to=youraccount&amount=1000.00" width="1" height="1" />

Including a link such as this on an otherwise seemingly innocuous forum post, blog comment, or social media site could catch a user unaware. More complex examples use JavaScript to build a complete HTTP post request and submit it to the target website.


Building a Vulnerable Web Application in ASP.NET MVC

Let’s create a simple ASP.NET MVC application and leave it vulnerable to this attack. I’ll be using Visual Studio 2012 for these examples, but this will also work in Visual Studio 2010 or Visual Web Developer 2010 will work if you’ve installed support for MVC 4 which can be downloaded and installed from Microsoft.

new-db-column

Begin by creating a new project and choose to use the Internet Project template. Either View Engine will work, but here I’ll be using the ASPX view engine.

We’ll add one field to the UserProfile table to store an email address. Under Server Explorer expand Data Connections. You should see the Default Connection created with the information for the logins and memberships. Right click on the UserProfile table and click Open Table Definition. On the blank line under UserName table, we’ll add a new column for the email. Name the column emailaddress, give it the type nvarchar(MAX), and check the Allow Nulls option. Now click Update to save the new version of the table.

This gives us a basic template of a web application, with login support, very similar to what many writers would start out with trying to create an application. If you run the app now, you will see it displays and is functional. Press F5 or use DEBUG -> Start Debugging from the menu to bring up the website.

default-web-page

Let’s create a test account that we can use for this example. Click on the Register link and create an account with any username and password that you’d like. Here I’m going to use an account called testuser. After creation, you’ll see that I’m now logged in as testuser. After you’ve done this, exit and let’s add a page to this application to allow the user to change their email.

default-register

Before we create that page to change the email address, we first need to make one change to the application so that the code is aware of the new column that we just added. Open the AccountModels.cs file under the Models folder and update the UserProfile class to match the following. This tells the class about our new column where we’ll store the email address for the account.

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string EmailAddress { get; set; }
}

Open the AccountController.cs file. After the RemoveExternalLogins function add the following code to create a new action. This will get the current email for the logged in user and pass it to the view for the action.

public ActionResult ChangeEmail()
    {
        // Get the logged in user
        string username = WebSecurity.CurrentUserName;
        string currentEmail;

        using (UsersContext db = new UsersContext())
        {
            UserProfile user = db.UserProfiles.FirstOrDefault(u => u.UserName.ToLower() == username);
            currentEmail = user.EmailAddress;
        }

        return View(currentEmail);
    }

We also need to add the corresponding view for this action. This should be a file named ChangeEmail.aspx under the Views\Account folder:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<string>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Change Email Address
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<hr>
<h2>Change Email Address</h2>

<p>Current Email Address: <%= Model ?? "<i>No Current Email</i>" %></p>

<% using(Html.BeginForm()) { %>
    <input type="text" name="newemail" />
    <input type="submit" value="Change Email" />
<% } %>

</asp:Content>

<asp:Content ID="Content3" ContentPlaceHolderID="FeaturedContent" runat="server">
</asp:Content>

<asp:Content ID="Content4" ContentPlaceHolderID="ScriptsSection" runat="server">
</asp:Content>

This gives us a new page we can use to change the email address for the currently logged in user.

change-email-page

If we run this page and go to the /Account/ChangeEmail action, we now see we currently do not have an email. But we do have a text box and a button that we can use to correct that. First though, we need to create the action which will execute, when the form on this page is submitted.

[HttpPost]
public ActionResult ChangeEmail(ChangeEmailModel model)
{
    string username = WebSecurity.CurrentUserName;

    using (UsersContext db = new UsersContext())
    {
       UserProfile user = db.UserProfiles.FirstOrDefault(u => u.UserName.ToLower() == username);
       user.EmailAddress = model.NewEmail;
       db.SaveChanges();
    }

    // And to verify change, get the email from the profile
    ChangeEmailModel newModel = new ChangeEmailModel();
    using (UsersContext db = new UsersContext())
    {
       UserProfile user = db.UserProfiles.FirstOrDefault(u => u.UserName.ToLower() == username);
       newModel.CurrentEmail = user.EmailAddress;
    }

    return View(newModel);
}

After making this change, run the website and again go to the /Account/ChangeEmail action that we just created. You can now enter a new email address and click the Change Email button and see that the email address will be updated.


Attacking the Site

As written, our application is vulnerable to a cross-site request forgery attack. Let’s add a webpage to see this attack in action. We’re going to add a page within the website that will change the email to a different value. In the HomeController.cs file we’ll add a new action named AttackForm.

public ActionResult AttackForm()
{
   return View();
}

We’ll also add a view for this named AttackForm.aspx under the /Views/Home folder. It should look like this:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Attack Form
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<hr>
<h2>Attack Form</h2>

<p>This page has a hidden form, to attack you, by changing your email:</p>

<iframe width="1px" height="1px" style="display:none;">
<form name="attackform" method="POST" action="<%: Url.Action("ChangeEmail", "Account") %>">
    <input type="hidden" name="NewEmail" value="newemail@evilsite.com"/>
</form>
</iframe>
<script type="text/javascript">
    document.attackform.submit();
</script>

</asp:Content>

<asp:Content ID="Content3" ContentPlaceHolderID="FeaturedContent" runat="server">
</asp:Content>

<asp:Content ID="Content4" ContentPlaceHolderID="ScriptsSection" runat="server">
</asp:Content>

Our page helpfully announces its ill intent, which of course a real attack would not do. This page contains a hidden form that will not be visible to the user. It then uses Javascript to automatically submit this form when the page is loaded.

attack-form

If you run the site again and go to the /Home/AttackForm page, you’ll see that it loads up just fine, but with no outward indication that anything has happened. If you now go to the /Account/ChangeEmail page though, you’ll see that your email has been changed to newemail@evilsite.com. Here of course, we’re intentionally making this obvious, but in a real attack, you might not notice that your email has been modified.


Mitigating Cross-Site Request Forgery

There are two primary ways to mitigate this type of attack. First, we can check the referral that the web request arrives from. This should tell the application when a form submission does not come from our server. This has two problems though. Many proxy servers remove this referral information, either intentionally to protect privacy or as a side effect, meaning a legitimate request could not contain this information. It’s also possible for an attacker to fake the referral, though it does increase the complexity of the attack.

The most effective method is to require that a user specific token exists for each form submission. This token’s value should be randomly generated each time the form is created and the form is only accepted if the token is included. If the token is missing or a different value is included, then we do not allow the form submission. This value can be stored either in the user’s session state or in a cookie to allow us to verify the value when the form is submitted.

ASP.NET makes this process easy, as CSRF support is built in. To use it, we only need to make two changes to our website.


Fixing the Problem

First, we must add the unique token to the form to change the user’s email when we display it. Update the form in the ChangeEmail.aspx view under /Account/ChangeForm:

<% using(Html.BeginForm()) { %>
    <%: Html.AntiForgeryToken() %>
    <%: Html.TextBoxFor(t=>t.NewEmail) %>
    <input type="submit" value="Change Email" />
<% } %>

This new line: <%: Html.AntiForgeryToken() %> tells ASP.NET to generate a token and place it as a hidden field in the form. In addition, the framework handles placing it in another location where the application can access it later to verify it.

If we load up the page now and look at the source, we’ll see this new line, in the form, rendered to the browser. This is our token:

<form action="/Account/ChangeEmail" method="post"><input name="__RequestVerificationToken" type="hidden" value="g_ya1gqEbgEa4LDDVo_GWdGB8ko0Y91p98GTdKVKUocEBy-xAoH_Pok4iMXMxzZWX_IDDAXEkVwu3gc6UNzRKt8tjZ88I9t4NE8WT0UTT0o1" />
    <input id="NewEmail" name="NewEmail" type="text" value="" />
    <input type="submit" value="Change Email" />
</form>

We also need to make a change to our action to let it know that we’ve added this token and that it should verify the token before accepting the posted form.

Again this is simple in ASP.NET MVC. At the top of the action that we created to handle the posted form, the one with the [HttpPost] attribute added, we’ll add another attribute named [ValidateAntiForgeryToken]. This makes the start of our action now look like the following:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult ChangeEmail(ChangeEmailModel model)
    {
        string username = WebSecurity.CurrentUserName;
        *rest of function omitted*

Let’s test this out. First go to the /Account/ChangeEmail page and restore the email for your account to a known value. Then we can return to the /Home/AttackForm page and again the attack code attempts to change our email. If you return to the /Account/ChangeEmail page again, this time you’ll see that your previously entered email is still safe and intact. The changes we made to our form and action have protected this page from the attack.

If you were to look at the attack form directly (easily done by removing the <iframe> tags around the form on the attack page, you’ll see the error that actually happens when the attack form attempts to post.

failed-attack

These two additional lines added to the site were enough to protect us from this error.


Conclusion

Cross-site request forgery is one of the most common and dangerous attacks on websites. They are often combined with other techniques which search out weaknesses in the site to make it easier to bring about the attack. Here I’ve demonstrated a way to secure your .NET site against this type of attack and make your website safer for your users.

Sponsored post
feedback2020-admin
04:05

July 31 2013

23:07

Integrating a JS Build Process Into MSBuild in Visual Studio 2012 Express

I’ve been working with ASP and ASP.NET for about ten years now, starting with ASP classic and settling on .NET 2.0 as my favorite. My new year resolution this year (2013) was to upgrade my .NET work to .NET 4.0 using Visual Studio 2012 Express and really get to grips with MSBuild, so that I can concatenate and minify my JavaScript files as part of the normal build process of a .NET project, in Visual Studio.

My first love is to use Ant in NetBeans with a PHP or JSP platform for this kind of work, but my company’s main website runs on a .NET platform and it’s time to update it, so I decided to bite the bullet and dive back in to some serious study of creating a fully integrated build process using MSBuild.

This tutorial will show you how to edit your Visual Studio 2012 Express project file to include your own separate build file which will perform the now widely familiar process of concatenating and minifying a set of JavaScript modules into one file ready for deployment.


Software Requirements

I wanted a non-trivial project to demonstrate this process, because I find the devil is in the details. I have often faithfully followed an overly-simple tutorial or introduction to an unfamiliar subject, then discovered that the tutorial did not prepare me for when you want to do something even slightly difficult. So, in this tutorial we’ll be attempting to marry Knockout.js and jQuery UI. We will also be using a JSON file with a hierarchy of data to define a menu. We will use a Knockout.js template with a foreach binding which loops through the JSON data to emit a hierarchy of ul elements to act as the HTML markup for a menubar compatible with jQuery UI.

Sadly, the menubar is not yet available (versions 1.9 or 1.10) bundled with jQuery UI, so you need to download the menubar files from the Menubar branch of jQuery UI. You also need the YUI Compressor for minifying your JavaScript source files. For this tutorial, you will need Visual Studio 2012 Express for Web installed. You will also need to download:

If you’re not used to JSON, it’s a good idea to visit the JSON website.


Why MSBuild and Not NAnt?

If you read my last tutorial Using Ant to Build a JavaScript Library, you might be wondering why this tutorial is not about NAnt. Well, with my shiny new installation of Visual Studio 2012 Express, I would like to try to bring my development under one roof. My absolute favorite IDE for C# Assembly development, for many years, was SharpDevelop. They moved some years ago from NAnt to MSBuild for SharpDevelop version three. It’s finally time for me to follow suit.

We are no longer using NAnt in our build process, we switched entirely to MSBuild / CruiseControl.NET. And we don’t view the ability to depend on the dominant operating system as a step back: it helps reduce the number of moving parts, the different configurations, different user setups.

#D 3.0 – Dropping NAnt Support: Why?

Rationale: Why Integrate the JavaScript Build Into the .NET Build?

For years, for my .NET development, I’ve worked with three different IDEs simultaneously:

  1. Sharp Develop for my C# assembly development, but I also shoe-horned the JavaScript and CSS concatenate and minify build process into that environment with a specially installed copy of NAnt.
  2. Visual Studio (2005 etc) for the master pages, content pages.
  3. An external editor like Aptana to handle JavaScript development.

Using three IDEs like this was exhausting (and surprisingly taxing for my CPU and RAM), so another new year’s resolution is to bring everything together into Visual Studio. Hence the need to understand how to integrate my JavaScript build process into the overall project build.

One of the major draws of MSBuild for me (on Windows platforms) is that it comes as part of .NET itself. That means that any Windows machine that is up-to-date with Windows Update will have MSBuild available.

Comparison of NAnt and MSBuild on StackOverflow.

Setting Up Your Environment

Open a new project in Visual Studio 2012 Express. I’ve called it NetTutsMSBuildJs and I’ve created it inside my NetTuts folder here: C:\NetTuts\MSBuildJs.

New Project Dialog Box

As you can see in the screenshot, I have created a number of folders as follows:

js_folders
Folder Contents css Production release versions of jQuery UI CSS files. For this tutorial, we’re using the smoothness theme. debug Various versions of the Default.aspx web form page for debugging purposes. debug-js Three folders: concat, min and src. js Production release versions of jQuery, jQuery UI and Knockout. jsbuild An XML build file with all the tasks needed for the JavaScript build and a copy of the YUI compressor. json The key JSON file menubar-data.json which has the data needed to build the menubar. Also the JSON files used to populate the page according to the user’s menu choices.

Notice some of the folders are greyed out. This is because I’ve excluded them from the project. You can toggle this setting from the context menu:

exclude_from_project

It’s easy to delete and create directories during the build process, but there’s no way to include or exclude items programmatically from the project. The concat and min folders in debug-js are disposable, generated automatically by the build process from whatever you’ve created in the src folder, so it’s appropriate to exclude them from the project. Note, you can’t exclude the debug folder from the project because it contains .NET web form pages that have code-behind files. If you exclude the folder, the web form pages throw errors saying that the classes defined in the code-behind files can’t be found.

show_all_files

You can toggle whether these excluded objects should be shown by going to the Show All Files icon at the top of the Solution Explorer and clicking. I always want to be able to see them.

There’s one more key piece of configuration we need for this project. IIS and the built-in IIS Express don’t include a JSON mime type by default, and we will be using JSON files extensively to deliver content, so we have to add that to the Web.config file. Within the configuration element add a system.webServer element like this:

    <system.webServer>
        <staticContent>
            <mimeMap fileExtension=".json" mimeType="application/json" />
        </staticContent>
    </system.webServer>

The JavaScript Project: Building a Menubar Using JSON, Knockout and jQuery UI

The focus of this tutorial is on how to build a JavaScript project within a .NET project, but we can’t go any further until we have something to build, so now let me explain the slightly ambitious project I have in mind.

Here’s a UML component diagram showing all the pieces that the project will need. Please note this is a comprehensive component diagram from a developer’s point of view showing all sorts of disposable artifacts that are only important, for instance, for debugging. It’s not a component diagram of only the key artifacts needed for the target system.

Component Diagram

A component diagram defines the composition of components and artifacts in the system.
IBM: Component Diagrams

In UML 2.0, “component” is used to describe a more abstract idea: autonomous, encapsulated units; “artifact” is used to describe what I’m showing in this diagram: files and libraries. It’s an ideal diagram to show how the various files depend on each other. For instance, all the web form pages depend on the Main master page. The js.build file won’t work if the compressor jar file is not present. The project file and the js.build file are, annoyingly, mutually dependent. If the js.build file is not present, the project will not load; js.build can’t run alone, the tasks defined there are triggered by the AfterBuild event in the overall project build.

For this tutorial, I want to display a horizontal menubar using the menubar branch of jQuery UI. To do that, I have a JSON file with the hierarchical data for the menu and a Knockout.js template looping through this data to render the
HTML markup needed by jQuery menubar. I’ve added a callback function renderMenu which is fired by the afterRender event in the Knockout template. renderMenu then simply makes a call to menubar to finally render the menubar with all the lovely jQuery UI shiny features.


Step 1: The Production Release Files

CSS

Download the full bundle from jQuery UI including a theme of your choice. After unzipping your download, drill down to the folder called css where you’ll find a folder with the name of your chosen theme. In my case, I’ve chosen smoothness. Open that folder and you should see the files you need:

jquery_ui_css

Copy the whole theme folder (smoothness) and paste it into your css folder in the project. Come back to Visual Studio, click the refresh icon at the top of the Solution Explorer and the smoothness folder should appear in the css folder. You should include the folder in the project as well.

In addition to jQuery UI and a specific theme, you also need the small CSS file specifically for the menubar. After downloading the menubar project from github, drill down to the jquery.ui.menubar.css file following this path: \jquery-ui-menubar\themes\base\jquery.ui.menubar.css. Copy that to the css folder of your project.

JavaScript

Download up-to-date versions of production releases of jQuery, jQuery UI and Knockout. I’m using 1.8.2 for jQuery, 1.9.2 for jQuery UI and 2.1.0 for Knockout. Copy them to the js folder in your project.

You’ll also need the latest, uncompressed release of jquery.ui.menubar.js, downloaded from the Menubar branch of the jQuery UI project. Copy that to the debug-js\src folder in your project.

The Main Master Page

We’re creating several versions of the same page to help debug and test our JavaScript. The master page can of course help to prevent duplication of code. Call this master page Main.Master.

add_new_master_page

Leave the title element blank (we’ll define the title for each page that uses this master) and link to all the stylesheets we need for jQuery UI and the menubar:

<title></title>
<link rel="stylesheet" type="text/css" href="/css/smoothness/jquery-ui-1.9.2.custom.css">
<link rel="stylesheet" type="text/css" href="/css/smoothness/jquery-ui-1.9.2.custom.min.css">
<link rel="stylesheet" type="text/css" href="/css/jquery.ui.menubar.css">

Add a ContentPlaceHolder just before the end of the body where each page will link to the relevant JavaScript files

    <asp:ContentPlaceHolder ID="JsScripts" runat="server"/>

Step 2: The JSON Definition of the Data Needed for the Menubar

Here is the JSON object defining a menubar that we might use for an English Instructors’ website. Create a JSON file called menubar-data.json in the json folder and populate it with the following JSON.

{
    "nodes":[{
        "text": "For Students", 
        "nodes": [

        {
            "text": "Listening Practice", 
            "url":"listening-practice.json"
        },
        {
            "text": "Grammar", 
            "url":"grammar.json",
            "nodes": [

            {
                "text": "Verb Forms", 
                "url":"verb-forms.json",
                "nodes": [

                {
                    "text": "Verb Tense and Aspect",
                    "url":"verb-tense-and-aspect.json"
                },
                {
                    "text": "Modal Auxiliary Verbs",
                    "url":"modal-auxiliary-verbs.json"
                }
                ]
            },
            {
                "text": "Verb Patterns",
                "url":"verb-patterns.json"
            },
            {
                "text": "Noun phrases",
                "url":"noun-phrases.json"
            },
            {
                "text": "Complex sentences",
                "url":"complex-sentences.json"
            }
            ]
        }
        ]
    },
    {
        "text": "For Teachers", 
        "nodes": [
        {
            "text": "Teaching Materials",
            "url":"teaching-materials.json"
        },
        {
            "text": "Tests and evaluation grids",
            "url":"tests-and-evaluation.json"
        },
        {
            "text": "Media",
            "url":"media.json"
        }
        ]
    }
    ]
}

Top-level nodes have no URL property defined, so when clicked, they will just display sub-menu items. The sub-menus contain nodes with the URL property defined. When you click one of these nodes, the system will retrieve the JSON data from the file at that URL.

Each JSON file linked to, in the menubar, contains some content in a simple structure defining a header and some text:

{
    "header": "Grammar", 
    "text": "A series of exercises helping you to improve your grammar."
}

Step 3: The Knockout Template for the Menubar

We define this in Main.Master. There is no obvious way of minifying or improving on it for deployment so I want to re-use it with every version of the pages that link to the master page.

I wanted to have just one Knockout template to render the HTML markup (a set of nested ul elements) for the menubar, but not surprisingly the afterRender event associated with the foreach binding fires with every loop, not at the end of the whole rendering process. So, I needed to create an observableArray with only one ul element, bind that to a Menu template which renders the outermost ul element, and nest the menubar template inside it. I can then handle that single foreach event with my function renderMenu, which calls the jQuery menubar constructor and renders the menubar in all its glory. I got a lot of help on this from this thread: nested-templates-with-knockoutjs-and-mvc-3-0.

Here is the menu template:

        <script type="text/html" id="MenuTemplate">
            <ul class="ui-widget-header" id="menu" data-bind="template: { name: 'MenuNodeTemplate', foreach: $data.root.nodes}"></ul>
        </script>

And here’s the node template for each node of the menubar:

        <script id="MenuNodeTemplate" type="text/html">
            <li data-bind="addData: $data.url">
                <a data-bind="attr: {href: ('#' + $data.url)}"><span data-bind="text: $data.text"></span></a>
                <!-- ko if: $data.nodes -->
                <ul data-bind="template: { name: 'MenuNodeTemplate', foreach: $data.nodes}"></ul>
                <!-- /ko -->
            </li>
        </script>

You then need a div element which you bind to MenuTemplate:

            <div data-bind="template: {name: 'MenuTemplate' , foreach: masters, afterRender: renderMenu}"></div>

Notice that the node template uses containerless control flow syntax, which is based on comment tags. There are a few things going on here, so let me explain

In the fully rendered jQuery menubar, I want to attach a handler to the select event. The handler has the signature event, ui. When you click a menubar item, the handler is passed the event object and a jQuery object representing the item. To get the text from the ui object, we can call the text method ( ui.item.text() ). But how do we get the url property from the underlying JSON? That is a little bit trickier and I explain it later when we look at the select function triggered by the click event on each sub-menu item and the custom binding addData attached to the li element in the Knockout template.

Finally you just need a div element where we can display the content retrieved from the JSON data files:

        <div id="show-result" class="ui-widget">
            <h1 data-bind="text: header" class="ui-widget-header ui-corner-all"></h1>
            <div data-bind="html: text" class="ui-widget-content ui-corner-all"></div>
        </div>

Step 4: Creating the Web Form Pages That Depend on the Main.Master File

Default-src.aspx

Create a Web Form using Master Page in the debug folder called Default-src.aspx.

add_page_using_master_page

This turns out to be a mercifully short file. This is one of the great advantages of the .NET approach to Master pages. There are only two ContentPlaceHolders in the master page. Add the links to your JavaScript files as follows to the Content element linked to the JsScripts ContentPlaceHolder:

<%@ Page Title="Default src" Language="C#" MasterPageFile="~/Main.Master" AutoEventWireup="true" CodeBehind="Default-src.aspx.cs" Inherits="NetTutsMsBuildJs.debug.Default_src" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="JsScripts" runat="server">
    <script src="/js/jquery-1.8.2.min.js"></script>
    <script src="/js/jquery-ui-1.9.2.custom.min.js"></script>
    <script src="/debug-js/src/jquery.ui.menubar.js"></script>
    <script src="/js/knockout-2.1.0.js"></script>
    <script src="/debug-js/src/default-src.js"></script>
</asp:Content>

Create a new JavaScript file called default-src.js in the debug-js\src folder.

We enclose everything in a call to the usual jQuery $ function that makes sure the page is fully loaded, before running anything.

        $(function () {
        
        });

As of jQuery 1.4, if the JSON file contains a syntax error, the request will usually fail silently. See: jQuery.getJSON().

We need three main pieces of functionality here:

  1. A call to the jQuery getJSON method to retrieve the JSON data for the menubar. If that succeeds, we create a Knockout view model and call ko.applyBindings(viewModel) to activate it.
  2. A renderMenu function which will be called by the afterRender event of the MenuTemplate. This function calls the menubar constructor to render the menubar.
  3. A select function which is called when the user clicks a menubar item. This function retrieves the JSON data from the relevant content file and displays it on the page.

Notice that the select function needs to be able to retrieve the URL from the underlying JSON data. This is the trickiest part of marrying the jQuery menubar functionality with the Knockout template. jQuery allows you to add data to and retrieve data from an HTML element. To add data from within our Knockout template, we need to use a custom binding, which has access to the HTML element it is bound to. The binding I have created is called addData and is simply attached to ko.bindingHandlers in the usual Knockout way with an init method and an update method.

    ko.bindingHandlers.addData = {
        init: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            if (value) {
                $.data(element, "url", value);
            }
        },
        update: function (element, valueAccessor) {
            var value = ko.utils.unwrapObservable(valueAccessor());
            if (value) {
                $.data(element, "url", value);
            }
        }
    };

Perhaps the node template makes more sense now. The jQuery object passed as ui in the select handler represents the topmost li element of each menubar item, so we add the custom binding to that list item element: data-bind="addData: $data.url". Now that each element has some data attached to it, we can retrieve it from the select handler with this syntax: ui.item.data("url"), using the jQuery data method.

The link element is more straightforward and just uses the standard attr and text bindings:

        <a data-bind="attr: {href: ('#' + $data.url)}">
            <span data-bind="text: $data.text"></span>
        </a>

Just note that I’ve prefixed the href with a hash symbol. That way when you click on the menubar item, you don’t follow a link to another page. Instead, the select event is fired and the handler, sorry, handles it.

Here’s the full select function using this approach to retrieve the data from the jQuery object representing the element rendered by Knockout:

    function select(event, ui) {
        var url = "/json/" + ui.item.data("url");
        $.getJSON(url, function (data) {
            viewModel.header(data.header);
            viewModel.text(data.text);
        })
        .error(function (errorData) {
            viewModel.header("Error");
            if (errorData.status === 404) {
                viewModel.text("Could not find " + ui.item.text() + " at " + url);
            } else {
                viewModel.text("There has been an error, probably a JSON syntax error. Check the JSON syntax in the file <code>" + url + "</code>");
                console.log(errorData);
            }
        });
    }

I added the extra error trap because jQuery now remains silent about JSON syntax errors. I don’t want the user to be burdened with the details of JSON syntax errors, but I want to give some clue about what might have gone wrong.

Here’s the Knockout view model defined in the function attached to the getJSON() method:

    $.getJSON('/json/menubar-data.json', function (data) {
        viewModel = {
            header: ko.observable(),
            text: ko.observable(),
            masters: ko.observableArray([
            {
                name: "Master1",
                root: data
            }
            ]),
            renderMenu: function () {
                $("#menu").menubar({
                    autoExpand: true,
                    menuIcon: true,
                    buttons: true,
                    select: select
                });
            }
        };
        ko.applyBindings(viewModel);
        viewModel.header("Welcome");
        viewModel.text("The English Resource Page");

    })
    .error(function (errorData) {
        console.log({ "errorData": errorData });
        console.log(errorData.error());
    });

Step 5: Run the Project in Debug Mode.

With Default-src.aspx open in the IDE window, click run (the green arrow just under the menu of the IDE) in Debug mode.

debug

After the build process, the Default-src.aspx should appear in your browser’s window. The IDE runs an Express version of the IIS web server in the background. In my case, the project uses port 54713 on localhost to run the page:

http://localhost:54713/debug/Default-src.aspx

Default-src

We’re now ready to work on the JavaScript build process.


Integrating the JavaScript Build Process Into MSBuild

This project will automate the two key steps we need to build a complex JavaScript project:

  • Concatenate: Collect all the source files you need for a particular page and concatenate them together into one file. MSBuild doesn’t have a built-in Concat task like Ant or NAnt so we’ll have to roll our own based on this excellent blog How To: Concatenate files using MSBuild tasks.
  • Minify: Minify our own source files and concatenate them with production release files, like the jQuery file, into one compressed file.

Step 1: Toggle Between the Project and Editing the Project Build File

The folder where you created your .NET project will include files that look like these:

project_file

The NetTutsMSBuildJs.csproj file is just an XML file specially configured to handle the MSBuild process for this project. It is perfectly legitimate to create one of these manually or edit it to suit your project. Obviously, for purely .NET purposes it’s much better to use the Visual Studio GUI to configure this file automatically for you, but the point of this tutorial is to show you how to add in a JavaScript build, which is not part of the standard .NET build.

In Visual Studio, you can’t edit this project file unless you unload the project, and you can’t load the project if there is a syntax error in the file! So, practice unloading and loading the project so that you can edit this key file. To unload the project, right-click the project and click the Unload Project item.

unload_project

After unloading the project, all the folders and files disappear and you’re left with just the solutions and projects in the Solution Explorer. Right-click the project and this time the context menu is very short. Choose Edit NetTutsMSBuildJs.csproj and the project configuration file opens.

edit_proj_file

Now, just to build your confidence and get used to dealing with those times when you can’t load the project because of a syntax error in the project files, type a deliberate mistake near the beginning of the project file: just type a letter before the first tag outside the XML document structure. Save and close the file. Try to load the project from the context menu and you will get an error message saying the project can’t be loaded. Yes, Visual Studio is very strict like this.

project_load_error

Re-open the project file, correct the error, save and close again. When you re-load the project, it should load smoothly. Now it’s time to edit for real. We will only manually change one thing in the project file, and that will be to add an Import element which will import a file to perform the JavaScript build.


Step 2: Create a Build File for the JavaScript Build and Import It Into the Project File.

If you add an Import element to the project file for a file which doesn’t exist, you won’t be able to load the project, so create a new text file called js.build in the jsbuild folder. After you enter the necessary XML code, the IDE will recognise this file as an XML file. There will be no need to actually associate the .build extension with the XML editor. Enter this starting code into jsbuild\js.build, save and close.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

Now, unload the project and edit the project file by adding this line to the end of the file just before the closing tag.

<Import Project="jsbuild\js.build" />

You should now be able to re-load the project.


Step 3: Hello Discworld!!!!!

Five exclamation marks, the sure sign of an insane mind. – Terry Pratchett, Reaper Man

I am a bit bored with saying “Hello World” at the beginning of every new IT tutorial. So this time, I’m going to say hello to Terry Pratchett’s amazing Discworld.

Open js.build. The IDE should automatically notice that it is an XML file. If not, perhaps you have invalid XML. After adding the following code to set up a Hello Discworld message, the IDE should finally realise this is XML. Make sure the js.build file now contains the following XML. Don’t forget the five exclamation marks to get the right flavour of insanity for the Discworld!!!!!

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="HelloDiscworld">
    <Message Text="Hello Discworld!!!!!" Importance="high"></Message>
  </<Target>
  <Target Name="AfterBuild">
    <CallTarget Targets="HelloDiscworld"></CallTarget>
  <Target>
</Project>

When you right click on the project and run build, you should see the message in the output window.

hello_discworld

Like Ant, MSBuild uses the idea of targets to perform groups of tasks. The AfterBuild target is run automatically by MSBuild after everything else has been successfully built. I’m tacking the JavaScript build onto the end of the .NET build so the AfterBuild extension point seems the best place to put this. Notice how AfterBuild is run automatically and within AfterBuild we call our Target HelloDiscworld. I’ve set the Importance of the message to high because otherwise it might not appear in the output window.


Step 4: Sort Out Paths

Right. We went a little bit mad in the Discworld with too many exclamation marks, but at least our JavaScript build file seems to be working! OK. Joking aside, we now have to get the most crucial thing in a build routine right: paths.

As with Ant, I have always had trouble understanding absolute and relative paths in these configuration files, so I want to tread carefully. Add a PropertyGroup element to the top of the js.build file, just below the Project tag and add two properties like this.

  <PropertyGroup>
    <ConcatDir>debug-js\concat</ConcatDir>
    <MinDir>debug-js\min</MinDir>
  </PropertyGroup>

Now, alter the message so we can see what these properties contain:

<Message Text="Hello Discworld!!!!! from $(ConcatDir)" Importance="high"></Message>

Now clean and build the project again or just choose rebuild. The message appears in the output like this:

Hello Discworld!!!!! from debug-js\concat


Step 5: Create Clean and Init Targets

Lovely. We’ve got our environment, our source files and we’ve got properties in the build file containing relative paths pointing to the directories we need to work with. Now we can add a CleanJs Target and an InitJs Target to Remove and Make the concat and min directories. I have a habit of putting little “hello” messages in to these targets when developing these files just to re-assure myself they’re actually running or checking property values. I find increasing the output verbosity in MSBuild tends to give me a flood of information that I don’t need, though it’s great when I can’t figure out where I’ve made a mistake.

MSBuild uses simple relative paths from the root folder of the whole project. If you have a folder called js in your project, you can use the value js in a named Property within a PropertyGroup without further complication.

  <Target Name="CleanJs">
    <Message Text="Hello from CleanJs" Importance="high"></Message>
    <RemoveDir Directories="$(ConcatDir)" Condition="Exists('$(ConcatDir)')">
      <Output PropertyName="ConcatDirRemoved" TaskParameter="RemovedDirectories"/>
    </RemoveDir>
    <RemoveDir Directories="$(MinDir)" Condition="Exists('$(MinDir)')"></RemoveDir>
    <Message Text="Hello from removed dirs $(ConcatDirRemoved)" Importance="high"></Message>
  </Target>
  <Target Name="InitJs">
    <MakeDir Directories="$(ConcatDir)" Condition="!Exists('$(ConcatDir)')"></MakeDir>
    <MakeDir Directories="$(MinDir)" Condition="!Exists('$(MinDir)')"></MakeDir>
  </Target>

To run these targets add CallTarget elements to the AfterBuild target.

    <CallTarget Targets="CleanJs"></CallTarget>
    <CallTarget Targets="InitJs"></CallTarget>

Step 6: Concatenating the Files

You’re probably getting used to editing the js.build file by now. You may have noticed an annoying error message linked to text underlined with wiggly blue lines, like this:

invalid_child_element

This is an annoying bug in Visual Studio which has been there for quite a while. PropertyGroup elements and ItemGroup elements can be populated with any value you like. The problem is Visual Studio wrongly reports an error for the first Property or Item you define in one of these groups. As you’ve seen, ConcatDir works when you build the project, and there is no problem loading the project. Just ignore these distracting invalid child element errors.

At last, some real build work. We add a new target to concatenate the files we want. Unlike Ant and NAnt, there is no built-in Concat task, so we have to roll our own with the ReadLinesFromFile task

  <Target Name="ConcatenateJsFiles">
    <ItemGroup>
    <ConcatFiles Include="
                 js\jquery-1.8.2.min.js;
                 js\jquery-ui-1.9.2.custom.min.js;
                 debug-js\src\jquery.ui.menubar.js;
                 js\knockout-2.1.0.js;
                 debug-js\src\default-src.js
                 "/>
    </ItemGroup>
    <ReadLinesFromFile File="%(ConcatFiles.Identity)">
      <Output TaskParameter="Lines" ItemName="ConcatLines"/>
    </ReadLinesFromFile>
    <WriteLinesToFile File="debug-js\concat\default-concat.js" Lines="@(ConcatLines)" Overwrite="true" />
  </Target>

Add a new CallTarget element to the AfterBuild target in js.build calling ConcatenateJsFiles. Rebuild the project as usual and lo and behold, a file called default-concat.js magically gets created in the debug-js\concat directory. You will probably have to refresh the Solution Explorer to see it.

Now add a new Web form page called Default-concat.aspx to the debug folder, linking it to the Main.Master page. This is very short and slightly different from the Default-src.aspx page. This time, all the JavaScript we need has been concatenated into one file, so you only need one script tag link to default-concat.js.

<%@ Page Title="Default concat" Language="C#" MasterPageFile="~/Main.Master" AutoEventWireup="true" CodeBehind="Default-src.aspx.cs" Inherits="NetTutsMsBuildJs.debug.Default_src" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="JsScripts" runat="server">
    <script src="/debug-js/concat/default-concat.js"></script>
</asp:Content>

To try this out, open the Default-concat.aspx page in the IDE window and run the project again in Debug mode. You should see the fully functioning menubar in your browser with the title Debug concat appearing in the title bar of the browser.


Step 7: Final Stage – Minifying

The final target, target!!!!!

Our menubar seems to be working and when we concatenate the files we seem to have got the right order and everything’s going smoothly in the Debug-concat.aspx page. It’s now finally time to minify the source files default-src.js and jquery.ui.menubar.js and concatenate them with the professional release files in the correct order. This is slightly more complicated because now we need to bring in an external dependency which, so far, we haven’t needed: the YUI compressor. There is a .NET port of this being developed but I’m so used to the Java version, I prefer to use my old favorite. Create a new target called MinifyJsFiles like this:

  <Target Name="MinifyJsFiles">
    <ItemGroup>
      <MinFiles Include="
                 debug-js\src\jquery.ui.menubar.js;
                 debug-js\src\default-src.js
           "/>
      <Compressor Include="jsbuild\yuicompressor-2.4.7.jar"></Compressor>
    </ItemGroup>
    <Message Text="Hello Compressor.Fullpath: %(Compressor.Fullpath)" Importance="high"></Message>
    <Exec Command="java -jar %(Compressor.Fullpath) debug-js\src\default-src.js --type js -o debug-js\min\default-min.js"/>
    <Exec Command="java -jar %(Compressor.Fullpath) debug-js\src\jquery.ui.menubar.js --type js -o debug-js\min\jquery.ui.menubar-min.js"/>

  </Target>

Notice the property Compressor. Here you just have to define the relative path from the project folder, but the jar file, run by the Java process, will need the full path. Luckily, MSBuild provides an easy way to convert a relative path into a full path. You use the % syntax and invoke the Fullpath property. This is an example of MSBuild Well-known Item Metadata.

Add yet another CallTarget element to the AfterBuild element to call the MinifyJsFiles target.

Now our final target, target. We have to take all the professional release files and concatenate them with the minified version of our sources and concatenate them into one file.

  <Target Name="ConcatenateMinFiles">
    <ItemGroup>
    <ConcatMinFiles Include="
                      js\jquery-1.8.2.min.js;
                      js\jquery-ui-1.9.0.custom.min.js;
                      debug-js\min\jquery.ui.menubar-min.js;
                      js\knockout-2.1.0.js;  
                      debug-js\min\default-min.js
                      "/>              
    </ItemGroup>
    <ReadLinesFromFile File="%(ConcatMinFiles.Identity)" >
      <Output TaskParameter="Lines" ItemName="ConcatMinFilesLines"/>
    </ReadLinesFromFile>
    <Message Text="We are concatenating these minified files %(ConcatMinFiles.Identity)" Importance="high"></Message>
    <WriteLinesToFile File="debug-js\min\default.js" Lines="@(ConcatMinFilesLines)" Overwrite="true" />
   </Target>

You have to be careful with this ItemName property in the build files. Property and item instances are stored in a global context in MSBuild. If you use the same name for ItemName in two different concatenated targets, you end up concatenating all the files from both targets.

Rebuild the project and you should now see two new files in the debug-js\min folder: default-min.js and jquery.ui.menubar-min.js. The debug-js folder should now look like this after re-building and refreshing the Solution Explorer:

debug-js

Create a new Web form page called Default-min.aspx linked to the Main.Master page and put it into the debug folder.

<%@ Page Title="Default min" Language="C#" MasterPageFile="~/Main.Master" AutoEventWireup="true" CodeBehind="Default-src.aspx.cs" Inherits="NetTutsMsBuildJs.debug.Default_src" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="JsScripts" runat="server">
    <script src="/debug-js/min/default-min.js"></script>
</asp:Content>

Conclusion

We walked through the steps required in Visual Studio Express 2012 for Web, to create a JavaScript project that marries Knockout with jQuery UI to create a menubar and then integrate a JavaScript build into the overall project build in Visual Studio.

In this tutorial we walked through the steps required in Visual Studio Express 2012 for Web, to create a JavaScript project that marries Knockout with jQuery UI to create a menubar from a JSON definition file and then integrate a JavaScript build of the source files into the .NET MSBuild process. The final result was that we had a web page with only one script tag containing all the complex JavaScript needed to run the page.

I think you can see how easy it would be to adapt this example to a very large, complex JavaScript library running in a .NET project. It should also be reasonably straightforward to develop these ideas to include tasks suitable for a release version. The obvious next step is to copy the fully minified and concatenated default.js file to the js folder, then include that in a definitive Default.aspx file in the root directory. With this example as a starting point, you should be able to explore the MSBuild documentation and develop a fully working build file to automate every part of your build process.

I also use this kind of approach for CSS files. In this particular case, the jQuery UI CSS files are so well optimized it hardly seemed worth minifying them, but in other projects it might be important for performance. A more sophisticated next step for you grunters out there would be to create a js.build file that runs a grunt file with an MSBuild Exec task. That way, you could easily include linting and testing to the build process.

Further reading

For further reading about Visual Studio, this excellent Nettuts+ Visual Studio: Web Dev Bliss will guide you on how to integrate Web Essentials and add code checking to your build process, but unfortunately, Web Essentials is not available for the Express edition. See Mads Kristensen’s answer here: “…unfortunately Express doesn’t allow third party extensions to be installed”. This tutorial is aimed at users of the Express edition and I hope it has given you a starting point for creating your own integrated JavaScript build, all within the Visual Studio Express environment.

May 30 2013

21:48

Say Hello to PowerShell

PowerShell has been in development for over ten years. Microsoft continues to invest in its development and adoption. These investments have transformed the ease and robustness with which developers and admins can automate Windows tasks.


What is PowerShell?

PowerShell solves administration and adaptability challenges by seamlessly integrating the .NET Framework.

PowerShell is Microsoft’s task automation framework, consisting of a command-line shell, an integrated scripting environment (ISE), a scripting language built on .NET Framework, an API allowing you to host PowerShell in your .NET applications, and it is a distributed automation platform. PowerShell provides full access to COM and WMI, enabling you to perform tasks on both local and remote Windows systems.

PowerShell is a new breed platform for automation, in that it solves administration and adaptability challenges by seamlessly integrating the .NET Framework. It’s good for developers, administrators, testers and more. Based on .NET, the tool drives down costs, while providing developers and administrators a simple and enterprise-ready way to automate, measure and improve all of their processes.


Follow Along

In this intro, I’ll highlight some of the depth and breadth PowerShell brings to the table. Things like the game changing object pipeline, the REPL (read, eval, print loop), .NET integration and more.

If you’re running Windows 7 or 8, PowerShell is already installed. Download PowerShell v3 for Windows 7 here. You need Windows 7 SP1 and the download also works for Windows 2008 R2 SP1 and Windows 2008 SP2. If you’re running Vista, XP or Windows 2003, you’ll need to settle for PowerShell v2 here.


What is it Good For? Absolutely Everything!

From deploying multiple resources to Azure, to handling your software builds for continuous integration, accessing web services or REST endpoints. PowerShell has you covered and provides so much more.

  • Slice and dice text, XML, CSV, and JSON with ease
  • Embed PowerShell to provide scripting capabilities for your C# apps
  • Create GUI applications five to ten times faster with less code
  • Leverage PowerShell’s capabilities to work with the Internet
  • Interact with DLLs and create objects, automatically display properties, and call methods in live interactive sessions
  • Build domain-specific languages (DSLs) and vocabularies to express solutions more clearly
  • Work with Microsoft Office via the Component Object Model (COM)
  • PowerShell v3 features

Bootstrapping PowerShell

What is a cmdlet? A cmdlet is the fundamental building block in PowerShell and is expressed as a verb-noun pair, helping to make them self-descriptive. For example:

PS C:> Get-Date

Sunday, May 26, 2013 8:46:16 AM

PowerShell includes hundreds of core cmdlets and you can write your own.

Memorize Two Cmdlets

PowerShell makes discoverability easy. Whenever you walk up to the blue screen of PowerShell and are not sure what to do, use Get-Command.

The Get-Command cmdlet gets all commands that are installed on the computer, including cmdlets, aliases, functions, workflows, filters, scripts, and applications.

In essence, Get-Command shows you all the things you can do in the current PowerShell session.

Get-Command

Get-Command supports wildcards. Let’s say I want to see all the cmdlets that have the verb, Invoke?

Get-Command Invoke*

Here is what I get after pressing enter.

CommandType Name                       ModuleName
----------- ----                       ----------
Function    Invoke-AsWorkflow          PSWorkflowUtility
Function    Invoke-Background          ShowUI
Function    Invoke-BrowserControl      AutoBrowse
Function    Invoke-Line                isepack
Function    Invoke-Line                PowerShellPack
Function    Invoke-Office365           Pipeworks
Function    Invoke-Pester              Pester
Function    Invoke-WebCommand          Pipeworks
Cmdlet      Invoke-CimMethod           CimCmdlets
Cmdlet      Invoke-Command             Microsoft.PowerShell.Core
Cmdlet      Invoke-Expression          Microsoft.PowerShell.Utility
Cmdlet      Invoke-History             Microsoft.PowerShell.Core
Cmdlet      Invoke-Item                Microsoft.PowerShell.Management
Cmdlet      Invoke-RestMethod          Microsoft.PowerShell.Utility
Cmdlet      Invoke-TroubleshootingPack TroubleshootingPack
Cmdlet      Invoke-WebRequest          Microsoft.PowerShell.Utility
Cmdlet      Invoke-WmiMethod           Microsoft.PowerShell.Management
Cmdlet      Invoke-WSManAction         Microsoft.WSMan.Management

What are the cmdlets ending in the noun Item?

Get-Command *-Item

Note that you start to see other verbs, like Clear, New, Remove and Set.

CommandType Name        ModuleName
----------- ----        ----------
Cmdlet      Clear-Item  Microsoft.PowerShell.Management
Cmdlet      Copy-Item   Microsoft.PowerShell.Management
Cmdlet      Get-Item    Microsoft.PowerShell.Management
Cmdlet      Invoke-Item Microsoft.PowerShell.Management
Cmdlet      Move-Item   Microsoft.PowerShell.Management
Cmdlet      New-Item    Microsoft.PowerShell.Management
Cmdlet      Remove-Item Microsoft.PowerShell.Management
Cmdlet      Rename-Item Microsoft.PowerShell.Management
Cmdlet      Set-Item    Microsoft.PowerShell.Management

Next I’ll use a few cmdlets to summarize what is available in my session on one of my boxes when I launch the PowerShell console.

Get-Command | Group CommandType -NoElement | Sort Count -Descending

I call Get-Command, group it, and sort it. Here, I can see that I have 1000+ Cmdlets to work with. I’m running PowerShell v3 with additional modules installed, so your mileage may vary.

Count Name
----- ----
 2487 Function
 1184 Cmdlet
   38 Alias
    1 Filter

What modules do these cmdlets come from? We can answer that question this way:

Get-Command -CommandType Cmdlet | Group ModuleName -NoElement | Sort Count -Descending

There is a lot I can get accomplished with PowerShell.

Count Name
----- ----
  379 ShowUI
  164 Hyper-V
  157 Azure
   92 Microsoft.PowerShell.Utility
   82 Microsoft.PowerShell.Management
   78 WebAdministration
   55 Microsoft.PowerShell.Core
   22 Dism
   18 International
   17 PKI
   16 PSScheduledJob
   13 Microsoft.WSMan.Management
   12 CimCmdlets
   10 Microsoft.PowerShell.Security
    9 TrustedPlatformModule
    8 BitsTransfer
    8 MsDtc
    6 Pipeworks
    6 Kds
    5 AppLocker
    5 SecureBoot
    5 Microsoft.PowerShell.Diagnostics
    4 NetSecurity
    4 Appx
    3 WindowsErrorReporting
    2 Microsoft.PowerShell.Host
    2 TroubleshootingPack
    1 PSWorkflow
    1 DnsClient

Get-Help

Get-Help does exactly that, it displays help for the cmdlet you are what to know more about. Not only is it easy to get help, it is easy to create/include help for the cmdlets/advanced functions you develop, a topic for another article. Having help at your fingertips is a huge time saver.

Get-Help Invoke-Command

Here is a Shortened version of the output.

NAME
    Get-Process

SYNOPSIS
    Gets the processes that are running on the local computer or a remote computer.

SYNTAX
    Get-Process [[-Name] <String[]>] [-ComputerName <String[]>] [-FileVersionInfo [<SwitchParameter>]] [-Module
    [<SwitchParameter>]] [<CommonParameters>]

    Get-Process [-ComputerName <String[]>] [-FileVersionInfo [<SwitchParameter>]] [-Module [<SwitchParameter>]] -Id
    <Int32[]> [<CommonParameters>]

    Get-Process [-ComputerName <String[]>] [-FileVersionInfo [<SwitchParameter>]] [-Module [<SwitchParameter>]]
    -InputObject <Process[]> [<CommonParameters>]

DESCRIPTION
    The Get-Process cmdlet gets the processes on a local or remote computer.
.
.
.
.

Easier still; there is a switch for this on the Get-Help cmdlet that takes you here.

Get-Help Get-Process -Online

Want to just see examples how to use the cmdlet? Use the -Examples switch. Plus, you can copy and paste example directly into the console and run it.

Get-Help Get-Process -Examples

It’s that easy and quick.

NAME
    Get-Process

SYNOPSIS
    Gets the processes that are running on the local computer or a remote computer.

    -------------------------- EXAMPLE 1 --------------------------

    PS C:> Get-Process

    This command gets a list of all of the running processes running on the local computer. For a definition of each column, see the "Additional Notes" section of the Help topic for Get-Help.

    -------------------------- EXAMPLE 2 --------------------------

    PS C:> Get-Process winword, explorer | format-list *

PowerShell Easily Works with Web Services

The W3C defines a “Web service” as:

[...] a software system designed to support interoperable machine-to-machine interaction over a network. It has an interface described in a machine-processable format (specifically WSDL). Other systems interact with the Web service in a manner prescribed by its description using SOAP messages, typically conveyed using HTTP with an XML serialization in conjunction with other Web-related standards.

PowerShell makes quick work of Webservices, using the New-WebServiceProxy cmdlet. Change the $zipcode, run it and get the latest weather info.

$zipCode = "96826"

$svc = New-WebServiceProxy http://wsf.cdyne.com/WeatherWS/Weather.asmx
$result = $svc.GetCityForecastByZIP($zipCode)

# Transform the results
$result.ForecastResult |
    ForEach {
        [PSCustomObject]@{
            City        = $result.City
            State       = $result.State
            Date        = $_.Date.ToString("d")
            Description = $_.Desciption
            DaytimeHigh = $_.Temperatures.DaytimeHigh
        }
    }

Result

I store the proxy object in $svc and then call the GetCityForecastByZIP method, capturing the results in $result. Looping through the ForecastResult array, I transform the record on the data. Note that the City and DaytimeHigh are at different levels in the hierarchy.

The technique I am using is creating key/value pairs for the hashtable. @{} is PowerShell syntax for a new hashtable. Using [PSCustomObject] is a PowerShell accelerator, which allows me, for one thing, to create a custom object from a hashtable.

The Weather.asmx web service returned hierarchical XML. In a handful of PowerShell commands, I re-shaped the data and formatted it (the Date) to my liking. For this example, I chose to let PowerShell print it out. Once I have the data in my PowerShell session, I am now connected to the PowerShell ecosystem and can easily pipe this array of custom objects to other cmdlets to push it to another web service, generate HTML, save it to a file, create a CSV file or export it to a SQL database.

City     State Date      Description   DaytimeHigh
----     ----- ----      -----------   -----------
Honolulu HI    5/22/2013 Showers       76
Honolulu HI    5/23/2013 Partly Cloudy 76
Honolulu HI    5/24/2013 Partly Cloudy 77
Honolulu HI    5/25/2013 Partly Cloudy 77
Honolulu HI    5/26/2013 Partly Cloudy 77
Honolulu HI    5/27/2013 Partly Cloudy 77
Honolulu HI    5/28/2013 Partly Cloudy 77

Working with CSV, JSON and XML

Slicing and dicing text formats is a PowerShell sweet spot. Here, I’ll convert three common formats to a PowerShell object. For the CSV and JSON, I’ll use the correct ConvertFrom-* cmdlets, and for the XML, I’ll use the accelerator which takes XML and creates an XMLDocument.

# Use CSV
$csv = "Name,Age`r`nJohn,10" | ConvertFrom-Csv
$csv

Name Age
---- ---
John 10

# Use JSON
$json = "{Name:'Tom', Age:20}" | ConvertFrom-Json
$json

Name Age
---- ---
Tom   20

# Use XML
$xml = (1"<data><record><Name>Harry</Name><Age>30</Age></record></data>").data.record
$xml

Name  Age
----  ---
Harry 30

# Combine all three
$csv,$json,$xml

Name  Age
----  ---
John  10
Tom   20
Harry 30

# Add up the ages
$csv,$json,$xml | % {$sum=0} {$sum+=$_.age} {$sum}

60

So, we took three heterogeneous formats, and at the end, performed an aggregation over one of the fields. I could have retrieved each of these data feeds from various places, the CSV from a network share, the JSON for an REST query and the XML from a Web Service. Like I said, this is a PowerShell sweet spot.


Twitter Search

Let’s use Twitter’s search REST API at the command line. I construct the Url, which you could use in your browser, and then I use the PowerShell cmdlet Invoke-RestMethod. It sends a request to the REST service and determines if the response is XML or JSON. Here I’m requesting a JSON response so, Invoke-RestMethod converts the results to an array of PowerShell objects. I pipe them to the Select cmdlet (an alias of the verb-noun Select-Object) choosing to only three fields. Think of this as a projection, similar to LINQ or SQL.

$query = "PowerShell"
$url = "http://search.twitter.com/search.json?q=$query"

(Invoke-RestMethod $url).results |
    Select created_at, from_user_name, text

Result

It’s that easy. Check out a video I did for version 2: “PowerShell, ShowUI and the Twitter API”. A mini WPF Twitter app in handful of PowerShell.

created_at       from_user_name       text
----------       --------------       ----
Sat, 25 May 2013 vitor pombeiro       @brunomlopes a falar sobre Powershell "Ã  minha maneira"
Sat, 25 May 2013 Jeffery Hicks        Did you know the #PowerShell ISE has startup options? In
Sat, 25 May 2013 Pat Richard          @mwjcomputing Yeah - had always used $MyInvocation.MyCom
Sat, 25 May 2013 Rob Fairman          "#PowerShell Script for Clearing #Windows Event Logs" ht
Sat, 25 May 2013 Jim Priestley        Automating SharePoint Deployments in Windows #Azure usin
Sat, 25 May 2013 VT Technology        RT @jangwoo_park: “@VTTechnology: Export Multiple Virtua
Sat, 25 May 2013 Aryan Nava           Using PowerShell to view Site created on the previous da
Sat, 25 May 2013 Aryan Nava           PowerShell Tips for SQL Server http://t.co/lVW2AY5BYZ
Sat, 25 May 2013 Private Cloud Tech   The Journey to the Private Cloud Part 3 – The Infrastruc
Sat, 25 May 2013 Dr Tom Shinder       The Journey to the Private Cloud Part 3 – The Infrastruc
Sat, 25 May 2013 Jacob Daniels        RT @tech_faq: Windows Server Manager is based on Windows
Sat, 25 May 2013 CodeCruiser          10 Tips for the SQL Server PowerShell Scripter http://t.

Compiling C# on the Fly in PowerShell

PowerShell is an interpreted language. So, there will be a penalty. It is not a major concern, but, sometimes, you’ll need the speed of a compiled language. PowerShell lets you compile C# on the fly in memory in your PowerShell session, by using the -TypeDefinition parameter on the Add-Type cmdlet. Note the here-string identified by the @" "@. They are super useful when quoting text. I encourage you to explore more with Add-Type and PowerShell’s quoting rules.

Add-Type -TypeDefinition @"
public class TestInline
{
    public long Fibonacci(long n)
    {
        long a = 0;
        long b = 1;

        for (long idx = 0; idx < n; idx+=1)
        {
            long temp = a;
            a = b;
            b = temp + b;
        }
            return a;
        }
}
"@

$obj = New-Object TestInline

1..10 | ForEach { $obj.Fibonacci($_) }

Interacting with DLLS

Now, let’s say I didn’t give you the source code – just the compiled DLL. No problem: Add-Type has a -Path parameter.

Add-Type -Path .FibLib.dll

$obj = New-Object TestInline
1..10 | ForEach { $obj.Fibonacci($_) }

Pay particular attention to this. Using Add-Type this way is how you easily wrap any .NET DLL coming from anybody, if they haven’t already provided a PowerShell interface. This is true whether the DLL is from Microsoft, DELL, Citrix or another developer.


In Closing

So that does it for now. Would you like to see more Powershell-specific content on Nettuts+? Let us know below!

August 21 2012

14:39

Building an ASP.NET MVC4 Application with EF and WebAPI

ASP.NET MVC has come a long way since “The Gu” jotted down some ideas during an airplane ride to a conference in 2007. In just under four years, ASP.NET MVC has seen its fourth release, and it provides developers an environment that eases development, streamlines processes, and promotes modern patterns.


Dive In

Jumping right in is one of the best ways to get a handle of new technology. Let’s go ahead and dive right into teh codez!

Setup

I will be using Visual Studio 2012 Release Candidate, which is available here. I also recommend downloading SQL Server 2012 because the new Management Studio is a much needed improvement over earlier versions.

Once VS 2012 is up and running, go ahead and create a new project. Go to File -> New Project and choose an Internet Application. It’s not a perfect template, but it’ll get the job done.

Project Options

Note: the code for this demo application is located in a Github repo. I won’t go through every single piece of code in this app, but you’ll have a good understanding of an MVC4 application at the end of this tutorial.

Entity Framework

I am going to use Entity Framework (EF) Code First for the data model. EF Code First lets us generate database tables with nothing more than a few Plain Old CLR Objects (POCO). Plus, EF lets us use LINQ to Entities and Lambda expressions, making it easy to query and issue commands. A win win!

Our application will be a review site for reviewing… stuff. Therefore, the data model needs to incorporate all the necessary bits and pieces for a single review. We’ll start with a class called Review. Write the following class in its own file in the Models directory:

// Review.cs
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Review.cs
public class Review
{
    public int Id { get; set; }
    
    [Required]
    public string Content { get; set; }
    
    [Required]
    [StringLength(128)]
    public string Topic { get; set; }
    
    [Required]
    public string Email { get; set; }
    
    [Required]
    public bool IsAnonymous { get; set; }
    
    public int CategoryId { get; set; }
    public virtual Category Category { get; set; }
    
    public virtual IEnumerable<Comment> Comments { get; set; }
}

The Review class has it’s Id (the primary key), the Content property to store the review, a Topic such as a restaurant name (or any name of an organization), an Email property, and an IsAnonymous flag to signify if the reviewer is anonymous. The CategoryId and the Category properties create a foreign key relationship to tie a review to a Category (eg: Doctors, Dentists, etc). And last is a collection of Comment objects.

Now write the Comment class. Once again, add the new class to the Models directory:

// Comment.cs
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Comment.cs
public class Comment
{
    public int Id { get; set; }
    
    [Required]
    public string Content { get; set; }
    
    [Required]
    public string Email { get; set; }
    
    [Required]
    public bool IsAnonymous { get; set; }

    public int ReviewId { get; set; }
    public Review Review { get; set; }
}

The comment class has an Id property for the primary key, Content of the comment, an Email property, and an IsAnonymous flag for users. Then there are ReviewId and Review properties to create a foreign key relationship between comments and reviews.

Last is the Category class. Here is its code:

// Category.cs
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Category.cs
public class Category
{
    public int Id { get; set; }
    
    [Required]
    [StringLength(32)]
    public string Name { get; set; }
}

This class is self-explanatory.

You probably noticed extensive use of the [Required] data annotation in the above classes. These designate a non-nullable field in the database and provide validation later down the road. You can also create your own custom validation attributes if you so desire. In addition to [Required], we also used the virtual keyword for some properties; those properties signify foreign key relationships with other tables.

To create the corresponding tables for these classes, you’ll need to create a DbContext class. The following code creates a context class called ReviewedContext:

    // https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/ReviewedContext.cs
    public class ReviewedContext : DbContext
    {
        public DbSet<Review> Reviews { get; set; }
        public DbSet<Category> Categories { get; set; }
        public DbSet<Comment> Comments { get; set; }

        public ReviewedContext()
        {
            Configuration.ProxyCreationEnabled = false;
        }
    }

EF Code First lets us generate database tables with nothing more than a few Plain Old CLR Objects (POCO).

Every property in this class corresponds to a table when generating the database. The Configuration.ProxyCreationEnabled = false; makes sure that the entities are retrieved as objects of their respective classes instead of proxies–making debugging much easier.

Next, we set up a database initializer. An initializer ensures that the database is created correctly when the data model undergoes any change. Without an initializer, you’ll have to manually delete the database if you make a change to one of your POCOs. There are a few different types of initializers to choose from: DropCreateDatabaseAlways and DropCreateDatabaseIfModelChanges. The names are self explanatory. The one we are going to use is DropCreateDatabaseIfModelChanges.

The DropCreateDatabaseAlways and DropCreateDatabaseIfModelChanges initializers have a side effect: they drop the tables (and thus data) in the database when the model structure changes. But EF Code First provides a third way to generate databases: Migrations. This new feature tracks changes to the database and does not lose data as the POCO classes change.

Here’s the code for our initializer:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/ReviewedContextInitializer.cs
// http://slipsum.com/
public class ReviewedContextInitializer : DropCreateDatabaseIfModelChanges<ReviewedContext>
{
    protected override void Seed(ReviewedContext context)
    {
        // Use the context to seed the db.
    }
}

The ReviewedContextInitializer class overrides the Seed() method. This gives us the ability to fill our database with some test data. Now, we need to visit the Global.asax file and add the following line to the Application_Start() method:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Global.asax.cs
Database.SetInitializer(new ReviewedContextInitializer());

Let’s create some repositories for retrieving data from the database, and we’ll go ahead and setup dependency injection (DI) with Ninject. If you don’t exactly know what DI or Inversion of Control (IoC) are, then take a moment to read this article.

Basically, the idea of dependency injection is to inject a concrete dependency into a class, as opposed to hard coding the class to be dependent upon the concrete dependency. In other words, it’s a decoupling of one concrete class from another. If that’s still clear as mud, let’s look at a brief example:

    public class Foo
    {
        private Bar _bar; 
        
        public Foo()
        {
            _bar = new Bar();
        }
    }

This code creates a class called Foo. It is dependent upon the functionality of an object of type Bar, and the Bar object is created within the Foo class. This can be difficult to maintain and unit test because:

  • Foo and Bar are tightly coupled. As a result, maintenance is less than ideal.
  • Foo is dependent upon a specific implementation of Bar, making unit testing difficult.

This code can be improved upon with just a few modifications. Take a look at the revised Foo class:

    public class Foo
    {
        private IBar _bar;
        
        public Foo(IBar bar)
        {
            _bar = bar;
        }
    }

In just under four years, ASP.NET MVC has seen its fourth release...

Now, the Foo class is not dependent upon a specific implementation of Bar. Instead, an object of a class implementing the IBar interface is supplied to Foo via the latter's constructor. This approach greatly improves maintainability, while also allowing us to inject any IBar object--making it easier to unit test our code.

With that brief description out of the way, let's get Ninject up and running. Fire up the Package Manager Console and run Install-Package Ninject.MVC3. This will add Ninject to our project.

The first repository we'll create is the ReviewsRepository, and it will implement the IReviewRepository interface. Here's the interface:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Abstract/IReviewRepository.cs
public interface IReviewRepository
{
    Review Get(int id);
    IQueryable<Review> GetAll();
    Review Add(Review review);
    Review Update(Review review);
    void Delete(int reviewId);
    IEnumerable<Review> GetByCategory(Category category);
    IEnumerable<Comment> GetReviewComments(int id);
}

This interface ensures that our review repositories provide the basic CRUD operations. We also get the utility of retrieving reviews by a specific category, as well as retrieving the comments for a given review. Now let's write a concrete class implementing this interface:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Repos/ReviewRepository.cs
public class ReviewRepository : IReviewRepository
{
    private ReviewedContext _db { get; set; }

    public ReviewRepository()
        :this (new ReviewedContext())
    {
        
    }

    public ReviewRepository(ReviewedContext db)
    {
        _db = db;
    }

    public Review Get(int id)
    {
        return _db.Reviews.SingleOrDefault(r => r.Id == id);
    }

    public IQueryable<Review> GetAll()
    {
        return _db.Reviews;
    }

    public Review Add(Review review)
    {
        _db.Reviews.Add(review);
        _db.SaveChanges();
        return review;
    }

    public Review Update(Review review)
    {
        _db.Entry(review).State = EntityState.Modified;
        _db.SaveChanges();
        return review;
    }

    public void Delete(int reviewId)
    {
        var review = Get(reviewId);
        _db.Reviews.Remove(review);
    }

    public IEnumerable<Review> GetByCategory(Category category)
    {
        return _db.Reviews.Where(r => r.CategoryId == category.Id);
    }

    public IEnumerable<Comment> GetReviewComments(int id)
    {
        return _db.Comments.Where(c => c.ReviewId == id);
    }
}

WebAPI is a MVC-like framework that we can use to easily create a RESTful API...

This repository relies on a ReviewedContext object that is stored as a class variable. This enables us to use LINQ in any of the repository's methods, making database interaction easy.

WebAPI has a nice feature that lets us add our own DI framework. This feature is beyond the scope of this tutorial, so be sure to read this article to help get that setup.

One of the most important locations for our code is the App_Start folder, which contains a file called NinjectCommonWeb.cs (installing Ninject automatically adds this file to App_Start). This file contains a static class called NinjectWebCommon, and it has a method called RegisterServices(). In this method, add the following code:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/App_Start/NinjectWebCommon.cs
kernel.Bind<IReviewRepository>().To<ReviewRepository>();
kernel.Bind<ICategoriesRepository>().To<CategoriesRepository>();
kernel.Bind<ICommentsRepository>().To<CommentsRepository>();

GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

The first three statements bind an interface to a concrete implementation of the interface, and the fourth line sets up the DI for WebAPI (the feature covered in the aforementioned article).

WebAPI

Let's now create the controllers for the API. WebAPI is a MVC-like framework that we can use to easily create a RESTful service, and it can run inside of a MVC4 application, in its own project, or it can be self hosted outside of IIS. But that's not all; it has many other features, such as: content negotiation (to automatically serialize it data into whatever format is requested), model binding, validation, and many more.

We first need to create an endpoint with WebAPI, and we do that by creating a class that inherits ApiController. Getting started with this is rather easy. Visual Studio 2012 has a new feature that creates a new, partially scaffolded controller.

Create ApiController

This will create a controller class with a few methods already defined for you. Here is an example:

// GET api/default1
public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

// GET api/default1/5
public string Get(int id)
{
    return "value";
}

// POST api/default1
public void Post(string value)
{
}

// PUT api/default1/5
public void Put(int id, string value)
{
}

// DELETE api/default1/5
public void Delete(int id)
{
}

The method names correspond to the HTTP verb they represent. We'll now create the ReviewsController class. The code a bit long, but pretty straightforward.

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Controllers/ReviewsController.cs
public class ReviewsController : ApiController
{
    private ICategoriesRepository _categoriesRepository { get; set; }
    private IReviewRepository _reviewRepository { get; set; }

    public ReviewsController(IReviewRepository reviewRepository, ICategoriesRepository categoriesRepository)
    {
        _reviewRepository = reviewRepository;
        _categoriesRepository = categoriesRepository;
    }

    // GET api/review
    public IEnumerable<Review> Get()
    {
        var reviews = _reviewRepository.GetAll();
        return reviews;
    }

    // GET api/review/5
    public HttpResponseMessage Get(int id)
    {
        var category = _reviewRepository.Get(id);
        if (category == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK, category);
    }

    // POST api/review
    public HttpResponseMessage Post(Review review)
    {
        var response = Request.CreateResponse(HttpStatusCode.Created, review);
        // Get the url to retrieve the newly created review.
        response.Headers.Location = new Uri(Request.RequestUri, string.Format("reviews/{0}", review.Id));
        _reviewRepository.Add(review);
        return response;
    }

    // PUT api/review/5
    public void Put(Review review)
    {
        _reviewRepository.Update(review);
    }

    // DELETE api/review/5
    public HttpResponseMessage Delete(int id)
    {
        _reviewRepository.Delete(id);
        return Request.CreateResponse(HttpStatusCode.NoContent);
    }

    // GET api/reviews/categories/{category}
    public HttpResponseMessage GetByCategory(string category)
    {

        var findCategory = _categoriesRepository.GetByName(category);
        if (findCategory == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK,_reviewRepository.GetByCategory(findCategory));
    }

    // GET api/reviews/comments/{id}
    public HttpResponseMessage GetReviewComments(int id)
    {

        var reviewComments = _reviewRepository.GetReviewComments(id);
        if (reviewComments == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK, reviewComments);
    }
}

This code uses IReviewRepository and ICategoriesRepository objects to perform the appropriate action (eg: retrieving data for GET requests, adding data with POST requests, etc). These respositories are injected with Ninject via Constructor Injection.

If you don't have Fiddler yet, get it now--even if you're not a .NET developer.

Notice that some of the methods return different data types. WebAPI gives us the ability to return a non-string data type (such as IEnumerable<Review>), and it will serialize the object to send in the server's response. You can also use the new HttpResonseMessage class to returning a specific HTTP status code along with the returned data. One way to create an HttpResponseMessage object is by calling Request.CreateResponse(responseCode, data).

We can properly test our WebAPI project with a tool such as Fiddler2. If you don't have Fiddler yet, get it now--even if you're not a .NET developer. Fiddler is a fantastic HTTP debugging tool. Once you're running Fiddler, click on RequestBuilder and enter the API URL you want to test. Then choose the appropriate request type. If making a POST request, be sure and specify a Content-Type: application/json header, and then place a valid JSON structure into the request body. The following image demonstrates a raw JSON POST request to the api/reviews URL:

When you send the request, you'll see something like the following image:

Notice the POST request's status code is a 201. WebAPI does a great job of returning the correct status code for a RESTfull web service. Have fun with Fiddler2, it's a fantastic tool!

With WebAPI, you can specify the routing for the controllers (just like MVC). In MVC4, a RouteConfig.cs file is added to the App_Start folder. Routes for a WebAPI project are just like MVC routes.

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/App_Start/RouteConfig.cs
routes.MapHttpRoute(
    name: "GetReviewComments",
    routeTemplate: "api/reviews/comments/{id}",
    defaults: new { id = RouteParameter.Optional, controller = "Reviews", action = "GetReviewComments" }
);

routes.MapHttpRoute(
    name: "GetByCategories",
    routeTemplate: "api/reviews/categories/{category}",
    defaults: new { category = RouteParameter.Optional, controller = "Reviews", action = "GetByCategory" }
);

routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

The DefaultApi route is automatically generated by Visual Studio. The other two routes are custom and map to specific methods on the Reviews controller. There are many articles and tutorials that provide good information on routing. Be sure to check this one out.

MVC4

That covers a lot of what WebAPI has to offer. Next, we'll write a few methods to display the data. We'll consume the API in a little bit, but for now we'll use the repositories in our HomeController. A HomeController was created by Visual Studio; let's just modify its methods to display the data. First, let's get a list of the categories in the Index method.

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Controllers/HomeController.cs
private ICategoriesRepository _categoriesRepository { get; set; }
private IReviewRepository _reviewRepository { get; set; }

public HomeController(ICategoriesRepository categoriesRepository, IReviewRepository reviewRepository)
{
    _categoriesRepository = categoriesRepository;
    _reviewRepository = reviewRepository;
}

public ActionResult Index()
{
    var categories = _categoriesRepository.GetAll();
    return View(categories);
}

Here, we continue to use DI by accepting the repositories as parameters for the HomeController constructor. Ninject automatically inject the appropriate concrete classes for us. Next, let's add some code to the Index view to display the categories:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Views/Home/Index.cshtml
@model IEnumerable<Reviewed.Models.Category>

<h3>Pick a Category:</h3>
<ul class="round">
    @foreach(var category in Model)
    {
        <li>
        <a href="@Url.Action("Reviews", new { id = @category.Name} )">@category.Name</a>
        </li>
    }
</ul>

This generates a list of categories that users can click on. Now add a new method to HomeController that retrieves a Review. We'll call this method Reviews, shown here:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Controllers/HomeController.cs
public ActionResult Reviews(string id)
{
    List<Review> reviews = new List<Review>();
    if (!string.IsNullOrWhiteSpace(id))
    {
        reviews = _reviewRepository.GetByCategory(_categoriesRepository.GetByName(id)).ToList();
    }
    else
    {
        reviews = _reviewRepository.GetAll().ToList();
    }

    foreach (var review in reviews)
    {
        var comments = _reviewRepository.GetReviewComments(review.Id);
        review.Comments = comments.ToList();
    }
    return View(reviews);
}

Because a route already exists for /{controller}/{action}/{id}, you can use a URL such as Home/Reviews/Doctors. The routing engine will pass "Doctors" as the id parameter to the Reviews method. We use the id as the category and retrieve all reviews associated with that category. If no category is provided, however, we simple retrieve all reviews in the database. Once we have all the reviews, we pass the review list to the view. Let's look at the view right now:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Views/Home/Reviews.cshtml
<div class="reviews">
@foreach(var review in Model)
{
    <h3>@review.Topic</h3>
    <p>
        @review.Content
    </p>
    
    var hasComments = review.Comments.Count > 0 ? "is-comments" : null;
    
    <ul class="@hasComments">
        @foreach(var comment in review.Comments)
        {
            <li>
                <strong>@(!comment.IsAnonymous ? string.Format("{0} says,", comment.Email) : "")</strong>
                <blockquote>@comment.Content</blockquote>
            </li>
        }
    </ul>
}
</div>

This code uses a new feature of MVC4. The <ul/> element's class attribute will not appear in the HTML if hasComments is null. Read more about this feature here.

JavaScript

No modern web app is complete without JavaScript, and we'll use it to consume our WebAPI service. We'll use Backbone.js for this; so, ahead on over and download Backbone and its dependency Underscore. Place the JavaScript files in the Scripts directory.

We'll take advantage of another new MVC4 feature called script bundling. In the App_Start folder, you'll find the BundleConfig.cs file. In this file, you can configure MVC4 to bundle JavaScript files together. Open it up and add a new bundle, like this:

bundles.Add(new ScriptBundle("~/bundles/backbone").Include(
        "~/Scripts/underscore*",
        "~/Scripts/backbone*"));

Then in the /Views/Shared/_Layout.cshtml file, add the following at the bottom of the page's body:

@Scripts.Render("~/bundles/backbone")

This will bundle your scripts if your application is in debug mode, or leave them alone with it turned off.

The MVC4 code we wrote for retrieving the review list is a fine way of displaying them, but all the new hawtness is using Ajax. So let's refactor the code to use Backbone.js. Through JavaScript, we'll retrieve the views asynchronously after the page has loaded. Create a new file in the Scripts folder called home.js. Add the following code to that file:

var Review = Backbone.Model.extend();
var Reviews = Backbone.Collection.extend({
    model: Review,
    url: '/api/reviews'
});
var Comment = Backbone.Model.extend({});
var Comments = Backbone.Collection.extend({
    model: Comment,
    url: '/api/reviews/comments/'
});

These are the JavaScript data models, each corresponding to a URL to retrieve data from the WebAPI service. Now let's write the view:

var ListReviews = Backbone.View.extend({
    el: '.reviews',
    initialize: function() {
        this.collection.on('reset', this.render, this);
        this.collection.fetch();
    },
    render: function() {
        this.collection.each(this.renderItem, this);
    },
    renderItem: function(model) {
        var view = new ReviewItem({
            model: model
        });
        this.$el.append(view.el);
    }
});

This view is for the entire list of reviews. When the collection's fetch() method is called, it triggers the reset event and then calls render(). The third parameter passed to the on() method is the scope, or what this will be in the render() callback. In the render() method, call the collection's each() method, passing the renderItem() method. The renderItem() method will be called on each item in the collection, generating a new ReviewItem for every review.

The code for ReviewItem follows:

var ReviewItem = Backbone.View.extend({
    events: {
        'click a': 'getComments'
    },
    tagName: 'li',
    initialize: function () {
        
        this.template = _.template($('#reviewsTemplate').html());
        this.collection = new Comments();
        this.collection.on('reset', this.loadComments, this);
        this.render();
    },
    render: function () {
        var html = this.template(this.model.toJSON());
        this.$el.append(html);
    },
    getComments: function () {
        this.collection.fetch({
            data: {
                Id: this.model.get('Id')
            }
        });
    },
    loadComments: function () {
        var self = this,
            item;
        this.comments = this.$el.find('ul');
        this.collection.each(function (comment) {
            item = new CommentItem({
                model: comment
            });
            self.comments.append(item.el);
        });
        
        this.$el.find('a').hide();
    }
});

WebAPI is a fantastic addition to the ASP.NET stack; a feature rich REST based API has never been easier.

The ReviewItem view is responsible for rendering each individual review. The initialize() method compiles the template used to display each review; this template resides in a <script/> element. Backbone pulls the template out of the <script/> element and combines it with the review.

A click event handler is also set up for loading the comments for each review. When the link is clicked, the getComments() method is called, fetching the comments by passing an Id to the WebAPI service. The fetch() method is merely an abstraction to jQuery's $.ajax method, so normal Ajax parameters, like data, can be passed in the fetch() call. Lastly, the loadComments() method will fire and create a new CommentItem view for each comment returned. The tagName on this view ensures the view is created with an <li/> as its $el property.

Next, let's look at the CommentItem view:

var CommentItem = Backbone.View.extend({
    tagName: 'li',
    initialize: function () {
        this.template = _.template($('#commentsTemplate').html());
        this.render();
    },
    render: function () {
        var html = this.template(this.model.toJSON());
        this.$el.html(html);
    }
    
});

This is a simple view that renders each comment. Now let's modify the Review.cshtml view as follows:

@model IEnumerable<Reviewed.Models.Review>

@section scripts {
    <script type="text/javascript" src="/Scripts/home.js"></script>
}

<div class="reviews">
    <ul></ul>
</div>

<script type="text/html" id="reviewsTemplate">

    <h3><%= Topic %></h3>
    <p>
        <%= Content %>
    </p>
    
    <a href="#comments">Load Comments</a>
    <ul></ul>

</script>

<script type="text/html" id="commentsTemplate">
<li>
    <strong><%= !IsAnonymous ? Email + " says," : "" %></strong>
    <blockquote><%= Content %></blockquote>
</li>       
</script>

Notice the @section scripts in the above code. This is not a new feature to MVC4, but it is a great tool to render specific pieces of JavaScript. In the _layout.cshtml file, there's also a @RenderSection("scripts", required: false) which renders the section defined in the view. The <script/> elements are Underscore templates to render content. They follow a Ruby-esque syntax, and anything inside <% %> is evaluated as a statement. Anything inside of <%= %> will output to the HTML. Loops and conditional statements can be used like this:

<ul>
<script type="text/html" id="template">
<% for (var i = 0; i < list.length; i++) { %>
    <li><%= list[i] %></li>
<% } %>
</ul>

<% if (someCondition) { %>
    <%= output %>
<% } %>
</script>

That's the template. To use it, do this:

var template = _.template($('#template').html());
var html = template({
    someCondition: true,
    output: 'hello world',
    list: ['foo', 'bar', 'bam']
});

There are many JavaScript templating frameworks available on the Web: Handlebars.js, mustache.js, and Hogan.js are quite popular. Be sure and check them out and pick the one that works for you.

Conclusion

WebAPI is a fantastic addition to the ASP.NET stack; a feature rich REST based API has never been easier. There are a lot of great new features in MVC4. Be sure and check them out! As I previously mentioned, the code for this example is available on Github. Fork it!


August 03 2012

15:23

ASP.NET AJAX Server Controls with Client-Side Functionality

Over the course of this tutorial, we’ll look at how to create a custom ASP.NET AJAX server control as a wrapper for the Google Maps JavaScript API. The server-side code will be written in C# (which I highly recommend), but it could just as easily be written in VB.NET. The focus will be on creating the control, and we’ll take a good look at the whole process of creating a custom ASP.NET AJAX server control, with client side functionality as well.


Getting Started

If you don’t already have Visual Studio installed, you’ll want to grab the latest express edition.

Once that’s done, fire it up and go to File -> New -> Project. From the list on the left, select Web, and then select ASP.NET AJAX Server Control from the main panel on the right. Name the project MapControl, and make sure that the option to create a new solution is selected (if applicable). Click OK to create the project.

Looking in Solution Explorer, you’ll notice that Visual Studio has generated some files for us already. We’ll examine the generated code a bit, but before we do, let’s rename the files and the classes contained in the files.

  • Rename ClientControl1.js to GoogleMap.js
  • Rename ClientControl1.resx to GoogleMap.resx
  • Rename ServerControl1.cs to GoogleMap.cs

Now, hit Control + H to bring up the Quick Replace window. Select the appropriate options to replace ServerControl1 with GoogleMap. Be sure that it’s set to look in the whole project, and not just the current file, and then click Replace All. Now do the same thing to replace ClientControl1 with GoogleMap.


GoogleMap.js – Client-Side

Let’s break GoogleMap.js apart piece by piece.

<reference name="MicrosoftAjax.js"/>

This line simply tells Visual Studio’s IntelliSense engine to include the types and methods contained within MicrosoftAjax.js in the IntelliSense dropdowns.

Type.registerNamespace("MapControl");

MapControl.GoogleMap = function(element) {
    MapControl.GoogleMap.initializeBase(this, [element]);
}

The first line registers the namespace MapControl with the AJAX framework. The rest of the code here acts as the constructor for the client class of our custom control. This is where we will declare all private properties on the client side.

MapControl.GoogleMap.prototype = {
    initialize: function() {
        MapControl.GoogleMap.callBaseMethod(this, 'initialize');
        
        // Add custom initialization here
    },
    dispose: function() {        
        //Add custom dispose actions here
        MapControl.GoogleMap.callBaseMethod(this, 'dispose');
    }
}

Here our custom control’s client class is defined using the prototype model. This is where all methods for the client class are declared. As you probably guessed, the initialize and dispose methods are called automatically upon the creation and destruction of an instance of this class, respectively. In this case, we’ll make use of the initialize method to make a call to the Google Maps API and set up the map.

MapControl.GoogleMap.registerClass('MapControl.GoogleMap', Sys.UI.Control);

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

The first part here registers the class with the defined class name and namespace, and also assigns a base class (Sys.UI.Control). Lastly, a call is made to Sys.Application.notifyScriptLoaded(), which notifies the Microsoft AJAX framework that the script has finished loading. Note that this is no longer necessary in the .NET Framework 4 and above.


GoogleMap.cs – Server-Side Code

The file named GoogleMap.cs is where all of the server-side code is contained. Opening the file, the first thing you’ll notice is that it contains a class called GoogleMap, which inherits from the ScriptControl class. ScriptControl is an abstract base class which inherits from WebControl, and implements IScriptControl.

public class GoogleMap : ScriptControl

Although it would be fine to leave that as it is, we can create a more flexible situation by implementing IScriptControl directly, and inheriting from WebControl instead. By doing so, we open up the possibility of inheriting from a more complex base class, such as ListControl. I also have run across problems inheriting from ScriptControl under various circumstances. Let’s change it now to the following:

public class GoogleMap : WebControl, IScriptControl

Passing by the constructor, you’ll see the GetScriptDescriptors and GetScriptReferences methods.

protected override IEnumerable<ScriptDescriptor>
            GetScriptDescriptors()
{
    ScriptControlDescriptor descriptor = new ScriptControlDescriptor("MapControl.GoogleMap", this.ClientID);
    yield return descriptor;
}

// Generate the script reference
protected override IEnumerable<ScriptReference>
        GetScriptReferences()
{
    yield return new ScriptReference("MapControl.GoogleMap.js", this.GetType().Assembly.FullName);
}

Since we’re implementing IScriptControl directly, the access level modifiers will need to be changed from protected to public, and the override modifiers should be removed altogether.

In the GetScriptDescriptors method, the ScriptControlDescriptor object that is created and returned tells the framework which client class to instantiate, and also passes the ID of the HTML element associated with the current instance of the control. As you’ll see in the next section, this is also the mechanism through which property values are passed from server-side code to the client class.

The code in the GetScriptReferences method simply adds a ScriptReference to our client code file – it will be loaded automatically by the framework when needed.


Defining Properties

Alright, now that we have some background information, it’s time to start building the map control. To start out, we’ll add some properties to the server-side class (in GoogleMap.cs), sticking with just the basics for now. The zoom and center point of the map is what comes to mind as necessary properties.

  • Zoom
  • CenterLatitude
  • CenterLongitude
private int _Zoom = 8;
public int Zoom
{
    get { return this._Zoom; }
    set { this._Zoom = value; }
}

public double CenterLatitude { get; set; }
public double CenterLongitude { get; set; }

You might be wondering how the values of these properties defined in the server-side class are going to end up in the client class. Well, this is where the ScriptControlDescriptor comes into play. By simply calling the AddProperty method of the ScriptControlDescriptor and passing in the client-side property name and current value, the framework takes care of all the details.

public IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
    ScriptControlDescriptor descriptor = new ScriptControlDescriptor("MapControl.GoogleMap", this.ClientID);
    descriptor.AddProperty("zoom", this.Zoom);
    descriptor.AddProperty("centerLatitude", this.CenterLatitude);
    descriptor.AddProperty("centerLongitude", this.CenterLongitude);
    yield return descriptor;
}

Now we need to define the properties in the client class. Open GoogleMap.js and modify the constructor to look like the following:

MapControl.GoogleMap = function(element) {
    MapControl.GoogleMap.initializeBase(this, [element]);

    this._zoom = null;
    this._centerLatitude = null;
    this._centerLongitude = null;
}

To make these properties accessible to the ASP.NET AJAX framework, we need to define get and set accessors. These accessor methods must follow the naming conventions of the framework – as an example, for the zoom property the accessors should be named get_zoom and set_zoom. Add the following code to the prototype declaration for the class:

get_zoom: function() {
    return this._zoom;
},
set_zoom: function(value) {
    if (this._zoom !== value) {
        this._zoom = value;
        this.raisePropertyChanged("zoom");
    }
},
get_centerLatitude: function() {
    return this._centerLatitude;
},
set_centerLatitude: function(value) {
    if (this._centerLatitude !== value) {
        this._centerLatitude = value;
        this.raisePropertyChanged("centerLatitude");
    }
},
get_centerLongitude: function() {
    return this._centerLongitude;
},
set_centerLongitude: function(value) {
    if (this._centerLongitude !== value) {
        this._centerLongitude = value;
        this.raisePropertyChanged("centerLongitude");
    }
}

The raisePropertyChanged method is defined on an ancestor class, Sys.Component, and raises the propertyChanged event for the specified property.


Creating the Map

We’ll be writing the code that creates the map in just a minute, but first we need to define a property that will store the map object. That way we will be able to access the map after it’s created – in an event handler, for example. Add the following property declaration to the constructor for the client class (GoogleMap.js) after the other properties:

    this._mapObj = null;

Now let’s add a createMap function to the prototype:

createMap: function() {
        var centerPoint = new google.maps.LatLng(this.get_centerLatitude(), this.get_centerLongitude());
        var options = {
            zoom: this.get_zoom(),
            center: centerPoint,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };
      this._mapObj = new google.maps.Map(this._element, options);
}

The google.maps.LatLng type is defined in the Google Maps JavaScript API (which we will reference later), and as you probably guessed, represents a point on the map defined by latitude/longitude. In the map options, we’re setting the zoom and center point of the map to the values passed in by the framework. A map type of roadmap is set, but this could easily be set to satellite or terrain.

The last line creates the google.maps.Map object, storing a reference to it in the property we created above.

You’ll notice the constructor takes two parameters – most notably the first one is a reference to the HTML element associated with the control – the second one is just passing in the map options.

All that remains now on the client side is to call our new createMap function from the initialize function, so that the map is created when the control is initialized.

initialize: function() {
    MapControl.GoogleMap.callBaseMethod(this, 'initialize');

    this.createMap();
},

Finishing Touches

Back in the server-side code (GoogleMap.cs), we need to override the TagKey property in our GoogleMap class, and return a value of HtmlTextWriterTag.Div. This will ensure that the control is rendered as an html div element.

protected override HtmlTextWriterTag TagKey
{
    get
    {
        return HtmlTextWriterTag.Div;
    }
}

Now let’s add a private field of type ScriptManager to the class – we’ll call it sm. This will store a reference to the page’s ScriptManager, which we’ll use in a bit.

    private ScriptManager sm;

Next, we’ll override the OnPreRender and Render methods of the GoogleMap class.

protected override void OnPreRender(EventArgs e)
{
    if (!this.DesignMode)
    {
        // Test for ScriptManager and register if it exists
        sm = ScriptManager.GetCurrent(Page);

        if (sm == null)
            throw new HttpException("A ScriptManager control must exist on the current page.");

        sm.RegisterScriptControl(this);
    }

    base.OnPreRender(e);
}

Here, we’re basically just getting the current page’s ScriptManager (and making sure it exists!), and then registering the current instance of the control with it. This step, as well as the next, is absolutely necessary – otherwise the client side of the control won’t work.

protected override void Render(HtmlTextWriter writer)
{
    if (!this.DesignMode)
        sm.RegisterScriptDescriptors(this);

    base.Render(writer);
}

This registers the control’s script descriptors with the page’s ScriptManagersm is a reference to the ScriptManager that we retrieved in the OnPreRender method.

Last of all (for now!), we’ll make this control compatible with partial trust scenarios, as is quite common due to the popularity of shared web hosting. In Solution Explorer, open the Properties folder, and then open AssemblyInfo.cs. Add the following reference near the top of the file.

using System.Security;

Add the following line somewhere in the middle or near the bottom of the file.

[assembly: AllowPartiallyTrustedCallers()]

Testing the Map Control

Now we’re ready to take the control for a test drive. We’ll come back later and add more functionality, but for now let’s set up a small website to test the control. Right click on the solution node in Solution Explorer, and select Add -> New Web Site. Make sure that ASP.NET Web Site is selected from the list. Name the website MapControlTest, and click OK.

In the newly created Default.aspx, add a ScriptManager to the page, just inside of the form element. Remember from the last section that this is required on the page in order for our GoogleMap control to work.

<body>
    <form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="ScriptManager1">
    </asp:ScriptManager>
    <div>
    </div>
    </form>
</body>

Right click on the MapControlTest website node in Solution Explorer, and select Add Reference from the popup menu. Navigate to the Projects tab, select MapControl, and click OK. Now we need to register the assembly and namespace in Default.aspx. Add the following line near the top of the file, just above the DOCTYPE declaration.

<%@ Register Namespace="MapControl" TagPrefix="mc" Assembly="MapControl" %>

At this point, you should build the solution (Build -> Build Solution or the F6 key) so that IntelliSense works correctly for the new control. Now add the following control declaration to the page.

<mc:GoogleMap runat="server" CenterLatitude="36.1658" CenterLongitude="-86.7844" Width="500" Height="500">
</mc:GoogleMap>

Lastly, add the Google Maps JavaScript API script (in the head of the page).

<script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>

Now right click in the editor (for Default.aspx) and select View in Browser from the popup menu. Your browser should open and load the page with the map centered on Nashville, TN. You can play around with the control properties to make sure everything’s working properly – specifically, try adding the Zoom property and watch the effect on the map.


Adding Markers

But a plain map isn’t so exciting, so in this section we’ll add some functionality that allows markers to be displayed on the map.

First, we’ll need a class that contains information about each marker. Right click on the MapControl project node in Solution Explorer, and select Add -> Class from the popup menu. Name the class MapMarker and click OK.

The Serializable attribute needs to be added to the class to allow it to be serialized and passed to the client-side code.

Add properties to the class so that the class declaration looks like this.

[Serializable]
public class MapMarker
{
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public string Title { get; set; }
    public virtual string InfoWindowHtml { get; set; }

    public MapMarker()
    {
    }
}

The Latitude and Longitude properties are fairly obvious – the Title property is for the tooltip text that will be displayed when the mouse is hovering over the marker, and the InfoWindowHtml property will contain the html to display in a popup when the marker is clicked.

In the server-side GoogleMap class (GoogleMap.cs) we’ll add a property of a list of MapMarkers. The PersistenceMode attribute specifies that the property persists within the ASP.NET server control as a nested tag.

private List<MapMarker> markers = new List<MapMarker>();

[PersistenceMode(PersistenceMode.InnerProperty)]
public List<MapMarker> Markers
{
    get { return this.markers; }
} 

The ParseChildren attribute also needs to be set on the GoogleMap
class for this to work.

[ParseChildren(true)]
public class GoogleMap : WebControl, IScriptControl

Now we’ll add another property to the ScriptControlDescriptor in the GetScriptDescriptors method for the new property.

public IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
    ScriptControlDescriptor descriptor = new ScriptControlDescriptor("MapControl.GoogleMap", this.ClientID);
    descriptor.AddProperty("zoom", this.Zoom);
    descriptor.AddProperty("centerLatitude", this.CenterLatitude);
    descriptor.AddProperty("centerLongitude", this.CenterLongitude);
    descriptor.AddProperty("markers", this.Markers);
    yield return descriptor;
}

Switching back to the client-side code (GoogleMap.js), add a new
property declaration named _markers to the constructor. While we’re
here, let’s also add a property called _infoWindow, which will
store a reference to a popup that appears when a marker is clicked.

MapControl.GoogleMap = function(element) {
    MapControl.GoogleMap.initializeBase(this, [element]);

    this._zoom = null;
    this._centerLatitude = null;
    this._centerLongitude = null;
    this._markers = null;

    this._mapObj = null;
    this._infoWindow = null;
}

Now we need to add the get and set accessors for the property, as before.

get_markers: function() {
    return this._markers;
},
set_markers: function(value) {
    if (this._markers !== value) {
        this._markers = value;
        this.raisePropertyChanged("markers");
    }
},

All that remains now is to add the code that will display the markers to the createMap function.

createMap: function() {
    var centerPoint = new google.maps.LatLng(this.get_centerLatitude(), this.get_centerLongitude());
    var options = {
        zoom: this.get_zoom(),
        center: centerPoint,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };

    this._mapObj = new google.maps.Map(this._element, options);

    var markers = this.get_markers();
    if (markers != null) {
        for (var i = 0; i < markers.length; i++) {
            var marker = new google.maps.Marker
            (
                {
                    position: new google.maps.LatLng(markers[i].Latitude, markers[i].Longitude),
                    map: this._mapObj,
                    title: markers[i].Title
                }
            );

            var that = this;
            (function(marker, infoHtml) {
                google.maps.event.addListener(marker, 'click', function() {

                    if (!that._infoWindow) {
                        that._infoWindow = new google.maps.InfoWindow();
                    }

                    that._infoWindow.setContent(infoHtml);

                    that._infoWindow.open(that._mapObj, marker);

                });
            })(marker, markers[i].InfoWindowHtml);
        }
    }
}

This might look complicated, but it’s really not – I’ll break it apart and go through it piece by piece.

var markers = this.get_markers();
if (markers != null) {
   for (var i = 0; i < markers.length; i++) {

Here we’re just getting the array of markers, making sure that it’s not a null reference, and iterating through the array.

var marker = new google.maps.Marker
(
    {
        position: new google.maps.LatLng(markers[i].Latitude, markers[i].Longitude),
        map: this._mapObj,
        title: markers[i].Title
    }
);

This snippet of code is what actually adds the marker to the map – grabbing the position and title of the marker from the array through markers[i], and setting the map property to the map that was created earlier.

var that = this;
(function(marker, infoHtml) {
    google.maps.event.addListener(marker, 'click', function() {

        if (!that._infoWindow) {
            that._infoWindow = new google.maps.InfoWindow();
        }

        that._infoWindow.setContent(infoHtml);

        that._infoWindow.open(that._mapObj, marker);

    });
})(marker, markers[i].InfoWindowHtml);

The first line is to preserve the current context into the event handler – this will no longer reference our custom control there, so we use that instead. Since we’re iterating through the array and the marker and i variables are changing, we need to pass the marker and infoHtml variables into a new self-executing anonymous function so that when the event handler is fired (which will be later), the variables still have their correct values. The code inside of the event handler is pretty straightforward – basically just setting the content of and opening the popup info window.

Now we can add markers to the map like this (you might need to build the solution again first for IntelliSense to work).

<mc:GoogleMap runat="server" CenterLatitude="36.1658" CenterLongitude="-86.7844" Width="500" Height="500">
    <Markers>
        <mc:MapMarker Latitude="36.1658" Longitude="-86.7844" Title="Nashville, TN" InfoWindowHtml="<code>Nashville, TN</code>" />
    </Markers>
</mc:GoogleMap>

If markers would be placed on the map through user input, there would be security issues to consider – specifically you would need to make sure that user input for the Title property is html encoded, and that input to the InfoWindowHtml property does not contain any dangerous code. As always, security in a production application should be of primary concern.


Conclusion

Throughout this tutorial, you hopefully not only learned a lot about creating a custom ASP.NET AJAX server control with client-side functionality, but also a bit about the Google Maps API. Some of you may be thinking that this technology is outdated, as it applies to ASP.NET Web Forms. However, Web Forms is still a very viable option for new web development, especially for individual developers working on short projects, and needing to get things done quickly.

ASP.NET MVC is probably better in terms of flexibility and testability. The point is that this tutorial isn’t advocating the use of one technology over another; it simply teaches a technique that can serve to be quite handy when building ASP.NET Web Forms applications.


March 01 2012

23:18

30 Days to Learn C#: New Premium Course

We’re pleased to announce our latest Tuts+ Premium course: “30 Days to Learn C#.” My aim is to introduce you to the C# language (and a tiny bit of the .NET Framework), and give you a clear understanding of the fundamentals needed to start writing applications in C#.

All I ask for is a few minutes of your time each day for a month.

This is by no means a fully exhaustive look at the language, but I will get you familiar with the language and platform. I won’t lie; some of the material is easier to grasp if you have some programming background. But I do try to explain things from the standpoint of a complete beginner. So even if you haven’t programmed before, I hope you’ll find my explanations of programming concepts and fundamentals understandable.

All I ask is for a few minutes of your time each day for a month. Most lessons are between ten and fifteen minutes. Naturally, some are shorter and some are longer, but I promise none go over 31 minutes!

Ready to become a better programmer?


Tuts+ Premium

The recently re-launched Tuts+ Premium is a service that provides top-tier training in a variety of creative fields. Whether you prefer books, visual training, or in depth tutorials, we have you covered. While we unfortunately can’t afford to provide the service for free, it’s only $19 a month – less than you’d spend on dinner.

I hope you’ll consider checking it out! In addition to learning a huge variety of new skills, it’s also a fantastic way to say thank you to Nettuts+.


November 29 2011

15:49

Why Many Developers Hate ASP.NET… and Why They’re Wrong

Few platforms draw the same amount of ire as ASP.NET (or .NET in general) from the development community. While there are certainly valid criticisms of the platform (what platform doesn’t?), the majority of negativity comes from those who haven’t spent any time with .NET. Those developers typically rely on misconceptions or flat out hatred to base their opinion, and they do a disservice to others looking to learn a new technology and to the platform itself. So, let’s examine these excuses and add a dose of reality on why you shouldn’t listen to the rabble and give ASP.NET a try.


It’s Made by Microsoft

This is probably the #1 reason for all ASP.NET hate.

Microsoft is a massive software corporation, and like all other corporations, they’re in business to make money. Duh, right? Unfortunately, this is probably the #1 reason for all the ASP.NET hate: it’s a Microsoft technology, and the “evil” taint still lingers over the giant in many people’s minds. I’ve always found this interesting because the other major technology companies, such as Google and Apple, are just as “evil” as Microsoft, but the zealots fans of those other companies typically turn a blind eye (or are in denial) to those “evils.” I personally think the majority of people are normal minded people. They don’t really care who makes a product as long as that product works well.

But I’m not talking about normal people, right? Normal people don’t see a headline containing "ASP.NET" and have an automatic urge to make an inane comment. Instead, I’m talking about the developers (and geeks) that treat technology, and/or the company that creates it, as a religion. I’m not kidding—find any article or tutorial on X platform, and chances are good you’ll find comments stating “X Sucks! Y Rules!”

It’s as if these people are on some weird crusade to defend their chosen tech/company to the hilt and bash the competition in an attempt to bring the unwashed masses into their fold.

It’s sad that the technology = religion mindset exists. Technology is a just tool, and a real developer is going to try multiple tools in order to find the right one for the job. That’s not to say that someone cannot dislike a technology, but to echo our parents, "you don’t know you don’t like it until you try it." In order for someone to truly dislike something, that person has to try it. So don’t listen to the rabble—they haven’t tried it and haven’t formed an informed opinion. If you decide you want to try it, they’ll attempt to dissuade you by saying it costs too much.


Misconception: It’s Expensive

Find any article comparing ASP.NET with any other platform, and you’ll read, either in the article or in the comments, “ASP.NET costs more than [insert any other server-side tech other than ColdFusion here].” Before discussing the actual cost of something, it’s important to put the term “expensive” in context, as what is expensive for personal use can be considered cheap in a business environment. In business, there are many factors that make up the “cost” of a product. The initial price obviously needs to be considered, but the benefit of the product is also factored into the overall cost.

If a product is $10,000, but it saves the company $1,000 a month, the purchase decision is a no brainer. But on a personal level, it would more than likely be difficult to justify the initial $10,000 cost.

So when talking about cost, it’s important to keep things in perspective according to the context in which it will be incurred.  To keep things simple, I’m going to assume that if you’re reading this, you’re more concerned with the personal cost than the business cost (if I’m wrong with that assumption, I’ll make this very easy for you: if you have a Windows environment, ASP.NET is cheap).

You don’t actually need Windows to develop ASP.NET apps, thanks to the Mono project.

Let’s get the biggest cost out of the way: the Windows operating system. You don’t actually need Windows to develop ASP.NET apps, thanks to the Mono project (more on this later), but Mono typically lags behind the official .NET Framework coming out of Microsoft’s ovens. So, if you want all of the latest features and .NET-goodness, you’ll need Windows. Most OEMs (companies like Dell, HP, Acer, etc) ship their computers with Windows already installed; so, if you buy your computer from an electronics chain store like Best Buy, chances are pretty darn good that the computer will have Windows. If you’re more of a power user and build your own computers or plan on run Windows in a virtual machine, you will have to purchase a copy of Windows. An OEM version of Windows will run you anywhere from $99 to $189, depending on which version of Windows you buy. You don’t need to have Professional ($139 OEM) or Ultimate ($189 OEM), but if you’re a power user, you’ll more than likely want to opt for one of those two versions (OEM versions are cheaper than retail versions, but they are tied to the hardware you activate them on).

Development Costs

With that out of the way, let’s review development costs. ASP.NET development is thought to be expensive for two reasons.

  1. It’s Microsoft. They supposedly don’t give anything away for free, but that’s exactly what they do. Everything you need to develop ASP.NET applications (or .NET apps in general) can be obtained without spending a dime.

    Beginners: First, Microsoft gives away WebMatrix, a development environment targeted at beginners. It combines an integrated development environment (IDE) with a built-in web server (IIS Express) and a database engine (SQL Compact Edition). It also has tools to help users deploy their websites to a remote host.

    Advanced Users: For more advanced developers, Microsoft makes available the Express editions of Visual Studio. Like WebMatrix, these trimmed down versions of Visual Studio are free, but they offer some of the features and abilities found in the full versions of Visual Studio. The web-focused Express product is Visual Web Developer Express (VWD), and it, too, has a built-in web server. It doesn’t have a built-in database engine, but Microsoft gives away SQL Server Express, a trimmed down version of SQL Server, that you can use for development (and even some deployment situations). If you later decide you like Visual Studio and want to purchase the full version, the projects you developed with VWD can be opened with Visual Studio.

    Students: And if you’re a student, you can get lots of Microsoft software (Visual Studio Pro, Windows Server OSs, and Expression Studio to name just a few) for free through the DreamSpark program.

  2. Secondly, Windows-based hosting is thought to be mucho expensive-o. Ten years ago, that argument held some weight. Today however, you can find no shortage of reasonably priced hosting for ASP.NET. DailyRazor (the company I use) starts plans at $2/month, and you can find other hosting providers that sell their services at low prices.

So cost isn’t really a problem, but naysayers will then say ASP.NET is only suitable for enterprise-class websites as opposed to your personal site(s).


Misconception: It’s Horrible for Small, Personal Websites

One only has to look at the .NET Framework’s class library to get the “this is for enterprise” feeling.

It’s actually easy to get into the mindset that ASP.NET isn’t suited for anything but large-scale sites. Microsoft is a platform company, after all, and their products are primarily focused towards business solutions. .NET isn’t really different in that respect; it’s huge in business environments, and its foothold continues to grow as Microsoft expands new and revitalized products like Azure (Microsoft’s Cloud platform) and Windows Phone, respectively. One only has to look at the .NET Framework’s class library to get the “this is for enterprise” feeling. It’s almost as if the framework guides developers to a mindset that (ASP).NET applications needs to be highly structured masterpieces of object oriented design. A lot of .NET is complex, and doing simple things isn’t always as simple as it should be. It sounds like I’m making the naysayer’s case, doesn’t it? I kind of am, but there two things to consider.

Simplicity

First, Microsoft wants you developing on their platform, and they’ve recognized that it needs some (perhaps a lot of) simplification in order to grow. After all, PHP is as popular as it is specifically because of its simplicity, and that’s the primary reason Microsoft released WebMatrix: to offer new developers (either to .NET development or web development in general) a simplified approach to writing sites with ASP.NET.

Not only is the all-in-one IDE easy to use, but Microsoft created a simplified API to make ASP.NET development easier and less complex.

Multiple Approaches

You can also build sites with the same kind of “scripting” mentality that thrives in PHP.

Second, you don’t have to fall into the “highly structured or die” mentality. There are many approaches to ASP.NET development. If you want to create highly structured masterpieces of object oriented design, you can. But you can also build sites with the same kind of “scripting” mentality that thrives in PHP. The point is, ASP.NET development is flexible enough to fit your needs, and you can choose the development approach that best fits you.

Oddly enough, there’s a somewhat prevalent idea that ASP.NET isn’t suitable for enterprise-class websites. o.0


Misconception: It’s Horrible for Large, Enterprise-class Websites

I honestly have no idea where this comes from because, as mentioned earlier, ASP.NET excels in the enterprise space. But don’t just take my word for it; let’s examine a real-world website (well, a network of websites) that run on ASP.NET.

Have you ever heard of StackOverflow.com? You probably have, and if you haven’t, it’s a Q&A website for developers (regardless of technology). Its an invaluable resource, and one I find myself visiting quite often.

StackOverflow is a member of the Stack Exchange Network, a network of Q&A websites for a variety of topics: servers, databases, legos, sci-fi, cars, and so on, and so on. There are currently 71 sites in the network, and it continues to grow.

The folks at the Stack Exchange Network are pretty open about their network. Much of the code running on the site is open sourced, and they often provide information regarding the network in general. In a March 2011 blog post, Kyle Brandt provided an overview of the technology powering the Stack Exchange Network, as well as the traffic the network gets. Keep in mind this information is regarding the entire Stack Exchange Network. It gets 95 million page views a month and handles 800 HTTP requests a second, and those requests are handled by twelve (yes only twelve) Windows web servers, two MS SQL Server servers, two Linux load balancers, and two Linux caching servers (fail-over hardware is not included in that count).

Reread those stats—I’ll wait. Phenomenal, right? It’s amazing that only twelve servers, serving many different websites, handle that amount of traffic. It’s a testament to just how good Microsoft’s server and application architecture is.


It’s Statically Typed

Dynamic languages rule the web. Be it on the server side, where languages like PHP, Ruby, Python, and Perl live, or in the browser with JavaScript, dynamic languages are the backbone of the web. It’s not that these languages are better, but they are quickly adopted because dynamic languages are typically easier to learn and understand than statically typed languages.

So what we essentially end up with is a massive community of developers who have only used dynamic languages, and that community almost has an aversion to static languages.

I fully understand the mindset. I used to be one of those people, and I understand the desire to stay within one’s comfort zone. After all, dynamic languages are lenient, and there is some comfort found in that leniency.

Static languages have a strict type system.

But there’s a bad side to that leniency; it is extremely easy to introduce bugs into your app if you’re not careful. You’ll typically not find that bug until runtime, and a common cause of bugs is the assignment of a different and unintended type of value to a critical variable. This is where the primary benefit of static languages comes in: type safety. Static languages have a strict type system, in that a variable can only contain one type of value (eg: a variable declared as an integer can only contain integer values; it cannot contain a string or floating point numbers). If you mistakenly assign a string to a number variable, you will immediately know of the error when you compile the code because the compiler with halt and alert you to the error.

Type safety can also alleviate the type checking you need to perform in dynamic languages. For example, how many times have you written code like the following to ensure the data a function accepts is of the expected type:

function add($a, $b) {
    if (is_int($a) && is_int($b)) {
        return $a + $b;
    }

    // throw error
}

This is a simple PHP function that adds two numbers together. In order to ensure predictable results, checking if the supplied values are of the appropriate type is imperative (admittedly, the type checking here isn’t complete; there are numeric types other than integer); otherwise, your app could break at unexpected times. In contrast, let’s look at the C# equivalent code:

int add(int a, int b) {
    return a + b;
}

This code defines an add() method. C# is the most popular .NET language, and it is purely object oriented. There are no functions; only methods of a class. This method accepts two integer values (denoted by the int keyword before the a and b identifiers), and it returns an integer value as denoted by the int before add. Because C# is a static language, the type checking is performed by the compiler—not by you. So, if you were to call this method, pass a string as one of the arguments, like add("hello", 123), and attempt to compile the code, the compiler will stop the build process and alert you to the error. Chances are, however, you wouldn’t even try to compile the code because Visual Studio performs its own type and syntax checking; the IDE will warn you of errors before you even try to compile (see the below screenshot of Visual Studio 2010).

Also consider that Microsoft continually updates and improves the C# language. In the first two versions of the language, you had to identify a variable’s type when declaring it like this:

XmlDocument document = new XmlDocument();

This code creates an instance of the XmlDocument class by declaring its type prior to the variable’s name. Admittedly, this syntax is rather cumbersome and adds far more typing, but as of C# 3.0, however, you can simply use the var keyword to define a variable, like this:

var document = new XmlDocument();

There are .NET-enabled versions of PHP, Ruby, Python, and PERL.

The compiler is smart enough to infer that the document variable is an XmlDocument. This syntax sort of blurs the line between dynamic and static languages. You get simple, typeless variable declarations with the benefits of type safety… a win-win in my book.

But if I still can’t persuade you to give C# a try, ASP.NET sites do not have to be written in C# (or even VB.NET… but who would want to do that?). There are .NET-enabled versions of PHP, Ruby, Python, and PERL (and others) that you can use to write ASP.NET sites with, and they are just as dynamic as usual thanks to the Dynamic Language Runtime, a feature of .NET 4. So while I recommend anyone picking up ASP.NET to learn C#, you don’t have to leave your comfort zone if you don’t want to (but if you do the benefits are worth it).


It’s Compiled

The same dynamic languages that rule the web are also interpreted, and there is a certain benefit that comes with interpreted languages. Unlike compiled environments like ASP.NET where you typically write your code, compile it, and upload it, interpreted environments let you simply write your code and upload it. The common idea being that compiled environments require an extra step in development, and that wastes time. But it really doesn’t. The compiler gives us many benefits that you just cannot get in an interpreted-language environment.

First, the compiler checks the code and can give you warnings. Warnings are just that: a warning. It’s something you’ve done that may be a bug, but it won’t stop the compiler from compiling your code. Let’s look at the following code that would cause a warning:

string DoSomething()
{
    var foo = "Hello";
    var bar = "World!";

    return foo;
}

This code defines a method called DoSomething(). Its body creates two string objects, foo and bar, and foo is returned to the caller. The bar variable is not used, so the compiler would issue a warning stating that bar is assigned but its value is never used. It may be that I created bar and forgot about it, or that I ended up not needing it. But it could be the source of a bug if I forgot bar already existed and used it elsewhere in the method. The compiler brings it to my attention so that I may address it and avoid future bugs. Here’s a screenshot of what Visual Studio tells me:

Do you want another example? Sure you do:

void DoSomethingElse()
{
    var foo = true;

    if (foo = false)
    {
        // this code will never execute
    }
}

In this method definition, a boolean variable, foo, and defined as true. It is then used in an if statement, where it is assigned a value of false. That may be exactly what I intended (although I would argue that I should never do that), but chances are I meant foo == false (yes, the logical not ! operator would be better here… but it doesn’t work for my example). It’s not an error, however, so the compiler will compile the code. However, it will issue a warning asking if I meant == instead of =. These are issues that I would have found an in interpreted environment, but I would have needed to run the app and test it in order to find those mistakes.

Second, the compiler checks the code for errors. Naturally, a compiler cannot catch logic errors, but it can type check and check the code’s syntax. Although, a decent IDE will do these things for you without needing a compiler, and Visual Studio does.

Last, you get a performance boost. Compiled code runs faster than interpreted. Admittedly, .NET isn’t a truly compiled environment. Our code is compiled into an intermediate language (IL), which is then just-in-time compiled by the .NET runtime. The IL, however, is optimized, and the .NET runtime executes it. But it’s still very fast.

In fact, ASP.NET’s raw performance is faster than PHP’s.


Misconception: It’s Closed

Microsoft makes the source code for the .NET Framework available for free.

Microsoft is a company that sells software, and they are naturally very protective of their products’ source code. So, one might think that ASP.NET (and .NET in general) is closed source, but that is not the case. Microsoft makes the source code for the .NET Framework available for free, and you can step into the code while debugging your own apps. You can even build your own personal version of the .NET Framework.

Microsoft also gives you access to the source code of ASP.NET releases, like WebForms and MVC, via CodePlex; giving you the ability to test new features and provide feedback to the ASP.NET team. I encourage every developer using .NET to download these free resources and study them. You’ll gain a greater understanding of how it works under the hood, and you can apply that same knowledge when writing your own code.


It’s Windows Only

Microsoft’s openness with the .NET Framework is what helped birth the Mono project, a cross-platform version of the .NET Framework. While Mono isn’t officially supported by Microsoft, the project has been publicly acknowledged by Microsoft. Mono isn’t going away; in fact, it’s growing in popularity  Regardless of what your favorite platform, you can probably use the .NET Framework and C# to write apps for it (you can even write iOS apps with Mono!).


It’s Not in Demand

Lastly, it’s often espoused that ASP.NET is not in demand, and that simply is not true. Demand is somewhat subjective because different areas of the world and in the country you live have different job markets. For all intents and purposes, .NET has been the development platform for Microsoft Windows environments (both for the desktop and the web) over the past ten years.

Most software developed for Windows uses the .NET Framework, and so there is a huge opportunity for new .NET developers to find work.

The Mono project also factors into demand. Mono is huge, and the community is just getting bigger. With its wide breadth of OS support, you can write apps for any of the big OSs, including mobile devices. There is opportunity galore, regardless of OS!


Conclusion

So where does all this leave us? Well, the haters and naysayers are wrong, and ASP.NET is a technology that you should try and get to know. After all, successful developers are polyglots—able to write applications in different languages for different platforms. So give ASP.NET a try. What do you say?


July 13 2011

20:46

Generating Traditional URLs with ASP.NET MVC3

Advertise here

There are certain truths in the world: we’re born, we die, and URLs should end with a slash if it doesn’t point to a file. The ASP.NET MVC framework bucks tradition and convention, and the built-in methods that generate URLs do so by omitting the trailing slash. It may seem like a non-issue (and to many people it’s not one), but many developers, this author included, are bugged by them.


First, Some Background

URL stands for Uniform Resource Locator; it tells web-aware clients where to locate a particular resource on the Internet. The URL of http://www.example.com/directory/file.html points to a physical file (the resource) called file.html that resides in a directory called directory on a web server found at the example.com domain. When the web server for example.com receives a request for that URL, it knows exactly where to look for the resource. If it finds the file, it serves its contents; if not, it responds with an error.

Traditional web servers do the same thing for directory requests.

Consider the URL of http://www.example.com/directory/. This URL ends with a trailing slash, denoting a directory. When the web server receives this request, it looks for the directory directory, and if it finds it, it gets the default document and returns it to the client. Otherwise, it responds with an error.

These two examples demonstrate a simple process, but it can get more complex with ambiguous requests. For example, the URL http://www.example.com/ambiguous points to a resource called ambiguous, but it is unclear what that resource is. It could be a file, but there is no extension; it could be a directory, but there’s no trailing slash. When receiving a request for this resource, a traditional web server goes through the following process:

  • The server looks for a file called ambiguous. If it finds one, it returns it. Otherwise…
  • It sends a response back to the client, redirecting it to http://www.example.com/ambiguous/
  • The client requests the new URL
  • The server looks for the ambiguous directory and returns the appropriate response

Without explicitly specifying a resource, the requester creates an overhead in both processing time and bandwidth usage.

Without explicitly specifying a resource, the requester creates an overhead in both processing time and bandwidth usage. For this reason, the prevailing rule of thumb has been to put the trailing slash on all URLs that point to a directory. Doing so completely eliminates the wasted processing time and bandwidth usage. It has become second nature to many (maybe most?) web veterans to always include the slash at the end of URLs that do not point to a file.

So where does ASP.NET MVC fit into this? Well, ASP.NET, as you probably know, typically runs on Microsoft’s web server, called IIS. IIS, by default, behaves just like any other web server, but its true power lies in its ability to pass the handling of requests to ISAPI modules or, even better, .NET code. In the case of an ASP.NET MVC application, IIS passes each request to the MVC app for processing. There, the app determines if the request should be routed to a method on a controller, or if it should pass control back to IIS to find a physical file or directory on the file system. So the process of handling a request for http://www.example.com/ambiguous by IIS and an MVC app looks something like this:

Wait, wait, wait! If MVC applications ignore the trailing slash, what’s the problem?

When the app routes the request to a controller, the method on that controller executes, processes whatever data it needs, and returns a result to the client. It does not redirect the client to another URL (unless the method is supposed to do that). MVC applications don’t care if URLs end with a slash or not–in fact, MVC apps ignore trailing slashes. As long as the URL matches a pattern in the routing table, the MVC app will handle the request and return the requested response without causing any extra overhead.

Wait, wait, wait! If MVC applications ignore the trailing slash, what’s the problem? Technically, there isn’t one. The ambiguous URL actually points to a resource on the server: a method on a controller object in the application. But as stated earlier, web developers have been putting slashes at the end of their URLs years before Microsoft released the MVC framework. It’s habit and convention to do so.

Microsoft’s stance on the "issue" is simply to be consistent with the URLs used in our application, and that’s a technically correct stance. But in typical Microsoft fashion, the MVC framework’s helper methods only generate URLs without the trailing slash-meaning developers have to write their own code to achieve "correct" URLs. The solution presented in this article is two-fold:

  • Create an extension method that generates URLs
  • Write customized versions of the RouteLink() method.

Because this solution uses variations of RouteLink(), it’s important that your routes are named. If you’re not naming your routes, you should! Finally, some code!


Generating URLs

The MVC framework provides a class called UrlHelper. As its name implies, its purpose is to help with generating URLs for our application. It has a static method called GenerateUrl() that will do most of the hard work for us. All we have to do is provide a route name and route values. We’ll create an extention method for HtmlHelper objects called RouteUrl(), and it will have two overloads.

Writing method overloads is pretty easy. There’s typically one overload that performs all the work (one overload to rule them all), and the other overloads simply pass through their arguments to it. So you’ll start by writing the main overload, and its code follows:

public static class HtmlHelperExtensions
{
    public static string RouteUrl(this HtmlHelper htmlHelper, string routeName, RouteValueDictionary routeValues)
    {
        string url = UrlHelper.GenerateUrl(
            routeName,
            null /*actionName*/,
            null /*controllerName*/,
            routeValues,
            htmlHelper.RouteCollection,
            htmlHelper.ViewContext.RequestContext,
            true
        );

        return String.Format("{0}/", url);
    }
}

The extension method accepts three arguments. The first is the HtmlHelper object that this method operates on. Note that when calling this method, you do not need to pass the HtmlHelper object; that is done automatically for you. The second argument is the string containing the route’s name. The GenerateUrl() method will use the route’s name to return a URL properly formatted according to the route’s pattern defined in the routing table. The last argument is a RouteValueDictionary object, which contains a set of key/value pairs with all the information needed to generate the URL for the route. This includes the controller and action names, as well as any parameters the UrlHelper may need to generate the URL for the specified route.

The first statement of the method calls UrlHelper.GenerateUrl() to generate the URL. There are two overloads for the GenerateUrl() method, and the above code calls the one with the least amount of parameters. The route name is passed, but you omit the parameters specifying action and controller names. These values are actually held within the routeValues object, which is passed to GenerateUrl() as fourth argument. The HtmlHelper object gives you the next two pieces of information you need, and the final argument passed tells GenerateUrl() to include the implicit MVC values of "action" and "controller".

After the URL is generated, the RouteUrl() method calls String.Format() to create a new string, essentially concatenating the URL and a trailing slash. Note that String.Format() isn’t necessary, and you can simply write return url + "/";. How you create a string is up to you.

With the main worker overload written, now add the lazy one. Here is its code:

public static string RouteUrl(this HtmlHelper htmlHelper, string routeName, object routeValues)
{
    return RouteUrl(htmlHelper, routeName, new RouteValueDictionary(routeValues));
}

This code is straight forward. It calls the main RouteUrl() overload by passing in the appropriate data. Because extension methods are static methods, they can be called just like any other static method-which is the case in this code. Note that you could just as easily have written this code by calling the main RouteUrl() as an instance (extension) method, like this:

// Alternative version
public static string RouteUrl(this HtmlHelper htmlHelper, string routeName, object routeValues)
{
    return htmlHelper.RouteUrl(routeName, new RouteValueDictionary(routeValues));
}

It doesn’t matter. Either way, the job gets done; it comes down to your personal preference.

Calling this method from your view is quite simple. First, make sure the namespace containing the HtmlHelperExtensions class is imported, and simply use the following syntax:

Html.RouteUrl("routeName", new
    {
        controller = "ControllerName",
        action = "ActionName",
        parameterOne = "Hello",
        parameterTwo = "World"
    })

Of course, the values for controller and action, as well as the parameters, will be different for your specific MVC app. But this gives you an idea of how to use the method. Now that you can generate pretty URLs with a trailing slash, it’s time to write more extension methods to generate your links.


Generating Links

One of the most helpful HtmlHelper methods is the RouteLink() method. All you have to do is provide it the route name and values to get a string containing an anchor element with a pretty relative URL to the specified action. Of course, RouteLink() returns anchor elements containing a URL without a trailing slash; so, you need to write your own method that uses RouteUrl().

There are eleven overloads for RouteLink(), so if you want to write your own version of all eleven, feel free. This article will only walk you through the creation of a few-likely the most popular overloads. The RouteLink() method is actually an extension method, and since extensions methods cannot be overridden or hidden, you’ll have to come up with a name for your own method. This article gets super creative and uses MyRouteLink().

The main overload will accept five arguments: the HtmlHelper instance, a link’s text, the route name, a RouteValueDictionary containing the route information, and a dictionary of HTML attributes to apply to the anchor element. Like RouteUrl(), MyRouteLink() is a static method of the HtmlHelperExtensions static class. Here is its code (to save space, the class declaration is omitted):

public static MvcHtmlString MyRouteLink(
    this HtmlHelper htmlHelper,
    string linkText,
    string routeName,
    RouteValueDictionary routeValues,
    IDictionary<string, object> htmlAttributes)
{
    string url = RouteUrl(htmlHelper, routeName, routeValues);

    TagBuilder tagBuilder = new TagBuilder("a")
    {
        InnerHtml = (!String.IsNullOrEmpty(linkText)) ? linkText : String.Empty
    };

    tagBuilder.MergeAttributes(htmlAttributes);
    tagBuilder.MergeAttribute("href", url);

    return MvcHtmlString.Create((tagBuilder.ToString(TagRenderMode.Normal)));
}

This code might look familiar to you if you have ever studied the ASP.NET MVC source code. The HtmlHelper class has a private method called GenerateRouteLink(), which was the inspiration for MyRouteLink(). Your method returns an MvcHtmlString object, which is an HTML-encoded string (you don’t have to do any encoding yourself). The first statement of this method uses your RouteUrl() method to get your special URL. Next, you use a TagBuilder object to build an anchor element, populating its InnerHtml property with the link’s text. Then the HTML attributes, those provided by the dictionary and the href attribute, are added to the element. Finally, the HTML output is created as a MvcHtmlString object and returned to the caller.

It’s cake from now on, as the remaining overloads will, in one way or another, call this version of MyRouteLink(). The next overload has a similar signature; the route values and attributes will simply be objects. Here is its code:

public static MvcHtmlString MyRouteLink(
    this HtmlHelper htmlHelper,
    string linkText,
    string routeName,
    object routeValues,
    object htmlAttributes)
{
    return MyRouteLink(
        htmlHelper,
        linkText,
        routeName,
        new RouteValueDictionary(routeValues),
        new RouteValueDictionary(htmlAttributes)
    );
}

This code is self-explanitory. You call the main MyRouteLink() overload by passing in the appropriate data. Note you’re using a RouteValueDictionary object for the HTML attributes; it’s a suitable container for HTML attributes.

The next, and final, two overloads are more of the same, except they do not accept an argument for HTML attributes. Here is their code:

public static MvcHtmlString MyRouteLink(
    this HtmlHelper htmlHelper,
    string linkText,
    string routeName,
    RouteValueDictionary routeValues)
{
    return MyRouteLink(
        htmlHelper,
        linkText,
        routeName,
        routeValues,
        new RouteValueDictionary()
    );
}

public static MvcHtmlString MyRouteLink(
    this HtmlHelper htmlHelper,
    string linkText,
    string routeName,
    object routeValues)
{
    return MyRouteLink(
        htmlHelper,
        linkText,
        routeName,
        new RouteValueDictionary(routeValues)
    );
}

The first overload in the above code omits the HTML attribute collection and specifies a RouteValueDictionary object for the route values. It calls the overload with a signature of MyRouteLink(HtmlHelper, string, string, RouteValueDictionary, IDictionary<string, object>), and passes an empty RouteValueDictionary object for the HTML attributes. The second overload has a slightly different signature, accepting an object for the route values. It calls the first overload in this code listing to generate the link.

To use this helper method, be sure you import the namespace containing the HtmlHelperExtensions class in your view. Then, you can write something like this:

@Html.MyRouteLink("My Link Text", "route name", new
    {
        controller = "ControllerName",
        action = "ActionName",
        parameterOne = "Hello",
        parameterTwo = "World"
    }
);

This code uses Razor syntax, but you can essentially do the same thing if using the ASPX view engine, like this:

<%:Html.MyRouteLink("My Link Text", "route name", new
    {
        controller = "ControllerName",
        action = "ActionName",
        parameterOne = "Hello",
        parameterTwo = "World"
    }
) %>

This code uses the new <%: %> nugget for HTML encoding output (introduced in .NET 4). The beauty of the MvcHtmlString returned by MyRouteLink() is that it's already HTML encoded, and it will not be re-encoded by using the new nugget. So you can use <%: %> or <%= %> without worrying about encoding or re-encoding.


In Closing

As mentioned earlier, there is nothing technically wrong with the URLs genereated by the MVC framework. They do not cause an overhead, as they point to an actual resource on the server. But if you've been bugged by them, now you can generate traditionally correct URLs with just a little work upfront. Microsoft is right, however: be consistent. Regardless of what URL style you prefer, make sure you consistently use the same one.

Let me know if you have any questions in the comments and thank you so much for reading!

July 08 2011

22:23

The Ins and Outs of WebMatrix: .NET Programming Using the Razor Syntax

Advertise here

This tutorial gives you an overview of programming with ASP.NET Web Pages using the Razor syntax. ASP.NET is Microsoft's technology for running dynamic web pages on web servers.


What You'll Learn:

  • The top 8 programming tips for getting started with programming ASP.NET Web Pages using Razor syntax.
  • Basic programming concepts you'll need for this session.
  • What ASP.NET server code and the Razor syntax is all about.

The Top 8 Programming Tips

This section lists a few tips that you absolutely need to know as you start writing ASP.NET server code using the Razor syntax.

Note: The Razor syntax is based on the C# programming language, and that's the language used throughout this session. However, the Razor syntax also supports the Visual Basic language, and everything you see in this session you can also do in Visual Basic.

1. You add code to a page using the @ character.

The @ character starts inline expressions, single statement blocks, and multi-statement blocks:

<!-- Single statement blocks  -->
@{ var total = 7; }
@{ var myMessage = "Hello World"; }

<!-- Inline expressions -->
<p>The value of your account is: @total </p>
<p>The value of myMessage is: @myMessage</p>

<!-- Multi-statement block -->
@{
    var greeting = "Welcome to our site!";
    var weekDay = DateTime.Now.DayOfWeek;
    var greetingMessage = greeting + " Today is: " + weekDay;
}
<p>The greeting is: @greetingMessage</p>

This is what these statements look like when the page runs in a browser:

Ch2-Img1

HTML Encoding

When you display content in a page using the @ character, as in the preceding examples, ASP.NET HTML-encodes the output. This replaces reserved HTML characters (such as < and > and &) with codes that enable the characters to be displayed as characters in a web page instead of being interpreted as HTML tags or entities. Without HTML encoding, the output from your server code might not display correctly, and could expose a page to security risks.

If your goal is to output HTML markup that renders tags as markup (for example <p></p> for a paragraph or <em></em> to emphasize text), see the section Combining Text, Markup, and Code in Code Blocks later in this article.

2. You enclose code blocks in braces.

A code block includes one or more code statements and is enclosed in braces.

<!-- Single statement block.  -->
@{ var theMonth = DateTime.Now.Month; }
<p>The numeric value of the current month: @theMonth</p>

<!-- Multi-statement block. -->
@{
    var outsideTemp = 79;
    var weatherMessage = "Hello, it is " + outsideTemp + " degrees.";
}
<p>Today's weather: @weatherMessage</p>

The result displayed in a browser:

Ch2-Img2

3. Inside a block, you end each code statement with a semicolon.

Inside a code block, each complete code statement must end with a semicolon. Inline expressions don’t end with a semicolon.

<!-- Single-statement block -->
@{ var theMonth = DateTime.Now.Month; }

<!-- Multi-statement block -->
@{
    var outsideTemp = 79;
    var weatherMessage = "Hello, it is " + outsideTemp + " degrees.";
}

<!-- Inline expression, so no semicolon -->
<p>Today's weather: @weatherMessage</p>

4. You use variables to store values.

You can store values in a variable, including strings, numbers, and dates, etc. You create a new variable using the var keyword. You can insert variable values directly in a page using @.

<!-- Storing a string -->
@{ var welcomeMessage = "Welcome, new members!"; }
<p>@welcomeMessage</p>

<!-- Storing a date -->
@{ var year = DateTime.Now.Year; }

<!-- Displaying a variable -->
<p>Welcome to our new members who joined in @year!</p>

The result displayed in a browser:

Ch2-Img3

5. You enclose literal string values in double quotation marks.

A string is a sequence of characters that are treated as text. To specify a string, you enclose it in double quotation marks:

@{ var myString = "This is a string literal"; }

If the string that you want to display contains a backslash character (\) or double quotation marks, use a verbatim string literal that’s prefixed with the @ operator. (In C#, the \ character has special meaning unless you use a verbatim string literal.)

<!-- Embedding a backslash in a string -->
@{ var myFilePath = @"C:\MyFolder\"; }
<p>The path is: @myFilePath</p>

To embed double quotation marks, use a verbatim string literal and repeat the quotation marks:

<!-- Embedding double quotation marks in a string -->
@{ var myQuote = @"The person said: ""Hello, today is Monday."""; }
<p>@myQuote</p>

The result displayed in a browser:

Ch2-Img4

Note:  The @ character is used both to mark verbatim string literals in C# and to mark code in ASP.NET pages.

6. Code is case sensitive.

In C#, keywords (like var, true, and if) and variable names are case sensitive. The following lines of code create two different variables, lastName and LastName.

@{
    var lastName = "Smith";
    var LastName = "Jones";
}

If you declare a variable as var lastName = "Smith"; and if you try to reference that variable in your page as @LastName, an error results because LastName won't be recognized.

Note: In Visual Basic, keywords and variables are not case sensitive.

7. Much of your coding involves objects.

An object represents a thing that you can program with — a page, a text box, a file, an image, a web request, an email message, a customer record (database row), etc. Objects have properties that describe their characteristics — a text box object has a Text property (among others), a request object has a Url property, an email message has a From property, and a customer object has a FirstName property. Objects also have methods that are the "verbs" they can perform. Examples include a file object's Save method, an image object's Rotate method, and an email object's Send method.

You'll often work with the Request object, which gives you information like the values of form fields on the page (text boxes, etc.), what type of browser made the request, the URL of the page, the user identity, etc. This example shows how to access properties of the Request object and how to call the MapPath method of the Request object, which gives you the absolute path of the page on the server:

<table border="1">
<tr>
    <td>Requested URL</td>
    <td>Relative Path</td>
    <td>Full Path</td>
    <td>HTTP Request Type</td>
</tr>
<tr>
    <td>@Request.Url</td>
    <td>@Request.FilePath</td>
    <td>@Request.MapPath(Request.FilePath)</td>
    <td>@Request.RequestType</td>
</tr>
</table>

The result displayed in a browser:

Ch2-Img5

8. You can write code that makes decisions.

A key feature of dynamic web pages is that you can determine what to do based on conditions. The most common way to do this is with the if statement (and optional else statement).

@{
   var result = "";
   if(IsPost)
   {
      result = "This page was posted using the Submit button.";
   }
   else
   {
      result = "This was the first request for this page.";
   }
}

<!DOCTYPE html>
<html>
    <head>
        <title></title>
    </head>
<body>
<form method="POST" action="" >
  <input type="Submit" name="Submit" value="Submit"/>
  <p>@result</p>
</form>
</body>
</html>
    </body>
</html>

The statement if(IsPost) is a shorthand way of writing if(IsPost == true). Along with if statements, there are a variety of ways to test conditions, repeat blocks of code, and so on, which are described later in this tutorial.

The result displayed in a browser (after clicking Submit):

Ch2-Img6

HTTP GET and POST Methods and the IsPost Property

The protocol used for web pages (HTTP) supports a very limited number of methods (verbs) that are used to make requests to the server. The two most common ones are GET, which is used to read a page, and POST, which is used to submit a page. In general, the first time a user requests a page, the page is requested using GET. If the user fills in a form and then clicks Submit, the browser makes a POST request to the server.

In web programming, it's often useful to know whether a page is being requested as a GET or as a POST so that you know how to process the page.

In ASP.NET Web Pages, you can use the IsPost property to see whether a request is a GET or a POST.

If the request is a POST, the IsPost property will return true, and you can do things like read the values of text boxes on a form. Many examples in this session show you how to process the page differently depending on the value of IsPost.


A Simple Code Example

This procedure shows you how to create a page that illustrates basic programming techniques. In the example, you create a page that lets users enter two numbers, then it adds them and displays the result.

  1. In your editor, create a new file and name it AddNumbers.cshtml.
  2. Copy the following code and markup into the page, replacing anything already in the page.
    @{
        var total = 0;
        var totalMessage = "";
        if(IsPost) {
    
            // Retrieve the numbers that the user entered.
            var num1 = Request["text1"];
            var num2 = Request["text2"];
    
            // Convert the entered strings into integers numbers and add.
            total = num1.AsInt() + num2.AsInt();
            totalMessage = "Total = " + total;
        }
    }
    
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <title>Add Numbers</title>
        <meta charset="utf-8" />
        <style type="text/css">
          body {background-color: beige; font-family: Verdana, Arial;
                margin: 50px; }
          form {padding: 10px; border-style: solid; width: 250px;}
        </style>
      </head>
    <body>
      <p>Enter two whole numbers and then click <strong>Add</strong>.</p>
      <form action="" method="post">
        <p><label for="text1">First Number:</label>
          <input type="text" name="text1" />
        </p>
        <p><label for="text2">Second Number:</label>
          <input type="text" name="text2" />
        </p>
        <p><input type="submit" value="Add" /></p>
      </form>
    
      <p>@totalMessage</p>
    
    </body>
    </html>
    

    Here are some things for you to note:

    • The @ character starts the first block of code in the page, and it precedes the totalMessage variable that's embedded near the bottom of the page.

    • The block at the top of the page is enclosed in braces.

    • In the block at the top, all lines end with a semicolon.

    • The variables total, num1, num2, and totalMessage store several numbers and a string.

    • The literal string value assigned to the totalMessage variable is in double quotation marks.

    • Because the code is case-sensitive, when the totalMessage variable is used near the bottom of the page, its name must match the variable at the top exactly.

    • The expression num1.AsInt() + num2.AsInt() shows how to work with objects and methods. The AsInt method on each variable converts the string entered by a user to a number (an integer) so that you can perform arithmetic on it.

    • The <form> tag includes a method="post" attribute. This specifies that when the user clicks Add, the page will be sent to the server using the HTTP POST method. When the page is submitted, the if(IsPost) test evaluates to true and the conditional code runs, displaying the result of adding the numbers.

  3. Save the page and run it in a browser. (Make sure the page is selected in the Files workspace before you run it.) Enter two whole numbers and then click the Add button.
    Ch2-Img7

Basic Programming Concepts

As you saw in lesson one of this series and in the previous example, even if you’ve never programmed before, with WebMatrix, ASP.NET web pages, and the Razor syntax, you can quickly create dynamic web pages with sophisticated features, and it won't take much code to get things done.

This tutorial provides you with an overview of ASP.NET web programming. It isn’t an exhaustive examination, just a quick tour through the programming concepts you’ll use most often. Even so, it covers almost everything you’ll need for the rest of the session.

But first, a little technical background.


The Razor Syntax, Server Code, and ASP.NET

Razor syntax is a simple programming syntax for embedding server-based code in a web page.

Razor syntax is a simple programming syntax for embedding server-based code in a web page. In a web page that uses the Razor syntax, there are two kinds of content: client content and server code. Client content is the stuff you're used to in web pages: HTML markup (elements), style information such as CSS, client script such as JavaScript, and plain text.

Razor syntax lets you add server code to this client content. If there's server code in the page, the server runs that code first, before it sends the page to the browser. By running on the server, the code can perform tasks that can be a lot more complex to do using client content alone, like accessing server-based databases. Most importantly, server code can dynamically create client content — it can generate HTML markup or other content on the fly and then send it to the browser along with any static HTML that the page might contain. From the browser's perspective, client content that's generated by your server code is no different than any other client content. As you've already seen, the server code that's required is quite simple.

ASP.NET web pages that include the Razor syntax have a special file extension (.cshtml or .vbhtml). The server recognizes these extensions, runs the code that's marked with Razor syntax, and then sends the page to the browser.

Where does ASP.NET fit in?

Razor syntax is based on a technology from Microsoft called ASP.NET, which in turn is based on the Microsoft .NET Framework. The.NET Framework is a big, comprehensive programming framework from Microsoft for developing virtually any type of computer application. ASP.NET is the part of the .NET Framework that's specifically designed for creating web applications. Developers have used ASP.NET to create many of the largest and highest-traffic websites in the world. (Any time you see the file-name extension .aspx as part of the URL in a site, you'll know that the site was written using ASP.NET.)

The Razor syntax gives you all the power of ASP.NET, but using a simplified syntax that's easier to learn if you're a beginner and that makes you more productive if you're an expert. Even though this syntax is simple to use, its family relationship to ASP.NET and the .NET Framework means that as your websites become more sophisticated, you have the power of the larger frameworks available to you.

Ch2-Img8

Classes and Instances

ASP.NET server code uses objects, which are in turn built on the idea of classes. The class is the definition or template for an object. For example, an application might contain a Customer class that defines the properties and methods that any customer object needs.

When the application needs to work with actual customer information, it creates an instance of (or instantiates) a customer object. Each individual customer is a separate instance of the Customer class. Every instance supports the same properties and methods, but the property values for each instance are typically different, because each customer object is unique. In one customer object, the LastName property might be “Smith”; in another customer object, the LastName property might be “Jones.”

Similarly, any individual web page in your site is a Page object that’s an instance of the Page class. A button on the page is a Button object that is an instance of the Button class, and so on. Each instance has its own characteristics, but they all are based on what’s specified in the object's class definition.


Language and Syntax

Earlier you saw a basic example of how to create an ASP.NET Web Pages page, and how you can add server code to HTML markup. Here you'll learn the basics of writing ASP.NET server code using the Razor syntax — that is, the programming language rules.

If you're experienced with programming (especially if you've used C, C++, C#, Visual Basic, or JavaScript), much of what you read here will be familiar. You’ll probably need to familiarize yourself only with how server code is added to markup in .cshtml files.


Basic Syntax

Combining Text, Markup, and Code in Code Blocks

In server code blocks, you'll often want to output text or markup (or both) to the page. If a server code block contains text that’s not code and that instead should be rendered as is, ASP.NET needs to be able to distinguish that text from code. There are several ways to do this.

  • Enclose the text in an HTML element like <p></p> or <em></em>.
  • @if(IsPost) {
        // This line has all content between matched
    
     tags.
    
    Hello, the time is @DateTime.Now and this page is a postback!
    
    } else {
        // All content between matched tags, followed by server code.
    
    Hello stranger, today is:  
    
      @DateTime.Now
    }
    

    The HTML element can include text, additional HTML elements, and server-code expressions. When ASP.NET sees the opening HTML tag, it renders everything including the element and its content as is to the browser (and resolves the server-code expressions).

  • Use the @: operator or the <text> element. The @: outputs a single line of content containing plain text or unmatched HTML tags; the <text> element encloses multiple lines to output. These options are useful when you don’t want to render an HTML element as part of the output.
    	@if(IsPost) {
    	    // Plain text followed by an unmatched HTML tag and server code.
    	    @: The time is:  @DateTime.Now
    	    // Server code and then plain text, matched tags, and more text.
    	    @DateTime.Now @:is the current time.
    	}
    	

    If you want to output multiple lines of text or unmatched HTML tags, you can precede each line with @:, or you can enclose the line in a <text> element. Like the @: operator, <text> tags are used by ASP.NET to identify text content and are never rendered in the page output.

    	@if(IsPost) {
    	    // Repeat the previous example, but use  tags.
    	    
    	    The time is:  @DateTime.Now
    	    @DateTime.Now is the current time.
    	    
    	}
    
    	@{
    	    var minTemp = 75;
    	    It is the month of @DateTime.Now.ToString("MMMM"), and
    	    it's a great day! 
    
    You can go swimming if it's at
    	    least @minTemp degrees. 
    
    
    	}
    	

    The first example repeats the previous example but uses a single pair of <text> tags to enclose the text to render. In the second example, the <text> and </text> tags enclose three lines, all of which have some uncontained text and unmatched HTML tags (<br />), along with server code and matched HTML tags. Again, you could also precede each line individually with the @: operator; either way works.

  • Note:  When you output text as shown in this section — using an HTML element, the @: operator, or the <text> element — ASP.NET doesn't HTML-encode the output. (As noted earlier, ASP.NET does encode the output of server code expressions and server code blocks that are preceded by @, except in the special cases noted in this section.)

    Whitespace

    Extra spaces in a statement (and outside of a string literal) don’t affect the statement:

    @{ var lastName =    "Smith"; }

    A line break in a statement has no effect on the statement, and you can wrap statements for readability. The following statements are the same:

    @{ var theName =
    "Smith"; }
    
    @{
        var
        personName
        =
        "Smith"
        ;
    }
    

    However, you can't wrap a line in the middle of a string literal. The following example doesn't  work:

    @{ var test = "This is a long
        string"; }  // Does not work!
    

    To combine a long string that wraps to multiple lines like the above code, there are two options. You can use the concatenation operator (+), which you'll see later in this tutorial. You can also use the @ character to create a verbatim string literal, as you saw earlier in this tutorial. You can break verbatim string literals across lines:

    @{ var longString = @"This is a
        long
        string";
    }
    

    Code (and Markup) Comments

    Comments let you leave notes for yourself or others. They also allow you to disable ("comment out") a section of code or markup that you don't want to run but want to keep in your page for the time being.

    There’s different commenting syntax for Razor code and for HTML markup. As with all Razor code, Razor comments are processed (and then removed) on the server before the page is sent to the browser. Therefore, the Razor commenting syntax lets you put comments into the code (or even into the markup) that you can see when you edit the file, but that users don't see, even in the page source.

    For ASP.NET Razor comments, you start the comment with @* and end it with *@. The comment can be on one line or multiple lines:

    @*  A one-line code comment. *@
    
    @*
        This is a multiline code comment.
        It can continue for any number of lines.
    *@
    

    Here is a comment within a code block:

    @{
        @* This is a comment. *@
        var theVar = 17;
    }
    

    Here is the same block of code, with the line of code commented out so that it won’t run:

    @{
        @* This is a comment. *@
        @* var theVar = 17;  *@
    }
    

    Inside a code block, as an alternative to using Razor comment syntax, you can use the commenting syntax of the programming language you’re using, such as C#:

    @{
        // This is a comment.
        var myVar = 17;
        /* This is a multi-line comment
        that uses C# commenting syntax. */
    }
    

    In C#, single-line comments are preceded by the // characters, and multi-line comments begin with /* and end with */. (As with Razor comments, C# comments are not rendered to the browser.)

    For markup, as you probably know, you can create an HTML comment:

    <!-- This is a comment.  -->

    HTML comments start with <!-- characters and end with -->. You can use HTML comments to surround not only text, but also any HTML markup that you may want to keep in the page but don't want to render. This HTML comment will hide the entire content of the tags and the text they contain:

    <!-- <p>This is my paragraph.</p>  -->

    Unlike Razor comments, HTML comments are rendered to the page and the user can see them by viewing the page source.


    Variables

    A variable is a named object that you use to store data. You can name variables anything, but the name must begin with an alphabetic character and it cannot contain whitespace or reserved characters.

    Variables and Data Types

    A variable can have a specific data type, which indicates what kind of data is stored in the variable. You can have string variables that store string values (like "Hello world"), integer variables that store whole-number values (like 3 or 79), and date variables that store date values in a variety of formats (like 4/12/2010 or March 2009). And there are many other data types you can use.

    However, you generally don’t have to specify a type for a variable. Most of the time, ASP.NET can figure out the type based on how the data in the variable is being used. (Occasionally you must specify a type; you’ll see examples in this session where this is true.)

    You declare a variable using the var keyword (if you don’t want to specify a type) or by using the name of the type:

    @{
        // Assigning a string to a variable.
        var greeting = "Welcome!";
    
        // Assigning a number to a variable.
        var theCount = 3;
    
        // Assigning an expression to a variable.
        var monthlyTotal = theCount + 5;
    
        // Assigning a date value to a variable.
        var today = DateTime.Today;
    
        // Assigning the current page's URL to a variable.
        var myPath = this.Request.Url;
    
        // Declaring variables using explicit data types.
        string name = "Joe";
        int count = 5;
        DateTime tomorrow = DateTime.Now.AddDays(1);
    

    The following example shows some typical uses of variables in a web page:

    @{
        // Embedding the value of a variable into HTML markup.
        <p>@greeting, friends!</p>
    
        // Using variables as part of an inline expression.
        <p>The predicted annual total is: @( monthlyTotal * 12)</p>
    
        // Displaying the page URL with a variable.
        <p>The URL to this page is: @myPath</p>
    }
    

    The result displayed in a browser:

    Ch2-Img9

    Converting and Testing Data Types

    Although ASP.NET can usually determine a data type automatically, sometimes it can’t. Therefore, you might need to help ASP.NET out by performing an explicit conversion. Even if you don’t have to convert types, sometimes it’s helpful to test to see what type of data you might be working with.

    The most common case is that you have to convert a string to another type, such as to an integer or date. The following example shows a typical case where you must convert a string to a number.

    @{
        var total = 0;
    
        if(IsPost) {
            // Retrieve the numbers that the user entered.
            var num1 = Request["text1"];
            var num2 = Request["text2"];
            // Convert the entered strings into integers numbers and add.
            total = num1.AsInt() + num2.AsInt();
        }
    }
    

    As a rule, user input comes to you as strings. Even if you’ve prompted users to enter a number, and even if they’ve entered a digit, when user input is submitted and you read it in code, the data is in string format. Therefore, you must convert the string to a number. In the example, if you try to perform arithmetic on the values without converting them, the following error results, because ASP.NET cannot add two strings:

    Cannot implicitly convert type 'string' to 'int'.

    To convert the values to integers, you call the AsInt method. If the conversion is successful, you can then add the numbers.

    The following table lists some common conversion and test methods for variables.

    Method

    Description

    Example

    AsInt(),
    IsInt()

    Converts a string that represents a whole number (like “593″) to an integer.

    var myIntNumber = 0;
    var myStringNum = "539";
    if(myStringNum.IsInt()==true) {
       myIntNumber = myStringNum.AsInt();
    }

    AsBool(),
    IsBool()

    Converts a string like "true" or "false" to a Boolean type.

    		var myStringBool = "True";
    		var myVar = myStringBool.AsBool();

    AsFloat(),
    IsFloat()

    Converts a string that has a decimal value like "1.3" or "7.439" to a floating-point number.

    		var myStringFloat = "41.432895";
    		var myFloatNum = myStringFloat.AsFloat(); 

    AsDecimal(),
    IsDecimal()

    Converts a string that has a decimal value like "1.3" or "7.439" to a decimal number. (In ASP.NET, a decimal number is more precise than a floating-point number.)

    		var myStringDec = "10317.425";
    		var myDecNum = myStringDec.AsDecimal(); 

    AsDateTime(),
    IsDateTime()

    Converts a string that represents a date and time value to the ASP.NET DateTime type.

    		var myDateString = "12/27/2010";
    		var newDate = myDateString.AsDateTime();		

    ToString()

    Converts any other data type to a string.

    		int num1 = 17;
    		int num2 = 76;
    		// myString is set to 1776
    		string myString = num1.ToString() + num2.ToString();

    Operators

    An operator is a keyword or character that tells ASP.NET what kind of command to perform in an expression. The C# language (and the Razor syntax that’s based on it) supports many operators, but you only need to recognize a few to get started. The following table summarizes the most common operators.

    Operator

    Description

    Examples

    +
    -
    *
    /

    Math operators used in numerical expressions.

    	@(5 + 13)
    	@{ var netWorth = 150000; }
    	@{ var newTotal = netWorth * 2; }
    	@(newTotal / 2)

    =

    Assignment. Assigns the value on the right side of a statement to the object on the left side.

    var age = 17;

    ==

    Equality. Returns true if the values are equal. (Notice the distinction between the = operator and the == operator.)

    	var myNum = 15;
    	if (myNum == 15) { // Do something. } 

    !=

    Inequality. Returns true if the values are not equal.

    	var theNum = 13;
    	if (theNum != 15) { // Do something. }

    <
    >
    <=
    >=

    Less-than,
    greater-than,
    less-than-or-equal, and
    greater-than-or-equal.

    	if (2 < 3) { // Do something. }
    	var currentCount = 12;
    	if(currentCount >= 12) { // Do something. }

    +

    Concatenation, which is used to join strings. ASP.NET knows the difference between this operator and the addition operator based on the data type of the expression.

    	// The displayed result is "abcdef".
    	@("abc" + "def")

    +=

    -=

    The increment and decrement operators, which add and subtract 1 (respectively) from a variable.

    	int theCount = 0;
    	theCount += 1; // Adds 1 to count

    .

    Dot. Used to distinguish objects and their properties and methods.

    	var myUrl = Request.Url;
    	var count = Request["Count"].AsInt();

    ()

    Parentheses. Used to group expressions and to pass parameters to methods.

    	@(3 + 7)
    	@Request.MapPath(Request.FilePath);

    []

    Brackets. Used for accessing values in arrays or collections.

    	var income = Request["AnnualIncome"];

    !

    Not. Reverses a true value to false and vice versa. Typically used as a shorthand way to test for false (that is, for not true).

    bool taskCompleted = false;
    	// Processing.
    	if(!taskCompleted) {
      // Continue processing
    }

    &&

    ||

    Logical AND and OR, which are used to link conditions together.

    	bool myTaskCompleted = false;
    	int totalCount = 0;
    	// Processing.
    	if(!myTaskCompleted && totalCount < 12) {
       // Continue processing.
    }
    

    Working with File and Folder Paths in Code

    You'll often work with file and folder paths in your code. Here is an example of physical folder structure for a website as it might appear on your development computer:

    C:\WebSites\MyWebSite
        default.cshtml
        datafile.txt
        \images
            Logo.jpg
        \styles
            Styles.css

     Here are some essential details about URLs and paths:

    • A URL begins with either a domain name (http://www.example.com) or a server name (http://localhost, http://mycomputer).
    • A URL corresponds to a physical path on a host computer. For example, http://myserver might correspond to the folder C:\websites\mywebsite on the server.
    • A virtual path is shorthand to represent paths in code without having to specify the full path. It includes the portion of a URL that follows the domain or server name. When you use virtual paths, you can move your code to a different domain or server without having to update the paths.

    Here's an example to help you understand the differences:

    Complete URL http://mycompanyserver/humanresources/CompanyPolicy.htm Server name mycompanyserver Virtual path /humanresources/CompanyPolicy.htm Physical path C:\mywebsites\humanresources\CompanyPolicy.htm

    The virtual root is /, just like the root of your C: drive is \. (Virtual folder paths always use forward slashes.) The virtual path of a folder doesn't have to have the same name as the physical folder; it can be an alias. (On production servers, the virtual path rarely matches an exact physical path.)

    When you work with files and folders in code, sometimes you need to reference the physical path and sometimes a virtual path, depending on what objects you're working with. ASP.NET gives you these tools for working with file and folder paths in code: the ~ operator, the Server.MapPath method, and the Href method.

    The ~ operator: Getting the virtual root

    In server code, to specify the virtual root path to folders or files, use the ~ operator. This is useful because you can move your website to a different folder or location without breaking the paths in your code.

    @{
        var myImagesFolder = "~/images";
        var myStyleSheet = "~/styles/StyleSheet.css";
    }
    

    The Server.MapPath method: Converting virtual to physical paths

    The Server.MapPath method converts a virtual path (like /default.cshtml) to an absolute physical path (like C:\WebSites\MyWebSiteFolder\default.cshtml). You use this method for tasks that require a complete physical path, like reading or writing a text file on the web server. (You typically don't know the absolute physical path of your site on a hosting site's server.) You pass the virtual path to a file or folder to the method, and it returns the physical path:

    @{
        var dataFilePath = "~/dataFile.txt";
    }
    <!-- Displays a physical path C:\Websites\MyWebSite\datafile.txt  -->
    <p>@Server.MapPath(dataFilePath)</p>
    

    The Href method: Creating paths to site resources

    The Href method of the WebPage object converts paths that you create in server code (which can include the ~ operator) to paths that the browser understands. (The browser can't understand the ~ operator, because that's strictly an ASP.NET operator.) You use the Href method to create paths to resources like image files, other web pages, and CSS files. For example, you can use this method in HTML markup for attributes of <img> elements, <link> elements, and <a> elements.

    @{
        var myImagesFolder = "~/images";
        var myStyleSheet = "~/styles/StyleSheet.css";
    }
    
    <!-- This code creates the path "../images/Logo.jpg" in the src attribute. -->
    <img src="@Href(myImagesFolder)/Logo.jpg" />
    
    <!-- This produces the same result, using a path with ~  -->
    <img src="@Href("~/images")/Logo.jpg" />
    
    <!-- This creates a link to the CSS file. -->
    <link rel="stylesheet" type="text/css" href="@Href(myStyleSheet)" />
    

    Conditional Logic and Loops

    ASP.NET server code lets you perform tasks based on conditions and write code that repeats statements a specific number of times (that is, code that runs a loop).

    Testing Conditions

    To test a simple condition you use the if statement, which returns true or false based on a test you specify:

    @{
      var showToday = true;
      if(showToday)
      {
        @DateTime.Today;
      }
    }
    

    The if keyword starts a block. The actual test (condition) is in parentheses and returns true or false. The statements that run if the test is true are enclosed in braces. An if statement can include an else block that specifies statements to run if the condition is false:

    @{
      var showToday = false;
      if(showToday)
      {
        @DateTime.Today;
      }
      else
      {
        <text>Sorry!</text>
      }
    }
    

    You can add multiple conditions using an else if block:

    @{
        var theBalance = 4.99;
        if(theBalance == 0)
        {
            <p>You have a zero balance.</p>
        }
        else if (theBalance  > 0 && theBalance <= 5)
        {
            <p>Your balance of $@theBalance is very low.</p>
        }
        else
        {
            <p>Your balance is: $@theBalance</p>
        }
    }
    

    In this example, if the first condition in the if block is not true, the else if condition is checked. If that condition is met, the statements in the else if block are executed. If none of the conditions are met, the statements in the else block are executed. You can add any number of else if blocks, and then close with an else block as the "everything else" condition.

    To test a large number of conditions, use a switch block:

    @{
        var weekday = "Wednesday";
        var greeting = "";
    
        switch(weekday)
        {
            case "Monday":
                greeting = "Ok, it's a marvelous Monday";
                break;
            case "Tuesday":
                greeting = "It's a tremendous Tuesday";
                break;
            case "Wednesday":
                greeting = "Wild Wednesday is here!";
                break;
            default:
                greeting = "It's some other day, oh well.";
                break;
        }
    
        <p>Since it is @weekday, the message for today is: @greeting</p>
    }
    

    The value to test is in parentheses (in the example, the weekday variable). Each individual test uses a case statement that ends with a colon (:). If the value of a case statement matches the test value, the code in that case block is executed. You close each case statement with a break statement. (If you forget to include break in each case block, the code from the next case statement will run also.) A switch block often has a default statement as the last case for an "everything else" option that runs if none of the other cases are true.

    The result of the last two conditional blocks displayed in a browser:

    Ch2-Img10

    Looping Code

    You often need to run the same statements repeatedly. You do this by looping. For example, you often run the same statements for each item in a collection of data. If you know exactly how many times you want to loop, you can use a for loop. This kind of loop is especially useful for counting up or counting down:

    @for(var i = 10; i < 21; i++)
    {
        <p>Line #: @i</p>
    }
    

    The loop begins with the for keyword, followed by three statements in parentheses, each terminated with a semicolon.

    • Inside the parentheses, the first statement (var i=10;) creates a counter and initializes it to 10. You don’t have to name the counter i — you can use any legal variable name. When the for loop runs, the counter is automatically incremented.
    • The second statement (i < 21;) sets the condition for how far you want to count. In this case, you want it to go to a maximum of 20 (that is, keep going while the counter is less than 21).
    • The third statement (i++ ) uses an increment operator, which simply specifies that the counter should have 1 added to it each time the loop runs.

    Inside the braces is the code that will run for each iteration of the loop. The markup creates a new paragraph (<p> element) each time and adds a line to the output,  displaying the value of i (the counter). When you run this page, the example creates 11 lines displaying the output, with the text in each line indicating the item number.

    Ch2-Img11

    If you’re working with a collection or array, you often use a foreach loop. A collection is a group of similar objects, and the foreach loop lets you carry out a task on each item in the collection. This type of loop is convenient for collections, because unlike a for loop, you don't have to increment the counter or set a limit. Instead, the foreach loop code simply proceeds through the collection until it’s finished.

    This example returns the items in the Request.ServerVariables collection that (which is an object that contains information about your web server). It uses a foreach loop to display the name of each item by creating a new <li> element in an HTML bulleted list.

    <ul>
    @foreach (var myItem in Request.ServerVariables)
    {
        <li>@myItem</li>
    }
    </ul>
    

    The foreach keyword is followed by parentheses where you declare a variable that represents a single item in the collection (in the example, var item), followed by the in keyword, followed by the collection you want to loop through. In the body of the foreach loop, you can access the current item using the variable that you declared earlier.

    Ch2-Img12

    To create a more general-purpose loop, use the while statement:

    @{
        var countNum = 0;
        while (countNum < 50)
        {
            countNum += 1;
            <p>Line #@countNum: </p>
        }
    }
    

    A while loop begins with the while keyword, followed by parentheses where you specify how long the loop continues (here, for as long as countNum is less than 50), then the block to repeat. Loops typically increment (add to) or decrement (subtract from) a variable or object used for counting. In the example, the += operator adds 1 to countNum each time the loop runs. (To decrement a variable in a loop that counts down, you would use the decrement operator -=).


    Objects and Collections

    Nearly everything in an ASP.NET website is an object, including the web page itself. This section discusses some important objects you’ll work with frequently in your code.

    Page Objects

    The most basic object in ASP.NET is the page. You can access properties of the page object directly without any qualifying object. The following code gets the page's file path, using the Request object of the page:

    @{
        var path = Request.FilePath;
    }
    

    To make it clear that you’re referencing properties and methods on the current page object, you can optionally use the keyword this to represent the page object in your code. Here is the previous code example, with this added to represent the page:

    @{
        var path = this.Request.FilePath;
    }
    

    You can use properties of the Page object to get a lot of information, such as:

    • Request. As you've already seen, this is a collection of information about the current request, including what type of browser made the request, the URL of the page, the user identity, etc.
    • Response. This is a collection of information about the response (page) that will be sent to the browser when the server code has finished running. For example, you can use this property to write information into the response.
      @{
          // Access the page's Request object to retrieve the Url.
          var pageUrl = this.Request.Url;
      }
      <a href="@pageUrl">My page</a>
      

    Collection Objects (Arrays and Dictionaries)

    A collection is a group of objects of the same type, such as a collection of Customer objects from a database. ASP.NET contains many built-in collections, like the Request.Files collection.

    You’ll often work with data in collections. Two common collection types are the array and the dictionary. An array is useful when you want to store a collection of similar items but don’t want to create a separate variable to hold each item:

    @* Array block 1: Declaring a new array using braces. *@
    @{
        <h3>Team Members</h3>
        string[] teamMembers = {"Matt", "Joanne", "Robert", "Nancy"};
        foreach (var person in teamMembers)
        {
            <p>@Person</p>
        }
    }
    

    With arrays, you declare a specific data type, such as string, int, or DateTime. To indicate that the variable can contain an array, you add brackets to the declaration (such as string[] or int[]). You can access items in an array using their position (index) or by using the foreach statement. Array indexes are zero-based — that is, the first item is at position 0, the second item is at position 1, and so on.

    @{
        string[] teamMembers = {"Matt", "Joanne", "Robert", "Nancy"};
        <p>The number of names in the teamMembers array: @teamMembers.Length </p>
        <p>Robert is now in position: @Array.IndexOf(teamMembers, "Robert")</p>
        <p>The array item at position 2 (zero-based) is @teamMembers[2]</p>
        <h3>Current order of team members in the list</h3>
        foreach (var name in teamMembers)
        {
            <p>@name</p>
        }
        <h3>Reversed order of team members in the list</h3>
        Array.Reverse(teamMembers);
        foreach (var reversedItem in teamMembers)
        {
            <p>@reversedItem</p>
        }
    }
    

    You can determine the number of items in an array by getting its Length property. To get the position of a specific item in the array (to search the array), use the Array.IndexOf method. You can also do things like reverse the contents of an array (the Array.Reverse method) or sort the contents (the Array.Sort method).

    The output of the string array code displayed in a browser:

    Ch2-Img13

    A dictionary is a collection of key/value pairs, where you provide the key (or name) to set or retrieve the corresponding value:

    @{
        var myScores = new Dictionary<string, int>();
        myScores.Add("test1", 71);
        myScores.Add("test2", 82);
        myScores.Add("test3", 100);
        myScores.Add("test4", 59);
    }
    <p>My score on test 3 is: @myScores["test3"]%</p>
    @(myScores["test4"] = 79)
    <p>My corrected score on test 4 is: @myScores["test4"]%</p>
    

    To create a dictionary, you use the new keyword to indicate that you’re creating a new dictionary object. You can assign a dictionary to a variable using the var keyword. You indicate the data types of the items in the dictionary using angle brackets ( < > ). At the end of the declaration, you must add a pair of parentheses, because this is actually a method that creates a new dictionary.

    To add items to the dictionary, you can call the Add method of the dictionary variable (myScores in this case), and then specify a key and a value. Alternatively, you can use square brackets to indicate the key and do a simple assignment, as in the following example:

    myScores["test4"] = 79;

    To get a value from the dictionary, you specify the key in brackets:

    var testScoreThree = myScores["test3"];

    Calling Methods with Parameters

    As you read earlier in this tutorial, the objects that you program with can have methods. For example, a Database object might have a Database.Connect method. Many methods also have one or more parameters. A parameter is a value that you pass to a method to enable the method to complete its task. For example, look at a declaration for the Request.MapPath method, which takes three parameters:

    public string MapPath(string virtualPath, string baseVirtualDir, bool allowCrossAppMapping);

    This method returns the physical path on the server that corresponds to a specified virtual path. The three parameters for the method are virtualPath, baseVirtualDir, and allowCrossAppMapping. (Notice that in the declaration, the parameters are listed with the data types of the data that they'll accept.) When you call this method, you must supply values for all three parameters.

    The Razor syntax gives you two options for passing parameters to a method: positional parameters and named parameters. To call a method using positional parameters, you pass the parameters in a strict order that's specified in the method declaration. (You would typically know this order by reading documentation for the method.) You must follow the order, and you can't skip any of the parameters — if necessary, you pass an empty string ("") or null for a positional parameter that you don't have a value for.

    The following example assumes you have a folder named scripts on your website. The code calls the Request.MapPath method and passes values for the three parameters in the correct order. It then displays the resulting mapped path.

    // Pass parameters to a method using positional parameters.
    var myPathPositional = Request.MapPath("/scripts", "/", true);
    <p>@myPathPositional</p>
    

    When a method has many parameters, you can keep your code more readable by using named parameters. To call a method using named parameters, you specify the parameter name followed by a colon (:), and then the value. The advantage of named parameters is that you can pass them in any order you want. (A disadvantage is that the method call is not as compact.)

    The following example calls the same method as above, but uses named parameters to supply the values:

    // Pass parameters to a method using named parameters.
    var myPathNamed = Request.MapPath(baseVirtualDir: "/", allowCrossAppMapping: true, virtualPath: "/scripts");
    <p>@myPathNamed</p>
    

    As you can see, the parameters are passed in a different order. However, if you run the previous example and this example, they’ll return the same value.


    Handling Errors

    Try-Catch Statements

    You’ll often have statements in your code that might fail for reasons outside your control. For example:

    • If your code tries to open, create, read, or write a file, all sorts of errors might occur. The file you want might not exist, it might be locked, the code might not have permissions, and so on.
    • Similarly, if your code tries to update records in a database, there can be permissions issues, the connection to the database might be dropped, the data to save might be invalid, and so on.

    In programming terms, these situations are called exceptions. If your code encounters an exception, it generates (throws) an error message that’s, at best, annoying to users:

    Ch2-Img14

    In situations where your code might encounter exceptions, and in order to avoid error messages of this type, you can use try/catch statements. In the try statement, you run the code that you’re checking. In one or more catch statements, you can look for specific errors (specific types of exceptions) that might have occurred. You can include as many catch statements as you need to look for errors that you are anticipating.

    Note   We recommend that you avoid using the Response.Redirect method in try/catch statements, because it can cause an exception in your page.

    The following example shows a page that creates a text file on the first request and then displays a button that lets the user open the file. The example deliberately uses a bad file name so that it will cause an exception. The code includes catch statements for two possible exceptions: FileNotFoundException, which occurs if the file name is bad, and DirectoryNotFoundException, which occurs if ASP.NET can't even find the folder. (You can uncomment a statement in the example in order to see how it runs when everything works properly.)

    If your code didn't handle the exception, you would see an error page like the previous screen shot. However, the try/catch section helps prevent the user from seeing these types of errors.

    @{
        var dataFilePath = "~/dataFile.txt";
        var fileContents = "";
        var physicalPath = Server.MapPath(dataFilePath);
        var userMessage = "Hello world, the time is " + DateTime.Now;
        var userErrMsg = "";
        var errMsg = "";
    
        if(IsPost)
        {
            // When the user clicks the "Open File" button and posts
            // the page, try to open the created file for reading.
            try {
                // This code fails because of faulty path to the file.
                fileContents = File.ReadAllText(@"c:\batafile.txt");
    
                // This code works. To eliminate error on page,
                // comment the above line of code and uncomment this one.
                //fileContents = File.ReadAllText(physicalPath);
            }
            catch (FileNotFoundException ex) {
                // You can use the exception object for debugging, logging, etc.
                errMsg = ex.Message;
                // Create a friendly error message for users.
                userErrMsg = "A file could not be opened, please contact "
                    + "your system administrator.";
            }
            catch (DirectoryNotFoundException ex) {
                // Similar to previous exception.
                errMsg = ex.Message;
                userErrMsg = "A directory was not found, please contact "
                    + "your system administrator.";
            }
        }
        else
        {
            // The first time the page is requested, create the text file.
            File.WriteAllText(physicalPath, userMessage);
        }
    }
    
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8" />
            <title>Try-Catch Statements</title>
        </head>
        <body>
        <form method="POST" action="" >
          <input type="Submit" name="Submit" value="Open File"/>
        </form>
    
        <p>@fileContents</p>
        <p>@userErrMsg</p>
    
        </body>
    </html>
    

    Stay tuned for lesson three in this session!

    June 22 2011

    20:58

    The Ins and Outs of WebMatrix: An Introduction

    Advertise here

    This tutorial introduces Microsoft WebMatrix, a free web development technology that delivers one of the best experiences for web developers. For a PDF version of these tutorials and the complete sample code, go to the Microsoft Download Center.

    What You'll Learn:

    • What is WebMatrix?
    • How to install WebMatrix.
    • How to get started creating a simple website using WebMatrix.
    • How to create a dynamic web page using WebMatrix.
    • How to program your web pages in Visual Studio to take advantage of more advanced features.



    What is WebMatrix?

    WebMatrix is a free, lightweight set of web development tools that provides the easiest way to build websites.

    It includes IIS Express (a development web server), ASP.NET (a web framework), and SQL Server Compact (an embedded database). It also includes a simple tool that streamlines website development and makes it easy to start websites from popular open source apps. The skills and code you develop with WebMatrix transition seamlessly to Visual Studio and SQL Server.

    The web pages that you create using WebMatrix can be dynamic—that is, they can alter their content or style based on user input or on other information, such as database information. To program dynamic Web pages, you use ASP.NET with the Razor syntax and with the C# or Visual Basic programming languages.

    If you already have programming tools that you like, you can try the WebMatrix tools or you can use your own tools to create websites that use ASP.NET.

    This tutorial shows you how WebMatrix makes it easy to get started creating websites and dynamic web pages.


    Installing WebMatrix

    To install WebMatrix, you can use Microsoft’s Web Platform Installer, which is a free application that makes it easy to install and configure web-related technologies.

    1. If you don't already have the Web Platform Installer, download it from the following URL:

      http://go.microsoft.com/fwlink/?LinkID=205867

  • Run the Web Platform Installer, select Spotlight, and then click Add to install WebMatrix.
    Install WebMatrix
  • Note   If you already have a WebMatrix Beta version installed, the Web Platform Installer upgrades the installation to WebMatrix 1.0. However, sites you created with earlier Beta editions might not appear in the My Sites list when you first open WebMatrix. To open a previously created site, click the Site From Folder icon, browse to the site, and open it. The next time you open WebMatrix, the site will appear in the My Sites list.


    Getting Started with WebMatrix

    To begin, you'll create a new website and a simple web page.

    1. Start WebMatrix.
      Start WebMatrix
    2. Click Site From Template. Templates include prebuilt files and pages for different types of websites.
      Create a Site
    3. Select Empty Site and name the new site Hello World.
    4. Click OK. WebMatrix creates and opens the new site.

      At the top, you see a Quick Access Toolbar and a ribbon, as in Microsoft Office 2010. At the bottom left, you see the workspace selector, which contains buttons that determine what appears above them in the left pane. On the right is the content pane, which is where you view reports, edit files, and so on. Finally, across the bottom is the notification bar, which displays messages as needed.

      [image]

    Creating a Web Page

    1. In WebMatrix, select the Files workspace. This workspace lets you work with files and folders. The left pane shows the file structure of your site.
      [image]
    2. In the ribbon, click New and then click New File.
      [image]

      WebMatrix displays a list of file types.

      [image]
    3. Select CSHTML, and in the Name box, type default.cshtml. A CSHTML page is a special type of page in WebMatrix that can contain the usual contents of a web page, such as HTML and JavaScript code, and that can also contain code for programming web pages. (You'll learn more about CSHTML files later.)
    4. Click OK. WebMatrix creates the page and opens it in the editor.
      [image]

      As you can see, this is ordinary HTML markup.

    5. Add the following title, heading, and paragraph content to the page:
      <!DOCTYPE html>
      <html lang="en">
      	<head>
      		<meta charset="utf-8" />
      		<title>Hello World Page</title>
      	</head>
      
      	<body>
      		<h1>Hello World Page</h1>
      		<p>Hello World!</p>
      	</body>
      </html>
    6. In the Quick Access Toolbar, click Save.
      [image]
    7. In the ribbon, click Run.
      [image]

      Note   Before you click Run, make sure that the web page you want to run is selected in the navigation pane of the Files workspace. WebMatrix runs the page that's selected, even if you're currently editing a different page. If no page is selected, WebMatrix tries to run the default page for the site (default.cshtml), and if there is no default page, the browser displays an error.

      WebMatrix starts a web server (IIS Express) that you can use to test pages on your computer. The page is displayed in your default browser.

      [image]

    Installing Helpers with the Administration Tool

    Now that you have WebMatrix installed and a site created, it's a good idea learn how to use the ASP.NET Web Pages Administration tool and the Package Manager to install helpers. WebMatrix contains helpers (components) that simplify common programming tasks and that you'll use throughout these tutorials. (Some helpers are already included with WebMatrix, but you can install others as well.) In the appendix you can find a quick reference for the included helpers and for other helpers that you can install as part of a package called the ASP.NET Web Helpers Library. The following procedure shows how to use the Administration tool to install the ASP.NET Web Helpers Library. You will use some of these helpers in this tutorial and other tutorials in this series.

    1. In WebMatrix, click the Site workspace.
    2. In the content pane, click ASP.NET Web Pages Administration. This loads an administration page into your browser. Because this is the first time you're logging into the administration page, it prompts you to create a password.
    3. Create a password.
      Package Manager

      After you click Create Password, a security-check page that looks like the following screen shot prompts you to rename the password file for security reasons. If this is the first time you're seeing this page, don't try to rename the file yet. Proceed to the next step and follow the directions there.

      Rename password file
    4. Leave the browser open on the security-check page, return to WebMatrix, and click the Files workspace.
    5. Right-click the Hello World folder for your site and then click Refresh. The list of files and folders now displays an App_Data folder. Open that and you see an Admin folder. The newly created password file (_Password.config) is displayed in the ./App_Data/Admin/ folder. The following illustration shows the updated file structure with the password file selected:
    6. Rename password file
    7. Rename the file to Password.config by removing the leading underscore (_) character.
    8. Return to the security-check page in the browser, and click the Click Here link near the end of the message about renaming the password file.
    9. Log into the Administration page using the password you created. The page displays the Package Manager, which contains a list of add-on packages.
      ch01_learnweb-14a

      If you ever want to display other feed locations, click the Manage Package Sources link to add, change, or remove feeds.

    10. Find the ASP.NET Web Helpers Library package. To narrow down the list, search for helpers using the Search field. The following image shows the result of searching for helpers. Notice that several versions of this package are available. 
      ch01_learnweb-14b
    11. Select the version that you want, click the Install button, and then install the package as directed. After the package is installed, the Package Manager displays the result. 
      ch01_learnweb-15

      This page also lets you uninstall packages, and you can use the page to update packages when newer versions are available. You can go to the Show drop-down list and click Installed to display the packages you have installed, or click Updates to display available updates for the installed packages.

      Note   The default website templates (Bakery, Calendar, Photo Gallery, and Starter Site) are available in C# and Visual Basic versions. You can install the Visual Basic templates by using the ASP.NET Web Pages Administration tool in WebMatrix. Open the Administration tool as described in this section and search for VB, and then install the templates you need. Website templates are installed in the root folder of your site in a folder named Microsoft Templates.

      In the next section, you'll see how easy is it is to add code to the default.cshtml page in order to create a dynamic page.


    Using ASP.NET Web Pages Code

    In this procedure, you'll create a page that uses simple code to display the server date and time on the page. The example here will introduce you to the Razor syntax that lets you embed code into the HTML on ASP.NET Web Pages. (You can read more about this in the next tutorial.) The code introduces one of the helpers that you read about earlier in the tutorial.

    1. Open your default.cshtml file.
    2. Add markup to the page so that it looks like the following example:
      <!DOCTYPE html>
      <html lang="en">
      
      <head>
      	<meta charset="utf-8" />
      	<title>Hello World Page</title>
      </head>
      
      <body>
      	<h1>Hello World Page</h1>
      	<p>Hello World!</p>
      	<p>The time is @DateTime.Now</p>
      </body>
      </html>

      The page contains ordinary HTML markup, with one addition: the @ character marks ASP.NET program code.

    3. Save the page and run it in the browser. You now see the current date and time on the page.
      Hello world with time

      The single line of code you've added does all the work of determining the current time on the server, formatting it for display, and sending it to the browser. (You can specify formatting options; this is just the default.)

    Suppose you want to do something more complex, such as displaying a scrolling list of tweets from a Twitter user that you select. You can use a helper for that; as noted earlier, a helper is a component that simplifies common tasks. In this case, all the work you'd otherwise have to do fetch and display a Twitter feed.

    1. Create a new CSHTML file and name it TwitterFeed.cshtml.
    2. In the page, replace the existing code with the following code:
      <!DOCTYPE html>
      <html lang="en">
      <head>
      	<meta charset="utf-8" />
      	<title>Twitter Feed</title>
      </head>
      
      <body>
      	<h1>Twitter Feed</h1>
      	<form action="" method="POST">
      		<div>
      			Enter the name of another Twitter feed to display: &nbsp;
      			<input type="text" name="TwitterUser" value=""/> &nbsp;
      			<input type="submit" value="Submit" />
      		</div>         
      
      		<div>
      			@if (Request["TwitterUser"].IsEmpty())
      			{
      				@Twitter.Search("microsoft")
      			}
      			else
      			{
      				@Twitter.Profile(Request["TwitterUser"])
      			}
      		</div>
      	</form>
      </body>
      </html>

      This HTML creates a form that displays a text box for entering a user name, plus a Submit button. These are between the first set of <div> tags.

      Between the second set of <div> tags there's some code. (As you saw earlier, to mark code in ASP.NET Web pages, you use the @ character.) The first time this page is displayed, or if the user clicks Submit but leaves the text box blank, the conditional expression Request["TwitterUser"].IsEmpty will be true. In that case, the page shows a Twitter feed that searches for the term "microsoft". Otherwise, the page shows a Twitter feed for whatever user name you entered in the text box.

    3. Run the page in the browser. The Twitter feed displays tweets with "microsoft" in them.
      Twitter page
    4. Enter a Twitter user name and then click Submit. The new feed is displayed. (If you enter a nonexistent name, a Twitter feed is still displayed, it's just blank.)

      This example has shown you a little bit about how you can use WebMatrix and how you can program dynamic web pages using simple ASP.NET code using the Razor syntax. The next tutorial examines code in more depth. The subsequent tutorials then show you how to use code for many different types of website tasks.


    Programming ASP.NET Razor Pages in Visual Studio

    Besides using WebMatrix to program ASP.NET Razor pages, you can also use Visual Studio 2010, either one of the full editions or the free Visual Web Developer Express edition. If you use Visual Studio or Visual Web Developer to edit ASP.NET Razor pages, you get two programming tools that can enhance your productivity—IntelliSense and the debugger. IntelliSense works in the editor by displaying context-appropriate choices. For example, as you enter an HTML element, IntelliSense shows you a list of attributes that the element can have, and it even can show you what values you can set those attributes for. IntelliSense works for HTML, JavaScript, and C# and Visual Basic (the programming languages you use for ASP.NET Razor pages.)

    The debugger lets you stop a program while it's running. You can then examine things like the values of variables, and you can step line by line through the program to see how it runs.

    To work with ASP.NET Razor Pages in Visual Studio, you need the following software installed on your computer:

    • Visual Studio 2010 or Visual Web Developer 2010 Express
    • ASP.NET MVC 3 RTM.

    Note   You can install both Visual Web Developer 2010 Express and ASP.NET MVC 3 using the Web Platform Installer.

    If you have Visual Studio installed, when you are editing a website in WebMatrix, you can launch the site in Visual Studio to take advantage of IntelliSense and the debugger.

    1. Open the site that you created in this tutorial and then click the Files workspace.
    2. In the ribbon, click the Visual Studio Launch button.
      Twitter page

      After the site opens in Visual Studio, you can see the site structure in Visual Studio in the Solution Explorer pane. The following illustration shows the website opened in Visual Web Developer 2010 Express:

      Twitter page

      For an overview of how to use IntelliSense and the debugger with ASP.NET Razor pages in Visual Studio, see the appendix item ASP.NET Web Pages Visual Studio.


    Creating and Testing ASP.NET Pages Using Your Own Text Editor

    April 16 2011

    15:30

    Getting Started with Umbraco: New Premium Series


    Umbraco is a super-friendly, ultra-configurable and uber-powerful .Net-based CMS, and you need it in your life! It is so powerful that you can literally do whatever you want with your site, but it’s so easy to use that even your non-technical clients will be able to pick it up with minimal training. In Part 1 of this 5-part Premium series, I’ll get you started!

    Become a Premium member to read this tutorial, as well as hundreds of other advanced tutorials and screencasts.

    Umbraco

    Where’s the fun in having it all done for you, right?!

    Umbraco can be installed very quickly and easily. Even better, it comes with many features straight out of the box. For example, it’s possible to build an entire site without delving into the code yourself, simply by using pre-built templates and the back-end CMS. But for us developers who like to get our hands dirty, websites can also be coded completely from scratch. In this series, we’ll be creating an entire site ourselves from scratch, because where’s the fun in having it all done for you, right?!


    Join Net Premium

    NETTUTS+ Screencasts and Bonus Tutorials

    For those unfamiliar, the family of Tuts+ sites runs a premium membership service. For $9 per month, you gain access to exclusive premium tutorials, screencasts, and freebies from Nettuts+, Psdtuts+, Aetuts+, Audiotuts+, Vectortuts+, and CgTuts+ For the price of a pizza, you’ll learn from some of the best minds in the business. Become a Premium member to read this tutorial, as well as hundreds of other advanced tutorials and screencasts.

    April 13 2011

    19:00

    ASP.NET from Scratch: Views with MVC3


    ASP.NET MVC3 is now available, and it includes a new View engine called Razor. In this lesson (dubbed 9.5), we download the MVC3 bits and look at Razor and rebuild the application from the previous lesson with the new View engine.


    Subscribe to our YouTube page to watch all of the video tutorials!
    Press the HD button for a clearer picture.

    February 22 2011

    21:41

    ASP.NET from Scratch: Views


    The last major piece of the ASP.NET MVC Framework is the View engine. In this lesson, we look at the default View Engine in MVC2 – the WebForms View Engine – and learn how we can use views to display information to the user.


    The Complete Series


    February 16 2011

    22:00

    ASP.NET and AJAX


    In this tutorial, we’ll take a look at some of the things you can do with ASP.NET and AJAX in your web applications. It’s more than just wrapping an UpdatePanel around some buttons, textboxes and grids!


    Asynchronous JavaScript and XML

    There are many caveats with arbitrarily dropping UpdatePanels onto webforms and hoping for the best.

    Though this tutorial will focus primarily on other components besides the UpdatePanel, it might be useful to take a look at postback triggers as well. Wrapping some controls on a webform in an UpdatePanel is a cheap and cheerful way of implementing Ajax.

    Postbacks caused by the web controls in the UpdatePanel should happen asynchronously and not cause an entire page postback. There are, however, many caveats with arbitrarily dropping UpdatePanels onto webforms and hoping for the best.

    There are also situations in which one may want to conditionally cause a postback of the entire page, or perhaps just make one method call to a backend method or web service to update some small part of the page.


    UpdatePanel

    An UpdatePanel control specifies what regions of a page can be updated asynchronously.

    Let’s start by looking at a simple UpdatePanel control and some of the things it can do out of the box. The control specifies what regions of a page can be updated asynchronously, and thus not require an entire postback of the page.

    Create a new ASP.NET Web Application project. To your default.aspx page, add a ScriptManager control, a TextBox control called txtOutsideUpdatePanel, and an UpdatePanel. Add a ContentTemplate to the UpdatePanel, and, within it, add a Button control called btnInsideUpdatePanel, and a TextBox control called txtInsideUpdatePanel. Below are the salient lines from the source view:

    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:TextBox ID="txtOutsideUpdatePanel" runat="server"></asp:TextBox>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Button runat="server" Text="Update" ID="btnInsideUpdatePanel" />
                <asp:TextBox runat="server" ID="txtInsideUpdatePanel"></asp:TextBox>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
    

    Next, add the following code to the code-behind for the page (or to the script tag if you’re not using the code-behind):

    Public Class _Default
        Inherits System.Web.UI.Page
    
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            txtOutsideUpdatePanel.Text = Now.ToString
        End Sub
    
        Protected Sub btnInsideUpdatePanel_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnInsideUpdatePanel.Click
            txtInsideUpdatePanel.Text = Now.ToString
        End Sub
    End Class
    

    View the page in your web browser, and you should see two textboxes on the webform. The first textbox should have a date and time in it. If you refresh the page, the first textbox should update its date and time. Press the button, and only the second textbox should refresh its date and time. Thus the button is causing an asynchronous postbox, because it’s within the UpdatePanel.

    What we’ve done so far is the easy way of Ajax’ifying a webform. We could easily put an entire grid with paging support within the UpdatePanel for flicker-less paging.

    Let’s look at all this in a little more detail.


    Controlling UpdatePanel Updates

    We can control when the UpdatePanel control posts back based on events that occur to controls both inside and outside the panel itself. Here is the properties window:

    There are three properties of interest to us at present:

    • UpdateMode: Always (default) or Conditional
    • ChildrenAsTriggers: True (default) or False
    • Triggers: A collection of controls – discussed further below

    There are three valid combinations of UpdateMode and ChildrenAsTriggers:

    • Always =True UpdatePanel will refresh when the whole page refreshes, or when a child control posts back.
    • Always = False (invalid)
    • Conditional = True UpdatePanel will refresh when the whole page refreshes, or when a child control posts back, or a trigger from outside of the UpdatePanel causes a refresh.
    • Conditional = False UpdatePanel will refresh when the whole page refreshes, or a trigger outside of the UpdatePanel causes a refresh. A child control will not cause a refresh.

    The next property we’re interested in is the Triggers property, which comes in two flavours:

    • AsyncPostBackTrigger: Causes an asynchronous refresh of the UpdatePanel
    • PostBackTrigger: Causes a page postback by a child control of the UpdatePanel

    Let’s take a look at how these affect the functionality of the UpdatePanel. Paste the following code into a webform, and then the VB.Net code below that into the code-behind.

    We have two buttons inside the panel and two buttons outside. We have wired up the triggers such that a button inside will cause a full page postback, and a button will cause an asynchronous refresh.

        <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="btnAsyncTrigger" />
                <asp:PostBackTrigger ControlID="btnPostBackTrigger" />
            </Triggers>
            <ContentTemplate>
                <asp:Label ID="lblInnerTime" runat="server"></asp:Label>
                <br />
                <asp:Button ID="btnInnerTime" runat="server" Text="Inner Time" />
                <asp:Button ID="btnPostBackTrigger" runat="server" Text="PostBack Trigger" />
            </ContentTemplate>
        </asp:UpdatePanel>
        <br />
        <br />
        <asp:Label ID="lblOuterTime" runat="server"></asp:Label>
        <br />
        <asp:Button ID="btnOuterTime" runat="server" Text="Outer Time" />
        <asp:Button ID="btnAsyncTrigger" runat="server" Text="Async Trigger" />
        </form>
    

    Code-behind:

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
            lblInnerTime.Text = Now
            lblOuterTime.Text = Now
        End Sub
    

    The webform should look as follows:

    Clicking the Inner Time button will cause an asynchronous postback. This is expected, as the button is within the UpdatePanel. Clicking the Outer Time button will cause a full page postback. Again, this is expected, as the Outer Time button is outside the panel.

    The two interesting cases are the PostBack trigger and Async Trigger buttons, to which we make reference in the triggers section of the UpdatePanel. When defining triggers, we need to specify the ControlID of the control acting as a trigger, and optionally the event for which the trigger should fire. If we omit the event, it will fire on the default event for that control.

    Conditional UpdatePanel Updates

    By setting the UpdateMode property of the UpdatePanel to Conditional, and ChildrenAsTriggers to False we can control when updates will be performed. An asynchronous postback will still be performed, but we can decide when to send the updated HTML content for that region of a page to the browser.

    Paste the following code into an ASPX page:

        <form id="form1" runat="server">
        <div>
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="False" >
                <ContentTemplate>
                    <asp:Label ID="lblDateTime" runat="server" Text=""></asp:Label><br />
                    <asp:Button ID="btnAsyncPostBack1" runat="server" Text="Inside UpdatePanel 1" />
                    <asp:Button ID="btnAsyncPostBack2" runat="server" Text="Inside UpdatePanel 2" />
                </ContentTemplate>
            </asp:UpdatePanel>
            <br />
            <asp:Button ID="btnSyncPostBack" runat="server" Text="Outside UpdatePanel" />
        </div>
        </form>
    

    And the following code into its code behind:

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            lblDateTime.Text = Now
        End Sub
    
        Protected Sub btnAsyncPostBack1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAsyncPostBack1.Click
            'Do Nothing
        End Sub
    
        Protected Sub btnAsyncPostBack2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAsyncPostBack2.Click
            UpdatePanel1.Update()
        End Sub
    

    You should get a form that looks like the following:

    • Clicking on the Inside UpdatePanel 1 button will cause an asynchronous postback to occur, but the UpdatePanelwon’t be updated.
    • Clicking on the Inside UpdatePanel 2 button will cause an asynchronous postback to occur, and we are explicitly updating the panel.
    • Clicking on the Outside UpdatePanel will cause a normal full page postback.

    Timers

    We can cause postbacks to occur periodically by using an ASP.NET timer control. This is useful for any regions of a webform that needs live/current data to be visible, such as news feeds or live stock numbers. The Timer.Tick event is fired at an interval defined by the Interval property, which is in milliseconds. It is the Tick event that we can use to cause asynchronous or full page postbacks.

    The way in which the timer control influences the panel can be controlled using the Triggers collection.

    • As a child control of the UpdatePanel, with no triggers defined: refreshes asynchronously on Timer.Tick
    • Outside, with no triggers defined: Entire page posts back on Timer.Tick
    • As a child control, with a PostBackTrigger defined: Entire page posts back on Timer.Tick
    • Outside, with an AsyncPostBackTrigger defined: UpdatePanel refreshes asynchronously on Timer.Tick

    ASP.NET Ajax Client Library

    When you add a ScriptManager control to a webform, it makes the ASP.NET Client Library JavaScript files available to the user’s browser.

    The JavaScript files are taken from the System.Web.Extensions assembly. Visual Studio’s Intellisense will also pick up the functionality exposed by the client library at design time.

    Add a ScriptManager to a webform, add a new <script> tag, type Sys. and you should see a whole host of new bits and pieces to play with. We’ll look at some of the namespaces exposed below.

    The examples consist mostly of JavaScript code, which belongs in a <script> tag.

    Ajax Client Library Namespaces

    • Global Namespace
    • Sys
    • Sys.Net
    • Sys.Serialization
    • Sys.Services
    • Sys.UI
    • Sys.WebForms

    Global Namespace

    The client library provides us with some extensions to existing JavaScript objects. The extensions should make working with JavaScript objects feel a little more like working with managed code. We can also very easily extend existing JavaScript objects ourselves. In addition to extending the functionality of JavaScript objects, the client library also automatically wires up a number of events that we can very easily hook into.

    Arrays:

    Here we are using the sort() and join() extension methods:

        var unsortedArray = [5, 4, 3, 2, 1];
        var sortedArray = unsortedArray.sort();
        alert(sortedArray.join(','));
    

    Here we are extending the Array object by adding a min() method:

        function minElement() {
            var minimum = Infinity;
            for (var i = 0; i < this.length; i++) {
                if (this[i] < minimum) {
                    minimum = this[i];
                }
            }
            return minimum;
        }
    
        var myArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
        Array.prototype.min = minElement;
        alert(myArray.min());
    

    And here we are adding elements to an array:

        var myArray1 = [1, 2, 3];
        var myArray2 = [5, 6, 7];
    
        Array.add(myArray1, 4);
        Array.addRange(myArray2, [8, 9]);
    

    Sys.Debug

    We can use the Sys.Debug.trace() method to display messages in the debugger. This is useful if you want to avoid using alert() calls all over your pages. The debugger messages appear in the Output window in Visual Studio during a debugging session. So this means that you need to "run" the web project and visit the page, or attach to an existing w3p process.

    In the piece of code below, we have a simple loop which causes a divide by zero, which might cause issues in subsequent calculations. By using trace(), we can print out the current value of the counter variable as the loop is running:

        var counter = 10;
        while (counter >= 0) {
            counter -= 1;
            Sys.Debug.trace("Current value of counter = " + counter);
            var someCalculatedValue = 10 / counter;
            document.write(someCalculatedValue + " ");
        }
    

    Now let's use it to help us design and test a new JavaScript object:

        Employee = function(employeeId, name) {
            this.EmployeeId = employeeId;
            this.Name = name;
        }
        Employee.prototype = {
            toString: function () {
                return this.EmployeeId + " : " + this.Name;
            },
            get_Name: function () {
                return this.Name;
            },
            set_Name: function (newName) {
                this.Name = newName;
            }
        }
        Employee.registerClass("Employee");
    
        var jamie = new Employee(123, "Jamie Plenderleith");
        Sys.Debug.trace("Before name change : " + jamie.Name);
    
        jamie.Name = "Jamie Plenderleith Esq.";
        Sys.Debug.trace("After name change : " + jamie.Name);
    

    Events

    The client library wires up some page events that we can hook into easily. Page-specific events are as follows:

    • pageLoad
    • pageUnLoad

    And then we can access some events wired up to the PageRequestManager object which are related to asynchronous postbacks:

    • InitializeRequest
    • BeginRequest
    • PageLoading
    • PageLoaded
    • EndRequest

    Let's use trace() to see when these events fire:

        <form id="form1" runat="server">
        <div>
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                <ContentTemplate>
                    <asp:Button ID="Button1" runat="server" Text="Button" />
                </ContentTemplate>
            </asp:UpdatePanel>
            <script language="javascript" type="text/javascript">
                var myPageRequestManager = Sys.WebForms.PageRequestManager.getInstance();
                myPageRequestManager.add_initializeRequest(onInitializeRequest);
                myPageRequestManager.add_beginRequest(onBeginRequest);
                myPageRequestManager.add_pageLoading(onPageLoading);
                myPageRequestManager.add_pageLoaded(onPageLoaded);
                myPageRequestManager.add_endRequest(onEndRequest);
    
                function pageLoad(sender, args) {
                    Sys.Debug.trace("pageLoad()");
                }
    
                function onInitializeRequest(sender, args) {
                    Sys.Debug.trace("PageRequestManager.InitializeRequest");
                }
                function onBeginRequest(sender, args) {
                    Sys.Debug.trace("PageRequestManager.BeginRequest");
                }
                function onPageLoading(sender, args) {
                    Sys.Debug.trace("PageRequestManager.PageLoading");
                }
                function onPageLoaded(sender, args) {
                    Sys.Debug.trace("PageRequestManager.PageLoaded");
                }
                function onEndRequest(sender, args) {
                    Sys.Debug.trace("PageRequestManager.EndRequest");
                }
    
                function pageUnload(sender, args) {
                    Sys.Debug.trace("pageUnload()");
                }
            </script>
        </div>
        </form>
    

    We could even cancel an asynchronous postback if we want to:

        <form id="form1" runat="server">
        <div>
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                <ContentTemplate>
                    <asp:Button ID="btnUpdateDateTime" runat="server" Text="Update" />
                    <asp:Label ID="lblDateTime" runat="server" Text=""></asp:Label>
                </ContentTemplate>
            </asp:UpdatePanel>
            <script language="javascript" type="text/javascript">
                var myPageRequestManager = Sys.WebForms.PageRequestManager.getInstance();
                myPageRequestManager.add_initializeRequest(onInitializeRequest);
    
                function onInitializeRequest(sender, args) {
                    var someCondition = false;
    
                    if (!someCondition) {
                        Sys.Debug.trace("someCondition=false. Aborting postback");
                        args.set_cancel(true);
                    }
                }
            </script>
        </div>
        </form>
    

    Remote Method Calls

    If the user has a particularly large ViewState, this will cause a lot of extra overhead for both them and the webserver. The remote aspx page will go through nearly its complete lifecycle from loading through to unloading.

    Now we'll take a look at making calls to specific remote methods. These exist entirely separate to the UpdatePanelcontrol, but they'll probably be used in conjunction in order to display the result of some method call.

    When an asynchronous postback occurs within the control, a full postback of the page's ViewState is sent to the webserver. So if the user has a particularly large ViewState, this will cause a lot of extra overhead for both them and the webserver. In addition to the ViewState, the remote aspx page will go through nearly its complete lifecycle from loading through to unloading. We can interface with .NET 2.0 ASP.NET Web Services, .Net 4.0 WCF Services (which act like .Net 2.0 ASP.NET Web Services when using HTTP Transport anyway) and with ASP.NET WebForms PageMethods. We'll take a look at using PageMethods.

    ASPX Page Methods

    A Page Method is a public shared (static in C#) method defined in a webform decorated with System.Web.Services.WebMethod(). In addition to decorating your methods appropriately, your ScriptManager must have its EnablePageMethods property set to True. From there you should see the method available through the PageMethods proxy class in JavaScript.

    Here is a very simple example of a call to managed code to perform a calculation. Paste the following into the source view of a webform:

        <form id="form1" runat="server">
        <div>
            <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
            </asp:ScriptManager>
            y = log <sub>b</sub>(x)<br />
            Base b =
            <input id="txtBase" type="text" /><br />
            Value x =
            <input id="txtValue" type="text" /><br />
            Result y = <span id="lblResult"></span>
            <br />
            <input id="btnCalculate" type="button" value="Calculate" />
            <script language="javascript" type="text/javascript">
                $addHandler($get('btnCalculate'), "click", btnCalculate_onclick);
    
                function btnCalculate_onclick() {
                    PageMethods.CalculateLog($get('txtBase').value, $get('txtValue').value, calculateLog_Finished, calculateLog_Failed);
                }
    
                function calculateLog_Finished(result) {
                    $get('lblResult').innerText = result;
                }
    
                function calculateLog_Failed(errObj) {
                    Sys.Debug.trace(errObj.get_message());
                }
            </script>
        </div>
        </form>
        

    And to the code-behind file add the following code:

        <System.Web.Services.WebMethod()> Public Shared Function CalculateLog(ByVal Value As Double, ByVal Base As Double) As Double
            Return Math.Log(Value, Base)
        End Function
        

    You can see it's a very simple call to the Math.Log() method, but it's executed asynchronously without requiring a postback, and without the use of an UpdatePanel. Observe the PageMethods.CalculateLog() method call. It takes the two parameters required by the method in the code-behind. In the example above, the next parameter is the callback to execute upon successful completion of the method call, and the last parameter is the callback to execute when an error occurs.

    A caveat on PageMethods however: If the class does not appear for you in the JavaScript, you can try a few things:

    • Ensure your code-behind method is Public Shared
    • Ensure there are no JavaScript syntax errors
    • Ensure the ScriptManager's EnablePageMethods property = True
    • Remove and re-add the ScriptManager
    • Perform a rebuild

    A more complete syntax for a PageMethod method call is as follows:

        PageMethods.MethodName(Param1, Param2 ... , ParamN, CompletionCallback, FailureCallback, ContextParameter)
    

    Consider our original calculateLog_Finished() method signature:

        function calculateLog_Finished(result) {}
    

    This method can take additional parameters:

        function calculateLog_Finished(result, context, method) {}
    
    • Result: The result of the method call
    • Context: The value of ContextParameter originally passed by the PageMethods proxy,
      if any
    • Method: The method that was invoked - useful when sharing callbacks

    Further Reading

    There are a plethora of aspects related to Ajax that we haven't touched on. Nonetheless, the following may be of interest to you in your projects:

    Thanks for reading!

    February 03 2011

    22:11

    Extend your .NET Applications with Add-ons


    Your application lacks a cool whizbang feature? Let other interested developers extend your application through add-ons. By opening up your app to additional functionality down the line, you can build a thriving community around your application, potentially even a marketplace!

    In today’s tutorial, we’re going to learn just that!


    Step 0 – Our Game Plan

    Depending on which version of Visual Studio you’re using, and the version of the framework you’re targeting, some screenshots may look slightly different.

    We’re going to build a proof-of-concept application that, upon start-up, loads add-ons that it finds in one of its subdirectories. These add-ons are .NET assemblies that contain at least one class which implements a particular interface as defined by us. The concepts in this tutorial should be easily transferred into your existing applications without much hard work. Then we’ll look at a more complete example utilizing UI components loaded from an add-on.

    This tutorial was written using Microsoft Visual Studio 2010, in VB.NET targeting .NET Framework 4.0. The salient concepts of this tutorial should work in other CLR languages, from .NET Framework 1.1 upwards. There is some minor functionality which will not work in other CLR languages – but should be very easily ported – and some concepts like generics which obviously won’t work in .NET 1.1 etc.

    Note: This is an expert level tutorial for people happy with converting code between different CLR languages and versions of the .NET framework. It’s more ‘replacing your car engine’ than ‘how to drive’.


    Step 1 – Initial Small Scale Implementation

    Note: Your references may be different depending on which version of the .NET Framework you’re targeting.

    Let’s start by implementing a small-scale version of our application. We will need three projects in our solution:

    • ConsoleAppA: A console application
    • ClassLibA: A class library
    • AddonA: A class library that will act as our add-on

    Add a reference from both ConsoleAppA and and AddonA to ClassLibA. Solution explorer should then look as follows:

    Creating the Add-on Interface

    For a compiled class to be considered compatible, every add-on for our application will need to implement a specific interface. This interface will define the required properties and operations that the class must have so that our application can interact with the add-on without hitches. We could also use an abstract/MustInherit class as the basis for add-ons but in this example we’ll use an interface.

    Here is the code for our interface, which should be placed in a file called IApplicationModule within the ClassLibA class library.

    Public Interface IApplicationModule
    
        ReadOnly Property Id As Guid
        ReadOnly Property Name As String
    
        Sub Initialise()
    
    End Interface
    

    The properties and methods you define in the interface are arbitrary. In this case,, I have defined two properties and one method, but in practice you can and should change these as required.

    We’re not going to use the Id or Name properties in our first example, but they’re useful properties to implement, and you’d probably want these present if you’re using add-ons in production.

    Creating an Add-on

    Now let’s create the actual add-on. Again, for any class to be considered an add-on for our application, it needs to implement our interface – IApplicationModule.

    Here is the code for our basic add-on, which should be placed in a file called MyAddonClass within the AddonA class library.

    Imports ClassLibA
    
    Public Class MyAddonClass
        Implements IApplicationModule
    
        Public ReadOnly Property Id As System.Guid Implements ClassLibA.IApplicationModule.Id
            Get
                Return New Guid("adb86b53-2207-488e-b0f3-ecd13eae4042")
            End Get
        End Property
    
        Public Sub Initialise() Implements ClassLibA.IApplicationModule.Initialise
            Console.WriteLine("MyAddonClass is starting up ...")
            'Perform start-up initialisation here ...
        End Sub
    
        Public ReadOnly Property Name As String Implements ClassLibA.IApplicationModule.Name
            Get
                Return "My first test add-on"
            End Get
        End Property
    End Class
    

    Step 2 – Finding Add-ons at Runtime

    Next, we need a way to find add-ons for our application. In this example, we’ll assume that an Addons folder has been created in the executable’s directory. If you’re testing this within Visual Studio, bear in mind the default project output directory for projects, namely ./bin/debug/, so you would need a ./bin/debug/Addons/ directory.

    Time to Reflect

    Place the TryLoadAssemblyReference method below into Module1 of ConsoleAppA. We investigate the loaded assembly through the use of Reflection. A pseudo-code walkthrough of its functionality is as follows:

    • Try to load the given dllFilePath as a .NET assembly
    • If we’ve successfully loaded the assembly, proceed
    • For each module in the loaded assembly
    • For each type in that module
    • For each interface implemented by that type
    • If that interface is our add-on interface (IApplicationModule), then
    • Keep a record of that type. Finish searching.
    • Finally, return any valid types found
        Private Function TryLoadAssemblyReference(ByVal dllFilePath As String) As List(Of System.Type)
            Dim loadedAssembly As Assembly
            Dim listOfModules As New List(Of System.Type)
            Try
                loadedAssembly = Assembly.LoadFile(dllFilePath)
            Catch ex As Exception
            End Try
            If loadedAssembly IsNot Nothing Then
                For Each assemblyModule In loadedAssembly.GetModules
                    For Each moduleType In assemblyModule.GetTypes()
                        For Each interfaceImplemented In moduleType.GetInterfaces()
                            If interfaceImplemented.FullName = "ClassLibA.IApplicationModule" Then
                                listOfModules.Add(moduleType)
                            End If
                        Next
                    Next
                Next
            End If
            Return listOfModules
        End Function
    

    Firing up our Add-ons

    Finally, we can now load a compiled class that implements our interface into memory. But we don’t have any code to find, instantiate, or make method calls on those classes. Next we’ll put together some code that does just that.

    The first part is to find all files which might be add-ons, as below. The code performs some relatively straightforward file searching, and for each DLL file found, attempts to load all of the valid types from that assembly. DLLs discovered under the Addons folder aren’t necessarily add-ons – they could simply contain extra functionality required by an add-on, but not actually be an add-on per se.

            Dim currentApplicationDirectory As String = My.Application.Info.DirectoryPath
            Dim addonsRootDirectory As String = currentApplicationDirectory & "\Addons\"
            Dim addonsLoaded As New List(Of System.Type)
    
            If My.Computer.FileSystem.DirectoryExists(addonsRootDirectory) Then
                Dim dllFilesFound = My.Computer.FileSystem.GetFiles(addonsRootDirectory, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dll")
                For Each dllFile In dllFilesFound
                    Dim modulesFound = TryLoadAssemblyReference(dllFile)
                    addonsLoaded.AddRange(modulesFound)
                Next
            End If
    

    Next we need to do something each valid type we’ve found. The code below will create a new instance of the type, type the type, call the Initialise() method (which is just an arbitrary method we defined in our interface), and then keep a reference to that instantiated type in a module level list.

            If addonsLoaded.Count > 0 Then
                For Each addonToInstantiate In addonsLoaded
                    Dim thisInstance = Activator.CreateInstance(addonToInstantiate)
                    Dim thisTypedInstance = CType(thisInstance, ClassLibA.IApplicationModule)
                    thisTypedInstance.Initialise()
                    m_addonInstances.Add(thisInstance)
                Next
            End If
    

    Putting it all together, our console application should begin to look something like so:

    Imports System.Reflection
    
    Module Module1
    
        Private m_addonInstances As New List(Of ClassLibA.IApplicationModule)
    
        Sub Main()
            LoadAdditionalModules()
    
            Console.WriteLine('Finished loading modules ...')
            Console.ReadLine()
        End Sub
    
        Private Sub LoadAdditionalModules()
            Dim currentApplicationDirectory As String = My.Application.Info.DirectoryPath
            Dim addonsRootDirectory As String = currentApplicationDirectory & '\Addons\'
            Dim addonsLoaded As New List(Of System.Type)
    
            If My.Computer.FileSystem.DirectoryExists(addonsRootDirectory) Then
                Dim dllFilesFound = My.Computer.FileSystem.GetFiles(addonsRootDirectory, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dll")
                For Each dllFile In dllFilesFound
                    Dim modulesFound = TryLoadAssemblyReference(dllFile)
                    addonsLoaded.AddRange(modulesFound)
                Next
            End If
    
            If addonsLoaded.Count > 0 Then
                For Each addonToInstantiate In addonsLoaded
                    Dim thisInstance = Activator.CreateInstance(addonToInstantiate)
                    Dim thisTypedInstance = CType(thisInstance, ClassLibA.IApplicationModule)
                    thisTypedInstance.Initialise()
                    m_addonInstances.Add(thisInstance)
                Next
            End If
        End Sub
    
        Private Function TryLoadAssemblyReference(ByVal dllFilePath As String) As List(Of System.Type)
            Dim loadedAssembly As Assembly
            Dim listOfModules As New List(Of System.Type)
            Try
                loadedAssembly = Assembly.LoadFile(dllFilePath)
            Catch ex As Exception
            End Try
            If loadedAssembly IsNot Nothing Then
                For Each assemblyModule In loadedAssembly.GetModules
                    For Each moduleType In assemblyModule.GetTypes()
                        For Each interfaceImplemented In moduleType.GetInterfaces()
                            If interfaceImplemented.FullName = 'ClassLibA.IApplicationModule' Then
                                listOfModules.Add(moduleType)
                            End If
                        Next
                    Next
                Next
            End If
            Return listOfModules
        End Function
    End Module
    

    Trial Run

    At this point we should be able to perform a full build of our solution. When your files have been built, copy the compiled assembly output of the AddonA project into the Addons folder of ConsoleAppA. The Addons folder should be created under the /bin/debug/ folder. On my machine using Visual Studio 2010, default project locations and a solution called “DotNetAddons” the folder is here:

    C:\Users\jplenderleith\Documents\Visual Studio 2010\Projects\DotNetAddons\ConsoleAppA\bin\Debug\Addons

    We should see the following output when we run the code is run:

    MyAddonClass is starting up ...
    Finished loading modules ...
    

    As it stands it’s not flashy or impressive but it does demonstrate a key piece of functionality, namely that at runtime we can pick up an assembly and execute code within that assembly without having any existing knowledge about that assembly. This is the foundation of building more complex add-ons.


    Step 3 – Integrating with a User Interface

    Next, we’ll take a look at building a couple of add-ons to provide additional functionality within a Windows Forms application.

    Similar to the existing solution, create a new solution with the following projects:

    • WinFormsAppA: A Windows Forms application
    • ClassLibA: A class library
    • UIAddonA: A class library that will house a couple of add-ons with UI components

    Similar to our previous solution, both the WinFormsAppA and UIAddonA projects should have references to the ClassLibA. The UIAddonA project will also need a reference to the System.Windows.Forms for access to functionality.

    The Windows Forms Application

    We’ll make a quick and simple UI for our application consisting of a MenuStrip and a DataGridView. The MenuStrip control should have three MenuItems

    • File
    • Add-ons
    • Help

    Dock the DataGridView to its parent container – the form itself. We’ll put together some code to display some mock data in our grid. The Add-ons MenuItem will be populated by any add-ons that have been loaded on application start-up.

    Here’s a screenshot of the application at this point:

    Let’s write some code to give the main form of WinFormsAppA some functionality. When the form loads it’ll call the LoadAddons() method which is currently empty – we’ll fill that in later. Then we generate some sample employee data to which we bind our DataGridView.

    Public Class Form1
    
        Private m_testDataSource As DataSet
        Private m_graphicalAddons As List(Of System.Type)
    
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            LoadAddons()
            m_testDataSource = GenerateTestDataSet()
            With DataGridView1
                .AutoGenerateColumns = True
                .AutoResizeColumns()
                .DataSource = m_testDataSource.Tables(0)
            End With
        End Sub
    
        Private Sub LoadAddons()        
    
        End Sub
    
        Private Function GenerateTestDataSet() As DataSet
            Dim newDataSet As New DataSet
            Dim newDataTable As New DataTable
            Dim firstNames = {"Mary", "John", "Paul", "Justyna", "Michelle", "Andrew", "Michael"}
            Dim lastNames = {"O'Reilly", "Murphy", "Simons", "Kelly", "Gates", "Power"}
            Dim deptNames = {"Marketing", "Sales", "Technical", "Secretarial", "Security"}
    
            With newDataTable
                .Columns.Add("EmployeeId", GetType(Integer))
                .Columns.Add("Name", GetType(String))
                .Columns.Add("IsManager", GetType(Boolean))
                .Columns.Add("Department", GetType(String))
            End With
    
            For i = 1 To 100
                Dim newDataRow As DataRow = newDataTable.NewRow()
                With newDataRow
                    .Item("EmployeeId") = i
                    .Item("Name") = firstNames(i Mod firstNames.Count) & " " & lastNames(i Mod lastNames.Count)
                    .Item("IsManager") = ((i Mod 20) = 0)
                    .Item("Department") = deptNames(i Mod deptNames.Count)
                End With
                newDataTable.Rows.Add(newDataRow)
            Next
    
            newDataSet.Tables.Add(newDataTable)
            Return newDataSet
        End Function
    
    End Class
    

    When we run the application it should look like so:

    We’ll come back to our empty LoadAddons() after we’ve defined the add-on interfaces.

    Add-on Interface

    Let’s define our add-on interface. UI components will be listed under the Add-ons MenuStrip, and will open up a windows form that has access to the data to which our DataGrid is bound. To the ClassLibA project add a new interface file called IGraphicalAddon and paste in the following code into the file:

    Public Interface IGraphicalAddon
    
        ReadOnly Property Name As String
        WriteOnly Property DataSource As DataSet
        Sub OnClick(ByVal sender As Object, ByVal e As System.EventArgs)
    
    End Interface
    
    • We have a Name property, which is pretty self-explanatory.
    • The DataSource properly is used to ‘feed’ data to this add-on.
    • The OnClick method, which will be used as the handler when users click on our add-on’s entry in the Addons menu.

    Loading the Add-ons

    Add a class library called AddonLoader to the ClassLibA assembly project, with the following code:

    Imports System.Reflection
    
    Public Class AddonLoader
        Public Enum AddonType
            IGraphicalAddon = 10
            ISomeOtherAddonType2 = 20
            ISomeOtherAddonType3 = 30
        End Enum
    
        Public Function GetAddonsByType(ByVal addonType As AddonType) As List(Of System.Type)
            Dim currentApplicationDirectory As String = My.Application.Info.DirectoryPath
            Dim addonsRootDirectory As String = currentApplicationDirectory & "\Addons\"
            Dim loadedAssembly As Assembly
            Dim listOfModules As New List(Of System.Type)
    
            If My.Computer.FileSystem.DirectoryExists(addonsRootDirectory) Then
                Dim dllFilesFound = My.Computer.FileSystem.GetFiles(addonsRootDirectory, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dll")
                For Each dllFile In dllFilesFound
    
                    Try
                        loadedAssembly = Assembly.LoadFile(dllFile)
                    Catch ex As Exception
                    End Try
                    If loadedAssembly IsNot Nothing Then
                        For Each assemblyModule In loadedAssembly.GetModules
                            For Each moduleType In assemblyModule.GetTypes()
                                For Each interfaceImplemented In moduleType.GetInterfaces()
                                    If interfaceImplemented.Name = addonType.ToString Then
                                        listOfModules.Add(moduleType)
                                    End If
                                Next
                            Next
                        Next
                    End If
    
                Next
            End If
    
            Return listOfModules
        End Function
    End Class
    

    You could use code similar to this to restrict add-on developers to build only specific types of add-ons

    In this class, we’ve provided a way to load different types of add-ons. You could use code similar to this to restrict add-on developers to build only specific types of add-ons, or to at least categorise them. In our example, we’ll just be using the first add-on type declared, namely IGraphicalAddon.

    If we had other add-on types in our project, for example to enhance reporting functionality or provide some useful keyboard shortcuts, then we don’t want them listed in our Add-ons menu, as there’s no point in someone being able to click on that add-on.

    Having said that though, it may be desirable to add a reference to all add-ons under some menubar, click on which would cause the add-on’s options form to be displayed. This however is beyond of the scope of this tutorial.

    The Graphical Add-on

    Let’s build the actual UI add-on. To the UIAddonA assembly project add the following two files; a class called UIReportAddon1 and a windows form called UIReportAddon1Form. The UIReportAddon1 class will contain the following code:

    Imports ClassLibA
    
    Public Class UIReportAddon1
        Implements ClassLibA.IGraphicalAddon
    
        Private _dataSource As DataSet
        Public WriteOnly Property DataSource As System.Data.DataSet Implements IGraphicalAddon.DataSource
            Set(ByVal value As System.Data.DataSet)
                _dataSource = value
            End Set
        End Property
    
        Public ReadOnly Property Name As String Implements IGraphicalAddon.Name
            Get
                Return "Managers Report"
            End Get
        End Property
    
        Public Sub OnClick(ByVal sender As Object, ByVal e As System.EventArgs) Implements IGraphicalAddon.OnClick
            Dim newUiReportingAddonForm As New UIReportAddon1Form
            newUiReportingAddonForm.SetData(_dataSource)
            newUiReportingAddonForm.ShowDialog()
        End Sub
    End Class
    

    To UIReportAddon1Form add a DataGridView that’s docked within its parent container. Then add the following code:

    Public Class UIReportAddon1Form
    
        Private m_providedDataSource As DataSet
    
        Public Sub SetData(ByVal DataSource As System.Data.DataSet)
            m_providedDataSource = DataSource
            FilterAndShowData()
        End Sub
    
        Private Sub FilterAndShowData()
            Dim managers = m_providedDataSource.Tables(0).Select("IsManager = True")
            Dim newDataTable = m_providedDataSource.Tables(0).Clone
            For Each dr In managers
                newDataTable.ImportRow(dr)
            Next
            DataGridView1.DataSource = newDataTable
        End Sub
    
        Private Sub UIReportAddon1Form_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Text = "List of managers"
        End Sub
    End Class
    

    We’re simply providing the means to send data to the form, and then let it decide what to do with said data. In this case, we’re going to perform a Select() on a DataTable, retrieving back a list of all employees who are managers.

    Back to our Main UI

    Now it’s time to complete our unfinished LoadAddons() method in our WinFormsAppA project. This code will instruct the GetAddonsByType method of ClassLibA.AddonLoader to find a particular type of add-on – in this case IGraphicalAddon add-ons.

    For each add-on found, the following actions are performed

    • Create a new instance of the add-on
    • Type the add-on instance to IGraphicalAddon
    • Populate its DataSource property
    • Add the add-on to the Add-ons menu item
    • Add a handler for that menu item’s Click event
        Private Sub LoadAddons()
            Dim loader As New ClassLibA.AddonLoader
            Dim addonsLoaded = loader.GetAddonsByType(ClassLibA.AddonLoader.AddonType.IGraphicalAddon)
    
            For Each graphicalAddon In addonsLoaded
                Dim thisInstance = Activator.CreateInstance(graphicalAddon)
                Dim typedAddon = CType(thisInstance, ClassLibA.IGraphicalAddon)
                typedAddon.DataSource = m_testDataSource
                Dim newlyAddedToolstripItem = AddonsToolStripMenuItem.DropDownItems.Add(typedAddon.Name)
                AddHandler newlyAddedToolstripItem.Click, AddressOf typedAddon.OnClick
            Next
        End Sub
        

    Testing our UI

    Ensure you can perform a full successful compile of the solution. Copy the UIAddonA.dll from the output debug folder of the UIAddonA project into the /bin/debug/Addons/ folder of the WinFormsAppA project. When you run the project, you should see a grid of data, as before. If you click into the Add-ons menu however you should now see a reference to the newly created add-on.

    When we click on the Managers Report menu item, this will case a method call to the OnClick method implemented in our add-on, which will cause UIReportAddon1Form to appear, as below.


    Wrap Up

    We’ve seen two examples of building an application which can pickup and run add-ons as required. As I mentioned earlier, it should be easy enough to integrate this type of functionality into existing applications. The question of how much control you’ll need (or want) to give third party developers is another matter entirely.

    I hope you had fun with this tutorial! Thank you so much for reading!

    Want to talk specifics? Discuss this post on the forums.

    December 16 2010

    14:30

    Create ASP.NET Server Controls from Scratch


    In this tutorial, you will learn how to build an ASP.NET server control by creating a HTML5 video player control. Along the way, we’ll review the fundamental process of server control development from scratch.


    Introduction

    ASP.NET comes with its own set of server-side controls, so why create our own?

    By creating our own controls, we can then build powerful, reusable visual components for our Web application’s user interface.

    This tutorial will introduce you to the process of ASP.NET server control development. You’ll also see how creating your own controls can simultaneously improve the quality of your Web applications, make you more productive and improve your user interfaces.

    ASP.NET custom controls are more flexible than user controls. We can create a custom control that inherits from another server-side control and then extend that control. We can also share a custom control among projects. Typically, we will create our custom control in a web custom control library that is compiled separately from our web application. As a result, we can add that library to any project in order to use our custom control in that project.


    HTML5 Video Overview

    Until now, there has never been a native way to display video on a web page. Today, most videos are shown, via the use of a plugin (like Flash or Silverlight). However, not all browsers have the same plugins. HTML5 specifies a standard, native way to include video, with the video element.

    Currently, there are two widely supported video formats for the video element: Ogg files [encoded with Theora and Vorbis for video and audio respectively] and MPEG 4 files [encoded with H.264 and AAC].

    To show a video in HTML5, this is all we need:

    <video width="320" height="240" controls="controls">
      <source src="movie.ogg" type="video/ogg" />
      <source src="movie.mp4" type="video/mp4" />
    </video>
            

    The controls attribute is for adding play, pause and volume controls. Without this attribute, your video would appear to be only an image. It is also always a good idea to include both the width and height attributes. The following table shows all attributes of the <video> element:

    • autoplay: Specifies that the video will start playing as soon as it is ready
    • controls: Specifies that controls will be displayed, such as a play button
    • height: The height of the video player
    • loop: Specifies that the media file will start over again, every time it is finished
    • preload: Specifies that the video will be loaded at page load, and ready to run. Ignored if “autoplay” is present
    • src: The URL of the video to play
    • width: The width of the video player
    • poster: The URL of the image to show while no video data is available

    Step 0: Getting Started

    All that is required to get started is a copy of Visual Studio of Visual Web Developer Express. If you don't have the full version of Visual Studio, you can grab the free Express Edition.

    The HTML5 video player that we will create here is only a simple video player that will render whatever native interface the browser provides. Browsers that support HTML5 video have video players built in, including a set of controls (play/pause etc.), so you will see a different interface for each browser when running this control.

    HTML5 Video Player of Firefox
    The HTML5 video player in Firefox 3.6.8.

    Step 1: Creating a Custom Control Project

    First, we need to create a new class library project to hold our custom controls. By creating the custom control in a separate class library, we can compile the project into a separate DLL and use the custom control in any application that requires it.

    Open your ASP.NET project with Visual Studio or Visual Web Developer. In Solution Explorer, right click the solution name, and select Add New Project from the context menu. In the Add New Project dialog box, choose the project type to be a Web project, and select ASP.NET Server Control as the template, like so:

    Add New Project

    Name the project CustomControls. Click OK. The new ASP.NET Server Control project is created, and Visual Studio also provides you with a simple Web control to start with. Delete this custom control because we don't need it.


    Step 2: Adding a Web Custom Control to the Project

    In Solution Explorer, right click the CustomControls project, and select Add New Item from the context menu. In the Add New Item dialog box, choose the category type to be a Web category, and select ASP.NET Server Control in the templates.

    Add New Item

    Name the new custom control VideoPlayer. Click Add. The new custom control (VideoPlayer.cs) is created and added to the CustomControls project.

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace CustomControls
    {
        [DefaultProperty("Text")]
        [ToolboxData("<{0}:VideoPlayer runat=server></{0}:VideoPlayer>")]
        public class VideoPlayer : WebControl
        {
            [Bindable(true)]
            [Category("Appearance")]
            [DefaultValue("")]
            [Localizable(true)]
            public string Text
            {
                get
                {
                    String s = (String)ViewState["Text"];
                    return ((s == null) ? "[" + this.ID + "]" : s);
                }
    
                set
                {
                    ViewState["Text"] = value;
                }
            }
    
            protected override void RenderContents(HtmlTextWriter output)
            {
                output.Write(Text);
            }
        }
    }
            

    The code above is the default code generated by Visual Studio for a web control library. To start working with VideoPlayer.cs, we need to modify the code above. The first thing that we should do is delete everything between the class declaration line and the end of the class. That leaves us with this code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace CustomControls
    {
        [DefaultProperty("Text")]
        [ToolboxData("<{0}:VideoPlayer runat=server></{0}:VideoPlayer>")]
        public class VideoPlayer : WebControl
        {
    
        }
    }
            

    As you see above, the VideoPlayer class derives from the System.Web.UI.WebControl class. In fact, all ASP.NET server-side controls derive from the WebControl class.


    Step 3: Modifying the Class Declaration Line

    The class declaration line in the default code also specifies the default property for the VideoPlayer control as the Text property. The VideoPlayer control that we create here doesn't have a property called Text. So, delete the reference to Text as the default property. After all the modifications, the VideoPlayer.cs code file should look like this:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace CustomControls
    {
        [ToolboxData("<{0}:VideoPlayer runat=server></{0}:VideoPlayer>")]
        public class VideoPlayer : WebControl
        {
    
        }
    }
            

    Step 4: Adding Properties

    In this step, we will add some properties to the VideoPlayer control to handle the control's behaviour. The following is the list of properties that we will add to the VideoPlayer.cs code file:

    • VideoUrl: A string property which specifies the URL of the video to play.
    • PosterUrl: A string property which specifies the address of an image file to show while no video data is available.
    • AutoPlay: A boolean property to specify whether the video should automatically start playing or not, when the webpage is opened.
    • DisplayControlButtons: A boolean property that specifies whether the player navigation buttons are displayed or not.
    • Loop: A boolean property that specifies whether the video will start over again or not, every time it is finished.

    Add the following code to the VideoPlayer class:

    private string _Mp4Url;
    public string Mp4Url
    {
        get { return _Mp4Url; }
        set { _Mp4Url = value; }
    }
    
    private string _OggUrl = null;
    public string OggUrl
    {
        get { return _OggUrl; }
        set { _OggUrl = value; }
    }
    
    private string _Poster = null;
    public string PosterUrl
    {
        get { return _Poster; }
        set { _Poster = value; }
    }
    
    private bool _AutoPlay = false;
    public bool AutoPlay
    {
        get { return _AutoPlay; }
        set { _AutoPlay = value; }
    }
    
    private bool _Controls = true;
    public bool DisplayControlButtons
    {
        get { return _Controls; }
        set { _Controls = value; }
    }
    
    private bool _Loop = false;
    public bool Loop
    {
        get { return _Loop; }
        set { _Loop = value; }
    }
            

    After we have added the above properties, the VideoPlayer class should look like

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace CustomControls
    {
        [ToolboxData("<{0}:VideoPlayer runat=server></{0}:VideoPlayer>")]
        public class VideoPlayer : WebControl
        {
            private string _Mp4Url;
            public string Mp4Url
            {
                get { return _Mp4Url; }
                set { _Mp4Url = value; }
            }
    
            private string _OggUrl = null;
            public string OggUrl
            {
                get { return _OggUrl; }
                set { _OggUrl = value; }
            }
    
            private string _Poster = null;
            public string PosterUrl
            {
                get { return _Poster; }
                set { _Poster = value; }
            }
    
            private bool _AutoPlay = false;
            public bool AutoPlay
            {
                get { return _AutoPlay; }
                set { _AutoPlay = value; }
            }
    
            private bool _Controls = true;
            public bool DisplayControlButtons
            {
                get { return _Controls; }
                set { _Controls = value; }
            }
    
            private bool _Loop = false;
            public bool Loop
            {
                get { return _Loop; }
                set { _Loop = value; }
            }
        }
    }
            

    Step 5: Creating the RenderContents Method

    The primary job of a server control is to render some type of markup language to the HTTP output stream, which is returned to and displayed by the client. It is our responsibility as the control developer to tell the server control what markup to render. The overridden RenderContents method is the primary location where we tell the control what we want to render to the client.

    Add the following override RenderContents method to the VideoPlayer class:

    protected override void RenderContents(HtmlTextWriter output)
    {
    
    }
            

    Notice that the RenderContents method has one method parameter called output. This parameter is an HtmlTextWriter object, which is what the control uses to render HTML to the client. The HtmlTextwriter class has a number of methods you can use to render your HTML, including AddAttribute and RenderBeginTag.


    Step 6: Adding Tag Attributes

    Before we write the code to render the <video> element, the first thing to do is add some attributes for it. We can use the AddAttribute method of the HtmlTextWriter object to add attributes for HTML tags.

    Append the following code into the RenderContents method:

    output.AddAttribute(HtmlTextWriterAttribute.Id, this.ID);
    output.AddAttribute(HtmlTextWriterAttribute.Width, this.Width.ToString());
    output.AddAttribute(HtmlTextWriterAttribute.Height, this.Height.ToString());
    
    if (DisplayControlButtons == true)
    {
        output.AddAttribute("controls", "controls");
    }
    
    if (PosterUrl != null)
    {
        output.AddAttribute("poster", PosterUrl);
    }
    
    if (AutoPlay == true)
    {
        output.AddAttribute("autoplay", "autoplay");
    }
    
    if (Loop == true)
    {
        output.AddAttribute("loop", "loop");
    }
            

    You can see that, by using the AddAttribute method, we have added seven attributes to the tag. Also notice that we are using an enumeration, HtmlTextWriterAttribute, to select the attribute we want to add to the tag.

    After we have added the code above, the RenderContents method should look like so:

    protected override void RenderContents(HtmlTextWriter output)
    {
        output.AddAttribute(HtmlTextWriterAttribute.Id, this.ID);
        output.AddAttribute(HtmlTextWriterAttribute.Width, this.Width.ToString());
        output.AddAttribute(HtmlTextWriterAttribute.Height, this.Height.ToString());
    
        if (DisplayControlButtons == true)
        {
            output.AddAttribute("controls", "controls");
        }
    
        if (PosterUrl != null)
        {
            output.AddAttribute("poster", PosterUrl);
        }
    
        if (AutoPlay == true)
        {
            output.AddAttribute("autoplay", "autoplay");
        }
    
        if (Loop == true)
        {
            output.AddAttribute("loop", "loop");
        }
    }
            

    Step 7: Rendering the <video> Element

    After adding some tag attributes for the video element, it's time to render the <video> tag with its attributes onto the HTML document. Add the following code into the RenderContents method:

    output.RenderBeginTag("video");
    if (OggUrl != null)
    {
        output.AddAttribute("src", OggUrl);
        output.AddAttribute("type", "video/ogg");
        output.RenderBeginTag("source");
        output.RenderEndTag();
    }
    
    if (Mp4Url != null)
    {
        output.AddAttribute("src", Mp4Url);
        output.AddAttribute("type", "video/mp4");
        output.RenderBeginTag("source");
        output.RenderEndTag();
    }
    output.RenderEndTag();
            

    We use the RenderBeginTag method of output object to render the opening tag of the video element, and RenderEndTag to render its closing tag. We also added the <source> element between the <video> element. The video element allows multiple source elements. Source elements can link to different video files. The browser will use the first recognized format.

    The RenderContents method should look like this after we have added the code above:

    protected override void RenderContents(HtmlTextWriter output)
    {
        output.AddAttribute(HtmlTextWriterAttribute.Id, this.ID);
        output.AddAttribute(HtmlTextWriterAttribute.Width, this.Width.ToString());
        output.AddAttribute(HtmlTextWriterAttribute.Height, this.Height.ToString());
    
        if (DisplayControlButtons == true)
        {
            output.AddAttribute("controls", "controls");
        }
    
        if (PosterUrl != null)
        {
            output.AddAttribute("poster", PosterUrl);
        }
    
        if (AutoPlay == true)
        {
            output.AddAttribute("autoplay", "autoplay");
        }
    
        if (Loop == true)
        {
            output.AddAttribute("loop", "loop");
        }
    
        output.RenderBeginTag("video");
        if (OggUrl != null)
        {
            output.AddAttribute("src", OggUrl);
            output.AddAttribute("type", "video/ogg");
            output.RenderBeginTag("source");
            output.RenderEndTag();
            }
    
        if (Mp4Url != null)
        {
            output.AddAttribute("src", Mp4Url);
            output.AddAttribute("type", "video/mp4");
            output.RenderBeginTag("source");
            output.RenderEndTag();
        }
        output.RenderEndTag();
    }
            

    Notice that the order in which we place the AddAttributes methods is important. We place the AddAttributes methods directly before the RenderBeginTag method in the code. The AddAttributes method associates the attributes with the next HTML tag that is rendered by the RenderBeginTag method, in this case the video tag.


    Step 8: Removing the Span Tag

    By default, ASP.NET will surround the control tag with a <span> element when rendering the control's HTML markup. If we have provided an ID value for our control, then the Span tag will also, by default, render an ID attribute. Having the tags can sometimes be problematic, so if we want to prevent this in ASP.NET, we can simply override the Render method and call the RenderContents method directly. Here's how to do that:

    protected override void Render(HtmlTextWriter writer)
    {
        this.RenderContents(writer);
    }
            

    After we have added the code above, the VideoPlayer class should look like this:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace CustomControls
    {
        [ToolboxData("<{0}:VideoPlayer runat=server></{0}:VideoPlayer>")]
        public class VideoPlayer : WebControl
        {
            private string _Mp4Url;
            public string Mp4Url
            {
                get { return _Mp4Url; }
                set { _Mp4Url = value; }
            }
    
            private string _OggUrl = null;
            public string OggUrl
            {
                get { return _OggUrl; }
                set { _OggUrl = value; }
            }
    
            private string _Poster = null;
            public string PosterUrl
            {
                get { return _Poster; }
                set { _Poster = value; }
            }
    
            private bool _AutoPlay = false;
            public bool AutoPlay
            {
                get { return _AutoPlay; }
                set { _AutoPlay = value; }
            }
    
            private bool _Controls = true;
            public bool DisplayControlButtons
            {
                get { return _Controls; }
                set { _Controls = value; }
            }
    
            private bool _Loop = false;
            public bool Loop
            {
                get { return _Loop; }
                set { _Loop = value; }
            }
    
            protected override void RenderContents(HtmlTextWriter output)
            {
                output.AddAttribute(HtmlTextWriterAttribute.Id, this.ID);
                output.AddAttribute(HtmlTextWriterAttribute.Width, this.Width.ToString());
                output.AddAttribute(HtmlTextWriterAttribute.Height, this.Height.ToString());
                if (DisplayControlButtons == true)
                {
                    output.AddAttribute("controls", "controls");
                }
    
                if (PosterUrl != null)
                {
                    output.AddAttribute("poster", PosterUrl);
                }
    
                if (AutoPlay == true)
                {
                    output.AddAttribute("autoplay", "autoplay");
                }
    
                if (Loop == true)
                {
                    output.AddAttribute("loop", "loop");
                }
    
                output.RenderBeginTag("video");
                if (OggUrl != null)
                {
                    output.AddAttribute("src", OggUrl);
                    output.AddAttribute("type", "video/ogg");
                    output.RenderBeginTag("source");
                    output.RenderEndTag();
                }
    
                if (Mp4Url != null)
                {
                    output.AddAttribute("src", Mp4Url);
                    output.AddAttribute("type", "video/mp4");
                    output.RenderBeginTag("source");
                    output.RenderEndTag();
                }
                output.RenderEndTag();
            }
    
            protected override void Render(HtmlTextWriter writer)
            {
                this.RenderContents(writer);
            }
        }
    }
            

    Our control is now finished! All we have left to do is build the project before we use it on a ASP.NET web page.


    Step 9: Building the Project

    It's time to build the project. Select Build, and then click Build Solution from the main menu.

    Build Solution

    After building the project, the next step is to add the VideoPlayer control into the Toolbox Explorer.


    Step 10: Adding VideoPlayer Control to the Visual Studio Toolbox

    • To add the VideoPlayer control to the Toolbox, right click in the Toolbox Explorer
    • Choose Items from the context menu
    • Click the Browse button in the Choose Toolbox Items dialog box
    • Navigate to the ASP.NET project directory
    • Go to the CustomControls directory
    • Open the Bin\Debug directory (Visual Studio builds debug versions by default.)
    • Select the CustomControls.DLL assembly and click on the Open button
    Choose Toolbox Items

    VideoPlayer will appear in the Choose Toolbox Items dialog box as shown in the image above. The check box will show it as selected. As soon as you click the OK button in the Choose Toolbox Items dialog box, the new VideoPlayer control will appear in the toolbox.

    Visual Studio Toolbox Explorer

    Step 11: Placing the VideoPlayer Control on ASP.NET Web Page

    To see how the control works, we need to give it a home. Add a new page to the website. Right click the ASP.NET project from the Solution Explorer. Select Add New Item, and add a Web Form. Name the Web Form VideoPlayerTest.aspx.

    To place the control on the page, switch to Design mode. Drag the VideoPlayer control from the Toolbox and drop it onto the VideoPlayerTest.aspx design view.

    The following Listing shows how the control is declared on the page:

    <cc1:VideoPlayer ID="VideoPlayer1" runat="server" Mp4Url="videos/movie.mp4" OggUrl="videos/movie.ogg" Width="400" Height="300" />
            

    The following line of code is what Visual Studio added to the ASPX file to accommodate the control. You can see it by selecting the Source tab from the bottom of the code window in Visual Studio. The Register directive tells the ASP.NET runtime where to find the custom control (which assembly) and maps it to a tag prefix.

    <%@ Register assembly="CustomControls" namespace="CustomControls" tagprefix="cc1" %>
            

    We can now test the control.

    HTML5 Video Player
    VideoPlayer control running on Google Chrome.

    Summary

    In this tutorial, you learned how to create your own ASP.NET custom server control from scratch. You now know every step of the process – from how to create a web custom control library project, how to add properties to a custom control, how to render the HTML markup of the control to the client, and, finally, how to use the ASP.NET custom control in a web form.

    Hopefully, you now have the skills to create custom controls that have all the functionality of the standard ASP.NET server-side controls. Thank you so much for reading!

    November 10 2010

    16:04

    How to Build an RSS Feed with ASP.NET


    Over the course of this tutorial, we’ll review how to create an RSS Feed with the ASP.NET framework. Having an RSS feed for your site has become a necessity in recent years. With blogs or news sites being updated frequently, and with the vast amount of blogs and news websites out there, RSS has allowed readers to keep up with new content without being forced to visit them. Once you’ve completed this tutorial, you’ll know how to create an RSS feed with ASP.NET, and how to render XML documents on ASP.NET Web pages.


    Step 0: RSS 2.0 Introduction

    RSS is a web content syndication format. It stands for “Really Simple Syndication,” and is written in XML. All RSS files must conform to the XML 1.0 specification, as published by the World Wide Web Consortium (W3C). With RSS, it is possible to distribute up-to-date web content from one web site to thousands of others around the world. To simplify the term, RSS allows fast browsing for news and updates.

    The syntax rules of RSS 2.0 are quite simple, though strict. Here is a simple RSS document:

    <?xml version="1.0" encoding="utf-8" ?>
    <rss version="2.0">
      <channel>
        <title>Your Website Name</title>
        <link>http://www.yourdomain.com</link>
        <description>Free RSS Tutorial</description>
        <item>
          <title>First Article</title>
          <link>http://www.yourdomain.com/article.aspx?ID=1</link>
          <description>The description of the first article.</description>
        </item>
        <item>
          <title>Second Article</title>
          <link>http://www.yourdomain.com/article.aspx?ID=2</link>
          <description>The description of the second article.</description>
        </item>
      </channel>
    </rss>
    

    The first line in the document – the XML declaration – defines the XML version and the character encoding used in the document. In this case, the document conforms to the 1.0 specification of XML, and uses the utf-8 character set. The next line is the RSS declaration, which identifies that this is, in fact, an RSS document (more specifically, RSS version 2.0).

    The next line contains the <channel> element. This element is used to describe the RSS feed. The <channel> element has three required child elements:

    • <title> – Defines the title of the channel (e.g. Your Website name)
    • <link> – Defines the hyperlink to the channel (e.g. http://www.yourdomain.com)
    • <description> – Describes the channel (e.g. Free RSS Tutorial)

    Each <channel> element can have one or more <item> elements. Each <item> element defines an article or "story" within the RSS feed.

    The <item> element requires three child elements:

    • <title> – Defines the title of the item (e.g. First Article)
    • <link> – Defines the hyperlink to the item (e.g. http://www.yourdomain.com/article.aspx?ID=1)
    • <description> – Describes the item (e.g. The description of the first article)

    When viewed in Firefox, the RSS document above should look similar to:

    RSS document

    Step 1: Getting Started

    To follow this tutorial, imagine that you work as a web developer, and are building a news website where all of the news stories are stored in Microsoft’s SQL Server database. Specifically, the articles are stored in a table called News, which contains the following fields:

    • ArticleID – an auto-increment primary key integer field uniquely identifying each article
    • Title – a nvarchar(256), specifying the title of the article
    • Author – a nvarchar(50), specifying the author of the article
    • Description – a nvarchar(500), providing a more in-depth description of the article
    • DatePublished – a datetime, indicating the date the article was published

    Note that there might be other fields in the News table, but those listed above are the only ones we are interested in using — at least for the purposes of an RSS feed.

    We’ll use Visual Studio to finish the example. If you don’t have the full version of VS, you can grab the free Express Edition.


    Step 2: Creating an rss.aspx Page

    Our next step is to create an ASP.NET Web page (rss.aspx) that will display a list of the most recent news items as a properly formatted RSS 2.0 document. In Solution Explorer, right-click the project name, and then click Add New Item. In thia dialog box, under Visual Studio installed templates, click Web Form.

    Add New Page

     In the Name box, type a name for the new Web page (rss.aspx), and then click Add. The new ASP.NET web page (rss.aspx) is created and displayed, accordingly.

    Because we want the rss.aspx page to produce XML output, the first thing that we must do is remove all HTML markup or web controls from the page, and then set the ContentType property of @page directive to "text/xml".

    After clearing all HTML markup from rss.aspx page, add a Repeater control into the page. We'll use Repeater control to render RSS document on rss.aspx page.

    Here is the source view of the rss.aspx page, after we’ve made some changes:

    <%@ Page Language="C#" ContentType="text/xml" AutoEventWireup="true" CodeBehind="rss.aspx.cs" Inherits="NettutsTutorial2.rss" %>
    
    <asp:Repeater ID="RepeaterRSS" runat="server">
    </asp:Repeater>
    

    Step 3: Setup The Connection String

    Next, we want to setup the connection string of the data source, within the Web.config file. By saving the connection string information, we'll avoid having to hard-code it in the code-behind file. This simplifies things, if the connection string information changes in the future. Place it in the <connectionStrings> section under configuration element, like so:

    <connectionStrings>
      <add name="ConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Nettuts.mdf;Integrated Security=True;User Instance=True"
       providerName="System.Data.SqlClient" />
     </connectionStrings>
    

    We will access this information from the code-behind file later when we want to retrieve data from database.


    Step 4: Removing Illegal Characters from the XML Document

    Some characters have special meaning in XML. If you place a character, such as "<", inside an XML element, it will generate an error, because the parser interprets it as the start of a new element. To avoid this error, replace the "<" character with its entity reference (&lt;).

    There are five predefined entity references in XML:

    &lt; < less than &gt; > greater than &amp; & ampersand  &apos; ' apostrophe &quot; " quotation mark

    To avoid our RSS feed producing an error, we have to change all illegal characters in an RSS document with their entity references. Add the following code into the code-behind file of the rss.aspx page (rss.aspx.cs):

    protected string RemoveIllegalCharacters(object input)
    {
        // cast the input to a string
        string data = input.ToString();      
    
        // replace illegal characters in XML documents with their entity references
        data = data.Replace("&", "&amp;");
        data = data.Replace("\"", "&quot;");
        data = data.Replace("'", "&apos;");
        data = data.Replace("<", "&lt;");
        data = data.Replace(">", "&gt;");
    
        return data;
    }
    

    The RemoveIllegalCharacters() function performs a few simple string replacements, if needed. We will call this function from the rss.aspx page shortly.


    Step 5: Retrieving Data from the Database

    Add the following code into the Page_Load event handler:

    protected void Page_Load(object sender, EventArgs e)
    {
        // Get connection string from the web.config file
        string connString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
    
        // Create SqlConnection object
        SqlConnection sqlConn = new SqlConnection();
        sqlConn.ConnectionString = connString;
    
        // SQL query to retrieve data from database
        string sqlQuery = "SELECT TOP 10 ArticleID, Title, Author, Description, DatePublished FROM News ORDER BY DatePublished DESC";
    
        // Create SqlCommand object
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = sqlConn;
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = sqlQuery;
    
        // open connection and then binding data into RepeaterRSS control
        sqlConn.Open();
        RepeaterRSS.DataSource = cmd.ExecuteReader();
        RepeaterRSS.DataBind();
        sqlConn.Close();
    }
    

    The code above will attempt to retrieve the ten most recent news items from your database. It will then bind them to a Repeater control (RepeaterRSS) when the page is loaded.


    Step 6: Rendering Data

    This is our last step. It's time to render items from the News table into an appropriate RSS 2.0 syndication file. The simplest and quickest way to display the database data as XML is to use a Repeater control (RepeaterRSS). Specifically, the Repeater will display the <rss>, <channel>, and Web site related element tags in its HeaderTemplate and FooterTemplate templates, and the <item> elements in the ItemTemplate template. Don't forget to call the helper RemoveIllegalCharacters() function to replace unwanted characters from the string output.

    The following is the HTML portion of our ASP.NET Web page (rss.aspx):

    <%@ Page Language="C#" ContentType="text/xml" AutoEventWireup="true" CodeBehind="rss.aspx.cs" Inherits="NettutsTutorial2.rss" %>
    
    <asp:Repeater ID="RepeaterRSS" runat="server">
            <HeaderTemplate>
               <rss version="2.0">
                    <channel>
                        <title>Name of the Website</title>
                        <link>http://www.yourdomain.com</link>
                        <description>
                        Short description of the website.
                        </description>
            </HeaderTemplate>
            <ItemTemplate>
                <item>
                    <title><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, "Title")) %></title>
                    <link>http://www.yourdomain.com/news.aspx?ID=<%# DataBinder.Eval(Container.DataItem, "ArticleID") %></link>
                    <author><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, "Author"))%></author>
                    <pubDate><%# String.Format("{0:R}", DataBinder.Eval(Container.DataItem, "DatePublished"))%></pubDate>
                    <description><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, "Description"))%></description>
            </item>
            </ItemTemplate>
            <FooterTemplate>
                    </channel>
                </rss>
            </FooterTemplate>
    </asp:Repeater>
    

    The first thing worth noting here is that the rss.aspx file above contains only the Repeater control (RepeaterRSS), and no other HTML markup or Web controls. This is because we want the page to emit nothing but XML output. We set the ContentType of the @page directive to "text/xml" to indicate that the output of the rss.aspx page is an XML document.

    In the HeaderTemplate template of the Repeater control, we place the <rss> and <channel> elements.

    Next, in the ItemTemplate, we place the <item> elements, which contain the <title>, <link>, <author>, <pubDate>, and <description> elements, as the place for database fields. We call the RemoveIllegalCharacters() function when adding the Title, Author, and Description database fields to the XML output. Remember, this function simply replaces any illegal XML characters with their  entity references.

    Finally, the DatePublished database field, entered into the <pubDate> element, is formatted using the String.Format method. The standard format specifier, R, formats the DatePublished value appropriately according to RFC 822, Date and Time Specification. This starts with an optional three-letter day abbreviation and comma, followed by a required day, the three-letter abbreviated month, and then the year, followed by a time with the time-zone name, such as Thu, 04 Nov 2010 20:50:26 GMT.


    The Result

    And there we have it! With minimal effort, we’ve created a custom RSS feed for an ASP.NET application.

    The Resulting Feed

    The Complete Code

    The rss.aspx File

    <%@ Page Language="C#" ContentType="text/xml" AutoEventWireup="true" CodeBehind="rss.aspx.cs" Inherits="NettutsTutorial2.rss" %>
    
    <asp:Repeater ID="RepeaterRSS" runat="server">
            <HeaderTemplate>
               <rss version="2.0">
                    <channel>
                        <title>Name of the Website</title>
                        <link>http://www.yourdomain.com</link>
                        <description>
                        Short description of the website.
                        </description>
            </HeaderTemplate>
            <ItemTemplate>
                <item>
                    <title><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, "Title")) %></title>
                    <link>http://www.yourdomain.com/news.aspx?ID=<%# DataBinder.Eval(Container.DataItem, "ArticleID") %></link>
                    <author><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, "Author"))%></author>
                    <pubDate><%# String.Format("{0:R}", DataBinder.Eval(Container.DataItem, "DatePublished"))%></pubDate>
                    <description><%# RemoveIllegalCharacters(DataBinder.Eval(Container.DataItem, "Description"))%></description>
            </item>
            </ItemTemplate>
            <FooterTemplate>
                    </channel>
                </rss>
            </FooterTemplate>
    </asp:Repeater>
    

    The rss.aspx.cs File

    using System;
    using System.Collections;
    using System.Configuration;
    using System.Data;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Linq;
    using System.Data.SqlClient;
    
    namespace NettutsTutorial2
    {
        public partial class rss : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                // Get connection string from web.config file
                string connString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
    
                // Create SqlConnection object
                SqlConnection sqlConn = new SqlConnection();
                sqlConn.ConnectionString = connString;
    
                // SQL query to retrieve data from database
                string sqlQuery = "SELECT TOP 10 ArticleID, Title, Author, Description, DatePublished FROM News ORDER BY DatePublished DESC";
    
                // Create SqlCommand object
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = sqlConn;
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = sqlQuery;
    
                // open connection and then binding data into RepeaterRSS control
                sqlConn.Open();
                RepeaterRSS.DataSource = cmd.ExecuteReader();
                RepeaterRSS.DataBind();
                sqlConn.Close();
            }
    
            protected string RemoveIllegalCharacters(object input)
            {
                // cast the input to a string
                string data = input.ToString();
    
                // replace illegal characters in XML documents with their entity references
                data = data.Replace("&", "&amp;");
                data = data.Replace("\"", "&quot;");
                data = data.Replace("'", "&apos;");
                data = data.Replace("<", "&lt;");
                data = data.Replace(">", "&gt;");
    
                return data;
            }
        }
    }
    

    The Web.config File

    <?xml version="1.0"?>
    <configuration>
    	<configSections>
    		<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
    			<sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
    				<section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
    				<sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
    					<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
    					<section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
    					<section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
    					<section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
    				</sectionGroup>
    			</sectionGroup>
    		</sectionGroup>
    	</configSections>
    	<appSettings/>
    	<connectionStrings>
    		<add name="ConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Nettuts.mdf;Integrated Security=True;User Instance=True" providerName="System.Data.SqlClient"/>
    	</connectionStrings>
    	<system.web>
    		<!--
                Set compilation debug="true" to insert debugging
                symbols into the compiled page. Because this
                affects performance, set this value to true only
                during development.
            -->
    		<compilation debug="true">
    			<assemblies>
    				<add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
    				<add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
    				<add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    				<add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
    			</assemblies>
    		</compilation>
    		<!--
                The <authentication> section enables configuration
                of the security authentication mode used by
                ASP.NET to identify an incoming user.
            -->
    		<authentication mode="Windows"/>
    		<!--
                The <customErrors> section enables configuration
                of what to do if/when an unhandled error occurs
                during the execution of a request. Specifically,
                it enables developers to configure html error pages
                to be displayed in place of a error stack trace.
    
            <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
                <error statusCode="403" redirect="NoAccess.htm" />
                <error statusCode="404" redirect="FileNotFound.htm" />
            </customErrors>
            -->
    		<pages>
    			<controls>
    				<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    				<add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    			</controls>
    		</pages>
    		<httpHandlers>
    			<remove verb="*" path="*.asmx"/>
    			<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    			<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    			<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
    		</httpHandlers>
    		<httpModules>
    			<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    		</httpModules>
    	</system.web>
    	<system.codedom>
    		<compilers>
    			<compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    				<providerOption name="CompilerVersion" value="v3.5"/>
    				<providerOption name="WarnAsError" value="false"/>
    			</compiler>
    		</compilers>
    	</system.codedom>
    	<!--
            The system.webServer section is required for running ASP.NET AJAX under Internet
            Information Services 7.0.  It is not necessary for previous version of IIS.
        -->
    	<system.webServer>
    		<validation validateIntegratedModeConfiguration="false"/>
    		<modules>
    			<remove name="ScriptModule"/>
    			<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    		</modules>
    		<handlers>
    			<remove name="WebServiceHandlerFactory-Integrated"/>
    			<remove name="ScriptHandlerFactory"/>
    			<remove name="ScriptHandlerFactoryAppServices"/>
    			<remove name="ScriptResource"/>
    			<add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    			<add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    			<add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    		</handlers>
    	</system.webServer>
    	<runtime>
    		<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    			<dependentAssembly>
    				<assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
    				<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
    			</dependentAssembly>
    			<dependentAssembly>
    				<assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
    				<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
    			</dependentAssembly>
    		</assemblyBinding>
    	</runtime>
    </configuration>
    

    Conclusion

    Creating an RSS feed with ASP.NET is quite simple, isn't it? We only need to understand the RSS 2.0 specification. Beyond that, by using the .NET Repeater control, we can render items from a database into the RSS document. Most content management systems will have this capability by default. However, if you're a developer, and are building an ASP.NET website from scratch, you now have the skills to build your own custom feed.

    Happy Coding!

    November 02 2010

    04:41

    ASP.NET From Scratch: Controllers and Simple Model Validation


    This latest episode continues to delve into the ASP.NET MVC framework by looking at controllers and their role in MVC applications. You also learn how to perform model validation by implementing the IDataErrorInfo interface.


    The Complete Series


    Controllers and Simple Model Validation

    Press the HD button for a clearer video.
    Premium Members: Download this Video ( Must be logged in)

    Sell ASP.NET Components on CodeCanyon

    Did you know that you can sell your ASP.NET scripts and components on CodeCanyon? Simply sign-up for a free author account, and start selling!

    September 29 2010

    15:55

    ASP.NET from Scratch: Routing in MVC


    In today’s episode of ASP.NET from Scratch, we’ll look into URL routing in the MVC framework, and examine how a request can be routed to a controller and action method. You’ll learn how to use constraints to gain better control over your routers, and also discuss best practices in adding routes to the route table.


    The Complete Series

    Premium Members: Download this Video ( Must be logged in)

    Sell ASP.NET Components on CodeCanyon

    Did you know that you can sell your ASP.NET scripts and components on CodeCanyon? Simply sign-up for a free author account, and start selling!

    Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
    Could not load more posts
    Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
    Just a second, loading more posts...
    You've reached the end.
    (PRO)
    No Soup for you

    Don't be the product, buy the product!

    close
    YES, I want to SOUP ●UP for ...