BTI420 Assignment 9

Rich text handling. Working with non-text media types. Post app to a public web host.

Read/skim all of this document before you begin work.


Due date

Wednesday, March 29, 2017, at 11:00pm ET

Grade value: 5% of your final course grade

If you wish to submit the assignment before the due date and time, you can do that. 



Add functionality to an existing app. Implement richness for text and media item handling.


Introduction to the problem to be solved

The recently-completed Assignment 8 enabled you to learn how to create a nice and functional user interaction experience, for a new data model in an ASP.NET MVC web app. We will assume that you are familiar with the Assignment 8 specifications.

Here, in Assignment 9, you will add rich text handling, as typically found in a production-quality public-facing web app. In addition, you will have the ability to work with media items in many different forms, again typical of the public web.


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:

  • Working with internet media types
  • Rich text handling
  • Post to a public web server

Here is a brief work plan sequence:

  1. Modify the data model, to accommodate a lengthy rich text field in the Artist entity class
  2. Update “add new” and optionally implement “edit existing” for Artist, to support rich text entry
  3. Update “get…” view(s) to display objects that have rich text
  4. Modify the data model again, to accommodate non-text media types in the Artist and Track entity classes
  5. Support add and display of the richer-looking objects

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 the previous Assignment 8, 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 “Assignment9”. 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.


Data storage preparation tasks

Enable a feature named “Code First Migrations”. How?

Open the package manager console. Type this command:


It will discover an existing data store, and it will create a migration class named “InitialCreate”. That will represent the initial (current) state of the design model and data store.


Preparing for rich text editing

The Artist design model class needs another string property, to hold rich text.

In the Artist class, add a new string property named “Profile”. Data annotations? Lengthy (thousands of characters), but it does not need “[Required]”. Its intention is to capture content about the history, biographical data, and musical style of the artist.

Build/compile the app, and run/load it in a browser. Uh oh, an error:



As it states, the data model has changed.

To fix this, review the coverage of the Migrations feature in the March 24 and 27 class notes:

  1. add-migration descriptive-name-for-migration
  2. update-database


Reminder about the rich text editing recipe

This is fully covered in the March 17 and March 20 class notes, but here’s a brief reminder about the “recipe” for enabling rich text editing and display:

  1. Add [DataType(DataType.MultiLineText)] to the string property in the view model class (this will cause it to be rendered as an HTML <textarea> element)
  2. In the view, before the code that renders the string property, add a reference to the rich text editor app
  3. After the code that renders the string property, run the command to convert the <textarea> into a rich text editor rectangle
  4. In the controller method that handles the data submitted by the user (the POST method), add [ValidateInput(false)]
  5. When displaying rich text, use the Raw() HTML Helper


Update the “add new” artist use case

Here, update the “add new” artist use case to accommodate rich text. This will require edits to the view model classes, view, and the controller, as noted in the recipe above.

The goal is to configure the “add new” Artist view to look similar to the following. Click the images to open them full-size in a new tab/window.





Then, edit the artist details view, so that it displays the rich text. (If you’re interested in how the rich text ended up in a box, it used the Bootstrap panel class set (panel panel-default panel-body).) Click the image to open it full-size in a new tab/window.



Prepare for non-text media types

In this app, two scenarios will be implemented for non-text media type handling.

In the simple scenario, the existing Track entity will be modified to handle an audio media item.

In the more complex scenario, a new ArtistMedia entity will be created. This new entity will be dedicated to the description and storage of media items. The existing Artist entity will be modified to have a collection of ArtistMedia objects.


Media type – add audio to the Track entity

As noted above, this is the simple scenario. The existing Track entity will be modified to handle an audio media item.

Do that now. Follow the guidance in the March 22 class notes, and in the PhotoProperty code example.

When you build/compile, and the load/run in a browser, the “model… changed” error appears. Again, add a migration, and update the database.


Prepare the track details view to play audio

The details view for the “get one” use case should include an HTML audio player for the track’s sample clip.

<audio src="/clip/@Model.Id" controls="controls"></audio>


As you can see, the value of the src attribute is a path like this:

  • /clip/123

That means that we need an action/method – somewhere – to fetch the clip. The PhotoProperty code example used a dedicated controller for that. You can do that if you wish.

Alternatively (and perhaps preferred), you can simply add a method to the Tracks controller that will work with the manager object to fetch and deliver the clip. Your choice. Whatever you do, make sure you use attribute routing, for a clean URL.

Your track details view may look like the following. Notice the disabled state of the audio player, because it could not find the audio clip data. (We’ll fix that soon.) Click the image to open it full-size in a new tab/window.



Update the “add new” track use case

To the existing “add new” track, add the ability to upload a sample clip of the track. Again, follow the guidance in the March 22 class notes, and in the PhotoProperty code example.

Remember to change the BeginForm() constructor to specify the correct “enctype”.

Your track create view may look like the following. Click the image to open it full-size in a new tab/window.



After completing the form, it look like the following. Click the image to open it full-size in a new tab/window.



Finally, after a successful save, it look like the following. Notice the enabled state of the audio player, with controls that can be used. Click the image to open it full-size in a new tab/window.



You will need track clips. Where can you get some? In the Week 10 folder of the GitHub code repository. Each are about 15 seconds in length.

Please do not use full-length tracks as clips. They’re too big. Multi-megabyte. Big problem when submitting your work on Blackboard.

Instead, limit your clip length to ten to fifteen seconds.


Do you want to create your own clips?

There are many ways to do this, assuming that you have a license (i.e. a legal right) to play the track. Here is one way.

Use the Audacity software. File > Open an existing audio file that’s on your computer.

Click a location about 15 seconds into the track.

Press Shift+End (or Edit > Select > Cursor to track end). Press Delete.

If you want a nice fade-out, click a location about 2 seconds from the end of the track. Shift+End again. Then Effects > Fade Out. (This works too for Fade In at the beginning of the track.)

Then File > Export Audio


Media type – add a media collection to the Artist entity

As noted above, this is the more complex  scenario. A new ArtistMedia entity will be created, and the existing Artist entity will be modified to handle a collection of ArtistMedia objects.

In this scenario, the design and coding approach will be similar to the one in the recent PhotoEntity code example.

The one difference is that we will permit any kind of media item to be associated with an artist object. In other words, a photo, some audio, or video, or even a digital document like a PDF or Word-or-Excel document.


What’s different here

During rendering, in the view code, we’ll make decisions about how to render a media item:

If image, then render an HTML <img> element.

If audio, then render an HTML <audio> element.

If video, then render an HTML <video> element.

If PDF, or Word, or Excel (etc.), then render an HTML <a> element, which uses the download-and-save workflow.


Implementing Artist object – MediaItem collection

Add a MediaItem design model class, probably with the same properties and constructor design that are in the PhotoEntity code example’s dedicated media item class.

It will be associated with Artist, which will have a one-to-many association with MediaItem.



Remember to add the DbSet<TEntity> property in the data context class.

Build/compile, and run in a browser. It will show an error, because the “model backing the ‘ApplicationDbContext’ context has changed since the database was created.” Add another migration, and update the database, before continuing.


View model classes – MediaItem

The following view model classes will be needed for MediaItem.

A “…Base” class, with identifying and descriptive properties, is needed.

Hint and tip:

Include the ContentType property. It will be useful later.

A “…Content” class, for the digital content of the media item, is needed.

Next, we need to write the view model classes that handle the “add media item for a known/existing artist” workflow.

An “…AddForm” class is needed. As you have learned, it MUST have an artist identifier, and it SHOULD have some descriptive information about the artist, to display on the HTML Form.

An “…Add” class is needed. It MUST have the artist identifier, and the properties that capture information and data for the media item.

Remember to add AutoMapper maps to cover the use cases.


Manager class method for “add media item for artist”

The design and coding approach will be similar to any one-to-many scenario where you are adding a new object for a known/existing object. This approach has been implemented many times before:

  • Add a new Product for an existing Supplier
  • Add a new Vehicle for an existing Manufacturer
  • Add a new Album for an existing Artist
  • Add a new Track for an existing Album

Here, we are adding a new MediaItem for an existing Artist.

Therefore, follow this well-known coding pattern. Add in the media-handling code, to extract and save the media item data from the HttpPostedFileBase object.


Artists controller “add new” media item handling

As you have learned, when you’re adding an item to a dependent collection, you start with the dependent object.

In other words, we will work with the Artists controller, and code the “add new” media item there. You have already done that with “add new” album, so do the same for “add new” media item. Yes, the Coordinator role claim will be needed to complete this task.

Create the GET method. Use attribute routing.

Generate the view. Remember to:

  1. Change the BeginForm() constructor to specify the correct “enctype”
  2. Add the hidden ArtistId information

At this point, your view may look something like the following. Click the image to open it full-size in a new tab/window.



Next, create the POST method. Test your work.


Add the dedicated media item delivery controller and Manager method

Next, add the dedicated media item delivery controller.

From the PhotoEntity code example, you should also include the download-and-save functionality.

Add a Manager class method that will deliver a media item object.


Prepare to display the media items

Let’s modify the existing artist details view, and all its bits and pieces.

We will create a new view model class, ArtistWithMediaInfo (in the style similar to the PhotoEntity code example). Remember to add an AutoMapper map.

In the Manager class, create another “get one” method (copy/paste), but it will fetech/include the media items, and return  an object of the new type (above).

In the Artists controller, call that new manager method. You’ll have to change the model type in the view too.

At this point in time, build/compile, and run in a browser. The app should continue to work.


Displaying or rendering media items

There are many ways to display or render media items. Images and sounds can use the built-in HTML elements.

For other content – digital documents for example – the content can be rendered as a hyperlink that references the media item. For best results, use the save-to-download feature for their URLs.

If you want to render a text-based hyperlink, do it. Alternatively, you can include icons in your app, and render those as the hyperlink. Here are some icons that you can save and use:

icon-pdf icon-word icon-excel


In the teacher’s sample solution, we chose to render the media items in groups. For example, we first rendered all the photos. Then the sounds. And then the digital documents. Click the image to open it full-size in a new tab/window.



Each group was rendered with “foreach” code, but using only the desired media type. For example:


  @foreach (var item in Model.MediaItems.Where(m => m.ContentType.Contains("image/")))
      <img src="~/media/@item.StringId" alt="@item.Caption" title="@item.Caption" width="200">


Publish to Azure

(more to come – will be updated)


Testing your work

In a browser, test your work, by doing tasks that fulfill the use cases in the specifications.

Remember to customize the app’s appearance (front/home page, menus, etc.) before you submit your work.

Add some artist, album, and track data. At least:

  • Two (2) artists (with profile info in the rich text field)
  • For an artist, one (1) album
  • For an album, five (5) tracks (with audio samples)

Edit one existing artist to include media items.


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 may be a few megabytes in size (depending on the size of your uploaded media item assets). 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.




























%d bloggers like this: