├── README.md ├── src ├── ComicBookGallery │ ├── Views │ │ ├── _ViewStart.cshtml │ │ ├── ComicBooks │ │ │ ├── Index.cshtml │ │ │ └── Detail.cshtml │ │ ├── Shared │ │ │ └── _Layout.cshtml │ │ └── web.config │ ├── Global.asax │ ├── Images │ │ ├── bone-50.jpg │ │ ├── the-amazing-spider-man-657.jpg │ │ └── the-amazing-spider-man-700.jpg │ ├── Fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── Models │ │ ├── Artist.cs │ │ └── ComicBook.cs │ ├── Global.asax.cs │ ├── packages.config │ ├── App_Start │ │ └── RouteConfig.cs │ ├── Content │ │ └── site.css │ ├── Controllers │ │ └── ComicBooksController.cs │ ├── Web.Debug.config │ ├── Web.Release.config │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Web.config │ ├── Data │ │ └── ComicBookRepository.cs │ ├── ComicBookGallery.csproj │ └── Scripts │ │ ├── bootstrap.min.js │ │ └── modernizr-2.6.2.js └── ComicBookGallery.sln ├── walkthroughs ├── README.md ├── add-a-tweet-button-to-the-detail-view │ ├── README.md │ ├── 01-adding-a-tweet-button.md │ └── 02-using-app-configuration.md └── add-series-list-and-detail-views │ ├── README.md │ ├── 06-removing-duplicated-view-code.md │ ├── 04-adding-the-series-list-page.md │ ├── 01-adding-a-series-model.md │ ├── 03-adding-the-series-repository.md │ ├── 05-adding-the-series-detail-page.md │ └── 02-centralizing-our-data.md └── .gitignore /README.md: -------------------------------------------------------------------------------- 1 | 2 | # ASP.NET MVC Basics 3 | 4 | ## Comic Book Gallery 5 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /src/ComicBookGallery/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="ComicBookGallery.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Images/bone-50.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treehouse-projects/aspnet-comic-book-gallery/HEAD/src/ComicBookGallery/Images/bone-50.jpg -------------------------------------------------------------------------------- /src/ComicBookGallery/Fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treehouse-projects/aspnet-comic-book-gallery/HEAD/src/ComicBookGallery/Fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /src/ComicBookGallery/Fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treehouse-projects/aspnet-comic-book-gallery/HEAD/src/ComicBookGallery/Fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /src/ComicBookGallery/Images/the-amazing-spider-man-657.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treehouse-projects/aspnet-comic-book-gallery/HEAD/src/ComicBookGallery/Images/the-amazing-spider-man-657.jpg -------------------------------------------------------------------------------- /src/ComicBookGallery/Images/the-amazing-spider-man-700.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treehouse-projects/aspnet-comic-book-gallery/HEAD/src/ComicBookGallery/Images/the-amazing-spider-man-700.jpg -------------------------------------------------------------------------------- /src/ComicBookGallery/Fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treehouse-projects/aspnet-comic-book-gallery/HEAD/src/ComicBookGallery/Fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /src/ComicBookGallery/Models/Artist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace ComicBookGallery.Models 7 | { 8 | public class Artist 9 | { 10 | public string Name { get; set; } 11 | public string Role { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/ComicBookGallery/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace ComicBookGallery 9 | { 10 | public class MvcApplication : System.Web.HttpApplication 11 | { 12 | protected void Application_Start() 13 | { 14 | AreaRegistration.RegisterAllAreas(); 15 | RouteConfig.RegisterRoutes(RouteTable.Routes); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /walkthroughs/README.md: -------------------------------------------------------------------------------- 1 | 2 | # ASP.NET MVC Basics Walkthroughs 3 | 4 | Now that you've completed the ASP.NET MVC Basics course, here's an opportunity to practice your new skills! 5 | 6 | These walkthroughs are designed to re-enforce the material covered in the course. We'll also cover some additional new information about ASP.NET MVC, but reading these walkthroughs is not required, as well also cover that new information in future Treehouse courses. 7 | 8 | * [Add Series List and Detail Views](add-series-list-and-detail-views/) 9 | * [Add a Tweet Button to the Detail View](add-a-tweet-button-to-the-detail-view/) 10 | -------------------------------------------------------------------------------- /walkthroughs/add-a-tweet-button-to-the-detail-view/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Add a Tweet Button to the Detail View 3 | 4 | ## Introduction 5 | 6 | In this step-by-step walkthrough, we'll update the Comic Book Gallery website's Comic Book Detail view with a "Tweet" button. 7 | 8 | To implement this feature, we'll use Twitter's website to generate the code for our "Tweet" button and learn how to use ASP.NET app configuration to parameterize key application values. 9 | 10 | * [Adding a Tweet Button](01-adding-a-tweet-button.md) 11 | * [Using App Configuration](02-using-app-configuration.md) 12 | 13 | [Return to Walkthroughs](../) 14 | -------------------------------------------------------------------------------- /src/ComicBookGallery/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/ComicBookGallery/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace ComicBookGallery 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "ComicBooks", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Views/ComicBooks/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model ComicBookGallery.Models.ComicBook[] 2 | 3 | @{ 4 | ViewBag.Title = "Comic Books"; 5 | } 6 | 7 |

@ViewBag.Title

8 | 9 |
10 | @foreach (var comicBook in Model) 11 | { 12 |
13 |

@Html.ActionLink(comicBook.DisplayText, "Detail", 14 | new { id = comicBook.Id })

15 | 16 | @comicBook.DisplayText 19 | 20 |
21 | } 22 |
23 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Content/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Set padding to keep content from hitting the edges */ 7 | .body-content { 8 | padding-left: 15px; 9 | padding-right: 15px; 10 | } 11 | 12 | /* Set width on the form input elements since they're 100% wide by default */ 13 | input, 14 | select, 15 | textarea { 16 | max-width: 280px; 17 | } 18 | 19 | /* Backbar Styles */ 20 | .backbar{ 21 | width: 100%; 22 | background-color: #555; 23 | margin-top: -10px; 24 | height: 45px; 25 | } 26 | .backbar .btn{ 27 | margin-top: 4px; 28 | } 29 | 30 | /* Series List Styles */ 31 | .series-list{ 32 | padding: 0; 33 | } 34 | 35 | .series-list li{ 36 | list-style: none; 37 | border-bottom: 1px #ddd solid; 38 | margin-bottom: 20px; 39 | padding-bottom: 10px; 40 | } 41 | 42 | .series-list li:last-child{ 43 | border: none; 44 | } 45 | -------------------------------------------------------------------------------- /walkthroughs/add-series-list-and-detail-views/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Add Series List and Detail Views 3 | 4 | ## Introduction 5 | 6 | In this step-by-step walkthrough, we'll update the Comic Book Gallery website with a feature that will allow users to view the list of available series for our comic books. 7 | 8 | To implement this feature, we'll need to extend our data model, add a new repository, controller, and a couple of new views. Along the way, there'll be lots of opportunity to practice what we've learned in the [ASP.NET MVC Basics](https://teamtreehouse.com/library/aspnet-mvc-basics) course. 9 | 10 | * [Adding a Series Model](01-adding-a-series-model.md) 11 | * [Centralizing Our Data](02-centralizing-our-data.md) 12 | * [Adding the Series Repository](03-adding-the-series-repository.md) 13 | * [Adding the Series List Page](04-adding-the-series-list-page.md) 14 | * [Adding the Series Detail Page](05-adding-the-series-detail-page.md) 15 | * [Removing Duplicated View Code](06-removing-duplicated-view-code.md) 16 | 17 | [Return to Walkthroughs](../) 18 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Models/ComicBook.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace ComicBookGallery.Models 7 | { 8 | public class ComicBook 9 | { 10 | public int Id { get; set; } 11 | public string SeriesTitle { get; set; } 12 | public int IssueNumber { get; set; } 13 | public string DescriptionHtml { get; set; } 14 | public Artist[] Artists { get; set; } 15 | public bool Favorite { get; set; } 16 | 17 | public string DisplayText 18 | { 19 | get 20 | { 21 | return SeriesTitle + " #" + IssueNumber; 22 | } 23 | } 24 | 25 | // series-title-issuenumber.jpg 26 | public string CoverImageFileName 27 | { 28 | get 29 | { 30 | return SeriesTitle.Replace(" ", "-") 31 | .ToLower() + "-" + IssueNumber + ".jpg"; 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/ComicBookGallery.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComicBookGallery", "ComicBookGallery\ComicBookGallery.csproj", "{30247B21-59EC-41FC-9117-99A46F934730}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {30247B21-59EC-41FC-9117-99A46F934730}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {30247B21-59EC-41FC-9117-99A46F934730}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {30247B21-59EC-41FC-9117-99A46F934730}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {30247B21-59EC-41FC-9117-99A46F934730}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Controllers/ComicBooksController.cs: -------------------------------------------------------------------------------- 1 | using ComicBookGallery.Data; 2 | using ComicBookGallery.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Web; 7 | using System.Web.Mvc; 8 | 9 | namespace ComicBookGallery.Controllers 10 | { 11 | public class ComicBooksController : Controller 12 | { 13 | private ComicBookRepository _comicBookRepository = null; 14 | 15 | public ComicBooksController() 16 | { 17 | _comicBookRepository = new ComicBookRepository(); 18 | } 19 | 20 | public ActionResult Index() 21 | { 22 | var comicBooks = _comicBookRepository.GetComicBooks(); 23 | 24 | return View(comicBooks); 25 | } 26 | 27 | public ActionResult Detail(int? id) 28 | { 29 | if (id == null) 30 | { 31 | return HttpNotFound(); 32 | } 33 | 34 | var comicBook = _comicBookRepository.GetComicBook((int)id); 35 | 36 | return View(comicBook); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/ComicBookGallery/Views/ComicBooks/Detail.cshtml: -------------------------------------------------------------------------------- 1 | @model ComicBookGallery.Models.ComicBook 2 | 3 | @{ 4 | ViewBag.Title = Model.DisplayText; 5 | ViewBag.ShowBackBar = true; 6 | } 7 | 8 |

@Model.DisplayText

9 | 10 |
11 |
12 |
13 |
@Model.SeriesTitle
14 |
@Model.IssueNumber
15 |
@(Model.Favorite ? "Yes" : "No")
16 | @if (Model.Artists.Length > 0) 17 | { 18 |
Artists:
19 |
20 |
    21 | @foreach (var artist in Model.Artists) 22 | { 23 |
  • @artist.Role: @artist.Name
  • 24 | } 25 |
26 |
27 | } 28 |
29 |
Description:
30 |
@Html.Raw(Model.DescriptionHtml)
31 |
32 |
33 | @Model.DisplayText 35 |
36 |
37 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ComicBookGallery")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ComicBookGallery")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("30247b21-59ec-41fc-9117-99a46f934730")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewBag.Title - Comic Book Gallery 7 | 8 | 9 | 10 | 11 | 12 | 29 | 30 | @if (ViewBag.ShowBackBar != null && ViewBag.ShowBackBar) 31 | { 32 |
33 |
34 | @Html.ActionLink("Return to List", "Index", 35 | null, new { @class = "btn btn-default" }) 36 |
37 |
38 | } 39 | 40 |
41 | @RenderBody() 42 |
43 | 46 |
47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Views/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/ComicBookGallery/Data/ComicBookRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using ComicBookGallery.Models; 6 | 7 | namespace ComicBookGallery.Data 8 | { 9 | public class ComicBookRepository 10 | { 11 | private static ComicBook[] _comicBooks = new ComicBook[] 12 | { 13 | new ComicBook() 14 | { 15 | Id = 1, 16 | SeriesTitle = "The Amazing Spider-Man", 17 | IssueNumber = 700, 18 | DescriptionHtml = "

Final issue! Witness the final hours of Doctor Octopus' life and his one, last, great act of revenge! Even if Spider-Man survives...will Peter Parker?

", 19 | Artists = new Artist[] 20 | { 21 | new Artist() { Name = "Dan Slott", Role = "Script" }, 22 | new Artist() { Name = "Humberto Ramos", Role = "Pencils" }, 23 | new Artist() { Name = "Victor Olazaba", Role = "Inks" }, 24 | new Artist() { Name = "Edgar Delgado", Role = "Colors" }, 25 | new Artist() { Name = "Chris Eliopoulos", Role = "Letters" }, 26 | } 27 | }, 28 | new ComicBook() 29 | { 30 | Id = 2, 31 | SeriesTitle = "The Amazing Spider-Man", 32 | IssueNumber = 657, 33 | DescriptionHtml = "

FF: THREE TIE-IN. Spider-Man visits the FF for a very private wake--just for family.

", 34 | Artists = new Artist[] 35 | { 36 | new Artist() { Name = "Dan Slott", Role = "Script" }, 37 | new Artist() { Name = "Marcos Martin", Role = "Pencils" }, 38 | new Artist() { Name = "Marcos Martin", Role = "Inks" }, 39 | new Artist() { Name = "Muntsa Vicente", Role = "Colors" }, 40 | new Artist() { Name = "Joe Caramagna", Role = "Letters" } 41 | }, 42 | Favorite = false 43 | }, 44 | new ComicBook() 45 | { 46 | Id = 3, 47 | SeriesTitle = "Bone", 48 | IssueNumber = 50, 49 | DescriptionHtml = "

The Dungeon & The Parapet, Part 1. Thorn is discovered by Lord Tarsil and the corrupted Stickeaters and thrown into a dungeon with Fone Bone. As she sleeps, a message comes to her about the mysterious \"Crown of Horns\".

", 50 | Artists = new Artist[] 51 | { 52 | new Artist() { Name = "Jeff Smith", Role = "Script" }, 53 | new Artist() { Name = "Jeff Smith", Role = "Pencils" }, 54 | new Artist() { Name = "Jeff Smith", Role = "Inks" }, 55 | new Artist() { Name = "Jeff Smith", Role = "Letters" } 56 | }, 57 | Favorite = false 58 | } 59 | }; 60 | 61 | public ComicBook[] GetComicBooks() 62 | { 63 | return _comicBooks; 64 | } 65 | 66 | public ComicBook GetComicBook(int id) 67 | { 68 | ComicBook comicBookToReturn = null; 69 | 70 | foreach (var comicBook in _comicBooks) 71 | { 72 | if (comicBook.Id == id) 73 | { 74 | comicBookToReturn = comicBook; 75 | 76 | break; 77 | } 78 | } 79 | 80 | return comicBookToReturn; 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /walkthroughs/add-a-tweet-button-to-the-detail-view/01-adding-a-tweet-button.md: -------------------------------------------------------------------------------- 1 | 2 | # Add a Tweet Button to the Detail View 3 | 4 | ## Adding a "Tweet" Button 5 | 6 | In this step, we'll visit Twitter's website to get the HTML and JavaScript to add a "Tweet" button to our Comic Book Detail page. 7 | 8 | To start, browse to [https://about.twitter.com/resources/buttons#tweet](https://about.twitter.com/resources/buttons#tweet). 9 | 10 | In the "Choose a button" section, select the "Share a link" option. Under the "Button options" section, use the following values. 11 | 12 | * For "Share URL" select "Use the page URL" option 13 | * For "Tweet text" select "Use the title of the page" option 14 | * For the "Via" value use your Twitter account name (for this walkthrough I'll be using my Twitter account name `SmashDev`) 15 | * Leave "Recommend" blank 16 | * For the "Hashtag" value use "comicbooks" 17 | * Check the "Large button" check box 18 | 19 | Then in the "Preview and code" section, select and copy the code in the field just below the preview "Tweet" button. At the time of this writing, the generated code looks like this. 20 | 21 | ``` 22 | 25 | 26 | ``` 27 | 28 | Now that we've got our "Tweet" button code, let's add it to our Comic Book Detail view! Open the "Views/ComicBooks/Detail.cshtml" view. 29 | 30 | Let's add the "Tweet" button in the "well" section of the view. Notice that I'm also adding a `

` element, containing a non-breaking space HTML entity, just above the "Tweet" button in order to create some whitespace between the button and the content just above it. 31 | 32 | ``` 33 |

34 |
@(Model.Series != null ? Model.Series.Title : "N/A")
35 |
@Model.IssueNumber
36 |
@(Model.Favorite ? "Yes" : "No")
37 | @if (Model.Artists.Length > 0) 38 | { 39 |
Artists:
40 |
41 |
    42 | @foreach (var artist in Model.Artists) 43 | { 44 |
  • @artist.Role: @artist.Name
  • 45 | } 46 |
47 |
48 | } 49 |

 

50 |

53 | 54 |
55 | ``` 56 | 57 | Ready to test our "Tweet" button? 58 | 59 | Press `F5` to run the website. If you started the website from the Comic Book Detail view, you'll initially get a `404` error. Go ahead and browse to the URL `http://localhost:50153/`. 60 | 61 | Here's our Comic Books List page. Click on a comic book to browse to the Comic Book Detail page. And here's our Comic Book Detail page with our "Tweet" button! Click on the "Tweet" button. You should see the "Share a link on Twitter" dialog prompting you to login (if you're not already) and share the following text. 62 | 63 | ``` 64 | The Amazing Spider-Man #700 - Comic Book Gallery http://localhost:50153/ComicBooks/Detail/1 #comicbooks via @SmashDev 65 | ``` 66 | 67 | We can see our page title, hashtag, and Twitter account name. 68 | 69 | _Important note: if you're running your Comic Book Gallery website locally on your PC (like I'm doing here), the URL in the Tweet text will only work on your PC and only when you're currently running the website using Visual Studio. You'd need to publish your website to a hosting provide in order to have URLs that would work for any user._ 70 | 71 | Close your browser and stop the website. 72 | 73 | If you're using GitHub, let's commit our changes. Enter a commit message of "Added Tweet button to the Comic Book Detail view" and click the "Commit All" button. 74 | 75 | In the [next step](02-using-app-configuration.md), we'll see how we can use ASP.NET app configuration to remove the hard-coded Twitter account name from our Comic Book Detail view. 76 | 77 | [Return to Introduction](README.md) 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | # NuGet v3's project.json files produces more ignoreable files 154 | *.nuget.props 155 | *.nuget.targets 156 | 157 | # Microsoft Azure Build Output 158 | csx/ 159 | *.build.csdef 160 | 161 | # Microsoft Azure Emulator 162 | ecf/ 163 | rcf/ 164 | 165 | # Microsoft Azure ApplicationInsights config file 166 | ApplicationInsights.config 167 | 168 | # Windows Store app package directory 169 | AppPackages/ 170 | BundleArtifacts/ 171 | 172 | # Visual Studio cache files 173 | # files ending in .cache can be ignored 174 | *.[Cc]ache 175 | # but keep track of directories ending in .cache 176 | !*.[Cc]ache/ 177 | 178 | # Others 179 | ClientBin/ 180 | ~$* 181 | *~ 182 | *.dbmdl 183 | *.dbproj.schemaview 184 | *.pfx 185 | *.publishsettings 186 | node_modules/ 187 | orleans.codegen.cs 188 | 189 | # RIA/Silverlight projects 190 | Generated_Code/ 191 | 192 | # Backup & report files from converting an old project file 193 | # to a newer Visual Studio version. Backup files are not needed, 194 | # because we have git ;-) 195 | _UpgradeReport_Files/ 196 | Backup*/ 197 | UpgradeLog*.XML 198 | UpgradeLog*.htm 199 | 200 | # SQL Server files 201 | *.mdf 202 | *.ldf 203 | 204 | # Business Intelligence projects 205 | *.rdl.data 206 | *.bim.layout 207 | *.bim_*.settings 208 | 209 | # Microsoft Fakes 210 | FakesAssemblies/ 211 | 212 | # GhostDoc plugin setting file 213 | *.GhostDoc.xml 214 | 215 | # Node.js Tools for Visual Studio 216 | .ntvs_analysis.dat 217 | 218 | # Visual Studio 6 build log 219 | *.plg 220 | 221 | # Visual Studio 6 workspace options file 222 | *.opt 223 | 224 | # Visual Studio LightSwitch build output 225 | **/*.HTMLClient/GeneratedArtifacts 226 | **/*.DesktopClient/GeneratedArtifacts 227 | **/*.DesktopClient/ModelManifest.xml 228 | **/*.Server/GeneratedArtifacts 229 | **/*.Server/ModelManifest.xml 230 | _Pvt_Extensions 231 | 232 | # Paket dependency manager 233 | .paket/paket.exe 234 | 235 | # FAKE - F# Make 236 | .fake/ 237 | -------------------------------------------------------------------------------- /walkthroughs/add-series-list-and-detail-views/06-removing-duplicated-view-code.md: -------------------------------------------------------------------------------- 1 | 2 | # Add Series List and Detail Views 3 | 4 | ## Removing Duplicated View Code 5 | 6 | In the previous step, we copied and pasted the comic books list markup from the "Views/ComicBooks/Index.cshtml" file to our Series Detail view. When we did that, we violated the DRY (Don't Repeat Yourself) design principle. 7 | 8 | ASP.NET MVC provides a feature, known as "partial views", that gives us a convenient way to avoid repeating that markup in two views. Instead, we can create a partial view that contains the comic book list markup, then render that partial view in both the Comic Books List and Series Detail views. 9 | 10 | Let's do that now! 11 | 12 | Right click on the "Views/Shared" folder and select the "Add > View" menu item. Change the "View name" field to "_ComicBooksList", select the "Empty (without model)" template, and check the "Create as a partial view" check box. Click the "Add" button to finishing adding the view. 13 | 14 | This time, Visual Studio won't provide any us with any starting code or markup for our partial view. 15 | 16 | Let's start by adding a `model` view directive to the top of the view in order to make it strongly typed. For the type, provide the fully qualified name for the `ComicBook` data model. Be sure to include a set of brackets `[]` at the end of the model type to indicate that we're expecting an array of that type. 17 | 18 | ``` 19 | @model ComicBookGallery.Models.ComicBook[] 20 | ``` 21 | 22 | Now let's copy and paste the comic book list markup from the "Series/Detail" view into our partial view. 23 | 24 | ``` 25 |
26 | @foreach (var comicBook in Model.Issues) 27 | { 28 |
29 |

30 | @Html.ActionLink(comicBook.DisplayText, "Detail", "ComicBooks", 31 | new { id = comicBook.Id }, null) 32 |

33 | 35 | @comicBook.DisplayText 38 | 39 |
40 | } 41 |
42 | ``` 43 | 44 | Update the `foreach` loop to use `Model` as its source instead of `Model.Issues`. 45 | 46 | ``` 47 | @foreach (var comicBook in Model) 48 | ``` 49 | 50 | That completes our partial view! Next, we can update the Comic Books List and Series Detail views to use our new partial view. 51 | 52 | Open the "Views/ComicBooks/Index.cshtml" file and replace the comic books list markup with a call to the `Partial` HTML helper method. After that change, the view should look like this. 53 | 54 | ``` 55 | @model ComicBookGallery.Models.ComicBook[] 56 | 57 | @{ 58 | ViewBag.Title = "Comic Books"; 59 | } 60 | 61 |

@ViewBag.Title

62 | 63 | @Html.Partial("_ComicBooksList", Model) 64 | ``` 65 | 66 | Then open the "Views/Series/Detail.cshtml" file and replace the comic books list markup with a call to the `Partial` HTML helper method. After that change, the view should look like this. 67 | 68 | ``` 69 | @model ComicBookGallery.Models.Series 70 | 71 | @{ 72 | ViewBag.Title = Model.Title; 73 | ViewBag.ShowBackBar = true; 74 | } 75 | 76 |

@ViewBag.Title

77 | 78 |
79 |
Description
80 |
81 | @Html.Raw(Model.DescriptionHtml) 82 |
83 |
84 | 85 |

Comic Books Available in This Series

86 | 87 | @Html.Partial("_ComicBooksList", Model.Issues) 88 | ``` 89 | 90 | Let's run our website by pressing `F5`. If you started the website from the Series Detail view, you'll initially get a `404` error. Go ahead and browse to the URL `http://localhost:50153/Series`. 91 | 92 | Here's our Series List page. Click on a series title to browse to the Series Detail page. And here's our Series Detail page! Looks good so far. Let's try clicking on one of the series' comic books. Clicking on the first comic book takes us to the Comic Book Detail page for that comic book. 93 | 94 | Click on the "Comic Books" item in the top menu to browse to the Comic Books List page. And here's our Comic Books List page, which also looks good. To finish, click on the first comic book in the list to browse to its Comic Book Detail page. Looks great! 95 | 96 | Close your browser and stop the website. 97 | 98 | If you're using GitHub, let's commit our changes. Enter a commit message of "Added comic books list partial view" and click the "Commit All" button. 99 | 100 | This concludes our walkthrough of adding Series List and Detail views to our website. I hope you had fun and learned something along the way! 101 | 102 | If you find any errors or mistakes with this walkthrough, feel free to fork this repo, fix the error, and issue a pull request back to this repo. Reach out to me on Twitter [@SmashDev](https://twitter.com/SmashDev) and give me your feedback and suggestions on how I can make this walkthrough better. 103 | 104 | See you next time! 105 | 106 | [Return to Introduction](README.md) 107 | -------------------------------------------------------------------------------- /walkthroughs/add-a-tweet-button-to-the-detail-view/02-using-app-configuration.md: -------------------------------------------------------------------------------- 1 | 2 | # Add a Tweet Button to the Detail View 3 | 4 | ## Using App Configuration 5 | 6 | The "Tweet" button on our Comic Book Detail page currently has the Twitter account name hard-coded into the code that we copied and pasted from Twitter's website. In this step, we'll see how we can use ASP.NET app configuration to remove that hard-code value from our view. 7 | 8 | Open the "Web.config" file that's located in the root of the project. "Web.config" is the main settings and configuration file for ASP.NET web applications. Within this file, there is an `appSettings` section that we can use to define global application settings as "key/value" pairs. 9 | 10 | Let's add a new app setting for our Twitter account. For the key, use "TwitterAccount" and for the value, use the Twitter account name that you're using for your "Tweet" button. 11 | 12 | ``` 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ``` 21 | 22 | Now we need to update our website to use this app settings value for our "Tweet" button's Twitter account. We'll start by updating our `ComicBooksController.Detail` action method. Open the "Controllers/ComicBooksController.cs" file. 23 | 24 | In the `Detail` action method, we'll use the `ConfigurationManager` class to retrieve the app setting value. To use the `ConfigurationManager` class, you'll need to add a `using` directive for the `System.Configuration` namespace. 25 | 26 | You can retrieve app setting values using the `ConfigurationManager` class' `AppSettings` property like this. 27 | 28 | ``` 29 | string twitterAccount = ConfigurationManager.AppSettings["TwitterAccount"]; 30 | ``` 31 | 32 | The string literal `TwitterAccount` inside of the brackets is similar to indexing into an array (i.e. `myArray[0]`) except in this case, we're indexing into a collection of app setting values using the app setting key name. 33 | 34 | App setting values are always represented as strings. If an app setting value is actually another data type, such as a number or boolean, you can parse or convert the string values to their "correct" data types (for an example of this, see the `Boolean.TryParse` method [https://msdn.microsoft.com/en-us/library/system.boolean.tryparse(v=vs.110).aspx](https://msdn.microsoft.com/en-us/library/system.boolean.tryparse(v=vs.110).aspx)). In a future course, we'll discuss string parsing in more detail. 35 | 36 | Now that we have our Twitter account app setting value, let's pass it to our view using a `ViewBag` object property. 37 | 38 | ``` 39 | ViewBag.TwitterAccount = twitterAccount; 40 | ``` 41 | 42 | Our updated action method now looks like this. 43 | 44 | ``` 45 | public ActionResult Detail(int? id) 46 | { 47 | if (id == null) 48 | { 49 | return HttpNotFound(); 50 | } 51 | 52 | string twitterAccount = ConfigurationManager.AppSettings["TwitterAccount"]; 53 | ViewBag.TwitterAccount = twitterAccount; 54 | 55 | var comicBook = _comicBookRepository.GetComicBook((int)id); 56 | 57 | return View(comicBook); 58 | } 59 | ``` 60 | 61 | To finish things up, let's update our Comic Book Detail view. Open the "Views/ComicBooks/Detail.cshtml" file. 62 | 63 | In the "Tweet" button code, we need to update the `` element's `data-via` attribute value to use the `ViewBag.TwitterAccount` property value. 64 | 65 | ``` 66 |

69 | ``` 70 | 71 | Let's test our updated "Tweet" button! 72 | 73 | Press `F5` to run the website. If you started the website from the Comic Book Detail view, you'll initially get a `404` error. Go ahead and browse to the URL `http://localhost:50153/`. 74 | 75 | Here's our Comic Books List page. Click on a comic book to browse to the Comic Book Detail page. Click on the "Tweet" button. You should see the "Share a link on Twitter" dialog with the Twitter account name that you specified in the "Web.config" app settings section. 76 | 77 | ``` 78 | The Amazing Spider-Man #700 - Comic Book Gallery http://localhost:50153/ComicBooks/Detail/1 #comicbooks via @SmashDev 79 | ``` 80 | 81 | _Important note: if you're running your Comic Book Gallery website locally on your PC (like I'm doing here), the URL in the Tweet text will only work on your PC and only when you're currently running the website using Visual Studio. You'd need to publish your website to a hosting provide in order to have URLs that would work for any user._ 82 | 83 | Close your browser and stop the website. 84 | 85 | If you're using GitHub, let's commit our changes. Enter a commit message of "Updated Tweet button to use app configuration" and click the "Commit All" button. 86 | 87 | This concludes our walkthrough of adding a "Tweet" button to our website's Comic Book Detail page. I hope you had fun and learned something along the way! 88 | 89 | If you find any errors or mistakes with this walkthrough, feel free to fork this repo, fix the error, and issue a pull request back to this repo. Reach out to me on Twitter [@SmashDev](https://twitter.com/SmashDev) and give me your feedback and suggestions on how I can make this walkthrough better. 90 | 91 | See you next time! 92 | 93 | [Return to Introduction](README.md) 94 | -------------------------------------------------------------------------------- /walkthroughs/add-series-list-and-detail-views/04-adding-the-series-list-page.md: -------------------------------------------------------------------------------- 1 | 2 | # Add Series List and Detail Views 3 | 4 | ## Adding the Series List Page 5 | 6 | Now that we've updated our models, centralized our data, and created our repository, we're ready to add the controller and view for our Series List page. Let's start by adding the `SeriesController` class. 7 | 8 | Instead of adding a class using the "Add > Class" menu item, let's right click on the "Controllers" folder and select the "Add > Controller" menu item. 9 | 10 | Visual Studio will open the "Add Scaffold" dialog and present us with a list of the available controller templates. Select the "MVC 5 Controller - Empty" template and click the "Add" button. Next, we'll be prompted by the "Add Controller" dialog for the name of the controller. Replace the "Default" text with "Series" and press `ENTER`. Remember, MVC controllers need to end with the suffix "Controller", so it's important to not remove the "Controller" text when naming your controller. 11 | 12 | Here's our controller. 13 | 14 | ``` 15 | public class SeriesController : Controller 16 | { 17 | // GET: Series 18 | public ActionResult Index() 19 | { 20 | return View(); 21 | } 22 | } 23 | ``` 24 | 25 | By using scaffolding to add our controller, Visual Studio has saved us a couple of steps by inheriting from the MVC `Controller` base class and adding the `Index` action method. The `// GET: Series` code comment doesn't add much value, so I'll remove it in order to keep our code clean. 26 | 27 | Next, let's add `_seriesRepository` private field of type `SeriesRepository` and a default constructor that instantiates the repository. Don't forget to add the `using` directive for the `ComicBookGallery.Data` namespace. 28 | 29 | ``` 30 | public class SeriesController : Controller 31 | { 32 | private SeriesRepository _seriesRepository = null; 33 | 34 | public SeriesController() 35 | { 36 | _seriesRepository = new SeriesRepository(); 37 | } 38 | 39 | public ActionResult Index() 40 | { 41 | return View(); 42 | } 43 | } 44 | ``` 45 | 46 | Update the `Index` method to make a call into the `_seriesRepository.GetSeries` method to get the available series. Store the result of the `GetSeries` method call into a `series` variable so we can pass the result into the `View` method call. 47 | 48 | ``` 49 | public ActionResult Index() 50 | { 51 | var series = _seriesRepository.GetSeries(); 52 | 53 | return View(series); 54 | } 55 | ``` 56 | 57 | That's it for our controller—at least for now. Let's turn our attention to the view. Right click on the `Index` method's `View` method call and select the "Add View" menu item. Visual Studio will present us with the "Add View" dialog. 58 | 59 | The "View name" field should default to "Index", which follows the convention of the view name matching the action name. Select the "Empty (without model)" template (if it's not already selected). Make sure that the "Create as a partial view" check box is not checked and the "Use a layout page" check box is checked. Click the "Add" button to finishing adding the view. 60 | 61 | Here's our view. 62 | 63 | ``` 64 | @{ 65 | ViewBag.Title = "Index"; 66 | } 67 | 68 |

Index

69 | ``` 70 | 71 | Let's start by adding a `model` view directive to the top of the view in order to make it strongly typed. For the type, provide the fully qualified name for the `Series` data model. Also, remember that the controller is passing an array of `Series` objects to our view, so be sure to include a set of brackets `[]` at the end of the model type to indicate that we're expecting an array of that type. 72 | 73 | ``` 74 | @model ComicBookGallery.Models.Series[] 75 | ``` 76 | 77 | Next, set the `ViewBag.Title` property to the string literal "Series". Then, update the `

` element content to display the `ViewBag.Title` property value. 78 | 79 | ``` 80 | @model ComicBookGallery.Models.Series[] 81 | 82 | @{ 83 | ViewBag.Title = "Series"; 84 | } 85 | 86 |

@ViewBag.Title

87 | ``` 88 | 89 | Now we're ready to add the markup for our series list. Here's the HTML that our designer provided to us for this view. 90 | 91 | ``` 92 |
93 |
94 | 100 |
101 |
102 | ``` 103 | 104 | That looks simple enough! Looks like we need to add a `foreach` loop inside of the `