Brendan Enrick

Daily Software Development

Creating a Simple Hello World Application Using MVC

So I am finally sitting down to play with the ASP.NET MVC Framework. I've installed Visual Studio 2008 on my machine. You can obtain a 90 day free trial of Visual Studio 2008 from Microsoft if you don't own a copy. There are also Express Editions of Visual Studio 2008.

After installing Visual Studio 2008 I installed the ASP.NET 3.5 Extensions Preview. It contains the required components to use the new MVC Framework. Now that you have it installed open up Visual Studio and create a new project. Choose the web section and select ASP.NET MVC Web Application. I named my project "HelloMvc".

 NewProjectHelloMvc

Here you can see the files currently in this empty project. Notice there are a bunch of files that it comes with including a Controller and a couple of Views.

 HelloMvcEmptySolution

So now run the application by pressing ctrl + F5. You'll see this page once you run the application.

HelloMvcStartingPage

Fairly simple for now, but hey it works. Now we should try to figure out how to create a simple static page. We'll make it look kind of like that about view that is already in there. We want it to be hello. OK, so click on the About Us link in the application. You'll be at a URL similar to this one http://localhost:64701/Home/About. So as a nice test try changing "About" to Hello in the address bar. You'll receive this nice error message which tells us the first step in creating our Hello World page.

 HelloMvcActionNotFound

Ok so we need to define an action in our controller. The Home part of our URL is saying we want to use the HomeController, so open up that file in the Controllers folder and add the following code into that file.

[ControllerAction]
public void Hello()
{
    RenderView("Hello");
}

Notice that all we needed to do here is to use the ControllerAction attribute for a method we define. We'll defined the method named Hello by added a line calling the RenderView method. Congratulations you've defined your first Controller Action. So we now refresh the page where we previously received an error message, and we're greeted with a new one. So we are on the right track.

 HelloMvcViewNotFound

Now we need to create the view that we are trying to call in our Controller Action. So we'll right click on the Home folder inside of the View folder and select Add then New Item. Here is where Microsoft has tried to trick you. They've now changed how you attach to MasterPages. Instead of picking a Web Form and checking a box you now have a new choice Web Content Form. Make sure you pick that or you'll not get a MasterPage added for you. It will look like this.

 HelloMvcAddNewView

So now that we have that empty view we can quickly add a nice message into it. So go ahead and type in some html like the following.

<h2>Hello World! MVC is here!</h2>

Now you need to go into the code of this view and place in the following.

using System;
using System.Web;
using System.Web.Mvc;

namespace HelloMvc.Views.Home
{
    public partial class Hello : ViewPage
    {
    }
}

Notice here that we need to inherit from the ViewPage class instead of the System.Web.UI.Page class. We are instead using the System.Web.Mvc.ViewPage class. This will allow our .aspx page to work as a view. Make sure to build the application and then open up the view again in the browser. Woohoo you've successfully created an MVC Controller Action and a View. And as some icing on the cake we will now add a link to our view on the MasterPage so that we can easily access this Hello View whenever we want to.

Open up the Site.Master file. It is located in the \Views\Shared. You will see an unordered list in the html. There are currently two list items in the list; Home and About Us. You will want to add a new one using the following code.

<li><%= Html.ActionLink("Say Hello", "Hello", "Home") %></li>

Now refresh the page. From anywhere on this site you can now get to the Hello World View. The method we used here took 3 arguments. The first is the text which appears for the link, the second is the name of the view, and the third is the name of the controller. The following is our final product. We have the Hello World page as well as a nice link to it.

HelloMvcHelloView

Enjoy creating simple MVC Views!

Accessing Controls inside of Templated Controls

One question that seems to come up often in the asp.net forums is from people who are trying to access controls within controls using templates. LoginViews and CreateUserWizard controls are two commonly used templated controls. These templated controls don't actually have their contents known until run-time because it is dependant on something else; data from a database, user permissions, etc.

Since this information is not known you can't just access the inner controls as you would normal controls, because it is not known until run-time what the controls are. You will get compiler errors if you try to access them. The easiest way to get the controls you need is to use a recursive find control function. Steve Smith has blogged about Using a Recursive Find Control as well as about a very important Code Optimization for using a recursive find control.

The cool thing about the recursive find control is that it will dig down into the controls collection of a control you specify looking for the control you are looking for. It is great for templated controls, because it is a lot neater than trying to statically go after it like this.

Bad Code Do Not Use This

Label Label1 = LoginView1.Controls[2].Controls[2].Controls[1].Controls[3].FindControl("Label1") as Label;

The problem with the above code is that if you move anything you'll break the code. It is not very stable, and is even hard to tell what is being done. Do not worry there is a better way of handling this. A recursive find control is an expensive operation, and this is why Steve's code optimization is important. You don't want to execute the find control more times than needed.

Good Code Use This

public static System.Web.UI.Control FindControl(System.Web.UI.Control start, string id)
{
    System.Web.UI.Control foundControl;
    if (start != null)
    {
        foundControl = start.FindControl(id);
        if (foundControl != null)
            return foundControl;
        foreach (Control c in start.Controls)
        {
            foundControl = FindControl(c, id);
            if (foundControl != null)
            return foundControl;
        }
    }
    return null;
}

The above code will find controls nested within templated controls for you. This code will probably go in one of your class libraries where you keep utility functions. When you're calling this function, I would recommend you call it within a property as in Steve's optimization. The following code shows how you would do the previous example in a better way.

Good Code Use This

private Label _label1 = null;
private Label Label1
{
    get
    {
        if (_label1 == null)
        {
            _label1 = Utilities.FindControl(LoginView1, "Label1") as Label;
        }
        return _label1 ;
    }
}

This allows you to access the control as you normally would try. You can just type in the name of the property and it will let you use it as if it were the control and there were no templated control there at all. Makes working with LoginViews and CreateUserWizard controls.

Repeating templated controls such as the GridView can also benefit from this functionality, but you need to be more careful with them because there is a control with the name you're looking for in each row of the repeating control. Make sure when using this there that you get the correct row first, and only search within that row.

Have fun finding your controls.

Dynamically Register an Asynchronous Postback Control with a ScriptManager

In order to use an update panel you have to specify the triggers either individually or by setting the ChildrenAsTriggers property of the UpdatePanel. Sometimes you may need to set these triggers dynamically such as if the desired trigger is inside of a repeater and is not inside of the update panel. In instances such as this you will need to from the code behind register the control with the script manager. To do this you will want to use the RegisterAsynchPostBackControl function of the ScriptManager in the following manner:

ScriptManager1.RegisterAsyncPostBackControl(Button1);

This code could be inside of the OnItemDataBound event handler for a repeater or even in page load if you want to register it in code. The script manager will now know to hijack the postbacks created by this control and turn them into asynchronous postbacks. The good thing about this is that you will now not do a full postback. The bad part is that you still have to let the update panel know that it needs to update after the asynchronous postback. To do this you will want to Call the Update() method of the UpdatePanel so for example you might do the following:

protected void Button1_Click(object sender, EventArgs e)
{
     // Do work
     UpdatePanel1.Update();
}

By using this method you will not be tied to your .aspx pages. It is not quite as elegant as when you just use the triggers collection in the UpdatePanel on the .aspx page, but this way of doing this is still easy and possible when inside of a template such as in a repeater or a gridview.

Happy AJAXing! 

Accessing a MasterPage ScriptManager from a Content Page

Recently I had forgotten how to access the ScriptManager in my MasterPage from one of the Content Pages. There is a static method on the ScriptManager class called GetCurrent() which will allow access to the current instance of a ScriptManager. This is useful because the ScriptManagerProxy is really just designed to do the declarative work normally performed on the ASP.NET page, but some work needs to be done through code. An example would be to check the ScriptManager instances IsInAsyncPostback property.

if (ScriptManager.GetCurrent().IsInAsyncPostback)

{

    // Perform only in asynchronous postback logic here.

This is very useful and easy, but I seem to always forget it is here. Perhaps now that I have blogged about it I will remember, and if not I can at least come back here to find it. Yes, when I forget I go through the trouble of casting Master as my MasterPage's class and then I access it that way (what a pain).

Accessing Master Page Properties from a content page

As I mentioned in my previous blog post about Accessing a property of a base page from a user control, I am going to explain how to access a property on a MasterPage from the content page. One merely has to check the namespace and the class name of the masterpage, which can be found in the code behind file. Just cast the Content Page’s Master as the class of the masterpage file which it uses, and then just access the value. It is really quite simple.

int neededValue = ((MyNameSpace.MyMasterPageClassName)Master).MyProperty;

Using that method you are able to easily access a property of a masterpage file when needed.

Accessing Properties of a Base Page from a User Control

Earlier today I was helping someone who was working with a user control. That control was on an ASP.NET page which was inheriting from a base page. From the user control he could not access the properties of the base page. He mentioned that he was getting an error message which said that the property did not exist in the current context.

I showed him that the reason he was having the problem is because the code in the user control came from the page before, and thus he would need to get the properties from there, but he was also going to need to cast the Page as the base Page in order to get to the property.

int myImportantValue = ((MyBasePage)Page).ImportantProperty;

This will retrieve the value from the property of the base page. It is a fairly simple task. Perhaps next I will show how to do a similar task with a masterpage.

I've now added that blog post about Accessing a Property of a MasterPage from a Content Page

Clearing Page Output Cache Entries

Earlier today I had a situation where I needed to clear the output cache entry of a page. After a quick Google search I turned up Steve Smith’s Article on Removing Page Output Cache Entries.

The article is a short, helpful article which quickly and easily explains how to remove the output cache entry of a page.

private void RemoveButton_Click(object sender, System.EventArgs e)
{
    HttpResponse.RemoveOutputCacheItem("/caching/CacheForever.aspx");
}

I hope everyone else finds this to be easy to understand and implement. The above should work as long as you have a page named “CacheForever.aspx” in the folder “caching” at the root of the site.

Happy Caching!

Embedded Resources not so painful anymore.

    Well after a frustrating time trying to figure out how to make embedded resources work, I finally understand. This makes everything much easier. As some of you may know I have been working on a content management tool. (This is not a full blown content management system) Since it is designed to be portable to existing ASP.NET web sites, it is just a dll file. Even though it uses a couple of images, I don’t want anyone to have to copy image files just to get the app working correctly.

    To accomplish this I decided to use embedded resources, something I had never done before. Starting out I fumbled a lot trying to figure out how to display these, bad idea. Well I started googling for a solution to my problem, and I tried doing what Microsoft said to do. Following what they said to do got me nowhere, and left me a bit more confused. The site makes many assumptions about what I all ready know. Since I did not know these things, I took some guesses. Sadly incorrect ones. I think the authors of those resources need to learn the value of a hyperlink. It would allow them to reference old material so I could learn what they assume I know.

    After reading that I had a better reference to start googling. I started looking for the GetWebResourceUrl method, and this led me to other web sites, which had some better explainations. At first I went to an article on codeproject explaining how to access embedded image resources. This was much better than the previous one I read, but I still could not get this one working right. My example didn’t quite fit with what they did, and they didn’t explain each part of the process.The problem is that even if I had incorrect code in my file, GetWebResourceUrl still returned a url that looked like it was supposed to. Again I needed to find something to get this working, or I would have to go back and start writing a lot of code I did not want to write.

    So I tried another link I found on google, and this article on Embedding Resources in ASP.NET 2.0 Assemblies explained to me very well how to get my embedded resources working. It explicitly told me where each part of code belonged It mentioned some specifics I might need that were not even part of that example. Not only that but it had more than one type of embedded resource that it accessed. If you are ever trying to use embedded resources I recommend it, but I suggest reading this article first. I may have to start reading more articled written by Mark Hines. If you are interested in this topic, I suggest reading this article as well Embedding Resources in ASP.NET 2.0 Assemblies - Part 2.