BTI420 notes – Tue Feb 17

Working with ‘details’ views. Handling the ‘edit item’ and ‘delete item’ use cases.

.

Quiz today

Near the end of the class/session, we’ll have a quiz.

The quiz will be ten (10) minutes in length.

You will answer two or three questions, on a single sheet of paper. The questions will cover topics, concepts, definitions, descriptions, and so on. Think about a question-and-answer session in a job interview. Those are the kinds of questions you can expect.

.

Prepare for in-class evaluation

In your Thursday (section B) or Monday (section A) class/session, we will have an in-class evaluation.

You will complete a programming task within a fixed period of time. As a hands-on evaluation, it is an ideal way to assess your capabilities.

.

Working with ‘details’ views

At this point in the course, you have been introduced to a ‘details’ view, as prepared by the scaffolder.

Today, you will learn more.

When scaffolding a ‘details’ view, you specify the view model class. The scaffolder then renders a view using a <dl> (description list) element as a container for <dt> (definition term) and <dd> (description) elements.

However, it does not render the following view model properties:

  • Id
  • navigation object or collection

.

details-artist-view-original

.

We really do not need to render the Id property, but we would probably like to render properties from the associated object and/or collection. To do this, we follow a general approach:

  1. for an entity, write a view model class that includes an associated object/collection property
  2. write a manager method that fetches an object with its associated object(s)
  3. call that method from the controller, and pass the results to the ‘details’ view
  4. edit the ‘details’ view to include this content

.

View model class, for the Artist entity, that includes an Album collection property

For the Artist entity, write a view model class that includes the Albums collection; something like this:

details-artist-view-model-class

.

Also, make sure that you add an AutoMapper CreateMap() method for this new view model class.

.

Manager method, for the Artist entity

Write a manager method that fetches a specific Artist object, with its collection of Albums; something like this:

details-artist-manager-fetch-method

.

Controller Details() method

In the past, you have coded a controller’s ‘details’ method to fetch then return a specific item.

You will do that here too.

However, there are two improvements that you must make to the method:

  1. change the type of the ‘id’ parameter to a nullable int
  2. verify that the manager returned a valid object

.

Open one of your existing projects that has a ‘details’ view. Test the above scenarios, with invalid URLs:

  1. on the URL, do not include a value for the ‘id’ parameter (e.g. /products/details/)
  2. on the URL, include a value for the ‘id’ parameter that does not exist (e.g. /products/details/4567)

.

What happens? Errors. Let’s fix them.

Change the type of the ‘id’ parameter to a nullable int 

Change the type of the id parameter to “int? id”.

Then, as the first statement, if id.HasValue, you can continue. If not, exit (by returning HttpNotFound()).

Verify that the manager returned a valid object

Instead of calling the manager method as an argument to return View(), use a temporary variable for the manager method’s return value. If the value is null, then exit. Otherwise pass the value to the view.

Here’s a suggested coding pattern:

details-artist-controller-details-method

.

Edit the ‘details’ view to include this content

Add the view, using scaffolding. Make sure that you specify the view model class that has the associated object(s).

Look at the view code. It will be missing some properties. For this situation, it will not render the collection of albums for the artist. We must add this code.

Here’s one approach:

details-artist-view-render-albums

.

The end result – it’s better, yes?

details-artist-view-with-albums

.

Running the invalid URL tests again

error-httpnotfoundBefore continuing, run the invalid URL tests again, from above:

  1. on the URL, do not include a value for the ‘id’ parameter (e.g. /artists/details/)
  2. on the URL, include a value for the ‘id’ parameter that does not exist (e.g. /artists/details/4567)

.

What happens? A generic error page appears. (Click to view it full-size in its own tab/window.)

This page is not user-friendly. Read this document for information on how to solve this problem.

.

Do the same task for the Album details view

If you use the scaffolder to create the ‘details’ view for an Album entity, you will see something like this:

details-album-view-original

.

Boring. Follow the instructions above to create an improved Album details view:

  • include the artist name
  • show the album cover image
  • render the album’s collection of songs

.

Hopefully, you will end up with something like this:

details-album-view-with-artist-and-songs

.

When coding the view model classes (perhaps with a name similar to “AlbumBaseWithSongs”), it will include a string property for the artist name, and a collection property for the songs. The ‘artist name’ string property was probably added to the “AlbumBase” view model class (it was in the Lab 5 specifications). Therefore, in the …WithSongs view model class, add the songs collection property.

.

Then, in the manager method that fetches a specific album, you will need two Include() method calls in the ‘fetch object’ statement:

details-album-manager-fetch-method

.

Do the same task for the Song details view

If you use the scaffolder to create the ‘details’ view for an Song entity, you will see something like this:

details-song-view-original

.

Boring. Follow the instructions above to create an improved Song details view:

  • maybe include more details about the artist and album
  • show the album cover image
  • delete the useless “AlbumId” field

.

Hopefully, you will end up with something like this:

details-song-view-with-album-and-artist

.

The Song entity is at the end of a chain of associations:

Artist > Album > Song

We need to ‘reach back’ to the top level – Artist – to fetch info from that object. How?

The SongBase view model class needs this property:


public AlbumBase Album { get; set; }

.

The AlbumBase view model needs this property:


public ArtistBase Artist { get; set; }

.

The manager method that fetches the specific song object must Include(“Album.Artist”).

.

Handling the ‘edit item’ use case

Handling an ‘edit item’ use case will seem similar to the ‘add item’ use case.

Two controller methods are needed. The HTTP GET handler will prepare the HTML Form, and the HTTP POST handler will process the user’s changes.

Both methods need their own view model classes, ‘item edit form’ and ‘item edit’. These view model classes may be identical to the ‘item add form’ and ‘item add’ classes, but they do not have to be. (One notable difference is that each includes the “Id” identifier property.)

General approach:

  1. Create view model classes
  2. Write two controller methods to service the GET and POST requests
  3. Write the manager method to process the edit request

The MusicBusiless web app code example, in the GitHub repository, will help you learn about the ‘edit’ and ‘delete’ patterns.

.

View model classes

Look at an entity object’s properties, and decide which are to be editable.

Not all properties need to be editable. It’s your choice.

Create a view model class (e.g. AlbumEditForm) to send to the HTML Form on the view, which includes:

  1. the object identifier,
  2. the editable properties, and
  3. anything else that needs to be rendered (e.g. SelectList for an <input> or <select> element).

.

Next, create a view model class (e.g. AlbumEdit) for the object that the user will post back.

.

Controller methods

The edit pattern requires a GET method and a POST method, similar to the ‘add item’ functionality.

In the GET method, create and configure the ‘item edit form’ object to send to the view, and do it.

In the POST method, two verification checks must always be performed.

The first checks whether the incoming object passes ModelState.IsValid. The second checks whether the identifier in the URI matches the identifier in the posted object. If both these checks pass, send it along to the manager object method that does the work. Handle the return value in an appropriate way.

What’s appropriate? It depends upon your use case. It may be acceptable to do any of the following:

  1. Display the edited object in a ‘details’ view
  2. Return to a ‘list’ view
  3. Return the ‘edit’ HTML Form again for additional editing tasks

.

If either check fails, return the ‘edit’ view, which will tell the user what to fix.

.

Manager method

In the manager class method, handle the editing request by doing the following:

  1. Extract the object identifier from the passed-in object
  2. Locate the object in the data store
  3. Update the object’s information
  4. Save the changes back to the data store
  5. Return the edited object

.

The fetched object offers a very nice SetValues() method that performs task 3 above. For example:


ds.Entry(fetchedObject).CurrentValue.SetValues(newItem);

.

It examines fetchedObject, and performs a property-matching task (name and data type). On a match, if the values are different, an update is performed. (If the values are the same, it moves on to the next property. Navigation properties are ignored. Extra properties are ignored. Missing properties are ignored. The ‘ignore’ result does not raise an exception.)

.

Handling the ‘delete item’ use case

Like the ‘add’ and ‘edit’ patterns, this is done as a GET and POST pair.

We display an HTML Form to the user, prompting them to confirm that yes, they want to delete the object. Create a view model object with enough information for the user to make a decision.

The delete handler method performs one or more validity checks, and then calls a manager method to perform the delete.

The manager method, in our initial design approach, returns a bool result. If you wish, you can use that to return an appropriate result to the user.

The above approach would permanently delete the object from the persistent storage.

This is not always a good thing. We may talk about this later in the course.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

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: