BTI420 notes – Thu Jan 22 and Mon Jan 26

Get data from a user. More about the Razor view engine. Scaffolding intro. Data persistence introduction. The “data manager” concept.

.

Code examples for today

1. GetDataFromUser

2. FormsIntro

.

Get data from a user

There are many ways to get data from a user (who is using a browser) into your app. Today, we will study three ways:

  1. From the URI, as query string data
  2. From an HTML Form, by reading the values in the request body data
  3. From an HTML Form, by using the preferred way, which is to use a strongly-typed view model

.

From the URI

The request processing framework parses ALL query string key-value pairs.

However, you can add parameters to the controller method for important values:

  • The parameter name must be used as the key name on the query string
  • The parameter data type must be string

Adding a parameter makes it simpler to refer to its passed-in value. If you don’t add the parameter, you’ll have to enumerate through all key-value pairs, looking for the data you need or want.

You must check whether the passed-in value exists. There are at least two ways to do this:

  1. Check whether Request.QueryString[“whatever”] is null or not
  2. Use string.IsNullOrEmpty(parameterName)

.

From an HTML Form, request body data

We ALWAYS use two methods with an HTML Form.

  • One method displays the form
  • The other method handles the form’s posted data

A programming best practice tells us to prefix the form post handling method with an [HttpPost] attribute.

In the form post handling method, your code can access the HTML Form data by using Request.Form. For example, assume that you wish to get access to the “first name” text box data (<input name=”firstName”…):

string firstName = Request.Form[“firstName”];

The data type of all incoming data is string. You must cast/convert to other data types if you need to.

After the form post handler completes its work, it ALWAYS redirects to a page/view. It can be to the same page, or to some other page. This approach implements the Post/Redirect/Get (PRG) pattern:

  1. Post: The page user submits the form, which creates an HTTP POST request
  2. Redirect: The form post handler completes its work, then 1) sets the Location response header to the URI of the page to go to, and 2) sets the response status code to 302
  3. Get: The browser receives the response, and as a result of the status code 302, it sends another HTTP GET request to the URI of the page that was in the Location header

The most notable benefit of using this pattern is that it prevents the browser user from the negative effects of executing the browser’s “back” or “refresh” (F5, or Ctrl+R, or Cmd+R) functions.

.

From an HTML Form, strongly-typed view model

As noted above, we ALWAYS use two methods with an HTML Form. And we ALWAYS use the PRG pattern.

What’s different in this approach? Well, Request.Form works fine for a few input fields, but an HTML Form with many inputs requires more code. In addition, there’s no check or test whether data for all fields was submitted. (And no check for “over-posting”, which is a security threat.)

Here’s what to do. It’s simple. Add a parameter to the form post handling method; its data type is a view model which matches the exact shape of the data collected in the HTML Form.

Then, at the top of the method, you can add this simple test:
if (ModelState.IsValid) …

The request processing framework will match and validate the posted data against the view model. (Soon, you will learn about data annotations, which enhance this match-and-validate process.)

Your code will also be easier to write, with fewer statements. Compare the two ways of getting access to a ‘first name’ HTML Form value. The first statement uses Request.Form, and the second uses the local variable name for the passed-in strongly-typed object (perhaps named “newitem”):

string firstName = Request.Form[“firstName”];
– or –
string firstName = newItem.FirstName;

 

More about ModelState and the PRG pattern

You have just learned that you must use the PRG pattern in the method that handles the HTML Form post.

You have also just learned that the ModelState property can easily validate the posted data.

So, do you use the PRG pattern if ModelState.IsValid is false?

No.

Simply return the view.

What if the browser user executes the browser’s “refresh” or “back” function?

Nothing bad.

If “back”, the browser displays the view as it existed before it was posted. That’s OK.

If “refresh”, the browser displays a dialog, as shown below (from Google Chrome v46):

  • If the browser user chooses “Cancel”, then the “refresh” function is cancelled
  • If the browser user chooses “Continue”, then the HTML Form is submitted again; the error condition will still exist, so the view (and its error message(s)) will still be displayed

In summary, nothing will be saved / changed / affected.

prg-browser-refresh

 

More about the Razor View Engine

The textbook has good coverage of this topic in chapter 3, “Views”.

The Razor View Engine is used during request processing to generate an HTML response. The view is the source code file that contains markup and code expressions.

  • Markup language is HTML
  • Code expression language is (for us in this course) C#

Begin a code expression with the ‘at’ sign, @. Then use C#. Razor will transition back to markup at the end of the code expression (in most situations).

In a view, the “Model” property is the strongly-typed model object that is passed in from the controller:

The first line of code in the view should declare the model object’s type…
@model IEnumerable<MyProject.Controllers.PersonFull>

Then, in the markup, it is dereferenced with “Model”.

Notice the difference – in the declaration, “model” begins with a lower-case letter. However, the “Model” property begins with an upper-case letter.

The “ViewBag” property provides access to other data that is passed in from the controller. It is dereferenced with “@ViewBag”. You should try to avoid its frequent use.

A multi-line code expression is placed in a code block: @{ }

Use parentheses to remove ambiguity: @( )

.

Introduction to “scaffolding”

This is a feature of the framework that’s well-loved by developers.

Question – what web app programming task is annoying?

Answer – for most people, its programming pages that perform common data operations – get-all, get-one, create, update, and delete.

Scaffolding helps address this task. We can build controllers easier, and views easier. Although some of the results may not make a web designer happy, they enable us to get results fast, and build a base that can be extended.

The ASP.NET MVC designers didn’t invent this approach. It was a well-established feature by the time they got started in 2009. Every major web app framework does this now.

We’ll create an app that performs data operations, using scaffolding. You’ll also learn to create a “manager” class for an ASP.NET web app that centralizes data operations. It’s a transitional concept, on the way to a more modular approach in the near future.

Although we’ll build some of this in real time, there’s a posted code example that supports this topic.

.

Data persistence introduction

At this point in the course, it’s time to learn something about data persistence.

We plan to use different data stores during the course. The first data store will be a simple plain-text (JSON) file-based store, managed by the Biggy project.

Add Biggy to your project:

  1. In Solution Explorer, select your project; it’s the one with this icon… project-icon
  2. Right-click, choose Manage NuGet Packages…
  3. On the left-side navigation panel, choose “Online”
  4. In the upper-right search field, search for “biggy json”
  5. The first result should be “Biggy.Data.Json” – select it, and “Install”

.

nuget-search-for-biggy-json

.

FYI: There’s a command-line alternative to the dialog box. On the TOOLS menu, choose NuGet Package Manager, then Package Manager Console. The console window/panel will open at the bottom of the editor area. Run this command:

install-package biggy.data.json

.

How do you use Biggy?

Before you begin, you need to know that it uses the “App_Data” folder (in your project) to store its data. So, you need to know the file system path to that folder.

Therefore, the first task that you must do is create (or open) the data store. (If the app has been loaded for the first time, it will create the data store. However, after that, it will open the data store.) The code looks something like this:

var store = new JsonStore<PersonFull>(localData, “your-name-for-the-data-store“, “collection-name“);

Then, you will create (or attach to) the collection you want. (As above, if the app has been loaded for the first time, it will create the collection. However, after that, it will attach to the collection.) The code looks something like this:

var whatever-items = new BiggyList<Object-Class-Name>(store);

The “whatever-items” collection can be added to (the Add method), or the collection can be worked with. Use the AsEnumerable method to convert it to a type that plays nice with other parts of your app.

.

The “data manager” concept

If we are going to work with persistent data, then it’s time to learn something about the “data manager” concept.

It is possible that a web app can grow to have a very large code base, with many controllers and views. We do not want to ‘sprinkle’ data access code throughout the controllers. How to solve this?

With a “data manager” class. It will manage the app’s data, by exposing properties and methods. Any controller can create an instance of the class, and work with the app’s data.

How do you implement this concept?

In the Controllers folder, add a new source code file named Manager.cs, which (by default) will create a Manager class.

Its default constructor will connect to (or open) the data store. (If the app is being loaded for the first time, the constructor will create the data store, and maybe add some initial data.)

Add one or more properties for your app’s collections. Use a custom getter to deliver results in a default ordered manner, as an IEnumerable<T>. Also, you will not need a setter.

Add one or more methods to perform data operations. For example, ‘add new’.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: