Objective(s)

Introduction to the problem to be solved

The recently-completed Assignment 7 enabled you to learn how to create your own data model in an ASP.NET MVC web app. We will assume that you are familiar with the Assignment 7 specifications.

In your work, recall that you programmatically added data to the genre, artist, album, and track entity collections.

Here, in Assignment 8, you will add functionality to enable browser users to add, edit, and delete objects. Depending on the entity, users must possess specific role claims to be able to begin or complete data modification tasks.

Also, in your work, you probably did not pay attention to the appearance of many of the views. In this assignment, you will learn simple and repeatable ways to improve the appearance.

Specifications overview and work plan

For this and the remaining assignments, continue to follow the oft-repeated list of general specifications (e.g. follows best practices, etc.). Here’s a brief list of specifications that are new to this assignment:

Enable “add new” use case for Artist, Album, and Track objects

Enable “edit existing” and “delete item” use cases for the Track object

Implement security settings that limit who can do which tasks

Here is a brief work plan sequence:

Add methods to the Manager class that handle the new use cases

Modify the Artist controller, implement the new use cases, including views and view models

Modify the Album controller, implement the new use cases, including views and view models

Modify the Track controller, implement the new use cases, including views and view models

During the class/session, your professor will help you get started and make progress on this assignment.

Every week, in the computer-lab class/session, your teacher will record a grade when you complete a specific small portion of the assignment. We call this “in-class grading“.

The in-class grading will be announced in-class by your professor.

Getting started

Your teacher team has created a sample solution for Assignment 7, and posted it to Blackboard/My.Seneca, in the Assignments area. Download that, and use it as a base project for your work.

When you open it, you will notice that the enclosing folder has been named “Assignment8”. However, inside, the other folders and files will still have the “Assignment7” names. Don’t worry about that, it’s unimportant for your work.

Build/compile, and run the app, to ensure that you are starting with a working error-free base. Then, as you write code, build/compile frequently.

Design model classes

Here’s a diagram of the design model classes. They are exactly the same as specified in Assignment 7. No changes.

Notice that the Genre class is NOT associated in any way with the other classes, as originally specified.

Now, let’s get to work. Remember, we are adding data modification features to the base web app.

Add methods to the Manager class that handle the new use cases

In this section, you will work in the Manager class, and you will be working with view model classes at the same time, in an iterative manner. And, it’s likely that you will begin work on a controller action, and decide that you must return to the manager method to add or fix something. That’s normal, and expected.

Here is a full list of use cases that will be supported:

Artist – add new

Album – add new (which requires an artist identifier)

Track – add new (which requires an album identifier)

Track – edit existing (some properties only)

Track – delete item

A reminder: Add new and edit existing will require “form” view model classes. For example:

ArtistAddForm

AlbumAddForm

etc.

And obviously, each will require an “add” view model class for the data entered by the browser user.

Associated data

When adding a new artist, we will not need to configure an associated album.

When adding a new album, we WILL need to configure an associated artist. As a starting point, assume that it will work the same as it does in the “Associations Add Edit” code example, where a vehicle could be added while working with a manufacturer. Here, we will be adding an album for a known artist.

However, we will also allow the browser user to select other artists, if any. Therefore, to the AlbumAddForm view model class, add a string property to display the name of the known associated artist, and a MultiSelectList property for all artists. Later, in the controller work, we will pre-select the known artist, when we create the MultiSelectList object. The view model class must also have an artist identifier property, configured as a hidden HTML Forms element.

Similarly, when adding a new track, we WILL need to configure an associated album. Assume that it will work in a way similar to above, where we will be adding a track for a known album.

Different from above, do not allow the browser user to select the album (or other albums). Therefore, add one or more properties to the view model class that enables you to display information about the associated album. As above, the view model class must also have an album identifier property, configured as a hidden HTML Forms element.

Genre data

Every artist, album, and track has a “Genre” string property. (It is NOT a navigation property.)

For every “add new” task, the browser user must be able to select from the allowable genres (as stored in the entity collection). Therefore, each new “…AddForm” view model class must have a SelectList property to hold the genres. And, each new “…Add” view model class must have a string property to hold the genre that was selected by the browser user.

User / owner data

Please note that there is a property in each new entity object that is designed to hold the user name of the current security principal (i.e. the authenticated user):

Artist has an “Executive” string property

Album has “Coordinator”

Track has “Clerk”

The value of the property is set/configured in the manager method. Do NOT attempt to do this work in the controller or view models. (If you do not know the reason for this, read the recent class notes, or ask your professor.)

Info about the Artist “add new” in the Manager class

For the “add new” use case, treat it like like any other “add new” situation. Don’t worry about associated data when adding an artist. Treat it as the most important object in the Artist-Album-Track interrelationship, so an artist object must always be created before we create an album (or track) object.

New method to fetch all tracks by a specific artist

Before discussing Album “add new”, we need another Manager method that will fetch all tracks for a specific artist. Maybe named something like “TrackGetAllByArtistId” (and returning a collection of TrackBase objects). Here’s a coding plan that you can follow:

// Fetch the object for the specific artist, and include albums and tracks
// Create a new in-memory collection to hold track objects
// Go through each album...
// Add the tracks to the new collection
// How? Use the "AddRange" method to do this
// https://msdn.microsoft.com/en-us/library/z883w3dc(v=vs.110).aspx
// Remove duplicates
// How? Use the "Distinct" method to do this
// https://msdn.microsoft.com/en-us/library/bb348436(v=vs.110).aspx
// Return the new collection, mapped to TrackBase objects

Info about the Album “add new” in the Manager class

The “add new” album use case will probably be the most challenging to handle in this assignment.

When adding a new album, we will assume that we’re currently working with – and have a reference to – an existing known artist object. Therefore, we must have that reference, and handle that data configuration task.

We will also allow other artists to be selected in the user interface, and therefore configured in this Manager class method. As a result, you will expect to get a collection of int values (artist identifiers), each of which must be validated and configured.

Finally, we will allow the artist’s tracks to be selected in the user interface, and therefore configured in this Manager class method. As a result, you will expect to get a collection of int values (track identifiers), each of which must be validated and configured.

Here’s a coding plan that you can follow for the “add new” album method in the Manager class:

// Assume that the name of the incoming AlbumAdd parameter is "newItem"
// Validate each of the associated artists...
// Create a new empty collection of Artist objects
// For each artist ID in newItem.ArtistIds
// Find the artist by its ID
// If found, add it to the collection of Artist objects
// Validate each of the associated tracks...
// Create a new empty collection of Track objects
// For each artist ID in newItem.ArtistIds
// Find the artist by its ID
// If found, add it to the collection of Track objects
// Continue only if there is at least one associated artist object
// Attempt to add the new album
// For each associated artist
// Add it to the new album's Artists collection
// For each associated track
// Add it to the new album's Tracks collection
// Set the Coordinator user name property
// Save changes
// Return the new album

Info about the Track “add new” in the Manager class

The “add new” use case will be much easier than album, but not as easy as artist.

When adding a new track, we will assume that we’re currently working with – and have a reference to – an existing known album object. Therefore, we must have that reference, and handle that data configuration task. Expect to get a single int value (album identifier), which must be validated and configured.

Supporting “add new” Artist

Handling the “add new” use case is familiar, and has no surprises. Just a few things to consider.

The “add new” pair of methods must be protected with an authorize attribute which allows only those with the Executive role claim to run the code.

Next, in the GET method, the “…AddForm” object must be created, and the genre select list object configured, before the object is passed to the view.

In the view, you must add the code to render a single-selection item selection element (e.g. dropdown list, or radio button group) for the genre. And fix the title etc.

Here’s what your initial result may look like. Click the image to open it full-size in a new tab/window.

In the POST method, handle the user-submitted data as you have done before.

After successfully adding the new artist object, redirect to the details view for the new artist object.

Supporting “add new” Album

As noted above, the album “add new” use case will be the most challenging to implement in this assignment. Here is some guidance. Read it through and think while reading, and then return to begin work.

Add new – GET method

When adding a new album, we WILL need to configure an associated artist. Again, assume that it will work the same as it does in the “Associations Add Edit” code example, where a vehicle could be added while working with a manufacturer.

In that code example, you learned that the code to add a new vehicle was in the manufacturer controller.

Note: It would probably be a good idea to have that code example open, so that you could remind yourself about the design technique and coding style.

We will follow that example here. So, switch over to the artists controller. We will create the “add new” album method pair in the artists controller.

The “add new” album pair of methods must be protected with an authorize attribute which allows only those with the Coordinator role claim to run the code.

Create an AddAlbum(int? id) method. Use attribute routing; the route should be:

artist/{id}/addalbum

Next, a quick detour: The project template unfortunately does not include the command that activates attribute routing. You must add it. How? Open the App_Start > RouteConfig.cs source code file. In the RegisterRoutes() method, add this statement:

routes.MapMvcAttributeRoutes();

Next, write code to get/fetch the associated artist object, based on the “id” method parameter. In code, if the object exists, there are several tasks to complete:

Fourth: Configure the multi select list object for the artists. Remember, we are adding an album for the current known artist. However, we will allow the user to select other artists too.

Therefore, we will configure the multi select list object with the current known artist identifier, as the selected value. The multi select list object constructor takes a collection of selected values, so you’ll have to package the current known artist identifier inside a new collection.

Hint: Look at any of the code examples we have done, and the code that you have written, to remind yourself about the suggested way to code/configure a multi select list object. For example, look at this controller, starting at line 75.

Fifth: Configure the multi select list object for the tracks.

Add new – view

Generate the view.

Run the web app, and then attempt to display this new view. Here’s what your initial result may look like. Click the image to open it full-size in a new tab/window.

To allow a browser user to navigate to the view, we suggest adding a hyperlink to the “Artist detail” view, which will point to this new view. This makes sense, because we are starting at a specific known artist, and adding a new album for that artist.

Another fix-up, on the list-of-albums view: Comment out or remove the “Create new album” hyperlink.

Now, look at the generated “add new” album view. It does not have any of the select list items. Or a title. So, fix these problems:

Change the title so that it’s useful.

Add the code to render the genres dropdown list.

We need the artist identifier, but we must not display it. Therefore, inside the HTML Form code in the view source code file, add code to keep it around as an HTML input field that’s hidden.

@Html.Hidden("ArtistId", Model.ArtistId)

Add the multi select list code for the artists check box group. Add another for the tracks check box group.

Hint: Use the Bootstrap row class to position the check box groups beside each other.

Offset the left-side group by 2 (which is the standard width of the form label area), and the right-side group by 1 (to create some space between). If you want to shade their backgrounds, use the well class.

You may end up with a result that looks like this. Click the image to open it full-size in a new tab/window.

Add new – POST method

This method will be similar to almost all other “add new” POST methods that you have written.

After model state validation, it will call a method in the manager object, and pass on the user-submitted data.

After a successful result, it will redirect to the details view for the new album.

Supporting “add new” Track

Here’s some information about the work plan for this section.

Add new – GET method

When adding a new track, we WILL need to configure an associated album. As above, assume that we will be adding a track for a known album.

We will follow the same pattern. Switch over to the albums controller. We will create the “add new” track method pair in that albums controller.

As noted earlier, the “add new” track pair of methods must be protected with an authorize attribute which allows only those with the Clerk role claim to run the code.

Create an AddTrack(int? id) method. Use attribute routing; the route should be:

album/{id}/addtrack

Next, write code to get/fetch the associated album object, based on the “id” method parameter. In code, if the object exists, there are several tasks to complete.

First: Create a new TrackAddForm.

Second: Configure the album name. Your TrackAddForm should have a string property for that.

Third: Configure the album identifier. Your TrackAddForm should have an int property for that.

Fourth: Configure the select list object for the genres.

Add new – view

Generate the view.

Run the web app, and then attempt to display this new view. Here’s what your initial result may look like. Click the image to open it full-size in a new tab/window.

To allow a browser user to navigate to the view, we suggest adding a hyperlink to the “Album detail” view, which will point to this new view. This makes sense, because we are starting at a specific known album, and adding a new track for that album.

Another fix-up, on the list-of-tracks view: Comment out or remove the “Create new track” hyperlink.

Now, look at the generated “add new” track view. It does not have the item-selection element. Or a title. It also displays data in editable fields. So, fix these problems:

Change the title so that it’s useful.

Add the code to render the genres dropdown list.

We need the album identifier, but we must not display it. Therefore, inside the HTML Form code in the view source code file, add code to keep it around as an HTML input field that’s hidden.

@Html.Hidden("AlbumId", Model.AlbumId)

You may end up with a result that looks like this. Click the image to open it full-size in a new tab/window.

Add new – POST method

This method will be similar to almost all other “add new” POST methods that you have written.

After model state validation, it will call a method in the manager object, and pass on the user-submitted data.

After a successful result, it will redirect to the details view for the new track.

Go back and improve the appearance of “get all” and “get one” views

In the previous assignment, the appearance of the views was (mostly) unchanged from the scaffolded views. In this section, you will update the “get all” and “get one” views to improve their appearance.

Artist – get all

Here’s what your initial result may look like. Click the image to open it full-size in a new tab/window.

The page title needs fixing, and the URL text is ugly. Why not rewrite that part of the view to render an HTML <img> element? Here’s what it could look like. Click the image to open it full-size in a new tab/window.

Artist – get one

Here’s what your initial result may look like. Click the image to open it full-size in a new tab/window.

The page title needs fixing, and the URL text is ugly. As above, why not rewrite that part of the view to render an HTML <img> element? Here’s what it could look like. Click the image to open it full-size in a new tab/window.

Album – get all

Here’s what your initial result may look like. Click the image to open it full-size in a new tab/window.

The page title needs fixing, and the URL text is ugly. As above, why not rewrite that part of the view to render an HTML <img> element? Here’s what it could look like. Click the image to open it full-size in a new tab/window. Click the image to open it full-size in a new tab/window.

Album – get one

In the view, fix the title etc. Also, use an HTML <img> element to render the album image / cover art. Here’s what your initial result may look like. Click the image to open it full-size in a new tab/window.

Track – get all

Here’s what your initial result may look like. Click the image to open it full-size in a new tab/window.

As is typical, there are a few things wrong with this list. We can fix some easily. So, fix the title, and remove (comment out) the “Create New” hyperlink. (The “add new” track feature will be linked from an album details page.) The AlbumId is useless on this “get all” list, so remove that data.

Track – get one

Here’s what your initial result may look like. Click the image to open it full-size in a new tab/window.

The title is ugly, so it must be fixed. Also, it would be nice for the tracks to include some album name information. For example, see below. Click the image to open it full-size in a new tab/window.

Here’s how to make that happen.

First, in the TrackWithDetail view model class, add a collection-of-strings property (maybe named AlbumNames), which will hold the names of the albums with this track.

Now, in the view, you will have a collection of strings in the AlbumNames property, which you can render in a foreach loop or whatever.

Note: Remember back in the album details section, where we stated that it would be nice to show the album artist(s) with the album details? You could fix that now, if you wish, using this same procedure.

Reminder about academic honesty

You must comply with the College’s academic honesty policy. Although you may interact and collaborate with others, you must submit your own work.

Submitting your work

Here’s how to submit your work, before the due date and time:

1. Locate the folder that holds your solution files. In Solution Explorer, right-click the “Solution” item, and choose “Open Folder in File Explorer”. It has three (or more) items: a Visual Studio Solution file, a folder that has your project’s source code, and a “packages” folder. Go UP one level.

2. Make a copy of the folder. This is the version that you will be uploading.

3. Remove the “packages” folder from the copied folder; also, remove the “bin” and “obj” folders.

4. Compress/zip the copied folder. The zip file SHOULD be about 2MB or less in size. If it isn’t, you haven’t followed the instructions properly.

5. Login to My.Seneca/Blackboard. Open the Web Programming on Windows course area. Click the “Assignments” link on the left-side navigator. Follow the link for this assignment. Submit/upload your zip file. The page will accept three submissions, so if you upload, then decide to fix something and upload again, you can do so.