Hostinicon
GET HOSTING FROM $3.95/MO PLUS A FREE YEAR ON TUTS+ (RRP $180). HURRY OFFER LIMITED. Check it out
Advertisement

ASP.NET for PHP Developers: Part 2

by
Gift

Get a free year on Tuts+ this month when you purchase a Siteground hosting plan from $3.95/mo

In part one of the "ASP.NET for PHP Developers" tutorial, we learned the basics of ASP.NET and the C# language. Part two builds on that foundation, and introduces some more advanced features and techniques to take your ASP.NET pages to the next level.


Before you Start...

Ensure you have read and completed the examples in part 1 of the tutorial. We'll be building on that application here. It's also worth stressing that you need a good grasp of object oriented programming (OOP) to continue.


And Before I Start...

I mentioned in part 1 of the tutorial that there are two flavours of ASP.NET available:

  • ASP.NET WebForms: the original framework allowing developers to create web applications using many of the same techniques used in .NET Windows desktop applications
  • ASP.NET MVC: a newer framework offering Model-View-Controller architecture and more control over client-side code

However I don't use either of those, but rather a third approach of my own devising. That's for several reasons:

  1. When I started writing serious ASP.NET applications I retained my high standards of HTML output learned when writing PHP. If the page didn't validate I felt dirty. There are a lot of developers who feel the same. ASP.NET WebForms gave, at the time, awful markup for many of the standard controls, so I had to come up with another solution. Adding runat="server" to HTML elements offered many of the advantages of true ASP.NET controls, but gave me full control over the HTML that was outputted. Things improved, and are looking even better for ASP.NET 4.0.
  2. I saw lots of examples of ASP.NET code where it was obvious the developer didn't care about the resulting HTML. Perhaps they were Windows desktop application developers making the jump to the web, maybe they had never hand-coded HTML. Whatever the reason, I determined I would not be one of them.
  3. Quite a few of the standard ASP.NET controls relied entirely on JavaScript which is, to be frank, unforgivable for public websites (in the UK web accessibility is a legal requirement). For example, the evil javascript:__doPostBack function is a perfect way to make your website impossible to use for a large proportion of the web audience - oh, and search engines as well.
  4. I wanted to use my own choice of JavaScript library (initially Prototype, but then jQuery, now officially supported by ASP.NET). If I had to use the ASP.NET framework JavaScript library it would have made that more difficult.
  5. So why not ASP.NET MVC? Well, it wasn't around when I started writing ASP.NET applications, and even if it was it would have been another hurdle to jump to get anything to work. Learning the .Net framework and C# language was challenging enough!

So you can see why I chose this "roll-your-own" approach. As ASP.NET matured and I discovered new features, I started to integrate those into my applications, and I fully expect that over time I'll be doing more of that.

So, let's take our ASP.NET application to the next level.


Master Pages

My second favourite feature of ASP.NET (after turning HTML controls into server controls) is master pages. A master page is a template file you can use to encapsulate HTML you use in multiple pages. For example, your master page could contain the header, menu and footer of your pages, while your normal .aspx pages contain the actual content on that page. let's look at an example web page:

A sample web page

You can see the parts which are used on multiple pages highlighted in green. The content which changes for each page in the site is highlighted in red. Master pages allow us to split up the code for these two sections into multiple files. If you've used templates in your PHP applications (for example Wordpress has header.php, footer.php and sidebar.php) you'll see how great master pages are.

Creating a master page

So let's create a master page. In the Solution view create a new directory in your ASP.NET application called "Master_Pages". In that directory create a new master page by right-clicking on the Master_Pages folder, selecting "Add > New file" then selecting "Master Page with Code Behind" and call it "DefaultMaster". Your new master page will be created and you'll see the "DefaultMaster.master", "DefaultMaster.master.cs" and "DefaultMaster.master.designer.cs" files in the Master_Pages folder.

A new master page in MonoDevelop

Open the "DefaultMaster.master" and "DefaultMaster.master.cs" files. The code-behind file (.cs) for the master page (.master) works exactly the same as the code-behind file for an .aspx page. The first thing to note is master pages do not inherit from System.Web.UI.Page like .aspx pages do. Instead they inherit from System.Web.UI.MasterPage. Here's the default code for the code-behind.

And for the .master file itself:

Because we're not using the WebForms model, let's quickly remove the tags for the <form runat="server"> element.

You should be getting used to page declarations (the <%@ Page ... %> bit in .aspx pages) by now, so the <%@ Master ... %> declaration will come as no surprise. What is different in this code is a new control: <asp:contentplaceholder>.

This content placeholder is where the content from your .aspx pages will be inserted. You can have as many of these in a .master page as you like.

Referencing your master page

Let's go back to our normal .aspx page and make some edits. The first thing to do is remove the <html>, <head> and <body> tags, as they will now be in the master page. That leaves:

Now we need to specify what content to place in the content placeholder. We do that by specifying where the master page is, and wrapping our content in an asp:Content control, like this:

There's a couple of things to note here. Firstly the Page declaration has an additional attribute of "MasterPageFile" with a value of "~/Master_Pages/DefaultMaster.master". In ASP.NET "~" means the root of the application, the rest of that path just points to our master page.

Secondly you see the new asp:Content control has an attribute of "ContentPlaceHolderID" with a value of "contentPlaceHolder", which is the "id" attribute of our <asp:contentplaceholder>. Running the application will give you:

An ASP.NET master page and content page working together

Checking the source code of the page proves that the master page (.master) and content page (.aspx) have been seamlessly integrated together. Now you see why I love master pages so much.

A more complex master page

We can push master pages a lot further than this simple example. Let's have a go at building something that looks more like a real web application, starting with the master page. Firstly we'll add some more content placeholders and a few server-side controls:

And in the code-behind file for our master page we'll put:

(I'll leave it as an exercise for you to add the SiteName and CopyrightNotice applications settings to web.config.)

Now for our content page. We have four content placeholders we can use: PageTitle, PageJS, PageCSS and PageContent. Here's the code for the .aspx content page:

And the code-behind for our .aspx content page:

A couple of new things to notice here. Firstly I haven't used the PageJS content placeholder at all - it's quite OK to leave it out entirely (of course nothing will be rendered to the page for that area). Secondly I've introduced another ASP.NET control, namely <asp:Literal>, which we'll take a quick look at now.

The Literal control

The Literal control is very useful when you want to render something to the page without any extra markup. For example, a lot of the time it's fine to use:

Gives:

But if you don't want the span tags at all, for example for the page <title>, you need the Literal control. Setting the "Text" property of the Literal control renders just that text to the page:

Gives:

The completed master and content page

So running our application should give us this:

An ASP.NET master page and content page with multiple content placeholders

This is really just scratching the surface, as it's possible to have multiple master pages (even nested master pages!). You can also set the master page programatically (but this needs to be done in the Page_Init event, as Page_Load is too late in the page lifecycle). There's lots more detail about MasterPages on the MSDN site.


Custom Classes

It's possible to create custom classes in your application, just like you would in PHP. Let's create a security class by right-clicking the root of your application and selecting "Add > New file" then choosing "Empty class" from the "General" section and calling it "Security".

An new empty class

The code for your new class looks like this:

I'll throw a bit more code into this file:

Pretty simple so far. The only new thing is the use of HttpContext.Current.Session rather than just Session, that's because HttpContext.Current is implicit in an .aspx web page, but not in a standalone class.

In our Default.aspx.cs code-behind file we write:

Which instantiates a new instance of the Security class names "security". Running the application shows this:

Not logged in

As you're familiar with OOP you can see how this can be used to build large-scale web applications. The only other thing to say about custom classes is how to make them static. Here's the code for a static class:

You can see there's no default method, as this class is never instantiated. I've also added the "static" keyword to the property and method, and I've made the CheckSession() method public. To use this static class we would write:

Pretty simple, really. As you're fully aware of the advantages that OOP can give you for abstraction, encapsulation and inheritance you'll see how powerful this is. But if we're going to use objects, we really need some serious data to model in our objects. We need a database.


Databases, Data Sources and Data Binding

ASP.NET works really well with databases, but works the best with Microsoft SQL Server (not surprisingly). Even if your ASP.NET application is running on a Linux box, you can still connect to SQL Server on a Windows server to use as a datastore. I'll demonstrate that below, but as I'm writing this tutorial in Linux I will also demonstrate the use of MySQL as an ASP.NET database. To use MySQL you'll need the ADO.NET driver for MySQL - this excellent article helped me a lot.

Database configuration

The first thing to do is configure how to connect to our database server. You can do this in web.config, add this code inside the "configuration" section (the MySQL and SQL Server code should be pretty obvious). Note that these are standard connection strings.

I've also created a table called "users" with this code (this is for MySQL, minor edits will make it work in most other database systems):

To access your connection string you can use the ConfigurationManager class which we used in part 1 of the tutorial to access global configuration settings. Here's the code:

Connecting and running a simple query

So we're now ready to connect to our database and run a query. First, insert a couple of rows into the " users" table so we have something to query:

We then need to ensure we reference the right assemblies. For MySQL make sure you have this at the top of your code-behind file:

Amd for SQL Server use this:

A quick note about connecting to MySQL in Linux. I had a bit of trouble making my application compile when I first tried this. I did various searches but found no answer that worked for me. The error I got was "The type or namespace name `MySqlConnection' could not be found." which looked like the MySQL Connector wasn't installed properly. The fix (for me) was to manually add the reference by right-clicking the References folder in my application and going to "Edit references". I then found the MySQL.Data.dll file in the .Net Assembly tab and referenced it. I also had to then manually reference the System.Data and System.Configuration assemblies from the Packages tab.

MonoDevelop references

Hopefully you won't need to jump through these hoops.

We now open a connection to our database like this for MySQL:

And this for SQL Server:

See, pretty easy, and not a million miles away from the equivalent PHP code. There are a couple of bits in here I'll explain in some more depth. Firstly the using statement:

The object you set up in the brackets is automatically destroyed when your code leaves the end curly brace "}". This is a really useful structure to know about, so read all about it here.

Secondly the DataSet. In the code above the results from the database query are fed into a DataSet, which is an object containing one or more tables, each table containing rows and columns. That means you can do useful things like:

And there are many other goodies in the DataSet class. You can also loop rows, just like you do in PHP, like this:

But there's a much better way to display simple loops, and that's using the Repeater control.

Using repeaters and databinding

First a confession. There are large ASP.NET applications I've written that use no ASP.NET controls except the Literal (which we looked at above) and the Repeater. The Repeater control allows you to "bind" data, for example from a DataSet, and display it in a looped manner. Firstly we need to add something to our database code above:

And in the .aspx page we put:

You can see what happens here. When the data is bound to the Repeater control the HeaderTemplate section is displayed. Then each row is displayed in the ItemTemplate and AlternatingItemTemplate sections (the names should give you a clue how they are displayed). Then finally the FooterTemplate section is displayed. Using this simple control gives you an easy way to display repeating data, with complete control over the resulting HTML - just like you would do in PHP. Here's the results (with some CSS for styling):

A simple example of a Repeater control

As a Repeater will throw an Exception if an empty DataSet is bound to it, you need to check there is data to be bound first. A simple if statement will work, checking if there are tables in the DataSet and if the first table has rows:

I think you'll agree that having a control which sets templating for repeating data as easily as that is a massive help to the developer. One thing to note with the Repeater control - if you bind a DataSet to it by default the first table is used. If you're using stored procedures instead of inline SQL to run commands against your database you can return multiple tables, meaning you can load several sets of data for use in a page at once. In that case you'd use code like this (to bind the second table in the DataSet to the Repeater):

Creating a data access class

Let's pull the last couple of sections together and create a data access class that will simplify connecting to and running commands on your database. This code is for MySQL, but as you've seen the code for SQL Server is very similar. Create a new empty class called "DB" and paste this into the new file:

To use this in your code-behind file you'd put:

This data access class introduces you to a new style of database connection syntax using the MySqlCommand class (SqlCommand for SQL Server) and the ExecuteNonQuery method. As the code says, the ExecuteNonQuery method executes a query and returns the number of affected rows. Very useful for INSERT, UPDATE and DELETE commands.

Those of you with a good knowledge of Wordpress will see how this class is similar to the $wpdb global class in WP which offers methods like $wpdb->get_results("select * from table"); and $wpdb->query("delete * from table");. It would be easy for you to extend this data access class to have more useful properties and methods for your applications.


User Controls

So far we've used just two ASP.NET controls - Literal and Repeater - in honour of our aim to keep full control of the output HTML. But sometimes it's useful to encapsulate functionality for your own controls. ASP.NET allows you to create user controls with properties and methods all your own. These user controls can be thought of as discrete blocks of HTML that can be used inside a .aspx page, just like you'd include a separate file in a .php file.

We're going to create a very simple control that displays a truncated link. Firstly add a new file of type "User control with code-behind file" and call it "ShortLink".

Adding a new user control

You may notice the new file has an extension of .ascx, this is the extension for user controls. Open the .ascx file and you'll see this:

Open the code-behind file (MyControl.ascx.cs) and you'll see this:

Now we're ready to create our user control. Paste this code into the .ascx.cs (code-behind) file (I won't explain this code, it's simple enough):

Yes, user controls use the same Page_Load event handler that normal .aspx pages use. Now open the .ascx file and paste this into it:

Here you can see instead of a Page declaration we have a Control declaration, but the same Inherits property to bind it to the code-behind file. We also have a standard <a> element with the runat="server" property to make it a server-side control.

To use this control in your page simply register a tag prefix (this can be anything) at the top of the page like this:

Then use the control wherever you want to. To demonstrate this control I'm using two instances of it:

The TagPrefix property is the first part of the control tag and the TagName the second part, separated by ":" - My:ShortLink. And this is the result:

A simple user control

Here you can see that the public string property I declared in my ShortCode user control class (public string Link;) can be set in a Link property of the control. You can have any number of properties and they can be of any type. You can only set string types in the control tag itself (i.e Link="http://www.google.com"), as you can set the properties programatically from your code-behind file (like Link1.DatasetProperty = new DataSet();).

There's one bit of code here which needs a little more explanation.

Using a custom tag prefix

Your user controls need to have their own tag prefix. In our example above this is "My", but of course it can be any simple string. In the example above the tag prefix was registered, so ASP.NET knew what to do when it encountered it, using a declaration at the top of the page:

However it's possible to register your tag prefixes in your web.config file, so you don't have to do it on every page (as explained by Scott Guthrie - that's one blog you'll want to follow). Here's how, but before you rush in watch out for the error I got:

So put your user controls in a subfolder, for example "Controls".

You'll now want to put user controls everywhere. And the best thing about user controls is, because they are just like pages (without <html>, <head> and <body> tags) you can put anything you like in them. In fact it would be possible to write an entire application in user controls, including the relevent controls in your page depending on some parameters passed to it. Amazing.


Compiling and Deploying

As mentioned in part 1 of the tutorial, C# is a compiled language. Rather than PHP, which is compiled into language the computer can understand at runtime, C# is pre-compiled (or sometimes compiled on first run) and saved in assemblies for the computer to process.

This means that C# is faster (yes, it's true, sorry), and that you can catch a lot of errors in your code *before* you try to run it. You've already seen that happening when we discussed errors above. However, it means you can't just drop your ASP.NET application on a server and expect it to run. It also means you can't do live hacking of your code-behind files in a running application. Deployment needs to be approached a little more methodically than in PHP.

There are several other articles which do a much better job at explaining this than I would so I'll just link to them.


Next Steps

Hopefully between part 1 and this tutorial, you now have a much better idea of what ASP.NET is, and the advantages it can provide for developers. For further reading, you can check out some of my favourite places:

Finally, good luck! It's been a hard climb for me, as a PHP guy for many years, to get to grips with ASP.NET. However I've found many good things in the framework, and have come to appreciate the power of the C# language - without losing my love for PHP. I hope that you can do the same.

Advertisement