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).
@:
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 thetext
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:!-- pThis 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. pThe predicted annual total is: @( monthlyTotal * 12)/p // Displaying the page URL with a variable. pThe URL to this page is: @myPath/p }The result displayed in a browser:
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.
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:WebSitesMyWebSite
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:websitesmywebsite 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.
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
TheServer.MapPath
method converts a virtual path (like /default.cshtml) to an absolute physical path (like C:WebSitesMyWebSiteFolderdefault.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:WebsitesMyWebSitedatafile.txt -- p@Server.MapPath(dataFilePath)/p
The Href method: Creating paths to site resources
TheHref
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 theif
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 { textSorry!/text } }You can add multiple conditions using an
else if
block: @{ var theBalance = 4.99; if(theBalance == 0) { pYou have a zero balance./p } else if (theBalance 0 theBalance = 5) { pYour balance of $@theBalance is very low./p } else { pYour 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; } pSince 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:
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 afor
loop. This kind of loop is especially useful for counting up or counting down:@for(var i = 10; i 21; i++) { pLine #: @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 counteri
— you can use any legal variable name. When thefor
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.
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. 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 foreac
h 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 } /ulThe
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.To create a more general-purpose loop, use the
while
statement:@{ var countNum = 0; while (countNum 50) { countNum += 1; pLine #@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 theRequest
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 ofCustomer
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. *@ @{ h3Team 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"}; pThe number of names in the teamMembers array: @teamMembers.Length /p pRobert is now in position: @Array.IndexOf(teamMembers, "Robert")/p pThe array item at position 2 (zero-based) is @teamMembers[2]/p h3Current order of team members in the list/h3 foreach (var name in teamMembers) { p@name/p } h3Reversed 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:
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 Dictionarystring, int(); myScores.Add("test1", 71); myScores.Add("test2", 82); myScores.Add("test3", 100); myScores.Add("test4", 59); } pMy score on test 3 is: @myScores["test3"]%/p @(myScores["test4"] = 79) pMy corrected score on test 4 is: @myScores["test4"]%/pTo 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, aDatabase
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/pWhen 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/pAs 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 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 theThe 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 includesResponse.Redirect
method intry/catch
statements, because it can cause an exception in your page.
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" / titleTry-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!