License

© Copyright 2016, Amelia Read Garripoli

Amelia Read Garripoli (agarripoli@olympic.edu)
Information Systems
Department of Business & Technology
Olympic College
Bremerton, WA 98337

Like those that came before it, this book can be distributed in unmodified form for non-commercial purposes. Modified versions can be made and distributed for non-commercial purposes provided they are distributed under the same license as the original. More specifically: This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/. Other uses require permission from the author.

The website for this book is: http://faculty.olympic.edu/agarripoli/New2ASP .

The source of this book and all sample code can be downloaded from https://github.com/argoc/ASP.NET-for-Web-Developers/archive/master.zip

This book is provided “as-is”. It may contain errors of spelling, grammar, or semantics. Information and views expressed in this document may change without notice. You bear the risk of using it. Examples depicted herein are provided for illustration only and are fictitious.

This book references websites from external sources not under my control. The web addresses may change, the content may change, and in particular they may have an invasive privacy policy. It is your responsibility to be aware of this and to act accordingly. You use the links in this text at your own risk.

Use shall constitute acceptance of the terms listed.

Microsoft, Windows, Visual Studio, IIS, and ASP.NET are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.

Dedication

This book is dedicated to my family for not minding me doing this project while on summer break; to my peers at Olympic College, for giving me this opportunity; and to all the developers I have enjoyed working with in the past — isn’t it crazy how the internet has taken over every facet of what we do?

Preface

I wrote this book over my 2016 summer break, off-contract from my position as tenure-track Information Systems Faculty at Olympic College, using only personal resources. My goal was to make the Introduction to ASP.NET class something approachable without requiring a heavy math background or a career in software development. It assumes that you have had some programming courses and written small (100-line or more) programs successfully in an object-oriented language (such as Java or JavaScript); put together multi-page websites in HTML and CSS succcessfully; have used SQL in database systems; and desire to learn the ASP.NET environment.

Due to time constraints, I’ve made heavy use of excellent OER resources written for Java; C# and Java share many similarities. That said, this could not have been accomplished without the excellent Microsoft Developer’s Network resources at http://www.asp.net/ and http://www.msdn.com/

This book will be covering Razor, C#, and the ASP.NET library. It assumes you have already taken these Olympic College courses:

  • CIS 155, Web Development I. This course covers HTML and CSS.

    If you need a refresher on HTML, I recommend the Microsoft Academy course, HTML5 & CSS3 Fundamentals: Development for Absolute Beginners

  • CIS 210, Introduction to SQL. This course covers SQL.

    If you need a refresher on SQL, I recommend SQLZoo’s Tutorial or Learn Code The Hard Way’s Learn SQL The Hard Way.

  • Either CIS 255, Web Development II, which covers programming in JavaScript, or CIS 142, Java Programming I, which covers OO programming in Java.

    If you need a refresher on programming, I recommend finding a "learn to program" course on JavaScript, Java or C# that includes Object Orientation (OO) in its description; look on Udemy, EdX, Coursera, or other platform. (If you have a specific one you recommend, let me know).

It’s always a good idea to know the history behind what you are learning, so here is a short look into the history behind this technology:

ASP.NET was first released in 2002 by Microsoft as a web application framework on top of the .NET platform (first released in 2000), their common framework and engine for several programming languages. It provides a library and framework to support web development, and replaced the earlier Active Server Pages tehnology developed by Microsoft.

Razor was developed in 2010 by Andrew Nurse (of vibrantcode.com) for Microsoft. It replaces Active Server Pages' (.aspx’s) inlining syntax with a simpler form that has been embraced by the Microsoft developer community. It streamlines the transition between HTML and code.

C# was developed in 1999 by Microsoft. Who designed paticular features we do not know, but the team lead was Anders Hejlsberg. If you know Java, some of the changes may seem silly (IndexOutOfBoundsException instead of ArrayIndexOutOfBoundsException, for example) but some changes are helpful — the foreach loop in C# resulted in the definition of a similar structure in Java, after C# did it. C# also introduced many helpful shorthands in defining classes, so properties really are properties, and not directly tied to class instance variables. Was C# a response to Java’s license requiring no changes to Java? we will never know, but its lead developer claims that C# is "not a Java clone" but is more related to C++.

For more background, see

1. Web Development

Welcome to ASP.NET for Web Developers. In this text we cover the basics of building full-stack websites in the ASP.NET environment. A full-stack website has three layers: the client browser (Users), the Web Server, and a backing database (BD). The clients share that backing database, but each have their own personal view of it, provided to them by the web server. The users' only way to communicate is through the HTTP protocol, via web pages and asynchronous partial-page AJAX requests.

1.1. What the user sees

All that the user can see on their side is HTML, rendered by CSS, and supplemented with JavaScript. Every so often, something they do (including the passage of time) triggers a trip back to the web server that can alter the contents on the page or move them to another page. The web server may in turn want to access the backing datastore, typically a database or file system.

Great web design without functionality is like a sports car with no engine.

— Paul Cookson

1.2. What you write

When you develop a website or web application in the ASP.NET environment, you write HTML, JavaScript, and CSS, and then you add server-side coding and databases using Razor to embed C# in your page/application and call out to your own C# classes and those of the ASP.NET library. The database access can be done in several ways; we will be executing SQL classes using the ASP.NET SQLClient. Microsoft also provides LINQ, which provides both a library and another language for database access. The LINQ language is like SQL — similar to how C# is like Java.

You write your application code in Visual Studio, and when it is run within Visual Studio, it runs in a local web server using IIS Express. IIS is Internet Information Services, Microsoft’s web server; IIS Express is a lightweight version for development use. In deployed mode, your application would be packaged and deployed in Internet Information Services (IIS) for Windows® Server or some other web server supporting ASP.NET.

Web applications can be a bit more disorganized than a typical computer program — web sites turn into spaghetti really easily. So it is best to do some design up front, with a wire-frame diagram, and lay out that design in your development environment — use directories to separate portions of your code. You will find that the Visual Studio IDE provides some framework for you, separating different types of files into different directories. We’ll walk through the Visual Studio organization in the next chapter.

1.3. Where your code sits

The code you write is meant to live on a file system that is managed by a web server. When a person puts a URL in their browser (or clicks on a search result linking to a URL), that URL is fed to a web server. URLs identify the target machine and then the target page on that machine. The web server takes the target page as input and locates the data to return. It doesn’t actually have to go directly to a file, but in our case it will.

Our users' URLs will map to pages in our web sites. The web server will find the page, and then it will run the C# code on that page and return an HTML page free of Razor and C# to the requesting browser. That means all of your C# code runs on the web server; only JavaScript code runs on the browser. You will need to keep this in mind as you develop your web site: the user’s only interaction with your web site is via HTML, that is, links being clicked, forms being submitted, and JavaScript requests being issued. Your only way to communicate back is to provide HTML that is rendered in the user’s browser. Keep that in mind, because it is both very limiting and very freeing, like trying to rent an apartment when you have a cat. Some things aren’t going to be feasible, or require solutions unlike those you use in traditional stand-alone applications.

1.4. Microsoft’s Alphabet Soup

.NET, ASP.NET, CLR, MSIL, MVC — there are many different names behind the Microsoft technologies. Let’s take a look at how they fit together and where we will be working in this text.

NETBlocks
Tip

.NET stands for "dot-net". The N-E-T is not an acronym. It’s meant to imply network, internet — those netty things that drive computers. All of our other letter-words are acronyms.

The .NET framework is the underpinning of all managed code that runs on a Windows machine. If you write unmanaged code, you are writing raw code that runs against the operating system unchecked. Managed code is run inside the Common Language Runtime (CLR), where there are services for memory management, type safety, thread management, and other features to provide additional security and robustness to your code. The CLR requires that your code be compiled down to Microsoft Intermediate Language (MSIL). It has a just-in-time compiler within it that compiles that code down to machine code. Microsoft provides compilers (such as those within Visual Studio) that will compile C#, Visual Basic, F#, C++, and other languages to MSIL to be run in the CLR.

The .NET Framework class library provides a large library of classes that can be used by any language compiled to MSIL. This includes basic type services such as string manipulation, file services, database access (often referred to separately as ADO.NET), and collection types. There are also a variety of environments provided in the .NET Framework for developing GUI applications — we won’t be looking into those in this course, as our focus is web applications.

For Web support, ASP.NET provides additional libraries and classes to write richly-functional web sites. Best practices for this, and emerging web technologies, has resulted in 5 different ASP.NET technologies. They share a common core set of classes for HTTP support on the server side, but provide different envirnoments for developing.

  • Web Forms provides a very GUI-like experience for users, with widgets on the web page that interact with the server side. This was the first ASP.NET technology and is in wide use. However, it "breaks" several key philosophies in web-site development, and so has been overshadowed by MVC. ASP.NET provides the widgets and the framework for supporting their execution. If you see a URL ending in .aspx, it is using Web Forms.

  • Web Pages is a very light-weight framework providing direct hooks between web page content and the server. It uses Razor as a templating language to embed C# in HTML pages. ASP.NET provides a rich set of Helpers and its core functionality to enable rapid development. Web Pages' light-weight ness means it doesn’t tend to scale to large web-sites. For that, developers move to MVC. If you see a web page ending in .cshtml, it is using Web Pages.

  • MVC is Microsoft’s version of the Model-View-Controller design pattern done with C# and Razor. It provides a rich environment for developing web applications in that pattern, as well as rich add-ons such as the Entity Framework for automatic database migration and object-relational mapping. MVC web pages typically are 'just words', with no file extension (on disk, your web pages end in .cshtml, but MVC includes a rich routing engine that maps names to web pages).

  • Web API is a way to develop not a web site, but a web service. It relies on the four HTTP verbs (GET, POST, PUT, DELETE) to provide those services. This makes your URL available to service a wider variety of requests, not just web page requests. Microsoft has been folding this technology into MVC, as web sites often want to provide services as well, such as the "APIs" we see that let you put Paypal checkout buttons on boutique websites.

  • Signal R provides a web sockets experience, where client and server communicate bidirectionally. It uses web sockets in modern browsers, and provides fall-back support in older browsers. This lets servers push information to clients without a prior client request, useful in situations such as auction sites and near-real-time information sharing.

In this text we will be exploring Web Pages. This is a good entry point for programmers learning C# from another language, giving you time to play with the language in the small before entering the much more rigorous MVC environment.

1.5. Pobody’s nerfect

Once you start coding you will discover it’s hard to write perfect code. You will have to isolate and repair errors in your code to make it work correctly; we call this debugging.

An Early Computer Bug: a Moth
Figure 2. An early computer bug (Public Domain; work of a federal government employee)

Bill Burke’s journal entry on September 9, 1947 captures an early use of the term bug for a problem in a computer - in this case a real bug, a moth in a relay.

Debugging websites can be more challenging than your typical program, since the error can occur at several levels: database, server-side code, and client-side code. Each has their own software environment and code you’ve written for them.

The cause of an error can be syntax errors, runtime errors, or semantic errors.

Compilers typically catch syntax errors, when you mistype a keyword or variable name. Runtime errors occur when you run out of memory or access memory incorrectly. Semantic errors are the trickiest to catch and may not be apparent, as they occur when your program simply doesn’t do the right thing. For example, your program runs without errors, but does not implement the requested behavior.

Just like written English, where Word cannot catch a "word" error that is not a spelling error, you may use the wrong variable name - when it doesn’t match up to any variable, the compiler catches it; but when it matches the wrong variable, the compiler cannot help you.

It can be frustrating to work through any of these. You may not see the syntax error, and the message provided by the compiler may misdirect you. Runtime errors can be hard to isolate, and may be caused by a different part of your code executed long before the error occurred. Semantic errors can be a simple oversight, forgetting a requirement. These can have the most serious repercussions, so it is always a good idea to double-check requirements once your code is complete.

One of the most important skills to develop as a programmer is debugging; the ability to track down the source of an issue and resolve it appropriately. It can be frustrating, but it is always necessary. A typical developer’s first job is to take on existing code and "maintain" it. Don’t fool yourself — maintain is another word for "debug". Very few programs are out there that are completely bug-free. Even long-time code has issues. See, for example, the Heartbleed bug in OpenSSL.

When you have a bug, you need to be a detective. The behavior you see is a clue. You need to unwind the clues to discover the root cause and fix it there.

1.6. Debugging

based on material from Think Python and Think Java

I realize you do not yet know C#, Razor, and ASP.NET; however, the advice here works for any environment; so compare these ideas to the development work you have already done and see how they are applicable there. Review this section as you learn more about ASP.NET to fit it into what you learn about C# and Razor along the way.

Different kinds of errors can occur in a program, and it is useful to distinguish among them in order to track them down more quickly:

  • Syntax errors are produced by HTML, CSS, JavaScript, Razor, and C# when Visual Studio first encounters them. If you are running "on the wire", without Visual Studio, then they are detected at the first piece of software to handle them. HTML, CSS, and JavaScript syntax errors may not be detected until the browser sees them; most browsers try to recover gracefully, but may also output error messages or bad pages when handed syntactically incorrect HTML, CSS, or JavaScript. Razor and C# syntax errors are detected at compile time (C#) or interpretation time (Razor). It is the web server that interprets Razor and turns it into HTML for the client to display. Syntax errors indicate that there is something wrong with the syntax of the program. Example: Omitting the semicolon at the end of a C# statement yields an error unexpected keyword when the next keyword is found at the start of the next statement.

  • Runtime errors are produced by the interpreter if something goes wrong while the program is running. Most runtime error messages include information about where the error occurred and what methods or functions were executing. Example: An infinite recursion eventually cases the runtime error StackOverflowException.

  • Semantic errors are problems with an application that runs without producing error messages but doesn’t do the right thing. Example: An expression may not be evaluated in the order you expect, yielding an incorrect result.

The first step in debugging is to figure out which kind of error you are dealing with. Although the following sections are organized by error type, some techniques are applicable in more than one situation.

1.6.1. Syntax errors

Syntax errors are usually easy to fix once you figure out what they are. Unfortunately, the error messages are often not helpful. The most common messages are SyntaxError: invalid syntax and SyntaxError: invalid token, neither of which is very informative.

On the other hand, the message does tell you where in the program the problem occurred. Actually, it tells you where Visual Studio noticed a problem, which is not necessarily where the error is. Sometimes the error is prior to the location of the error message, often on the preceding line.

If you are building the program incrementally, you should have a good idea about where the error is. It will be in the last line you added.

If you are copying code from a book, start by comparing your code to the book’s code very carefully. Check every character. At the same time, remember that the book might be wrong, so if you see something that looks like a syntax error, it might be.

Nevertheless, you might find yourself in one of the following situations. For each situation, we have some suggestions about how to proceed.

The compiler is spewing error messages.

If the compiler reports 100 error messages, that doesn’t mean there are 100 errors in your program. When the compiler encounters an error, it often gets thrown off-track for a while. It tries to recover and pick up again after the first error, but sometimes it reports spurious errors.

Only the first error message is truly reliable. We suggest that you only fix one error at a time, and then recompile the program. You may find that one semicolon or brace “fixes” 100 errors.

I’m getting a weird compiler message, and it won’t go away.

First of all, read the error message carefully. It may be written in terse jargon, but often there is a carefully hidden kernel of information.

If nothing else, the message will tell you where in the program the problem occurred. Actually, it tells you where the compiler was when it noticed a problem, which is not necessarily where the error is. Use the information the compiler gives you as a guideline, but if you don’t see an error where the compiler is pointing, broaden the search.

Generally the error will be prior to the location of the error message, but there are cases where it will be somewhere else entirely. For example, if you get an error message at a method invocation, the actual error may be in the method definition itself.

If you don’t find the error quickly, take a breath and look more broadly at the entire program. Make sure each file is indented properly; that makes it easier to spot syntax errors.

Here are some ways to avoid the most common syntax errors:

  1. Make sure you are not using a HTML, CSS, JavaScript, Razor, or C#, keyword for a variable name.

  2. Check that all parentheses and brackets are balanced and properly nested. All method definitions should be nested within a class definition. All program statements should be within a method definition or a Razor code block.

  3. Remember that uppercase letters are not the same as lowercase letters.

  4. Check for semicolons at the end of statements, but no semicolons after a compound statement’s curly braces.

  5. Make sure that any strings in the code have matching quotation marks. Make sure that you use double quotes for strings and single quotes for characters in C# and JavaScript code. Make sure that all quotation marks are "straight quotes", not “curly quotes”. Be careful if you paste in text from another source.

  6. If you have multiline strings, make sure you have terminated the string properly. An unterminated string may cause an invalid token error at the end of your program, or it may treat the following part of the program as a string until it comes to the next string. In the second case, it might not produce an error message at all!

  7. Make sure that the types in your comparison, assignment, or method invocation statement are all compatible and convert correctly: pay attention to the type conversions that automatically occur.

  8. For each assignment statement, make sure that the expression on the left is a variable name or something else that you can assign a value to (like an element of an array).

  9. An unclosed opening operator--(, {, <, or [-- makes most languages continue with the next line as part of the current statement. Generally, an error occurs almost immediately in the next line.

  10. Check for the classic = instead of == inside a comparison.

  11. Check for object identity versus value comparison (== vs. === in JavaScript).

  12. Check the indentation to make sure it lines up the way it is supposed to. The best way to avoid this problem is to use automatic code formatting that generates consistent indentation.

  13. If you have non-ASCII characters in the code (including strings and comments), that might cause a problem, although most languages usually handle non-ASCII characters. Be careful if you paste in text from a web page or other source.

If nothing works, move on to the next section…​

I can’t get my application to compile no matter what I do.

If Visual Studio says there is an error and you don’t see it, that might be because you and the IDE are not looking at the same code. Check your development environment to make sure the application you are editing is the application the IDE is compiling.

This situation is often the result of having multiple copies of the same file. You might be editing one version of the file, but compiling a different version.

If you are not sure, try putting an obvious and deliberate syntax error right at the beginning of the program. Now compile again. If the compiler doesn’t find the new error, you are not compiling the code you are editting.

There are a few likely culprits:

  • You edited the file and forgot to save the changes before running it again. Some programming environments do this for you, but some don’t.

  • You changed the name of the file, but you are still running the old name.

  • Something in your development environment is configured incorrectly.

If you get stuck and you can’t figure out what is going on, one approach is to start again with a new program like “Hello, World!”, and make sure you can get a known program to run. Then gradually add the pieces of the original program to the new one. If you don’t want to restart, then try this instead…​

If you have examined the code thoroughly, and you are sure the compiler is compiling the right source files, it is time for extreme measures: debugging by halves.

  • Make a backup of the file you are working on. If you are working on Bob.cs, make a copy called Bob.cs.old.

  • Delete about half the code from Bob.cs. Try compiling again.

  • If the program compiles now, you know the error is in the code you deleted. Bring back about half of what you deleted and repeat.

  • If the program still doesn’t compile, the error must be in the code that remains. Delete about half of the remaining code and repeat.

  • Once you have found and fixed the error, start bringing back the code you deleted, a little bit at a time. This process is ugly, but it goes faster than you might think, and it is very reliable. It works for other programming languages too!

I did what the compiler told me to do, but it still doesn’t work.

Some error messages come with tidbits of advice, like “class Golfer must be declared abstract. It does not define int compareTo(java.lang.Object) from interface java.lang.Comparable.” It sounds like the compiler is telling you to declare Golfer as an abstract class, and if you are reading this book, you probably don’t know what that is or how to do it.

Fortunately, the compiler is wrong. The solution in this case is to make sure Golfer has a method called compareTo that takes an Object as a parameter.

Don’t let the compiler lead you by the nose. Error messages give you evidence that something is wrong, but the remedies they suggest are not always appropriate.

1.6.2. Runtime errors

Once your application is syntactically correct, IIS (the web server) can read it and at least start running it. What could possibly go wrong?

My application does absolutely nothing.

This problem is most common when your application consists of Razor code blocks does not actually generate HTML, or does not have a web page target to land on. This may be intentional if you only plan to import this module to supply classes and methods.

If it is not intentional, make sure there is HTML in the application, and make sure the flow of execution reaches it (see “Flow of Execution” below).

My application hangs.

If an application stops and seems to be doing nothing, it is “hanging”. Often that means that it is caught in an infinite loop or infinite recursion.

  • If there is a particular loop that you suspect is the problem, add a print statement immediately before the loop that says “entering the loop” and another immediately after that says “exiting the loop”. Run the program. If you get the first message and not the second, you’ve got an infinite loop. Go to the “Infinite Loop” section below.

  • Most of the time, an infinite recursion will cause the program to run for a while and then produce a “RuntimeError: Maximum recursion depth exceeded” error. If that happens, go to the “Infinite Recursion” section below. If you are not getting this error but you suspect there is a problem with a recursive method or function, you can still use the techniques in the “Infinite Recursion” section.

  • If neither of those steps works, start testing other loops and other recursive functions and methods.

  • If that doesn’t work, then it is possible that you don’t understand the flow of execution in your program. Go to the “Flow of Execution” section below.

Infinite Loop

If you think you have an infinite loop and you think you know what loop is causing the problem, add a print statement at the end of the loop that prints the values of the variables in the condition and the value of the condition.

For example:

while (x > 0 && y < 0) {
    // do something to x
    // do something to y

    <p>x: @x</p>
    <p>y: @y</p>
    <p>condition: @(x > 0 && y < 0)</p>
}

Now when you run the program, you will see three lines of output for each time through the loop. The last time through the loop, the condition should be false. If the loop keeps going, you will be able to see the values of x and y, and you might figure out why they are not being updated correctly.

You can also test your program by stepping through it with the Visual Studio debugger and displaying the values not only of the variables, but also of the boolean expression.

Infinite Recursion

Recursion means that a function or method calls itself.

Most of the time, infinite recursion causes the program to run for a while and then produce a StackOverflowException error.

If you suspect that a function is causing an infinite recursion, make sure that there is a base case. There should be some condition that causes the function to return without making a recursive invocation. If not, you need to rethink the algorithm and identify a base case.

If there is a base case but the program doesn’t seem to be reaching it, add a print statement at the beginning of the function that prints the parameters. Now when you run the program, you will see a few lines of output every time the function is invoked, and you will see the parameter values. If the parameters are not moving toward the base case, you will get some ideas about why not.

You can also test your application by stepping through it with the Visual Studio debugger and displaying the parameter values and the call stack at each invocation of the function.

Flow of Execution

If you are not sure how the flow of execution is moving through your application, add print statements to the beginning of each function with a message like “entering function foo”, where foo is the name of the function.

Now when you run the application, it will print a trace of each function as it is invoked.

In the days of IDEs, this type of "print" debugging is becoming old-school. You can use the debugger to step through your code, line by line, and examine the call stack, the value of parameters, variables and expressions, and the state of the system environment at each step along the way. However, in the multi-faceted ASP.NET web application environment, you may find it useful to include "print"-style debugging by generating information that shows up in your HTML on the client side to aid in debugging an active web application.

When I run the program I get an exception.

When an exception occurs, IIS displays a message that includes the name of the exception, the line of the program where the exception occurred, and a “stack trace”. The stack trace includes the method that was running, the method that invoked it, the method that invoked that one, and so on. In other words, it traces the sequence of calls that got you to where you are, including the file and line number where each call occurred. Many of these may be ASP.NET infrastructure methods; examine the list carefully to locate your files and methods in the list.

In deployed mode, IIS will not display this information, as it would be a security leak to show information about the internals of your server-side program.

The first step is to examine the place in the program where the error occurred and see if you can figure out what happened. Here are some common exceptions:

NullReferenceException: You tried to access an instance variable or invoke a method on an object that is currently null. You should figure out which variable is null and then figure out how it got to be that way. Remember that when you declare a variable with an array type, its elements are initially null until you assign a value to them. For example, this code causes a NullReferenceException:

Point[] array = new Point[5];
<p>array[0].x</p>

IndexOutOfRangeException: The index you are using to access an array is either negative or greater than array.Length - 1. If you can find the site where the problem is, add a print statement immediately before it to display the value of the index and the length of the array. Is the array the right size? Is the index the right value?

Now work your way backwards through the program and see where the array and the index come from. Find the nearest assignment statement and see if it is doing the right thing. If either one is a parameter, go to the place where the method is invoked and see where the values are coming from.

StackOverflowExeption: See “Infinite recursion”.

FileNotFoundException: Your application didn’t find the file it was looking for. If you are using Visual Studio, you might have to import the file into the project. Otherwise make sure the file exists and that the path is correct. This problem depends on your file system, so it can be hard to track down.

DivideByZeroException: Something went wrong during an arithmetic operation causing a value to be divided by zero.

NotFiniteNumberException: Something went wrong during an arithmetic operation causing an operation to occur on or return a NaN (not a number) or infinite value.

OverflowException: Something went wrong during an arithmetic operation causing the result to be too large for the target variable or property.

The Visual Studio debugger is useful for tracking down exceptions because it allows you to examine the state of the application immediately before the error. You can read about Debugging in Visual Studio at https://msdn.microsoft.com/en-us/library/sc65sadd.aspx.

I added so many print statements I get inundated with output.

One of the problems with using print statements for debugging is that you can end up buried in output. There are two ways to proceed: simplify the output or simplify the application.

To simplify the output, you can remove or comment out print statements that aren’t helping, or combine them, or format the output so it is easier to understand.

To simplify the application, there are several things you can do. First, scale down the problem the application is working on. For example, if you are searching a list, search a small list. If the application takes input from the user, give it the simplest input that causes the problem.

Second, clean up the application. Remove dead code and reorganize the application to make it as easy to read as possible. For example, if you suspect that the problem is in a deeply nested part of the application, try rewriting that part with simpler structure. If you suspect a large function, try splitting it into smaller functions and testing them separately.

Often the process of finding the minimal test case leads you to the bug. If you find that an application works in one situation but not in another, that gives you a clue about what is going on.

If you find that a program works in one situation but not in another, that gives you a clue about what is going on.

— Allen Downey

Similarly, rewriting a piece of code can help you find subtle bugs. If you make a change that you think shouldn’t affect the application, and it does, that can tip you off.

1.6.3. Semantic errors

In some ways, semantic errors are the hardest to debug, because IIS and the IDE provide no information about what is wrong. Only you know what the application is supposed to do.

The first step is to make a connection between the application text and the behavior you are seeing. You need a hypothesis about what the application is actually doing. One of the things that makes that hard is that computers run so fast.

You will often wish that you could slow the application down to human speed, and with some debuggers you can. But the time it takes to insert a few well-placed print statements is often short compared to setting up the debugger, inserting and removing breakpoints, and “stepping” the application to where the error is occurring.

1.6.4. My application doesn’t work.

You should ask yourself these questions:

  • Is there something the application was supposed to do but which doesn’t seem to be happening? Find the section of the code that performs that function and make sure it is executing when you think it should.

  • Is something happening that shouldn’t? Find code in your application that performs that function and see if it is executing when it shouldn’t.

  • Is a section of code producing an effect that is not what you expected? Make sure that you understand the code in question, especially if it involves other files. Read the documentation for the functions you call. Try them out by writing simple test cases and checking the results. In order to program, you need a mental model of how applications work. If you write a application that doesn’t do what you expect, often the problem is not in the application; it’s in your mental model.

The best way to correct your mental model is to break the application into its components and test each component independently. Once you find the discrepancy between your model and reality, you can solve the problem.

Of course, you should be building and testing components as you develop the application. If you encounter a problem, there should be only a small amount of new code that is not known to be correct.

1.6.5. I’ve got a big hairy expression and it doesn’t do what I expect.

Writing complex expressions is fine as long as they are readable, but they can be hard to debug. It is often a good idea to break a complex expression into a series of assignments to temporary variables.

For example:

this.Hands[i].AddCard(this.Hands[this.FindNeighbor(i)].PopCard());

This can be rewritten as:

neighbor = this.FindNeighbor(i);
pickedCard = this.hands[neighbor].PopCard();
this.hands[i].AddCard(pickedCard);

The explicit version is easier to read because the variable names provide additional documentation, and it is easier to debug because you can check the types of the intermediate variables and display their values.

Another problem that can occur with big expressions is that the order of evaluation may not be what you expect. For example, if you are translating the expression x/2 π into C#, you might write:

y = x / 2 * Math.Pi;

That is not correct because multiplication and division have the same precedence and are evaluated from left to right. So this expression computes ( x / 2 ) and then multiplies it by π, which is x π / 2.

A good way to debug expressions is to add parentheses to make the order of evaluation explicit:

 y = x / (2 * Math.Pi);

Now we can clearly see that π is in the divisor, not above it.

Whenever you are not sure of the order of evaluation, use parentheses. Not only will the program be correct (in the sense of doing what you intended), it will also be more readable for other people who haven’t memorized the order of operations.

1.6.6. I’ve got a function that doesn’t return what I expect.

If you have a return statement with a complex expression, you don’t have a chance to print the result before returning. Again, you can use a temporary variable. For example, instead of:

return this.Hands[i].RemoveMatches();

you could write:

count = this.Hands[i].RemoveMatches();
return count;

Now you have the opportunity to display the value of count before returning.

1.6.7. I’m really, really stuck and I need help.

First, try getting away from the computer for a few minutes. Computers emit waves that affect the brain, causing these symptoms:

  • Frustration and rage.

  • Superstitious beliefs (“the computer hates me”) and magical thinking (“the program only works when I wear my hat backward”).

  • Random walk programming (the attempt to program by writing every possible code bite and choosing the one that does the right thing).

  • Sour grapes (“this program is lame anyway”).

If you suffer from any of these symptoms, get up and go for a walk. When you are calm, think about the program. What is it doing? What are possible causes of that behavior? When was the last time you had a working program, and what did you do next?

If you suffer from any of these symptoms, get up and go for a walk. When you are calm, think about the application.
What is it doing?
What are some possible causes of that behavior?
When was the last time you had a working application, and what did you do next?

Sometimes it just takes time to find a bug. I often find bugs when I am away from the computer and let my mind wander. Some of the best places to find bugs are buses, parks, and in the gym or on a walk.

1.6.8. No, I really need help.

It happens. Even the best programmers occasionally get stuck. Sometimes you work on a program so long that you can’t see the error. You need a fresh pair of eyes.

Before you bring someone else in, make sure you are prepared. Your application should be as simple as possible, and you should be working on the smallest input that causes the error. You should have print statements in the appropriate places (and the output they produce should be comprehensible). You should understand the problem well enough to describe it concisely.

When you bring someone in to help, be sure to give them the information they need:

  • What kind of bug is it, syntax, run-time, or semantic?

  • If there is an error message, what is it and what part of the program does it indicate?

  • What was the last thing you did before this error occurred? What were the last lines of code that you wrote, or what is the new test case that fails?

  • What have you tried so far, and what have you learned?

By the time you explain the problem to someone, you might see the answer. This phenomenon is so common that some people recommend a debugging technique called “rubber ducking”. Here’s how it works:

  1. Buy a standard-issue rubber duck (or, just use the picture above).

  2. When you are really stuck on a problem, put the rubber duck on the desk in front of you and say, “Rubber duck, I am stuck on a problem. Here’s what’s happening…​”

  3. Explain the problem to the rubber duck.

  4. Discover the solution.

  5. Thank the rubber duck.

We’re not kidding, it works! See https://en.wikipedia.org/wiki/Rubber_duck_debugging.

1.6.9. I found the bug!

When you find the bug, it is usually obvious how to fix it. But not always. Sometimes what seems to be a bug is really an indication that you don’t understand the program, or there is an error in your algorithm. In these cases, you might have to rethink the algorithm, or adjust your mental model. Take some time away from the computer to think, work through test cases by hand, or draw diagrams to represent the flow of control.

After you fix the bug, don’t just start in making new errors. Take a minute to think about what kind of bug it was, why you made the error, how the error manifested itself, and what you could have done to find it faster. Next time you see something similar, you will be able to find the bug more quickly. Or even better, you will learn to avoid that type of bug for good.

Remember, the goal is not just to make the application work. The goal is to learn how to make the application work.

1.8. Exercises

We have only touched on concepts in this chapter, no concrete programming as of yet has been covered. So our "exercises" are thought exercises to consider as we move into technical aspects of programming Web Pages.

  1. What bugs in your own code have been the most difficult for you to identify and solve? What tactics will make resolving similar bugs easier for you in the future?

  2. When is it appropriate to put code on the server-side versus on the browser-side?

  3. What is the difference between a web site and a web application? How are they similar?

  4. What is the difference between a mobile application and a web application? How are they similar?

1.9. Project

Our goal for the course is to develop a full-stack web application: one that uses a database, server-side code, client-side code, HTML, and CSS. What that may be is wide open. Here are some suggestions, or perhaps you have a favorite website or app you’d like to pursue:

  • Pokemon Go (Ingress). Yes, it’s a mobile app. Consider a cut-down version that you could do with HTML forms/buttons and your current level of JavaScript skills (don’t, whatever you do, put this book down and go spend three months learning a JavaScript game engine such as Phaser). Pokemon Go has alot going on in it — GPS tracking, capturing Pokemon, Gym battles, shopping, creature growth/repair, starting Gyms, placing Pokestops, and on and on — it’s a game, a shopping experience, and so much more. Pick some aspect that interests you and run with it.

  • craigslist.org (or if you’d prefer Monster.com or some other job/resume posting board) — a way to post your things for sale/search and to see what others have posted. Possibly the simplest UI, but not the simplest UX. Definitely looks a bit dated, but easy to mimic with basic HTML skills. Or perhaps you want to make a more modern craigslist — and you can name it after yourself, since Craig did.

  • AirBnB — much prettier than craigslist, its focus is on renting rooms; has a full shopping cart experience. There are many specialty sales sites out there, this is just one possible example.

  • Uber (Lyft) — connecting people who are near one another, one giving a ride, one needing a ride; so not only a service provider and a customer, but also location information.

  • Amazon — go big or go home; a shopping experience with lots of organization, suggested items, wishlists, and on and on. What part of it do you find irresistible and want to explore?

  • RottenTomatoes (Flixster, AngiesList) — a site that posts in a particular genre (RottenTomatos is movies, AngiesList is services) and lets users rate them and post comments about them. It maintains an overall average score of ratings.

  • Facebook (or if you’d rather, MySpace, Twitter, Instagram, LinkedIn) — social networking; your profile and posts make it to your friends. Find people, make friends, have flame wars, start groups, …​ more here than meets the eye. What interests you?

  • Wikipedia: community-driven information site. Fan wikipedias include comments, not just community editing with editorial approval.

  • Yummly (allrecipes). Sharing recipes, comments and ratings on recipes, sharing photos of results of cooking them. …​ could be any sort of sharing site, perhaps sharing photos, parenting advice, or something else.

  • Yelp. Restaurants, their menus and statistics, and customer reviews. (Yelp actually publishes their data as a huge JSON bundle to see if programmers could come up with interesting new analyses of it.)

  • Google Drive. Users upload files, download, browse. Each user sees only their own files. Then there’s sharing: you let someone see a file or directory of yours, with either read or delete access. Google docs takes this even further with multi-user editing, but that’s a bit beyond the scope of this text.

  • The Internet Archive — capturing web pages and making them searchable. This has saved me so many times, I love it. It also has a way for the original author to get contents removed (not everyone wants a permanent presence). Make a craigslist wayback machine, that would be handy (the only one I’ve found costs money and requires a law enforcement certification to use).

The internet is your oyster — find something you’d like to figure out how to do in ASP.NET Web Pages. Make sure it has persistent server data, and write up a proposal. Nothing fancy — we’ll get into prototyping in the next chapter.

Whichever one you pick as your course project, know that you all will be evaluating each others' a few times in the quarter, providing feedback to your peers on their work to help it improve and to highlight its strong points.

2. Web Pages

This text assumes you are already familiar with the client-side languages: HTML, CSS, and JavaScript.

For an excellent CSS reference, download Smashing Magazine’s cheat sheet at https://www.smashingmagazine.com/wp-content/uploads/images/css3-cheat-sheet/css3-cheat-sheet.pdf

For an excellent HTML reference, download Smashing Magazine’s cheat sheet at https://www.smashingmagazine.com/wp-content/uploads/images/html5-cheat-sheet/html5-cheat-sheet.pdf

For a JavaScript reference, download both Pam’s JavaScript Cheat Sheet at http://thewebivore.com/wp-content/uploads/2013/02/PamsJavascriptCheatSheet.pdf and cheatography’s cheat sheet at https://www.cheatography.com/davechild/cheat-sheets/javascript/pdf/

As none of these are creative commons, I have not included them here.

2.1. ASP.NET

ASP.NET operates on several levels in our environment.

  1. It provides the engine on which our C# code runs, the Common Language Runtime. Microsoft has several languages that compile to the binary format understood by the CLR, which is called "Microsoft Intermediate Language", or MSIL, pronounced "missile".

  2. It provides the infrastucture for understanding and moving around in websites; each page of your website is actually a Page object in ASP.NET, and as such has properties that you can get and set, and actions that you can perform. We will see many such useful objects: Page, Session, HttpRequest, and others as we develop our web applications.

  3. It provides a rich set of functionality, often referred to as a library, that you can access as actions performed by objects. There is quite a bit of code that you will not have to write because it is already available to you in ASP.NET. For example, "substring" has already been written, and so has "WebMail.Send", which when configured properly will send an email for you.

Note

The ASP.NET library actions can look like function calls at times. However, when a target object is not identified, the current object is implicit. In your .cshtml files, this is the Page object, identifying the current page being rendered in the system.

ASP.NET runs within Microsoft Internet Information Services, which is the Microsoft web server. You install your web application within the web server, and when users request pages that reside in your web application, ISS renders them and provides them to the client.

From within Visual Studio, a local IIS Express engine is started up when you "run" your application, and automatically loads and starts your web application at its root page, Default.cshtml. Your machine operates as both client and server, providing both the IIS web server and the web browser that accesses its contents. We will cover deployment to a separate server later, but keep in mind it means that the local file system cannot be assumed to be where your web application lives.

Note

How does IIS know where to find the root page? It looks in the root directory for a file with a recognizable extension (.html, .htm, .aspx, .cshtml, .php even) and with a recognizable file name (Default, Index). Since Windows is not case sensitivie with respect to file names, it could even find defaulT.CSHtml. By convention, our projects always start at Default.cshtml.

2.2. Visual Studio

For this book, I have assembled a template available through the Visual Studio Gallery. This section describes that template’s organization, which follows Microsoft conventions.

To start your project with that template, in Visual Studio 2015’s menu, choose File → New → Project. On the left column of the New Project panel, select Templates → Visual C# → Web.

To install the template the first time, click the link at the bottom of the center panel that reads "Click here to go online and find templates.". In the search box (upper right corner, with the text "Search Online Templates" in it), enter "Identity,Razor". The template named "ASP.NET Web Pages Starter Site with Identity" will appear in the list. Select that template, replace "WebPagesSite1" with the name of your project, make sure "create directory for solution" is unclicked, verify the location for your project, and then click OK. This will create a new project with that template for you. Here is the screen showing that selection:

VSfirstproject
Figure 4. First Project in Visual Studio

All future projects will find ASP.NET Web Pages Starter Site with Identity listed under the Visual C# Web templates, along with the Empty web site:

VSnthproject
Figure 5. Template in Visual Studio

You can select the template there, enter an appropriate Name and Location, and click OK to start from that template in your next projet.

If you choose File → New → Project → C# ASP.NET Web Application → Empty or File → New → Web Site → ASP.NET Empty Web Site, you will get just a single file (Web.config) and no supporting infrastructure to work with. We will use that for some of our smaller examples, but want to make use of the template site for our more complete projects.

Note

There is a Microsoft-supplied template available in Visual Studio when you create your site with File → New → Web Site → ASP.NET Web Site (Razor v3). This creates you something similar to what is described here, but uses the old user login system of ASP.NET Membership, which relies on SQLCE. This isn’t compatible with deploying (Chapter 6) and so we use an alternative template that provides a user login system using the current ASP.NET Identity library.

VSdirectory
Figure 6. Web Site Template Tree

If there is no App_Data directory, create it by right-clicking on the prject name, and selecting Add → Add ASP.Net Folder → App_Data. This ensures the project knows about this special folder.

2.2.1. Review of website initial directories

  • Account holds the pages that access the Microsoft ASP.NET Identity system. This is a basic system, sufficient for our needs, and well-tested from wide distribution. It is unlikely you will need to alter the contents of this directory unless you choose to expand it with Identity plug-ins such as external authentication or two-factor authorization.

Tip

The files in Account are a great, in-depth collection of code for a single purpose; review their contents as you learn Razor, C#, and ASP.NET until you can understand how they work.

  • App_Code holds some startup code for the identity system (Startup.cs). You will add any C# files you create to this directory; the parent directory contains only configuration and Razor-enhanced html files (.cshtml)

  • App_Data holds the database(s) for your website; you start out with one for the user accounts, and may add to it or create a second one for your application data. You would also put text data files in this directory. The Identity database is usually stored in a file named Identity.mdf, and is created the first time you access the identity system on your website (create a login or attempt to login).

  • bin contains libraries to make your application self-contained; it is populated by Visual Studio when your C# code is compiled. "bin" is short for "binary", i.e. compiled code — taken from text to a binary format, MSIL (MicroSoft Intermediate Language), that is understood and executed by the CLR (Common Language Runtime). You never directly change the contents of this directory.

  • Content contains the CSS used by your web application. It is pre-populated with the CSS used by the template website, which includes JQuery.

Tip

The Content and Scripts directories have the same file twice, once with .min between the file name and the prefix, and once without. .min means "minified", which is a processing of the CSS and JavaScript to remove any unneeded whitespace and compress internal names. This is done to reduce the network traffic required for the website - though it also makes the files pretty unreadable.

  • Images contains the image files used by your web application. It is pre-populated with the images used by the template website.

  • obj contains the compiled files before they are packaged up and put in the bin directory. You should never need to directly alter the contents of this directory.

  • Scripts contains the JavaScript used by your web application. It is pre-populated with JQuery, Knockout, and Modernizr, three well-known frameworks used by the template website.

2.2.2. Review of website initial files

Important

Only the top-level files are discussed here; the ones within the directories are mentioned in the previous section.

  • _AppStart.cshtml contains HTML that is executed at the first request of any page in the site. (Not each page, the very first request only.) It is used if you have application-wide setup or values to prepare.

  • _PageStart.cshtml. This will let us use a common layout among our pages.

  • _SiteLayout.cshtml sets up to use the Web Pages templating convention, complete with a common title bar for user account login/registration and the outer tags of any HTML page. This is a powerful tool, used to give all of your pages a common look and feel.

  • About.cshtml, Contact.cshtml, and Default.cshtml are template pages provided to jump-start your website. You can see that they are not stand-alone HTML pages; they rely on Web Pages integrating it with _SiteLayout.cshtml and _PageStart.cshtml to become complete web pages.

Tip

You may be wondering where the Login pages are? They are in the Account folder. It is common to organize a website so that separate portions are kept in their own subdirectories.

  • favicon.ico is a small image file used as the icon in the web browser’s tab bar for your website. It must be a 16-pixel by 16-pixel bitmap file; you can create them, or edit this one, in Microsoft Paint or from within Visual Studio.

  • packages.config lists all external packages your web application depends on.

  • Web.config, you may notice, appears to be both a file and a directory. In File Explorer, you will find it is just a file, and that there are two more files right after it, Web.debug.config and Web.release.config. The debug file sets up additional parameters for removing items you don’t want visible in production code such as stack traces. Web.release.config does the opposite, removing configuration that makes a website easier to debug but less secure.

2.3. Web Pages Layouts

The layout structure supplied in Web Pages makes it easy to have a common template within which your pages appear.

This is a good thing, as it lets you give your website a consistent look without having to repeat the HTML across all the files.

Web Page Layouts let you lay out a "parent file" that specifies the layout of all your pages as well as separate header and footer files pulled in for your pages. You can isolate down portions that need to be the same and portions that need to change.

Tip
Don’t Repeat Yourself

This Web Pages feature embodies an important programming concept: D.R.Y.: Don’t Repeat Yourself. (oops)

Layouts are done using the ASP.NET library. This requires that you learn the first step of Razor: how to embed an ASP.NET function call in your code.

This is done by prefixing the function call with the @ symbol.

2.4. Layout Functions

Here are the ASP.NET functions used to manage layouts:

Table 1. ASP.NET Layout Functions
Function Example Description

RenderPage

@RenderPage("header.cshtml")

Finds the named page and pulls its contents in to the current location.

RenderBody

@RenderBody()

Pulls in the main HTML from the file this template is being applied to.

RenderSection

@RenderSection("help", required:false)

Pulls in the named section from the file this template is being applied to; if required is true or not specified, the section must exist.

2.4.1. Identifying the Template

You get the template by creating a layout file (_SiteLayout.cshtml is the one supplied) and then having a _PageStart.cshtml that identifies it in a Razor code block, like so:

@{
    Layout="~/_SiteLayout.cshtml";
}

This is doing several things:

  • @{..} embeds a C# code block - this is our second Razor construct.

  • Layout=…​ is a C# assignment statement that assigns a value to the page Layout property, which will cause the template to be pulled in and used along with the contents of this file. Layout is a page property, which says what layout to use for the page. That layout file will contain instructions on how to use the rest of the content of your page.

  • "~/_SiteLayout.cshtml" is a C# string value that will be used to find the template file. This one in particular uses the ASP.NET convention for a file name, ~ represents the root directory of the website. You should always use either ~ rooted references or relative references, since your website’s location in a particular directory is not guaranteed and will be different in deployment than in development.

Tip

Alternatively to using a _PageStart.cshtml, you can have each page in your site set the Layout variable directly in a Razor code block at the top of the file. This lets you have a different layout for each page if you want it — but usually it’s best to have one layout shared among the files in your site, for a consistent experience.

2.4.2. Identifying a section

You identify a section named help within your .cshtml file like so:

@section (1)
  help (2)
{
  <p>If you are looking for assistance with this web site, please contact admin@website.com.</p> (3)
}
  1. @section is the Razor marker to make this portion of your file a section; it will only be rendered if there is a matching @RenderSection call in the layout file.

  2. This is the name of the section; you can give your sections any valid identifier.

  3. The section begins and ends with curly braces; within you place HTML and potentially embedded Razor blocks.

2.5. Making Layout Setting DRY

You have seen that you can apply different layouts to different pages in your website by setting the Layout property at the start of each page. However, what if you forget one page?

This is handled at a directory-wide level with a _PageStart.cshtml file. When a target page is identified, a _PageStart.chtml file in the same directory is read and rendered before the file for the page itself. So you can ensure that all the files in a given directory use the same layout file by creating a _PageStart.cshtml file that sets the Layout property like so:

Listing 1. _PageStart.cshtml
@{
  Layout = "~/SiteLayout.cshtml";
}

You can put any other common processing in that file as well.

If you need to override the Layout property for a single file in the same directory, you can reset it at the start of your individual .cshtml file — it will change the property’s value onces _PageStart completes and your actual page begins rendering.

If you create a subdirectory, you would create a _PageStart.cshtml file in it to have each page in the new subdirectory use the same Layout.

2.5.1. Other uses for _PageStart

_PageStart can be used for more than just selecting a common layout: it lets you specify any common action you desire. This might include

  • initializing Page properties

  • specialized error handling

  • restricting folder access

2.5.2. Subdirectories?

I mentioned earlier that subdirectories are often used to separate different sections of a website. In the template provided, we see the Accounts directory contains all of the code for user accounts, login and registration, separate from the rest of the web site.

Within a directory, ASP.NET will look for a _PageStart file to use prior to rendering the file within the directory that you have requested.

2.6. Web Design

Layouts are simply a tool; the key task behind them is designing your web application. We are looking at web applications that would have several pages, would be accessed by a variety of people (this is the internet, after all), and involve persistent data kept on the server.

2.6.1. Learn from the Internet

You probably already have favorite places on the internet — consider what you like about them, and how they are organized. You can always take a peek at how they did their HTML with a simple right-click and View Source…​ on the pop-up menu that appears. You won’t see their client-side code, but you will see their HTML, and any links to additional CSS and JavaScript files there can be clicked on to bring those up as well.

When you do this, remember: there is an implicit copyright on anything you see on the internet, unless they have released it with an explicit statement or license such as Creative Commons (for content) or Open Source (for code). You can’t simply copy and paste what is there, you need to learn from it, internalize it, and then put it aside when you work on your own web applications. Copying code is a copyright violation, and in the workplace can be grounds for losing your job or legal prosecution.

2.6.2. Responsive Web Design

A current theme in web design is to have your site be responsive; in fact, this replaced the prior theme of "mobile-ready" web sites. Razor provides some capabilities for "mobile-ready" — we will not be discussing them in this text. To make your web site responsive regardless of its target client, use the CSS/Javascript framework called Bootstrap. This framework is included in ASP.NET MVC projects due to its rich capabilities.

Bootstrap is outside the scope of this text; for more information, I recommend: the official bootstrap resources and the Tutorials Point Bootstrap Tutorial.

2.6.3. Basic Design Principles

Good design starts and ends with the user: is your website usable. Yes, it has a purpose; it is your job as its designer to mold that purpose into a positive user experience. As developers, we often forget to look at the user and get lost in the purpose. So, design focuses on the user perspective, as you see in the list below.

Design is a plan for arranging elements in such a way as best to accomplish a particular purpose.
— Charles Eames
1. Don’t make users think

Make it easy for users to "do the right thing" — you want them to stay on your site and enjoy it. This means inviting them to push the right button, not making them click several times where one click will do.

There are a few things to know about users that can help you with this:

  • users know quality when they see it; if they hit typos or things that don’t work, you’ve lost them.

  • users scan: don’t overload them with text; you are making a website, not a book.

  • users are impatient, and that means they will choose early rather than look at all the options.

2. Don’t waste users' time

This can be anything from slow load times to requiring several clicks where one would do. Right-size your images for the web, and consider mobile load times; you can tailor images to several platforms with CSS media rules.

Also consider not having them register at first — get them interested in your site so that they want to register. When you do make them register, don’t ask them for more information than you need. Privacy is important to users, and they may leave your site if you ask for irrelevant information.

Consider how you want your website to flow; different parts may need different flows — think about the user experience and what they will expect, to make them as intuitive as possible.

Two typical flows are hierarchical, where you drill down to more detail on a particular item; and sequential, where you step through a series of equal items. E-books are often a collection of both; the book opens to a table of contents that lets you drill down to particular chapters, and chapters drill down to sections. Once you are on text, you can move sequentially from page to page.

hierarchical
Figure 7. Hierarchical flow
sequential
Figure 8. Sequential flow

Website layout is often done with a "wire diagram" showing how the pages are interconnected. Cloud tools such as Cacoo and freeware such as Pencil are great tools for layout out your website before you commit to HTML.

3. Keep it simple

Choose simple words, keep phrases and text short and focused. Technical writing is an art in itself. Remember to focus on avoiding spelling errors and also on using active voice.

Tip

What is active voice? Write as if you were talking to your user, and use direct language. For example, instead of saying "at this point in the installation one may see that the icon is changing colors", say "now you see the icon change color". Active voice is tight, crisp, and direct.

Your layout should also be simple; don’t overload the user with flashing icons, lots of fonts, and random color changes. Keep it clean and crisp — keep it simple. In this regard, white space is your friend. Look at websites you like — see where they put gaps, around headers, around images, between sections on their pages. Strive to use whitespace to add organization and direction to your site.

4. Make the right choice obvious

Each page should have one goal; and users should be able to figure that out and satisfy that goal quickly. Focus the user’s attention on the key activity the page wants them to do.

Guide the user — you may feel like you are oversimplifying things, but remember, they will decide to stay on your site or not in three seconds.

There is some great advice on this here: ttp://conversionxl.com/8-universal-web-design-principles-you-should-to-know/

5. Use layout carefully

There should be a consistent look to all of the pages in your application. That layout needs to consider that it is on all of your pages. Keep common features such as links to a privacy policy, out of the way but available. Navigation is usually at the top of a page, links to common pages at the bottom.

HTML provides you with the ability to change font sizes and font families easily. Do this with care. Use the semantic tags appropriately, so <h1> is your largest, most important heading and <h6> is your smallest, least important heading. It’s seldom appropriate to have more than 2 levels of headers, actually, as users won’t stay engaged long enough if they need to keep the upper levels in mind to know where they are.

Step away from your monitor to view the page from a distance — is there a visual clue there that aids the user in finding out what to do, without being able to read the text? There should be.

6. Don’t be unconventional

Sure, it’s fine to work on being a break-out designer with the newest look. But when you are creating something that is new-but-not-new, such as a website to sell shoes, consider what the biggest in the business do: zappos.com has this down. Now, you can’t copy their site, but you can learn from it: where do they put their privacy policy? what order are their shopping cart check-out steps in? You will soon find that websites that sell things (even non-shoe things) have a pretty standard order for cart check-out. It would be to your benefit to use the same order. That way users won’t get lost, and you will get the sale.

Even a game website has some conventions: there will be help links, inventory pages, pages to shop for extra goodies, and the basic game play page.

There are conventions for web pages that are there for very good reasons, such as WebAIM's guidelines for accessibility. When you learn about conventions such as those, use them. It will help your web site if more people can use it. Some conventions may actually be a legal requirement for your website: accessibility, copyright, terms of service, and privacy policies are becoming more mandatory, with legal requirements in some fields such as education and government web sites.

2.8. Exercises

  1. Design a layout that mimics craigslist.org: a home page with links to sections, section pages with links to individual items, and individual item pages. Develop a wire-frame and then implement your layout in Web Pages. Include at least 3 sections and 6 items (it is fine to cross-list items in multiple sections). Have a common look-and-feel, and capture it in _SiteLayout.cshtml. Use _AppStart.cshtml and _PageStart.cshtml. Use the Web Pages convention of ~ as the location of the root directory of your website, not an absolute path.

    This will be a hierarchical layout (with a little spaghetti at the lowest level if you reuse item pages).

  2. Design a layout that mimics a shopping cart purchase process: a cart page showing contents, and includes at least three steps in the process.

    Consider what you want displayed on each page, and why you chose the steps and the order in which you present the steps (was it modeled after a well-known website? what reasoning did you use in putting the pages in the order you chose?)

    Design a wire-frame and then implement your layout in Web Pages. Have a common look-and-feel, and capture it in _SiteLayout.cshtml. Use _AppStart.cshtml and _PageStart.cshtml. Use the Web Pages convention of ~ as the location of the root directory of your website, not an absolute path.

    This will be a sequential layout.

2.9. Project

Design a layout for your application. Use the Layouts and Render, and start with the default Razor 3 application so that user logins are a part of your website. Rewrite the About and Contact pages. Make the contact information reflect how you would like to be contacted - only include information for the methods of contact you want to respond to. Use a _PageLayout.cshtml file so that you do not repeat the code to set the Layout property in every page.

Start looking into Geolocation in HTML, using this: http://apress.jensimmons.com/v5/pro-html5-programming/ch5.html

Make a You Are Here webpage that shows the user’s current location by latitude and longitude. Or go for it, and show it on a map. Be sure to include a citation of sources used in your HTML. To display a map you will have to have a google account so that you can get a Google Maps key. This is available at no charge at the google link above. (Bing also has a map service, if you prefer using a Microsoft account; theirs also requires a key.)

3. Razor

Believe it or not, you’ve already seen almost enough Razor to infer how it is used to embed C# within a web page.

Let’s take a step back and review what’s going on:

RazorEngine
Figure 9. Where Razor fits in the web request processing

When a client requests a particular page, the web server determines how to "source" it — it may be a file (as ours are) or it may be an interface to another system. It locates the file, and then determines if it needs further processing before it is returned.

A web browser (in the client) can only handle HTML, CSS, and JavaScript, so anything beyond that needs to be turned into one of those three on the server. So, when the web server realized the page has Razor in it, it hands it to the Razor engine. That engine will execute the code within the Razor markers, which may impact the server-side state and may also cause HTML to be generated within the page. Once the processing completes, the final HTML page is returned to the client for rendering in the web browser.

Razor is a templating "language": it defines how to note that you are now in C#, which needs to be executed on the server side. Razor is used for two reasons:

  1. to impact server-side state

  2. to generate in-place HTML within the page

Its rules are fairly basic and intuitive, and just like we can use parentheses to clarify order of operations, Razor gives us several ways to make very clear when we are specifying client-side code (HTML, JavaScript, and CSS) and when we are specifying server-side code (C#).

Note

Yes, Razor can also be used to embed Visual Basic. We won’t go there. To see those rules: http://www.asp.net/web-pages/overview/getting-started/introducing-razor-syntax-vb

3.1. Razor’s Rules

1. Use the file extension .cshtml

To tell the web server that your page has Razor and C# in it, you give the file the extension .cshtml. That’s all.

If your page in fact has no Razor/C# in it, it works fine. The processsor won’t find anything to process, and simply returns the file unchanged.

2. @{ …​ } marks a code block.

To put a block of C# code in your file at the point you want it executed, you open the block with @{ and close the block with }. Everything within is considered to be C# and is interpretted as such. The contents must follow the rules of C# (but note #4 below).

<!- - Multi-statement block - - >
@{
var weekDay = DateTime.Now.DayOfWeek;  (1)
var weekDayMessage = "Thank goodness it's " + weekDay;
}
  1. the variable weekDay is looking into an ASP.NET object named DateTime. The "." operator on DateTime accesses a property called Now, which is then accessed with another . operator to get its DayOfWeek property. That holds a string value which is, you guessed it, the day of the week when the code is executed.

3. @ marks an inline expression.

If you want a simple value in your HTML, you can slip into C# mode with a simple @ symbol. The expression is evaluated by the Razor engine and its value put into the resulting output HTML file.

Typically the @ is used with a variable previously declared in a code block, or with a function call. It can also be an arbitrary expression, wrapped in parentheses.

ASP.NET provides many useful functions; you saw this with the @RendorBody() method used in Layouts.

<p>Hello. @weekDayMessage</p> (1)
<p>Did you know that 1 + 1 is @(1+1)?</p> (2)
  1. Assuming the code block above occurs first, this will substitute the string in place of the variable when the page is processed in the web server, so on a Monday, the resulting HTML will be the code shown below.

  2. And yes, @(1+1) is a bit silly but shows the use of parentheses around an expression.

<p>Hello. Thank goodness it's Monday</p>
<p>Did you know that 1 + 1 is 2?</p>
Caution
HTML Encoding

The @ marker has a very interesting and valuable side-effect. The content that is put is is "HTML encoded". ASP.NET replaces reserved HTML characters with codes that will display the character in the web page rather than let them be interpretted as HTML. This is valuable because it prevents a security hole with user data called an "injection attack", where user data causes execution on the web page.

So, characters such as <, >, and & will be replaced with numeric entity references and will be displayed as text, rather than coming through unchanged in a string value.

If you want to have the string value appear as raw HTML, un-encoded, you will need to wrap the value in an ASP.NET function such as Html.Raw().

4. Declare variables with the var keyword.

This is one slight difference from C# general use, where variables are usually given types. Razor expects a more dynamic environment, so variables are declared simply with var and their type is inferred from their initialization.

C# does require the variables be declared, unlike PHP and other weak-typing languages.

@{ var total = 7; } (1)

<p>The value of your account is: @total </p> (2)
  1. total takes an integer value

  2. the value in the variable is put in its place in the resulting HTML.

The variable must be both declared and initialized, so that its type can be inferred from the initial value.

5. C# is case sensitive.

This is true in C# in general, and applies here as well. C# keywords and names are always case sensitive. The name you access a variable with must match the case of how it was declared. lastName and LastName do not match.

6. Statements end with semicolons.

If you use @ to start a statement, end it with a semicolon. (We won’t see an example of this until we get to more complex features requiring @using.)

Within code blocks, the normal rules of C# apply, where statements usually end with ; and compound statements are surrounded with { }.

7. To put @ in your HTML, use @@.

How do you put an email in a HTML file? like so: me@@gmail.com. @@ is replaced with @ by the Razor engine.

8. String values use quotation marks

Strings use the double-quote, or " mark, in Razor blocks and expressions.

We look to C# to see how to handle all the lovely corner cases with strings that always occur in a language:

C# requires \ (backslash) and " (the double quote) be handled with special string literals.

To put a \ in a string, you have to prefix the string literal with a @ marker. This is a C# @, not a Razor @. C# calls this a verbatim string literal. This is because the \ marker is used to include character encodings in string literals.

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

To put a double quote within a string, you use the verbatim string literal and double up the double quote, like so:

<!-- Embedding double quotation marks in a string -->
@{ var quote = @"Then she said, ""Hello, how are you?"""; }
<p>@quote</p>

This renders as:

<p>Then she said, "Hello, how are you?"</p>

To continue a long string value across multiple lines, start with a verbatim string literal opening (@") and then wherever you have newlines they will be ignored. Close the string with ".

9. ASP.NET Objects are available to you in code blocks and inline expressions.

Even before we start declaring our own objects in C#, you will be working with many ASP.NET objects. You have already done this with layouts: the RenderBody, RenderSection, and other functions are actually methods on the Page object available by default in a page.

Objects have properties that describe their characteristices and methods that define actions on the object. You can read or change an object’s properties and call its methods.

Besides the Page, you will have access to the Request that came in for the page, and many other system objects such as the DateTime object we’ve used already in our examples.

The Request object is an interesting one to explore:

<table border="1">
<tr>
    <td>Requested URL</td>
    <td>Relative Path</td>
    <td>Full Path</td>
    <td>HTTP Request Type</td>
</tr>
<tr>
    <td>@Request.Url</td> (1)
    <td>@Request.FilePath</td> (2)
    <td>@Request.MapPath(Request.FilePath)</td> (3)
    <td>@Request.RequestType</td> (4)
</tr>
</table>
  1. The Url property gives you the URL of the page

  2. FilePath gives you the path on the URL (after the domain name)

  3. MapPath is a method on Request that gives you the absolute path of the page on the server

  4. RequestType tells you if it was a GET or POST request.

10. Everything outside the Razor markers is HTML.

So, HTML comments are used in HTML, and C# comments are used within Razor blocks.

11. Put HTML inside Razor blocks with @: or <text>

You can actually include HTML within a Razor block by using any matching tags; the <text> tag is specific to Razor, but HTML tags such as <p> and <em> can also be used.

A single line of HTML can be included with @: at the start of the line.

You can also use inline expressions within those "HTML-inside-Razor" blocks - this can get confusing fast, so use this type of embedding carefully.

@{
    var minTemp = 75;

    <text>It is the month of @DateTime.Now.ToString("MMMM"), and
    it's a <em>great</em> day! <br /><p>You can go swimming if it's at
    least @minTemp degrees. </p></text>

    @: It is @DateTime.Now.DayOfWeek. (1)

    <p>We can just use the HTML markers too. And inline a value: @minTemp.</p>
}
  1. You might notice the closing . here — why doesn’t Razor consider it to be a dot operator? because there isn’t a valid name following it. Razor keeps following dot operators as long as they are followed by names, but when they aren’t, it stops and assumes the . is part of the HTML, not part of the inline expression. Razor’s really clever that way.

12. You can embed the C# if statement directly.

The C# if can be directly embedded with the @ operator rather than inside a code block. This may remind you of PHP, which does something similar:

@if(IsPost) { (1)
    <p>Hello, the time is @DateTime.Now and this page is a postback!</p> (2)
} else { (3)
    // All content between matched tags, followed by server code. (4)
    <p>Hello <em>stranger</em>, today is: <br /> </p>  @DateTime.Now
}
  1. IsPost is a property on the page which is true if the request was a POST of a form.

  2. This is HTML within the code block.

  3. Notice that the else uses curly braces but no additional @ symbols.

  4. The // is used to make a C# comment within the block.

13. Razor comments use @* *@

Yes, you have HTML comments in your HTML. Yes, you have C# comments in your code blocks.

You also have a third choice, which can be used in both places: Razor comments.

Razor comments are removed by the Razor processor, so they will not be seen on the client. HTML comments are seen on the client.

3.1.1. Is that it?

There are a few more uses of Razor that we will see, such as @using, but we will explain them when we have enough context to make them useful.

Razor itself is a small set of conventions that allow you to embed C# within HTML. So alot of our "Razor" rules above are actually C# rules (verbatim string literals, variables, and case sensitivity, for example). Helpers are also considered to be part of Razor; we saw some in Layout with the various Render calls that pull pages together from layout templates.

Razor also is used as a base in ASP.NET MVC, the next level of Web Development technology in the Microsoft stack.

I know Stack Overflow is a favorite landing pad when there are questions, but Microsoft Developer’s Network maintains forums that you may find useful, specifically the * ASP.NET Web Pages forum.

3.2. An example: a simple calculator

Listing 2. SimpleCalculator.cshtml
@{
    var result = 0;
    var message = "";
    if (IsPost) {
        // Retrieve the numbers the user entered.
        var num1 = Request["num1"].AsInt(); (1)
        var num2 = Request["num2"].AsInt();

        // Add the numbers and provide the result message
        result = num1 + num2;
        message = "Total = " + result;
    }
}

<!DOCTYPE html>
<html>
  <head>
    <title>Simple Calculator</title>

    <style type="text/css">
      body {font-family: Verdana, Arial; margin: 50px;}
      form {padding: 10px; border-style: solid; width: 250px;}
    </style>
  </head>

  <body>
    <p>Enter two integers and then click <strong>Add</strong>.</p>
    <form action="" method="post"> (2)
      <p><label for="num1">First Number:</label>
        <input type="text" name="num1" />
      </p>
      <p><label for="num2">Second Number:</label>
        <input type="text" name="num2" />
      </p>
      <p><input type="submit" value="Add" /></p>
    </form>

    <p>@message</p> (3)
  </body>
</html>
  1. The Request object is used to access a form’s fields. Since field names are dynamic, the […​] syntax is used with the field name to get to the form field value, rather than dot notation. The values are available as strings, so the .AsInt() method is called on the string value to conver it to an integer.

  2. Notice post here — that ensures when submit is clicked, the request is a post request, so IsPost is true in the C# code when the form is submitted. The original page request will be a get request. <3>The result message is completely filled out in the message variable so that no text is output if the user has not yet submitted the form. An empty paragraph will be output before the form is submitted.

Note
GET and POST in HTTP

HTTP requests are usually GET requests; forms can be submitted with either GET or POST. We use POST here so that we can use IsPost to determine that the form has been submitted (it keeps our code simple). POST is also used for long forms, to put the form values in the HTTP request rather than within the URL. A GET submission causes the values to be placed within the URL itself Google does this - check out the search URL next time you do a search.They use GET so the search result can be bookmarked. Since you set up the form, you get to decide how it will be submitted. This lets you handle form processing appropriately.

One thing our page lacks is error handling; we will see that there are calls we can make to check the input values and ensure they are valid integers prior to converting them to integers. There are several checks we may want to make, if our code is going to be used to control peoples' bank balances or fly shuttles to Mars. (Don’t believe me? see http://www.hq.nasa.gov/office/pao/History/alsj/a11/a11.1201-pa.html)

3.3. Giving Information to Pages

You can provide information to a page in your website using a Form, a URL, or a Query String.

3.3.1. Form and Query String information

As you’ve already seen, when a form is posted, the information is available in the Request object, which is held in the Request property for the page. Query information is also available in the Request object.

The Request object holds a dictionary, mapping fields and parameters to their values, as shown in the calculator example above. This dictionary also holds key/value pairs for cookies, client certificates, and server variables.

If you want to ensure you are looking at a URL query parameter, you can specify that you want to only look at the Query dictionary, by looking in Reqeust.QueryString rather than just Request.

If you want to ensure you are looking at a Form field, you can specify that you want to only look at the Form dictionary, by looking in Request.Form rather than just Request.

3.3.2. URL information

The meaning of URLs has been shifting in recent years. URLs with file extensions, query values, and even relative links are becoming less common. These complex URLs actually provide implementation details about your site you may not want to share. They are also given lower SEO scores or not even indexed by search engines.

This has lead to a rise in routing frameworks, including ASP.NET Routing. A routing framework knows how to map URLs to actions on a web server. Those actions might be fetching pages, or more complex actions re-routing a URL to a method call or database access.

ASP.NET Routing includes the ability to include information on the path portion of a URL.

Given a URL of the form http://mydomain.com/SimpleCalculator/Pi, ASP.NET will first attempt to locate the page Pi.cshtml in the directory SimpleCalculator. If it does not find that, it will look for SimpleCalculator.cshtml. If it doesn’t find that, it will report a HTTP 404 error on the original URL. However, if that is a page on our website, then it will invoke it, and will provide the unused portions of the URL in the page’s UrlData property. This property is an array of values, so UrlData[0] in our example would contain the string value "Pi".

If you invoked the same page with a different URL, http://mydomain.com/SimpleCalculator/Zero, then UrlData[0] would hold the string value "Zero", and http://mydomain.com/SimpleCalculator/1 would have the string value "1" in UrlData[0] .

We could use this value in our SimpleCalculator to initialize the field value like so:

    ...
    <input type="text" name="num1" value="@UrlData[0]"/>
    ...

Notice that I assume there is a value there; if there is not, the value is "", an empty string.

In general, this search for a page steps through each portion of the path until a page match is found. So, you could have several UrlData entries, one for each step in the directory.

Once the page is running, it can access the path that came after it in the URL through the UrlData property available on the page. UrlData is a simple array of strings, with UrlData[0] holding the first (on the left) unused name in the path, and UrlData[1] holding the second one, and so on; all of the URL’s /-separated names after the page name are in the UrlData array.

You can use this yourself to encode values passed to pages for course navigation, or to build URLs that will have higher SEO-scores than query-driven URLs.

3.4. Passing information to Layouts

The Layout page could also access Form, Query, and UrlData; however a Layout has to assume it is used by more than one page, and those structures may not be used by every page using that Layout.

It is more typical to pass information to the Layout from a content page using page properties, so that each page can construct the information in the same way for the Layout. That information can then be used by the Layout to configure its own content. We see this with Page.Title already.

ASP.NET Web Pages provides a general way to do this, using a special dictionary property named PageData. This dictionary maps keys to values; you choose the keys available in the dictionary. Keys do not have to be fixed at compile-time; they could even come from a database or external source.

Any PageData dictionary entries you make in the opening code block on your page will be visible to the Layout page and any other content pulled in to the Layout page.

For example, if I want to pass not only a page title but also a header for the page content, my opening codeblock on my page would look like this:

@{
    Page.Title = "Favorite Page";
    PageData["PageHeading"] = "My Favorite Page";
}

Then, in my Layout page, I can test to see if the value is set and if so, use it on the page:

@{
    // checking to make sure a heading was desired
    // (if you know it will be there, check could be skipped)

    if (PageData.ContainsKey("PageHeading")) {

        <h1>PageData["PageHeading"]</h1>

    }
}

There are several ways to accomplish this information-passing task available in ASP.NET, PageData is just one of them. If you look into this area of ASP.NET further, you will also see that you can use the dynamic nature of the Page object to assign dynamic properties, and may see reference to AppData or ViewBag properties used in this manner. Our convention follows the Razor Web Pages convention of using PageData.

3.6. Exercises

  1. The Introducing ASP.NET Web Pages - Getting Started tutorial steps you through a "hello, world" style razor page. Complete this walkthrough in Visual Studio (just this page’s information, not the pages that follow).

  2. The Microsoft Introduction to Razor page steps through several code examples. Take the one called "Add Numbers" and get it working in Visual Studio.

  3. The Walkthrough: Creating a Web Site using Razor Syntax in Visual Studio walks through one example, adding to it as it goes. Do the walkthrough starting after the VS update (with VS 2015 you already have Razor), and get the final page working in Visual Studio.

3.7. Project

  1. Forms are a big deal — they bring a website to life, getting input from the user for a tailored experience in the app. In this chapter you were given a simple example that processes form results on the same page as the form. Build a form that collects interesting data from the user, and have it route its results to a different page that then processes and displays the data entered. You can use either GET or POST as the action, since the target page is only used to process form results. It will not need to check IsPost, it can assume there is a Request with the values available. Make your form be something you might want to collect data about, such as movies, a bucket list, songs, goals, magic cards, pokemon, flowers, birds, yarns, or beers. You can use this later in your project when you have a backing database.

4. C# Variables and Expressions

Based on Think Java Chapter 2

You have already seen a little bit of C#. Now we are going to take a step back and cover the core features a bit more thoroughly.

This chapter describes how to write statements using variables, which store values like numbers and words, and operators, which are symbols that perform a computation. We also explain three kinds of programming errors and offer additional debugging advice building on that in Chapter 1.

This chapter will cover primitive types, variables, literals, expressions, assignment statements and method calls.

Later chapters will look into control flow statements, arrays, exception handling, object classes, properties, and methods.

4.1. Declaring variables

One of the most powerful features of a programming language is the ability to define and manipulate variables. A variable is a named location that stores a value. Values may be numbers, strings, booleans, objects, and other types of data. To store a value, you first have to declare a variable.

string message;

This statement is a declaration, because it declares that the variable named message has the type string. Each variable has a type that determines what kind of values it can store. For example, the int type can store integers, and the char type can store characters.

Some types begin with a capital letter and some with lowercase. We will learn the significance of this distinction later, but for now you should take care to get it right. There is no such type as Int; there is actually a String type in C#; it is the system class defined to support the string primitive type. Tere is also an Int32 class behind the int type.

To declare an integer variable, the variable declaration statement is:

int x;

Note that x is an arbitrary name for the variable. In general, you should use names that indicate what the variables mean. For example, if you saw these declarations, you could probably guess what values would be stored:

string firstName;
string lastName;
int hour, minute;

This example declares two variables with type string and two with type int. When a variable name contains more than one word, like firstName, it is conventional to capitalize the first letter of each word except the first. Variable names are case-sensitive, so firstName is not the same as firstname or FirstName.

variable names can contain underscores and numbers as well as letters. By convention, start with a lowercase letter, start inner words with an uppercase letter, even when they are acronyms such as HTML (use Html within a name or html at the start of a name).

This example also demonstrates the syntax for declaring multiple variables with the same type on one line: hour and minute are both integers. Note that each declaration statement ends with a semicolon.

You can use any name you want for a variable. But there are about 50 reserved words, called keywords, that you are not allowed to use as variable names. These words include public, class, static, void, and int, which are used by the compiler to analyze the structure of the program.

You can find the complete list of keywords at https://msdn.microsoft.com/en-us/library/x53a06bb.aspx, but you don’t have to memorize them. Most programming editors provide “syntax highlighting”, which makes different parts of the program appear in different colors.

A variable, once defined, has a visible scope. In Razor, a variable can be used anywhere on the page once it is declared in a Razor code block, including in a later Razor code block.

C# also allows another form of variable declaration:

var message = "Hello World";
var age = 23;

The keyword var can be used in C# to declare a variable if there is an initialization in the same statement — the = is used to assign an initial value to the variable. The C# compiler uses this to determine the type of the variable.

The type is fixed at compile time by the type of the initialization value.

In our example, message will be a string variable, and age will be an int variable.

The initializer on a var declaration cannot be null (which is a special, untyped value).

4.2. Assignment

Now that we have declared variables, we want to use them to store values. We do that with an assignment statement.

message = "Hello!";  // give message the value "Hello!"
hour = 11;           // assign the value 11 to hour
minute = 59;         // set minute to 59

This example shows three assignments, and the comments illustrate different ways people sometimes talk about assignment statements. The vocabulary can be confusing here, but the idea is straightforward:

  • When you declare a variable, you create a named storage location.

  • When you make an assignment to a variable, you update its value. As a general rule, a variable has to have the same type as the value you assign to it. For example, you cannot store a string in minute or an integer in message. We will see some examples that seem to break this rule, but we’ll get to that later.

A common source of confusion is that some strings look like integers, but they are not. For example, message can contain the string "123", which is made up of the characters '1', '2', and '3'. But that is not the same thing as the integer 123.

message = "123";     // legal
message = 123;       // not legal
Note

Assignment statements are actually expressions; if you use an assignment statement without a semicolon, then it is an expression, and it can be placed inside a larger expression. The value of an assignment expression is the value placed into the storage location (variables, so far, are our only storage locations; later we will see array indexes and properties used this way also).

Variables must be initialized (assigned for the first time) before they can be used. You can declare a variable and then assign a value later, as in the previous example. You can also declare and initialize on the same line:

string message = "Hello!";
int hour = 11;
int minute = 59;

This is the same syntax we saw with the var declarations above.

4.3. State diagrams

Because C# uses the = symbol for assignment, it is tempting to interpret the statement a = b as a statement of equality. It is not!

Equality is commutative, and assignment is not. For example, in mathematics if a = 7 then 7 = a. In C# a = 7; is a legal assignment statement, but 7 = a; is not. The left side of an assignment statement has to be a storage location (so far the only storage locations we have covered are local variables; we will see others in later sections).

Also, in mathematics, a statement of equality is true for all time. If a = b now, a is always equal to b. In C#, an assignment statement can make two variables equal, but they don’t have to stay that way.

int a = 5;
int b = a;     // a and b are now equal
a = 3;         // a and b are no longer equal

The third line changes the value of a, but it does not change the value of b, so they are no longer equal. When you store a value in a variable with an assignment statement, it replaces the value that was in that location earlier.

Taken together, the variables in a program and their current values make up the program’s state. This figure shows the state of the program after these assignment statements run:

variablevalues
Figure 10. State diagram of the variables a and b

Diagrams like this one that show the state of the program are called state diagrams. Each variable is represented with a box showing the name of the variable on the outside and the value inside. As the program runs, the state changes, so you should think of a state diagram as a snapshot of a particular point in the execution.

4.4. Constants

Sometimes we want names for values even though they don’t change. This cuts down on comments in the code, if the names are well-chosen. However, variable contents can be changed with a simple assignment statement. C# comes to the rescue with constants: add the keyword const before the variable declaration like so:

const int meaning = 42;

The constant must be initialized when it is declared, and its value cannot be changed once it is declared.

C# conventions say that local constants should be named just like local variables, with camel case (not all upper case as we see in other languages).

4.5. Displaying values

You can put the value of the variable on your web page with an inline expression.

The following statements declare a variable named firstLine, assign it the value "Hello, again!", and display that value.

@{ string firstLine = "Hello, again!"; }
<p>@firstLine</p>

When we talk about displaying a variable, we generally mean the value of the variable. To display the name of a variable, you have to put it in the HTML directly.

<p> The value of firstLine is @firstLine</p>

For this example, the resulting HTML is:

<p>The value of firstLine is Hello, again!</p>

Conveniently, the syntax for displaying a variable is the same regardless of its type. For example:

@{
int hour = 11;
int minute = 59;
}

<p>The current time is @hour:@minute.</p>

For this example, the resulting HTML is:

<p>The current time is 11:59.</p>

Note that the HTML formatting is required. Without the <p> tags, the text will run together even if you put whitespace between your un-tagged 'paragraphs'.

4.6. Data types in C#

Variables, constants, and literals all have a data type — the type of the data. So far, you’ve seen int and char. C# has a rich set of built-in primitive types, as shown in the table below.

type

description

range of values

literal

byte

8-bit unsigned integer

0 - 255

whole number in range

sbyte

8-bit signed integer

-128 - 127

whole number in range

short

16-bit signed integer

-32,768 - 32,767

whole number in range

ushort

16-bit unsigned integer

0 - 65,535

whole number in range

int

32-bit signed integer

- 2,147,483,648 - 2,147,483,647

whole number i.e. 452

uint

32-bit unsigned integer

0 - 4,294,967,295

whole number in range

long

64-bit signed integer

-9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807

whole number with l sufficx, i.e. 452l

ulong

64-bit unsigned integer

0 .. 18,446,744,073,709,551,615

ul suffix

float

32-bit floating point (7 digits)

±1.5e−45 to ±3.4e38

decimal number with f suffix

double

64-bit floating point (15 digits)

±5.0e−324 to ±1.7e308

decimal number with optional d suffix

decimal

128-bit, 28 digits of precision

-79228162514264337593543950335 .. 79228162514264337593543950335

decimal number with m suffix

char

16-bit Unicode character

U+0000 - U+FFFF

single quotes around one character

string

sequence of Unicode characters

double quotes around 0 or more characters or null (a special value meaning there is no value)

bool

Boolean value

true or false

true or false

object

An object

new creates one; null (more on this later)

As you will see later, C# also allows you to define classes, which are object-oriented types you can then use in your programs. ASP.NET actually defines its own classes, which C# maps to these primitive types. So, int maps to ASP.NET’s Int32 and string maps to String. It is C#'s convention to capitalize class names, property names, and method names while the primitive types and local variables and local constants are initial lower case. Both use camel case.

It is best to stick with the data type that will fit the values you need; however, if you are using a library of previously written methods, such as ASP.NET, you may use types larger than you need, to avoid conversion between types when you make calls to methods in that library.

4.6.1. String.Format

ASP.NET provides a helper method for formatting values. This is useful to truncate double values and also to display date time values. This helper is String.Format: the Format method on the system object String.

Here is a first example of how String.Format works. Its first parameter is a format string, and the remaining parameters are expressions that are plugged into the format string.

@String.Format("Hello, {0}.",name)

If the value in the variable name is "Dave", then the String.Format result is the string "Hello, Dave.". name is the first expression in the list after the format string, and so it is put in place of the {0}, which is a specification for the first expression (Format uses 0-based counting).

Here are some additional examples showing formatting and what it produces. Notice that the arguments do not need to be variables — they can be any expression, a literal, a method call, or operations on them:

String.Format("{0:C}",23.456)

"$23.45" // C is for currency

String.Format("{0:0.00}", Math.PI)

"3.14" // the result is always a string

String.Format("{0:#,##0.00}", 123456789)

"123,456,789.00" // notice the .00

String.Format("{0,-6}{1,10},"Name","Phone")

"Name Phone" // field widths: -6 left aligns; 10 right aligns

String.Format("It is now {0:d} at {0:t}", DateTime.Now)

"It is now 4/10/2015 at 10:04 AM"
//notice the value is used in two places

For more information on String.Format formats, see https://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx and the links at the end of that page to numeric, date/time, and additional formatting options.

4.7. Arithmetic operators

Operators are symbols that represent simple computations. In C#, the arithmetic operators include the addition operator is +, subtraction is -, multiplication is *, division is /, and remainder of division (modulus) is %.

The following code converts a time of day to minutes:

@{
  int hour = 11;
  int minute = 59;
 }

<p>Number of minutes since midnight:
   @(hour * 60 + minute)</p>

In this program, hour * 60 + minute is an expression, which represents a single value to be computed. When the program runs, each variable is replaced by its current value, and then the operators are applied. The values operators work with are called operands.

The result of the previous example is:

<p>Number of minutes since midnight: 719</p>

Expressions are generally a combination of numbers, variables, and operators. When complied and executed, they become a single value.

For example, the expression 1 + 1 has the value 2. In the expression hour - 1, C# replaces the variable with its value, yielding 11 - 1, which has the value 10. In the expression hour * 60 + minute, both variables get replaced, yielding 11 * 60 + 59. The multiplication happens first, yielding 660 + 59. Then the addition yields 719.

Addition, subtraction, and multiplication all do what you expect, but you might be surprised by division. For example, the following fragment tries to compute the fraction of an hour that has elapsed:

<p>Fraction of the hour that has passed:
@(minute / 60)</p>

The output is:

<p>Fraction of the hour that has passed: 0</p>

This result often confuses people. The value of minute is 59, and 59 divided by 60 should be 0.98333, not 0. The problem is that C# performs “integer division” when the operands are integers. By design, integer division always rounds toward zero, even in cases like this one where the next integer is close.

As an alternative, we can calculate a percentage rather than a fraction:

<p>Percent of the hour that has passed:
@(minute * 100 / 60)</p>

The new output is:

<p>Percent of the hour that has passed: 98</p>

Again the result is rounded down, but at least now it’s approximately correct.

4.7.1. Assignment and arithmetic

C# defines several short-hand operators that combine arithmetic and assignment: +=, -=, *=, /=, and %=.

These work like so:

x += 2;

means

x = x + 2;

The other operators work in the same manner.

There is an even shorter form for +1 and -1, the post-fix (after) ++ and -- and pre-fix (before) ++ and -- operators.

These have subtle impacts when embedded within other expressions.

x++ and ++x both add one to x, changing the value in the variable x. However, the value of x++ is x before it is updated, while the value of ++x is the value of x after it is updated.

int x = 3;
int y, z;

y = x++; // y is now 3 and x is now 4
z = ++x; // z is now 5 and x is now 5

4.8. Floating-point numbers

A more general solution is to use floating-point numbers, which can represent fractions as well as integers. In C#, the default floating-point type is called double, which is short for double-precision. You can create double variables and assign values to them using the same syntax we used for the other types:

double pi;
pi = 3.14159;

C# performs “floating-point division” when one or more operands are double values. So we can solve the problem we saw in the previous section:

double minute = 59.0;
<p>Fraction of the hour that has passed:
@(minute / 60.0)</p>

The output is:

<p>Fraction of the hour that has passed: 0.9833333333333333</p>

Although floating-point numbers are useful, they can be a source of confusion. For example, C# distinguishes the integer value 1 from the floating-point value 1.0, even though they seem to be the same number. They belong to different data types, and strictly speaking, you are not allowed to make assignments between types.

The following is illegal because the variable on the left is an int and the value on the right is a double:

int x = 1.1;  // compiler error

It is easy to forget this rule because in many cases C# automatically converts from one type to another:

double y = 1;  // legal, but bad style

The preceding example should be illegal, but C# allows it by converting the int value 1 to the double value 1.0 automatically. This leniency is convenient, but it often causes problems for beginners. For example:

double y = 1 / 3;  // common mistake

You might expect the variable y to get the value 0.333333, which is a legal floating-point value. But instead it gets the value 0.0. The expression on the right divides two integers, so C# does integer division, which yields the int value 0. Converted to double, the value assigned to y is 0.0.

One way to solve this problem (once you figure out the bug) is to make the right-hand side a floating-point expression. The following sets y to 0.333333, as expected:

double y = 1.0 / 3.0;  // correct

As a matter of style, you should always assign floating-point values to floating-point variables. The compiler won’t make you do it, but you never know when a simple mistake will come back and haunt you.

4.8.1. Rounding errors

Most floating-point numbers are only approximately correct. Some numbers, like reasonably-sized integers, can be represented exactly. But repeating fractions, like 1/3, and irrational numbers, like π, cannot. To represent these numbers, computers have to round off to the nearest floating-point number.

The difference between the number we want and the floating-point number we get is called rounding error. For example, the following two statements should be equivalent:

<p>@(0.1 * 10)</p>
<p>@(0.1 + 0.1 + 0.1 + 0.1 + 0.1
     + 0.1 + 0.1 + 0.1 + 0.1 + 0.1)</p>

But on many machines, the output is:

<p>1.0</p>
<p>0.9999999999999999</p>

The problem is that 0.1, which is a terminating fraction in base 10, is a repeating fraction in base 2.

Note

In base 2, 0.1 is 0.000110011…​ The …​ means that it keeps repepating 0011 over and over again; the computer has to cut it off, so cannot represent this value precisely. That is why they are called "floating point" or approximate numeric values.

So its floating-point representation is only approximate. When we add up the approximations, the rounding errors accumulate.

For many applications, like computer graphics, encryption, statistical analysis, and multimedia rendering, floating-point arithmetic has benefits that outweigh the costs. But if you need absolute precision, use integers instead. For example, consider a bank account with a balance of $123.45:

double balance = 123.45;  // potential rounding error

In this example, balances will become inaccurate over time as the variable is used in arithmetic operations like deposits and withdrawals. The result would be angry customers and potential lawsuits. You can avoid the problem by representing the balance as a decimal:

decimal balance = 123.45m;      // decimal literal, 28 digits of precision

This solution works as long as the value does not exceed 28 digits.

Note that there is an m after the value — this tells the compiler the literal is a decimal literal, not a double literal.

4.9. String operators

In general, you cannot perform mathematical operations on strings, even if the strings look like numbers. The following expressions are illegal:

"Hello" - 1     "World" / 123     "Hello" * "World"

The + operator works with strings, but it might not do what you expect. For strings, the + operator performs concatenation, which means joining end-to-end. So "Hello, " + "World!" yields the string "Hello, World!".

Or if you have a variable called name that has type string, the expression "Hello, " + name appends the value of name to the hello string, which creates a personalized greeting.

Since addition is defined for both numbers and strings, C# performs automatic conversions you may not expect:

@(1 + 2 + "Hello") @* the value is 3Hello *@

@("Hello" + 1 + 2) @* the value is Hello12 *@

C# executes these operations from left to right. In the first line, 1 + 2 is 3, and 3 + "Hello" is "3Hello". But in the second line, "Hello" + 1 is "Hello1", and "Hello1" + 2 is "Hello12".

4.9.1. string methods

In C#, even the primitive types are seen as objects. So, you can dot off of a string variable to invoke any of the methods defined on the string type. Many useful methods are defined, including:

CompareTo

compares the string to another string

Contains

determines if the string contains another string or character

EndsWith

determines if the string ends with another string

Equals

determines if the string is equal to another string

IndexOf

returns the first index of the provided char or string within the string

IsNullOrEmpty

returns true if the string is null or has no characters

IsNullOrWhitespace

returns true if the string is null or is a valid whitespace character (such as a space, tab, or other non-printing character)

LastIndexOf

returns the last index of the provided char or string within the string

PadLeft

pads the string on the left with the provided string or char

PadRight

pads the string on the right with the provided string or char

Remove

removes the provided char or string from the string

Replace

replaces a given char or string within the string with a new one

Split

splits the string on the given char (returns an array of strings)

StartsWith

returns true if the string starts with the specified char or string

ToLower

converts the string to lower case

ToUpper

converts the string to upper case

For the full list of string operators and their behavior, see https://msdn.microsoft.com/en-us/library/system.string(v=vs.110).aspx

These methods do not actually change the current string — those that return strings create a new string that holds the value described above. So to affect a variable, you would need to say, for example:

string message = "Welcome to my Page";
string thanks = "Thanks for Shopping";
message = message.ToLower(); // message holds "welcome to my page"
thanks.ToLower(); // thanks holds "Thanks for Shopping"

The second call to ToLower returns the new string, but since it isn’t stored with an assignment statement, it isn’t captured anywhere.

4.9.2. string extensions in Razor

In the Razor environment, string extensions provide a collection of conversion and test methods as well:

AsBool, AsDateTime, AsDecimal, AsFloat, AsInt

converts the string value to the specified type, returns a 0/false if it was not the type

IsBool, IsDateTime, IsDecimal, IsFloat, IsInt

returns true if the string value can be converted to a value of the specified type

Any operators that would alter the string contents return a new string value, they do not modify the underlying string value.

4.9.3. string properties

In addition there are two properties available on string variables:

Name

Description

[x]

Gets the char at position x in the string (there is no dot operator before this)

Length

Gets the number of characters in the string

4.9.4. ToString()

All types in C# define a method ToString() that converts the value of the type to a string value. This is useful when you want to get a printable version of a value, or compare the value to that stored in a string.

4.10. Comparison and Boolean Operators

C# has a primitive boolean type. These are very handy for storing simple states, testing conditions, and other operations. We will see they are heavily used in the C# flow-of-control statements. They take on only two values: true or false.

Having a boolean type means that we can discuss comparisons as expressions, since they take two values and compare them, resulting in a true or a false.

Comparison operators are supplied on all of the primitive types that result in boolean values: <, >, <=, >=, ==, !=, is. Note that == tests equality, not =, which is for assignment statements. is tests the type of a value and is true if the value has the type specified. These operators are defined to work in the logical way: numbers compare numerically, characters and strings compare from left to right based on character values, and false < true for booleans. Classes can override these operators to define them for a class as well.

We have to peek ahead just a little at objects to fully explain ==. == tests values for the built-in types, but for objects it tests object identity. So == on two objects returns true if and only if they reference the same object (or if they override the == operator, another possibility).

Caution

C# diverges from Java in how it tests string equality; string values are fully fledged objects in Java, where they are built-in types in C#. One particular result of this is that the C# == comparison on strings is a value comparison, while in Java it is an identity comparison.

The operators that take booleans include

&&

logical and

both sides must be true for true result

^^

logical exclusive or

only one side can be true for true result

!

logical not (unary operator)

reverses the value

4.11. Precedence of operators

When more than one operator appears in an expression, they are evaluated according to order of operations. Generally speaking, C# evaluates operators from left to right (as we saw in the previous section). But for numeric operators, C# follows mathematical conventions:

  • Multiplication and division take “precedence” over addition and subtraction, which means they happen first. So 1 + 2 * 3 yields 7, not 9, and 2 + 4 / 2 yields 4, not 3.

  • If the operators have the same precedence, they are evaluated from left to right. So in the expression minute * 100 / 60, the multiplication happens first; if the value of minute is 59, we get 5900 / 60, which yields 98. If these same operations had gone from right to left, the result would have been 59 * 1, which is incorrect.

  • Any time you want to override the order of operations (or you are not sure what it is) you can use parentheses. Expressions in parentheses are evaluated first, so (1 + 2) * 3 is 9. You can also use parentheses to make an expression easier to read, as in (minute * 100) / 60, even though it doesn’t change the result. Don’t work too hard to remember the order of operations, especially for other operators. If it’s not obvious by looking at the expression, use parentheses to make it clear.

There are many operators defined in C#, similar to those found in Java, C, and other languages. This table provides the order of precedence of the operators from highest (first to evaluate) to lowest (last to evaluate). When the order of precedence is the same, expressions are evaluated from left to right.

Table 2. Precedence and Associativity of C# Operators

Symbol

Type of Operation

Associativity

()

parentheses

left to right

. ?. f(x) a[x] a?[x] x++ x-- new typeof sizeof

Primary: member access, null conditional member access, function invocation, aggregate object indexing, null conditional indexing, postfix increment, postfix decrement, type instantiation, type object, size

left to right

+x -x !x ~x (T)x

Unary positive, negative, negation, bitwise negation, type cast

Right to left

* / %

Multiplicative

Left to right

+ –

Additive

Left to right

<< >>

Bitwise shift

Left to right

< > <= >= Is As

Relational and conversion

Left to right

== !=

Equality

Left to right

&

Bitwise-AND

Left to right

^

Bitwise-exclusive-OR

Left to right

|

Bitwise-inclusive-OR

Left to right

&&

Logical-AND

Left to right

||

Logical-OR

Left to right

??

Null coalesce

Left to right

? :

Conditional-expression

Right to left

= *= /= %=
+= –= <<= >>=
&= ^= |=
=>

assignments and lambda

Right to left

There are additional operators not included here, see MSDN C# Operators.

Notice the Associativity column; English readers expect left-to-right associativity, which means the operators are evaluated from left to right (1 + 2 + 3 is 3 + 3 is 6). However, the conditional expression and the assignment statements have right-to-left associativity. This means their right side is evaluated before their left side. For assignments this makes sense: the value to be assigned has to be evaluated before it can be stored in the storage location, so x = y = 2 first assigns 2 to y and then takes the value of that assignment expression, 2, and stores that in x.

4.12. Composition

So far we have looked at the elements of a programming language – variables, expressions, and statements – in isolation, without talking about how to put them together.

One of the most useful features of programming languages is their ability to take small building blocks and compose them. For example, we know how to multiply numbers and we know how to display values. We can combine these operations into a single statement:

@(17 * 3)

Any arithmetic expression can be used inside an inline expression. We’ve already seen one example:

@(hour * 60 + minute)

You can also put arbitrary expressions on the right side of an assignment:

@{
  int percentage;
  percentage = (minute * 100) / 60;
 }

The left side of an assignment must be a variable name, not an expression. That’s because the left side indicates where the result will be stored, and expressions do not represent storage locations.

hour = minute + 1;  // correct
minute + 1 = hour;  // compiler error

The ability to compose operations may not seem impressive now, but we will see examples later on that allow us to write complex computations neatly and concisely. But don’t get too carried away. Large, complex expressions can be hard to read and debug.

Composition is used extensively with boolean expressions. For example, we might say

// can I sell a movie ticket?
bool okToSell = ((movie < 17) || (age >= 17)) && (cash > total);

In this code we are testing to see if we can sell a movie ticket: if the movie requires the person be over 17, then we check their age; and they have to have the money to buy the ticket. Notice the use of parentheses; the expression would not evaluate correctly without the outer pair on the left, since && is evaluated before || (but luckily () is evaluated before &&).

4.13. General operators

These operators work on a variety of types and return either the same type or another one

??

null coalescing

x??y is y if x is null, otherwise it is x

?:

conditional operator

x?y:z is y if x is true, otherwise it is z

x++

postfix addition

result is x before changing, but x is incremented after that

++x

prefix addition

x is incremented and that new value is the result

sizeof(x)

size of

gives the size in bytes of the storage location or type

type(x)

type of

returns the object representing the type of the storage location

4.14. Method calls

We have already shown you method calls, as we are making use of ASP.NET throughout our code. When a method is called, it is called on an object (there is an implicit object for RenderBody, the current page). We call this "dotting off" of the object. The function name is given, and then values are specified to be passed to the method for it to use. These are called the method’s argument values. Argument values can be literals, variables, expressions, and even other function calls. They are evaluated and their value is copied and passed to the method. Any connection to a variable is broken at that point, as in C# "pass by copy" is used, with a copy of the value going into the method’s parameters for use in the method.

Methods can change the object they are invoked on, and can invoke methods on objects they are passed to change their state as well. It is important ot understand that it is not the original variable that changes, but only object state.

4.15. Classes and Objects

While we will not study objects in detail until a later chapter, it will be useful for you to know a little about them and about a closely related topic: classes. ASP.NET’s functionality is provided as a library of classes with properties and methods, and to understand what they are doing we need to explain just a bit about objects and classes up front.

4.15.1. Built-in methods and properties

A method is a set of program instructions that have been chunked together and given a name. A method is designed to perform some task. To get that task performed in a program, you can "call" the method by dotting off of the object that it acts on. Later on you will learn how to write your own classes and methods, but you can get a lot done in a program just by calling methods that have already been written for you. In C#, every method is contained either in a class or in an object. Some classes that are standard parts of the C# language contain predefined methods that you can use. Even the primitive types are viewed as objects, and have methods that can be used to manipulate them. These methods are "built into" the C# language, as part of ASP.NET. You can call all these methods without understanding how they were written or how they work. Indeed, that’s the whole point of methods: A method is a "black box" which can be used without knowing what goes on inside.

Let’s first consider methods that are part of a class. One of the purposes of a class is to group together some properties and methods, which are contained in that class. These properties and methods are called static members of the class. You’ve seen one example: Math is actually a class, and has a static member called Pi, a static property on the class. The parts of a class definition that define static members are marked with the reserved word "static", as you will see when we cover class definition.

When a class contains a static property or method, the name of the class is part of the full name of the property or method. For example, the standard class named Math contains a method named Abs. To use that method in your program, you must refer to it as Math.Abs. This full name consists of the name of the class that contains the method, followed by a period, followed by the name of the method. This method requires a number as parameter, and returns a new number that is the absolute value, so you would actually use it with a method call expression such as

absVal = Math.Abs(val);

Calling Math.Abs will invoke a system utility provided in ASP.NET. That utility is provided in compiled form, and in fact may not even have been written in C# — it doesn’t matter.

The Math class gives us an example of a class that contains static properties: Math.Pi and Math.E whose values are the mathematical constants π and e. Math also contains a large number of mathematical "functions." Every method performs some specific task. For some methods, that task is to compute or retrieve some data value. Methods of this type are called functions. We say that a function returns a value. Generally, the returned value is meant to be used somehow in the program that calls the function.

You are familiar with the mathematical function that computes the square root of a number. The corresponding function in C# is called Math.Sqrt. This function is a static method in the class named Math. If x is any numerical value, then Math.Sqrt(x) computes and returns the square root of that value. Since Math.Sqrt(x) represents a value, it doesn’t make sense to put it on a line by itself in a call statement such as

Math.Sqrt(x);   // This doesn't make sense!

What, after all, would the computer do with the value computed by the function in this case? You have to tell the computer to do something with the value. You might tell the computer to display it:

<p>@Math.Sqrt(x)</p>

or you might use an assignment statement to tell the computer to store that value in a variable:

lengthOfSide = Math.Sqrt(x);

The function call Math.Sqrt(x) represents a value of type double, and it can be used anyplace where a numeric literal of type double could be used.

The Math class contains many static member functions. Here is a list of some of the more important of them:

  • Math.Abs(x), which computes the absolute value of x.

  • The usual trigonometric functions, Math.Sin(x), Math.Cos(x), and Math.Tan(x). (For all the trigonometric functions, angles are measured in radians, not degrees.)

  • The inverse trigonometric functions arcsin, arccos, and arctan, which are written as: Math.Asin(x), Math.Acos(x), and Math.Atan(x). The return value is expressed in radians, not degrees.

  • The exponential function Math.Exp(x) for computing the number e raised to the power x, and the natural logarithm function Math.Log(x) for computing the logarithm of x in the base e.

  • Math.Pow(x,y) for computing x raised to the power y.

  • Math.Floor(x), which rounds x down to the nearest integer value that is less than or equal to x. Even though the return value is mathematically an integer, it is returned as a value of type double, rather than of type int as you might expect. For example, Math.Floor(3.76) is 3.0. The function Math.Round(x) returns the integer that is closest to x, and Math.Ceil(x) rounds x up to an integer. ("Ceil" is short for "ceiling", the opposite of "floor.")

For these functions, the type of the parameter — the x or y inside the parentheses — can be any value of any numeric type. For most of the functions, the value returned by the function is of type double no matter what the type of the parameter. However, for Math.Abs(x), the value returned will be the same type as x; if x is of type int, then so is Math.Abs(x). So, for example, while Math.Sqrt(9) is the double value 3.0, Math.Abs(9) is the int value 9.

You also saw the useful class DateTime, which has the very useful static property Now. Now is itself an object of type DateTime, representing the current system time. Because it is an object, not a class, you can call the instance methods and access the instance properties defined on the DateTime class. ("Instance" is the opposite of "static".) Instance properties and methods are defined for objects, not classes; you have to have an object instance to access them.

It is useful to look at how long processing takes; to do that, you will need to access the Ticks instance property on Now; this is the number of 100-nanosecond intervals since 12:00:00 midnight, January 1, 0001. This is a long value. Recording this value at the start and after completion of a section of code, lets you measure the time that it takes the computer to perform a task. Remember that C# is executed on the web server, so the performance you are measuring is the web server’s performance, not the client machine’s.

Here is a sample program that performs a few mathematical tasks and reports the time that it takes for the program to run. On some computers, the time reported might be zero, because it is too small to measure in ticks. Even if it’s not zero, you can be sure that most of the time reported by the computer was spent doing output or working on tasks other than the program, since the calculations performed in this program occupy only a tiny fraction of a 100-nanosecond interval of a computer’s time.

Listing 3. TimedComputation.cshtml
<!DOCTYPE html>
<html>
<head><title>Timed Computation</title></head>
<body>

<p>We performed some mathematical computations on the server;
here are the results, and how long it took to perform them.</p>

@{
    // capture the start time
    DateTime startTime = DateTime.Now;

    <p>Time at the start is @startTime.</p>

    // Compute the hypotenuse of a fixed triangle:
    double width, height, hypotenuse;  // sides of a triangle
    width = 42.0;
    height = 17.0;
    hypotenuse = Math.Sqrt( width*width + height*height );
        <p>A triangle with sides @width and @height
        has hypotenuse @hypotenuse.</p>

    // Compute a known mathematical value, see if double can handle it
    <p>Mathematically, <code>sin(x)*sin(x) + cos(x)*cos(x) - 1</code>
        should be 0.</p>
    <p>Let's check this for x = 1:<br/>
    <code>sin(1)*sin(1) + cos(1)*cos(1) - 1 =
    @(Math.Sin(1)*Math.Sin(1) + Math.Cos(1)*Math.Cos(1) - 1)
    </code></p>
    <p>(There can be round-off errors when computing with real numbers.)</p>

    // print a few random things...
    Random rand = new Random();
    <p>Here is a random number: @rand.NextDouble()</p>

    <p>The value of &pi; is @System.Math.PI</p>

    // figure out if time has passed ... how fast is your server?
    DateTime stopTime = DateTime.Now;
    TimeSpan elapsedTime = stopTime - startTime;

    <p>Time at the end is @stopTime.</p>
    <p>Run time was @(elapsedTime.TotalMilliseconds) milliseconds.</p>
}
</body>
</html>
Tip

If you get 0 time elapsed, that’s due to either the speed of your machine and the inaccuracy of DateTime.Now. See https://blogs.msdn.microsoft.com/ericlippert/2010/04/08/precision-and-accuracy-of-datetime/ for an interesting writeup on this topic.


4.15.2. Classes and Objects

Classes can be containers for static properties and methods. However classes also have another purpose. They are used to describe objects. In this role, the class is a type, in the same way that int and double are types. That is, the class name can be used to declare variables. Such variables can only hold one type of value. The values in this case are objects. An object is a collection of properties and methods. Every object has an associated class that tells what "type" of object it is. The class of an object specifies what properties and methods that object contains. All objects defined by the same class are similar in that they contain similar collections of properties and methods. For example, an object might represent a point in the plane, and it might contain properties named x and y to represent the coordinates of that point. Every point object would have an x and a y, but different points would have different values for these properties. A class, named Point, for example, could exist to define the common structure of all point objects, and all such objects would then be values of type Point.

As another example, let’s look at DateTime.Now.Time. DateTime is a class, and Now is a static property within that class. However, the value of Date.Now is an object, and DateTime.Now.Time is actually the full name of a property that is contained in the object DateTime.Now. You don’t need to understand it at this point, but the object referred to by DateTime.Now is an object of the class DateTime. Any object of type DateTime has a Time property that can be used to get the time value from the object. The object in DateTime.Now is just one possible object, and DateTime.Now.Time is a property of that value. Other objects of type DateTime will have a Time property that holds their time value. This is object-oriented programming: Many different things which have something in common — they can all be used to hold specific datetime values — can all be used in the same way — through accessing a Time property. The DateTime class expresses the commonalities among all these objects.

The dual role of classes can be confusing, and in practice most classes are designed to perform primarily or exclusively in only one of the two possible roles. Fortunately, you will not need to worry too much about it until we start working with objects in a more serious way, in a later chapter.

By the way, since class names and variable names are used in similar ways, it might be hard to tell which is which. Remember that all the built-in, predefined names in C# follow the rule that class names begin with an upper case letter while variable names begin with a lower case letter. While this is not a formal syntax rule, I strongly recommend that you follow it in your own programming. Method and Property names should also begin with upper case letters. This way there is no possibility of confusing a variable with a property, since a variables start with lower case and properties with uppercase.

In other languages, you may run across the terms function and procedure — in non-OO languages, there are no methods, but stand-alone named routines that are called directly, not dotted off of classes or objects. A function returns a value, and a procedure does not. In C#, we call them both methods, and put those that do not return values in statements and those that do return values in expressions. If you put a function or method returning a value alone in a statement, then the value that is returned is lost, not captured anywhere.

Java refers to properties as variables; however as we will see when we define classes, C# diverges quite a bit from Java in how it defines properties, making them unique and more powerful than the static and instance variables defined in Java classes.

4.15.3. The Random class

Some classes are very useful, but do not provide static properties. These require that you generate instances usually for security or multi-processing thread safety. Random gives you the ability to generate random numbers, very useful to simulate behavior in programs, as we will see throughout this text.

However, when you generate a random number, you change the state of the Random object; if you have methods that may run at the same time, you have to be careful that those methods do not attempt to update the same object at the same time. This is referred to as thread safety. C# contains syntax and operations to provide the ability to control object updates, however that is advanced C# programming. We will rely on the fact that our code runs in a single thread, so we can safely create a Random object instance and request numbers from it without being concerned about thread safety.

How do you create an instance of a class? You use the special new expression and invoke a special method on a class called a constructor. You will store this new object in a variable, like so:

Random rand = new Random();

Once you have a Random object instance, you have a variety of methods available to you:

Method

Description

Next()

Returns a non-negative random integer.

Next(i)

Returns a non-negative random integer that is less than the specified maximum integer i.

Next(low, high)

Returns a random integer that is within a specified range of low..high.

NextBytes(Byte[])

Fills the elements of a specified array of bytes with random numbers.

NextDouble()

Returns a random floating-point number that is greater than or equal to 0.0, and less than 1.0.

Sample()

Returns a random floating-point number between 0.0 and 1.0.

You would not create a new Random object for each random number you need — rather, you should create a Random object and reuse it as much as possible within your code.

How random is Random? According to Microsoft, "The chosen numbers are not completely random because a mathematical algorithm is used to select them, but they are sufficiently random for practical purposes." Microsoft supplies cryptography classes that are more random, but have slower performance. Read more about them here https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx

4.15.4. Enums

C# has a very rich type system; it contains not only a significant set of primitive types and object-oriented classes but also the ability to define structs — simple types that contain only fields; and enums — simple types that have a limited number of values. As they cannot be directly defined in Web Pages, we will save discussing them until we cover defining classes in C#.

4.16. Types of errors

Three kinds of errors can occur in a program: compile-time errors, run-time errors, and logic errors. It is useful to distinguish among them in order to track them down more quickly.

Compile-time errors occur when you violate the syntax rules of the C# language. For example, parentheses and braces have to come in matching pairs. So (1 + 2) is legal, but 8) is not. In the latter case, the program cannot be compiled, and the compiler displays an error.

Error messages from the compiler usually indicate where in the program the error occurred, and sometimes they can tell you exactly what the error is. As an example, let’s take a simple web page body named Hello.cshtml:

Listing 4. Hello.cshtml
@{
   var message = "Hello, World";
  }

<p>@message</p>

If you forget the semicolon at the end of the variable declaration, you might get an error message like this:

Hello.cshtml(7,33): error CS1002: ; expected

That’s pretty good: the location of the error is correct, and the error message tells you what’s wrong.

But error messages are not always easy to understand. Sometimes the compiler reports the place in the program where the error was detected, not where it actually occurred. And sometimes the description of the problem is more confusing than helpful.

For example, if you leave out the closing brace at the end of the Razor block, you may get an error like this:

Hello.cshtml(6): Build (web): The code block is missing a closing "}" character.  Make sure you have a matching "}" character for all the "{" characters within this block, and that none of the "}" characters are being interpreted as markup.

There are two problems here. First, the error message is written from the compiler’s point of view, not yours. Parsing is the process of reading a program before translating; if the compiler gets to the end of the file while still parsing, that means something was omitted. But the compiler doesn’t know what. It also doesn’t know where. The compiler discovers the error at the end of the program (line 6), but the missing brace should be 2 lines above that.

Error messages contain useful information, so you should make an effort to read and understand them. But don’t take them too literally.

During the first few weeks of your programming career, you will probably spend a lot of time tracking down compile-time errors. But as you gain experience, you will make fewer mistakes and find them more quickly.

The second type of error is a run-time error, so-called because it does not appear until after the program has started running. In C#, these errors occur while the interpreter is executing byte code and something goes wrong. These errors are also called “exceptions” because they usually indicate that something exceptional (and bad) has happened.

Run-time errors are rare in the simple programs you will see in the first few chapters, so it might be a while before you encounter one. When a run-time error occurs, the interpreter displays an error message that explains what happened and where.

For example, if you accidentally divide by zero you will get a message like this in Visual Studio:

An exception of type 'System.DivideByZeroException' occurred in App_Web_zst0xju3.dll but was not handled in user code

Additional information: Attempted to divide by zero.

Some parts of this output are useful for debugging. The first line includes the name of the exception, System.DivideByZeroException', and a message that indicates more specifically what happened, Attempted to divide by zero. If you look into the detail of the error (click View Detail…​), and then open the exception up, you will see the file where the error occurred in the Stack Trace:

   at ASP._Page_Hello_cshtml.Execute() in Hello.cshtml:line 13
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.WebPages.WebPage.ExecutePageHierarchy(IEnumerable`1 executors)
   at System.Web.WebPages.WebPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.WebPages.WebPageHttpHandler.ProcessRequestInternal(HttpContextBase httpContext)

It also reports the line number where the error occurred, 13. The other items listed in the stack trace show the internal handling of your web page by the web server, and are unlikely to have caused the issue.

Error messages sometimes contain additional information that won’t make sense yet. So one of the challenges is to figure out where to find the useful parts without being overwhelmed by extraneous information. Also, keep in mind that the line where the page crashed may not be the line that needs to be corrected.

The third type of error is the logic error. If your program has a logic error, it will compile and run without generating error messages, but it will not do the right thing. Instead, it will do exactly what you told it to do. For example, here is a version of the hello world program with a logic error:

@{ hours = 11;
   minutes = 30;
 }

<p>The portion of the hour taken up is @(minutes/60)</p>

This program compiles and runs just fine, but the output is:

<p>The portion of the hour taken up is 0</p>

Assuming that we wanted the value 0.5, this is not correct. The problem is that the math is integer division, when double precision was desired.

Identifying logic errors can be hard because you have to work backwards, looking at the output of the program, trying to figure out why it is doing the wrong thing, and how to make it do the right thing. Usually the compiler and the interpreter can’t help you, since they don’t know what the right thing is.

Remember to re-read Chapter 1, to review some of our favorite debugging advice. It refers to language features we haven’t talked about yet, so you might want to re-read it from time to time.

4.17. Data types in C#

type description range of values literal

byte

8-bit unsigned integer

0 - 255

whole number in range

sbyte

8-bit signed integer

-128 - 127

whole number in range

short

16-bit signed integer

-32,768 - 32,767

whole number in range

ushort

16-bit unsigned integer

0 - 65,535

whole number in range

int

32-bit signed integer

- 2,147,483,648 - 2,147,483,647

whole number i.e. 452

uint

32-bit unsigned integer

0 - 4,294,967,295

whole number in range

long

64-bit signed integer

-9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807

whole number with l sufficx, i.e. 452l

ulong

64-bit unsigned integer

0 .. 18,446,744,073,709,551,615

ul suffix

float

32-bit floating point (7 digits)

±1.5e−45 to ±3.4e38

decimal number with f suffix

double

64-bit floating point (15 digits)

±5.0e−324 to ±1.7e308

decimal number with optional d suffix

decimal

128-bit, 28 digits of precision

-79228162514264337593543950335 .. 79228162514264337593543950335

decimal number with m suffix

char

16-bit Unicode character

U+0000 - U+FFFF

single quotes around one character

string

sequence of Unicode characters

double quotes around 0 or more characters

bool

Boolean value

true or false

true or false

object

An object

new creates one; null (more on this later)

Implicit type conversion will occur when a loss of significant digits will not occur. For example, a byte will be implicitly converted to an int (exactly) and even to a double (though the exact value may be lost on the conversion) since the range of the double will fit the range of the byte.

From To

sbyte

short, int, long, float, double, or decimal

byte

short, ushort, int, uint, long, ulong, float, double, or decimal

short

int, long, float, double, or decimal

ushort

int, uint, long, ulong, float, double, or decimal

int

long, float, double, or decimal

uint

long, ulong, float, double, or decimal

long

float, double, or decimal

char

ushort, int, uint, long, ulong, float, double, or decimal

float

double

ulong

float, double, or decimal

  • Precision but not magnitude might be lost in the conversions from int, uint, long, or ulong to float and from long or ulong to double.

  • There are no implicit conversions to the char type. But note that char is treated as a numeric that can convert to many other types.

  • There are no implicit conversions between floating-point types and the decimal type. This is because decimal is an exact numeric but the floating-point types are approximate numeric types.

  • A constant expression of type int can be converted to sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant expression is within the range of the destination type.

  • There are no implicit conversions with boolean.

Explicit converstion can be done with the cast operator, like so:

double val = (double)42;

The type of the cast is put in parentheses in front of the expression being converted.

Notes on explicit conversions from Microsoft:

  • The explicit numeric conversion may cause loss of precision or result in throwing exceptions.

  • When you convert a decimal value to an integral type, this value is rounded towards zero to the nearest integral value. If the resulting integral value is outside therange of the destination type, an OverflowException is thrown.

  • When you convert from a double or float value to an integral type, the value is truncated. If the resulting integral value is outside the range of the destination value, the result depends on the overflow checking context. In a checked context, an OverflowException is thrown, while in an unchecked context, the result is an unspecified value of the destination type.

  • When you convert double to float, the double value is rounded to the nearest float value. If the double value is too small or too large to fit into the destination type, the result will be zero or infinity.

  • When you convert float or double to decimal, the source value is converted to decimal representation and rounded to the nearest number after the 28th decimal place if required. Depending on the value of the source value, one of the following results may occur:

    • If the source value is too small to be represented as a decimal, the result becomes zero.

    • If the source value is NaN (not a number), infinity, or too large to be represented as a decimal, an OverflowException is thrown.

  • When you convert decimal to float or double, the decimal value is rounded to the nearest double or float value.

There is another type of conversion, a user-defined conversion. An example of this are the .AsInt(), AsBoolean(), and other methods supplied on the string type which are used to convert the string to a value of the other type. The rules are defined in the method as to how the conversion is done.

4.18. Namespaces

Every class in C# is contained in something called a namespace. Classes that are not explicitly put into a namespace are in the "default" namespace. Almost all the examples in this textbook are in the default namespace; we will look at namespaces further when we look at classes and objects in a later chapter. However, the classes we use from ASP.NET will come from a variety of namespaces, so we will take a look at them now.

Namespaces are a way of grouping classes, identifying them as filling a common purpose and keeping them separate from classes with a different purpose. They use the dot notation we are already familiar with from accessing properties and methods. You can define a namespace as a top-level namespace or within another namespace. ASP.NET defines a top-level System namespace; the classes that we use from ASP.NET are actually in the System namespace, which is "always available" no matter what your current namespace is.

To use classes from other namespaces, you have to make them visible to your web page with a @using statement:

@using System.Collections;

This makes the classes in the namespace System.Collections visible. We will be using collections quite a bit when we look at databases in a later chapter.

Our Web Pages (.cshtml files) reside in the default namespace. We can do the same with our C# classes, or place them into namespaces to keep them apart and organize them in groups based on their use. C# classes will also include using statements to make classes in other namespaces visible to them.

Tip

There are two files in Visual Studio Web Sites that contain further information about namespaces: packages.config and web.config. These configuration files identify namespaces that are not automatically available, and make them available to your web pages. This is why, even though the Razor classes are defined in System.Web.WebPages, you do not need to put a @using System.Web.WebPages in each of your .cshtml files.

packages.config is managed for you by Visual Studio; VS will update it when you install a package using the NuGet package manager.

If you later find there is a namespace that you use often, you can add it to web.config to have it automatically available to all of your pages.

4.20. Exercises

  1. Find a partner and play “Stump the Newbie”:

    Start with a web page that compiles and displays correctly. One player looks away while the other player adds an error to the program. Then the first player tries to find and fix the error. You get two points if you find the error without compiling the program, one point if you find it using the compiler, and your opponent gets a point if you don’t find it.

  2. The point of this exercise is (1) to use string concatenation to display values with different types (int and string), and (2) to practice developing applications gradually by adding a few statements at a time.

    1. Create a new page named Date.cshtml. Copy or type in something like the hello world program and make sure you can compile and run it.

    2. Following the example in the text, write a program that creates variables named day, date, month, and year. The variable day will contain the day of the week (like Friday), and date will contain the day of the month (like the 13th). What type is each variable? Assign values to those variables that represent today’s date.

    3. Display the value of each variable on a line by itself. This is an intermediate step that is useful for checking that everything is working so far. Compile and run your page before moving on.

    4. Modify the program so that it displays the date in standard American format, for example: Thursday, July 16, 2015.

    5. Modify the program so it also displays the date in European format. The final output should be:

      American format: Thursday, July 16, 2015
      
      European format: Thursday 16 July 2015
  1. The point of this exercise is to (1) use some of the arithmetic operators, and (2) start thinking about compound entities (like time of day) that are represented with multiple values.

    1. Create a new page called Time.cshtml. From now on, we won’t remind you to start with a small, working program, but you should.

    2. Following the example program in this chapter, create variables named hour, minute, and second. Assign values that are roughly the current time. Use a 24-hour clock so that at 2pm the value of hour is 14.

    3. Make the program calculate and display the number of seconds since midnight.

    4. Calculate and display the number of seconds remaining in the day.

    5. Calculate and display the percentage of the day that has passed. You might run into problems when computing percentages with integers, so consider using floating-point.

    6. Change the values of hour, minute, and second to reflect the current time using DateTime.Now.Hour, DateTime.Now.Minute, and DateTime.Now.Second. Then write code to compute the elapsed time since you started working on this exercise. Hint: You might want to use additional variables to hold values during the computation. Variables that are used in a computation but never displayed are sometimes called “intermediate” or “temporary” variables.

  2. Write a Web Page that simulates rolling a pair of dice. You can simulate rolling one die by choosing one of the integers 1, 2, 3, 4, 5, or 6 at random. The number you pick represents the number on the die after it is rolled. As pointed out in this chapter, the expression rand.NextInt(6) + 1 does the computation to select a random integer between 1 and 6 if rand holds an instance of the class Random. You can assign this value to a variable to represent one of the dice that are being rolled. Do this twice and add the results together to get the total roll. The content of the <body> should all be generated in a Razor code block. Your Web Page should report the number showing on each die as well as the total roll. For example:

    The first die comes up 3
    The second die comes up 5
    Your total roll is 8
  3. Write a Web Page that asks the user’s name, and then takes them to a new page that greets the user by name. Before outputting the user’s name, convert it to upper case letters. For example, if the user’s name is Fred, then the program should respond "Hello, FRED, nice to meet you!". This should be two pages, with the form on the first page and the output on a separate page.

  4. Write a Web Page that helps the user count his change. The program should ask how many quarters, dimes, nickels, and pennies the user has. Then the program should tell the user how much money he has, expressed in dollars. Do this as a single page application, and show the values in the fields when you display the result. This will require putting a Razor code block before the form, and using an inline expression to output the answer after the form. HTML forms will display values using the value attribute on the form field elements.

  5. If you have N eggs, then you have N/12 dozen eggs, with N%12 eggs left over. (This is essentially the definition of the / and % operators for integers.) Write a Web Page that asks the user how many eggs she has and then tells the user how many dozen eggs she has and how many extra eggs are left over.

    A gross of eggs is equal to 144 eggs. Extend your Web Page so that it will tell the user how many gross, how many dozen, and how many left over eggs she has. For example, if the user says that she has 1342 eggs, then your program would respond with

    Your number of eggs is 9 gross, 3 dozen, and 10

    since 1342 is equal to 9*144 + 3*12 + 10.

    Implement this as a single page web application, and provide the user with an appropriate message if the input value is not an integer.

  6. This exercise asks you to write a Web Page that tests some of the built-in subroutines for working with strings. The program should ask the user to enter their first name and their last name, separated by a space, in one form field. Break the input string up into two strings, one containing the first name and one containing the last name. You can do that by using the IndexOf() subroutine to find the position of the space, and then using Substring() to extract each of the two names. Also output the number of characters in each name, and output the user’s initials. (The initials are the first letter of the first name together with the first letter of the last name.) A sample output with the input "Mary Smith" should look something like this:

    Your first name is Mary, which has 4 characters
    Your last name is Smith, which has 5 characters
    Your initials are MS

4.21. Project

One feature you may be using in your project is Geolocation, which is available in browsers as shown here http://www.w3schools.com/html/html5_geolocation.asp.

http://apress.jensimmons.com/v5/pro-html5-programming/ch5.html a very thorough overview of HTML5 geolocation with the distance formula shown below (which was found on stack overflow).

It’s pretty easy to find distance-between calculations in JavaScript, however you will need to do the computation on the server side as you work through a large (potentially) database of locations relative to the user’s current location. You don’t want to copy all the data to the client, so you will need to do it on the server.

Write a web page that takes the user’s current location in a form, and then computes (on the same page, like we did in the simple calculator in Chapter 3) the distance between the user’s location and a fixed location of your choosing. Put that fixed location into constants in your code, do not hard code the numbers within the computation.

Number.prototype.toRad = function() { return this * (Math.PI / 180); }

var R = 6371.0; // Earth's radius in kilometers
var Rm = 6378137.0; // meters
var Rft = Rm * 100.0/2.54/12.0; // feet
var Rmi = Rft/5280.0; // miles

var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();

var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // km results, use the other vars for their results

(why yes, your C# code will look quite similar…​)

http://www.movable-type.co.uk/scripts/latlong.html a bit too nerdy but interesting explanation

https://msdn.microsoft.com/en-us/library/system.math_methods(v=vs.110).aspx C#'s Math class contains the PI property and the methods needed. You will have to repeat the code to convert values to radians many times as we have not yet discussion functions, and there is no toRad function in ASP.NET. You will be able to make it a function after chapter 7, when methods are introduced.

5. C# Statements, Arrays, and Objects

This material is derived from Chapter 3 in Introduction to Programming Using Java

The basic building blocks of programs — variables, expressions, assignment statements, and subroutine call statements — were covered in the previous chapter. Starting with this chapter, we look at how these building blocks can be put together to build complex programs with more interesting behavior.

Since we are still working on the level of "programming in the small" in this chapter, we are interested in the kind of complexity that can occur within a small block of code. On this level, complexity is provided by control structures. The two types of control structures, loops and branches, can be used to repeat a sequence of statements over and over or to choose among two or more possible courses of action. C# includes several control structures of each type, and we will look at each of them in some detail.

Program complexity can be seen not just in control structures but also in data structures. A data structure is an organized collection of data, chunked together so that it can be treated as a unit. We will end this chapter with an introduction to one of the most common data structures: arrays.

5.1. Blocks, Loops, and Branches

The ability of a computer to perform complex tasks is built on just a few ways of combining simple commands into control structures. In Java, there are just six such structures that are used to determine the normal flow of control in a program — and, in fact, just three of them would be enough to write programs to perform any task. The six control structures are: the block, the while loop, the do..while loop, the for loop, the if statement, and the switch statement. Each of these structures is considered to be a single "statement," but a structured statement that can contain one or more other statements inside itself.

5.1.1. Blocks

The block is the simplest type of structured statement. Its purpose is simply to group a sequence of statements into a single statement. The format of a block is:

{
     statements
}

That is, it consists of a sequence of statements enclosed between a pair of braces, "{" and "}". In fact, it is possible for a block to contain no statements at all; such a block is called an empty block, and can actually be useful at times. An empty block consists of nothing but an empty pair of braces. Block statements usually occur inside other statements, where their purpose is to group together several statements into a unit. However, a block can be legally used wherever a statement can occur. There is one place where a block is required: As you might have already noticed in the case of the main subroutine of a program, the definition of a subroutine is a block, since it is a sequence of statements enclosed inside a pair of braces.

I should probably note again at this point that C# is what is called a free-format language. There are no syntax rules about how the language has to be arranged on a page. So, for example, you could write an entire block on one line if you want. But as a matter of good programming style, you should lay out your program on the page in a way that will make its structure as clear as possible. In general, this means putting one statement per line and using indentation to indicate statements that are contained inside control structures. This is the format that I will generally use in my examples.

Here are two examples of blocks:

{
   intro="The answer is ";
   message=intro+ans;
}

{  // This block exchanges the values of x and y
   int temp;      // A temporary variable for use in this block.
   temp = x;      // Save a copy of the value of x in temp.
   x = y;         // Copy the value of y into x.
   y = temp;      // Copy the value of temp into y.
}

In the second example, a variable, temp, is declared inside the block. This is perfectly legal, and it is good style to declare a variable inside a block if that variable is used nowhere else but inside the block. A variable declared inside a block is completely inaccessible and invisible from outside that block. When the computer executes the variable declaration statement, it allocates memory to hold the value of the variable. When the block ends, that memory is discarded (that is, made available for reuse). The variable is said to be local to the block. There is a general concept called the "scope" of an identifier. The scope of an identifier is the part of the program in which that identifier is valid. The scope of a variable defined inside a block is limited to that block, and more specifically to the part of the block that comes after the declaration of the variable.

Block activation records

Every time a block is entered, if it has local parameters, an activation record is created on the "activation stack", a portion of memory reserved for executing code. When the block completes, its activation record is destroyed and removed from the stack. This means that a local variable defined within a block does not keep its value with each subsequent trip to the same block - it is gone at the end of the block, and created again anew when the block is re-entered.

5.1.2. The Basic While Loop

The block statement by itself really doesn’t affect the flow of control in a program. The five remaining control structures do. They can be divided into two classes: loop statements and branching statements. You really just need one control structure from each category in order to have a completely general-purpose programming language. More than that is just convenience. In this section, I’ll introduce the while loop and the if statement. I’ll give the full details of these statements and of the other three control structures in later sections.

A while loop is used to repeat a given statement over and over. Of course, it’s not likely that you would want to keep repeating it forever. That would be an infinite loop, which is generally a bad thing. (There is an old story about computer pioneer Grace Murray Hopper, who read instructions on a bottle of shampoo telling her to "lather, rinse, repeat." As the story goes, she claims that she tried to follow the directions, but she ran out of shampoo. (In case you don’t get it, this is a joke about the way that computers mindlessly follow instructions.))

To be more specific, a while loop will repeat a statement over and over, but only so long as a specified condition remains true. A while loop has the form:

while (boolean-expression)
     statement

Since the statement can be, and usually is, a block, most while loops have the form:

while (boolean-expression) {
    statements
}

Some programmers think that the braces should always be included as a matter of style, even when there is only one statement between them, but I don’t always follow that advice myself.

Warning

C# in Razor requires the braces on the body of the while statement — even when it is a single statement. It also requires them on the body of an if statement and the other looping statements of the language.

The semantics of the while statement go like this: When the computer comes to a while statement, it evaluates the boolean-expression, which yields either true or false as its value. If the value is false, the computer skips over the rest of the while loop and proceeds to the next command in the program. If the value of the expression is true, the computer executes the statement or block of statements inside the loop. Then it returns to the beginning of the while loop and repeats the process. That is, it re-evaluates the boolean-expression, ends the loop if the value is false, and continues it if the value is true. This will continue over and over until the value of the expression is false when the computer evaluates it; if that never happens, then there will be an infinite loop.

Here is an example of a while loop that simply prints out the numbers 1, 2, 3, 4, 5:

string message = ""; // build up a message
int number;   // The number to be tracked.
number = 1;   // Start with 1.
while ( number < 6 ) {  // Keep going as long as number is < 6.
    message= message+" "+number;
    number = number + 1;  // Go on to the next number.
}
//value in message is "1 2 3 4 5".

The variable number is initialized with the value 1. So when the computer evaluates the expression "number < 6" for the first time, it is asking whether 1 is less than 6, which is true. The computer therefore proceeds to execute the two statements inside the loop. The first statement adds " 1" to message. The second statement adds 1 to number and stores the result back into the variable number; the value of number has been changed to 2. The computer has reached the end of the loop, so it returns to the beginning and asks again whether number is less than 6. Once again this is true, so the computer executes the loop again, this time adding " 2" to the message and then changing the value of number to 3. It continues in this way until eventually number becomes equal to 6. At that point, the expression "number < 6" evaluates to false. So, the computer jumps past the end of the loop to the next statement after the loop. Note that when the loop ends, the value of number is 6, but the last value that was put into message was 5.

By the way, you should remember that you’ll never see a while loop standing by itself in a real program. It will always be inside a web page or C# method which is itself defined inside some class. As an example of a while loop, here is a little program that computes the interest on an investment over several years.

Listing 5. InvestmentValue.cshtml
@{
      double principal;  // The value of the investment.
      double rate;       // The annual interest rate.
      string message="";

      /* Get the initial investment and interest rate from the user. */
      if (IsPost) {
        principal = (double) Request["principal"].AsDecimal(); (1)

        rate = (double) Request["rate"].AsDecimal();

        /* Simulate the investment for 5 years. */

        int years;  // Counts the number of years that have passed.

        years = 0;
        while (years < 5) {
           double interest;  // Interest for this year.
           interest = principal * rate;
           principal = principal + interest;     // Add it to principal.
           years = years + 1;    // Count the current year.
           message = "The value of the investment after "+years
               + " years is $" + String.Format("{0:0.00}",principal); (2)
        } // end of while loop

      }
}

<!DOCTYPE html>
<html>
  <head>
    <title>Add Numbers</title>

    <style type="text/css">
      body {background-color: beige; font-family: Verdana, Arial;
            margin: 50px; }
      form {padding: 10px; border-style: solid; width: 250px;}
    </style>
  </head>

  <body>
  <p>Enter two numbers and then click <strong>Calculate</strong>.</p>
  <form action="" method="post">
    <p><label for="principal">Initial investment:</label>
       <input type="text" name="principal" />
    </p>
    <p><label for="rate">Interest rate (decimal, not percentage):</label>
      <input type="text" name="rate" />
    </p>
    <p><input type="submit" value="Calculate" /></p>
  </form>

  <p>@message</p>
  </body>
</html>

You should study this program, and make sure that you understand what the computer does step-by-step as it executes the while loop.

  1. Note the use of .AsDecimal() and the typecast to (double) — this is required because there is no .AsDouble() method available on strings. We could choose, instead, to keep all of our numbers as decimals and avoid the typecast.

  2. The raw double value gives all the digits, but since we are dealing with money we want to display it in a shorter form showing just the money-relevant digits. There is a system String object (which is also a class — more on this later in this text) that provides a Format method for creating the string representation of the double value. Format’s input is quite rich, this is just a first example. See https://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx for details on using this.

Tip

Go ahead and modify our page to use just decimals and avoid the typecast to double. This may take some debugging — more than just principal and rate need to be changed. Consider why all of the changes were necessary.

Tip

Modify the page so that the value is displayed in the form after the POST request, so that the user can see their values when the results are displayed. Put the numbers in the form fields directly. Consider why you can do this — and in future pages, consider revisitng this and how the code on the page has to change to make it work.

5.1.3. The Basic If Statement

An if statement tells the computer to take one of two alternative courses of action, depending on whether the value of a given boolean-valued expression is true or false. It is an example of a "branching" or "decision" statement. An if statement has the form:

if ( boolean-expression )
    statement1
else
    statement2
Caution

Remember, Razor will require that the statements in the if and else always have braces, even if there is just a single statement within it.

When the computer executes an if statement, it evaluates the boolean expression. If the value is true, the computer executes the first statement and skips the statement that follows the "else". If the value of the expression is false, then the computer skips the first statement and executes the second one. Note that in any case, one and only one of the two statements inside the if statement is executed. The two statements represent alternative courses of action; the computer decides between these courses of action based on the value of the boolean expression.

In many cases, you want the computer to choose between doing something and not doing it. You can do this with an if statement that omits the else part:

if ( boolean-expression )
    statement

To execute this statement, the computer evaluates the expression. If the value is true, the computer executes the statement that is contained inside the if statement; if the value is false, the computer skips over that statement. In either case, the computer then continues with whatever follows the if statement in the program.

Sometimes, novice programmers confuse while statements with simple if statements (with no else part), although their meanings are quite different. The statement in an if is executed at most once, while the statement in a while can be executed any number of times. It can be helpful to look at diagrams of the the flow of control for while and simple if statements:

Control flow diagrams for while and simple if

In these diagrams, the arrows represent the flow of time as the statement is executed. Control enters the diagram at the top and leaves at the bottom. Similarly, a flow control diagram for an if..else statement makes it clear that exactly one of the two nested statements is executed:

Control flow diagram for if..else statement

Of course, either or both of the statements in an if statement can be a block, and again many programmers prefer to add the braces even when they contain just a single statement. So an if statement often looks like:

if ( boolean-expression ) {
    statements
}
else {
    statements
}

or:

if ( boolean-expression ) {
    statements
}

As an example, here is an if statement that exchanges the value of two variables, x and y, but only if x is greater than y to begin with. After this if statement has been executed, we can be sure that the value of x is definitely less than or equal to the value of y:

if ( x > y ) {
    int temp;      // A temporary variable for use in this block.
    temp = x;      // Save a copy of the value of x in temp.
    x = y;         // Copy the value of y into x.
    y = temp;      // Copy the value of temp into y.
}

Finally, here is an example of an if statement that includes an else part. See if you can figure out what it does, and why it would be used:

if ( years > 1 ) {  // handle case for 2 or more years
    message="The value of the investment after "
     + years + " years is $";
}
else {  // handle case for 1 year
    message="The value of the investment after 1 year is $";
}  // end of if statement
message += principal;  // this is done in any case

I’ll have more to say about control structures later in this chapter. But you already know the essentials. If you never learned anything more about control structures, you would already know enough to perform any possible computing task. Simple looping and branching are all you really need!

5.1.4. Definite Assignment

I will finish this introduction to control structures with a somewhat technical issue that you might not fully understand the first time you encounter it. Consider the following two code segments, which seem to be entirely equivalent:

int y;                          int y;
if (x < 0) {                    if (x < 0) {
    y = 1;                           y = 1;
}                               }
else {                          if (x >= 0) {
    y = 2;                           y = 2;
}                               }
message = "answer is "+y;       message = "answer is "+y;

In the version on the left, y is assigned the value 1 if x < 0 and is assigned the value 2 otherwise, that is, if x >= 0. Exactly the same is true of the version on the right. However, there is a subtle difference. In fact, the Java compiler will report an error for the final statement in the code on the right, while the code on the left is perfectly fine!

The problem is that in the code on the right, the computer can’t tell that the variable y has definitely been assigned a value. When an if statement has no else part, the statement inside the if might or might not be executed, depending on the value of the condition. The compiler can’t tell whether it will be executed or not, since the condition will only be evaluated when the program is running. For the code on the right above, as far as the compiler is concerned, it is possible that neither statement, y = 1 or y = 2, will be evaluated, so it is possible that the output statement is trying to print an undefined value. The compiler considers this to be an error. The value of a variable can only be used if the compiler can verify that the variable will have been assigned a value at that point when the program is running. This is called definite assignment. (It doesn’t matter that you can tell that y will always be assigned a value in this example. The question is whether the compiler can tell.)

Note that in the code on the left above, y is definitely assigned a value, since in an if..else statement, one of the two alternatives will be executed no matter what the value of the condition in the if. It is important that you understand that there is a difference between an if..else statement and a pair of plain if statements. Here is another pair of code segments that might seem to do the same thing, but don’t. What’s the value of x after each code segment is executed?

int x;                             int x;
x = -1;                            x = -1;
if (x < 0)                         if (x < 0)
    x = 1;                             x = 1;
else                               if (x >= 0)
    x = 2;                             x = 2;

After the code on the left is executed, x is 1; after the code on the right, x is 2.


5.2. Algorithm Development

Programming is difficult (like many activities that are useful and worthwhile — and like most of those activities, it can also be rewarding and a lot of fun). When you write code, you have to tell the computer every small detail of what to do. And you have to get everything exactly right, since the computer will blindly follow your code exactly as written. How, then, do people write any but the most simple programs? It’s not a big mystery, actually. It’s a matter of learning to think in the right way.

A program is an expression of an idea. A programmer starts with a general idea of a task for the computer to perform. Presumably, the programmer has some idea of how to perform the task by hand, at least in general outline. The problem is to flesh out that outline into a complete, unambiguous, step-by-step procedure for carrying out the task. Such a procedure is called an "algorithm." (Technically, an algorithm is an unambiguous, step-by-step procedure that always terminates after a finite number of steps. We don’t want to count procedures that might go on forever.) An algorithm is not the same as a program. A program is written in some particular programming language. An algorithm is more like the idea behind the program, but it’s the idea of the steps the program will take to perform its task, not just the idea of the task itself. When describing an algorithm, the steps don’t necessarily have to be specified in complete detail, as long as the steps are unambiguous and it’s clear that carrying out the steps will accomplish the assigned task. An algorithm can be expressed in any language, including English. Of course, an algorithm can only be expressed as an actual program if all the details have been filled in.

So, where do algorithms come from? Usually, they have to be developed, often with a lot of thought and hard work. Skill at algorithm development is something that comes with practice, but there are techniques and guidelines that can help. I’ll talk here about some techniques and guidelines that are relevant to "programming in the small," and I will return to the subject several times in later chapters.

5.2.1. Pseudocode and Stepwise Refinement

When programming in the small, you have a few basics to work with: variables, assignment statements, and input/output. You might also have some routines, objects, or other building blocks that have already been written by you or someone else. (ASP.NET libraries and their routines fall into this class.) You can build sequences of these basic instructions, and you can also combine them into more complex control structures such as while loops and if statements.

Suppose you have a task in mind that you want the computer to perform. One way to proceed is to write a description of the task, and take that description as an outline of the algorithm you want to develop. Then you can refine and elaborate that description, gradually adding steps and detail, until you have a complete algorithm that can be translated directly into programming language. This method is called stepwise refinement, and it is a type of top-down design. As you proceed through the stages of stepwise refinement, you can write out descriptions of your algorithm in pseudocode — informal instructions that imitate the structure of programming languages without the complete detail and perfect syntax of actual program code.

Tip

The informal description is not written in a programming language, but is expressed in pseudocode, which can be a mix of simple English statements and some programming terminology as you will see in our examples here. There is no 'standard' pseudocode language — simply write out the text in a way that is understandable to you and should be understandable to a peer as well.

As an example, let’s see how one might develop the application from the previous section, which computes the value of an investment over five years. The task that you want the application to perform is: "Compute and display the value of an investment for each of the next five years, where the initial investment and interest rate are to be specified by the user." You might then write — or more likely just think — that this can be expanded as:

Get the user's input
Compute the value of the investment after 1 year
Display the value
Compute the value after 2 years
Display the value
Compute the value after 3 years
Display the value
Compute the value after 4 years
Display the value
Compute the value after 5 years
Display the value

This is correct, but rather repetitive. And seeing that repetition, you might notice an opportunity to use a loop. A loop would take less typing. More important, it would be more general: Essentially the same loop will work no matter how many years you want to process. So, you might rewrite the above sequence of steps as:

Get the user's input
while there are more years to process:
    Compute the value after the next year
    Display the value

Following this algorithm would certainly solve the problem, but for a computer we’ll have to be more explicit about how to "Get the user’s input," how to "Compute the value after the next year," and what it means to say "there are more years to process." We can expand the step, "Get the user’s input" into

Ask the user for the initial investment
Read the user's response
Ask the user for the interest rate
Read the user's response
Tip

Remember, we are working with a web page, so we "ask" with a form and "read response" with the POST request using the Response object available to us there.

To fill in the details of the step "Compute the value after the next year," you have to know how to do the computation yourself. (Maybe you need to ask your boss or professor for clarification?) Let’s say you know that the value is computed by adding some interest to the previous value. Then we can refine the while loop to:

while there are more years to process:
    Compute the interest
    Add the interest to the value
    Display the value

As for testing whether there are more years to process, the only way that we can do that is by counting the years ourselves. This displays a very common pattern, and you should expect to use something similar in a lot of programs: We have to start with zero years, add one each time we process a year, and stop when we reach the desired number of years. This is sometimes called a counting loop. So the while loop becomes:

years = 0
while years < 5:
    years = years + 1
    Compute the interest
    Add the interest to the value
    Display the value

We still have to know how to compute the interest. Let’s say that the interest is to be computed by multiplying the interest rate by the current value of the investment. Putting this together with the part of the algorithm that gets the user’s inputs, we have the complete algorithm:

Ask the user for the initial investment (1)
Read the user's response (2)
Ask the user for the interest rate (1)
Read the user's response (2)
years = 0
while years < 5: (3)
    years = years + 1
    Compute interest = value * interest rate
    Add the interest to the value
    Display the value (4)

The numbers above correspond the the number markers in the finished code below.

Finally, we are at the point where we can translate pretty directly into proper programming-language syntax. We still have to choose names for the variables, decide exactly what we want to say to the user, and so forth. Having done this, we could express our algorithm in C# as:

Listing 6. InvestmentValue2.cshtml
<!DOCTYPE html>
<html>
  <head>
    <title>Compute Investment Value</title>

    <style type="text/css">
      body {background-color: beige; font-family: Verdana, Arial;
            margin: 50px; }
      form {padding: 10px; border-style: solid; width: 250px;}
    </style>
  </head>

  <body>
  <p>Enter two numbers and then click <strong>Calculate</strong>.</p>
  <form action="" method="post"> (1)
    <p><label for="principal">Initial investment:</label>
       <input type="text" name="principal" />
    </p>
    <p><label for="rate">Interest rate (decimal, not percentage):</label>
      <input type="text" name="rate" />
    </p>
    <p><input type="submit" value="Calculate" /></p>
  </form>

  @{
      double principal;  // The value of the investment.
      double rate;       // The annual interest rate.
      string message="";

      /* Get the initial investment and interest rate from the user. */
      if (IsPost) {
        principal = Request["principal"].AsDouble(); (2)

        rate = Request["rate"].AsDouble();

        /* Simulate the investment for 5 years. */

        int years;  // Counts the number of years that have passed.

        years = 0;
        while (years < 5) { (3)
           double interest;  // Interest for this year.
           interest = principal * rate;
           principal = principal + interest;     // Add it to principal.
           years = years + 1;    // Count the current year.
           <p>@years : @principal</p> (4)
        } // end of while loop

      }
  }
  </body>
</html>

This still needs to be wrapped inside a complete website, it still needs to be commented, and it really needs to print out more information in a nicer format for the user. But it’s essentially the same application as the one in the previous section. (Note that the pseudocode algorithm used indentation to show which statements are inside the loop. In C#, indentation is completely ignored by the computer, so you need a pair of braces to tell the computer which statements are in the loop. If you leave out the braces, the only statement inside the loop would be "double interest;". The other statements would only be executed once, after the loop ends. The nasty thing is that the computer won’t notice this error for you, like it would if you left out the parentheses around "(years < 5)". The parentheses are required by the syntax of the while statement. The braces are only required semantically. The computer can recognize syntax errors but not semantic errors.)

One thing you should have noticed here is that my original specification of the problem — "Compute and display the value of an investment for each of the next five years" — was far from being complete. Before you start writing a program, you should make sure you have a complete specification of exactly what the application is supposed to do. In particular, you need to know what information the application is going to input and output and what computation it is going to perform. Here is what a reasonably complete specification of the problem might look like in this example:

"Write an application that will compute and display the value of an investment for each of the next five years. Each year, interest is added to the value. The interest is computed by multiplying the current value by a fixed interest rate. Assume that the initial value and the rate of interest are to be input by the user when the program is run."

5.2.2. The 3N+1 Problem

Let’s do another example, working this time with a program that you haven’t already seen. The assignment here is an abstract mathematical problem that is one of my favorite programming exercises. This time, we’ll start with a more complete specification of the task to be performed:

"Given a positive integer, N, define the '3N+1' sequence starting from N as follows: If N is an even number, then divide N by two; but if N is odd, then multiply N by 3 and add 1. Continue to generate numbers in this way until N becomes equal to 1. For example, starting from N = 3, which is odd, we multiply by 3 and add 1, giving N = 3*3+1 = 10. Then, since N is even, we divide by 2, giving N = 10/2 = 5. We continue in this way, stopping when we reach 1. The complete sequence is: 3, 10, 5, 16, 8, 4, 2, 1.

"Write a program that will read a positive integer from the user and will print out the 3N+1 sequence starting from that integer. The program should also count and print out the number of terms in the sequence."

A general outline of the algorithm for the program we want is:

   Get a positive integer N from the user.
   Compute, print, and count each number in the sequence.
   Output the number of terms.

The bulk of the program is in the second step. We’ll need a loop, since we want to keep computing numbers until we get 1. To put this in terms appropriate for a while loop, we need to know when to continue the loop rather than when to stop it: We want to continue as long as the number is not 1. So, we can expand our pseudocode algorithm to:

Get a positive integer N from the user;
while N is not 1:
    Compute N = next term;
    Output N;
    Count this term;
Output the number of terms;

In order to compute the next term, the computer must take different actions depending on whether N is even or odd. We need an if statement to decide between the two cases:

Get a positive integer N from the user;
while N is not 1:
    if N is even:
       Compute N = N/2;
    else
       Compute N = 3 * N + 1;
    Output N;
    Count this term;
Output the number of terms;

We are almost there. The one problem that remains is counting. Counting means that you start with zero, and every time you have something to count, you add one. We need a variable to do the counting. The variable must be set to zero once, before the loop starts, and it must be incremented within the loop. (Again, this is a common pattern that you should expect to see over and over.) With the counter added, we get:

Get a positive integer N from the user;
Let counter = 0;
while N is not 1:
    if N is even:
       Compute N = N/2;
    else
       Compute N = 3 * N + 1;
    Output N;
    Add 1 to counter;
Output the counter;

We still have to worry about the very first step. How can we get a positive integer from the user? If we just read in a number, it’s possible that the user might type in a negative number or zero. If you follow what happens when the value of N is negative or zero, you’ll see that the program will go on forever, since the value of N will never become equal to 1. This is bad. In this case, the problem is probably no big deal, but in general you should try to write programs that are foolproof. One way to fix this is to keep reading in numbers until the user types in a positive number:

Ask user to input a positive number;
Let N be the user's response;
while N is not positive:
   Print an error message;
   Read another value for N;
Let counter = 0;
while N is not 1:
    if N is even:
       Compute N = N/2;
    else
       Compute N = 3 * N + 1;
    Output N;
    Add 1 to counter;
Output the counter;

Getting input on a web page can be checked on the client-side in JavaScript to avoid sending the value to the server until it is valid. However, the value would still need to be checked on the server in case a user turned off JavaScript. So we need to think about how that works:

  1. Give the user a form to fill out

  2. Accept the submitted form

  3. Check the values

  4. If the values are not valid, return to step 1

In pseudocode, we can express this as a while, however in actual code we will be re-displaying the form and requesting valid data without using an explicit loop; the web page does it for us.

So, the first loop will end only when N is a positive number, as required. (A common beginning programmer’s error is to use an if statement instead of a while statement here: "If N is not positive, ask the user to input another value." The problem arises if the second number input by the user is also non-positive. The if statement is only executed once, so the second input number is never tested, and the program proceeds into an infinite loop. With the loop, after the second number is input, the computer jumps back to the beginning of the loop and tests whether the second number is positive. If not, it asks the user for a third number, and it will continue asking for numbers until the user enters an acceptable input. After the input loop ends, we can be absolutely sure that N is a positive number.)

Here is the C# implementing this algorithm. It uses the operators <= to mean "is less than or equal to" and != to mean "is not equal to." To test whether N is even, it uses "N % 2 == 0". All the operators used here were discussed in the previous chapter.

Listing 7. ThreeNPlusOne.cshtml
<!DOCTYPE html>
<html>
  <head>
    <title>3N+1 sequence</title>

    <style type="text/css">
      body {background-color: beige; font-family: Verdana, Arial;
            margin: 50px; }
      form {padding: 10px; border-style: solid; width: 250px;}
    </style>
  </head>

  <body>
  <p>Enter a numbers and then click <strong>Show</strong>.</p>
  <form action="" method="post">
    <p><label for="principal">Number:</label>
       <input type="text" name="num" />
    </p>
    <p><input type="submit" value="Show" /></p>
  </form>

  @{
      int num;  // The value of the investment.

      /* Get the initial number from the user. */
      if (IsPost) {
        num = Request["num"].AsInt();

        if (num <= 0) { (1)
          <p>Number must be &gt; 0, try again.</p>
        } else {
         // At this point, we know that N > 0

         /**
          * This  prints out a 3N+1 sequence starting from a positive
          * integer specified by the user.  It also counts the number of
          * terms in the sequence, and prints out that number.
          */

          int counter = 0;
          while (num != 1) { (2)
             if (num % 2 == 0) {
                num = num / 2;
             }
             else {
                num = 3 * num + 1;
             }
             <p>@num</p>
             counter = counter + 1;
          }

          <p>There were @counter terms in the sequence.</p>
        } // end num > 0

      } // end IsPost
  }
  </body>
</html>
  1. As you can see, this is written as a simple if statement; however it leaves us on the web page, so the form is available and the user can re-enter data and try again. Notice that web pages give users another, unspoken, option as well: they can choose not to continue and move on to another page. This is actually quite powerful; in a stand-alone application, you would have to explicitly give users a way to quit the program at any input step.

  2. The second loop remains a loop — it is generating output as it executes.

Two final notes on this program: First, you might have noticed that the first term of the sequence — the value of N input by the user — is not printed or counted by this program. Is this an error? It’s hard to say. Was the specification of the program careful enough to decide? This is the type of thing that might send you back to the boss/professor for clarification. The problem (if it is one!) can be fixed easily enough. Just add the following lines after int counter = 0; and before the while loop:

<p>@num</p> @* print out initial term *@
counter = 1;       // and count it

Second, there is the question of why this problem might be interesting. Well, it’s interesting to mathematicians and computer scientists because of a simple question about the problem that they haven’t been able to answer: Will the process of computing the 3N+1 sequence finish after a finite number of steps for all possible starting values of N? Although individual sequences are easy to compute, no one has been able to answer the general question. To put this another way, no one knows whether the process of computing 3N+1 sequences can properly be called an algorithm, since an algorithm is required to terminate after a finite number of steps! (Note: This discussion really applies to integers, not to values of type int! That is, it assumes that the value of N can take on arbitrarily large integer values, which is not true for a variable of type int in a C# program. When the value of N in the program becomes too large to be represented as a 32-bit int, the values output by the program are no longer mathematically correct. So the program does not compute the correct 3N+1 sequence if N becomes too large.

5.2.3. Coding, Testing, Debugging

It would be nice if, having developed an algorithm for your program, you could relax, press a button, and get a perfectly working program. Unfortunately, the process of turning an algorithm into Java source code doesn’t always go smoothly. And when you do get to the stage of a working program, it’s often only working in the sense that it does something. Unfortunately not what you want it to do.

After program design comes coding: translating the design into a program written in C# or some other language. Usually, no matter how careful you are, a few syntax errors will creep in from somewhere, and the C# compiler will reject your program with some kind of error message. Unfortunately, while a compiler will always detect syntax errors, it’s not very good about telling you exactly what’s wrong. Sometimes, it’s not even good about telling you where the real error is. A spelling error or missing "{" on line 45 might cause the compiler to choke on line 105. You can avoid lots of errors by making sure that you really understand the syntax rules of the language and by following some basic programming guidelines. For example, I never type a "{" without typing the matching "}". Then I go back and fill in the statements between the braces. A missing or extra brace can be one of the hardest errors to find in a large program. Always, always indent your program nicely. If you change the program, change the indentation to match. It’s worth the trouble. Use a consistent naming scheme, so you don’t have to struggle to remember whether you called that variable interestrate or interestRate. In general, when the compiler gives multiple error messages, don’t try to fix the second error message from the compiler until you’ve fixed the first one. Once the compiler hits an error in your program, it can get confused, and the rest of the error messages might just be guesses. Maybe the best advice is: Take the time to understand the error before you try to fix it. Programming is not an experimental science.

When your code compiles without error, you are still not done. You have to test the code to make sure it works correctly. Remember that the goal is not to get the right output for the two sample inputs that the professor gave in class. The goal is code that will work correctly for all reasonable inputs. Ideally, when faced with an unreasonable input, it should respond by gently chiding the user rather than by crashing. Test your program on a wide variety of inputs. Try to find a set of inputs that will test the full range of functionality that you’ve coded into your program. As you begin writing larger programs, write them in stages and test each stage along the way. You might even have to write some extra code to do the testing — for example to call a routine that you’ve just written. You don’t want to be faced, if you can avoid it, with 500 newly written lines of code that have an error in there somewhere.

Caution

What is a reasonable input? Any value that the user could reasonably type in or provide as input. On an HTML form, for example, any key (any key) on the keyboard that produces a character can be used to put a value into a form field: they are strings. So when you need a number, you need to consider how your program will behave when the user types in "balloon" instead of "5".

Go ahead and see how your web page behaves with input like this; ask yourself if it is reasonable, or if further checks and meaningful.

The point of testing is to find bugs — semantic errors that show up as incorrect behavior rather than as compilation errors. And the sad fact is that you will probably find them. Again, you can minimize bugs by careful design and careful coding, but no one has found a way to avoid them altogether. Once you’ve detected a bug, it’s time for debugging. You have to track down the cause of the bug in the program’s source code and eliminate it. Debugging is a skill that, like other aspects of programming, requires practice to master. So don’t be afraid of bugs. Learn from them. One essential debugging skill is the ability to read source code — the ability to put aside preconceptions about what you think it does and to follow it the way the computer does — mechanically, step-by-step — to see what it really does. This is hard. I can still remember the time I spent hours looking for a bug only to find that a line of code that I had looked at ten times had a "1" where it should have had an "i", or the time when I wrote a subroutine named WindowClosing which would have done exactly what I wanted except that the computer was looking for windowClosing (with a lower case "w"). Sometimes it can help to have someone who doesn’t share your preconceptions look at your code.

Often, it’s a problem just to find the part of the program that contains the error. Most programming environments come with a debugger, which is a program that can help you find bugs. Typically, your program can be run under the control of the debugger. The debugger allows you to set "breakpoints" in your program. A breakpoint is a point in the program where the debugger will pause the program so you can look at the values of the program’s variables. The idea is to track down exactly when things start to go wrong during the program’s execution. The debugger will also let you execute your program one line at a time, so that you can watch what happens in detail once you know the general area in the program where the bug is lurking.

I will confess that I only occasionally use debuggers myself. A more traditional approach to debugging is to insert debugging statements into your program. These are output statements that print out information about the state of the program. Typically, a debugging statement would say something like

<p>At start of while loop, num = @num</p>

You need to be able to tell from the output where in your program the output is coming from, and you want to know the value of important variables. Sometimes, you will find that the computer isn’t even getting to a part of the program that you think it should be executing. Remember that the goal is to find the first point in the program where the state is not what you expect it to be. That’s where the bug is.

And finally, remember the golden rule of debugging: If you are absolutely sure that everything in your program is right, and if it still doesn’t work, then one of the things that you are absolutely sure of is wrong.


5.3. The while and do..while Statements

<big>S</big>tatements in Java can be either simple statements or compound statements. Simple statements, such as assignment statements and subroutine call statements, are the basic building blocks of a program. Compound statements, such as while loops and if statements, are used to organize simple statements into complex structures, which are called control structures because they control the order in which the statements are executed. The next five sections explore the details of control structures that are available in Java, starting with the while statement and the do..while statement in this section. At the same time, we’ll look at examples of programming with each control structure and apply the techniques for designing algorithms that were introduced in the previous section.

5.4. The while statement

The while statement was already introduced earlier in this chapter. A while loop has the form

while ( boolean-expression )
   statement

The statement can, of course, be a block statement consisting of several statements grouped together between a pair of braces. This statement is called the body of the loop. The body of the loop is repeated as long as the boolean-expression is true. This boolean expression is called the continuation condition, or more simply the test, of the loop. There are a few points that might need some clarification. What happens if the condition is false in the first place, before the body of the loop is executed even once? In that case, the body of the loop is never executed at all. The body of a while loop can be executed any number of times, including zero. What happens if the condition is true, but it becomes false somewhere in the middle of the loop body? Does the loop end as soon as this happens? It doesn’t, because the computer continues executing the body of the loop until it gets to the end. Only then does it jump back to the beginning of the loop and test the condition, and only then can the loop end.

this section from Think Java Chapter 7 Let’s look at a typical use of while loops in web pages: generating a table. Our problem will be to display a number of bits and the maximum value it can be used to store as an unsigned binary value. For example, with 2 bits, we can represent 0, 1, 2, 3, and 4. For a given value x, the maximum binary value we can store in x bits is 2x. We want to display this value for all x from 1 to 16.

Here is a pseudocode algorithm for the program:

Let start = 1   // our first value
start the table
while start <= 16
    compute 2^start
    display a table row
end the table

Notice we have a terminal value, 16. This is a "magic value". Good programming practice is to put such magic values in constants so that the constant name documents the purpose of the value. We will keep this in mind when we write the actual code.

Notice the <= there as well — if you checked only <, the loop would stop one step before you wanted to. Such so-called off-by-one errors are very common. Counting turns out to be harder than it looks!)

It is quite typical to just use a < comparison on loops like this, which means the terminal test needs to compare the value to 17, not 16, in our example. So be careful to check both your terminal test value and operator if you have an off-by-one error.

We can easily turn the algorithm into a complete program. Note that the code is going to integrate HTML with Razor, since the table is an HTML construct.

Here is the full source code for the program:

Listing 8. BitMax.cshtml
<!DOCTYPE html>
<html>
  <head>
    <title>BitMax</title>
  </head>

  <body>
    <table>
    <tr><th># Bits</th><th>Maximum Value</th></tr>
    @{
       /*
        * print out the values 1-16 and the maximum binary value storable in the
        * corresponding number of bits.
        */
        int numBits = 1;
        const int maxBits = 16;

        while (numBits <= maxBits) {

            <tr><td>@numBits</td><td>@Math.Pow(2,numBits)</td></tr> (1)

             numBits++; (2)
        }
    }
    </table>
  </body>
</html>
  1. Notice that we use the system Math object to compute the exponent value 2numBits. Also be careful: there is no @ before the numbits argument, because we are already in an inline expression.

  2. numBits increments the value in numBits. This is considered better form than writing out the expression ``numBits = numbits + 1;`` -- you are more likely to see ``numBits`` in code, and probably already have if you are using StackOverflow.

Tip

Your turn: modify this page to take the terminal value from the user rather than as a hard-coded constant. What will you need to check to ensure the page works correctly?

Consider what you would need to check if the user is inputting both start and stop values. What happens if start is more than stop?

Your while loop would still look like this:

        while (numBits <= maxBits) {

            <tr><td>@numBits</td><td>@Math.Pow(2,numBits)</td></tr>

             numBits++;
        }

But incrementing numBits would never bring it closer to maxBits. Rather, it would move it further away. This is called an infinite loop. In Razor, your web page would never display, because the Razor engine would keep generating the output HTML until the server’s resources were exhausted.

Whenever you are getting values from the user, consider not only what they may input, but also how the values need to relate to one another and to other values in your code.

5.4.1. The do..while Statement

Sometimes it is more convenient to test the continuation condition at the end of a loop, instead of at the beginning, as is done in the while loop. The do..while statement is very similar to the while statement, except that the word "while," along with the condition that it tests, has been moved to the end. The word "do" is added to mark the beginning of the loop. A do..while statement has the form

do
    statement
while ( boolean-expression );

or, since, as usual, the statement can be a block,

do {
    statements
} while ( boolean-expression );

Note the semicolon, ';', at the very end. This semicolon is part of the statement, just as the semicolon at the end of an assignment statement or declaration is part of the statement. Omitting it is a syntax error. (More generally, every statement in C# ends either with a semicolon or a right brace, '}'.)

To execute a do loop, the computer first executes the body of the loop — that is, the statement or statements inside the loop — and then it evaluates the boolean expression. If the value of the expression is true, the computer returns to the beginning of the do loop and repeats the process; if the value is false, it ends the loop and continues with the next part of the program. Since the condition is not tested until the end of the loop, the body of a do loop is always executed at least once.

For example, consider our previous while loop. The do loop makes sense here instead of a while loop because with the do loop, you know there will be at least one time through the loop.

do {
    <tr><td>@numBits</td><td>@Math.Pow(2,numBits)</td></tr>
    numBits++;
} while ( numBits <= maxBits );

This is safe in our example because we know that numBits will always be less than maxBits at the start. If you have user input, that may not be the case.

Although a do..while statement is sometimes more convenient than a while statement, having two kinds of loops does not make the language more powerful. Any problem that can be solved using do..while loops can also be solved using only while statements, and vice versa. In fact, if doSomething represents any block of program code, then

do {
    doSomething
} while ( boolean-expression );

has exactly the same effect as

doSomething
while ( boolean-expression ) {
    doSomething
}

Similarly,

while ( boolean-expression ) {
    doSomething
}

can be replaced by

if ( boolean-expression ) {
   do {
       doSomething
   } while ( boolean-expression );
}

without changing the meaning of the program in any way.

5.4.2. break and continue

The syntax of the while and do..while loops allows you to test the continuation condition at either the beginning of a loop or at the end. Sometimes, it is more natural to have the test in the middle of the loop, or to have several tests at different places in the same loop. C# provides a general method for breaking out of the middle of any loop. It’s called the break statement, which takes the form

break;

When the computer executes a break statement in a loop (or, as we will see later, a switch statement also), it will immediately jump out of the loop or switch. It then continues on to whatever follows the loop in the program. Consider this version of our previous while loop for example:

while (true) {  // looks like it will run forever!

  <tr><td>@numBits</td><td>@Math.Pow(2,numBits)</td></tr>

  numBits++;

  if (numBits > maxBits) {   // time to go
    break;
  }

}
// continue here after break

The test to exit the loop is no longer in the while expression, but instead is embedded in the loop.

The first line of this loop, "while (true)" might look a bit strange, but it’s perfectly legitimate. The condition in a while loop can be any boolean-valued expression. The computer evaluates this expression and checks whether the value is true or false. The boolean literal "true" is just a boolean expression that always evaluates to true. So "while (true)" can be used to write an infinite loop, or one that will be terminated by a break statement.

A break statement terminates the loop that immediately encloses the break statement. It is possible to have nested loops, where one loop statement is contained inside another. If you use a break statement inside a nested loop, it will only break out of that loop, not out of the loop that contains the nested loop. There is something called a labeled break statement that allows you to specify which loop you want to break. This is not very common, so I will go over it quickly. Labels work like this: You can put a label in front of any loop. A label consists of a simple identifier followed by a colon. For example, a while with a label might look like "mainloop: while…​". Inside this loop you can use the labeled break statement "break mainloop;" to break out of the labeled loop. For example, here is a code segment that checks whether two strings, s1 and s2, have a character in common. If a common character is found, the value of the flag variable nothingInCommon is set to false, and a labeled break is used to end the processing at that point:

boolean nothingInCommon;
nothingInCommon = true;  // Assume s1 and s2 have no chars in common.
int i,j;  // Variables for iterating through the chars in s1 and s2.

i = 0;
bigloop: while (i < s1.length()) {
   j = 0;
   while (j < s2.length()) {
      if (s1.charAt(i) == s2.charAt(j)) { // s1 and s2 have a common char.
          nothingInCommon = false;
          break bigloop;  // break out of BOTH loops
      }
      j++;  // Go on to the next char in s2.
   }
   i++;  //Go on to the next char in s1.
}
Caution

It is not considered good style to use a break when a while expression could be used; so our first example is not good programming — use break with caution, and only when you cannot otherwise write a loop to do what you need it to.

The continue statement is related to break, but less commonly used. A continue statement tells the computer to skip the rest of the current iteration of the loop. However, instead of jumping out of the loop altogether, it jumps back to the beginning of the loop and continues with the next iteration (including evaluating the loop’s continuation condition to see whether any further iterations are required). As with break, when a continue is in a nested loop, it will continue the loop that directly contains it; a "labeled continue" can be used to continue the containing loop instead.

break and continue can be used in while loops and do..while loops. They can also be used in for loops, which are covered in the next section. Later, we’ll see that break can also be used to break out of a switch statement. A break can occur inside an if statement, but only if the if statement is nested inside a loop or inside a switch statement. In that case, it does not mean to break out of the if. Instead, it breaks out of the loop or switch statement that contains the if statement. The same consideration applies to continue statements inside ifs.

Caution

There is one other control flow statement that you will find in the C# reference manual but will not be discussed further here: the goto statement. It, too, uses labeled statements, and causes the flow of control to be immediately moved from the goto statement to the labeled statement. This is never recommended, and is not necessary given the other control flow statements in the language.

On the other hand, with just if and goto, you can program loops and so have a complete language without ever using a loop; you would use if and goto to code loops. But don’t do it. It’s terrible practice and the code written that way is unreadable.


5.5. The for Statement

We turn in this section to another type of loop, the for statement. Any for loop is equivalent to some while loop, so the language doesn’t get any additional power by having for statements. But for a certain type of problem, a for loop can be easier to construct and easier to read than the corresponding while loop. It’s quite possible that in real programs, for loops actually outnumber while loops.

5.5.1. For Loops

The for statement makes a common type of while loop easier to write. Many while loops have the general form:

initialization
while ( continuation-condition ) {
    statements
    update
}

For example, consider this example from earlier in the chapter:

    years = 0;  // initialization
    while (years < 5) { //continuation condition

       interest = principal * rate; // compute interest for this year
       principal += interest;       // add it to principal.
       <p>@principal</p>            // display the principal for the year

       years++; // update to the next year
    }

This loop can be written as the following equivalent for statement:

for ( years = 0;  years < 5;  years++ ) {
       interest = principal * rate; // compute interest for this year
       principal += interest;       // add it to principal.
       <p>@principal</p>            // display the principal for the year
}

The initialization, continuation condition, and updating have all been combined in the first line of the for loop. This keeps everything involved in the "control" of the loop in one place, which helps make the loop easier to read and understand. The for loop is executed in exactly the same way as the original code: The initialization part is executed once, before the loop begins. The continuation condition is executed before each execution of the loop, and the loop ends when this condition is false. The update part is executed at the end of each execution of the loop, just before jumping back to check the condition.

The formal syntax of the for statement is as follows:

for ( initialization; continuation-condition; update )
     statement

or, using a block statement:

for ( initialization; continuation-condition; update ) {
     statements
}

The continuation-condition must be a boolean-valued expression. The initialization is usually a declaration or an assignment statement, but it can be any expression that would be allowed as a statement in a program. The update can be any simple statement, but is usually an increment, a decrement, or an assignment statement. Any of the three parts can be empty. If the continuation condition is empty, it is treated as if it were "true," so the loop will be repeated forever or until it ends for some other reason, such as a break statement. (Some people like to begin an infinite loop with "for (;;)" instead of "while (true)".) Here’s a flow control diagram for a for statement:

control diagram for a for loop

Usually, the initialization part of a for statement assigns a value to some variable, and the update changes the value of that variable with an assignment statement or with an increment or decrement operation. The value of the variable is tested in the continuation condition, and the loop ends when this condition evaluates to false. A variable used in this way is called a loop control variable. In the example given above, the loop control variable was years.

Certainly, the most common type of for loop is the counting loop, where a loop control variable takes on all integer values between some minimum and some maximum value. A counting loop has the form

for ( variable = min;  variable <= max; variable++ ) {
     statements
}

where min and max are integer-valued expressions (usually constants). The variable takes on the values min, min+1, min+2, …​, max. The value of the loop control variable is often used in the body of the loop. The for loop at the beginning of this section is a counting loop in which the loop control variable, years, takes on the values 1, 2, 3, 4, 5. Here is an even simpler example, in which the numbers 1, 2, …​, 10 are displayed :

for (int i = 1 ;  i <= 10 ;  i++ ) {
   <p>@i</p>
}
Note

One-letter variables are usually frowned upon in code; one exception is for-loop variables, where we will often see i or j used as simple counters. If there is more reason than simply counting, give your for-loop variable a meaningful name.

For various reasons, Java programmers like to start counting at 0 instead of 1, and they tend to use a "<" in the condition, rather than a "⇐". The following variation of the above loop prints out the ten numbers 0, 1, 2, …​, 9:

for (int i = 0 ;  i < 10 ;  i++ ) {
   <p>@i</p>
}

Using < instead of <= in the test, or vice versa, is a common source of off-by-one errors in programs. You should always stop and think, Do I want the final value to be processed or not?

It’s easy to count down from 10 to 1 instead of counting up. Just start with 10, decrement the loop control variable instead of incrementing it, and continue as long as the variable is greater than or equal to one.

for (int i = 10 ;  i >= 1 ;  i-- ) {
   <p>@i</p>
}

Now, in fact, the official syntax of a for statement actually allows both the initialization part and the update part to consist of several expressions, separated by commas. So we can even count up from 1 to 10 and count down from 10 to 1 at the same time!

for ( i=1, j=10;  i <= 10;  i++, j-- ) {
   <pre>@System.format("{0,5}{1,5}", i, j)</pre>  // i and j each get 5 character fields (use pre to keep space)
}

As a final introductory example, let’s say that we want to use a for loop that prints out just the even numbers between 2 and 20, that is: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20. There are several ways to do this. Just to show how even a very simple problem can be solved in many ways, here are four different solutions (three of which would get full credit):

 (1)   // There are 10 numbers to print.
       // Use a for loop to count 1, 2,
       // ..., 10.  The numbers we want
       // to print are 2*1, 2*2, ... 2*10.

       for (int i = 1; i <= 10; i++) {
          <text>@(2*i) </text>
       }

 (2)   // Use a for loop that counts
       // 2, 4, ..., 20 directly by
       // adding 2 to N each time through
       // the loop.

       for (int i = 2; i <= 20; i += 2) {
          <text>@i </text>
       }

 (3)   // Count off all the numbers
       // 2, 3, 4, ..., 19, 20, but
       // only print out the numbers
       // that are even.

       for (int i = 2; i <= 20; i++) {
          if ( i % 2 == 0 )  { // is i even?
              <text>@i </text>
           }
       }

 (4)   // Irritate the professor with
       // a solution that follows the
       // letter of this silly assignment
       // while making fun of it.

       for (int i = 1; i <= 1; i++) {
          <text>2 4 6 8 10 12 14 16 18 20</text>
       }

Perhaps it is worth stressing one more time that a for statement, like any statement except for a variable declaration, never occurs on its own in a real program. A statement must be inside the main routine of a program or inside some other subroutine. And that subroutine must be defined inside a class. (In ASP.NET, the code you put in Razor code blocks are put into a generated class for the page.)

I should also remind you that every variable must be declared before it can be used, and that includes the loop control variable in a for statement. In all the examples that you have seen so far in this section, the loop control variables should be declared to be of type int. It is not required that a loop control variable be an integer. Here, for example, is a for loop in which the variable, ch, is of type char, using the fact that the ++ operator can be applied to characters as well as to numbers:

@* Print out the alphabet on one line of output. *@
<p>
@for ( char ch = 'A';  ch <= 'Z';  ch++ ) {
    <text>@ch </text>
}
</p>

Here I show another use of Razor — any of the loop and conditional statements can be directly placed in your web page with a @ prefix before the keyword for, while, do, if, or switch. This lets you put all of the contents within a single paragraph as the example shows.


5.5.2. Example: Counting Divisors

Let’s look at a less trivial problem that can be solved with a for loop. If N and D are positive integers, we say that D is a divisor of N if the remainder when D is divided into N is zero. (Equivalently, we could say that N is an even multiple of D.) In terms of C# programming, D is a divisor of N if N % D is zero.

Let’s write a program that inputs a positive integer, N, from the user and computes how many different divisors N has. The numbers that could possibly be divisors of N are 1, 2, …​, N. To compute the number of divisors of N, we can just test each possible divisor of N and count the ones that actually do divide N evenly. In pseudocode, the algorithm takes the form

Get a positive integer, N, from the user
Let divisorCount = 0
for each number, testDivisor, in the range from 1 to N:
    if testDivisor is a divisor of N:
        Count it by adding 1 to divisorCount
Output the count

This algorithm displays a common programming pattern that is used when some, but not all, of a sequence of items are to be processed. The general pattern is

for each item in the sequence:
   if the item passes the test:
       process it

The for loop in our divisor-counting algorithm can be translated into Java code as

for (testDivisor = 1; testDivisor <= N; testDivisor++) {
   if ( N % testDivisor == 0 )
      divisorCount++;
}

On a modern computer, this loop can be executed very quickly. It is not impossible to run it even for the largest legal int value, 2147483647. (If you wanted to run it for even larger values, you could use variables of type long rather than int.) However, it does take a significant amount of time for very large numbers. So when I implemented this algorithm, I decided to output a dot every time the computer has tested one million possible divisors. In the improved version of the program, there are two types of counting going on. We have to count the number of divisors and we also have to count the number of possible divisors that have been tested. So the program needs two counters. When the second counter reaches 1000000, the program outputs a '.' and resets the counter to zero so that we can start counting the next group of one million. Reverting to pseudocode, the algorithm now looks like

Get a positive integer, N, from the user
Let divisorCount = 0  // Number of divisors found.
Let numberTested = 0  // Number of possible divisors tested
                      //       since the last period was output.
for each number, testDivisor, in the range from 1 to N:
    if testDivisor is a divisor of N:
        Count it by adding 1 to divisorCount
    Add 1 to numberTested
    if numberTested is 1000000:
        print out a '.'
        Reset numberTested to 0
Output the count

Finally, we can translate the algorithm into a complete Java program:

Listing 9. CountDivisors.cshtml
<!DOCTYPE html>
<html>
  <head>
    <title>Count Divisors</title>

    <style type="text/css">
      body {background-color: beige; font-family: Verdana, Arial;
            margin: 50px; }
      form {padding: 10px; border-style: solid; width: 250px;}
    </style>
  </head>

  <body>
  <p> This page counts how many divisors the number has and prints the result.</p>

  <p>Enter a numbers and then click <strong>Count Divisors</strong>.</p>
  <form action="" method="post">
    <p><label for="principal">Number:</label>
       <input type="text" name="num" />
    </p>
    <p><input type="submit" value="Count Divisors" /></p>
  </form>
  <br/>

  @{
      int num;  // A positive integer entered by the user.
              // Divisors of this number will be counted.

      int testDivisor;  // A number between 1 and N that is a
                        // possible divisor of N.

      int divisorCount;  // Number of divisors of N that have been found.

      int numberTested;  // Used to count how many possible divisors
                         // of N have been tested.  When the number
                         // reaches 1000000, a period is output and
                         // the value of numberTested is reset to zero.

      /* Get the initial number from the user. */
      if (IsPost) {
        num = Request["num"].AsInt();

        if (num <= 0) {
          <p>@num is not positive.  Please try again.</p>
        } else {
         // At this point, we know that num > 0

        /* Count the divisors, printing a "." after every 1000000 tests. */

        divisorCount = 0;
        numberTested = 0;

        for (testDivisor = 1; testDivisor <= num; testDivisor++) {
           if ( num % testDivisor == 0 ) {
              divisorCount++;
           }
           numberTested++;
           if (numberTested == 1000000) {
            <text>.</text>
            numberTested = 0;
          }
        }

        /* Display the result. */
        <text><br /></text>
        <p>The number of divisors of @num is @divisorCount.</p>

        } // end num > 0

      } // end IsPost
  }
  </body>
</html>

Note that because the whole web page is displayed only once its HTML is generated by the Razor processor, all of the .'s display at once, after the computation completes. This kind of progress meter would be displayable during the execution of the computation only with a more complex call-back in place, beyond the scope of our work.


5.5.3. Nested For Loops

Control structures in Java are statements that contain other, simpler statements. In particular, control structures can contain control structures. You’ve already seen several examples of if statements inside loops, and one example of a while loop inside another while, but any combination of one control structure inside another is possible. We say that one structure is nested inside another. You can even have multiple levels of nesting, such as a while loop inside an if statement inside another while loop. The syntax of Java does not set a limit on the number of levels of nesting. As a practical matter, though, it’s difficult to understand a program that has more than a few levels of nesting.

Nested for loops arise naturally in many algorithms, and it is important to understand how they work. Let’s look at a couple of examples. First, consider the problem of printing out a multiplication table like this one:

 1   2   3   4   5   6   7   8   9  10  11  12
 2   4   6   8  10  12  14  16  18  20  22  24
 3   6   9  12  15  18  21  24  27  30  33  36
 4   8  12  16  20  24  28  32  36  40  44  48
 5  10  15  20  25  30  35  40  45  50  55  60
 6  12  18  24  30  36  42  48  54  60  66  72
 7  14  21  28  35  42  49  56  63  70  77  84
 8  16  24  32  40  48  56  64  72  80  88  96
 9  18  27  36  45  54  63  72  81  90  99 108
10  20  30  40  50  60  70  80  90 100 110 120
11  22  33  44  55  66  77  88  99 110 121 132
12  24  36  48  60  72  84  96 108 120 132 144

The data in the table are arranged into 12 rows and 12 columns, so we should generate an HTML table. The process of printing them out can be expressed in a pseudocode algorithm as

start a table
for each rowNumber = 1, 2, 3, ..., 12:
   start a row
   Print the first twelve multiples of rowNumber on one line
   end the row
end the table

The first step in the for loop can itself be expressed as a for loop. We can expand "Print the first twelve multiples of rowNumber on one line" as:

for N = 1, 2, 3, ..., 12:
   Print N * rowNumber

so a refined algorithm for printing the table has one for loop nested inside another:

start a table
for each rowNumber = 1, 2, 3, ..., 12:
   start a row
   for N = 1, 2, 3, ..., 12:
      Print N * rowNumber
   end the row
end the table

We want to print the output in neat columns, with each output number taking up four spaces. This can be done using formatted output with format specifier %4d. Assuming that rowNumber and N have been declared to be variables of type int, the algorithm can be expressed in Java as

<table>
@for ( int rowNumber = 1;  rowNumber <= 12;  rowNumber++ ) {
   // start a row in the table
   @: <tr>
   for ( int N = 1;  N <= 12;  N++ ) {
        // print in columns
        <td align="right">@( N * rowNumber )</td>
   }
   //end the current row in the table
   @: </tr>
}
</table>
Note

Note the use of @: to mark the HTML-only rows. This is needed for the </tr> since it is just a closing tag on its own. For consistency, I’ve used it on the <tr> as well — consistency makes the code easier to read.

This section has been weighed down with lots of examples of numerical processing. For our next example, let’s do some text processing. Consider the problem of finding which of the 26 letters of the alphabet occur in a given string. For example, the letters that occur in "Hello World" are D, E, H, L, O, R, and W. More specifically, we will write a program that will list all the letters contained in a string and will also count the number of different letters. The string will be input by the user. Let’s start with a pseudocode algorithm for the program.

Ask the user to input a string
Read the response into a variable, text
Let count = 0  (for counting the number of different letters)
for each letter of the alphabet:
   if the letter occurs in text:
      Print the letter
      Add 1 to count
Output the count

This follows our form model very well, since forms' input come to us as strings already. The line of the algorithm that reads "for each letter of the alphabet" can be expressed as "for (letter='A'; letter⇐'Z'; letter++)". But the if statement inside the for loop needs still more thought before we can write the program. How do we check whether the given letter, letter, occurs in str? One idea is to look at each character in the string in turn, and check whether that character is equal to letter. We can get the i-th character of text with an index into the string like so: text[i], where i ranges from 0 to str.Length - 1.

One more difficulty: A letter such as 'A' can occur in str in either upper or lower case, 'A' or 'a'. We have to check for both of these. But we can avoid this difficulty by converting str to upper case before processing it. Then, we only have to check for the upper case letter. We can now flesh out the algorithm fully:

Ask the user to input a string
Read the response into a variable, text
Convert text to upper case
Let count = 0
for letter = 'A', 'B', ..., 'Z':
    for i = 0, 1, ..., text.Length-1:
        if letter == text[i]:
            Print letter
            Add 1 to count
            break  // jump out of the loop, to avoid counting letter twice
Output the count

Note the use of break in the nested for loop. It is required to avoid printing or counting a given letter more than once (in the case where it occurs more than once in the string). The break statement breaks out of the inner for loop, but not the outer for loop. Upon executing the break, the computer continues the outer loop with the next value of letter. You should try to figure out exactly what count would be at the end of this program, if the break statement were omitted. Here is the complete program:

Listing 10. ListLetters.cshtml
<!DOCTYPE html>
<html>
<head>
    <title>List Letters</title>

    <style type="text/css">
        body {
            background-color: beige;
            font-family: Verdana, Arial;
            margin: 50px;
        }

        form {
            padding: 10px;
            border-style: solid;
            width: 250px;
        }
    </style>
</head>

<body>
    <p>Enter a line and I'll tell you what letters it has, and
       how many different letters there are.</p>

    <p>Enter your line and then click <strong>List Letters</strong>.</p>
    <form action="" method="post">
        <p>
            <label for="principal">Text:</label>
            <input type="text" name="text" />
        </p>
        <p><input type="submit" value="List Letters" /></p>
    </form>
    <br />

@{
   if (IsPost) {
      string text;  // Line of text entered by the user.
      int count=0;  // Number of different letters found in str.

      text = Request["text"].ToUpper();

      <p>Your input contains the following letters: </p>

      @: <p>
      for (char letter = 'A'; letter <= 'Z'; letter++ ) {
          int i;  // Position of a character in str.
          for ( i = 0; i < text.Length; i++ ) {
              if ( letter == text[i] ) {
                  <text>@letter </text>
                  count++;
                  break;
              }
          }
      }
      @: </p>

      <p>There were @count different letters.</p>
   } // end IsPost
}
</body>
</html>

In fact, there is actually an easier way to determine whether a given letter occurs in a string, str. The built-in function str.IndexOf(letter) will return -1 if letter does not occur in the string. It returns a number greater than or equal to zero if it does occur. So, we could check whether letter occurs in str simply by checking "if (str.IndexOf(letter) >= 0)". If we used this technique in the above program, we wouldn’t need a nested for loop. This gives you a preview of how subroutines can be used to deal with complexity.

Tip

It is a good idea to get familiar with the common methods such as those on string so that you avoid re-writing code that is available to you in ASP.NET already.

…​

5.6. The if Statement

The first of the two branching statements in Java is the if statement, which you have already seen. It takes the form

if (boolean-expression)
     statement-1
else
     statement-2

As usual, the statements inside an if statement can be blocks. The if statement represents a two-way branch. The else part of an if statement — consisting of the word "else" and the statement that follows it — can be omitted.

This section delves into complex uses of if statements and how to consider what can go wrong with them.

5.6.1. The Dangling else Problem

Note

Since Razor requires {}'s on all bodies of if statements, these types of issues can only occur in your C# class files' code. They will not occur in your .cshtml files.

Now, an if statement is, in particular, a statement. This means that either statement-1 or statement-2 in the above if statement can itself be an if statement. A problem arises, however, if statement-1 is an if statement that has no else part. This special case is effectively forbidden by the syntax of C#. Suppose, for example, that you type

if ( x > 0 )
    if (y > 0)
       msg="First case";
else
    msg="Second case";

Now, remember that the way you’ve indented this doesn’t mean anything at all to the computer. You might think that the else part is the second half of your "if (x > 0)" statement, but the rule that the computer follows attaches the else to "if (y > 0)", which is closer. That is, the computer reads your statement as if it were formatted:

if ( x > 0 )
    if (y > 0)
       msg="First case";
    else
        msg="Second case";

You can force the computer to use the other interpretation by enclosing the nested if in a block:

if ( x > 0 ) {
    if (y > 0)
       msg="First case";
}
else
    msg="Second case";

These two if statements have different meanings: In the case when x <= 0, the first statement doesn’t set msg to anything, but the second statement sets it to "Second case".

5.6.2. Multiway Branching

Much more interesting than this technicality is the case where statement-2, the else part of the if statement, is itself an if statement. The statement would look like this (perhaps without the final else part):

if (boolean-expression-1)
     statement-1
else
     if (boolean-expression-2)
         statement-2
     else
         statement-3

However, since the computer doesn’t care how a program is laid out on the page, this is almost always written in the format:

if (boolean-expression-1)
     statement-1
else if (boolean-expression-2)
     statement-2
else
     statement-3

You should think of this as a single statement representing a three-way branch. When the computer executes this, one and only one of the three statements — statement-1, statement-2, or statement-3 — will be executed. The computer starts by evaluating boolean-expression-1. If it is true, the computer executes statement-1 and then jumps all the way to the end of the outer if statement, skipping the other two statements. If boolean-expression-1 is false, the computer skips statement-1 and executes the second, nested if statement. To do this, it tests the value of boolean-expression-2 and uses it to decide between statement-2 and statement-3.

Here is an example that will print out one of three different messages, depending on the value of a variable named temperature:

if (temperature < 50) {
   <p>It's cold.</p>
} else if (temperature < 80) {
   <p>It's nice.</p>
} else {
   <p>It's hot.</p>
}
Tip

Notice the brace placement above: Razor allows you to not put braces between the else and if, it reads "else if" as a unit.

If temperature is, say, 42, the first test is true. The computer prints out the message "It’s cold", and skips the rest — without even evaluating the second condition. For a temperature of 75, the first test is false, so the computer goes on to the second test. This test is true, so the computer prints "It’s nice" and skips the rest. If the temperature is 173, both of the tests evaluate to false, so the computer says "It’s hot" (unless its circuits have been fried by the heat, that is).

You can go on stringing together "else-if’s" to make multi-way branches with any number of cases:

if (test-1)
     statement-1
else if (test-2)
     statement-2
else if (test-3)
     statement-3
  .
  . // (more cases)
  .
else if (test-N)
     statement-N
else
     statement-(N+1)

The computer evaluates the tests, which are boolean expressions, one after the other until it comes to one that is true. It executes the associated statement and skips the rest. If none of the boolean expressions evaluate to true, then the statement in the else part is executed. This statement is called a multi-way branch because one and only one of the statements will be executed. The final else part can be omitted. In that case, if all the boolean expressions are false, none of the statements are executed. Of course, each of the statements can be a block, consisting of a number of statements enclosed between { and }. Admittedly, there is lot of syntax here; as you study and practice, you’ll become comfortable with it. It might be useful to look at a flow control diagram for the general "if..else if" statement shown above:

Flow control diagram for a multiway if statement

5.6.3. If Statement Examples

As an example of using if statements, let’s suppose that x, y, and z are variables of type int, and that each variable has already been assigned a value. Consider the problem of printing out the values of the three variables in increasing order. For example, if the values are 42, 17, and 20, then the output should be in the order 17, 20, 42.

One way to approach this is to ask, where does x belong in the list? It comes first if it’s less than both y and z. It comes last if it’s greater than both y and z. Otherwise, it comes in the middle. We can express this with a 3-way if statement, but we still have to worry about the order in which y and z should be printed. In pseudocode,

if (x < y && x < z) { // && is the boolean operator, logical and.
    output x, followed by y and z in their correct order
}
else if (x > y && x > z) {
    output y and z in their correct order, followed by x
}
else {
    output x in between y and z in their correct order
}

Determining the relative order of y and z requires another if statement, so this becomes

if (x < y && x < z) {        // x comes first
    if (y < z) {
       <p>@x @y @z</p>
    } else {
       <p>@x @z @y</p>
    }
}
else if (x > y && x > z) {   // x comes last
    if (y < z) {
       <p>@y @z @x</p>
    } else {
       <p>@z @y @x</p>
    }
}
else {                       // x in the middle
    if (y < z) {
       <p>@y @x @z</p>
    } else {
       <p>@z @x @y</p>
    }
}

You might check that this code will work correctly even if some of the values are the same. If the values of two variables are the same, it doesn’t matter which order you print them in.

Note, by the way, that even though you can say in English "if x is less than y and z," you can’t say in C# "if (x < y && z)". The && operator can only be used between boolean values, so you have to make separate tests, x<y and x<z, and then combine the two tests with &&.

There is an alternative approach to this problem that begins by asking, "which order should x and y be printed in?" Once that’s known, you only have to decide where to stick in z. This line of thought leads to different Java code:

if ( x < y ) {  // x comes before y
   if ( z < x ) {  // z comes first
      <p>@z @x @y</p>
   } else if ( z > y ) {  // z comes last
      <p>@x @y @z</p>
   } else {   // z is in the middle
      <p>@x @z @y</p>
   }
} else {          // y comes before x
   if ( z < y ) {  // z comes first
      <p>@z @y @x</p>
   } else if ( z > x ) {  // z comes last
      <p>@y @x @z</p>
   } else {  // z is in the middle
      <p>@y @z @x</p>
   }
}

Once again, we see how the same problem can be solved in many different ways. The two approaches to this problem have not exhausted all the possibilities. For example, you might start by testing whether x is greater than y. If so, you could swap their values. Once you’ve done that, you know that x should be printed before y.


Finally, let’s write a complete program that uses an if statement in an interesting way. I want a program that will convert measurements of length from one unit of measurement to another, such as miles to yards or inches to feet. So far, the problem is extremely under-specified. Let’s say that the program will only deal with measurements in inches, feet, yards, and miles. It would be easy to extend it later to deal with other units. The user will type in a measurement in one of these units, such as "17 feet" or "2.73 miles". The output will show the length in terms of each of the four units of measure. (This is easier than asking the user which units to use in the output.) An outline of the process is

Read the user's input measurement and units of measure
Express the measurement in inches, feet, yards, and miles
Display the four results

TWe will read the input from a form and convert the value to a double. The conversion into different units of measure can be simplified by first converting the user’s input into inches. From there, the number of inches can easily be converted into feet, yards, and miles. Before converting into inches, we have to test the input to determine which unit of measure the user has specified:

Let measurement = Request["measurement"]
Let units = Request["units"]
if the units are inches
   Let inches = measurement
else if the units are feet
   Let inches = measurement * 12         // 12 inches per foot
else if the units are yards
   Let inches = measurement * 36         // 36 inches per yard
else if the units are miles
   Let inches = measurement * 12 * 5280  // 5280 feet per mile
else
   The units are illegal!
   Print an error message and stop processing
Let feet = inches / 12.0
Let yards = inches / 36.0
Let miles = inches / (12.0 * 5280.0)
Display the results

We can use HTML to limit the user to only the units of measure we currently support. However, since HTML POST requests could be made without the form, we will check for not only the allowed values but also illegal values, just in case.

Also, the magic values 12, 36, and 5280 are coded as constants to document what they are.

Here’s the complete program:

Listing 11. LengthConverter.cshtml
<!DOCTYPE html>
<html>
<head>
    <title>Length Converter</title>

    <style type="text/css">
        body {
            background-color: beige;
            font-family: Verdana, Arial;
            margin: 50px;
        }

        form {
            padding: 10px;
            border-style: solid;
            width: 300px;
        }
    </style>
</head>

<body>
    <p>Enter your measurement and units and then click <strong>Convert</strong>
    to see it in other units.<br/>
    I will convert your input into the other units
    of measure.</p>
    <form action="" method="post">
        <p>
            <label for="measurement">Measurement:</label>
            <input type="text" name="measurement" />
        </p>
        <p>
            <label for="units">Units:</label>
            <select name="units">
                <option value="inches">inches</option>
                <option value="feet">feet</option>
                <option value="yards">yards</option>
                <option value="miles">miles</option>
            </select>
        </p>
        <p><input type="submit" value="Convert" /></p>
    </form>
    <br />

    @{
   if (IsPost) {
       double measurement;  // Numerical measurement, input by user.
       string units;        // The unit of measure for the input, also
                            //    specified by the user.

       double inches, feet, yards, miles;  // Measurement expressed in
                                           //   each possible unit of
                                           //   measure.

       const int inchesInFeet = 12; // constants for conversions
       const int inchesInYard = 36;
       const int feetInMile = 5280;

       /* Get the user's input, and convert units to lower case. */
       measurement = (double)Request["measurement"].AsDecimal();
       units = Request["units"].ToLower();

       /* Convert the input measurement to inches. */
       if (units.Equals("inches")) {
           inches = measurement;
       }
       else if (units.Equals("feet")) {
           inches = measurement * inchesInFeet;
       }
       else if (units.Equals("yards")) {
           inches = measurement * inchesInYard;
       }
       else if (units.Equals("miles")) {
           inches = measurement * inchesInFeet * feetInMile;
       }
       else {
           // in case the form is submitted incorrectly
           <p>Sorry, but I don't understand @units. Will assume inches.</p>
           inches = measurement;
       }

       /* Convert measurement in inches to feet, yards, and miles. */
       feet = inches / inchesInFeet;
       yards = inches / inchesInYard;
       miles = inches / (inchesInFeet*feetInMile);

       /* Output measurement in terms of each unit of measure. */
       <p>That's equivalent to:</p>
       <p>@inches inches</p>
       <p>@feet feet</p>
       <p>@yards yards</p>
       <p>@miles miles</p>
   } // end IsPost
}
</body>
</html>

Here you can see we have really taken advantage of the web experience to tailor the user’s selection. Consider how you would write this in a Java application, where you would also have to request the units from the user rather than provide them with a limited number of choices.


5.6.4. The Empty Statement

As a final note in this section, I will mention one more type of statement in C#: the empty statement. This is a statement that consists simply of a semicolon and which tells the computer to do nothing. The existence of the empty statement makes the following legal, even though you would not ordinarily see a semicolon after a } :

if (x < 0) {
    x = -x;
};

The semicolon is legal after the }, but the computer considers it to be an empty statement, not part of the if statement. Occasionally, you might find yourself using the empty statement when what you mean is, in fact, "do nothing." For example, the rather contrived if statement

if ( done )
   ;  // Empty statement
else
   message="Not done yet.";

does nothing when the boolean variable done is true, and sets message to "Not done yet" when it is false. You can’t just leave out the semicolon in this example, since Java syntax requires an actual statement between the if and the else. I prefer, though, to use an empty block, consisting of { and } with nothing between, for such cases. (So does Razor, which requires the { } instead of the ; here.)

Occasionally, stray empty statements can cause annoying, hard-to-find errors in a program. For example, the following program segment sets message to "Hello", rather than "Hello Hello Hello Hello Hello":

for (int i = 0; i < 5; i++);
    message+="Hello ";

Why? Because the ";" at the end of the first line is a statement, and it is this empty statement that is executed ten times. The assignment statement is not really inside the for statement at all, so it is executed just once, after the for loop has completed. The for loop just does nothing, ten times!

(In Razor, it would fail to compile, requesting that you use {}s after the for loop.)

5.7. The switch Statement

The second branching statement in C# is the switch statement, which is introduced in this section. The switch statement is used far less often than the if statement, but it is sometimes useful for expressing a certain type of multiway branch.

5.7.1. The Basic switch Statement

A switch statement allows you to test the value of an expression and, depending on that value, to jump directly to some location within the switch statement. Only expressions of certain types can be used. The value of the expression can be one of the primitive integer types int, short, or byte. It can be the primitive char or bool types. It can be string. Or it can be an enum type (we are not covering C# enums in this book, see https://msdn.microsoft.com/en-us/library/sbbt4032.aspx for information on this type). In particular, note that the expression cannot be a double, float, or decimal value.

The positions within a switch statement to which it can jump are marked with case labels that take the form: "case constant:". The constant here is a literal of the same type as the expression in the switch. A case label marks the position the computer jumps to when the expression evaluates to the given constant value. As the final case in a switch statement you can, optionally, use the label "default:", which provides a default jump point that is used when the value of the expression is not listed in any case label.

A switch statement, as it is most often used, has the form:

switch (expression) {
   case constant-1:
      statements-1
      break;
   case constant-2:
      statements-2
      break;
      .
      .   // (more cases)
      .
   case constant-N:
      statements-N
      break;
   default:  // optional default case
      statements-(N+1)
} // end of switch statement

This has exactly the same effect as the following multiway if statement, but the switch statement can be more efficient because the computer can evaluate one expression and jump directly to the correct case, whereas in the if statement, the computer must evaluate up to N expressions before it knows which set of statements to execute:

if (expression == constant-1) { // but use .equals for String!!
    statements-2
}
else if (expression == constant-2) {
    statements-3
}
else
    .
    .
    .
else if (expression == constant-N) {
    statements-N
}
else {
    statements-(N+1)
}

The break statements in the switch are technically optional. However, does require that execution not continue to the next switch case: it has to end with a break, throw, return, or other statement that interrupts the flow of control. The effect of a break is to make the computer jump past the end of the switch statement, skipping over all the remaining cases. If you leave out the break statement, you will get a compilation error.

Note that you can leave out one of the groups of statements entirely (including the break). You then have two case labels in a row, containing two different constants. This just means that the computer will jump to the same place and perform the same action for each of the two constants.

Here is an example of a switch statement. This is not a useful example, but it should be easy for you to follow. Note, by the way, that the constants in the case labels don’t have to be in any particular order, but they must all be different:

switch ( N ) {   // (Assume N is an integer variable.)
   case 1:
      message="The number is 1.";
      break;
   case 2:
   case 4:
   case 8:
      message="The number is 2, 4, or 8.";
      message+="(That's a power of 2!)";
      break;
   case 3:
   case 6:
   case 9:
      message="The number is 3, 6, or 9.";
      message+="(That's a multiple of 3!)";
      break;
   case 5:
      message="The number is 5.";
      break;
   default:
      message="The number is 7 or is outside the range 1 to 9.";
}

The switch statement is pretty primitive as control structures go, and it’s easy to make mistakes when you use it. C# has addressed a key issue that exists in other languages by requiring that the switch be exited at the end of a case block.

5.7.2. Lists and switch Statements

One application of switch statements is in processing list selections. A form can have a drop-down list of options. The user selects one of the options. The computer has to respond to each possible choice in a different way. The value of chosen option can be used in a switch statement to select the proper response.

Here is an example that could be used in a variation of the LengthConverter example from the previous section:

Listing 12. LengthConverter2.cshtml
<!DOCTYPE html>
<html>
<head>
    <title>Length Converter</title>

    <style type="text/css">
        body {
            background-color: beige;
            font-family: Verdana, Arial;
            margin: 50px;
        }

        form {
            padding: 10px;
            border-style: solid;
            width: 300px;
        }
    </style>
</head>

<body>
    <p>Enter your measurement and units and then click <strong>Convert</strong>
    to see it in other units.<br/>
    I will convert your input into the other units
    of measure.</p>
    <form action="" method="post">
        <p>
            <label for="measurement">Measurement:</label>
            <input type="text" name="measurement" />
        </p>
        <p>
            <label for="units">Units:</label>
            <select name="units">
                <option value="inches">inches</option>
                <option value="feet">feet</option>
                <option value="yards">yards</option>
                <option value="miles">miles</option>
            </select>
        </p>
        <p><input type="submit" value="Convert" /></p>
    </form>
    <br />

                @{
   if (IsPost) {
       double measurement;  // Numerical measurement, input by user.
       string units;        // The unit of measure for the input, also
                            //    specified by the user.

       double inches, feet, yards, miles;  // Measurement expressed in
                                           //   each possible unit of
                                           //   measure.

       const int inchesInFeet = 12; // constants for conversions
       const int inchesInYard = 36;
       const int feetInMile = 5280;

       /* Get the user's input, and convert units to lower case. */
       measurement = (double)Request["measurement"].AsDecimal();
       units = Request["units"].ToLower();

       /* Convert the input measurement to inches. */
       switch(units) { (1)
       case "inches":
           inches = measurement;
           break;
       case "feet":
           inches = measurement * inchesInFeet;
           break;
       case "yards":
           inches = measurement * inchesInYard;
           break;
       case "miles":
           inches = measurement * inchesInFeet * feetInMile;
           break;
       default:           // in case the form is submitted incorrectly
           <p>Sorry, but I don't understand @units. Will assume inches.</p>
           inches = measurement;
           break;
       }

       /* Convert measurement in inches to feet, yards, and miles. */
       feet = inches / inchesInFeet;
       yards = inches / inchesInYard;
       miles = inches / (inchesInFeet*feetInMile);

       /* Output measurement in terms of each unit of measure. */
       <p>That's equivalent to:</p>
       <p>@inches inches</p>
       <p>@feet feet</p>
       <p>@yards yards</p>
       <p>@miles miles</p>
   } // end IsPost
}
</body>
</html>
  1. This is the new code, using a switch instead of a series of if tests.

5.7.3. Definite Assignment and switch Statements

As a somewhat more realistic example, the following switch statement makes a random choice among three possible alternatives. The value of the expression rand.Next(3) is one of the integers 0, 1, or 2, selected at random with equal probability, so the switch statement below will assign one of the values "Rock", "Paper", "Scissors" to computerMove, with probability 1/3 for each case:

Note

Random is a useful ASP.NET class, with an interesting collection of methods available on it for our use: see https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx. We haven’t introduced objects yet; Random rand = new Random(); is creating an object based on the Random class so that we can access the object’s methods. Why didn’t ASP.NET just provide a Random object? this has to do with thread safety and how random numbers are generated: it’s up to an application to ensure that only one thread at a time accesses the Random objects it manages. Don’t worry, we only have one thread of execution in our Web Pages.

String computerMove;
Random rand = new Random();
switch ( rand.Next(3) ) {
   case 0:
      computerMove = "Rock";
      break;
   case 1:
      computerMove = "Paper";
      break;
   case 2:
      computerMove = "Scissors";
      break;
}

Now, this switch statement is perfectly OK, but suppose that we use it in the following code segment:

String computerMove;
Random rand = new Random();
switch ( rand.Next(3) ) {
   case 0:
      computerMove = "Rock";
      break;
   case 1:
      computerMove = "Paper";
      break;
   case 2:
      computerMove = "Scissors";
      break;
}
<p>The computer's move is @computerMove</p>

Now there is a subtle error on the last line! The problem here is due to definite assignment, the idea that the Java compiler must be able to determine that a variable has definitely been assigned a value before its value is used. Definite assignment was discussed earlier in this chapter. In this example, it’s true that the three cases in the switch cover all the possibilities, but the compiler is not smart enough to figure that out; it just sees that there is an integer-valued expression in the switch but not all possible integer values are covered by the given cases.

A simple solution is to replace the final case in the switch statement with default. With a default case, all possible values of the expression in the switch are certainly covered, and the compiler knows that computerMove is definitely assigned a value:

String computerMove;
Random rand = new Random();
switch ( rand.Next(3) ) {
   case 0:
      computerMove = "Rock";
      break;
   case 1:
      computerMove = "Paper";
      break;
   default:
      computerMove = "Scissors";
      break;
}
<p>The computer's move is @computerMove</p>

5.8. Variables and Scope

Variables can be defined within any of the compound statements in the C# statements. Once a variable is defined within a compound statement, it is visible until the end of that compound statement. This has two implications:

  1. After the compound statement, the variable is no longer visible. You can declare a variable by the same name in a later compound statement.

  2. Another variable by the same name cannot be defined in a nested compound statement.

5.9. Exception Handling

In addition to the control structures that determine the normal flow of control in a program, C# has a way to deal with "exceptional" cases that throw the flow of control off its normal track. When an error occurs during the execution of a program, the default behavior is to terminate the program and to print an error message. However, C# makes it possible to "catch" such errors and program a response different from simply letting the program crash. This is done with the try..catch statement. In this section, we will take a preliminary and incomplete look the try..catch statement, leaving out a lot of the rather complex syntax of this statement. Error handling is a complex topic, which we will return to in a later chapter, and we will cover the full syntax of try..catch at that time.

5.9.1. Exceptions

The term exception is used to refer to the type of error that one might want to handle with a try..catch. An exception is an exception to the normal flow of control in the program. The term is used in preference to "error" because in some cases, an exception might not be considered to be an error at all. You can sometimes think of an exception as just another way to organize a program.

Exceptions in C# are represented as objects of type Exception. Actual exceptions are usually defined by subclasses of Exception. Different subclasses represent different types of exceptions. We will look at only three types of exception in this section: FormatException, ArgumentException, and DivideByZeroException.

A FormatException can occur when an attempt is made to convert a a value with String.Format but the value and format specifier are not compatible. Consider the function call String.Format("The cost is {0:Q2}.", 15.32m). Q2 is not a valid format for decimals, so this will receive a FormatException. If C2 had been specified, then the call would work and return "The cost is $15.32". If nothing is done to handle the exception, the web page will not render but the exception will be displayed instead.

An ArgumentException can occur when an illegal value is passed as an argument to a method. For example, if a method requires that a parameter be greater than or equal to zero, an ArgumentException might occur when a negative value is passed to the subroutine. How to respond to the illegal value is up to the person who wrote the code, so we can’t simply say that every illegal parameter value will result in an ArgumentException. However, it is a common response.

A DivideByZeroException occurs when a value is divided by zero. This is caught at compile-time when there is a literal 0, but a computed divisor won’t be known until run-time.

5.9.2. try..catch

When an exception occurs, we say that the exception is "thrown". For example, we say that String.Format(formatString,val) throws an exception of type FormatException when a format in the formatString is illegal. When an exception is thrown, it is possible to "catch" the exception and prevent it from crashing the program. This is done with a try..catch statement. In simplified form, the syntax for a try..catch can be:

try {
   statements-1
}
catch ( exception-class-name  variable-name ) {
   statements-2
}

The exception-class-name could be FormatException, ArgumentException, or some other exception class. When the computer executes this try..catch statement, it executes the statements in the try part. If no exception occurs during the execution of statements-1, then the computer just skips over the catch part and proceeds with the rest of the program. However, if an exception of type exception-class-name occurs during the execution of statements-1, the computer immediately jumps from the point where the exception occurs to the catch part and executes statements-2, skipping any remaining statements in statements-1. Note that only one type of exception is caught; if some other type of exception occurs during the execution of statements-1, it will crash the program as usual.

Tip

Actually, it may not crash the program — what an uncaught exception does is interrupt the flow of control; the computer will look for a try/catch in a larger scope (the calling method) if it cannot find one in the current method. So, at any point in a program, any layer could choose to handle an exception generated lower down in the stack.

During the execution of statements-2, the variable-name represents the exception object, so that you can, for example, print it out. The exception object contains information about the cause of the exception. This includes an error message, which will be displayed if you print out the exception object.

After the end of the catch part, the computer proceeds with the rest of the program; the exception has been caught and handled and does not crash the program.

By the way, note that the braces, { and }, are part of the syntax of the try..catch statement. They are required even if there is only one statement between the braces. This is different from the other statements we have seen, where the braces around a single statement are optional.

As an example, suppose that you are computing a value that involves division. Then we could say:

double y;
bool success;
try {
   y = Math.PI/x; //x's value previously set by other computations
   success = true;
}
catch ( DivideByZeroException e ) {
   y = Double.NaN;
   success = false;
}

If an error is thrown by the division then the second statement in the try part is skipped, and the statements in the catch part are executed. (In this example, I set z to be the value Double.NaN when an exception occurs. Double.NaN is the special "not-a-number" value for type double.)

It’s not always a good idea to catch exceptions and continue with the program. Often that can just lead to an even bigger mess later on, and it might be better just to let the exception crash the program at the point where it occurs. However, sometimes it’s possible to recover from an error.

For example, the AsInt() method on strings does not throw ArgumentException when the string value is not a valid integer value; instead it simply returns a 0. Similarly, if you can take a reasonable default action rather than throw an exception, you might code your web pages and methods accordingly.

5.9.3. Multiple catch blocks and finally

You can put multiple catch blocks after a try block. C# will stop at the first one that satisfies the exception found, using inheritance (see a future chapter for information on inheritance). It is convention to list only the specific exception classes, not a more general one.

There is another type of block you can place after (or instead of) your catch blocks, a finally block. Its syntax is:

try {
... try code
}
... zero or more catch blocks
finally {
... finally code
}

The finally code is used to clean up; it is always executed (even if a catch block is executed; the finaly follows the catch block). This is useful to clean up external resources such as file references and open sockets, as if you do not clean up those resources your code’s runtime environment will be impacted as it tracks items it does not need to track.

For more information, see MSDN’s Exceptions and Exception Handling (C# Programming Guide).

5.9.4. throw

Exceptions are generated by a throw statement. If, for example, you determine that you have been handed invalid values for a computation, then instead of having a bad value come back, you can throw an exception to alert the caller.

if (word.Length < 1) {
  throw new ArgumentException("Input word has to contain characters");
}

Notice that we have to "new" the exception, just as we did with Random. In C#, there are exception classes, and you create an exception object to throw.

There are many exceptions available to you in C#; you can use these, or define your own. The standard exceptions all can be created with a message as shown above; it is a good idea to include a message, but consider also the impact on security — your message has to convey useful information without providing information that would allow entry into the system.

Table 3. ASP.NET Exception classes
Exception type Description Example

System Exceptions

IndexOutOfRangeException

an array is indexed improperly

Indexing an array outside its valid range: arr[arr.Length+1]

NullReferenceException

a null object is referenced

object o = null;
o.ToString(); // null referenced

AccessViolationException

invalid memory is accessed

invalid pointer used in unmanaged or unsafe code (a C library, typically)

InvalidOperationException

method in an invalid state

used by collections and other libraries that track state, for example, calling Enumerator.GetNext() after removing an item from the underlying collection.

Argument Exceptions

ArgumentNullException

null argument when not allowed

String s = null;
"hello".IndexOf(s); // IndexOf can’t take a null

ArgumentOutOfRangeException

arguments required to be in a given range

String s = "string";
s.Chars[9]; // range check rather than index check

External Exceptions

OMException

encapsulates COM HRESULT information.

Occurs when accessing COM.

SEHException

encapsulates Win32 structured exception handling information.

Occurs when accessing unmanaged code.

To see how to define your own exceptions, see Creating and Throwing Exceptions (C# Programming Guide)


5.10. Arrays

There is another control structure in C# that requires at least a brief introduction to arrays to be useful. This structure will turn out to be extremely useful when we visit collections in a later chapter.

This section is an introduction to arrays. Arrays are a basic and very commonly used data structure, and array processing is often an exercise in using control structures.

5.10.1. Creating and Using Arrays

A data structure consists of a number of data items chunked together so that they can be treated as a unit. An array is a data structure in which the items are arranged as a numbered sequence, so that each individual item can be referred to by its position number. In C# all the items must be of the same type, and the numbering always starts at zero. You will need to learn several new terms to talk about arrays: The number of items in an array is called the length of the array. The type of the individual items in an array is called the base type of the array. And the position number of an item in an array is called the index of that item.

Suppose that you want to write a program that will process the names of, say, one thousand people. You will need a way to deal with all that data. Before you knew about arrays, you might have thought that the program would need a thousand variables to hold the thousand names, and if you wanted to print out all the names, you would need a thousand print statements. Clearly, that would be ridiculous! In reality, you can put all the names into an array. The array is a represented by a single variable, but it holds the entire list of names. The length of the array would be 1000, since there are 1000 individual names. The base type of the array would be string since the items in the array are strings. The first name would be at index 0 in the array, the second name at index 1, and so on, up to the thousandth name at index 999.

The base type of an array can be any C# type, but for now, we will stick to arrays whose base type is string or one of the other primitive types. If the base type of an array is int, it is referred to as an "array of ints." An array with base type string is referred to as an "array of strings." However, an array is not, properly speaking, a list of integers or strings or other values. It is better thought of as a list of variables of type int, or a list of variables of type string, or of some other type. As always, there is some potential for confusion between the two uses of a variable: as a name for a memory location and as a name for the value stored in that memory location. Each position in an array acts as a variable. Each position can hold a value of a specified type (the base type of the array), just as a variable can hold a value. The value can be changed at any time, just as the value of a variable can be changed. The items in an array — really, the individual variables that make up the array — are more often referred to as the elements of the array.

As I mentioned above, when you use an array in a program, you can use a variable to refer to array as a whole. But you often need to refer to the individual elements of the array. The name for an element of an array is based on the name for the array and the index number of the element. The syntax for referring to an element looks, for example, like this: namelist[7]. Here, namelist is the variable that names the array as a whole, and namelist[7] refers to the element at index 7 in that array. That is, to refer to an element of an array, you use the array name, followed by element index enclosed in square brackets. An element name of this form can be used like any other variable: You can assign a value to it, print it out, use it in an expression.

Note

If this looks familiar, it’s because we already saw indexing when we wanted to look inside a string value at individual characters: a string behaves like an array of characters in this respect. One of the quirks of a primitive type is that the compiler can choose to handle special cases related to the primitives. Indexing does not work on numbers, that is, you cannot pull out the ith digits of an int x using x[i].

An array also has a Length property representing its length. For example, you can refer to the length of the array namelist as namelist.Length. However, you cannot assign a value to namelist.Length, since the length of an array cannot be changed.

Before you can use a variable to refer to an array, that variable must be declared, and it must have a type. For an array of strings, for example, the type for the array variable would be string[], and for an array of ints, it would be int[]. In general, an array type consists of the base type of the array followed by a pair of empty square brackets. Array types can be used to declare variables; for example,

string[] nameList;
int[] a;
double[] prices;

and variables declared in this way can refer to arrays. However, declaring a variable does not make the actual array. Like all variables, an array variable has to be assigned a value before it can be used. In this case, the value is an array. Arrays have to be created using a special syntax. (The syntax is related to the fact that arrays in C# are actually objects, but that doesn’t need to concern us here.) Arrays are created with an operator named new. Here are some examples:

nameList = new string[1000];
a = new int[5];
prices = new double[100];

The general syntax is

array-variable = new base-type[array-length];

The length of the array can be given as either an integer or an integer-valued expression. For example, after the assignment statement "a = new int[5];", a is an array containing the five integer elements a[0], a[1], a[2], a[3], and a[4]. Also, a.length would have the value 5. It’s useful to have a picture in mind:

illustration of an array of 5 ints

When you create an array of int, each element of the array is automatically initialized to zero. Any array of numbers is filled with zeros when it is created. An array of boolean is filled with the value false. And an array of char is filled with the character that has Unicode code number zero. (For an array of string, the initial value is null, a special value used for objects that we won’t encounter officially until a later chapter.)

You assign a value into an array item by referencing the item on the left-hand side of an assignment statement, like so:

a[0] = 1;

There is another form of initialization that both allocates the array space and assigns values, like so:

int[] a = { 2, 4, 6, 8 };

This initializes a to have 4 elements with the initial values 2, 4, 6, and 8, respectively. It is equivalent to saying:

int[] a = new int[4];
a[0] = 2;
a[1] = 4;
a[2] = 6;
a[3] = 8;

5.10.2. Arrays and For Loops

A lot of the real power of arrays comes from the fact that the index of an element can be given by an integer variable or even an integer-valued expression. For example, if list is an array and i is a variable of type int, then you can use list[i] and even list[2*i+1] as variable names. The meaning of list[i] depends on the value of i. This becomes especially useful when we want to process all the elements of an array, since that can be done with a for loop. For example, to print out all the items in an array, list, we can just write

for (int i = 0; i < list.Length; i++) {
    <p>@list[i]</p>
}

The first time through the loop, i is 0, and list[i] refers to list[0]. So, it is the value stored in the variable list[0] that is printed. The second time through the loop, i is 1, and the value stored in list[1] is printed. The loop ends after printing the value of list[4], when i becomes equal to 5 and the continuation condition "i < list.Length" is no longer true. This is a typical example of using a loop to process an array.

Note

Notice what is going on here: because arrays count elements starting from zero, the length is always one more than the highest index. So, for loops compare the index to be < the length. You might try changing this to <= the length and see how it behaves. In fact, you will be walking off the end of the array, and should expect an exception to be thrown. C# and Java added this protection — in earlier languages such as C, you could walk off the end of an array and look at memory you didn’t actually have access to.

Let’s look at a few more examples. Suppose that A is an array of double, and we want to find the average of all the elements of the array. We can use a for loop to add up the numbers, and then divide by the length of the array to get the average:

double total;    // The sum of the numbers in the array.
double average;  // The average of the numbers.
total = 0;
for ( int i = 0; i < A.Length; i++ ) {
    total = total + A[i];  // Add element number i to the total.
}
average = total / A.Length;  // A.length is the number of items

Another typical problem is to find the largest number in the array A. The strategy is to go through the array, keeping track of the largest number found so far. We’ll store the largest number found so far in a variable called max. As we look through the array, whenever we find a number larger than the current value of max, we change the value of max to that larger value. After the whole array has been processed, max is the largest item in the array overall. The only question is, what should the original value of max be? One possibility is to start with max equal to A[0], and then to look through the rest of the array, starting from A[1], for larger items:

double max;  // The largest number seen so far.
max = A[0];   // At first, the largest number seen is A[0].
int i;
for ( i = 1; i < A.length; i++ ) {
    if (A[i] > max) {
       max = A[i];
    }
}
// at this point, max is the largest item in A

Sometimes, you only want to process some elements of the array. In that case, you can use an if statement inside the for loop to decide whether or not to process a given element. Let’s look at the problem of averaging the elements of an array, but this time, suppose that we only want to average the non-zero elements. In this case, the number of items that we add up can be less than the length of the array, so we will need to keep a count of the number of items added to the sum:

double total;    // The sum of the non-zero numbers in the array.
int count;       // The number of non-zero numbers.
double average;  // The average of the non-zero numbers.
total = 0;
count = 0;
for (int i = 0; i < A.length; i++ ) {
    if ( A[i] != 0 ) {
        total +=  A[i];  // Add element to the total
        count++;         // and count it.
    }
}
if (count == 0) {
    <p>There were no non-zero elements.</p>
}
else {
    average = total / count;  // Divide by number of items
    <p>Average of @count elements is @average</p>
}

5.10.3. Random Access

So far, my examples of array processing have used sequential access. That is, the elements of the array were processed one after the other in the sequence in which they occur in the array. But one of the big advantages of arrays is that they allow random access. That is, every element of the array is equally accessible at any given time.

As an example, let’s look at a well-known problem called the birthday problem: Suppose that there are N people in a room. What’s the chance that there are two people in the room who have the same birthday? (That is, they were born on the same day in the same month, but not necessarily in the same year.) Most people severely underestimate the probability. We will actually look at a different version of the question: Suppose you choose people at random and check their birthdays. How many people will you check before you find one who has the same birthday as someone you’ve already checked? Of course, the answer in a particular case depends on random factors, but we can simulate the experiment with a computer program and run the program several times to get an idea of how many people need to be checked on average.

To simulate the experiment, we need to keep track of each birthday that we find. There are 365 different possible birthdays. (We’ll ignore leap years.) For each possible birthday, we need to keep track of whether or not we have already found a person who has that birthday. The answer to this question is a boolean value, true or false. To hold the data for all 365 possible birthdays, we can use an array of 365 boolean values:

bool[] used;
used = new bool[365];

For this problem, the days of the year are numbered from 0 to 364. The value of used[i] is true if someone has been selected whose birthday is day number i. Initially, all the values in the array are false. (Remember that this is done automatically when the array is created.) When we select someone whose birthday is day number i, we first check whether used[i] is true. If it is true, then this is the second person with that birthday. We are done. On the other hand, if used[i] is false, we set used[i] to be true to record the fact that we’ve encountered someone with that birthday, and we go on to the next person. Here is a program that carries out the simulated experiment (of course, in the program, there are no simulated people, only simulated birthdays):

<!DOCTYPE html>
<html>
<head>
    <title>Duplicate Birthdays</title>
    <style type="text/css">
        body {
            background-color: beige;
            font-family: Verdana, Arial;
            margin: 50px;
        }
    </style>
</head>

<body>
    <p>We simulate choosing people at random and checking the day of
    the year they were born on.  If the birthday is the same as one that
    was seen previously, stop, and output the number of people who were checked.
    </p>
@{
       boolean[] used = new boolean[365];
                        // For recording the possible birthdays
                        //   that have been seen so far.  A value
                        //   of true in used[i] means that a person
                        //   whose birthday is the i-th day of the
                        //   year has been found.
                        // Initially, all entries are false.

       int count = 0;   // The number of people who have been checked.

       Random rand = new Random(); // for generating random numbers.

       while (true) {
             // Select a birthday at random, from 0 to 364.
             // If the birthday has already been used, quit.
             // Otherwise, record the birthday as used.

          int birthday;  // The selected birthday.
          birthday = rand.Next(365);
          count++;

          <p>Person @count has birthday number @birthday.</p>

          if ( used[birthday] ) {
                // This day was found before; it's a duplicate.  We are done.
             break;
          }

          used[birthday] = true;

       } // end while

       <p>duplicate birthday was found after @count tries.</p>
}
</body>
</html>

You should study the program to understand how it works and how it uses the array. Also, try it out! You will probably find that a duplicate birthday tends to occur sooner than you expect.

5.10.4. Partially Full Arrays

Consider an application where the number of items that we want to store in an array changes as the program runs. Since the size of the array can’t be changed, a separate counter variable must be used to keep track of how many spaces in the array are in use. (Of course, every space in the array has to contain something; the question is, how many spaces contain useful or valid items?)

Consider, for example, a program that reads positive integers entered by the user and stores them for later processing. The program stops reading when the user inputs a number that is less than or equal to zero. The input numbers can be kept in an array, numbers, of type int[]. Let’s say that no more than 100 numbers will be input. Then the size of the array can be fixed at 100. But the program must keep track of how many numbers have actually been read and stored in the array. For this, it can use an integer variable. Each time a number is stored in the array, we have to count it; that is, value of the counter variable must be incremented by one. One question is, when we add a new item to the array, where do we put it? Well, if the number of items is count, then they would be stored in the array in positions number 0, 1, …​, (count-1). The next open spot would be position number count, so that’s where we should put the new item.

As a rather silly example, let’s write a program that will read the numbers input by the user and then print them in the reverse of the order in which they were entered. We will provide the user with a form, and then use an empty field to determine where the numbers stop. (This is, at least, a processing task that requires that the numbers be saved in an array. Note that many types of processing, such as finding the sum or average or maximum of the numbers, can be done without saving the individual numbers.)

<!DOCTYPE html>
<html>
<head>
    <title>Reverse Numbers</title>

    <style type="text/css">
        body {
            background-color: beige;
            font-family: Verdana, Arial;
            margin: 50px;
        }
        form {
            padding: 10px;
            border-style: solid;
            width: 300px;
        }
    </style>
</head>

<body>
    <p>Enter up to 10 numbers and I will print them out in reverse order
    after you click Reverse. I stop looking at numbers after the first blank entry.</p>
    <form action="" method="post">
        <p>
            <input type="text" name="a" />
            <input type="text" name="b" />
            <input type="text" name="c" />
            <input type="text" name="d" />
            <input type="text" name="e" />
            <input type="text" name="f" />
            <input type="text" name="g" />
            <input type="text" name="h" />
            <input type="text" name="i" />
            <input type="text" name="j" />
        </p>
        <p><input type="submit" value="Reverse" /></p>
    </form>
    <br />

    @{
   if (IsPost) {
     int[] numbers = new int[10];  // An array for storing the input values.
     int count = 0;      // The number of numbers saved in the array.
     int i=0;
     for (char c='a';c<'k';c++,i++) {
         if (Request[c.ToString()].IsInt()) {
             numbers[i] = Request[c.ToString()].AsInt();
             count++;
         } else {
             break; // stop at first non-integer
         }
     }

     <p>Your numbers in reverse order are:</p>
     @: <ul>
     for (i = count - 1; i >= 0; i--) {
        <li> @numbers[i] </li>
     }
     @: </ul>
   } // end IsPost
}
</body>
</html>

It is especially important to note how the variable count plays a dual role. It is the number of items that have been entered into the array. But it is also the index of the next available spot in the array.

 When the time comes to print
out the numbers in the array, the last occupied spot in the array is location
count - 1, so the for loop prints out values starting from
location count - 1 and going down to 0.  This is also a nice
example of processing the elements of an array in reverse order.
Tip

Note that the page says it stops at the first blank — IsInt will return false on a blank, so that satisfies it. However, what other values will cause IsInt to return false? Consider how to inform the user in those situations - take ReverseNumbers.cshtml and modify it to make this change.


You might wonder what would happen in this program if our array was not large enough for the expected number of values. The result would be an error that would crash the program. When the processing attempts to store a number beyond the end of the array, there is no such array element. The attempt to use an index past the end of the array generates an exception of type IndexOutOfBoundsException. Exceptions of this type are a common source of run-time errors in programs that use arrays.


5.10.5. Two-dimensional Arrays

The arrays that we have considered so far are "one-dimensional." This means that the array consists of a sequence of elements that can be thought of as being laid out along a line. It is also possible to have two-dimensional arrays, where the elements can be laid out in a rectangular grid. We consider them only briefly here.

In a two-dimensional, or "2D," array, the elements can be arranged in rows and columns. Here, for example, is a 2D array of int that has five rows and seven columns:

an array of its with 5 rows and 7 columns

This 5-by-7 grid contains a total of 35 elements. The rows in a 2D array are numbered 0, 1, 2, …​, up to the number of rows minus one. Similarly, the columns are numbered from zero up to the number of columns minus one. Each individual element in the array can be picked out by specifying its row number and its column number. (The illustration shown here is not what the array actually looks like in the computer’s memory, but it does show the logical structure of the array.)

In C#, the syntax for two-dimensional arrays is similar to the syntax for one-dimensional arrays, except that an extra index is involved, since picking out an element requires both a row number and a column number. For example, if A is a 2D array of int, then A[3][2] would be the element in row 3, column 2. That would pick out the number 17 in the array shown above. The type for A would be given as int[][], with two pairs of empty brackets. To declare the array variable and create the array, you could say,

int[][]  A;
A  =  new int[5][7];

The second line creates a 2D array with 5 rows and 7 columns. Two-dimensional arrays are often processed using nested for loops. For example, the following code segment will print out the elements of A in a table:

<table>
@for (int row = 0; row < 5; row++ ) {
    @:<tr>
    for (int col = 0; col < 7; col++ ) {
        <td> A[row][col] </td>
    }
    @:</tr>
}
</table>

The base type of a 2D array can be anything, so you can have arrays of type double[][], String[][], and so on.

There are some natural uses for 2D arrays. For example, a 2D array can be used to store the contents of the board in a game such as chess or checkers. Tables in databases are natural two-dimensional arrays, but with more complex types. But sometimes two-dimensional arrays are used in problems in which the grid is not so visually obvious. Consider a company that owns 25 stores. Suppose that the company has data about the profit earned at each store for each month in the year 2014. If the stores are numbered from 0 to 24, and if the twelve months from January 2014 through December 2014 are numbered from 0 to 11, then the profit data could be stored in an array, profit, created as follows:

double[][]  profit;
profit  =  new double[25][12];

profit[3][2] would be the amount of profit earned at store number 3 in March, and more generally, profit[storeNum][monthNum] would be the amount of profit earned in store number storeNum in month number monthNum (where the numbering, remember, starts from zero).

Let’s assume that the profit array has already been filled with data. This data can be processed in a lot of interesting ways. For example, the total profit for the company — for the whole year from all its stores — can be calculated by adding up all the entries in the array:

double totalProfit;  // Company's total profit in 2014.
int store, month;  // variables for looping through the stores and the months
totalProfit = 0;
for ( store = 0; store < 25; store++ ) {
   for ( month = 0; month < 12; month++ ) {
      totalProfit += profit[store][month];
   }
}

Sometimes it is necessary to process a single row or a single column of an array, not the entire array. For example, to compute the total profit earned by the company in December, that is, in month number 11, you could use the loop:

double decemberProfit;
int storeNum;
decemberProfit = 0.0;
for ( storeNum = 0; storeNum < 25; storeNum++ ) {
   decemberProfit += profit[storeNum][11];
}

Two-dimensional arrays are sometimes useful, but they are much less common than one-dimensional arrays. Java actually allows arrays of even higher dimension, but they are only rarely encountered in practice.

5.10.6. For-each Loops

Arrays are often processed using for loops. A for loop makes it easy to process each element in an array from beginning to end. For example, if nameList is an array of strings, then all the values in the list can be printed using

for (int i = 0; i < nameList.Length; i++) {
    <p>nameList[i]</p>
}

This type of processing is so common that there is an alternative form of the for loop that makes it easier to write. The alternative is called a for-each loop. It is probably easiest to start with an example. Here is a for-each loop for printing all the values in an array of Strings:

foreach ( string name in nameList ) {
    <p>name</p>
}

The meaning of "foreach (string name in nameList)" is "for each string, name, in the array, nameList, do the following". The effect is that the variable name takes on each of the values in nameList in turn, and the body of the loop is executed for each of those values. Note that there is no array index in the loop. The loop control variable, name, represents one of the values in the array, not the index of one of the values.

The for-each loop is meant specifically for processing all the values in a data structure, and we will see later that it applies to other data structures besides arrays. The for-each loop makes it possible to process the values without even knowing the details of how the data is structured. In the case of arrays, it lets you avoid the complications of using array indices.

A for-each loop will perform the same operation for each value that is stored in an array. If itemArray is an array of type BaseType[], then a for-each loop for anArray has the form:

foreach ( BaseType item in itemArray ) {
   .
   .  // process the item
   .
}

As usual, the braces are optional if there is only one statement inside the loop, except in Razor. In this loop, item is the loop control variable. It is declared as a variable of type BaseType, where BaseType is the base type of the array. (In a for-each loop, the loop control variable must be declared in the loop; it cannot be a variable that already exists outside the loop.) When this loop is executed, each value from the array is assigned to item in turn and the body of the loop is executed for each value. Thus, the above loop is exactly equivalent to:

for ( int index = 0; index < itemArray.Length; index++ ) {
   BaseType item;
   item = itemArray[index];  // Get one of the values from the array
     .
     .  // process the item
     .
}

For example, if A is an array of type int[], then we could print all the values from A with the for-each loop:

foreach ( int item in A ) {
   <p> item </p>
}

and we could add up all the positive integers in A with:

int sum = 0;   // This will be the sum of all the positive numbers in A
foreach ( int item in A ) {
   if (item > 0) {
      sum = sum + item;
   }
}

The for-each loop is not always appropriate. For example, there is no simple way to use it to process the items in just a part of an array, or to process the elements in reverse order. However, it does make the code a little simpler when you do want to process all the values, in order. since it eliminates any need to use array indices.

It’s important to note that a for-each loop processes the values in the array, not the elements (where an element means the actual memory location that is part of the array). For example, consider the following incorrect attempt to fill an array of integers with 17’s:

int[] intList = new int[10];
foreach ( int item in intList ) {   // INCORRECT! DOES NOT MODIFY THE ARRAY!
   item = 17;
}

The assignment statement item = 17 assigns the value 17 to the loop control variable, item. However, this has nothing to do with the array. When the body of the loop is executed, the value from one of the elements of the array is copied into item. The statement item = 17 replaces that copied value but has no effect on the array element from which it was copied; the value in the array is not changed. The loop is equivalent to

int[] intList = new int[10];
for ( int i = 0; i < intList.length; i++ ) {
   int item = intList[i];
   item = 17; // Doesn't change intList[i]!
}

which certainly does not change the value of any element in the array.

In order to change the items in the array, you have to use a for loop, like so:

int[] intList = new int[10];
for ( int i = 0; i < intList.length; i++ ) {
   intList[i] = 17; // OK!
}

5.11. When good code has bugs

Review Chapter 1’s debugging tips now that you have the core programming operations behind you. Even with that general advice, you will find that you still collect your own set of "gotchas", problems you hit due to your own style. If you’re curious to see what other people hit, see Top 10 useful yet paranoid Java programming techniques. Yes, it’s Java, but the issues listed occur in C# also.

5.12. There’s more …​

C# is rich with features that an introductory course can’t reach. Explore these features of C# that add greatly to its functionality:

  • the using() { } statement manages an object, automatically creating and disposing of it once the block completes, even with exceptions.

  • defining your own exceptions

  • threading, which involves locking, synchronization, and controlling threads within a single application

5.14. Exercises

  1. Now that you know more C#, you can come up with even more inventive "Stump the Newbie" problems. Start with a web page that compiles and displays correctly. One player looks away while the other player adds an error to the program. Then the first player tries to find and fix the error. You get two points if you find the error without compiling the program, one point if you find it using the compiler, and your opponent gets a point if you don’t find it.

  2. Consider the following code:

        int n = 10;
        int i = n;
        while (i > 1) {
            <p>@i</p>
            if (i % 2 == 0) {
                i = i / 2;
            } else {
                i = i + 1;
            }
        }
    1. Draw a table that shows the value of the variables i and n during the execution of loop. The table should contain one column for each variable and one line for each iteration.

    2. What is the output of this program?

    3. Can you provide an explanation that this loop will terminate for any positive value of n?

  3. How many times do you have to roll a pair of dice before they come up snake eyes? You could do the experiment by rolling the dice by hand. Write a web page that simulates the experiment, using C# for your algorithm. The page should report the number of rolls that it makes before the dice come up snake eyes. (Note: "Snake eyes" means that both dice show a value of 1.) Simulate rolling a pair of dice. You can simulate rolling one die by choosing one of the integers 1, 2, 3, 4, 5, or 6 at random. The number you pick represents the number on the die after it is rolled. The expression rand.Next(6)+1 does the computation to select a random integer between 1 and 6. You can assign this value to a variable to represent one of the dice that are being rolled. Do this twice and add the results together to get the total roll.

  4. Which integer between 1 and 10000 has the largest number of divisors, and how many divisors does it have? Write a Web Page to find the answers using Razor and C# for your algorithm and display the results. It is possible that several integers in this range have the same, maximum number of divisors. Your program only has to print out one of them. The example CountDivisors.cshtml in this chapter discussed divisors.

    You might need some hints about how to find a maximum value. The basic idea is to go through all the integers, keeping track of the largest number of divisors that you’ve seen so far. Also, keep track of the integer that had that number of divisors.

  5. Write a Web Page application that will evaluate simple expressions such as 17 + 3 and 3.14159 * 4.7. The expressions are to be typed in by the user. The input always consists of a number, followed by an operator, followed by another number. The operators that are allowed are +, -, *, and /. Have the user put the values in a form with 3 fields: the left operand, the operation, and the right operand. Allow decimal values in the operands and use a select list for the operators. You should report an error if either value is not a number. Your program should print out the expression and the result after the user clicks Compute. The form should be available for the user to enter a new expression: make this a one-page Web Page application.

  6. Write a Web Page application that reads one line of input text and breaks it up into words. Your page should give the user a text input so the user can only input one line; however, that line can be as long as they want it to be. The words should be output one per line. A word is defined to be a sequence of letters. Any punctuation in the input that is not part of a word (i.e., apostrophes are parts of words if there is an s before and after them; semicolons, commas, quotes, and other punctuation are not parts of words) should be discarded. For example, if the user inputs the line He said, "That’s not a good idea." then the output of the program should be

    He
    said
    That's
    not
    a
    good
    idea

    Use string.Split() to break up a string into an array using the space character as the word separator. You will still need to clean up the "words" since punctuation may be on either end, or it may be punctuation in its entirety. You will need to trim punctuation (look into string.Trim() for this).

    To test whether a character is a letter, you might use (ch >= 'a' && ch ⇐ 'z') || (ch >= 'A' && ch ⇐ 'Z'). However, this only works in English and similar languages. A better choice is to call the standard function ch.IsLetter(), which returns a boolean value of true if ch is a letter and false if it is not. This works for any Unicode character. You might want to look at all of the methods available on char values here: https://msdn.microsoft.com/en-us/library/system.char.aspx to determine if one will help you break up strings and handle punctuation at the same time.

  1. The goal of this exercise is to program a “Guess My Number” game. When it’s finished, it will work like this:

    I'm thinking of a number between 1 and 100
    (including both). Can you guess what it is?
    Enter a number: 45 [Submit Guess]
    
    // once submit is clicked, it would output:
    
    Your guess is: 45
    The number I was thinking of is: 14
    You were off by: 31

    To choose a random number, use the Random class as shown in the previous chapter, like so:

        Random rand = new Random();
        int number = rand.Next(100)+1;
        ...

    The result of Next(100) is between 0 and 99, including both. Adding 1 yields a number between 1 and 100, including both.

    Let the user keep playing as much as they want; you generate a new number each time they enter their guess.

  2. An exercise above asked you to find the number in the range 1 to 10000 that has the largest number of divisors. You only had to print out one such number. Revise the program so that it will print out all numbers that have the maximum number of divisors. Use an array as follows: As you count the divisors for each number, store each count in an array. Then at the end of the program, you can go through the array and print out all the numbers that have the maximum count. The output on the Web Page should look something like this:

    Among integers between 1 and 10000,
    The maximum number of divisors was 64.
    Numbers with that many divisors include:
       7560
       9240
  3. An example in this chapter tried to answer the question, How many random people do you have to select before you find a duplicate birthday? The source code for that web page was given in BirthdayProblem.cshtml. Here are some related questions:

    • How many random people do you have to select before you find three people who share the same birthday? (That is, all three people were born on the same day in the same month, but not necessarily in the same year.)

    • Suppose you choose 365 people at random. How many different birthdays will they have? (The number could theoretically be anywhere from 1 to 365).

    • How many different people do you have to check before you’ve found at least one person with a birthday on each of the 365 days of the year?

      Write three separate pages to answer these questions and a home page that directs the user to each of the pages. Review the elements of Web Design from chapter 2 in deciding on your flow and the content of each page. Each of your pages should simulate choosing people at random and checking their birthdays. (In each case, ignore the possibility of leap years.)

  4. Write a page that requests a line of text from the user and then tests to see if the letters in it form a palindrome. A palindrome as the same letters forward and back; it is not case sensitive. For example,"A Man, A Plan, A Canal - Panama!" is a famous long palindrome. It informs the user where in the string the palindrome test failed, if it is not a palindrome, and lets them know it is a palindrome, if it is.

  5. Write a page that requests a line of text from a user, and regardless of how it was typed in (all upper, all lower, or a mix), converts it to "Title Case" where every word has its first letter transformed to upper case and the rest transformed to lower case. You will want to use string.Split() to break the line into an array of strings. You will need to ensure that any punctuation at the start of a word does not cause it to fail to be capitalized. So, for example, if the user input: He said, "hello" then you would output He Said "Hello".

    To test whether a character is a letter, you might use (ch >= 'a' && ch ⇐ 'z') || (ch >= 'A' && ch ⇐ 'Z'). However, this only works in English and similar languages. A better choice is to call the standard function ch.IsLetter(), which returns a boolean value of true if ch is a letter and false if it is not. This works for any Unicode character. You might want to look at all of the methods available on char values here: https://msdn.microsoft.com/en-us/library/system.char.aspx to determine if one will help you break up strings and handle punctuation at the same time.

    Remember that you have both the string and the char types here, so be sure to check both for useful methods for this exercise.

5.15. Project

Look at your original proposal and layout; introduce functionality with data hard-coded in arrays. We will be conquering databases next, and will replace array accesses with database accesses there.

For example, you might hard-code several GPS locations in an array, and then take the user’s location and calculate which of the "stored" locations they are closest to.

6. Deploying Web Page Applications

Your web application isn’t live until it’s actually on the internet. So far, we’ve been running our website on the same machine as our browser; that’s highly unrealistic — and may have lead you to take non-viable shortcuts such as absolute paths and security loopholes.

In this chapter we will deploy our web applications so that we can test for any defects due to our assumptions. We will explore security issues in a later chapter.

You’ve probably heard of the cloud at this point in your studies. We will deploy our web applications to a cloud provider that lets small applications like ours be deployed for free. This will require creating an account — so read through the privacy policy and ensure you are comfortable with it.

What can you do if you do not want cloud deployment? That’s a much larger task, outside the scope of this text. You would need to set up an IIS server on a computer that is visible on the internet, with a fixed IP address and domain name, so that you could put your application on it and your users could find it.

6.1. Choosing a service

Most services have free trials, but cost money after the first few weeks. There is one, at the time of this writing, that is free for one application at a time: appharbor.com. Read their terms of service https://appharbor.com/page/terms before you create your account (which is free) at https://appharbor.com/ .

Creating an account requires only a valid email address; you will be required to use a link provided to that email address to complete your registration.

It’s important, when using a cloud service, such as AppHarbor, to be aware of any requirements they put on your application. AppHarbor in particular requires that if you have user accounts, you inform the user that the information is available to both your application and to AppHarbor. Also, as is common among cloud services, AppHarbor reserves the right to use your application in their advertising.

Because you are deploying to the cloud, you must not violate anyone’s copyright, per the Digital Millenium Copyright Act. Disney is well-known for going after anyone putting Disney images on their pages. Keep it safe, use wikimedia commons, flickr commons, or use your own images (photos or drawings). Yes, this may make your pages not look as good without an authentic Mickey Mouse image, but your future employers may actually come across your web application (especially if you put it in your portfolio), and will appreciate that you respected copyrights rather than "borrowing" images, text, or code. If you really feel the need to re-use copyrighted material, be sure it falls within general fair use guidelines, not academic fair use, which is more lenient, but only pertains to material kept in the school setting.

6.2. Platform as a Service

AppHarbor is a way for you to publish your application and make it available on the internet. They provide the ASP.NET platform as a service.

AppHarbor takes the source for an ASP.NET-based website and builds, tests, and deploys it. You provide your source to AppHarbor using a software versioning system (Git, Mercurial, Subversion, or Team Foundation Server) to provide a stable version of your software to AppHarbor.

AppHarbor then builds your code locally. Why? This way it can compile to its host operating system and available libraries, and not rely on being compatible with your local build and system setup. It also has hooks to run unit tests if you provide them, so you can stop a deployment if the tests do not pass.

If the build and tests succeed, then AppHarbor will deploy your application: install it and make it available through an IIS server. It will do all of this for free, giving you one "worker thread". You purchase additional worker threads and services such as databases, caching, and e-mail if you want to, for scaling or more functionality; we won’t purchase any for our projects.

AppHarbor can scale your application across CPUs, disks, and servers to provide better performance and reliability (for a fee). This means it could actually run within several different instances, and have copies of its data on several different disks, to allow more users to access it and to provide failover should a disk go bad.

When your web application is live, it is available through a free subdomain of apphb.com or a domain name you’ve purchased and configured (for a fee).

AppHarbor is actually running within Amazon Web Services — so their service layer is the ASP.NET configuration and management, and how they choose to do scaling and services within the AWS infrastructure. (AWS provides direct ASP.NET support as well.) Your application is running in the same server as other applications, but AppHarbor isolates different applications from each other.

For more information, visit https://appharbor.com/page/how-it-works

The basic setup can be found in a variety of services like this; ASP.NET C# cloud service include:

6.3. Deploying on AppHarbor

This requires that you have Git installed on your machine. Git is code versioning/repository software that manages source code.

Once you have an AppHarbor account (created at appharbor.com), follow these steps:

  1. Log in to your account at appharbor.com

  2. Create an application at appharbor.com/applications. You will pick a name for the application — call it the same name you gave your application (not Default, but "SimpleCalculator", for example).

  3. Once the application is created, you are on the application page. The box on the left that has the application name at the top has a button "Repository URL" on the bottom. Click that box, and then get the AppHarbor respository URL that is provided. It will look something like this: https://username@appharbor.com/applicationname-32.git

  4. Make or update your local code repository with Git:

    1. The very first time you deploy, you will need to install Git on your machine. See "How do I get Git?" below for how to do this.

    2. The first time you deploy a new application, you first need to put it into a local Git repository. See "Create a Git Repository" below for how to do this.

    3. Re-deployments will require udpating your local Git Repository; it is not sufficient to just edit the files. See "Update a Git Repository" below for the steps to do this.

  5. Open a git command window on your local machine, and cd to the directory at the root of your site (where _AppStart.cshtml and Default.cshtml and other files are located). Add the remote repository like this:

    git remote add appharbor MY_REPOSITORY_URL (1)
    1. Replace MY_REPOSITORY_URL with the repository URL you got in step 3 above.

    You will only need to do this step one time, the first time you deploy your repository.

  6. Deploy using:

    git push appharbor master

    This step will ask you for your AppHarbor password. Once you supply that, it will then prepare and upload the files from your local code repository to AppHarbor. You will see messages similar to this (but with different numbers and specific names):

    Counting objects: 126, done.
    Compressing objects: 100% (123/123), done.
    Writing objects: 100% (126/126), 535.97 KiB | 0 bytes/s, done.
    Total 126 (delta 14), reused 0 (delta 0)
    To https://appharbor.com/simplecalculator-1.git
     * [new branch]      master -> master

    The number of files will change based on what was changed since your last commit and upload.

    Do this step each time you want to update the code on AppHarbor. It will be updated to the currently committed code on your local git repository (see step 4.c. above for how to do that).

Once you deploy to AppHarbor, there may be issues. So next you will need to go to your live application and start testing it. Continue with Deployed on AppHarbor.

6.3.1. How do I get Git?

Git software will need to be on your machine; there is a great download writeup here with Linux, Mac, and Windows links:

We will be installing the portable Windows version.

  1. Go to https://git-scm.com/download/win

  2. Cancel the default download that starts

  3. Scroll down to the portable thumbdrive versions, and download the appropriate one for your hardware (32-bit or 64-bit). This will get you the most current version. At the time of this writing, that was the 8-19-16 release of 2.9.3, and is almost 30MB in size.

  4. Once it is downloaded, run the installer. You can install it on a local drive, or if you want to take Git with you between several machines, install it on a thumb drive for portable use.

    1. The first question the installer asks is where to install it.

    2. Then it unpacks the compressed file to proceed — depending on your machine, this can take some time.

    3. That’s it, it’s installed.

  5. You can now get to a git command window by double-clicking on git-cmd.exe in your portable git directory. If you want some more information on what you now have, open "Readme.portable", located in the installation directory, in a text editor such as notepad or notepad++. This file contains instructions on how to set up your environment to make git available in regular Windows cmd windows.

There is a good online tutorial of Git available at try.github.io if you’d like to see some of the power of this new tool. Below we will discuss just the commands needed for deployment.

6.3.2. Create a Git Repository

Before your first deployment of a given application you will need to create a local Git repository so that you can push your application to AppHarbor. Git provides a web API that AppHarbor uses to get its copy of your code.

Tip
Why not use FTP?

AppHarbor uses Git and not FTP since it expects you to be working on code that is under active development or maintenance — that means version control to any professional developer. Git provides that version control, so AppHarbor doesn’t have to.

AppHarbor even supports deployment from GitHub accounts, so true multi-user cloud-based development can be done with several users sharing code through GitHub and deploying to AppHarbor when they have a stable codeline.

In a git command window (start with git-bash or git-cmd in our portable Git) do:

  1. cd path\to\my\application — your application is located in the directory you put your WebSite in when you first created it.

  2. git init — this creates a new directory, .git, which will be used by git to track your software files.

  3. Add a file named .gitignore with the contents of the .gitignore file available here.

  4. Add a file named .gitattributes with the contents of the .gitattributes file available here.

    These two files clarify what files in your local codeline get transferred to AppHarbor and how they are dealt with in that transfer. They are needed due to "fluff" Visual Studio needs that your deployed application should not have present, and because AppHarbor does its own builds, it does not use the compiled code from your local machine.

  5. Issue these two commands so that line endings in your text files (a perennial issue with Linux vs. Windows file transfers) do not cause deployment issues:

    git config core.autocrlf false
    git config core.safecrlf false
  6. git add . — this adds all files, except for those mentioned in .gitignore, to your repository

  7. git commit -m "Initial commit" — this finalizes the initial state of your repo and makes it deployable to AppHarbor. The list of all of the files (not excluded by .gitignore) will scroll up your screen as the commit completes. There will be quite a few files if you worked from a Visual Studio template, both files you created and files the template provided.

Your repository is now ready for its first deployment.

6.3.3. Update a Git Repository

Once your code is in a Git Repository, you can use Git to save its state. Git is a very powerful version control tool; you can save the state of your code at any point in its development. Once saved, you can return to that state at a future time, or undo recent saves if they turn out to be flawed. We aren’t going to explore those capabilities of Git, but there are good writeups on that at git-scm.com and a tutorial at try.github.io

You have to save its state when you want to push that state up to AppHarbor.

These are the steps in making an update:

  1. In Visual Studio, make the changes to your local code; you may add files, remove files, or alter files.

  2. Open a git command window. You will need to:

    1. git add . to add any newly created files and any altered files to your commit. This will find them all.

    2. git rm FILENAME with the FILENAME of any file that you deleted from your project, to remove it in your commit (so it will be removed on AppHarbor);if you did not remove any, you do not need to issue any git rm requests. If you are not sure if you have deleted any, perform a git status command and see if it reports any files removed. Those files will need to have git rm commands issued to record their removal. Read the output of git status carefully — it tells you what commands to issue before issuing a commit.

    3. git commit -m "UPDATE_MESSAGE" — record a one-line summary (think "tweet") of the changes captured in this commit; this captures all of your changes for the next upload

6.4. Deployed on AppHarbor

You’ve set up Git, set up AppHarbor, and pushed your local code. But how do you get to your application?

First, it needs to be compiled on AppHarbor. Once you deploy with a git push, go to https://appharbor.com/applications — here I have just my first one, SimpleCalculator (circled):

appharbor applications 1
Figure 11. AppHarbor applications page

Click on your application name to go to its administrative panel. There you will see the build status for all of your uploads:

appharbor simplecalc 1
Figure 12. AppHarbor SimpleCalculator application page

If it failed, there will be a red crossed circle to the left of the build. As you can see, it took me a few tries to clean up my deployment. Click on the red crossed circle to see the build details page:

appharbor build details
Figure 13. AppHarbor SimpleCalculator build details page

Click on the second "View Log" to see what the problems are. You may need to resort to StackOverflow if it is a configuration issue — as you can see from the list of failures on my screen, I worked through a few configuration issues (now addressed in this writeup and associated .gitignore file).

You will have to go back to your source code in Visual Studio, fix the issue, re-build and test locally, then update your local repository and git push the code back up to AppHarber. Check the build status again. Once your codeline is completely working, you will see the other mark next to your build, a green bulls-eye.

The green bulls-eye means that your application is working! AppHarbor automatically deploys a working build to its live site, putting it on the internet. It takes a minute or two to deploy your application. If you had a previously working one, it will be a few minutes until the new one replaces it. The build that is deployed has ACTIVE next to it; if you want a different build to be deployed, you can click its DEPLOY button to swap it with the currently active one.

6.5. Access a Deployed Application on AppHarbor

Once you have a green build that is deployed, you can access your web application with the "Go to your application" link in the upper-right of the administration panel. The link for your deployed application will be some variant of the application name. For example, my application is named SimpleCalculator, and my URL is simplecalculator-1.apphb.com.

You can give that link to anyone — anyone with internet access can get to your deployed website.

The URL goes to the home page of your website. For ASP.NET, that is Default.cshtml. If you have not defined that page in your web site, users will get a page that says "Welcome to nginx!" - so you should make sure to include a Default landing page, even if all it does is reroute the user to your application page. Users can type in a full URL to a particular page, if you provide it to them. So,

will bring up my calculator page. (Note, I deleted it, so that link won’t take you to it.)

6.6. Got Database?

We haven’t covered databases yet, but if you used the ASP.NET Web Site with Identity Template, you already have a database. You are going to need to locate and add database support for this database to work in deployment. App Harbor only supports a single database in an application, so any additional tables will also need to be (re-)located in the Identity database.

Caution

If you used the Web Site Starter Site Template, then you have a SQL Compact Edition (SQLCE) database (.sdf file). This textbook does not discuss how to deploy a SQLCE database, and App Harbor recommends that you not use it, as it will only be a transient database (destroyed each time the app idles).

Go to your application’s main administration panel and look for "Add ons". Click this, then page down until you find "Shared SQL Server"; click "See More" for that service, and then add the Free level of support. This provides 20 MB of storage (something to keep in mind).

Upon a successful install, you are returned to the Application Console. Click the "SQL Server" service that appears under so that you go back to the Add On console for SQL Server — you need to return to do some more configuration.

On the SQL Server add-on page, you need to click "Go to SQL Server" to configure the connection string. This puts you on a page with private configuration information (not the kind of information to publish yourself — these are the private keys that get you to your private SQL Server instance).

On that page click the "Edit database configuration" button. In the Alias box, put the name of your connection — this is the name that you used in the Web.config file. With the Web Pages with Identity template it is DefaultConnection. Click Apply. This returns you to the previous page, and the alias now shows up in the information there.

Why did you do this? So that AppHarbor will find its database server rather than the one you developed with. It has to do this, as it has a shared database server, not private ones for each application.

Note

It is possible to access this deployed database, if you want to "look behind the web site". Install SQL Server 2008, and use it to access the database

On the Application Console, you will see a "Configuration variables" link by your SQL Server add-on (below the builds). Click this link. Three keys are listed there:

  • SQLSERVER_CONNECTION_STRING

  • SQLSERVER_CONNECTION_STRING_ALIAS

  • SQLSERVER_URI

You can use these values to initiate a connection to your database from your local machine using SQL Server 2008 Management Studio. For more information on the AppHarber shared SQL Server service, see Using Sequelizer and the support note on remote access Can’t connect to SQL Server from Management Studio, both on appharbor.com.

6.7. Your Second Application

You can have multiple applications available on your AppHarbor account. Use all of the steps provided earlier in this chapter for each deployed application:

  1. Create a Visual Studio Web Site or Project

  2. Create a local Git Repo for it.

  3. Create an AppHarbor application for it.

The local repo and AppHarbor deployment are specific to the VS Web Site; each Web Site needs its own local Git repo and its own AppHarbor application.

6.8. Summary of Deployment

Setup (per machine) First Time (per application) Nth Time
  1. Install Visual Studio

  2. Install Portable Git

  3. Create an AppHarbor Account

  1. Create a VS Web Site

  2. Create an AppHarbor application

  3. Create a local git repo:

    • open git-cmd window

    • cd to directory

    • git init

    • create .gitignore and .gitattributes

    • git config core.autocrlf false

    • git config core.safecrlf false

    • git add .

    • git commit -m "initial commit"

  4. Tie the local git repo to your AppHarbor application:

    • git remote add appharbor MY_REPOSITORY_URL

  5. Put the code on AppHarbor:

    • git push appharbor master

  6. If needed, configure Shared SQL and tell it your connection name.

  7. Go to AppHarbor application build result page; if working, go to application, otherwise see Nth time.

  1. Modify a VS Web Site

  2. Update the local git repo

    • open git-cmd window

    • cd to directory

    • git status

    • git add .

    • git rm FILENAME (if needed)

    • git commit -m "DESCRIBE_CHANGES"

  3. Put the code on AppHarbor:

    • git push appharbor master

  4. Go to AppHarbor application build result page; if working, go to application, otherwise repeat.

6.9. Removing an Application

If you decide you no longer want an application to be deployed, you can delete it from AppHarbor. This removes your code from AppHarbor and removes the last build from AppHarbor’s Web Server.

To do this, navigate to your application from appharbor.com/applications and on that page, select Settings under the application name (I’ve circled it in red in the image):

appharbor demo admin
Figure 14. Demo Application Management Menu

On the Settings page, at the very bottom, there is a DELETE button. Click on that to remove your application from AppHarbor:

appharbor demo settings
Figure 15. Demo Application Settings Page (bottom)

It will double-check with you in case you slipped; but once you click on SURE?, your application is gone.

appharbor demo deleted
Figure 16. Demo Application Deleted

Your local code and local git repository are still on your machine. So, if you wish to deploy it in the future, you will be able to create a new application and then connect your existing git repository to that application by issuing a new git remote command to connect that existing local Git repository to your new AppHarbor application.

To remove your local Git repository, you would delete the .git directory and all of its contents from within your Web Site directory on your machine. (If you have hidden system files in your File Explorer view, you will not see the .git director. It is there; change the File Explorer properties on your machine to display hidden files to see it.) Your .gitignore and .gitattributes files will still be there; they can also safely be deleted. This has no effect on Visual Studio or the files currently in your VS Web Site or Project.

6.10. Keeping it Free

Remember to review the AppHarber policies. They are there to ensure in part that they can keep their free service free. As long as you never request an add-on or resource that costs money — AppHarbor will tell you if it costs money — then it’s free (given their current policies).

There are limits; your database can only grow to a certain size, and there are likely bandwidth limits for the amount of data going between your application and its users.

6.11. Debugging on the Internet

If you publish to Azure, then there are hooks to let you debug your web application in real time, as described here: https://azure.microsoft.com/en-us/documentation/articles/web-sites-dotnet-troubleshoot-visual-studio/

Since we are using AppHarbor, we have these choices:

  • expose errors as they happen in the deployed site

  • put output in our web page to show what is happening on the live server

  • use try/catch to trap exceptions so our pages work around the error

  • debug on the local machine (not the live server) with Visual Studio’s debugger

Note that AppHarbor offers you advice on this also here https://support.appharbor.com/kb/getting-started/frequently-asked-questions.

6.11.1. Expose errors as they happen in the deployed site

One of the differences between a Debug build and a Release build is that a Release build (which is what AppHarbor does) prevents clients from seeing stack traces that occur in your web application.

You can turn this back on, but should only use it for testing and turn it off in general in a deployed site.

If you see this page:

ah runtime error
Figure 17. AppHarbor default error page

Then follow its instructions to change your Web.config file, adding

<customErrors mode="Off"/>

within the <system.web> block within <configuration>.

In a live website, you would instead actually not turn the custom errors off, but add a custom error page that overrides the default AppHarbor custom error page (the one shown in the picture above). You may have seen this on another website, a typical error page displays the HTML error code and some sort of "oops" image.

6.11.2. Put output on a web page

You can gain quite a bit of information about the state of your web server using the object ServerInfo that is available to you.

Listing 13. ServerInfo.cshtml
<!DOCTYPE html>
<html>
    <head>
        <title>Server Info</title>
    </head>
    <body>
        @ServerInfo.GetHtml()
    </body>
</html>

the GetHTML generates a table that will provide you with information about the state of your server: environment variables, configuration, version, and much more. Do not use this on a production page that casual users can see, as it provides hackers with information they can use to break into the server and your application.

Caution

Do not use this on a production page that casual users can see, as it provides hackers with information they can use to break into the server and your application.

Rather than display global information, pick and choose what you display. You already know how to do this in the HTML and in a Razor code block (this same line works the same way in both):

<p>@totalServed</p>

This will display the value in the variable totalServed.

There is a shorthand in a Razor code block as well:

@{
  // code here
  ...

  @totalServed

  // code continues
  ...
}

This will also display the value, at that point in the code block. The @ tells Razor to put the current value of totalServed into the output stream. Since there is no HTML formatting around it, it is simply put there, so it will show up without formatting on your page.

This works with strings, numbers, and even objects — the ToString() method of non-strings is called to convert them to string values. Most objects just report on their type, which isn’t very useful. ASP.NET provides you with a useful helper, ObjectInfo, which will generate a string containing the type of the expression it is handed and its value.

Listing 14. DebugDemo.cshtml
<!DOCTYPE html>
<html>
    <head>
        <title>Debug Demo</title>
    </head>
    <body>
    @{
      var weekday = DateTime.Now.DayOfWeek;
      @ObjectInfo.Print(weekday)

      var message = "Hello, it's" + weekday;
    }
    @ObjectInfo.Print(DateTime.Now)

    @ObjectInfo.Print(message)

    </body>
</html>

The output HTML on a Friday afternoon in August was:

<!DOCTYPE html>
<html>
    <head>
        <title>Debug Demo</title>
    </head>
    <body>
    <p>DayOfWeek Friday<p>  (1) (2)
    <p>DateTime 8/23/2016 2:00:20 PM</p> (3)
    <p>string "Hello, it's Friday"</p>
    </body>
</html>
  1. If you view the Page Source, you will see quite a bit of generated styling using div’s, not simple paragraphs. ObjectInfo.Print colorizes its contents to hint at their difference, putting the type name in blue, strings in red, and so on.

  2. DayOfWeek is a C# enum, and Friday is one of its values.

  3. For non-strings, the ToString() is used to get the value for ObjectInfo.Print. The argument passed to it does not have to be a local variable — it can be a property or method or more complex expression.

You can use ObjectInfo.Print() with some very interesting objects such as Request and Response, like so: @ObjectInfo.Print(Request). They will print out complex information that exposes the internal workings of your website, so use them with caution on a live website.

Warning

If you start printing out values in a live website, be careful not to give away private information. You must protect data such as passwords and personal information. When we cover users, you will see how to restrict display to only administrative users, but even that should be done with caution. Once your information is in an HTTP response, anyone can "watch the wire" and see the information, unless you encode it.

6.11.3. Use try..catch

When a page hits an exception, the displayed page shows just the exception, not the HTML that was generated before it on the page. Sometimes it helps to be able to see what was happening before the exception was hit; try..catch can be used as a debugging tool to help you do this.

The try..catch block stops ASP.NET from turning the response into just an error message. Instead, you retain control on the page and can add your own error text to provide information that is useful to you.

@{
  try {
    // do a lot of math that you think should work
    ...

  }
  catch (DivideByZeroException ex ) {
    <p>Please report the following information to tech support:</p>
        <p>ex.Message</p>
        ObjectInfo.Print(someVar)
        ObjectInfo.Print(anotherVar)
        <p>Thank you</p>
  }

// Other code or markup here ...

}

Now when your page gets a DivideByZeroException, it is not halted, but will add the exception and the values of someVar and anotherVar to the output to help you determine the cause of the error.

When you use this approach, be careful about how the page behaves should the exception occur — execution will continue after the catch block, so your local variables need to hold values that will not trigger continued exceptions, or you will still have an exception result rather than a complete HTML page.

6.11.4. The Visual Studio debugger

When you run your web site locally on your development machine, you can debug it in Visual Studio. Its debugger lets you step through code, line by line, or from breakpoint to breakpoint, and inspect the value of local variables. You can drill into variables to look at their contents when they are complex objects.

you can set breakpoints on any C# code in your page. To do this, click in the gutter to the left of your code on the Visual Studio. If a red circle appears, then you have a "breakpoint". If no red circle appears, then either you didn’t hit the correct gutter (on mine it is the grey column left of the code) or the line is not actual C# code. You cannot set breakpoints on HTML-only lines, only those that the Razor Engine will evaluate.

Now, when you run your web site, it will stop at that breakpoint and a debug toolbar will be available to you. You can inspect variables by mousing over them to see their current contents. When you are ready to continue, use the debug tool bar to move to the next statement or to continue running the program until the next breakpoint.

debugtoolbar
Figure 19. Visual Studio debug toolbar

The "step into" item is highlighted: use that to move to the next statement. Use the "continue" item ( → ) to have your website run until another break point is hit.

For more information on the Visual Studio debugger, see Debugging in Visual Studio.

6.13. Exercises

  1. Pick a previous exercise and deploy it. Visit its pages on the internet.

  2. Then deploy a second application and visit it on the internet.

  3. Remove an application and its local git repo. Try to visit its page on the internet — it will no longer be there.

  4. Play "Stump The Newbie" with a classmate: make a page that runs but requires some debugging for your peer to fix. See what steps they take to determine the cause of the problem and how they fix it. Would you have looked for the problem differently, or fixed it differently?

6.14. Project

Deploy your prototype web application. Once you have a working deployment, get some friends or classmates to try it out, collect feedback from them, make changes, and re-deploy it.

7. C# Methods, Classes, and Objects

So far, C# looks very similar to JavaScript and Java. It is object-oriented, so it supports reusability through classes with methods and properties and polymorphism with inheritance, interfaces,and overloading. C# also introduces some unique and powerful features, such as delegates (type-safe function pointers) and lambda expressions (anonymous functions). There is a rich set of foundation classes provided in ASP.NET, the Foundation Class Library, providing collections, threads and locking, security, and much more.

Object oriented design requires defining a class and then giving it both class (static) properties and methods and object (instance) properties and methods. Instances of the class are called objects. Static properties and methods are shared by all of the instances — if one changes it, they all see the change. In fact, anyone who can see the class can see them (more on this in a bit). Each instance of the class gets its own copy to manipulate of the instance properties and methods in the class.

So far we’ve been playing fast and loose with static versus instance methods and properties; it’s time to clear that up:

  • When we call a method or access a property by dotting off of a local variable or a property (remember, DateTime.Now is a property), then we are calling the instance method or property for the object instance that variable holds. If we change the property value, then it only changes it for that instance.

  • When we call a method or access a property by dotting off of a class name (DateTime and Math are class names), then we are calling the static method or property of the class — there is only one copy of that property or method, and it’s visible to us. If we change the property value, then everyone who accesses that property sees the change.

DateTime.Now.Month accesses the Month property of the instance stored in the Now property of the DateTime class. Math.Sqrt(9) accesses the static method Sqrt on the Math class.

How do we tell which ones are static versus instance? As you will see as we introduce the language structures, the keyword static is used on static properties and methods, and no such keyword is used on instance properties and methods.

Let’s look at methods first, then classes and their properties and methods.

7.1. Methods

So far we’ve only written short blocks of code in our web pages. In this chapter, we’ll show you how to organize more complex code and make code reusable, using methods and classes.

A method is a collection of code with a name and some inputs; it may or may not produce an output, and it may also alter the state of the object and of any objects it has access to. Because we can give it inputs, the method can change its action based on the values it is given. If the method returns a value, our program gets the value when the method completes.

Methods provide the behaviors for a class or an object; typically these are things the class or instance will want to do repeatedly. Rather than have a huge method for a complex action, we may also define smaller methods that are called by other methods. Each method should have one clear action that it performs.

Methods can be used over and over, at different places in the program. A method can even be used inside another method. This allows you to write simple methods and then use them to help write more complex methods, which can then be used in turn in other methods. In this way, very complex programs can be built up step-by-step, where each step in the construction is reasonably simple.

7.1.1. Adding methods to a page

Razor provides a way for us to put server-side code in a web page. There is a special Razor block for adding methods to the web page, @functions { .. }. This block has to contain pure C#, no embedded HTML is permitted; this keeps the Razor engine simpler, and Razor provides Helpers, a similar tool, to create re-usable code blocks that do contain embedded HTML.

Razor’s @functions are methods. We’ve mentioned earlier that your page is an object; in fact, there is a class for it, and each user who accesses your page gets an instance of that class. The @functions that you define are methods in that class.

Here is a function block containing functions to compute a tip amount:

@functions {
    double ComputeTip(double subtotal, double tipRate) {
        double tip;

        tip = subtotal * tipRate;

        return tip;
    }

}

Notice that this is computing just the tip — it is important to clearly document what your method is doing, so that those who use it can tell what it is doing. We see this with Math.Sin and the other trigonometric functions: they clarify that they work on radian values, not degrees. There are tools that will turn the comments on your methods into such documentation, so be sure to clearly document the assumptions your method makes and the computation it performs. Not everyone will have access to your source code.

Let’s pull apart the function above: double ComputeTip specifies that this method will return a value of type double, and that its name is ComputeTip. If it did not return a value, its return type would be the non-type void. Notice the keyword static did not appear — that makes this an instance method. Instance methods are mainly needed if they change the object state, and you may be able to determine that this one does not change the object state: it computes a value based solely on its inputs. It could have been defined static.

Notice that the C# convention is that method names start with an initial uppercase letter and parameter names start with an initial lowercase letter.

Next we see (double subtotal, double tipRate). The parentheses tell the compiler "I am giving you the parameters now", and are needed even if your method has no parameters. Each parameter is specified with a type and a name. The name becomes a local variable that we can use inside the method. When the method is called, the argument value is computed and then copied into the parameter for use within the method. The parameter’s value is never copied back out to the caller, so any changes to it will not be seen by the caller.

A parameter’s scope is the method it is defined within. Parameters behave like variables, so no variable within a method can have the same name as a parameter.

Finally, we see { .. } — this looks like our Razor code block. It is the body of the method. It can only contain C#, Razor does not permit HTML lines within a method.

Within the code block, you may notice a statement you have not seen before: the return statement: return tip;. The syntax for this statement is:

    return EXPRESSION;

When that statement is seen within a method, the EXPRESSION is evaluated and the method is exited, with the value of the expression returned to the caller. This happens no matter where the return is within the method; if it is within a for loop or a switch statement, execution of the method halts at that point, and the value is returned to the caller.

Void methods (those not returning values) can use a return; statement to return control to the caller, or will return control when the closing } is reached, if there was no explicit return statement.

You can include additional methods in the @functions { } block; and because of how Razor processes it, the functions can appear anywhere in the page and be called even before they appear. By convention, we will place them at the top, before they are used.

You can invoke the same method more than once, and you can have one method invoke another. A method can even invoke itself.

subTotal += ComputeTip(subTotal,chosenRate); (1)
total = subTotal + ComputeTax(subTotal,locationCode); (2)
  1. In the code above, you see that subTotal is passed to ComputeTip, and the result is added to subTotal and put back into the subTotal local variable.

  2. Next you see that the tax is computed using the new value of subTotal and a location code for looking up tax rates, and added to subTotal to compute the total amount.

We see that two different methods are called and used in the code above. Notice that the methods are not executed when the @functions { } block is seen; rather, they are executed when the are called from other C# code. This is called the flow of execution. It’s important to keep this in mind; if you never call a method, then it is never executed.

Beginners often wonder why it is worth the trouble to create new methods. There are many reasons, here are a few of them:

  • Creating a new method gives you an opportunity to give a name to a group of statements, which makes code easier to read and understand.

  • Introducing new methods can make a program smaller by eliminating repetitive code. For example, we can compute the tip amount based on the value the user gave us without a separate computation for each specific amount.

  • A common problem solving technique is to break tasks down into sub-problems. Methods allow you to focus on each sub-problem in isolation, and then compose them into a complete solution.

7.1.2. Parameters and Arguments

Some of the methods we have used require arguments, which are the values you provide when you invoke the method. For example, to take a substring, you provide the starting and stopping locations with in the string value.

When you use a method, you provide the arguments. When you write a method, you name the parameters. The parameter list indicates what arguments are required. The following code shows an example:

@functions {

    // Put the first letter at the end and add "ay"
    string PigLatin(string word) {
        return word.Substring(1,word.Length-1)+word[0]+"ay";
    }
}

// form to get a word from the user

<p>@PigLatin("Hello") @PigLatin("There"), in Pig Latin your word is: @PigLatin(yourWord).</p>

PigLatin has a parameter named word with type string. When we call PigLatin, we have to provide an argument with type string. This can be a variable, a string literal, another method call (for a method that also returns a string), or an expression which evaluates to a string. In our example, we’ve called it three times: twice with string literals, and once with a local variable.

Before the method executes, the argument gets assigned to the parameter. In this example, the argument "Hello" gets assigned to the parameter word for the first call to PigLatin. In each subsequent call, the value of the argument is assigned to word in turn.

This process is called parameter passing because the value gets passed from outside the method to the inside. An argument can be any kind of expression, so this works also:

@PigLatin(yourWord+"s");

Here the word you supplied has an s added to the end before that value is assigned to the parameter named word. The value you provide as an argument must have the same type as the parameter. So if your word was "round", word get the value "rounds" assigned to it.

The value you supply has to be a string. For example, if you try:

 @PigLatin(17);  // syntax error

You will get an error message like this:

PigLatin.cshtml(25,10): error CS1502: The best overloaded method match for 'ASP._Page_PigLatin_cshtml.PigLatin(string)' has some invalid arguments
PigLatin.cshtml(25,19): error CS1503: Argument 1: cannot convert from 'int' to 'string'

The first error message is letting you know the compiler tried to find any method named PigLatin that will work (you can define two methods with the same name — more on this in a bit). The second one is more useful: it’s telling you your argument has the wrong type.

Sometimes C# can convert an argument from one type to another automatically. For example, Math.Sqrt requires a double, but if you invoke Math.Sqrt(25), the integer value 25 is automatically converted to the floating-point value 25.0. But in the case of PigLatin, C# can’t (or won’t) convert the integer 17 to a string.

Parameters and other variables only exist inside their own methods. Inside your page, there is no variable named word. If you try to use it there, you’ll get a compiler error.

Because variables and parameters only exist inside the methods where they are defined, they are often called local variables.

7.1.3. Named Parameters and Optional Arguments

You may have noticed an issue with our pig latin implementation: PigLatin("There") returns the value hereTay when it should return the value ereThay, since "Th" is the first sound-unit in the word.

Usually only one letter is needed; so we could require a length, but that makes everything work harder. C# solves this by offering us default parameters. You can specify a default value for a parameter, and if it is not specified, its default value is used.

To make this work, C# also lets you specify a name next to an argument value, to say what parameter the value is for. Let’s rewrite our code and see how this works:

@functions {

    // Put the first letter at the end and add "ay"
    // if the length gives us nonsense, ignore it and return the word
    string PigLatin(string word, int numChars = 1) {
        if (numChars < 1 || numChars > (word.Length-1)) {
            return word; // just return the word on bad lengths
        }

        return word.Substring(numChars,word.Length-numChars)
               + word.Substring(0,numChars)
               + "ay";
    }
}

// form to get a word from the user

<p>@PigLatin("Hello") @PigLatin("There",2), in Pig Latin your word is: @PigLatin(word: yourWord).</p>

Because we have given a default value for numChars, if it is not specified then when the method executes it is given the value 1. We say that numChars is an optional argument.

Notice the final call: @PigLatin(word: yourWord). Here we use the parameter name and a colon to say what parameter the argument value is assigned to. With named parameters, we don’t have to match the order specified in the method. We could say: @PigLatin(numChars:2, word:"cheese"). C# will match up the arguments to the named parameters, rather than using their positions.

If you do not specify parameter names on the method invocation, then positional matching is done. C# lets you use positional matching for the start of a method call, but once you use a named parameter, then you have to name the rest of your arguments as well. Any unnamed or unspecified parameters in the method call must have defaults, and those defaults will be used when the method is invoked.

Tip

Notice that I took care in writing the new version of PigLatin to deal with bad input values. I also stated how I handled them in the comments on the method. Consider what inputs can make your method mis-behave, and determine what behavior you want it to have. Here are some typical choices:

  1. just let it do whatever C# would have it do, whether that is to throw an exception or continue on with a corrupt value (sometimes this is the right thing to do, but it should still be made clear that it was a decision made in your design)

  2. throw an explicit exception about the bad input values (this informs the caller about specifically what went wrong, and lets the caller decide how to handle it)

  3. handle the situation so that the program continues with some known good state (this lets the program continue uninterrupted, but does mask the problem of the bad inputs)

C# has another type of variable parameter list, for details on that see https://msdn.microsoft.com/en-us/library/w5zay9db.aspx.

7.1.4. Parameters and Objects

C# uses pass by value for parameters: the argument value is copied into the parameter value, and no changes to the parameter’s value are ever seen by the caller. However, if you go through a parameter to values it has access to (if it is an object or an array), then the changes you make through the parameter will be visible to the caller.

With arrays, this means that you can change the contents of the array, and the caller will see those changes.However, if your method changes the parameter’s value, to point to a new array, that change will not be seen by the caller.

Caution

C# also provides two other parameter modes: pass by reference and pass as output.

"pass by reference" on parameters means that changes to them are seen; this is done by putting the keyword ref before the parameter type. When used, the keyword ref must be put before the argument as well, and it must be a storage location (something that can be on the left of an assignment statement). Any changes to the parameter’s contents will be visible to the caller.

"pass as output" on parameters means that the values are not read in from the arguments, but are only assigned within the method and then visible upon return. out must be put both on the parameter declaration and the argument value. The argument will not be read or copied to the parameter when the method is called, but they will be updated with the value of the parameter when the method completes.

This isn’t generally good practice in OO programming, but does give fine-grained control that is useful in procedural systems programming.

7.1.5. the call stack

When a method is called, it needs space for its parameters. The system notes where it was called from (the calling method’s activation record). It creates an activation record with room for the methods parameters, and puts that on the activation record stack, often just called the "call stack", as its primary contents are method invocations.

When the method completes, its activation record is removed from the stack; if it had a return value, that is supplied to the calling method for that method to use in the containing expression.

Let’s step through an example with these methods:

int Times2(int val) {
  return val*2;
}

int Times10(int val) {
  return val * Times2(5);
}

int TImes20(int val) {
  return val * Times10(2);
}

When Times20(4) is called, an activation record is put on the top of the stack to hold the fact that Times20 is called, and its parameter val is given the value 4, from the argument value.

Times20(4) will call Times10(2); this creates a new activation record which is put on top. Times10(2) will call Times2(5). At this point the call stack looks like this:

top of stack

Times2(5) val = 5

Times10(2) val = 2

Times20(4) val = 4

…​ calls below Times20(4)

bottom of stack

When Times2(5) completes, it is removed from the call stack and returns the value 10 to its caller (Times10(2)), who then uses it to compute val * 10, using its own value of val, i.e. 2. That then removes itself from the call stack, returning its value, 20, to Times20(4). That then removes itself from the call stack, using the returned 20 and its value of val, 4, to compute 80; it then removes itself from the call stack and returns 80 to its caller.

It’s important to be able to draw call stacks and trace the values in variables — a key style of debugging is the "code walkthrough" where you are the computer, checking that the code is doing what you expect with a manual walkthrough yourself rather than running the code.

7.1.6. method syntax

A method is defined in a class; since our Razor pages are turned into classes, it provides us with the @functions { .. } block to permit us to do this. We can also put methods in classes, as we will see in the next section.

A method definition in C# takes the form:

modifiers  return-type  method-name  ( parameter-list ) {
    statements
}

The statements between the braces, { and }, in a method definition make up the body of the method. These statements are the instructions that the computer executes when the method is called. Methods can contain any of the statements discussed previously.

The modifiers that can occur at the beginning of a method definition are words that set certain characteristics of the method, such as whether it is static or not. Another modifier that can be specified is the visibility of the method, one of these:

public

the method can be called from anywhere.

private

the method is only visible within the class, so it can only be called from other methods in the same class.

protected

the method is only visible to its class, or from a subclass of this class.

internal

the method is only visible from within the same project. This limits callers to just your library, if you were building a library and wanted some internal utility methods.

protected internal

the method is visible from this class, any subclasses (even if in another project), and any other class in the same project.

If you do not specify a visibility for your method, then its visibility is private . Since you do not explicitly access the page class for your Razor page, and won’t need to access the methods outside of the page, this is appropriate.

For the full list of modifiers, some of which are beyond the scope of this text, see https://msdn.microsoft.com/en-us/library/ms173121.aspx.

If the method computes a value, then the return-type is used to specify the type of value that is returned by the function. It can be a type name such as string, an array type such as double[], or a Class - any valid C# type. If the method does not return a value, then the return-type is replaced by the special value void, which indicates that no value is returned. The term "void" is meant to indicate that the return value is empty or non-existent.

Finally, we come to the parameter-list of the method. Parameters represent information that is passed into the method from outside, to be used by the method’s internal computations. The parameter list in a subroutine can be empty, or it can consist of one or more parameter declarations of the form parameter-modifier type parameter-name optional-default-value. If there are several declarations, they are separated by commas. Note that each declaration can name only one parameter. For example, if you want two parameters of type double, you have to say "double x, double y", rather than "double x, y".

parameter-modifier

is optional and specifies either pass by value (no modifier), pass by reference (ref), or pass as output (out). ref and out have to be used as prefixes to argument values as well.

type

any valid C# type can be used as a parameter type.

optional-default-value

is specified as = constant-value, providing a default value if no argument value is provided for this parameter. The constant value can be a literal or a constant expression (something the compiler can evaluate).

Tip

You may also see methods with abbreviated bodies such as this:

public string Name => First + " " + Last;

Here, the method Name has no parameters, and returns the value computed using the properties First and Last from the containing class.

These are Expression Body Definitions, and you can read more about them here: https://msdn.microsoft.com/en-us/library/ms173114.aspx

7.1.7. Helpers

Razor has a feature not found in C# classes, the helper. This is a type of function that embeds HTML within it, the same way we have already done in our Razor code blocks. You define one helper at a time, like so:

@helper HelperName (parameters) {
  .. helper body ..
}

Then you can invoke the helper with @HelperName(arguments) later in your Razor page. The helper body can contain the same code as any other Razor block, that is, it can contain both C# and HTML.

When you invoke the helper, it is replaced with the HTML that its helper body generates. You do not use a return statement in a helper.

For example:

@helper OperatorList() {
      <option value="add">+</option>
      <option value="sub">-</option>
      <option value="mul">*</option>
      <option value="div">/</option>
      <option value="mod">%</option>
}

<form ...>

...
<select name="op1">@OperatorList</select>
...
<select name="op2">@OperatorList</select>
...

</form>

Here you can see we have a helper that will put the same list of operators wherever it is used. This helps us keep our page correct — if we need to change the list, we only change it once, and that is seen everywhere the list is used.

7.2. Classes

Classes are what make object orientation so rich; they provide many, many capabilities. We’ve already seen methods, but there are properties also, and many aspects of classes to fulfill the OO features of inheritance, encapsulation, and overloading.

You will define each class in its own file with the file extension .cs. To make your source code deployable, put these files in the App_Code directory of your project. ASP.NET looks to that directory to compile code.

What code goes in a class, versus in Razor functions? Object-oriented design says that you design a class when you want to have the ability to use the functionality from different pages in your web site. So if you have common functionality that several of your pages use, you would define a class for it, and then use the class’s methods and properties to access the functionality.

Remember to be DRY : if you find yourself repeating code, then methods and classes are called for.

7.2.1. Classes live in Namespaces

Namespaces give you a way to group classes into logical groups. You place a class within a namespace when you define the class, like so:

namespace Storage {

  // class definitions here

}

Typically you put one class in a file; this means you put the namespace clause around it in that file. You use the same namespace clause in each of your files containing classes in that namespace.

If you do not use a namespace clause, your class is put into the default, unnamed, namespace. Although this is not good practice, you will often see this done in learn-to-program situations. A general convention is to put your code in a namespace that matches your project name, and then to further organize it into multi-level namespaces to separate your code into logical groups.

The namespace name can have multiple parts separated by dots, i.e. Storage.Binary, Storage.Text, and Storage.Text.Utc are all valid namespace names.

By convention, you build a directory structure that matches your namespace names; where namespaces use . to separate the name, you make another level of directories. Your classes go in the lowest directory. So, if the namespace Storage.Text.Utc had a class UtcUtilities, you would see this directory structure:

NamespaceSample
Figure 20. Namespace Directory Hierarchy
Tip

Namespaces, like classes and methods, start with an Uppercase letter. This is a coding convention, not a requirement.

Notice another convention here: CamelCase even applies to acronynms like UTC — in a C# name, we write it as Utc. Similarly, HTML becomes Html when used in a C# name. This convention may seem grating, but if you want your code to appear professional, it’s best to follow the convention.

You can decide if the class ought to be visible outside of its assembly by setting an access modifier on it; these are similar to the ones for methods:

  • public : visible outside of its assembly

  • internal : only visible within its assembly (the default)

internal, the default, is sufficient for our needs.

Tip

What’s an assembly? it’s whatever code was assembled for your application. We aren’t building cross-assembly projects here, but we do use ASP.NET: everything from that that we use had to have been declared public.

Once you have classes within namespaces, you can then decide how to access them outside of their namespaces. In order to access a class from another Namespace without qualifying it by its namespace name, you add a using statement to the top of your .cs file, before the namespace clause:

using System.Collections;
using System.Web.WebMail;

namespace Storage {

  // class definitions here

}

The using statement lets you reference classes within that namespace without qualifing them. It does not let you reference nested namespaces — you have to explicitly add a using statement for each nested namespace to use its classes without qualification.

You can put any number of using statements at the top of your file, or even within the namespace clause. If they define classes that have the same names, references to those names are considered ambiguous; C# has ways to resolve this, the simplest is to fully qualify those names. If your using namespace contains a class by the same name as your class, the class you are defining is the one used.

For other ways to resolve ambiguous class names, see https://msdn.microsoft.com/en-us/library/aa664766(v=vs.71).aspx

7.2.2. Classes define Methods

We’ve already stepped through method definitions; methods are placed within a class, and can operate either as static methods, called by dotting off of the class name, or as instance methods, called by dotting off of a variable or property referencing an object of the class type.

namespace Utilities {

  /// methods to manipulate strings
  public class StringUtilities {

      /// returns the word turned into pig latin
      /// assumes the word is a word (not more than one word)
      public static string PigLatin(string word) {
          ...
      }
  }

}

Here we have put our PigLatin method in a class called StringUtilities, in a namespace called Utilities. So we can invoke the method like so:

    string result = Utilities.StringUtilities.PigLatin("hello");

Because it is a static method, we dot off of the class name.

7.2.3. Constructors: how Classes create Objects

How would we call an instance method? First, we need to be able to create instances of the class. We saw an early example of this with Random, where we created a new Random object by saying new Random(). This was actually using something in the class: the constructor.

A constructor is a special code block (you may hear it called a "special method", as it looks like a method) defined in the class to say what steps to take when a new instance is created. For instance, you may want to initialize the instance’s properties or you may want to require certain information be provided when instances are created.

You define a constructor in the same manner as a method except that it has no return type, and the name is the same as the class name. It also has no return statement — it can only be used within a new statement, to create an instance of the class.

public class Car
{
    string model;

    public Car()
    {
        model = "Ford";
    }
}
Note

Yes, I did sneak a variable definition into the class; they are allowed in class bodies, too; more on this in a bit.

If you do not define a constructor, then a class implicitly has one that takes no arguments, and initializes any class variables to their default values (0, false, or null).

If you define a constructor that takes parameters, then there is no longer a default constructor. You can define as many constructors for a class as you like; they must all take different parameter types or a different number of parameters.

public class Car
{
    string model;

    public Car()
    {
        this("Ford"); // "call" the other constructor; you can only call
                     // constructors from other constructors, and you use the
                     // special 'method' name `this` to do it.
                     // It's good practice to call the more specific
                     // constructor, supplying defaults.
                     // This avoids duplicating code between constructors.
    }

    public Car(string m)
    {
        model = m;
    }
}

If you do not want instances of the class created, then you can define a 0-arg constructor that is private; this hides the construtor from any other class. We might do this in our StringUtilities class to prevent anyone from creating instances, since it only defines static methods:

public class StringUtilities
{
    private StringUtilities() { } // no instances can be created

    ... static methods here
}

In order to create an instance of a class (an object), you have to know what constructor(s) it has. You create the instance with a new operator, passing the values the constructor requires.

  Car myCar = new Car();
  Car myDaughtersCar = new Car("Volkswagon");

The new operator takes a class name and constructor arguments and returns a new object that has been created and initialized by the constructor. That new object can be:

  1. stored in a variable (as our example)

  2. stored in an array of that object’s class

  3. stored in a Property of that object’s class

  DateTime[] importantDates = {
    new DateTime(1944,1,1), // first computer
    new DateTime(1991,8,6) // first web server
  };

Here we initialize an array with two objects.

Tip

That’s handy, but what about the class — perhaps we want to initialize the static properties. You can define a static initializer in a class like so:

class CalendarEvent {

    static DateTime calendarStarted;

    static {
        calendarStarted = DateTime.Now;
    }
}

In this code, we have a private variable in the class and we initialize it to the current system time when the class is loaded. It captures the time the calendar was started in our application.

7.2.4. Objects: where are they?

Objects are pretty complex entities. As such, it’s important to understand that what is in the variable, array entry, or property is not the mass of the object but is an object reference. Objects are located in a separate part of your computer’s memory usually called the heap. The address of your object is what is stored in the variable, array entry, or property. We call this an object reference.

So, if two variables are assigned the same object, then changes to the object in one variable are seen by the other variable. But we need properties to show this more clearly, so let’s return to this in a bit.

7.2.5. Classes define Variables and Properties

Classes get their power from having not only methods, to implement common behaviors, but also by having properties, to store state.

Properties can be at the class level: static; or they can be at the object level: instance.

C# does a very nice job of separating the idea of a property from another idea, that of a variable.

Properties are the visible state of the object.

Class local variables (aka fields)

I hinted above that you can have variables defined directly in your class. Static variables are defined for the class (so all instances share them) and instance variables are defined for instances (so each instance has its own instance of the local variable, the other instances get their own).

These are defined just like those in code blocks:

class Car
{
    string model;
    int odometer;
    int gallons;

    ... rest of class here
}

Here we see we define three variables in the class; these are not defined static, so when an object is created, it gets its own three variables local to it. All of its methods can see these variables; they are primarily used as a way to track the object’s properties.

You could make these variables available outside of the class by giving them an access modifier. Variables use the same access modifiers as methods, and their default is also private.

Tip

It is not good practice to give outside access to class variables; proeprties should be used instead. For this reason, by convention a class’s variables are initial lower case like other local variables and are private.

Properties

Properties define state. Static properties define the class state (like Now on DateTime) and instance properties define the object state (like Month on DateTime).

Poperties are defined like this:

class Car
{
    string model;
    int odometer;
    int gallons;

    public int Model {
        get { return model; }
        set { model = value; }
    }

    public double MilesPerGallon {
        get { return odometer/(double)gallons; }
    }

    ... rest of the class
}

Properties define their visibility, type, and name, and then provide their get and set operations. The get operation is used whenever you access the property in an expression, and the set operation is used whenever you have the property as the target of an assignment statement.

As you can see in our example, Model is very simple: it simply reads from the instance variable model, and writes to it (value is a keyword in C#, meaning the value of the right side of the assignment statement). However, MilesPerGallon only has a get operation, and that is computed from two of the instance variables. This means that MilesPerGallon cannot be the target of an assignment statement.

You can put access modifiers on the get and set code blocks; this is useful if you want those who use your class to get it, but only make it settable within the class. You will see this in StatClass.cs in the exercises.

Since the style of property that directly reads and writes it underlying variable is so common, C# defines a shorthand to do both at the same time:

class Car {
    int odometer;
    int gallons;

    public int Model { get; set; }

    public double MilesPerGallon {
        get { return odometer/(double)gallons; }
    }

    ... rest of the class
}

Notice that we don’t have to define the variable separately.

Caution

This clear definition of properties is a very clever feature of C#. You often want to "gate" property access with security levels, and ensure that assignments only get valid values. By using code blocks, you can make sure your properties are correctly accessed and updated.

Properties, like methods and variables, can have access modifiers. They, like other class contents, are private by default. When you want a property to be visible state of the class (static) or object (instance), you need to make it public.

For more on C# Properties see Properties (C# Programming Guide).

7.3. Objects

Now that we have classes, how do we use them?

Let’s define one for our examples with objects:

class CalendarEntry {

    static const Date OldestYearPermitted = new Date(1900,0,0);

    DateTime date;

    public CalendarEntry(Date d, string e) {
        EventDate = d;
        Event = e;
    }

    public string Event { get; set; }

    public DateTime EventDate {

        get {
            return date;
        }

        set {
            // Check boundaries for dates.
            if (value.Year > 1900 && value.Year <= DateTime.Today.Year) {
                date = value;
            } else {
                throw new ArgumentOutOfRangeException();
            }
        }
    }
}
Note

Notice the order of defintions in CalendarEntry. Any order is allowed, but by convention we put them in this order:

  • constants (variables defined static const cannot change value and are available to the class and all instances).

  • static variables

  • instance variables

  • constructors

  • public methods (static and then instance)

  • private methods (static and then instance)

  • destructors

7.3.1. The new expression creates instances

When we want to create a CalendarEntry instance, we use a new expression. Because it has defined a constructor, there is no default constructor; this forces us to provide values for the object’s properties.

 CalendarEntry internetBirthday =
       new CalendarEntry(
           new DateTime(1991,8,6),"internet's birthday");

Notice that we had to create a DateTime object to put in the EventDate property, used when we create the CalendarEntry instance, which is then put into the local variable internetBirthday.

This is what that looks like conceptually.

internetBirthdayHeap

We have two objects on the heap, and the local variable within its scope (which may be a method or a class).

There is a shorthand way to create and initialize an object when its class has only a default or no-argument constructor:

    new DateTime{ Year = 1901, Month = 6, Day = 30 }

This creates a new instance and then updates its properties to the supplied values. The example here shows DateTime with three of its properties being initialized. Any uninitialized properties are set to default values (0, false, or null).

7.3.2. The null value

Now, you might not always have an object; what do you do then? C# provides a special value, null. This can be assigned to any variable or property that holds an object. If you recall, arrays are actually objects — so any variable that holds an array can also be set to null.

Tip

You can turn any primitive type to one that can also hold a null; do this by delaring the variable with a ? after the type. This does require more storage space for the variable.

Tip

The ?? operator is a shorthand way to check nullability: x ?? y has the result y if x is null, and x if it is not null.

Because variables can hold this value, if you try to look at a property or invoke a method on an object when there is no object (the value is null), you will get a NullReferenceException. Usually this is a defect in your code — you should always check for nulls and then determine appropriate handling, whether it is raising an exception or taking a substitute action.

7.3.3. this

Notice that we have accessed the instance variables, methods, and properties directly by name within the class, while outside the class you have to dot off of a local variable to access them. There is an implicit local variable always available within the methods of your class, named this. this refers to the current object that the method or property is being invoked upon. Within the class definition, if the reference is not ambiguous, this is optional.

For CalendarEntry, I could have written the constructor like this:

    public CalendarEntry(Date d, string e) {
        this.EventDate = d;
        this.Event = e;
    }

The optional this. has been put in front of each of the properties having values assigned. When the properties' set code blocks are executed, they are executed against the current object, this.

7.3.4. Objects as parameters

Notice that variables hold references to objects. When you change a property in that object, it makes the change on the heap.

That means if two different variables hold references to the same object, each will see changes the other made.

    DateTime internetBirthdate = new DateTime(1990,8,6);
    DateTime firstWebPageServed = internetBirthday; (1)
    firstWebPageServed.Day = 7;
  1. Notice that the object reference is copied from internetBirthdate to firstWebPageServed. So both refer to the same object on the heap. When the Day property of one is changed, it changes it on the heap: so the change is immediately visible to the other variable as well.

TwoVarsOneObj
Figure 21. Two Variables Reference the same Object

That also means if a variable passes its value to a parameter, and the method makes changes to the object through the parameter, they will be visible to the variable after the call completes.

The only way to have that not happen is to ensure the variables point to different objects on the heap, using a separate new for each one. Even if they have the same property values, there will be two distinct instances on the heap.

7.3.5. But wait, won’t memory fill up?

It would, yes, if all we did was`new` all day. However, the system is watching everything we do (in this case, the system is the ASP.NET CLR engine that is running our compiled code). In particular, it keaps track of whether we have a variable or property referencing an object or not. Once no variable or property references an object, it can be thrown out, and its memory made available back to the heap. This is called "garbage collection".

7.3.6. Boxing and Unboxing

I already mentioned the nullable attribute for the primitive types; but that is not always sufficient; sometimes, you have to have an Object rather than a primitive type.

In fact, each of the C# primitives maps to a specific ASP.NET Class, as shown in the following table.

Table 4. C# type and .NET class
C# Type .NET Framework Type

bool

System.Boolean

byte

System.Byte

sbyte

System.SByte

char

System.Char

decimal

System.Decimal

double

System.Double

float

System.Single

int

System.Int32

uint

System.UInt32

long

System.Int64

ulong

System.UInt64

object

System.Object

short

System.Int16

ushort

System.UInt16

string

System.String

This means if you declare a parameter with the .NET type, and use a variable or expression that results in the C# type, that value will be boxed within an object of the .NET type. Similarly, if you use of the thes .NET types in an expression where the C# type is needed, it will be automatically unboxed and its value used; note that a null value in this situation will be handled according to how the variable was defined: if it’s nullable, it takes the null. Otherwise, it raises a *NullReferenceException`.

  int currentDay = 26;
  Int32 tomorrow = currentDay + 1; (1)

  ... time passes

  currentDay = tomorrow; (2)
  tomorrow = currentDay + 1; (1)
  1. currentDay is an int, so it can be added to 1 and will result in an int. The target of the assignment statement is a Int32 so that result will have to be boxed; it would be the same as saying: Int 32 tomorrow = new Int32(currentDay + 1); We don’t have to explicitly use the new, as our int value result will be wrapped in an Int32 to automatically box the primitive with object-ness. (We could call this boxing’s object-ive. Couldn’t resist.)

  2. When we want to assign an Int32 to an int, the reverse has to happen. The int value within the Int32 is unboxed, and its value is copied into the variable. Because this behavior is specific to each particular target type, there is no single method that is called to do it.

You may have noticed the type object in our list above; objects can hold any item at all; if they are assigned a primitive from a local variable, they will box it. To unbox from an object, you have to first typecast it down to the appropriate primitive type.

  int currentDay = 26;
  object objectDay = currentDay; // boxed, put in the heap

  currentDay = (int)objectDay; // to get it back out

Similarly, you can put any object instance in an object. But to see it as its original class, you will have to typecast it back to that class. As an object, the methods specific to your class are not accessible.

  DateTime internetBirthday = new DateTime(1991,8,6);
  object something = internetBirthday; // copies the object reference,
                                       // but loses its DateTime-ness

  internetBirthday = (DateTime)something; // transform it back
Note

Boxing and Unboxing have a huge impact on performance, so it is best to be aware of when you have the C# type and when you have the .NET class. In general, stick with the C# types unless there’s no way to avoid using the .NET types.

7.4. Inheritance

The object built-in type hints at a key object-orientation feature: inheritance.

Class definitions are a good start at smart programming, as they modularize our code into understandable units with state and behavior.

We get an even stronger amount of re-use when one class can be a subclass of another class: that is, it inherits all of the fields, properties, and methods and then adds more.

Often you need classes that differ only a little bit; either one can be the supertype of the other, or they have a common supertype and they are both its subclasses.

The keyword extends is used to note that a class has a superclass, like so:

class CalendarRepeatingEntry extends CalendarEntry {
    Public int NumRepeats { get; set; }

    ... more added to class
}

All of the public methods, properties and variables in CalendarEntry are now available to CalendarRepeatingEntry and its instances. So it not only has NumRepeats but also has EventDate and Event.

If you do not specify extends, then your class automatically extends System.Object.

The method, property, and variable access modifiers may make more sense at this point, now that you have seen inheritance:

public

the method can be called from anywhere.

private

the method is only visible within the class, so it can only be called from other methods in the same class.

protected

the method is only visible to its class, or from a subclass of this class.

internal

the method is only visible from within the same project. This limits callers to just your library, if you were building a library and wanted some internal utility methods.

protected internal

the method is visible from this class, any subclasses (even if in another project), and any other class in the same project.

If you do not specify a visibility for a method, property, or variable then its visibility is private . If you do not specify a visibliity for a class, then its visibility is internal.

If you have a class and you do not want anyone to create a subclass of it, you add the class modifier sealed prior to the class name.

7.4.1. Impact on types

We can assign any instance to an object variable because object is the superclass of all other classes. In fact, for any variable defined to hold a particular class, we can assign not only instances of that class but also instances of its subclasses. Basically, an object instance is an instance of its immediate class and also an instance of its superclasses. Each class has one single immediate superclass, except object (and System.Object, the same class), which has no superclass.

Let’s walk through an example:

 CalendarEntry internetBirthday;

 RepeatingCalendarEntry internetParty =
       new RepeatingCalendarEntry {
           EntryDate = newDateTime(1991,8,6),
           Entry = "Internet's Party",
           NumRepeats = 100 };

 internetBirthday = internetParty; // OK
 internetParty.NumRepeats = 101; // OK
 internetBirthday.NumRepeats = 102; // ERROR

 internetParty = internetBirthday; // ERROR
 internetParty = (RepeatingCalendarEntry) internetBirthday; // OK but...

 CalendarEvent tcpBirthday = new CalendarEvent(
       newDateTime(1983,1,1),"TCP's Ratification Date");

 RepeatingCalendarEntry tcpParty;

 tcpParty = tcpBirthday; // ERROR

When we assign internetParty to internetBirthday, this works. Any access of the object through that variable (internetBirthday) will assume it is a CalendarEntry, and not a RepeatingCalendarEntry. This means that we can’t access NumRepeats through internetBirthday, since it is hidden by the implicit cast to be just CalendarEvent.

The other direction is worse: when we try to assign a CalendarEvent instance to a RepeatingCalendarEvent variable, we can’t do it at all. Why not? because there is no NumRepeats property in our CalendarEvent instance.

If we know we have a RepeatingCalendarEvent in our CalendarEvent variable, we can typecast it back to a RepeatingCalendarEvent. Now, our "know" may actually be riddled with bugs, and a CalendarEvent object may have snuck into our variable; the execution engine does a final type check at runtime, and if the type cannot be cast because it is not actually a RepeatingCalendarEvent, then a InvalidCastException is thrown.

7.5. Overloading and Overriding

You may have noticed, if you have been looking at MSDN ASP.NET class specifications, that they often have methods with the same name but different parameter lists (a different number of parameters, or a different type parameter at a particular position in the list). This is called overloading a method with multiple implementations. When you call a method, method resolution occurs based on the arguments specified; their types have to match the types declared for one of the overloaded methods. That will be the method called.

For example:

namespace System;

class StringUtilities {

    static public char FirstLetter (long i) {
     .... determines the first letter of a short, int, or long
     return i.ToString()[0];
    }

    ststic public char FirstLetter (string s) {
     return s[0];
    }
}

Our class defines two FirstLetter methods, one that operates on longs (and thus, due to automatic conversion, will also work on ints and shorts — this type of widening of parameters is a common design choice) and one that operates on strings.

When used, the type of the argument is used to determine which method to call:

    char firstOfOne = StringUtilities.FirstLetter(1); // returns '1'
    char firstOfOne = StringUtilities.FirstLetter("hello"); // returns 'h'

The first call resolves to FirstLetter(long i) while the second call resolves to FirstLetter(string s). Notice that both return the same type — that is required in overloaded methods.

You saw overloading at work in our constructor; you can define more than one constructor as long as the type or number of parameters differs.

For more on overloading, including how it is resolved with named parameters, see Member Overloading in the .NET Development Guide.

Overriding, on the other hand, is about defining the same method with the same signature in a superclass and a subclass. We say the subclass’s method overrides the superclass’s method.

You must design a method to deliberately allow itself to be overridden:

  1. declare it to be a virtual method, with a method body; then its body is used unless it is later overridden; or

  2. declare it to be an abstract method, without a method body, just a signature, and a ; where the body would have been; or

  3. declare it to be an override method, providing a method body; such a method must be overriding a method in its parent using these three rules (note this requires some overall superclass to initially define the method virtual or static).

abstract and virtual methods cannot be static; only one is used, and it typically goes before the access modifier for the method (public, protected, etc.).

The overriding method must declare itself to override in the same manner that the base method delared itself override-able. It must also have the same access modifier, return type and parameter types as the overridden method.

Properties can also be overridden, using the same rules on the overriding modifier on the property (static, virtual, abstract, or override).

To access the superclass’s overridden method or property within the overriding class, use 'base.' before the method or property name. This resolves to the method in the superclass rather than the local one, and is done so that your class can extend the definition found in the subclass, adding to it rather than completely replacing it.

If you want to call the superclass’s constructor from your class’s constructor, you do that by invoking it as the special method name base() and pass the arguments to match the parameters for the superclass constructor you want. This call has to be placed after the constructor’s parameters and before its opening brace, like so:

public class FlyingCar extends Car
{
    public FlyingCar(string model, int maxAltitude) : base(model)
    {
        ... rest of constructor
    }

    ... rest of class
}

The root class in C# is System.Object. System.Object defines two methods, Equals and ToString that is expects all classes under it to redefine. When you do so, you will be overriding these methods. Equals returns a boolean saying whether this instance is equal to the one passed to it; and ToString returns a string representation of the object. System.Object.Equals bases equals on object identity; it’s up to you to use that, or to replace it with one based on object state, which is commonly done. ToString returns a representation as a string of the object’s type and value.

We might define these on CalendarEntry like so:

class CalendarEntry {
    ... other contents

    public override bool Equals(Object obj) {
        CalendarEntry calObj = obj as CalendarEntry;
        if (calObj == null)
            return false;
        else
            // base it on the date and string values...
            // not perfect, what about nulls?
            return EntryDate.Equals(calObj.EntryDate)
                 && Entry.Equals(calObj.Entry);
    }

    public override string ToString() {
        return EntryDate+": "+Entry;
    }
}

Notice that I want to ensure value equality; I am using the .Equals methods on DateTime and String, which check value equality. If i read the API, I can determine if they have overridden the == operator to use value equality (have they? Check their specification pages on http://msdn.microsoft.com/

7.6. Interfaces

Inheritance is very powerful, and complex. So C#, like Java before it, restricts programmers to 1 immediate parent; we call this "single inheritance". There are designs so complex that single inheritance is not sufficient. However, implementing multiple inheritance is very complex.

C# took the same route as Java in this regard, adding interfaces and allowing a class to implement several different interfaces. An interface can be thought of as a class without any implementation, for example:

interface IListableCalendarItem {

    ... methods and properties without code bodies

}

We can use more than one interface when we define a class:

class CalendarEntry implements IListableCalendarItem, IIterable {

    ...

}

The keyword implements on the class definition specifies which interfaces the class implements.

Note

The C# naming convention is to start all interfaces with the letter I and then an initial uppercase letter of the first word in its name. I’ve followed that convention in my example, and we will see it throughout ASP.NET.

If the class does not implement all of the methods and properties in the interface, then it is considered an abstract class, and it must have subclasses that complete the implementation. You cannot use a new expression on an abstract class. You can also explicitly make a class abstract by putting abstract before the keyword class in its definition.

We won’t be defining interfaces ourselves in this text, but there are many useful interfaces in ASP.NET. We will see these in the chapter on Collections and Databases.

7.7. The ASP.NET and .NET Libraries

There are so many classes in ASP.NET that reviewing them all takes time; most developers get familiar with the ones they use regularly, and know how to look up the ones they don’t use as often.

It’s a good idea to always look around a little bit, as the ASP.NET libraries are large, and it’s very possible the code you want, or some portion of it, is available to you in ASP.NET already. Why use the library? That code has been field-tested in diverse applications and environments, and stood the test of time. Are you going to test your code as thoroughly?

You can find the core classes in the .NET Framework Class Library.

The framework comes with .NET, which is underneath ASP.NET.

Here are a few classes it’s useful to be familiar with:

System.Math - useful functions for numbers
System.String - many utilities for string manipulation
System.Convert - static functions to convert among the base types
System.DateTime - a date/time representation
System.Random - a random number generating class

System.Text is a useful namespace to explore if you are manipulating strings; it contains the class System.Text.StringBuilder, which is more efficient and building strings than System.String.

System contains the core classes, but as we expand our look into databases, we will also be looking at the namespaces System.Collections and System.Data.

The Framework Class Library comes in .NET, which is underneath ASP.NET. ASP.NET adds the System.Web namespace and all of its sub namespaces, which provide web functionality to your application.

7.8. There’s more …​

We can only go so deep with C# classes in a first C# course. There are many more complex features to the C# class system including:

  • partial classes

  • abstract classes

  • asynchronous methods

  • delegates

  • destructors

  • nested types

  • structs and enums

  • anonymous types

  • generic types

  • class attributes

  • overloading operators

The Microsoft Developer Network C# Programming Guide provides an overview of these features.

7.10. Exercises

  1. Rewrite your GPS coordinate code from Chapter 3 to be two functions in a @function block. One returns the radians given the degrees, and the second returns the distance between two points in feet.

  2. Remember the dice calculations in previous exercises? Build a PairOfDice class that simulates having two dice; it will have a Roll method with a void return type that generates two new random, valid dice values, and methods ValueDie1 and ValueDie2 that return the individual values on the dice, and Total that returns the sum of the two die. This can be impelemented to require an object or as static methods and properties (explain your choice in comments on the PairOfDice class). It should have both of its dice values be stored in private variables (or an array of 2).

    Roll simulates olling a pair of dice. You can simulate rolling one die by choosing one of the integers 1, 2, 3, 4, 5, or 6 at random. The number you pick represents the number on the die after it is rolled. The expression rand.Next(6)+1 does the computation to select a random integer between 1 and 6, where rand is a variable holding a Random object.

    Do not store the total, but compute it when it is requested from the two dice values. OO design is always a tradeoff: if you stored the total, you would recalculate it whenever there was a new roll, even if it was not requested, while if you don’t, then you have to compute it each time it is requested. Your design would consider which of these was more likely, and program for that. Since we only request the total once for each roll, not storing it makes sense — we won’t be slower, and our object will require less storage in memory.

    With that class, rework your page from Chapter 5. Make a page that reports how many times it has to roll a pair of dice before they come up snake eyes. This is a simulation using your PairOfDice Class and using its Roll method to roll its dice.

    The page should report the number of rolls that it makes before the dice come up snake eyes. (Note: "Snake eyes" means that both dice show a value of 1.)

  3. A common programming task is computing statistics of a set of numbers. (A statistic is a number that summarizes some property of a set of data.) Common statistics include the mean (also known as the average) and the standard deviation (which tells how spread out the data are from the mean). I have provided a class called StatCalc that can be used to compute these statistics, as well as the sum of the items in the dataset and the number of items in the dataset.

    Listing 15. StatCalc.cs
    using System;
    
    /// <summary>
    /// An object of StatCalc can be used to gather statistics about numbers
    /// that are entered. The enter(double) method adds the numbers to those
    /// already evaluated. You can get the current statistics with the properties,
    /// which provide them in getters.
    /// </summary>
    public class StatCalc {
    
        private double squareSum;
    
        /// Add a number to the dataset.  The statistics will be computed for all
        /// the numbers that have been added to the dataset using this method.
        public void enter(double num) {
            Count++;
            Sum += num;
            squareSum += num * num;
        }
    
        /// Return the number of items that have been entered into the dataset.
        public int Count { get; set; }
    
        /// Return the sum of all the numbers that have been entered.
        public double Sum { get; set; }
    
        /// Return the average of all the items that have been entered.
        /// The return value is Double.NaN if no numbers have been entered.
        public double Mean {
            get { return Sum / Count; }
        }
    
        /// Return the standard deviation of all the items that have been entered.
        /// The return value is Double.NaN if no numbers have been entered.
        public double StandardDeviation {
            get {
                if (Count == 0)
                    return Double.NaN;
                return Math.Sqrt(squareSum / Count - Mean * Mean);
            }
        }
    
    }  // end class StatCalc

    Notice the <summary> tag and the use of three /'s — this is C#'s way of providing documentation in published classes. If you are interested to find out more, see XML Documentation Comments on MSDN.

    If calc is a variable of type StatCalc, then the following instance methods and properties are available:

    • calc.Enter(item) where item is a number, adds the item to the dataset.

    • calc.Count is a property that returns the number of items that have been added to the dataset.

    • calc.Sum is a property that returns the sum of all the items that have been added to the dataset.

    • calc.Mean is a property that returns the average of all the items.

    • calc.StandardDeviation is a property that returns the standard deviation of the items.

      Typically, all the data are added one after the other by calling the Enter() method over and over, as the data become available. After all the data have been entered, any of the other methods and properties can be called to get statistical information about the data. The properties Mean and StandardDeviation should only be called if the number of items is greater than zero.

      Starting with StatCalc.cs, add properties Max and Min. The Max property should return the largest of all the items that have been added to the dataset, and Min should return the smallest. You will need to keep track of the largest and smallest items that have been seen so far; consider your initial values for these properties carefully and initialize them in a 0-argument constructor.

      Test your new class by using it in a web site to compute statistics for a set of non-zero numbers entered by the user. Start by creating an object of type StatCalc:

      StatCalc  calc;   // Object to be used to process the data.
      calc = new StatCalc();

      Read numbers from the user and add them to the dataset. Request 5 numbers from the user; decide how to handle blank entries and document it on your page so your user knows what to expect. After all the user’s numbers have been entered, print out each of the six statistics that are available from calc. You do not need to print the numbers again.

  4. This problem uses the PairOfDice class from exercise 1 and your updated StatCalc.cs class from exercise 2.

    The program you wrote for a previous chapter performs the experiment of counting how many times a pair of dice is rolled before a given total comes up. It repeats this experiment 10000 times and then reports the average number of rolls. It does this whole process for each possible total (2, 3, …​, 12).

    Redo that exercise. But instead of just reporting the average number of rolls, you should also report the standard deviation and the maximum number of rolls. Use a PairOfDice object to represent the dice. Use a StatCalc object to compute the statistics. (You’ll need a new StatCalc object for each possible total, 2, 3, …​, 12. You can use a new pair of dice if you want, but it’s not required.)

  5. In the board game Scrabble, each tile contains a letter, which is used to spell words in rows and columns, and a score, which is used to determine the value of words.

    1. Write a definition for a class named Tile that represents letter/number tiles like those used in Scrabble. The properties should include a character named Letter and an integer named Value.

    2. Write a constructor that takes parameters named letter and value and initializes the instance variables.

    3. Write a method named ToString that returns the two property values combined in a string that is the return value, for examples A(1).

      Create a web site that generates random tiles and displays a hand of 6 tiles upon request. The letters should be between A and Z, and the values should be between 1 and 10. The 6 tiles should be stored in an array of tiles, and then displayed from the array.

      Stretch goal: Write the display in a helper, and invoke the helper on your page.

  6. Write a page to play Hangman. Let’s keep it simple and limit ourselves to 6 letter words; make an array of 20 strings and store 20 6-letter words in it. You’re going to have to track which word the user is guessing, but don’t give it away in the HTML; I recommend passing the index into the word array in a hidden form field; the hidden field won’t be displayed, but by using the index you are making sure your word can’t be found in the HTML source.

    Decide if you want to just use code blocks on your page or a separate class holding property and methods. Note that a class and its instances is specific to each load of your page: a function created on a page is no longer available when the user resubmits a form on that page or clicks to another page.

  7. Review the System.Text.StringBuilder specification and then rewrite PigLatin to use a StringBuilder in building its return value (it should still return a string).

  8. Write a performance test on the two versions of PigLatin: call one PigLatinS and the other PigLatinSB; run each within a loop 1000 times and see which is faster. If they are the same speed, run them 10000 times. Once you see a difference, double the number and see if the difference doubles or not. Write a report summarizing your testing and its results. This type of analysis of performance and reporting of the results often happens as part of the prototyping cycle, when you are exploring alternatives and want to determine which is better, and by how much.

7.11. Project

We are early for the database portion, but consider the data you would want to have be persistent. Databases store data in tables, with each row representing an object. Design the objects you will want to store in your database; create a class for each object, if you have more than one (there will be one type of object per table).

Redo your prototype to use this object — create a static array that holds several instances of this object to represent data you might look through or present to the user.

8. Collections and Databases

A key value proposition of web sites is that they provide global access to persistent information. We typically store the persistent information in databases and files on a file system. Databases store the data as tables (or sometimes more complex structures, but for now, let’s stick with tables).

A table is a set of rows, where each row has the same entries (the entry is called a column in the database). In OO design, you typically define an object that holds as its properties the entries within a row; so a table can be viewed as holding a collection of rows, or objects.

C# uses this model when it interacts with databases — a query against a table returns a collection of objects; each property in a returned object maps to a column in the table or query.

8.1. Collections

C# has one built-in collection, the array. Arrays are fine, but consider what happens when you need to remove the second item in an array: if it’s an array of objects, you can put a null there, but if it’s a primitive, it has to have a value. If you wanted to "fill" the hole but maintain order, you would have to copy down all of the entries above, and then track that the array has one more entry empty at the end. Collections are much richer: they do all of that management of entries for you, so you can add and remove entries as you need to. They can also maintain an order, based on the collection type: some maintain a sorted order, some maintain the order items were inserted.

An interesting feature that makes all of this possible is the generic class. A generic class lets you specialize a class when you use it, providing additional types used by that class. This lets you say what your collection holds; so you can specialize your collection to contain a particular type of object, rather than any object at all. This is similar to how you give an element type for your array when you declare it; that type is the only type allowed in the array (if it is a class, then instances of the class or of any of its subclasses are allowed).

8.1.1. Collection Interfaces

Although the implementations of collections provided in C# are classes, it defines interfaces for them as well. It is wise to use the interface on your variables, and restrict use of classes to the new statement. This lets you replace the chosen class with another one if you need to alter its performance or sort behavior. Collections' performance differ based on the types of operations you are performing or the type of sorting that is desired, if any.

The main Collection interfaces

ICollection

the most general interface; it mainly defines Count, ToArray, and GetEnumerator

IDictionary

a collection of key/value pairs; values can be accessed by keys . The Keys function on an IDictionary will return an ICollection containing just the keys.

IList

a collection that can be accessed by a numeric index (like an array)

There are two more interfaces in System.Collections which we make heavy use of: IEnumerator and IEnumerable. A class that implements IEnumerator will provide an IEnumerable. This is important because IEnumerable lets you not only move through the collection item by item, but also lets you access the collection’s elements using a foreach loop. We say that the foreach loop enumerates through the items in the collection.

8.1.2. Collection Classes

The popular collection classes are:

Popular Collection classes

ArrayList

IList

Items are ordered in the list. This looks alot like an array, but it lets you add and remove items dynamically (resizing the array). Sort and search capabilities are provided as well.

Hashtable

IDictionary

Keys map to values, and you use keys to access the elements. The collection is not sorted; with a good hash function (which is used to assign storage locations), your data is dispersed in memory and both access and removal are quick.

SortedList

IList & IDictionary

this allows both key and index access into a list; its entries when indexed contain both key and value. It is sorted on the key values.

Stack

IList

the stack is a special type of list that only allows items to be pushed on top of the stack and taken off of the top of the stack. Knowing this is the main type of access lets the implementation focus on being fast for those accesses. It is often described as "Last In, First Out".

Queue

IList

the queue is a special type of list as well; it only allows items to be added at one end, and taken off of the other end. It is described as "First In, First Out".

When you use these, or the interfaces, you can just use them "as-is", as they are fully-fledged classes. However, when you do that, it means the collection can contain any type of object at all; the default element type in the collection is object. And, boxing and unboxing means that primitives will get boxed up and stored in your collection as well.

8.1.3. Generic Collections

If you want to ensure that your collection contains only a particular type of object, you can do so by using a generic Collection type that permits adding a special type parameter to the class. This uses <> notation rather than a method’s () notation for its parameters.

List<element-type>

a type-safe ArrayList, permits any instance of element-type or its subtypes

Dictionary<key-type,value-type>

a type-safe Hashtable, permits any instance of the key-type or its subclasses for the key, and any instance of value-type or its subclasses for the value.

So, an ArrayList can hold anything: ints (boxed), Cars, Pirates, even ArrayLists. But a List<Pirate> can hold only Pirates and instance of subclasses of Pirates.

When you want to ensure your collection contains only a particular type of objects, use the generic collections. This ability is referred to as generic classes, since you create a new, specialized class when you provide the type parameters to it.

C# provides a way for you to create your own generic classes as well; however that is advanced programming, not covered in this text.

8.1.4. Example using collections

@using System.Collections.Generic;

... later in the page ...

@{
  IDictionary<string,int> phoneBook; // a map from strings to integers

  phoneBook = new Dictionary<string,int>();

  phoneBook.Add("Sarah Adams",1234567);
  phoneBook.Add("Jim Jones",5551212);
  phoneBook.Add("Nancy Smith",5010001);
  phoneBook.Add("Bill Blass",1237654);

  if (phoneBook.ContainsKey("Jim Jones")) {
    <p>Jim Jone's phone number is @phoneBook["Jim Jones"]</p>
  }
  else {
    <p>No phone number for Jim Jones.</p>
  }

  /// can also add items like so:
  phoneBook["Sam Sanders"] = 5051122;

  // this will also update an existing item:
  phoneBook["Nancy Smith"] = 5019999;

  ICollection<string> names = phoneBook.Keys;

  <p>Here is your current phone list:</p>
  foreach (string name in names) {
    // the key indexes into the dictionary to retrieve the value:
    <p>@name : @phoneBook[name]</p>
  }

}

8.2. Database Access

Today there are two popular database choices: Relational or NoSQL databases. For this text, our focus is a relational database. These databases store data in tables, which have rows and columns. You can query the database, selecting which rows you want from your tables and then which columns from the rows. You do this with the language SQL.

Note

This text assumes familiarity with SQL, so it will not introduce it to you, but will use it and provide descriptions of that use. We use Microsoft SQL Server Compact Edition through Visual Studio and IIS Express; applications developed in this manner transfer seamlessly to Microsoft SQL Server when deployed. But to deploy onto Oracle, MySQL, or some other database, you would need to adjust the connection mechanism and possibly the SQL syntax, as each database system has its own dialect of SQL.

Let’s assume we have a contact list in our database with the following data:

Id Name PhoneNumber Email TwitterHandle

1

Sarah Adams

123-4567

sarah@nowhere.com

@sarahnowhere

2

Jim Jones

555-1212

jjones@gmail.com

@jjones3254

3

Nancy Smith

501-0001

null

@flywitheagles

4

Bill Blass

123-7654

bblass@bblass.net

@blassisback

Note that we have an Id column; this is because good database design requires having a unique identifier (called a primary key) for each row. Name may not be good enough to be unique, if we have lots of contacts. Strings are slower in comparisons than integers, so we will usually see integers used as Id values.

In order to access a database, you first need to create one; in Visual Studio, in addition to IIS Express providing a local web server, SQL Server Express provides a local database server.

8.2.1. Create a Database

To create a database for your website, you must have it open in Visual Studio. If your website has an App_Data folder with a .sdf or .mdf file in it, then it already has a database; if you choose to use that one, jump ahead to "Create a Table".

If you do not have an App_Data directory in your project, right click in the Solution Explorer window on your web site/project name and click Add; in its menu click Add ASP.NET directory; and select App_Data from the list provided. You want to use this menu and not create it in the file system so that your project knows it exists.

Once you have an App_Data directory, right-click on that and click Add; then click Add New Item. In the dialog, under Installed>Visual C#, you should see "SQL Server database" in the list of choices. Select that, and then enter a name for your database (keep the .mdf file extension intact).

Once you are done, your database should appear under App_Data.

Note

If you are deploying to AppHarbor, or some other cloud ASP.NET PaaS, check to see if it allows more than one database. You may need to put all of your tables in a single database, rather than separate ones. This can be an issue if you are already using ASP.NET Identity, which assumes it can use a database named Identity with the connection name DefaultConnection.

You can add tables to the Identity database for your application’s database functionality; it’s just not the cleanest design to do so.

8.2.2. Database Configuration in Web.config

Your project Web.config file needs to have a connection string for your database. Check, and if it does not, add within the <connectionStrings> section of the file the following XML:

  ... if tag not found, add this as a child of <configuration>,
  ... after  <system.web>
  <connectionStrings>
    <add name="DatabaseName" connectionString="Data source=(LocalDB)\MSSQLLocalDB;|DataDirectory|\DatabaseName.mdf;Initial Catalog=DatabaseName;Integrated Security=true" providerName="System.Data.SqlClient"/>
    ... the rest of the element's children, if any
  </connectionStrings>

Replace DatabaseName in 3 places with the name you gave your database file. If you need to make this change, you will want to check that the setting in Tools→Options→Database Tools→Data Connections says (LocalDB)\MSSQLLocalDB. If you need to make either of these changes, exit and restart Visual Studio to ensure the changes are used when you access the database from within Visual Studio (before you create the table).

8.2.3. Create a Table

Creating a database is an administrative task that requires actions such as those done above; however, creating a table can be done by issuing an SQL statement. It’s up to you, to do it manually or programmatically. If you code it, then you can re-run that code in the future to create the table again; if you do it manually, you will need to repeat the steps each time you want the table re-created. It is not uncommon for web developers to keep special pages for their website that will issue SQL commands to check or recreate the database.

Manual table creation
  1. Click on the "Server Explorer" tab to open it (it is under View if you do not have the tab visible already).

  2. If it is not open, click to open the list under "Data Connections". You should see your database there, click to expand its contents if it is not showing a list within it.

  3. Right-click on the Tables item (first in the list, usually) and click "Add New Table".

  4. This puts you in the table designer, where you can either create the table using the chart, defining each column and its type, or enter the SQL in the window at the bottom of the page.

    Enter the following SQL to create our table:

CREATE TABLE PhoneBook(
  Id INT NOT NULL IDENTITY PRIMARY KEY,
  Name VARCHAR(50),
  PhoneNumber INT,
  Email VARCHAR(100),
  TwitterHandle VARCHAR(20)
  )

Click Update in the table design window. It will then ask if you want a Script before it does the update. Typically database administration involves keeping a collection of SQL commands in scripts to re-run them at a future date to update or repair a database. This is one such script. Since we have the command here, you can skip that and just click Update Database.

The log window will show if the database was successfully updated or not.

Once the table is created, you will need to right-click and click Refresh on your database name in the Server Explorer window for it to appear.

Code to create the table

The following Razor Page presents us with buttons; when clicked, they return us to the page and execute the specified SQL command.

Listing 16. DBAdmin.cshtml
@using System.Data.SqlClient;

<!DOCTYPE html>
<html>
<head>
    <title>Database Administration Tasks</title>
</head>
<body>
    @{
        int choice = Request.Form["choice"].AsInt();
        string command = null;

        switch (choice)
        {
            case 1:
                command = "DROP TABLE PhoneBook";
                break;

            case 2:
                command = @"CREATE TABLE PhoneBook(
                                 Id INT NOT NULL IDENTITY PRIMARY KEY,
                                 Name VARCHAR(50), PhoneNumber INT,
                                 Email VARCHAR(100), TwitterHandle VARCHAR(20) )";
                break;

        }

        Database db = null;
        if (command != null) {
            try {
                //my connection name in web.config is PhoneBookDB
                db = Database.Open("PhoneBookDB");
                db.Execute(command);
            } catch (SqlException se) {
                <p>
                    Oops, that didn't work. I got this exception:
                    @se.GetType()
                </p>
                <pre>@se.Message</pre>
                    <pre>@se.StackTrace</pre>
            } finally {
                if (db != null) {
                    db.Close();
                }
            }

        }
    }

    <form method="post">
        <button type="submit" name="choice" value="1">Drop Table PhoneBook</button>
        <br /><br />
        <button type="submit" name="choice" value="2">Create Table PhoneBook</button>
    </form>

</body>
</html>

This is an interesting Razor example since it uses several features of Razor, C#,and HTML:

  • @using — to import the namespace that SQLException lives in

  • try..catch — so we can tell the user if something went wrong with the SQL command; note that returning stack traces is not good in live sites, you would want to protect this by requiring that the page only be used by administrators (see the next chapter for security information).

  • we also used a finally block; it’s important to free up the database connection when you are done with it, as it is holding onto quite a few system resources. If you don’t explicitly close it, eventually the garbage collector will clean it up, but it’s not a good idea to rely on that happening. We use a finally because it ensures the connection is closed no matter what exception was thrown.

  • We use a special string value syntax, opening it with C#'s @",so that our long SQL command string can span lines in the file.

  • The form has two submit buttons with the same name and different values; this is how the POST action can tell which button was clicked — the value of the clicked button is the value of the buttons' name in the Request.Form dictionary.

  • Notice if a form submission is manufactured with a bad choice, no command is run — we don’t even tell the user it was an invalid choice. This was a design decision, to give back minimal information to malicious users (since only spoofed POSTs could use bad values).

8.2.4. Put Data in the Table (INSERT)

Once you have a table, you need to be able to put data into it. If your table’s data is static, you can do this through the Server Explorer view of the table in Visual Studio. If you right-click on the table in the Server Explorer view, you can see its data with the "Show Table Data" menu item. This shows you the data, and if you enter additional rows, they are saved to the table.

However, it is likely you will want to update your tables from your website; either as an administrative action or to let users share data with one another. You could request data directly from the user with a form, or you could collect the data more indirectly, such as a GPS location request or to save the results of a game they played in their browser.

Warning

When passing user data to an SQL command, do not ever just concatenate a user string to your SQL command. If you do, you open up your system to an SQL Injection attack, which can wreak havoc within your database system. For a hint at how to do this, see the XKCD comic usually referred to as Little Bobby Tables (CC-BY-NC-2.5):

exploits of a mom

We will always use safe strings, either checking values or passing them through dynamic parameters to prevent SQL injection attacks.

In order to issue an INSERT command, we have to connect to the database, and then we can issue commands to it. Database connections use the connection name assigned in the Web.config file, so we make the connection like this:

var db = Database.Open("PhoneBookDB");

Notice we are just letting C# determine the type of the variable db; in fact it is a Database, which is a helper class in WebMatrix.Data, supplied to make direct database interactions available.

PhoneBookDB is the name I gave this database in the Web.config file. It is usually the database name without the .mdf file extension.

Once you have a connection, you can issue an INSERT into a table that exists in that database. If the table does not exist, you will get an SQLException. The INSERT needs to list the columns and then list its parameters in the same order. Here is an insert into our PhoneBookDB:

    var insertQuery = "INSERT INTO Product (Name, Description, Price) " +
                "VALUES (@0, @1, @2)";
    db.Execute(insertQuery, Name, Description, Price);

The @0, @1, and @2 are not Razor @'s, here they are SQL @'s, marking the parameters to the SQL statement. This protects against SQL injection because the values supplied are kept separate and not simply concatenated into the SQL string.

Caution

Never, ever, ever, do this instead:

var insertQuery = "INSERT INTO Product (Name, Description, Price) " +
                "VALUES (\""+@Name+"\",\""+Description+"\","+@Price+")";
db.Execute(insertQuery);

Why not? because if Name came directly from a form field, it can contain malicious content that will take over the command and turn it into whatever SQL command the malicious user wants to make your database do, such as dropping all the tables or pulling out private data.

When you create your INSERT statement, you need to list all of the columns that you want to supply data for. If a column is not listed, then a SQL NULL value is put into that column in the new row.

Here is a page that will insert data into our table; note that if the form has no data, it is going to put in empty strings or 0’s for numbers — we really need validation on the values prior to this; you will see how to add validation in Validation and Helpers.

Listing 17. AddPhoneBookEntry.cshtml
@{
    string name = "";
    string email = "";
    string twitter = "";
    int? phone = null;
    string message = "";

    if (IsPost) {
        var db = Database.Open("PhoneBookDB");
        name = Request.Form["name"]; // required
        phone = Request.Form["phone"].AsInt(); // 0 if blank or missing
        email = Request.Form["email"]; // "" if blank or missing
        twitter = Request.Form["twitter"];

        // make no data turn into SQL NULL values
        if (phone == 0) {
            phone = null;
        }
        if (email.Length == 0) {
            email = null;
        }
        if (twitter.Length == 0) {
            twitter = null;
        }

        // Define the INSERT statement. The values to assign to the
        // columns in the PhoneBook table are defined as parameters.
        var insertStatement =
            @"INSERT INTO PhoneBook (Name, PhoneNumber, Email, TwitterHandle)
                 VALUES (@0, @1, @2, @3)";
        db.Execute(insertStatement, name, phone, email, twitter);

        message = "Phone Book entry "+ db.GetLastInsertId()+" created.";

        db.Close(); // clean-up
    }
}

<!DOCTYPE html>
<html>
<head>
    <title>Add PhoneBook Entry</title>
    <style type="text/css">
        label { float: left; width: 8em;
            text-align: right; margin-right: 0.5em; }
        form { padding: 1em; border: 1px solid; width: 50em; }
    </style>
</head>
<body>
    <h1>Add PhoneBook Entry</h1>
    <form method="post" action="">
        <div>
            <label>Name:</label>
            <input name="Name" type="text" size="50" value="@name" required />
        </div>
        <div>
            <label>Phone Number:</label>
            <input name="phone" type="text" size="50"
                   value="@phone" />
        </div>
        <div>
            <label>Email:</label>
            <input name="email" type="text" size="50" value="@email" />
        </div>
        <div>
            <label>Twitter Handle:</label>
            <input name="twitter" type="text" size="50" value="@twitter" />
        </div>
        <div>
            <label>&nbsp;</label>
            <input type="submit" value="Insert" class="submit" />
        </div>
    </form>
    <p>@message</p>
</body>
</html>

This is a very basic page; when the insert succeeds, the user is given a brief note, but if there is a problem, the page is replaced with an error page. There is almost no data validation — all the code does is make sure SQL NULL values will be inserted when the form fields were left blank. It assumes the required field (name) will be present. We will see how to address this in a later chapter with the Validation helper.

Tip

Notice that we do not insert into the Id column — because it was defined as an IDENTITY column, unique values will be automatically generated for us. Most SQL engines have this capability, though the syntax is often different.

We used the same Execute method that the CREATE TABLE and DROP TABLE statements used in our admin page, and could have used the same try..catch around it to determine what went wrong. Execute takes a variable number of parameters, so that you can specify the number to match all of the SQL parameters you have defined in your statement. If you specify fewer values than you have parameters, the Execute statement will throw an SQLException.

The database class has a useful method, GetLastInsertId, that you see used in the page. Because we inserted into a table with an identity column, the database will give us back the value it generated for that column. We give it to the user (though usually you would not, but you might use it for some other, internal purpose).

8.2.5. View Data in the Table (SELECT, WebGrid)

Once you have data in your database, you will want to display it to the user. This means getting the data back out of the database. There are three methods on Database that return data:

  • Query — for a SELECT statement that you expect to return any number of rows (including zero).

  • QuerySingle — for a SELECT statement that you expect to return exactly one row (just a single row)

  • QueryValue — for a SELECT statement that you expect to return exactly one column in one row (just a single value).

These methods all have the same parameters as Execute: the SELECT statement as a string, followed by any needed parameter values for parameters in the statement.

The Query method returns a collection as an IEnumerable — it is typical to use a foreach loop on the query result, to generate an HTML table. Toward this end, there is a WebGrid helper which will transform your IEnumerable not only to a HTML table, but to one with multiple pages.

But let’s explore that returned type, first. It is an IEnumerable of …​ objects. C# transforms the row in the result to an anonymous object. Anonymous objects are objects created on the fly without an associated class. The row is transformed into an object by making each column value in it a property of the object. The property names are the SELECT column names — so it’s important to name expressions in your SELECT list, or understand how SQL Server names columns that are computed from expressions in SELECTs. If you look at the type of the variable of a row, you see it is dynamic. That means that the compiler doesn’t know its type, and the runtime will only know it at the moment it gets created.

Let’s generate our own table first, and then look at WebGrid.

Listing 18. SelectTable.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Phone Book</title>
</head>
<body>
    <h1>Phone Book</h1>
@{
    var db = Database.Open("PhoneBookDB");
    var select = "SELECT * FROM PhoneBook";

    var rows = db.Query(select);

    <table border="1">
        <tr><th>Name</th><th>Phone Number</th><th>Email</th><th>Twitter Handle</th></tr>
        @foreach (var row in rows)
        {
            <tr><td>@row.Name</td><td>@row.PhoneNumber</td>
                <td>@row.Email</td><td>@row.TwitterHandle</td></tr>
        }
    </table>

    db.Close();
}
</body>
</html>

As you can see, we can dot off of our foreach variable row (which has the type dynamic) with the column names from our table. If you try to dot off of it with a different name, the compiler won’t detect the error — at runtime, you would get an exception.

The row is actually a WebMatrix.Data.DynamicRecord, and there are three different ways to access a given column:

  1. row.ColumnName as used in the code above

  2. row["ColumnName"]

  3. row[1] if ColumnName is column number 1 (remember, numbering starts at 0), returns that column

In addition to those access methods, DyanmicRecord provides the property Columns, which returns a list containing the column names. This can be useful if you do not know the names — you can use that list to index into the rows with the column names, or to get the count of columns to use the integer indexing. You can read more about DynamicRecord here: https://msdn.microsoft.com/en-us/library/webmatrix.data.dynamicrecord(v=vs.111).aspx.

8.2.6. WebGrid Helper

You could use the DynamicRecord ability to report column names and index the row columns to write your own helper that would generate an HTML table — but you don’t have to, since ASP.NET has done that. It has developed a very rich helper, WebGrid, which not only generates an HTML table, but provides paging so that long data results don’t cause long pages.

Here is our example, changed to use WebGrid:

Listing 19. SelectWebGrid.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Phone Book</title>
    <style>
      .grid { margin: 4px; border-collapse: collapse; width: 600px; }
      .grid th, .grid td { border: 1px solid #C0C0C0; padding: 5px; }
      .head { background-color: #E8E8E8; font-weight: bold; color: #FFF; }
      .alt { background-color: #E8E8E8; color: #000; }
    </style>
</head>
<body>
    <h1>Phone Book at @DateTime.Now</h1>
    <div>
        @{
            var db = Database.Open("PhoneBookDB");
            var select = "SELECT * FROM PhoneBook";

            var rows = db.Query(select);
            var grid = new WebGrid(source: rows, defaultSort: "Name", rowsPerPage: 3);
        }

        @grid.GetHtml(
        tableStyle: "grid",
        headerStyle: "head",
        alternatingRowStyle: "alt",
        columns: grid.Columns(
          grid.Column("Name"),
          grid.Column("PhoneNumber"),
          grid.Column("Email")
        )
      )
    </div>

    @{
    db.Close();
    }
</body>
</html>

As you can see, we create the WebGrid in a Razor code block, and then use its GetHtml method to generate the HTML for the Grid later on our page. When we use the WebGrid constructor, we supply:

  • source: an IEnumerable (in fact, it doesn’t even need to come from a query…​)

  • defaultSort: the column to sort the results on in the table

  • rowsPerPage: how many rows to put in the table at a time

The WebGrid will generate an HTML table that lets you click back and forth between "pages" in the table. That switching is all done in the client, so there are no additional trips to the server.

To generate the HTML, call WebGrid’s GetHtml method. This lets you specify:

  • tableStyle: the class to put on the table; in the CSS of our example, you can see how we also applied it to the td’s and th’s within the table using CSS selectors.

  • headerStyle: the class to put on the header row of the table.

  • alternatingRowStyle: the class to put on alternating rows; this lets you shade every other row for more visual impact. If not specified, all rows are styled the same.

  • columns: identify which columns of the result to display - you can include some or all, and put them in the order you want them to show up in the table.

You can rely on information from the database, and get a basic table, by passing just the SELECT result to WebGrid:

  var grid = new WebGrid(rows);

and then calling GetHtml with no styling options:

  @grid.GetHtml()

This displays all of the data returned in one table, with default table styling.

WebGrid is a very rich helper; as used here, it repeats the call whenever the next/previous page links are clicked. However, it has the ability to only update the table portion and not the whole page with a callback. This uses AJAX, Asynchronous Javascript And XML — the link is turned into a JavaScript call that interacts with the server independently of the rest of the page, updating just the table to display the next (or previous) page of data.

8.2.7. Change Data in the Table (UPDATE and DELETE)

In addition to having data entered, you may wish to allow users to update or delete their data.

Good design is to have the user identify the row they wish to edit or delete, and then to write your code to use the primary key to identify the row in the database. The user should typically not see the keys when they are autogenerated, so you don’t display them, but do track them in your code.

When requesting an update, you can either spend effort determining which values were changed by the user, or take the simpler route of assuming they’ve updated all of the columns. This works fine unless you have a very large column — then knowing that it was or was not changed is good, since you save alot of space and time by not sending unchanged data back to the server.

A typical model for this is to present the user with a table of all of their data, and then let them choose a row to delete or update. This means that each row in the table has two operations; we could choose to make them links or buttons. Since I’ve given an multi-butotn example already, I will do this one with links.

Listing 20. PhoneBookChoices.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Phone Book</title>
    <style>
      .grid { margin: 4px; border-collapse: collapse; width: 600px; }
      .grid th, .grid td { border: 1px solid #C0C0C0; padding: 5px; }
      .head { background-color: #E8E8E8; font-weight: bold; color: #FFF; }
      .alt { background-color: #E8E8E8; color: #000; }
    </style>
</head>
<body>
    <h1>Phone Book</h1>
    @{
    var db = Database.Open("PhoneBookDB");
    var select = "SELECT * FROM PhoneBook";

    var rows = db.Query(select);
    var grid = new WebGrid(source: rows, defaultSort: "Name", rowsPerPage:5);
    }

    <div>
        @grid.GetHtml(
        tableStyle: "grid",
        headerStyle: "head",
        alternatingRowStyle: "alt",
        columns: grid.Columns(
          grid.Column("Name"),
          grid.Column("PhoneNumber","Phone Number"),
          grid.Column("Email"),
          grid.Column("TwitterHandle", "Twitter Handle"),
          grid.Column("Id","Change",
            format: @<text><a href="~/DeleteEntry?id=@item.Id">Delete</a>&nbsp;
                <a href="~/UpdateEntry?id=@item.Id">Update</a> </text>)
        )
      )
    </div>
    <div><a href="~/AddPhoneBookEntry">Add new entry</a></div>
    @{
    db.Close();
    }
</body>
</html>

Notice the "extra" column in the GetHtml on the grid:

grid.Column("Id","Change",
            format: @<text>
                <a href="~/DeleteEntry?id=@item.Id">Delete</a>&nbsp;
                <a href="~/UpdateEntry?id=@item.Id">Update</a> </text>)

This column uses Id as its underlying value, but has its displayed column header say "Change". We don’t want to display the Id, but we do want to use it in links. We do this by generating links directly in the format parameter. Notice that this is embedded HTML, not a string value, for the parameter.

The page link is useful, because it gives us the opportunity to confirm the change with the user; and since we pass in the id, we can fetch the record to display it to them before the confirm their change.

You may have noticed the added link below the table as well, to add a new entry. This links to our AddPhoneBookEntry.cshtml page, which does an insert, but does not link back to our page. ASP.NET gives us a way to make that happen automatically — once AddPhoneBookEntry.cshtml completes an insert, it doesn’t have to stay on its page. If we add this code after db.Close(), we will return to the PhoneBookChoices.cshtml page:

Response.Redirect("~/PhoneBookChoices");

Let’s take a look at the delete operation, which also will use a redirect when it completes:

Listing 21. DeleteEntry.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Phone Book Delete</title>
    <style>
      .grid { margin: 4px; border-collapse: collapse; width: 600px; }
      .grid th, .grid td { border: 1px solid #C0C0C0; padding: 5px; }
      .head { background-color: #E8E8E8; font-weight: bold; color: #FFF; }
      .alt { background-color: #E8E8E8; color: #000; }
    </style>
</head>
<body>
    <h1>Remove Phone Book Entry</h1>
    @{
    var db = Database.Open("PhoneBookDB");
    var select = "SELECT * FROM PhoneBook WHERE Id=@0";
    var id = Request["id"].AsInt();

    var row = db.Query(select,id);
    //only one row, but use Query so we can use WebGrid...
    var grid = new WebGrid(source: row);

    if (IsPost) {
        var delete = "DELETE FROM PhoneBook WHERE Id=@0";
        db.Execute(delete,id);
        db.Close(); // clean up then return to the list
        Response.Redirect("~/PhoneBookChoices");
    }


    }

    <div>
      @grid.GetHtml(
        tableStyle: "grid",
        headerStyle: "head",
        alternatingRowStyle: "alt",
        columns: grid.Columns(
          grid.Column("Name"),
          grid.Column("PhoneNumber","Phone Number"),
          grid.Column("Email"),
          grid.Column("TwitterHandle", "Twitter Handle"),
          grid.Column("Id","Confirm",
            format: @<form method="post">
                <button type="submit" name="id" value="item.Id">Confirm Delete</button>
            </form>)
        )
      )
    </div>
    <div><a href="~/PhoneBookChoices">Cancel</a></div>
    @{
    db.Close();
    }
</body>
</html>

You can see the redirect after a successful delete — it returns us to the previous page; the cancel link at the bottom also does this, without making a delete. We keep the id value in the same place by making submit button use id as its name and the id value as its value. Alternatively, we could have made it a hidden field in our form.

This page should be more defensive; it makes these assumptions:

  • that the id will find a row

  • that a post will find a valid row

  • that the delete will remove exactly 1 row, not 0 or more than 1 (since it’s a primary key, the 'not more than one' is actually a fine assumption).

So we should expand the page to do these checks and inform the user appropriately if the delete request is no good.

The update operation is similar, but since we have to let the user change the data, we can use QuerySingle rather than Query to get the single row we are expecting. This time, we will code more defensively as well.

Listing 22. UpdateEntry.cshtml
@{
    string name = "";
    string email = "";
    string twitter = "";
    int? phoneNumber = null;
    string message = "";

    var db = Database.Open("PhoneBookDB");
    var select = "SELECT * FROM PhoneBook WHERE Id=@0";
    var id = Request["id"].AsInt();

    // using QuerySingle because id selections have to return 0 or 1 rows:
    var row = db.QuerySingle(select,id);

    //no row, 'quiet' error and return to the list page
    if (row == null) {
        db.Close();
        Response.Redirect("~/PhoneBookChoices");
    }

    if (IsPost) {
        name = Request.Form["name"]; // required
        phoneNumber = Request.Form["phone"].AsInt(); // 0 if blank or missing
        email = Request.Form["email"]; // "" if blank or missing
        twitter = Request.Form["twitter"];

        // make no data turn into SQL NULL values
        if (phoneNumber == 0) {
            phoneNumber = null;
        }
        if (email.Length == 0) {
            email = null;
        }
        if (twitter.Length == 0) {
            twitter = null;
        }

        // Define the UPDATE statement. The values to assign to the
        // columns in the PhoneBook table are defined as parameters.
        var update =
            @"UPDATE PhoneBook SET Name=@0, PhoneNumber=@1, Email=@2, TwitterHandle=@3
                 WHERE Id=@4";

        int numRows = db.Execute(update, name, phoneNumber, email, twitter, id);
        if (numRows != 1) {
            @: <script>alert("Oops, @numRows rows were altered.")</script>
        }

        db.Close(); // clean-up
        Response.Redirect("~/PhoneBookChoices");
    } else {
        // get the values from the row to see what changes the user wants to make
        name = row.Name;
        email = row.Email;
        phoneNumber = row.PhoneNumber;
        twitter = row.TwitterHandle;
    }
}

<!DOCTYPE html>
<html>
<head>
    <title>Change PhoneBook Entry</title>
    <style type="text/css">
        label { float: left; width: 8em;
            text-align: right; margin-right: 0.5em; }
        form { padding: 1em; border: 1px solid; width: 50em; }
    </style>
</head>
<body>
    <h1>Change PhoneBook Entry</h1>

    <form method="post" action="">
        <div>
            <label>Name:</label>
            <input name="Name" type="text" size="50" value="@name" required />
        </div>
        <div>
            <label>Phone Number:</label>
            <input name="phoneNumber" type="text" size="50"
                   value="@phoneNumber" />
        </div>
        <div>
            <label>Email:</label>
            <input name="email" type="text" size="50" value="@email" />
        </div>
        <div>
            <label>Twitter Handle:</label>
            <input name="twitter" type="text" size="50" value="@twitter" />
        </div>
        <div>
            <label>&nbsp;</label>
            <input type="submit" value="Update" class="submit" />
        </div>
    </form>
</body>
</html>

As you can see, before we display data or make any changes, we validate that we got a row back from QuerySingle. If there is no row, we return to the list page (a quiet error) rather than let the user know they phished us, if they were malicious.

We also check the number of rows updated by looking at the value returned by Execute; up until now, we’ve been ignoring this value; but we can use it to code more defensively. On an Update, Insert, or Delete, it returns the number of rows affected by the statement. In order for our Update to fail to find the 1 row, we’d need to have a very busy website with multiple users making changes at the same time — so it is possible, but highly unlikely. I’ve coded a simple JavaScript alert but it would be more appropriate to say something like "please reissue request", or just bounce the user back to the home page to try again.

This collection of 4 pages: the list of entries, add, delete, and update lets us control the contents of our table. You will see this "CRUD" (create, update, delete) model again in ASP.NET MVC. These are the 4 basic operations on persistent storage; knowing how to do these 4 lets you then use the operations within other contexts to suit your application’s needs.

8.2.8. Database class

We’ve used several methods of the Database class. Here is a list of its property and methods to review:

Static property description

Connection

the current connection

Static methods description

Open(string)

Opens a connection using the specified connection name or file name.

OpenConnectionString(string)

Opens a connection to a database using the specified connection string (these are like the values in our Web.config file).

OpenConnectionString(String, String)

Opens a connection to a database using a connection string and a provider.

Method description

Close()

Closes the database.

Dispose()

Releases all resources used by the database.

Execute(string)

Executes an SQL statement.

Execute(string,object,..)

Executes an SQL statement with the specified values for its parameters.

GetLastInsertId()

Returns the generated identity column value of the most recently inserted row.

Query

Executes a SQL query that returns a list of rows as the result (as an IEnumerable); can specify parameter values

QuerySingle

Executes a SQL query that returns a single row as the result (as an anonymous object); can specify parameter values

QueryValue

Executes a SQL query that returns a single value as the result (as an object); can specify parameter values

When using this class, it’s important to remember to clean up. Otherwise, you may use up more system resources than you need to. So, once you are done with the database, use the Close method to release the connection. If you don’t call this explicitly, the resources will be released when the garbage collector realizes no-one is using the database object any longer; but that relies on something that may not occur for a while.

As you saw with the Query, it returns a collection of objects; each object is made up of properties that match the columns in the query. C#'s support for anonymous objects lets this happen automatically. If you define a class to match your query row result, you can convert the SQL result’s anonymous class to your class. This lets you treat the rows in your tables like object instances, and your class can define additional behaviours and checks above the database to control how the values are set. You do have to pull them back out to properties to do an INSERT, but you could choose to write behaviors for your objects that handled that for you.

One thing we have not explored is a multi-table database and joins to reconnect their data; with any sizeable application, your database will end up with several tables related to each other in particular ways.

Note

ASP.NET provides an automatic object-to-relational mapping called the Entity Framework and an additional language integrated into C# called LINQ for manipulating databases. Those are beyond the scope of this text, but we will walk through it in ASP.NET Extreme.

8.3. Application Database Design

Good database design is a topic in itself, and beyond the scope of this text. Good application database use is a programming design exercise.

You can see a clean example of application-database design in the ASP.NET Identity system and its use in the ASP.NET Web Site with Identity template.

In particular, there is a UserManager class that controls all changes made to the User table, and a User class that holds instances created from rows of the table. Microsoft calls this style of use Entity Framework; in the wider general design literature, it is called Object-Relational Mapping (ORM), as objects in your application are representations of rows in the table, and the manager for them ensures that changes are made to the underlying table.

UserManager does not expose the SQL it uses, but rather provides the user with specific actions given a User or values that help identify a user, with methods such as:

  • FindUserById(username) — returns the user from the database with the given user name

  • FindUserByEmail(email address) — returns a user given an email address

  • DeleteUser(user) — given a user object, removes it from the underlying table

  • ChangeUserPassword(username, oldpassword, newpassword) — changes the user’s password in the object and in the database

  • CheckEmail(username, email address) — returns true if the email address is the one for the user, or false otherwise

  • CreateUser (username, email, password, …​) — creates a new user and puts it into the database

The User class is a simple class with properties for each of the columns in the database.

The UserManager instance also manages connecting to the database. These connections are expensive and must be released when database access completes. In the web universe, this can lead to a lot of churning, since HTTP is a session-less protocol. A typical mature web application will reuse a database connection within the session it thinks it has with a user, but will release it after a certain length without activity, assuming the user has left the web site.

You can ensure that your database connections are closed by cleaning them up by wrapping the connection and database access in a try block with a finally clause. The finally of a try always runs, even if an exception is thrown.

Another way to ensure the connection is closed is to use a C# using statement. This statement ensures that the instance held in its variable declaration is disposed of, no matter how the using block completes.

using (var db = Database.Open("PhoneBookDB") )
{
    ... SQL operations
}

The dispose action will close the database and ensure all resources are released; it invokes the Close operation on the database.

For more information on using, see using Statement (C# Reference, MSDN)

8.4. File Handling

Big files such as images can be stored in databases, but often are not. You can receive a file in an HTTP request and write it out to the server’s file system; and take a file from the server’s file system and include it in a HTTP response.

We are going to look at images and what is particular to them, as they are a common upload/display item on a web page. C#'s file operations include the ability to open and read through text files, and you can find third-party helpers that will display PDF file contents on a page as well.

8.4.1. Uploading files

HTML5 forms provide the ability to locate a file and have it sent to the server in a POST request. The operations you need to handle are the server-side storage of the file. Most databases (including SQL Server) have a Binary Large Object (BLOB) data type that could be used to save a file; however, you may want to simply put the file on the server’s disk rather than loading it into the database.

Warning

When you start allowing file uploads, be aware that file size can cause serious issues in the server (memory use) and on the server’s permanent storage. Use caution and set limits to prevent too many uploads or uploads of large files. Also be careful what you do with the file contents — user files can cause injection attacks if you use their content as HTML or SQL content or allow it to execute in some other fashion on the server.

We will walk through the server side code shown in this example:

Listing 23. ImageUpload.cshtml
@functions {
    // validate that it is an image file
    bool isImageFile(HttpPostedFileBase file)
    {
        string mimeType = file.ContentType.ToLower();
        // image types we want to allow:
        return (mimeType == "image/jpeg" ||
                mimeType == "image/gif" ||
                mimeType == "image/png");
        // should also check file extension and
        // actual file contents to be more secure
    }
}

@{
    var fileName = "";
    bool uploadedFile = false;
    if (IsPost)
    {
        var fileSavePath = "";
        var file = Request.Files[0];
        if (file.ContentLength != 0 && isImageFile(file))
        {
            fileName = Path.GetFileName(file.FileName);
            // under App_Data protects files from access
            // this directory does not protect from access
            fileSavePath = Server.MapPath(@"~/uploads/" + fileName);
            file.SaveAs(fileSavePath);
            uploadedFile = true;
        }
    }
}
<!DOCTYPE html>
<html>
<head>
    <title>Image Upload</title>
</head>
<body>
    <h1>Image Upload</h1>
    <p>Choose your file image and click Upload.</p>
    <!-- use a multipart form so the file is delineated in the post -->
    <form action="" method="post" enctype="multipart/form-data">
        <label for="file">Filename:</label>
        <input type="file" name="file" id="file" />
        <input type="submit" name="submit" value="Upload" />
    </form>

    @{
        if (IsPost) {
            if (uploadedFile) {
                <p>@fileName uploaded.</p>
            } else {
                <p>No file uploaded.</p>
            }
        }
    }
</body>
</html>

Notice that at the top, I’ve defined a function isImageFile; I’ve separate this out as it is a complex check which I may want to expand later to check for image files more thoroughly.

The files in the post are stored in the collection Request.Files; their contents are streamed within the HTTP request (yes, all of them) — so client-side JavaScript checks for file size would be a very good thing to add.

Before saving the file, we check that it has content and that it is an image file. Once we have that, we look for the actual file name. The full path on the client side is provided in the file’s FileName property, so we use the static method Path.GetFileName to get just the actual file name, stripped of any path above it. Then we create a server-side absolute file name using Server.MapPath and providing a target directory, ~/uploads/ and the user’s file name. The uploads directory needs to already exist in your project - the first time you will need to create it manually. You could choose a different location - it is not uncommon to store the files in a diretory under App_Data; App_Data is a protected location, files in it cannot be viewed by users — attempts will get a 404.8, Not Found, HTTP Response Code.

Tip

You may, actually, want to make up your own file names on the server — one user could overwrite another user’s files by uploading a file with the same name. This type of file management requires a database to map users' file names to the file names you’ve used in the server-side file system.

8.4.2. Displaying Image Files

To display an image file stored on the server, you actually don’t do anything special; it appears in an HTML <img> tag just like any other image.

The tricky part is knowing the file names, if the files were previously uploaded to the server. You might store them in a database, or you might simply browse your image directory on the server to display the files found there.

In our example, we will look in our UploadedFiles directory for files ending in .jpg, .png, or .gif to display on our page.

@functions {
    // validate that it is an image file
    bool IsImageFile(string file)
    {
        string fileExtension = Path.GetExtension(file).ToLower();
        // image files we want to allow:
        return (fileExtension == ".jpeg" ||
                fileExtension == ".jpg" ||
                fileExtension == ".gif" ||
                fileExtension == ".png");
        // should check actual file contents to be more secure
    }
}

<!DOCTYPE html>
<html>
<head>
    <title>Display Images</title>
</head>
<body>
    <h1>Display Images</h1>

    @{
        string[] files = Directory.GetFiles(Server.MapPath(@"~/uploads/"));

        foreach (var file in files ) {

            if (IsImageFile(file)) {
                string fileURL=Href(@"~/uploads/"+Path.GetFileName(file));
                <img width="50"src="@Html.AttributeEncode(fileURL)"
                     alt="@Html.AttributeEncode(Path.GetFileName(file))"/>
            }
        }
    }

</body>
</html>

First, you see a helper function, IsImageFile, which is similar to our last method. This one checks file extensions, as the file is not embedded in a POST request with a MIME type any longer.

Then in the main body of the page, we use a system class (in the System.IO namespace) Directory. This class contains quite a few methods helpful for listing and traversing directory structures. In particular,

Directory.GetFiles(Server.MapPath(@"~/uploads/"));

First, you see Server.MapPath: that creates a server path, replacing the ~ with the local file system path. So this provides the name of the directory on the server where we expect the files to be.

The outer call, Directory.GetFiles looks in the specified directory for files. It returns an array of file names as strings. These names include the full path to the file.

Once we have the array of files, we can go through it and generate <img> links to the images. First, though, instead of a server filesystem path, we need a URL. This is constructed with the builtin helper Href, similar to the MapPath call earlier. Notice the special call Html.AttributeEncode: that makes sure the attribute values parse correctly. We do this because the original file name may contain characters that cannot be used in an attribute value, such as a ", <, or &. (This also prevents filename-based injection attacks.)

Note

There is a Helper named WebImage — this helper does a lot of useful activities on images, including resizing, flipping, and watermarking; we could even rewrite our pages to just use WebImage and not HttpPostedFileBase at all. However, we wanted to give you an overview of file handling regardless of file type in this text, so we’ve used the general form file class.

Making files downloadable is very similar to the image display code; enough that we will leave that as an exercise. Instead of generating <img> tags that users can right-click and do "Save As" on, you would generate file names that users could then right-click and do "Save As" on.

8.4.3. Deleting Files

If you are doing any sort of file/image upload and saving them as files on the server, you are going to have to do some mop-up operations at some point, to remove files. You may, for example, be storing a profile image for a user, and then when it is updated, you need to delete the old image and save the new one.

Listing 24. ImageDelete.cshtml
@{
    bool deleted = false;
    var filename = "";
    if (IsPost) {
        filename = Request["filename"];
        var fullPath = Server.MapPath("~/uploads/" + filename);

        if (File.Exists(fullPath)) {
            File.Delete(fullPath);
            deleted = true;
        }
    }
}
<!DOCTYPE html>
<html>
<head>
    <title>Image Delete</title>
</head>
<body>
    <h1>Image Delete</h1>
    <form name="deletePhoto" action="" method="post">
        <p>Choose file to delete:</p>

        @{
            string[] files = Directory.GetFiles(Server.MapPath(@"~/uploads/"));

            foreach (var file in files ) {
                string justfile = Path.GetFileName(file);

                <text>
                  <input type="radio" name="filename"
                       value="@Html.AttributeEncode(justfile)" />
                  @(Html.Encode(justfile)) <br />
                </text>
            }
        }
        <p><input type="submit" value="Submit" /></p>
    </form>

    @if(deleted) {
        <p>@filename deleted!</p>
    }
</body>
</html>

For our delete page, we’ve listed all of the files with radiobuttons; one is chosen, and when the Submit button is pressed, it is deleted. You see many of the same calls we’ve made in our other pages: Server.MapPath to get the file server path; Directory.GetFiles to list all of the files; and Html.AttributeEncode to protext the attribute value. You will notice that we used Html.Encode on the value next to the radio button, again to prevent an injection attack through file names.

The other new calls you will notice are File.Exists and File.Delete; these look at the local filesystem to see if the file exists, and to remove it.

Warning

When you write code that changes files on the server disk, consider it very carefully, and think through the potential ways your code or system could be attack. Consider the impact of a flood of requests; of large files; of files with malicious content; of file names. Protect carefully access to files shared among all of your users. Think about the models on the internet: the user who installs a file typically has the right to remove it, while other users may see it but not modify it. To implement such a system, we will need to add user accounts, which we will look at in the next chapter.

8.4.4. WebImage Helper

If you are only uploading and displaying image files, there is a helper tailored to images, WebImage. This is described in https://msdn.microsoft.com/en-us/library/system.web.helpers.webimage(v=vs.111).aspx. In addition to basic file information, this allows you to create images from an array of bytes, and to flip, watermark, or resize an image. It is used in the MSDN tutorial http://www.asp.net/web-pages/overview/ui-layouts-and-themes/9-working-with-images.

8.4.5. Deployment and file management

If you are using a PaaS such as AppHarbor, check its file management policy; many limit where files can be uploaded to, and may not keep files persistently — they may disappear when your app cycles off of their server, and in complex scenarios may disappear mid-way due to your app getting relocated within their server farm.

8.6. Exercises

  1. Build a 4-page phone book application that combines databases and images: start with PhoneBookDB and its 4 pages, and enable uploading images when adding an entry. The database row should record the image file name so that you know how to find it, or a null if there is no image. This will require adding a column to the table.

    Once you have that working, update it so that when images are uploaded, don’t use the original file name; generate a unique name using the system class Guid (GUID is Globally Unique Identifier) like so:

     string g = Guid.NewGuid().ToString();

    You will need to save and append the original file’s file extension on the guid; Path.GetExtension will provide this information.

    Save both the original file name and the GUID-based file name in the database (yes, another column in the table is needed) so that you can display the user’s file name to them rather than the internal, server-side GUID-based name.

    When you display the full record (on the Update page) show the current image and give the user the ability to replace it. The replace should delete the old file and save the new one.

    Modify the site to have a common layout and appearance using _SiteLayout.cshtml and _PageStart.cshtml.

  2. Rewrite the word-guessing page from the exercises in the chapter C# Methods, Classes, and Objects. Have the words stored in a database, so that you don’t have to generate an array on every load of the page, but rather access the database to see the list of words.

    Move out common look and feel portions of the page to a _SiteLayout.cshtml file and then add an administrative panel that also uses that layout. The Administrative panel for your game should, in one page (not 4 separate pages) let you add, remove, or alter words all on the same page; this is a design exercise, so consider how you would go about it in a way that fits our word list and is clear to the user how to add, remove, or modify words.

  3. One common activity on websites is to upload files and have them analyzed. Write a web page that requests a text file upload, then performs a word count of the contents. Save the file locally as a GUID and delete it once the count is completed. See http://www.asp.net/web-pages/overview/data/working-with-files for examples of how to read files and split up their lines and words.

    What other analysis might you do? think of one, write a specification for it, and implement it. This is an exercise in writing a precise-enough specification, and then implement it. Consider if you need to add more detail to the specification if you were not the implementer, but had to hand it over to someone else to implement.

    This exercise uses two skills from this chapter, collections and File I/O. Get comfortable with the power of the foreach loop with collections, and with the variety of methods and properties on File I/O.

  4. Suppose that the user gives you a file contains information about sales figures for a company in various cities. Each line of the file contains a city name, followed by a colon (:) followed by the data for that city. The data is a number of type double. However, for some cities, no data was available. In these lines, the data is replaced by a comment explaining why the data is missing. For example, several lines from the file might look like:

    San Francisco:  19887.32
    Chicago:  no report received
    New York: 298734.12

    Write a program that will compute and print the total sales from all the cities together. The program should also report the number of cities for which data was not available. The name of the file is "sales.dat".

    To complete this program, you’ll need to save the file locally, then open the file and read from it. C# provides a convenient File method ReadAllLines that ties file reading into collections. The method File.ReadAllLines opens a file and makes all of the lines available as an IEnumerable<string>. This means you can use a foreach loop to look at each line in turn, and know that when it completes, you have reached the end of the file.

    Suggestion: For each line, split it on the colon into two strings using Split with the ':' character. See if the second string is a valid number with IsDouble(), and convert it with AsDouble().

    The file class has all of the methods you need to read the file; see the .NET Class specification. Notice that ReadAllLines opens the file, reads all of the lines, and closes it. This does use alot of memory, since the file’s contents are held in memory.

    Remember to use iterative development; you might expand the pseudocode above into pseudocode containing the processing of the lines. Make small changes to your code so that when you hit a problem, you have only a few things to look at to determine the cause.

    How might you process the file if it was too large to hold in memory? Add a check of the file size before opening it, and only uses your solution for small files. What do you think the line between large and small should be?

    Challenge: Implement an alternative solution for large files that avoids bringing the file into memory at one time; this is complex, as it requires reading from the file a byte or chunk at a time, processing that, and then continuing.

  5. Develop a web application that provides you with a file server. It should:

    • list the directory structure and files on the server under some "root" upload location

    • let you create or remove a directory there

    • let you upload a file to a particular remote directory

    • let you download a file from a particular remote directory

    • let you delete a previously uploaded file

      To make this task manageable, start with just uploading/downloading/listing remote files in a single directory, and then add directory management as a second exercise.

      This isn’t very secure, since anyone with the web page can access all of these files; in a future chapter, you will add user management, so each user has their own file server. Consider how you might make this file server specific to one user, perhaps with a root directory that is a GUID specific to that user; the user should not need to know the GUID to use their files.

8.7. Project

This chapter represents a huge step forward: you can now make your data persistent, and provide users with the ability to alter it, whether that is through the direct 4-page "CRUD" style or more indirect, as actions taken when they move around your website.

Add a persistent backing store to your project, replacing any hard-coded arrays with database accesses.

9. Security and Accessibility

Once you start exposing pages on the internet, security becomes a huge concern. Websites suffer from vulnerabilities if data from users is not handled carefully. With the ability for multiple users to access a website, any that offer persistent storage need to be careful about how data sharing between users occurs.

OWASP (Open Web Application Security Project) has developed guidelines for secure development and testing of web applications such as ours. This chapter touches on key features of secure web applications based on their top .NET issues. Issues for other web frameworks and languages may present in a different manner or need different methods of handling.

The top 10 security issues collected by OWASP are:

  • A1 Injection

  • A2 Broken Authentication and Session Management

  • A3 Cross-Site Scripting (XSS)

  • A4 Insecure Direct Object References (can’t happen in HTTP)

  • A5 Security Misconfiguration

  • A6 Sensitive Data Exposure

  • A7 Missing Function Level Access Control

  • A8 Cross-Site Request Forgery (CSRF) (same as A3 in Web Pages)

  • A9 Using Components with Known Vulnerabilities

  • A10 Unvalidated Redirects and Forwards

Material in this section is based on .NET Security Cheat Sheet by Bill Sempf, Troy Hunt, and Jeremy Long (CC-BY-SA-2.0)

9.1. Injection Attacks

The most common vulnerability for security remains Injection. In particular, SQL commands can be an attack vector through SQL injection attacks.

In Collections and Databases, we issued SQL commands against a database. This is a particular issue with web applications that base queries or results on user input, such as search values or insert values. We showed safe programming in that chapter, using SQL parameters rather than string concatenation to build up our SQL commands. Any time you use a user’s value, it should come into your system as an SQL Parameter.

There are limits to where parameters are accepted in SQL; for example, they can be compared to column values, but you cannot let a user provide you with a table name, as table names cannot be passed in SQL parameters. If you need users to provide you with table names, have them choose the names from a list on the client-side, and then make sure the name chosen is one of the values from the list on the server-side, to prevent introduction of SQL injection. This is often called white-listing, where you check a value is on a list of allowed values.

Never, ever, just concatenate user input into an SQL command string; whitelisting or SQL parameter use will protect against SQL injection.

If you use enums to limit values, note that enums are still vulnerable to unexpected values. .NET only validates a successful cast to the underlying data type, integer by default. Enum.IsDefined can validate whether the input value is valid within the list of defined constants.

Be aware of how your application connects to the database; its connection specifies a role or user. Apply the principle of least privilege when setting up the Database User in your database of choice. The database user should only be able to access items that make sense for the use case.

Use of the Entity Framework (EF) is a very effective SQL injection prevention mechanism. Remember that building your own ad hoc queries in EF is just as susceptible to SQL injection as a plain SQL query. LINQ can reduce SQL injection even more.

When using SQL Server, prefer integrated authentication over SQL authentication. This removes the need to define roles and users for the system, using the own user’s authentication for the connection. This may only be possible in an intranet environment when users of the Windows OS are those who will be accessing the database. When your database is used by those without Windows accounts, you have to find an alternative solution. It is not unusual for a single connection to the database to exist, tied to the application. If you take this approach, be careful to ensure that the application’s access is limited only to data it needs to access, and that you have as many checks in place at the database level as possible to protect each user’s data from other users. Triggers and other SQL features may provide additional layers of protection.

9.2. Authentication and Session Management

Never, ever write your own encryption. User passwords are typical values that need encryption; user management in general is a huge issue. To this end, Microsoft has begun supplying user login management code within its Web Pages and MVC templates. Use their code — it undergoes more rigorous testing than you are likely to do. However, note that as provided it does still have some weaknesses.

The ASP.NET Membership provider and role provider is a good start, but review the password storage. The default storage hashes the password with asingle iteration of SHA-1 which is rather weak. The ASP.NET MVC4 template uses ASP.NET Identity instead of ASP.NET Membership, and ASP.NET Identity uses PBKDF2 by default which is better. Review the OWASP Password Storage Cheat Sheet for more information.

The ASP.NET Web Pages with Identity project template provided with this book also uses ASP.NET Identity and provides a simple user account subsystem written in Web Pages.

Once you have a user-based system, implement proper access controls; compare a user-provided username with the session’s username, and check that the user is in the appropriate role.

Caution

ASP.NET Membership uses SQL Server Compact Edition, which AppHarbor does not support. The template provided with this book uses ASP.NET Identity, which uses SQL Server. Microsoft may deprecate Membership, so using Identity is recommended.

9.2.1. ASP.NET Identity

The ASP.NET Identity template is used in the ASP.NET Web Pages with Identity template, available for download as an online template under New Project in Visual Studio, or from Github as Web-Pages-Identity-Template. This gives you a template web site with Default, About, and Contact pages and also a full user login/registration module with Registration, Login, Forgotten Password, and additional pages, and a backing database for them.

Note

This database relies on SQL Server LocalDB, and will start the database server. In VS 2015, there is often an issue with the LocalDB server not stopping when IIS Express stops. If you are having access issues, this may be the cause. You will need to stop and delete the LocalDB server daemon yourself. To do this, open a cmd window on C:\Program Files\MS SQL Server\130\Tools\Binn and issue these two commands:

    sqllocaldb stop mssqllocaldb
    sqllocaldb delete mssqllocaldb

This will shut down any active LocalDB server operating as mssqllocaldb, the database server name used in the default Identity configuration.

You will see an Account directory which contains these files:

  • ForgotPassword.cshtml - page to generate an email to reset a password

  • Login.cshtml - login page (redirects to home page)

  • Logout.cshtml - code processed on logout (redirects to page that invoked it)

  • Manage.cshtml - change password or remove login (redirects to login page)

  • PasswordReset.cshtml - get a password reset link sent

  • Register.cshtml - create local account (redirects to login page)

One piece of code is in the project to provide login support, you will see it in App_Code:

Once you have used Register or Login, there will be an App_Data directory with this file:

  • Identity.mdf - the Identity database

This file (Identity.mdf) is not a project file, so you will have to click "Show All Files" in the Solution Explorer toolbar to make it visible there. Once you can see it, if you double-click it will open in the Server Explorer and you can explore the tables, their contents and shape, from the Server Explorer view.

The root directory has these additional files:

  • _AppStart.cshtml - first file loaded, ensures login database exists

  • _PageStart.cshtml - makes _SiteLayout the default layout

  • _SiteLayout.cshtml - puts common header on all pages with login/register links

  • About.cshtml - template about page found on most websites.

  • Contact.cshtml - template contact page found on most websites.

  • Default.cshtml - template home page founc on most websites.

  • favicon.ico - small image used in browser tab

The Web.config file’s <connectionStrings> element contains an <add> element to allow access to the Identity database (Identity.mdf). It uses defaultConnection as the connection name.

9.2.2. Confirming Login and Password Reset

It is not uncommon to have registrations and forgotten passwords handled via email, so ASP.NET provides these services.

Warning

The code in this section has not yet been tested. Let me know if you run into any issues with it.

This requires the UserManagerExtensions (which are provided through UserManager in ASP.NET), and also that you have SMTP configured in your Web.config file. To do that, have a <mailSettings> section in <system.net> like so:

Listing 25. in Web.config
<configuration>
  <system.net>
    <mailSettings>
      <smtp from="example@domain.com" deliveryMethod="Network">
          <network host="smtp.gmail.com" port="587"
              userName="example@domain.com" password="password"/>
      </smtp>
    </mailSettings>
  </system.net>
</configuration>

replace host, port, userName, and password with your information.

Caution

Basic SMTP services in ASP.NET send passwords in the clear. You may want to explore SendGrid or other more secure options, or use a "burner" email that is only used for this purpose.

Do not put this file in a public repository or provide it to others, as it now has your email account information in it.

Confirming Login

The template provided sends users to the Login page upon completing Registration. To require email registration, that needs to be replaced with code to generation a confirmation email and a link to a page to confirm the registration.

In Register.cshtml, you will need to comment out the redirect call and replace it with code as follows:

Listing 26. in Register.cshtml
  // Response.Redirect("~/Account/Login");
  string code = UserManager.GenerateEmailConfirmationToken(user.Id);
  var callbackUrl = Url.Action("ConfirmEmail", "Account",
             new { userId = user.Id, code = code },
             protocol: Request.Url.Scheme);
  manager.SendEmail(user.Id, "Confirm your account",
            "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a> or entering the code " + code +
            " on the confirmation page.");
  Response.Redirect("~/Account/ConfirmEmail");

When email confirmation is used as shown above, this reroutes users to a new page, ConfirmEmail, shown here:

Listing 27. ConfirmEmail.cshtml
@{
    Page.Title = "Registration Confirmation Page";

    string message = "";
    var confirmationToken = Request["code"];
    var userId = Request["userId"];
    var askedAgain = Request["newCode"];

    // Log out of the current user context, if any
    var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
    authenticationManager.SignOut();

    // confirming the login, not a request for a new one
    if (!confirmationToken.IsEmpty() && !userId.IsEmpty() && askedAgain.IsEmpty()) {
        // may need a try/catch if this is the first DB hit
        var result = userManager.ConfirmEmail(userId, code);

        if (!result.Succeeded) {
            foreach (var error in result.Errors) {
                // find out what Identity thought went wrong...
                ModelState.AddFormError(error);
            }
        }
        else {
            message = "Registration Confirmed! "+
                "<a href='~/Account/Login'>Click login</a> to log in to the site.";
        }
    }

    // no problems and they want their code again...
    if (!askedAgain.IsEmpty()) {
        if (userId.IsEmpty() {
            ModelState.AddFormError("Username required.");
        }
        string code = userManager.GenerateEmailConfirmationToken(userId);
        var callbackUrl = Url.Action("ConfirmEmail", "Account",
            new { userId = userID, code = code }, protocol: Request.Url.Scheme);
        userManager.SendEmail(userID, subject,
            "Please confirm your account by clicking <a href=\"" +
            callbackUrl + "\">here</a>");
    }
}

<h1>@Page.Title.</h1>
<h2>Use the form below to confirm your account.</h2>

@if (!message.IsEmpty()) {
    <p>@Html.Raw(message)</p>
} else {
    <p>
    Check your email and use the link or enter your user name and
    code here to confirm your account. You must be confirmed
    before you can log in.
    </p>

    <form method="post">
        <fieldset>
            <legend>Confirm Account</legend>
            <p>
                <label for="userId">User name</label>
                <input type="text" id="userId" name="userId" />
            </p>
            <p>
                <label for="code">Confirmation code</label>
                <input type="text" id="code" name="code" />
            </p>
            <p><input type="submit" name="confirm" value="Confirm" /></p>
            <p><input type="submit" name="newCode" value="Regenerate Code" /></p>
        </fieldset>
    </form>
}

The Login page should be altered to check that email confirmation has occurred:

Listing 28. in Login.cshtml
    var user = userManager.Find(userName, password);

    if (user != null)
    {
        // Require the user to have a confirmed email before they can log on.
        if (!userManager.IsEmailConfirmed(user.Id)) (1)
        {
           // note this tells someone there is an unconfirmed account;
           // may want to echo the "No such user or password" message instead.
           ModelState.AddFormError("You must have a confirmed email to log on.");
        } else {
            var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
            var userIdentity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);

            authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = false }, userIdentity);
            Context.RedirectLocal(returnUrl);
        }
    } else {
        ModelState.AddFormError("The user name or password provided is incorrect.");
    }
  1. marks the new if block to validate confirmation prior to the login. Note that the error provided here leaks information about the account existing; you may want to instead always reroute to the ConfirmEmail page on this failure and the login failure (so users do not know the actual reason for the failure - bad login, bad password, or unconfirmed login).

Note that any login attempt should include a similar check, so Manage.cshtml should also validate confirmation before allowing the password to be altered. It might decide to let the account be deleted, but that would be up to the website designer to decide, and should be considered carefully as a potential security weakness.

Resetting your password

This user self-management task is linked to on the Manage page, ForgotPassword.cshtml. SMTP configuration is also needed for password resets.

You will need to uncomment the code and set smtpSetup to true in ForgotPassword.cshtml like so:

Listing 29. in ForgotPassword.cshtml
    if (user!=null) {
        smtpSetup = true;
           // For more information on how to enable password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
           // Send an email with this link
           string code = userManager.GeneratePasswordResetToken(userId);
           var hostUrl = Request.Url.GetComponents(UriComponents.SchemeAndServer,
                            UriFormat.Unescaped);
           var resetUrl = hostUrl +
                            VirtualPathUtility.ToAbsolute(
                              "~/Account/PasswordReset?resetToken=" +
                              HttpUtility.UrlEncode(code) +
                              "&email="+ HttpUtility.UrlEncode(email));
            userManager.SendEmail(userId, "Reset Password",
                            "Please reset your password by clicking <a href=\"" +
                            resetUrl + "\">here</a>");
    }

9.2.3. Other Identity Features

ASP.NET Identity also provides two-factor authentication; the asp.net site discusses this in the MVC environment here: Two-factor authentication using SMS and email with ASP.NET Identity.

You can also enable reCaptcha authentication using Google’s recaptcha.net. Stubs for this are present in the ASP.NET Web Pages with Identity template. This does not require any special ASP.NET Identity features to perform.

9.2.4. Account Management Page Flow

Your site is now configured with user logins. You will notice when someone is logged in, the upper right corner changes. Let’s step through the code that does this (in _SiteLayout.cshtml):

        <section id="login">
                @if (User.Identity.IsAuthenticated) { (1)
                        <text>
                                Hello, <a class="email" href="~/Account/Manage"
                                          title="Manage">@User.Identity.GetUserName()</a>! (2)
                                <form id="logoutForm" action="~/Account/Logout" method="post">
                                        @AntiForgery.GetHtml()  (3)
                                        <a href="javascript:document.getElementById('logoutForm').submit()">
                                            Log out             (4)
                                        </a>
                                </form>
                        </text>
                } else { (5)
                        <ul>
                                <li><a href="~/Account/Register">Register</a></li>
                                <li><a href="~/Account/Login">Log in</a></li>
                        </ul>
                }
        </section>
  1. User.Identity.IsAuthenticated is true if there is currently a logged-in user in the session.

  2. User.Identity.GetUserName() is the name of the currently logged-in user. As you can see here, if the user clicks their name, it will go to the page ~/Account/Manage.cshtml, which is for account management. Note we don’t need the .cshtml on our link, it is assumed.

  3. We see here a use of the anti-forgery token; it is the first line within the form

  4. The form is "just" a Log out link — but notice that it is hooked to javascript so it actually submits the form, which will post to ~/Account/Logout.cshtml.

  5. When no-one is logged in, the Register and Log in links are presented, routing to their respective pages.

Notice that much of the account management system is only found through using the login management system; only Register and Login are visible to non-users, Manage and Logout are presented to users, ForgotPassword is only visible from the Manage page, and ConfirmEmail is only accessed through the email link generated by a Registration request.

account mgmt flow
Figure 22. Account Management Page Flow

9.2.5. Using Authentication

Caution

ASP.NET Identity sends credentials to the server in clear text (unencrypted). A production site should use HTTPS (secure HTTP, using SSL) to encrypt sensitive information between the client and the server. For more information about SSL, see What is SSL and How to Implement in ASP.NET Web Application and Securing Communications with Secure Socket Layer (SSL) If you are not running with SSL, be very clear to the user that their password is unsafe. I recommend putting this on all pages, using _SiteLayout.cshtml.

Once you have account management and authentication, you can block off access to that portion of your website that requires a user account; or make pages behave differently for guests than for logged-in users.

If you want a portion of your website to not present itself until a user is logged in, you can accomplish that with these steps:

  1. Make a subdirectory, let’s call it authorized.

  2. In authorized, make a _PageStart.cshtml file that contains the following code:

    Listing 30. ~/authorized/_PageStart.cshtml
    @using Microsoft.AspNet.Identity
    
    @{
        if (!User.Identity.IsAuthenticated) {
            Response.Redirect("~/Account/Login?returnUrl="
                + Request.Url.LocalPath);
        }
        Layout = "~/_SiteLayout.cshtml";
    }

    We redirect to the login page if the user is not logged in — thus preventing the current page from rendering. Notice also that the login will return to this page once it completes. The returnUrl parameter is used in Login.cshtml to redirect upon a successful login.

    Using _PageStart.cshtml ensures that all pages in the current directory require logging in prior to their use. It overrides the _PageStart.cshtml file in the parent directory, so be sure to repeat any thing needed from that starting page to this one (not exactly DRY, I know…​).

9.2.6. Roles

Roles are useful when groups of users have access to specific areas of your web site that other users do not. For example, administration is usually assigned to a role rather than a single user; or you may have a group functionality that lets groups share files, but limit cross-group file sharing.

Roles may be fixed, or roles may be something that administrators (or, role administrators) can create and drop.

Roles can be created through ASP.NET once a connection to the identity database is made with WebSecurity.InitializeDatabaseConnection() using the Roles property of a page to access the SimpleRoleProvider instance for the Membership database.

For example, your administrative page might have code to create an admin role if one does not exist, and then if there are no users in the role, to put the user "admin" into that role if such a user exists.

@using Microsoft.AspNet.Identity
@using Microsoft.AspNet.Identity.EntityFramework
@using Microsoft.Owin.Security

@{
  var userStore = new UserStore<IdentityUser>();
  var roleManager = new RoleManager(new RoleStore(userStore.Context));
  var userManager = new UserManager<IdentityUser>(userStore);

  const AdminRoleName = "admin";
  const AdminUserName = "admin";

  if (!roleManager.RoleExists(AdminRoleName)) {
    var adminRole = new IdentityRole { Name = AdminRoleName };
    roleManager.Create(adminRole);
  }

  var adminRole = roleManager.FindByName(AdminRoleName);

  if (adminRole.Users.Count == 0) {
    var adminUser = userManager.FindUserByName(AdminUserName);

    if (adminUser != null) {
        adminUser.AddToRole(adminRoleName);
    }
  }
}
Tip

This particular design decision, to make sure there is an admin user in an admin role, is not very secure, since it is plain in our code what the login and role names are. One improvement is to put this code, or constants for the strings, in _AppStart.cshtml. Another would be to further isolate these values to environment variables that can then be configured on the server completely outside of the source code and accessed through the Request object.

Your administrative page may provide you with a list of users that allows you to add or remove administrative privilege from them, disable or remove their accounts, or create new accounts (for example, some sites do not have independent registration).

If there is a portion of your website that is only for administrators, you could use a similar organization to what we did with authorization to limit access to all pages in a diretory:

  1. Make a subdirectory, let’s call it admin.

  2. In admin, make a _PageStart.cshtml file that contains the following code:

    Listing 31. ~/admin/_PageStart.cshtml
    @using Microsoft.AspNet.Identity
    
    @{
        if (!User.Identity.IsAuthenticated) {
            Response.Redirect("~/Account/Login?returnUrl="
                + Request.Url.LocalPath); (1)
        }
        // set AdminRole in _AppStart.cshtml
        if(!User.IsInRole(AdminRole)) { (2)
            Response.Redirect("~/NotAuthorized");
        }
        Layout = "~/_SiteLayout.cshtml";
    }
    1. As before, we redirect to the login page if the user is not logged in — thus preventing the current page from rendering. Notice also that the login will return to this page once it completes. The returnUrl parameter is used in Login.cshtml to redirect upon a successful login.

    2. If the user is logged in, we will check to see if they are in the admin role; that value is set elsewhere, as a constant value. If the current user is not an admin, they are sent to a page letting them know they are not authorized. For security’s sake, you may actually want this to route to a Not Found page.

    Using _PageStart.cshtml ensures that all pages in the current directory require logging in prior to their use.

With ASP.NET Identity, setting up roles is done through the RoleManager class; however, once you have a user logged in, the User property of the Page instance for the current page gives you access to its Identity instance and the IsInRole() test.

The Identity instance provides access to the Name and IsAuthenticated properties; you typically would use Name only after checking IsAuthenticated, and then could use Name, and the UserManager, to locate the User object and manipulate its state, as shown in our code in this chapter.

The UserManager provides these capabilities:

Name Description

AccessFailed(TKey)

Tracks access failures, and logs the user out if goes over the configured maximum allowed.

AddLogin(TKey, UserLoginInfo)

Associates an external login with a user.

AddPassword(TKey, String)

Adds a user password (can’t have one already).

AddToRole(TKey, String)

Adds a user to a role.

AddToRoles(TKey, String[])

Adds a user to multiple roles

ChangePassword(TKey, String, String)

Changes a user password.

ChangePhoneNumber(TKey, String, String)

Sets a user phone number with the verification token.

CheckPassword(TUser, String)

Determines whether the password is valid for the user.

ConfirmEmail(TKey, String)

Confirms the user e-mail with confirmation token.

Create(TUser)

Creates a user with no password.

Create(TUser, String)

Creates a user with the given password.

Delete(TUser)

Deletes a user.

Find(String, String)

Returns a user with the specified username and password or null if there is no match.

Find(UserLoginInfo)

Returns the user associated with this login.

FindByEmail(String)

Finds a user by his e-mail.

FindById(TKey)

Finds a user by ID.

FindByName(String)

Finds a user by user name.

GenerateChangePhoneNumberToken(TKey, String)

Generates a code that the user can use to change their phone number to a specific number.

GenerateEmailConfirmationToken(TKey)

Gets the e-mail confirmation token for the user.

GeneratePasswordResetToken(TKey)

Generates a password reset token for the user using the UserTokenProvider.

GenerateTwoFactorToken(TKey, String)

Gets a token for a specific two factor provider.

GetAccessFailedCount(TKey)

Returns the number of failed access attempts for the user.

GetEmail(TKey)

Gets a user e-mail.

GetLockoutEnabled(TKey)

Determines whether the lockout is enabled for the user.

GetLockoutEndDate(TKey)

Returns when the user is no longer locked out, dates in the past are considered as not being locked out.

GetLogins(TKey)

Gets the external logins for a user.

GetPhoneNumber(TKey)

Gets a user phone number.

GetRoles(TKey)

Returns the roles for the user.

GetTwoFactorEnabled(TKey)

Determines whether two factor authentication is enabled for a user.

GetValidTwoFactorProviders(TKey)

Returns a list of valid two factor providers for a user.

HasPassword(TKey)

Determines whether the user has a password.

IsEmailConfirmed(TKey)

Determines whether the user e-mail has been confirmed.

IsInRole(TKey, String)

Determines whether the user is in the specified role.

IsLockedOut(TKey)

Determines whether the user is locked out.

IsPhoneNumberConfirmed(TKey)

Determines whether the user phone number has been confirmed.

NotifyTwoFactorToken(TKey, String, String)

Notifies a user with a token using a specific method of two-factor authentication provider.

RegisterTwoFactorProvider(String, IUserTokenProvider<TUser, TKey>)

Registers a two factor authentication provider with the TwoFactorProviders mapping.

RemoveFromRole(TKey, String)

Removes a user from a role.

RemoveFromRoles(TKey, String[])

Remove user from multiple roles

RemoveLogin(TKey, UserLoginInfo)

Removes a user login.

RemovePassword(TKey)

Removes a user password.

ResetAccessFailedCount(TKey)

Resets the access failed count for the user to 0.

ResetPassword(TKey, String, String)

Resets a user password using a reset password token.

SendEmail(TKey, String, String)

Sends an e-mail to the user.

SendSms(TKey, String)

Sends the user a SMS message.

SetEmail(TKey, String)

Sets a user e-mail.

SetLockoutEnabled(TKey, Boolean)

Sets whether lockout is enabled for this user.

SetLockoutEndDate(TKey, DateTimeOffset)

Sets the time when a user lockout ends.

SetPhoneNumber(TKey, String)

Sets a user phone number.

SetTwoFactorEnabled(TKey, Boolean)

Sets the two factor authentication enabled property for the user.

UpdateSecurityStamp(TKey)

Generates a new security stamp for a user, used for SignOutEverywhere functionality.

VerifyChangePhoneNumberToken(TKey, String, String)

Verifies whether the code is valid for a specific user and for a specific phone number.

VerifyTwoFactorToken(TKey, String, String)

Verifies a two factor token with the specified provider.

As you can see, the reset/confirm password calls are all here, as are calls for setting up and using external logins and two-factor authorization.

Although the UserManager lets us manipulate roles for a given user, sometimes you need to manipulate the roles themselves directly.

The RoleManager provides these capabilities: FIXFIXFIX

method description

Create(TRole)

Creates a role.

Delete(TRole)

Deletes a role.

FindById(TKey)

Finds a role by ID (a Role instance)

FindByName(String)

Finds a role by name.

RoleExists(String)

Determines whether the role exists.

Microsoft provides additional functionality in ASP.NET Identity including external authentication services such as Google and Facebook, and you can integrate reCaptcha validation of human interaction. For information on using those services, see http://www.asp.net/web-api/overview/security/external-authentication-services. Note that the writeup is based on a MVC project, some adjustments will be needed to use this with Web Pages.

9.3. Cross-site scripting

Next to SQL Injection, HTML injection also needs to be considered. If you allow user data to be displayed as HTML, that data can create a client-side injection attack. This is usually called cross-site scripting because its goal is to spoof the form from another site or send it to another site upon rendering. This data need not come from a form; it can be data previously stored in a database or a file. Consider that the database could be attacked from another source than your website and thus the virus may not appear until you select the data. So view any source of data as suspicious, and protect it upon display.

ASP.NET provides you with the ability to protect against user data by HTML encoding such data before displaying it. This turns any character that could signal an injection into its named entity; < is turned into <, & is turned into &, and so on. This is an automatic conversion when you display the content of a variable or expression using @something in your page.

If, for some reason, you need the value not to be encoded, then be certain the value contains only the HTML tags you expect or whatever your allowed values are before displaying it. You can stop the automatic encoding by wrapping the expression or variable in Html.Raw() like so:

    string message = "<b>This is a test</b>";

    <p>Encoded: @message</p>
    <p>Raw: @Html.Raw(message)</p>
Tip

You might wonder why ASP.NET encodes even for data in a database. It does because even if we clean the data going into the database, a malicious user could corrupt the database contents. So, ASP.NET always encodes on the way to the user, rather than on the input data. Yes, you can, and should, check the incoming data to rule out injection attacks as much as you reasonably can, but know that attacks can occur at any level in your web stack, at any time, so ASP.NET always acts defensively unless explicitly told not to by an Html.Raw() call.

In addition to automatic encoding of output, ASP.NET Web Pages validates incoming form data, and rejects any that contain any HTML tags at all. There are times when this may not be the action you want; for example, if your page allows user text that contains simple HTML tags such as <p>, <em>, or <code>.

Tip

One way around this is to use a markup language such as markdown for comments, rather than allow HTML in forms; or to integrate a package that provides WYSIWYG editing with HTML safety in forms such as Rich Text Editor.

To access data that would fail incoming validation requests, you have to access it through the Request.Unvalidated method rather than through Request, Request.Form, or Request.QueryString. This causes the user’s data to be passed to you directly without validation.

For example, instead of accessing it this way:

  string line = Request.Form["line"];

You would access it this way:

  string line = Request.Unvalidated().Form["line"];

If you were to try to access the data through the Form field directly, you would get an error.

It is very important that you perform whitelisting validation on this input yourself if you bypass validation. Request Validation in ASP.NET proposes a very smooth approach:

Encode the whole input, and then only decode the tags that you want to allow.

// Encode the string input
StringBuilder sb = new StringBuilder(Html.Encode(line));
// Selectively allow <b> and <i>
sb.Replace("&lt;b&gt;", "<b>");
sb.Replace("&lt;/b&gt;", "</b>");
sb.Replace("&lt;i&gt;", "<i>");
sb.Replace("&lt;/i&gt;", "</i>");

This type of bypassing should be done with extreme caution: if you forget to check or make a mistake in your code, then you have a security flaw that can be exploited.

You can also add checks to your forms and the processing of their contents to detect if a form request was forged.

To do this, add to the form like so:

<form ...>
@AntiForgery.GetHtml() <!-- first line within the form -->
... continue with form
</form>

And then when you process the posted data, add a check first for forgery:

if (IsPost) {
    AntiForgery.Validate();
    ... continue with form processing
}

This adds an anti-forgery token to a form and then has the server-side validate that token after a post. The form submission has to come from the expected client for the anti-forgery check to pass.

9.4. Security Configuration

Whenever there is a way to specify security, it must be carefully configured. This includes not only your web application’s security configuration but also the web server’s security configuration, the database’s security configuration, and any underlying server operating system security configuration.

For your web application, you should lock down the web.config file:

9.5. Sensitive Data

If you put account numbers, passwords, or other sensitive data in URLs or forms, then malicious users have access to data that they could use to compromise your web application. Never expose sensitiive data in URLs — always use a level of indirection that keeps all sensitive data on the server under its security.

Always use HTTPS. You may have noticed that our web sites are just using HTTP. HTTPS requires an SSL certificate; a real SSL certificate costs money, but for testing purposes you can write your own certificate and put it in place. There is a writeup on that here: http://www.c-sharpcorner.com/UploadFile/225740/what-is-ssl-and-how-to-implement-in-Asp-Net-web-aaplication/

Note that since you are not using SSL on your deployed application, you should make it very clear in your web pages that users should not use a password they use elsewhere; your site does not provide the security that commercial sites have.

To make it less obvious to clients what software you are using:

  • Remove the version header in your web.config.

   <httpRuntime enableVersionHeader="false" />
  • Also remove the Server header (doing this in _PageStart.cshtml removes it in each response).

   HttpContext.Current.Response.Headers.Remove("Server");

9.6. Check at every level

Previously in this text we’ve stressed checking data both in the client and in the server. Often developers think if the data has been checked once, that is sufficient. But because malicious users can spoof requests and potentially even get into the database directly, we need to check at every level.

When users are introduced, they also need to be revalidated at each level; it’s not enough to check the user name on the client side and then let server or database access proceed; the server and database should also check the user name against allowed permissions. That way, malicious users going in below the client, entering the server or database directly, will be prevented from access.

9.7. Updating the .NET Framework

A key vulnerability (A9 Using Components with Known Vulnerabilities) is not keeping libraries up to date, allowing known security issues to be used; this was a key issue with HeartBleed issues and has led to the demise of Java in the browser. ASP.NET is no different, as a library it, too, needs to be kept up to date so that security holes are quickly closed.

The .NET Framework is kept up-to-date by Microsoft with the Windows Update service. Developers do not normally need to run seperate updates to the Framework. Windows update can be accessed at Windows Update or from the Windows Update program on a Windows computer.

Individual frameworks can be kept up to date using NuGet. Watch the updates on your development setup, and plan updates to your applications accordingly.

Any third party library your application might use will also need to be updated. If it does not use Nuget, then you will need to update it explicitly through its update mechanism.

If you have a version of .NET running in a web server, it is the administrator’s role to ensure updates are applied in a timely manner. If you are using a cloud service such as AppHarbor or AWS, check on their update policy to be aware of what your exposure might be to exploitation of a known bad version.

Always check the MD5 hashes of the .NET Framework assemblies to prevent the possibility of rootkits in the framework. Altered assemblies are possible and simple to produce. Checking the MD5 hashes will prevent using altered assemblies on a server or client machine. See https://www.owasp.org/index.php/File%3APresentation_-.NET_Framework_Rootkits-_Backdoors_Inside_Your_Framework.ppt (.NET Framework Rootkits (ppt))

9.8. Redirects and Forwards

The tenth issue in the OWASP Top 10 is unvalidated redirects and forwards. These occur in C# when your page does a Response.Redirect call to change the page you land on when a form is processed. You may also do redirects in JavaScript, consult OWASP’s information sheet on redirects and forwards.

ASP.NET provides you with the ability to redirect to another URL. A form of attack is to take over the redirect or forward with a phishing URL rather than the intended one. So, whenever you code a redirect or forward in your web page that may have come from a user’s choice or input, you should use a white-list test to ensure the URL is value.

One check you can make in ASP.NET MVC is to validate that the URL is local, that is, remains on the same domain. For more information on MVC’s approach to this see Preventing Open Redirection Attacks (C#).

9.9. Accessibility

On the one hand, security aims at coding your pages to keep out users who are being malicious. Web accessibility is about coding your pages to allow users who want to view your page but have limitations in vision, mobility, hearing, or otherwise have difficulty accessing a web site.

WebAIM.org compiled a set of guidelines for web pages. These are primarily at the HTML level, and are relatively straight-forward to implement, but can be extensive if not considered up front for a large site. Here are their guidelines:

  1. Perceivable

    • Provide text alternatives for any non-text content such as images, buttons, and videos

    • Provide alternatives for time-based media, such as transcripts for videos

    • Content can be presented in different ways without losing information or structure

    • Make it easier for users to see and hear content including separating foreground from background, consider the impact of color-blindness

  2. Operable

    • Make all functionality available from a keyboard

    • Provide users enough time to read and use content

    • Do not design content in a way that is known to cause seizures

    • Provide ways to help users navigate, find content, and determine where they are

  3. Understandable

    • Make text content readable and understandable

    • Make Web pages appear and operate in predictable ways

    • Help users avoid and correct mistakes

  4. Robust

    • Maximize compatibility with current and future user agents, including assistive technologies

Many of these can be achieved by actions such as: * use alt attributes to describe images * use HTML tags semantically; that means the tag is used correctly, i.e.: use table column and row headers to mark column and row headers, not to style the table use headers (<h1>, …​ <h6>) appropriately, not to get certain styles use headers, don’t just use styles to present text as if it was a headers forms use appropriately tagged labels for fields * videos/audio tracks have transcripts and subtitles * use a logical layout that reacts well to screen readers and re-sizing and doesn’t rely on colors, shapes, or sizes of items * do not require a mouse; for example, provide keyboard alternatives

In addition to WebAIM’s general guidelines, some organizations have to satisfy regulations such as Section 508 of the Rehabilitation Act, §1194.22. These check even more deeply into page layout, content, and use.

With ASP.NET’s Web Pages, accessibility is driven by the HTML and the content; if you use the HTML Helpers to generate HTML, provide argument values for alt tags and others appropriate to provide accessibility.

9.11. Exercises

  1. Time for another round of "Stump the Newbie". Design a page with a security hole, and have a peer try to find the hole. You might do this by providing them source, or by providing them with a deployed application to "hack".

  2. Take the template Web Site’s user management functionality and add an admin role to it along with management for that role.

    The management of the admin role should include:

    • the ability to make a user an admin

    • the ability to take away admin privilege from a user

    • the requirement that there be at least one user in the admin role

    • the ability to delete a user

    • the ability to lock a user’s account (so they can log in, but get sent to an 'Account Locked' page).

    • the ability to unlock a user’s account

    • the ability to take on admin privilege outside of being given it in some manner (you design and document the manner), such as one of these:

      • the very first account created gets admin

      • a hard-coded user name gets admin given when the account is created

      • the database is seeded with an admin account

        In all cases, that specially-granted admin can be taken away if/when admin is given to another user, and won’t re-occur unless explicitly handed admin privilege through the admin management page.

        Note, this is in part a web site design exercise; we have at least two "management" activiities: user management and admin management. Consider how you want to lay this out and present it to the user.

  3. Pick an earlier exercise and check it against the WebAIM or Section 508 check-lists; make appropriate changes to satisfy those checklists. Have someone review your work to see if you overlooked any of the items, and review their page to see if they overlooked any of the items.

  4. Research the availability of tools to probe a website for security holes. Run them against your admin page web site.

9.12. Project

Review your project for attack vectors. Identify its weaknesses and apply appropriate hardening.

Add user management to your project using the provided ASP.NET Membership set-up from the template Web Site. Note that since you are not using SSL on your deployed application, you should make it very clear in your web pages that users should not use a password they use elsewhere; your site does not provide the security that commercial sites have.

Consider if your site needs an admin role that has more permissions, and if so implement an admin role and add checks to adminstrative functions so they are only carried out by users in the admin role.

Also do a review of your project against the WebAIM checklist and make any needed adjustments.

10. Validation and Helpers

It’s considered good design in web sites to check for valid data early — before the data goes to the server. Note that you still have to check for valid data on the server, since HTTP requests may not come from your page but be manually created and issued (even form post requests).

HTML5 has some check for client-side validation; ASP.NET provides validators for ensuring the values are good at the server, and providing helpful messages when they are not. These will check for values you specify are valid, and will generate appropriate messages when a request’s values are not valid.

This requires that we look at how data comes from the user, and at the ASP.NET utilities supplied for Validation, the Validation class and the Html.ValidationSummary and Html.ValidationMessage methods. These three work in conjunction with each other.

10.1. Input values

Values can come in from several places: they can be submitted in a form, present in the query string of the URL, or part of the url route request.

10.1.1. ASP.NET routes

A URL has these distinct parts:

UrlParts
Figure 23. Parts of a URL from What is a URL? CC-BY-SA-2.5

The protocol, domain name, and port identify the web server. The path to the file is used by ASP.NET Routing and may become part of the input values. We will see how to access the parameters in the next section.

So far in this material, I’ve always had the URL path lead directly to a file, including the .cshtml extension. However, a key issue in Search Engine Optimization (SEO) is how pages are located and bookmarked. It is harder to get a high ranking with parameters on your URL.

ASP.NET provides an alternative interpretation of the path to allow for parameter values to be encoded in the path rather than supplied as separate parameters. Here is its path interpretation algorithm:

  1. If there is a .cshtml extension on the last value in the path, locate the file and run it (this will get a 404 if there is no file).

  2. Otherwise, if there is no file extension on the last value, look for one with a .cshtml extention in that directory, and if found, run it.

  3. Otherwise, look at the parent "directory" name as if it were a file with no extension and see if there is a .cshtml file at that path; if there is such a file, run that page and pass the last value to it.

  4. Otherwise continue this check up the path until you find a match or root is reached; if a match is found, pass the unused part of the path as values in UrlData.

  5. If no file is found and root is reached, go back to the full path and look for Default.cshtml and then Index.cshtml in that directory (all cases of those two names are used, so default and index will also be found).

So we could construct URLs for a page collecting social data like so:

  1. It doesn’t end in .cshtml so rule 1 is skipped.

  2. Look for SocialData/argoc/42.cshtml - it won’t be found as that is data for the Social Data page.

  3. Look for SocialData/argoc.cshtml and be ready to pass 42 to it. It won’t be found, as this is still data for my page.

  4. Look for SocialData.cshtml. This one is found, so argoc/42 is passed to it in the UrlData and it is run.

  5. There was no need to return to the full URL and look for /SocialData/argoc/42/Default.cshtml or /SocialData/argoc/42/Index.cshtml.

Once the page is running, it can access the path that came after it in the URL through the UrlData property available on the page. UrlData is a simple array of strings, with UrlData[0] holding the first (on the left) unused name in the path, and UrlData[1] holding the second one, and so on; all of the /-separated names are in the UrlData array.

This code would display all that were available to you; try passing "long" URLs to this page to see what shows up.

Listing 32. UrlDataDemo.cshtml
<!DOCTYPE html>
<html>
    <head>
        <title>URL Data Demo</title>
    </head>
    <body>
        @if (UrlData.Count == 0)
        {
        <p>Enter this page with a URL such as
            <a href="@((Request.Url).ToString())/a/b/c/1/2/3 ">
                @((Request.Url).ToString())/a/b/c/1/2/3</a>
        (and drop the .cshtml if you used it) to see what is displayed.</p>
        } else
        {
            <p>The URL you entered was @Request.Url</p>
        }

        <p>Number of items in UrlData: @UrlData.Count</p>
        <ul>
            @for (int i = 0; i < UrlData.Count; i++)
            {
                <li>[@i]: @UrlData[i]</li>
            }
        </ul>
    </body>
</html>

10.1.2. URL parameters

A URL has these distinct partsLooking at our URL again:

UrlParts
Figure 24. Parts of a URL from What is a URL? CC-BY-SA-2.5

The protocol, domain name, and port identify the web server. The path to the file is used by ASP.NET Routing and may become part of the input values.

The parameters in the URL are key-value pairs; if you submit your form with method="get", you will see the form fields as parameters, with the form name as the key and the form field value as the value.

These URL parameters are available to you in ASP.NET using the Query property of the page. The Query property is a dictionary index like Request; you index into it with the key, and the value is returned to you, like so:

    // if the url has ?screenName=argoc&faveNum=42:
    string screenName=Request.Query["screenName"]; // argoc
    int num = Request.Query["faveNum"].AsInt(); // 42, convert into int

The values are all strings, so any integers or other information will need to be converted back to their types. Note that the URL-encoding you see in your browser bar will be turned back into characters in the Query values (spaces will be spaces, not the three charaters "%20").

10.1.3. Form fields

We have been getting form fields directly from the Request, like so: Request["field-name"]. The \[]'s look like an array index operation, and they are, but to a special array with string indexes rather than numeric ones. These are usually referred to as dictionaries — the string key is used to look up the value.

Note

The .NET class behind dictionaries is called System.Collections.Generic.Dictionary. It is a generic type, meaning you can say what the types are for both the key and the index. Request is a Dictionary from a string key to a string value.

When we use Request as the dictionary, it is actually searching 4 different parts of the HTTP request for keys (from HTML name attributes), in this order:

  1. parameters

  2. form fields

  3. cookies

  4. client certificate

  5. server variables

If you want to ensure you are only looking at one of those 5 areas' available keys, and not the other 4, then look at its particular property in request, which is also available as a dictionary with key indexing:

HTTP request portion Property name

parameters

QueryString

form fields

Form

cookies

Cookies

client certificate

ClientCertificate

server variables

ServerVariables

We will disuss using the other three later in this chapter.

10.2. Check if user’s input matches validation

The ASP.NET class Validator class provides static methods that let you say what fields you want to test, and how to test them. Typical checks include:

  • ensuring a value was specified

  • ensuring the value is the right type (int, date, string…​)

  • ensuring the value is in the appropriate range or matches the appropriate pattern

You should validate all portions of the form, as the user may be manually generating the post request, so select list values are not guaranteed to match those supplied.

Validation check Description

Validation.RequireField(field-name, optional-error-message)

provide the form field name (from your form’s name attribute) as a string value and, if desired, the error to display when no value is provided for that field.

Validation.RequireFields(field1-name, field2-name, …​)

provide the required fields in a single call.

Validation.Add(field-name, validation-type)

add a check on the named field. The validation-type can be:

  • Validator.DateTime(optional-error-message)

  • Validator.Decimal(optional-error-message)

  • Validator.EqualsTo(otherField , optional-error-message)

  • Validator.Float(optional-error-message)

  • Validator.Integer(optional-error-message)

  • Validator.Range(min, max, optional-error-message)

  • Validator.RegEx(pattern, optional-error-message)

  • Validator.Required(optional-error-message)

  • Validator.StringLength(length)

  • Validator.Url([error message])

These checks would be defined at the start of your page.

10.3. Check if all validation tests pass

You check if the validation checks succeeded before doing any processing by calling Validation.IsValid() and checking the result, a boolean value. Since the form had to be submitted, this typically foes with the IsPost check like so:

if(IsPost && Validation.IsValid()){
    // Process form submit
}

If IsValid returns false, you typically skip normal page processing and re-present the form to the user with the bad values.

10.4. Display validation errors

The two methods Html.ValidationMessage and Html.ValidationSummary can be used to inform the user what checks did not pass. Html.ValidationMessage must be given the form field name; it checks the result for that particular field, and if any failed, provides their error messages. These are the messages you provided, or defaults if you did not provide any.

Typically you put Html.ValidationMessage(field-name) by each form field, so the message shows up when there is an issue with the value. You might put Html.ValidationSummary at the top of your form or by the Submit button.

Here is an example showing the Validation setup and checks:

Listing 33. ValidationDemo.cshtml
@{
    var message="";
    // Specify validation requirements for different fields.
    Validation.RequireField("screenName", "Screen name is required");
    Validation.RequireField("faveNum", "Favorite number is required");
    Validation.Add("screenName", Validator.StringLength(10));
    Validation.Add("faveNum", Validator.Integer("Favorite number must be an integer"));
    Validation.Add("faveNum", Validator.Range(1, 100, "Favorite number must be between 1 and 100"));
    Validation.Add("faveUrl", Validator.Url("Favorite site must be a URL"));

    if (IsPost)  {
        // Before processing anything, make sure that all user input is valid.
        if (Validation.IsValid()) {
            var screenName = Request["screenName"];
            var faveNum = Request["faveNum"].AsInt();
            var faveUrl = Request["faveUrl"];
            message += @"For screen name, you entered " + screenName;
            message += @"<br/>For favorite number, you entered " + faveNum;
            message += @"<br/>For favorite site, you entered " + faveUrl;

            // Further processing here
        }
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Validation Demo</title>
  <style>
      body {margin: 10%; font-family: 'Verdana, Arial'; font-size: medium; }
   </style>
</head>
<body>
  <h1>Validation Demo</h1>
  <p>Enter information, see if you can break the form.</p>
  <form method="post">
    @Html.ValidationSummary()
    <div>
      <label for="screenName">Your screen name (up to 10 characters): </label>
      <input type="text" name="screenName" value="@Request["screenName"]" />
      @Html.ValidationMessage("screenName")
    </div>

    <div>
      <label for="faveNum">Your favorite number (1-100): </label>
      <input type="text" name="faveNum" value="@Request["faveNum"]" />
      @Html.ValidationMessage("faveNum")
    </div>

    <div>
      <label for="faveUrl">Favorite website (URL): </label>
      <input type="text" name="faveUrl" value="@Request["faveUrl"]" />
      @Html.ValidationMessage("faveUrl")
    </div>

   <div>
      <input type="submit" value="Submit" class="submit" />
    </div>

    <div>
      @if(IsPost){
        <p>@Html.Raw(message)</p>
      }
    </div>
  </form>
</body>
</html>

10.5. Client-side validation

All of our checks so far are server-side checks. Rather than require you to hand-code client-side checks in HTML5 and JavaScript, ASP.NET Web Pages provides hooks to have most checks made on the client-side as well.

Warning

You must check values on the server, as that is the point at which the values impact potential persistent data. Checking on the client has become popular as it avoids the round-trip to the server before reporting a failure.

Server-side checking is mandatory for a secure system; client-side checking is a nice-to-have that improves the user’s experience.

To make these checks function on the client-side, you must register three JavaScript libraries in your page:

<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

If you created your site from a template, all three files will be in your Scripts directory and can be directly referenced (the version number on jquery may differ; change the src value to match your file). If you are not already working with a non-empty Web Pages template (like Starter Site) that includes the library, create a Web Pages site that’s based on Starter Site. Then copy these three .js file to your current site.

In each form field, add a call to Validation.For(field-name) to get the client-side check; this will put attributes in the form field to match the required validations.

Validation.For is a Razor helper, so it is replaced by attributes that are used by client-side validation. jQuery uses these to do unobtrusive validation (thus the third script’s name).

Here is our example with these two changes made:

Listing 34. ValidationDemoClient.cshtml
@{
    var message="";
    // Specify validation requirements for different fields.
    Validation.RequireField("screenName", "Screen name is required");
    Validation.RequireField("faveNum", "Favorite number is required");
    Validation.Add("screenName", Validator.StringLength(10));
    Validation.Add("faveNum", Validator.Integer("Favorite number must be an integer"));
    Validation.Add("faveNum", Validator.Range(1, 100, "Favorite number must be between 1 and 100"));
    Validation.Add("faveUrl", Validator.Url("Favorite site must be a URL"));

    if (IsPost)  {
        // Before processing anything, make sure that all user input is valid.
        if (Validation.IsValid()) {
            var screenName = Request["screenName"];
            var faveNum = Request["faveNum"].AsInt();
            var faveUrl = Request["faveUrl"];
            message += @"For screen name, you entered " + screenName;
            message += @"<br/>For favorite number, you entered " + faveNum;
            message += @"<br/>For favorite site, you entered " + faveUrl;

            // Further processing here
        }
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Validation Demo</title>
  <style>
      body {margin: 10%; font-family: 'Verdana, Arial'; font-size: medium; }
  </style>
  <script src="~/Scripts/jquery-1.10.2.js"></script>
  <script src="~/Scripts/jquery.validate.js"></script>
  <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
</head>
<body>
  <h1>Validation Demo</h1>
  <p>Enter information, see if you can break the form.</p>
  <form method="post">
    @Html.ValidationSummary()
    <div>
      <label for="screenName">Your screen name (up to 10 characters): </label>
      <input type="text" name="screenName"
              value="@Request["screenName"]"
                  @Validation.For("screenName") />
      @Html.ValidationMessage("screenName")
    </div>

    <div>
      <label for="faveNum">Your favorite number (1-100): </label>
      <input type="number" name="faveNum"
              value="@Request["faveNum"]"
                  @Validation.For("faveNum") />
      @Html.ValidationMessage("faveNum")
    </div>

    <div>
      <label for="faveUrl">Favorite website (URL): </label>
      <input type="text" name="faveUrl"
              value="@Request["faveUrl"]"
                                    @Validation.For("faveUrl") />
      @Html.ValidationMessage("faveUrl")
    </div>

   <div>
      <input type="submit" value="Submit" class="submit" />
    </div>

    <div>
      @if(IsPost){
        <p>@Html.Raw(message)</p>
      }
    </div>
  </form>
</body>
</html>

Some checks will not be made on the client: data type validation is not done. You could choose to add some of these checks, as HTML5 forms added values to the type attribute that would permit direct client-side checks of them.

These checks are made on the client (as well as the server):

  • Required

  • Range(min,max)

  • StringLength(max-length, optional-min-length])

  • Regex(pattern)

  • EqualsTo(otherField)

In this example, the test for a valid URL won’t work in client code. However, the test will be performed in server code.

Note that validation checks will be applied to form data regardless of whether it is submitted with GET or POST; however, our IsValid check only occurs if the form has been submitted via a POST request, given how we’ve coded the page (which, since the form is submitted POST, works just fine).

Tip

When would you want to submit form data with GET? Hint: google.com does this.

Submitting form data with GET is useful if you want to let the user bookmark the results.

In fully-fledged web sites, if bookmarking form results is expected, usually more advanced methods are used so that the bookmark looks like a URL with no parameters - which is one key reason why ASP.NET includes routing and ways to redefine it. This can be important in Search Engine Optimization (SEO).

10.6. HTML5 validation tools

HTML5 provides several new form attributes for client-side validation of form contents. It also has CSS selectors to enable highlighting bad form values; these are not fully integrated with Validation.For, so be sure to test them carefully.

Css has a :invalid and a :valid selector that can be useful in providing visual cues to the user:

input:invalid {
  border: 1px solid red;
}
input:valid {
  border: 1px solid green;
}

These attributes can be used on form fields (<input>, <select>, <textarea>, and the other items active in a field):

attribute values description

required

presence

field cannot be blank when submitted

maxLength

integer

limits the numer of characters in the field

pattern

regex

requires the input match the regular expression supplied

min and max

integers

limit the range of values in the field

disabled

-

value cannot be changed from what is shown

The type value can be set to something other than text for more complete checking of types on the client. The recognized values are:

type value notes

text

constrained by maxLength

number

can be decimal; constrained by min and max

email

not validated in all browsers yet

tel

semantic type for telephone numbers, but not validated due to the large variety of formats around the world

url

valid URL

password

not displayed to the user; however, clear-text in the POST value

search

text field, but set up as a search

In addition you can provide <datalist>s to suggest appropriate values to the user; they can type in any value, but the datalist will be used for autocomplete if the user’s input matches a prefix of any of the values.

<label for="faveUrl">What's your favorite web site?</label>
<input type="url" id="faveUrl" list="suggUrl" />
<datalist id="suggUrl">
  <option>http://google.com/</option>
  <option>http://stackoverflow.com/</option>
  <option>http://slack.net/</option>
  <option>http://wired.com.</option>
</datalist>

Another type of example you can provide is a "placeholder" attribute value, which puts a value in the text box that disappears as soon as the user types. The internet community has not decided whether it likes these or not, see if you think they add value to your site.

<label for="faveNum">What's your favorite number?</label>
<input type="number" id="faveNum" placeholder="42" />

Note that even with type=number in the form, the value provided to you on the server is still a string.

There are no built-in checks for dates; however there is a datepicke available in jquery-ui. This helps the user enter the date correctly, and also gives them a clear visual to improve data entry accuracy. See https://jqueryui.com/datepicker/ for details on its use.

10.7. Helpers

The Validation class is a Razor Helper; it is there to make generating validating web pages easier, and it does its job well.

There are several other Helper classes provided in ASP.NET to aid in generating solid web pages.

We already discussed HTML encoding issues, and the use of Html.Raw and Html.Encode to protect your site against HTML/JavaScript injection attacks.

We also covered the WebGrid and Map Helpers when we discussed collections and databases.

However, the HtmlHelper class contains quite a variety of methods that can be very useful in generating a variety of HTML structures.

Tip
Porting happens

It’s up to you to use the form helpers or not — if you use them, you are tieing your code very tightly to the ASP.NET section of the universe. If you write out the HTML yourself, then at least the client-side code for your website is easier to port to another web stack. Porting is the act of taking your code from one framework or language and rewriting it to work under a different framework or language. HTML5 has come a long way, so it is not as important to use the HtmlHelpers in ASP.NET as it was prior to HTML5.

Html Helper method description

Html.CheckBox

generate a checkbox field

Html.DropDownList

generate a select list field

Html.Hidden

generate a hidden field

Html.Label

generate a label for a given field

Html.ListBox

generate a select list field

Html.Password

generate a password field

Html.Radio

generate a radio-button field

Html.TextArea

generate a textarea field

Html.TextBox

generate a text field

Each of these methods has several different implementations (it is overloaded).

For example, TextBox has these signatures:

signature use

TextBox(string)

generates the field with the given string as name and id attribute values.

TextBox(string, object)

as above; the object specifies the initial value (its ToString will be used)

TextBox(String, Object, IDictionary<String, Object>)

as above, and pass additional attributes as key/value pairs

TextBox(String, Object, Object)

same as the previous one, using an anonymous object rather than a dictionary

You can see details of these with examples on the MSDN ASP.NET Web Pages 2 Reference page on HtmlHelper Methods

The following sample creates a drop down list using the helper. Helpers like this are especially useful when you are displaying a form based on values in a database (the SelectListItem can be constructed when you return values from the database).

Listing 35. DropDownListHtmlHelperDemo.cshtml
<!DOCTYPE html>
<html>
<head>
    <title>Drop Down List Demo</title>
</head>
<body>
    <h1>Drop Down List Demo</h1>

    @{
        // build the list for the drop down list manually or
        // pull a list of name/value pairs from a database.
        List<SelectListItem> items = new List<SelectListItem>();

        items.Add(new SelectListItem { Text = "Ford", Value = "ford" });
        items.Add(new SelectListItem { Text = "Chevrolet", Value = "chevrolet" });
        items.Add(new SelectListItem { Text = "GMC", Value = "gmc", Selected = true });
        items.Add(new SelectListItem { Text = "Lincoln", Value = "lincoln" });

    }

    <form method="get"> <!-- choice visible in URL on submit -->
        @Html.Label("Choose one:","choiceList")
        @Html.DropDownList("choiceList", @items)
        <input type="submit" />
    </form>

</body>
</html>

Notice that the DropDownList requires a collection of SelectItem`s to provide the name/value pairs needed for the list. `ListBox behaves similarly.

The generated form looks like this on the page:

<form method="get"> <!-- choice visible in URL on submit -->
        <label for="choiceList">Choose one:</label>
        <select id="choiceList" name="choiceList">
<option value="ford">Ford</option>
<option value="chevrolet">Chevrolet</option>
<option selected="selected" value="gmc">GMC</option>
<option value="lincoln">Lincoln</option>
</select>
        <input type="submit" />
</form>
Tip

These Helpers become more useful in ASP.NET MVC, when Model class attributes also impact the HTML they generate.


10.8. Other helpers

ASP.NET provides several other helpers you might find useful to explore, see the System.Web.Helpers namespace for links to their specifications. Here are a few you may be interested in exploring further:

Class Description

AntiForgery

helps prevent forged requests and cross-site scripting attacks

Chart

generates charts from data (see tutorial)

Crypto

encryption capabilities for keys and passwords

Json

manipulates data in JavaScript Object Notation (JSON) format.

WebCache

helps improve performance by caching client-side data (see tutorial)

WebGrid

generates a HTML table from data

WebImage

image display and management

WebMail

email using Simple Mail Transfer Protocol (SMTP)

10.9. Other HTTP request data sources

As we mentioned earlier, there are 5 sources of data in an HTTP Request:

  • QueryString

  • Form

  • Cookies

  • ClientCertificate

  • ServerVariables

When you access the Form fields, you usually know the names of the fields; however that may not be the case with the final three.

All five are actually collections, and so could be accessed with foreach loops, iterating through their contents.

10.9.1. Cookies

In the Cookies collection, each cookie is an element in the collection; it is an instance of System.Web.HttpCookie, with several cookie properties:

HttpCookie property description

Domain

the domain the cookie is associated with

HasKeys

true if the cookie has subkeys

HttpOnly

false if the cookie is accessible by client-side script

Item[String]

a shortcut to the Values property (for backward compatibility)

Name

the name of the cookie (its key)

Path

the virtual path of the cookie

Secure

indicates whether to transmit using HTTPS only or not

Shareable

if true, the cookie can participate in output caching

Value

the cookie’s value

Values

the cookie’s key/value pairs if they are embedded within the cookie

It’s not likely we will be using cookies with our simple applications, but there are some Helpers for Security that will be making use of them. Cookies are one way to maintain session state if you need to retain information for a user session.

Name and Value are the two properties you would be most likely to want to read, as they represent the key/value pair of the cookie.

Note

The European Union has strict regulations on the use of cookies, so it’s best to pop up a warning to inform the user you are using cookies to satisfy their regulations, regardless of the source of the HTTP request you are processing.

Be careful about what you put in cookies; they travel between client and server, and so you risk exposing information in a live web site that could compromise security.

10.9.2. ClientCertificate

The ClientCertificate property holds an HttpClientCertificate object, which contains information about the client’s security certificate, if one was provided in the HttpRequest. This class has several fields, and it is likely you would want to print them all out to get a complete view of the certificate.

ClientCertificate properties

Certificate

Cookie

Flags

IsPresent

Issuer

IsValid

KeySize

SecretKeySize

SerialNumber

ServerIssuer

ServerSubject

Subject

ValidFrom

ValidUntil

You may find that a ToString or ObjectInfo.Print call will give you sufficient information should you need to debug a certificate. Be careful exposing this information in a live web site, as it could compromise security.

10.9.3. ServerVariables

The web server runs within an operating system itself. At the operating system level, it is possible to set environment variables. This is often done as a way to configure servers with sensitive information such as passwords - putting them in _AppStart.cshtml is not secure if your source code is Open Source, as then anyone who finds your Open Source repository can see the contents of that file.

The variables can be browsed with the ServerVariables property. This is often quite a long list, so be prepared for output if you print them all out.

The ServerVariables property holds a NameValueCollection, so is accessed like other dictionaries, getting the AllKeys property, which provides an array of strings, with each entry in the array being a key from the collection. Then the code needs to iterate through the keys to get the values associated with each key in turn. A NameValueCollection can map one key to several values, so once the values are retrieved with the GetValues(key-value) method as an array of strings, an embedded for loop (or foreach loop) is needed to print out that array’s contents in turn.

Be careful exposing this information in a live web site, as it could compromise security.