July 2010 - Posts

When you are using ASP.NET with WebFormViewEngine and wants to call a method in a separate namespace, you can add a reference to the namespace in web.config to get a cleaner view.

You can easily do it with:

<add namespace="Custom.Namespace" />

In ASP.NET MVC 3 there is a new View Engine, Razor. If we use this, the code above won’t work since the imports in web.config are ignored.

You can get access to the classes and methods quick and easy by using the “using” statement in the view:

@using Custom.Namespace

We need this in all the views where we want to access the classes, which requires more code.

To get rid of this, we need to know how Razor works. Every time a website with Razor is started, the InlinePageBuildProvider is registered for all files with the .cshtml and .vbhtml extensions. This BuildProvider implementation is used by Razor to build the views. What we need to do here is to add “Custom.Namespace” to the BuildProvider so it can include that when building the views.

What we need to do that is a new class which we can call PreApplicationStart. It has a static method where we add the global import which will be used by InlinePageBuildProvider:

using Microsoft.WebPages.Compilation;
 
public class PreApplicationStart
{
    public static void InitializeApplication()
    {
        CodeGeneratorSettings.AddGlobalImport("Custom.Namespace");
    }
}

To execute this method, we are going to use a new attribute in .NET 4.0, System.Web.PreApplicationStartMethodAttribute. This attribute can only be used by assemblies, so we add the following code in AssemblyInfo.cs:

[assembly: PreApplicationStartMethod(typeof(PreApplicationStart), "InitializeApplication")]

The parameters we send to the attribut is the type of the class where we have the static method, and the name of the static method.

When we start our website, the method will be executed before Application_Start in global.asax, which will make sure we always have access to this namespace in our application.

We can now get access to all classes in Custom.Namespace in our Razor views, just like we could before with WebFormViewEngine.

What is ASP.NET MVC 3?

In march, ASP.NET MVC 2 was released. It contains many new features such as data annotations, areas, validation and other things. These functions makes it easier to create larger projects where we easily can set annotations for the models, and also split the projects into different sections.

There are though some things that we want to change, and we often have to repeat ourselves, like when using ActionFilter for all controls and action methods We could solve this using ASP.NET MVC 2, but that requires extra work from us since there isn´t any kind of built-in support for that.

The solution for these and many other problems exists in ASP.NET MVC 3, which is released as a preview.

So, what are the biggest new features and changes in this firs preview of ASP.NET MVC 3?

  • Razor, a new ViewEngine for ASP.NET MVC. Razor also works for ASP.NET Web Pages.
  • ASP.NET MVC 3 requires .NET 4.0 and does not suport .NET 3.5 anymore.
  • Global ActionFilters, which make it possible to register action filters for all controllers and method in one place.
  • Dynamic View and ViewModel properties. In previous versions of ASP.NET we had to useViewData, which is a dictionary with strings and objects. Now we have dynamic properties instead.
  • The possibility to choose View Engine when creating a new view.
  • Support for injecting code using a built-in Service Locator.
  • JsonValueProviderFactory which makes it possible to post Json directly to a page and retrieve it as a custom type.
  • Support for new data annotations in .NET 4.0.
  • Support for IValidateObject in our models, so we can use custom validation for the values directly from the model.
  • New types of ActionResult.

I am going to talk about most of these new features here, and the other things will be published later in separate articles.

Create your first ASP.NET MVC 3 project

When ASP.NET MVC 3 is installed, we can see some new project types in Visual Studio 2010. When we choose to create a new project, it will look like this:

1 - New project

We can see three new project templates here: ”ASP.NET MVC 3 Web Application (ASPX)”, ”ASP.NET MVC 3 Web Application (Razor)” and ”ASP.NET MVC 3 Empty Web Application”. If we create a project using ASPX, we will get the same views as in earlier versions, which are using WebFormViewEngin, but if we choose to use Razor, we will use this new View Engines instead. In this case I choose to create a Razor project.

What we have now is an ordinary ASP.NET MVC project with folders for Models, Views and Controllers. There are some changes though, instead of aspx files in the views folder, we have cshtml files:

2 - ViewsCshtml

Cshtml is the file extension for views using the Razor vew engine. We can still use aspx files, but then the WebFormViewEngine will be used instead.

If we open View\Home\Index.cshtml we will see this:

@inherits System.Web.Mvc.WebViewPage
 
@{
    View.Title = "Home Page";
    LayoutPage = "~/Views/Shared/_Layout.cshtml";
}
 
<h2>@View.Message</h2>
<p>
    To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>

There is no intellisense or syntax highlighting for Razor in Preview 1, so if you want t use it, you will still havet o use aspx files until it´s there.

If we take a look at the code, we can find some interesting things. First, we have @inherits on the first line. We use that to declare which type the view uses. In ASP.NET MVC 2 we had ViewPage or ViewPage<T>, and with Razor we now have WebViewPage or WebViewPage<T>. If we use aspx files with ASP.NET MVC 3, they will still use ViewPage.

After that we have a code block with two lines of code. On the first line we set View.Title, and on the other we set LayoutPage. View is the dynamic type we use instead of ViewData, and LayoutPage is used to set the master page we want to use.

After the code block we display View.Message, wich is a ViewData object.

How come we set one View value, and then display another?

If we take a look at HomeController.cs, we can see this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace MvcRazor.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewModel.Message = "Welcome to ASP.NET MVC!";
 
            return View();
        }
 
        public ActionResult About()
        {
            return View();
        }
    }
}

Here is ViewModel.Message set. ViewModel is exactly the same as View, which means we use it instead of ViewData. This is the value we use in the view.

But we also set View.Title without displaying the value in the view. What happens here is that the value is sent to the LayoutPage which looks like this:

@inherits System.Web.Mvc.WebViewPage
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>@View.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
</head>
 
<body>
    <div class="page">
 
        <div id="header">
            <div id="title">
                <h1>My MVC Application</h1>
            </div>
 
            <div id="logindisplay">
                @Html.Partial("_LogOnPartial")
            </div>
 
            <div id="menucontainer">
 
                <ul id="menu">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                </ul>
 
            </div>
        </div>
 
        <div id="main">
            @RenderBody()
            <div id="footer">
            </div>
        </div>
    </div>
</body>
</html>

Here are we reading the value from View.Title for the header in the page. The value have been sent from the view to the masterpage, just like we could do with a ContentPlaceHolder before.

In the LayoutPage we use standard helpers for ASP.NET MVC, just like we use to do before. There are some new things as well though, like the RenderBody() which is used to specify where the view should be rendered.

If we click on F5 to start the project, we will get this:

3 - Start site

This site looks just like it dit in earlier versions of ASP.NET MVC, and we can now start buidling the page.

Create a guestbook

If we want to get feedback from our visitors, we could have a guestbook on the page. I am going to create a new guestbook from scratch, using ASP.NET MVC 3 with Razor, and store the values in a SQL Server Compact 4 database created with Entity Framework 4 CTP 4.

First we will need to create a model. We give the model the name GuestbookEntry and create it like this:

using System;
using System.ComponentModel.DataAnnotations;
 
namespace MvcRazor.Models
{
    public class GuestbookEntry
    {
        public int Id { get; set; }
 
        [StringLength(25)]
        [Required]
        public string Name { get; set; }
 
        [DataType(DataType.EmailAddress)]
        [Required]
        public string Email { get; set; }
 
        [Required]
        public string Message { get; set; }
 
        public DateTime Posted { get; set; }
    }
}

To create a database I first create a new folder named Code, where I create a new class file with the name DataContext. I add the following code:

using System.Data.Entity;
using MvcRazor.Models;
 
namespace MvcRazor.Code
{
    internal class DataContext : DbContext
    {
        public DbSet<GuestbookEntry> Guestbook { get; set; }
    }
}

To use the new functions in Entity Framework 4 CTP 4, we need to add a reference to the dll for the CTP. Thanks to the new Code-First functionality, we will be able to use our model directly in our database without the need of writing custom SQL.

To create the database automatically if it´s not existing already, we will have to add this to Application_Start in global.asax:

Database.SetInitializer<DataContext>(new RecreateDatabaseIfModelChanges<DataContext>());

The database will now be recreated everytime we change the model.

The last thing we need before using the model is to add a key in web.config with the connection string to the database.

<add name="DataContext" connectionString="Data Source=|DataDirectory|DataContext.sdf" providerName="System.Data.SqlServerCe.4.0" />

Since the database doesn´t exist yet, it will be created the first time we run the application.

How you can use DataContext to work with the database

To work with the database we need to create controllers which sends the data between our database and views. I am now going to create a new GuestbookController where I check the box for creating additional action methods:

4 - Add controller

Since we don´t have all the functionality in our guestbook, I will remove unnecessary methods, and get this:

using System.Web.Mvc;
using MvcRazor.Code;
using MvcRazor.Models;
 
namespace MvcRazor.Controllers
{
    public class GuestbookController : Controller
    {
        DataContext _ctx = new DataContext();
 
        // GET: /Guestbook/
        public ActionResult Index()
        {
            return View();
        }
 
        // GET: /Guestbook/Create
        public ActionResult Create()
        {
            return View();
        } 
 
        // POST: /Guestbook/Create
        [HttpPost]
        public ActionResult Create(GuestbookEntry entry)
        {
            try
            {
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
    }
}

Outside of the methods, I create a new instance of DataContext, which will be used by the different methods to work with the data.

In the index method we will have a list with all entries in the guestbook. Since we have a reference to an ObjectContext (in this case it´s DataContext), it will be really easy to accomplish this The index method will look like this:

public ActionResult Index()
{
    return View(_ctx.Guestbook.ToList());
}

We also updates the Create method so we can save new entries:

// POST: /Guestbook/Create
[HttpPost]
public ActionResult Create(GuestbookEntry entry)
{
    try
    {
        entry.Posted = DateTime.Now;
 
        _ctx.Guestbook.Add(entry);
        _ctx.SaveChanges();
 
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

It´s really easy to work with the data using our DataContext, and now we have everything we need to list and create entries in our guestbook.

The next step is to create the views, so we start with the index view. It´s a generic view (GuestbookEntry), and it is going to list the entries using the Razor view engine. Right-click inside of the Index method and choose Add View. If you are familiar with ASP.NET MVC 2 or the previous version, you will see some changes here:

5 - Add view

The new feature here is the ability to choose which view engine to use, and automatically use the corresponding T4 template to render it. If we click on Add, the view will be generated. There are though some properties we don´t want to show here, such the links and Id, so we delete them. The result is:

@inherits System.Web.Mvc.WebViewPage<IEnumerable<MvcRazor.Models.GuestbookEntry>>
 
@{
    View.Title = "Guestbook";
    LayoutPage = "~/Views/Shared/_Layout.cshtml";
}
 
    <h2>Index</h2>
 
    <table>
        <tr>
            <th>
                Name
            </th>
            <th>
                Email
            </th>
            <th>
                Message
            </th>
            <th>
                Posted
            </th>
        </tr>
 
    @foreach (var item in Model) {
    
        <tr>
            <td>
                @item.Name
            </td>
            <td>
                @item.Email
            </td>
            <td>
                @item.Message
            </td>
            <td>
                @String.Format("{0:g}", item.Posted)
            </td>
        </tr>
    
    }
 
    </table>
 
    <p>
        @Html.ActionLink("Create New", "Create")
    </p>

The view looks like the start page, but now we have a model, which we can see on the first line. We also use Razor instead of the old code blocks (<%%>).

We will now create a view for adding entries, so we choose Create instead of List for the new view.

We will remove the Id and Date fields for this new view, so it looks like this:

@inherits System.Web.Mvc.WebViewPage<MvcRazor.Models.GuestbookEntry>
 
@{
    View.Title = "Create";
    LayoutPage = "~/Views/Shared/_Layout.cshtml";
}
 
<h2>Create</h2>
 
    @using (Html.BeginForm()) {
        @Html.ValidationSummary(true)
 
        <fieldset>
            <legend>Fields</legend>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.Name)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
            </div>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.Email)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.Email)
                @Html.ValidationMessageFor(model => model.Email)
            </div>
            
            <div class="editor-label">
                @Html.LabelFor(model => model.Message)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.Message)
                @Html.ValidationMessageFor(model => model.Message)
            </div>
            
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>
 
    }

If we press F5, we will see this:

6 - View page

We have now created a very simple guestbook where the visitors can create new entries. The database is auto-generated, so we will not have to think about that.

If we go to the create view and posts the form without the correct values, we can see that we also got validation based on our data annotations for the model.

Scott Guthrie and Scott Hanselman have written great blog posts about how to use the new Code-First functionality in the latest Entity Framework CTP. But what about ASP.NET Web Pages?

Entity Framework 4 requires .NET 4.0, and since ASP.NET Web Pages is built on .NET 4.0 it should work, and it does! ASP.NET Web Pages is just not classic ASP on steroids, it´s the full .NET 4.0 made simple. Smile

I posted the code you need and how to do it as an answer on the ASP.NET Forums here:

http://forums.asp.net/t/1580303.aspx

When the database is generated, you can edit the data in the built-in database manager in WebMatrix.

Det här finns att läsa på svenska här:

http://www.aspsidan.se/default.asp?page=readarticle&artId=713

With ASP.NET MVC we can get nice URLs, like /Products/Computers to show all products in the Computer category. We can set up the routes in global.asax, and can after that get the values in the controller. In ASP.NET Web Pages we don´t have neither global.asax nor controllers, so how can we use routing with this?

When we want to have dynamic pages where we show products based on the URL, we use to have something like this:

Products.cshtml?category=cars

This opens the page Products.cshtml and selects the category ”cars”. Since there is built-in support for routing in ASP.NET Web Pages, we can instead use this URL:

/Products/Category/Cars

When we go to that URL, ASP.NET Web Pages try to open Products.cshtml if it exists. If it does exist, /Category/Cars will be sent as UrlData to the page, and if it doesn´t exist it tries to open /Products/Categorycshtml and sends /Cars as UrlData and so on.

To test this we create a new file, “Products.cshtml”, and open it in the browser with the following URL: /Products/Category/Cars. What we get is the empty Products.cshtml, which means that this actually works as it should.

To get Cars from the URL we get @UrlData[1]. When get get index 1 we get Cars, since index 0 is Category. If we want to get all UrlData values, we can just loop through the object since it implements IEuerable<string>

The final code for Products.cshtml looks like this:

<!DOCTYPE html>
<html>
    <head>
        <title></title>
    </head>
    <body>
        @UrlData[1]
    </body>
</html>

This is what is returned to the browser:

<!DOCTYPE html>
<html>
    <head>
        <title></title>
    </head>
    <body>
        Cars
    </body>
</html>

We can then use this information to get a specific cateory from a database if we want too.

When you install WebMatrix, SQL Server Compact 4 is automatically installed with it. If you only want to download just the database, you can do so here:

http://www.microsoft.com/downloads/details.aspx?FamilyID=0d2357ea-324f-46fd-88fc-7364c80e4fdb&displaylang=en

The SQL Server Compact Team has a great blog post about it here:

http://blogs.msdn.com/b/sqlservercompact/archive/2010/07/07/introducing-sql-server-compact-4-0-the-next-gen-embedded-database-from-microsoft.aspx

This means you can download it and use it in your web applications right away (for test purposes of course since it´s a CTP)! Smile

When we create new sites in WebMatrix, they are automatically being used by IIS Express for rendering them. To modify how IIS Express is used, we can use the Settings page in WebMatrix.

If you open a web site in WebMatrix and take a look at the left menu under the Site panel, you can see a shortcut to the Settings page. On this page you can modify the settings for how IIS Express is going to be used with our web site.

The settigs page looks like this:

clip_image002

At the top we can change the URL for the page which is used when visiting the page locally (when clicking F12). We can easily change port number here.

Under that we have the possibility to activate SSL, which is encrypting. IIS Express contains a SSL certificate that is used if we activate SSL.

Under Select .NET Framework version we can choose .NET 2.0 or .NET 4.0. ASP.NET Web Pages is built on .NET 4.0 because of the dynamic functions, but we can run other projects on .NET 2.0 if we want to.

The last setting allows you to set the startpages that will be used. We can add new pages here, remove existing, and set the priority for them.

It is really easy to change the way our web sites should work with IIS Express, using WebMatrix!

Artikeln på svenska:

http://www.aspsidan.se/default.asp?page=readArticle&artId=711

When developing web sites you often need to run some code the first time the web site is loaded, or every time a page is loaded. In ASP.NET MVC you can do this in global.asax in Application_Start, or with custom action filters for a controller or action method.

Run code when the site starts

Since we don´t have a global.asax file or any controllers in our ASP.NET Web Pages projects, where we could run the code, we have new functionality.

The first time a visitor loads the site for the first time we might want to set a date in a global variable. After that we want to get the value from which page we want in the site.

To make it possible, we can create a file called _start.cshtml. As I mentioned in my article “Introduction to ASP.NET Web Pages”, we can not visit pages with a underscore as prefix, which means we can´t open this page directly. Instead it is executed the first time the web site loads.

In this file we remove all HTML and adds this:

@{
    AppData["timeStarted"] = DateTime.Now.ToLongTimeString();
}

AppData is a global variable which contains values for our web site. After that we create a new file called default.cshtml and add this code to it:

The site started at @ApplicationInstance.Application["timeStarted"]

When we visit default.cshtml we can se that we have got the current time. If we update the page, the time will be exactly the same. If we go to WebMatrix and click on the Restart button in the Ribbon and reloads the page, the time is updated, since the application is restarted.

Run code for every page

Except from running code when the site is started, we might want to run code before and after a page is loaded, for example logging.

To run code before and after a page is loaded, we create a new file called _init.cshtml. If we add code to this it is automatically executed before the page is loaded.

Add this to the file:

<p>This is loaded before the page! </p>

When we open a web page, this will automatically be added to the top of the page. We don´t need to have HTML here, but can instead use C# with the Razor syntax.

After _init.cshtml is loaded, the page loads itself automatically. We can choose when to load the page ourselves, though. To do that we just add a call to the method RunPage() in _init.cshtml. If we add code after calling RunPage(), it will be executed after the page run.

An example where we set LayoutPage in _init.cshtml:

<p>This is loaded before the page!</p>
@{
    LayoutPage = "~/_Layout.cshtml";
    RunPage();
}
<p>This is loaded after the page!</p>

Default.cshtml can then look like this:

The site started at @ApplicationInstance.Application["timeStarted"]

And _Layout.cshtml:

<!DOCTYPE html>
<html>
    <head>
        <title>Layout</title>
    </head>
    <body>
        @RenderBody()
    </body>
</html>

The layout page will now be automatically used by all cshtml pages, which makes it possible to have very clean pages, but still have a LayoutPage set.

The article as pdf and xps can be found here.

A very interesting feature in Web Matrix is the possibility to show logs. When we visit a page through IIS Express, Web Matrix stores the requests which makes it possible to see them afterwards.

To get the logs, click on Site in the left menu, and then Requests. A table is then displayed with all the requests, and we can also filter the requests by clicking on the different buttons in the ribbon, or by searching. If an error has occurred, we can get more information about it and also get recommendations for how we can proceed.

Example:

clip_image002

We can quick and easy see how long it have taken to make the requests, when they were made and then see information about a specific request at the right. If we click on “More information”, we will get a page with more information about the error.

This information is easy to get and will give us important information that can help us creating great web sites using ASP.NET Web Pages.

Post in swedish:

[Coming]

Those who are using PHP might have big use of phpinfo() which sows information about the server and the current runtime. This function have not been around in ASP.NET, and the only thing we have had is the Trace which can show information about what have been loaded on the page.

In ASP.NET Web Pages there is a new helper function called ServerInfo. What it does is to print the information in a table with four categories:

  • Server Configuration
    • Information about the server´s hardware and software.
  • ASP.NET Server Variables
    • Variable with IP, port, URL, path etc.
  • HTTP Runtime Information
    • Information about .NET. Shows the current version, where .NET is installed, which AppDomain is used and other information.
  • Environment Variables
    • Displays information about the environment such as information about the user.

This information kan be good to have on a admin site where you want to get information about the server and hardware, which can be good to know if something unexpected occurs on the site.

To display this information on a page, all you have to do is to add this code:

@ServerInfo.GetHtml()

What you will se in the browser is:

clip_image002

The post is available as pdf and xps here:

http://cid-4aa13e17331c7398.office.live.com/browse.aspx/Public/Artiklar/ASP.NET%20Web%20Pages?uc=4

Artikeln finns på svenska här:
http://www.aspsidan.se/default.asp?page=readarticle&artId=709 

Web sites are often complex and show much information from external sources. News on the site can come from the database, news from other sites are aggregated from their RSS feed, stock quotes can be imported using a web service and so on. Since all these calls can take some time to do, the result can be a slow web site. To solve this you can cache the information on the page, which saves the information in the memory so you only need to get this information when it´s updated. If we set the cache to 20 minutes, the data will be saved for 20 minutes in the memory, and will after that be imported again.

In ASP.NET Web Pages there is a helper which makes it possible to fast and easy use the cache in .NET.

These are the methods that can be used:

  • WebCache.Get(string key)
    • Returns the value with the key specified.
  • WebCache.Set(string key, object value[, int minutesToCache][bool slidingExpiration]
    • Inserts data in the cache with the specified key. The optional parameters minutesToCache and slidingExpiration determines how long the value should be cached, and if its expiration will be extended when used.
  • WebCache.Remove(string key)
    • Removes the object with the specified key from the cache.

What we are going to do now is to see if there is a date in the cache. If it is there we print it out, and if not we save the date in the cache and print it out. We are also adding a button which we can click on to remove the cached value.

The full code for the page:

@{
    if (IsPost)
    {
        WebCache.Remove("date");
    }
 
    DateTime date = DateTime.Now;
    DateTime cachedDate = DateTime.Now;
 
    if (WebCache.Get("date") != null)
    {
        cachedDate = WebCache.Get("date").ToString().AsDateTime();
    }
    else
    {
        WebCache.Set("date", date, 3);
    }
}
 
<!DOCTYPE html>
<html>
    <head>
        <title>ASP.NET Web Pages Cache</title>
    </head>
    <body>
        <p>
            Cached time: @cachedDate.ToLongTimeString()
        </p>
        <p>
            Current time: @date.ToLongTimeString()
        </p>
        <p>
            <form action="/Cache" method="post">
                <input type="submit" value="Remove from cache" />
            </form>
        </p>
    </body>
</html>

The first thing we do here is to check whether the user have posted to the page or not, which we have not the first time we visit the page. After that we create two variables, one with the current time, and one with the cached time, which is the same as the current the first time we visit the page.

The next step is to see if there is anything saved in the cache. We get the value for the key ”date” and check if it is null. If the value exists, we save it as a DateTime object using the extension method AsDateTme(), which can be used by all string objects in ASP.NET Web Pages. If the value is not yet in the cache, we save the value there for three minutes.

When all the code have been executed we will have two values – the current time and the cached time. On the page we are going to print both values which are the same for the first time, and when we update the page the cached value will be the same as before and the other value will be updated.

The cached value will be updated after three minutes, or when we click on the button which will remove it from the cache.

Except for simple types like DateTime we can save more complex type, like a list with news on the page.

It is important to remember to not cache everything too long. Information that needs to be updated often can be cached for a short time (like a chat), while things that do not have to be updated often can be cached for a longer time (news and similar).

The article can be found as pdf and xps here:
http://www.aspsidan.se/default.asp?page=readarticle&artId=709

More Posts Next page »