Building Dynamic Responsive Web Applications with ASP.NET MVC

This collection of text excerpts is from Jamie Munro’s book, “ASP.NET MVC 5 with Bootstrap and Knockout.js: Building Dynamic, Responsive Web Applications,” published by O’Reilly Media in 2015. The book provides a practical guide to building modern web applications using these three technologies. It covers foundational concepts such as MVC architecture, integrating Bootstrap for responsive design, and utilizing Knockout.js for dynamic client-side interactions. Later sections explore working with data, implementing robust code architecture with filters and services, and building a complete shopping cart application as a comprehensive example.

Podcast

Listen or Download Podcast – Building Dynamic Responsive Web Applications with ASP.NET MVC

Building Responsive Web Applications with ASP.NET MVC 5

Based on the sources provided, ASP.NET MVC 5 is a framework that implements the Model-View-Controller (MVC) architecture pattern. In the context of web development, MVC is described as an architecture pattern where the Model manages the application’s data, often representing database tables. The View contains the visual representation, typically using HTML, CSS, and JavaScript. The Controller acts as the middleman, requesting data from the Model and passing it to the View for display, or receiving data from the View and passing it to the Model for saving. The book uses ASP.NET MVC 5 (or the MVC framework) frequently, often just referring to it as MVC.

The book utilizes ASP.NET MVC 5 for several key tasks in building dynamic, responsive web applications:

  • To build sophisticated server-side web applications.
  • To interact with a database.
  • To dynamically render HTML.

ASP.NET MVC 5 has evolved significantly since its initial release in March 2009 and is now considered a technology leader with many useful features readily available.

The book focuses on combining ASP.NET MVC 5 with Bootstrap (a front-end framework) and Knockout.js (a JavaScript library implementing the Model-View-ViewModel pattern). ASP.NET MVC 5 serves as the server-side component, interacting with a database and rendering dynamic HTML. Knockout.js enhances responsive web design by adding snappy client-side interactions driven by the server-side application built with ASP.NET MVC 5.

The book guides the reader through using ASP.NET MVC 5 by starting with creating a new project using the MVC template in Visual Studio. This template preloads useful files and folders, including a default shared layout view and a HomeController with basic actions (Index, About, Contact). Controllers in ASP.NET MVC extend the base Controller class, and actions typically return an ActionResult type. The ViewBag property is introduced as a way to pass data dynamically from the Controller to the View. Views, often .cshtml files, contain a mix of HTML and C# using Razor syntax to render dynamic content. Shared layouts, like _Layout.cshtml, contain reusable HTML elements common across multiple pages, and views are inserted into this layout when the RenderBody function is called.

URL routing in ASP.NET MVC 5 maps URLs to specific controllers and actions. A default route is configured when a project is created, following a {controller}/{action}/{id} pattern with defaults for Home controller and Index action. This can be configured in App_Start/RouteConfig.cs. Starting with MVC 5, attribute routing is also available, allowing routes to be defined directly on controller actions or controllers using the [Route] attribute. This approach can be beneficial for creating more convenient or SEO-friendly URLs. Attribute routing supports prefixes ([RoutePrefix]) and constraints (e.g., :int, :min(0)) to make routing more specific and intelligent.

For data persistence, ASP.NET MVC projects commonly integrate with databases, often using an ORM like Entity Framework (EF). Visual Studio provides built-in support for EF when scaffolding controllers and views. Scaffolding is a feature that allows rapid creation of web pages with basic CRUD (Create-Read-Update-Delete) functionality based on a model and data context.

The book also covers various global filters available in ASP.NET MVC 5, which allow applying consistent behavior across requests. These include:

  • Authentication filters: New in MVC 5, responsible for validating credentials.
  • Authorization filters: Determine if an authenticated user is allowed to access a resource.
  • Action filters: Execute code before or after a controller action.
  • Result filters: Execute code when a result is executing or has finished executing, before being returned.
  • Exception filters: Handle errors that occur during a request. These filters can be registered globally or applied using attributes on specific controllers or actions.

ASP.NET MVC can be integrated with Web API, which is used for building RESTful web applications. Web API controllers extend the base ApiController class. When integrating Web API with MVC, the Web API controller often serves as the entry point for interacting with a resource (Model), and the View is typically a JSON or XML representation of the resource. This allows for dynamic updates to the user interface without full-page reloads, as demonstrated in updating the list of authors example. Web API controllers leverage HTTP Status Codes (like 2xx for success, 4xx for client errors, 5xx for server errors) to provide feedback on API requests.

A key concept discussed in the book is the “fat model, skinny controller” approach, which aims to place business logic in the Model (or supporting layers like services and behaviors) rather than the Controller. This promotes reusability and maintainability. Layers like Services (middleman for data fetching/saving), Behaviors (logic execution), Repositories (common queries), Orchestrations (coordinating services), and Unit of Work (managing database transactions) can be used to achieve separation of concerns within the “fat model”. The example refactors the AuthorsController to use a separate AuthorService and QueryOptionsCalculator behavior to demonstrate this principle.

The final part of the book demonstrates these concepts by building a shopping cart application, showcasing how ASP.NET MVC 5 works together with Bootstrap and Knockout.js to create dynamic and responsive web pages. This includes building data models, implementing layouts using partial views and HtmlHelper methods, displaying lists of books, and adding, updating, and deleting cart items with dynamic UI updates using Knockout.js and Web API [Chapters 14-18].

Building Web Apps with Bootstrap and ASP.NET MVC

Based on the sources provided, Bootstrap is an HTML, CSS, and JavaScript framework used to create consistent-looking, responsive websites. Its primary purpose is to help developers build sleek and responsive views that render well on a variety of modern devices. By combining Bootstrap with server-side ASP.NET MVC and client-side Knockout.js, the framework allows for the rapid development of complex, dynamic, and responsive web applications. The book focuses on using ASP.NET MVC 5 with Bootstrap and Knockout.js to bring dynamic server-side content and responsive web design together.

Bootstrap provides a set of custom components that facilitate building an incredible user experience using easy-to-implement HTML, CSS, and JavaScript. Many common Bootstrap components are automatically installed with MVC 5 applications and are immediately seen in action within the default project layout.

Specific components and features discussed include:

  • Responsive Layout: Bootstrap provides a responsive web layout that automatically adjusts pages based on screen resolution.
  • Menus: Bootstrap defines menu structures using div with the navbar class, ul with the nav class, and li tags for elements. It includes features like inverse coloring (navbar-inverse), fixing the menu to the top (navbar-fixed-top), responsive collapsing for small devices (navbar-collapse, collapse, navbar-toggle), drop-downs (dropdown, dropdown-toggle, dropdown-menu, divider), and integrating elements like search boxes (navbar-form, navbar-right). Different styles like “pill” menus (nav-pills) are also available.
  • Buttons: Bootstrap includes six different themed buttons: Default, Primary, Success, Info, Warning, and Danger, which are created using the btn class along with a theme-specific class like btn-success. These classes can be applied to button tags, links, or submit buttons. Buttons can also be grouped (btn-group) and include drop-downs.
  • Alerts: The framework provides styled alert messages (Success, Info, Warning, Danger) using the alert class and a theme-specific class. Alerts can optionally be made dismissible using the alert-dismissible class and a close button with data-dismiss=”alert”.
  • Forms: Bootstrap provides classes for styling form elements and integrates with MVC client-side validation using jQuery.
  • Tables: Classes like table-bordered, table-striped, and table-hover can be used to style tables for better readability.
  • Pagination: A pagination component is used to create navigation links like “Next” and “Previous”, including styling to disable links on the first or last page.
  • Modals: Bootstrap modals can be used to display content, such as delete confirmations, in a dialog window over the current page. They are structured with classes like modal, modal-dialog, modal-content, modal-header, modal-body, and modal-footer.
  • Glyphicons: Bootstrap provides a set of icons (glyphicons) that can be easily included using span tags with appropriate classes, such as glyphicon glyphicon-sort or glyphicon glyphicon-trash.
  • Jumbotron: This feature is used to create a prominent display area or call-to-action, often seen near the top of a page.

A significant advantage of using Bootstrap is that the developers have already written, organized, and tested much of the repetitive CSS code across a variety of web browsers. This saves developers time and provides confidence that the website will work consistently, allowing them to focus on building more sophisticated application features. The implementation effort for features like alert messages is also greatly alleviated.

Bootstrap is automatically installed with MVC 5 project templates and can be managed or updated using the NuGet Package Manager in Visual Studio. Its core CSS is typically located in Content/bootstrap.css. The book notes that some features demonstrated align with Bootstrap version 3.3 documentation.

While the book explores many components, it mentions that its examples “barely scratch the surface” of the numerous components Bootstrap offers. More complex components requiring JavaScript interaction are often covered in conjunction with Knockout.js integration. Bootstrap theming customization is noted as being outside the book’s scope.

Understanding Knockout.js for Dynamic Web UIs

Based on the provided sources, Knockout.js is an open source JavaScript library that allows developers to create dynamic and rich web applications. It is built with the Model-View-ViewModel (MVVM) pattern, and its primary purpose is to provide data binding between your ViewModel and your user interface (the View).

The sources emphasize several key aspects and benefits of using Knockout.js:

  • Purpose and Benefits:
  • Knockout.js helps implement a complex user interface that responds to user interactions.
  • It enhances responsive web design with snappy client-side interactions driven by the server-side ASP.NET MVC application.
  • It provides sophisticated logic to automatically update the user interface based on user interaction.
  • It is described as lightweight and doesn’t try to be an all-in-one framework; it serves the single purpose of data binding.
  • Accomplishing tasks with Knockout.js takes very little time compared to writing plain JavaScript.
  • Its features are thoroughly tested in a variety of browsers, offering confidence that the web application will work consistently.
  • Integrating Knockout.js with Web API for dynamic UI updates without full-page reloads results in a much smoother user interface.
  • MVVM Implementation:
  • Implementing Knockout involves three distinct things: a view (HTML/CSS/JavaScript), a ViewModel (JavaScript code containing data), and telling Knockout to perform the data binding (ko.applyBindings).
  • The ViewModel should be organized to make it easy to represent how your View uses the data, distinct from how data might be stored in a database Model.
  • Core Concepts:
  • Data Binding: Achieved using easy-to-implement HTML attributes like data-bind. Various bindings are discussed and demonstrated, including:
  • text: Updates the text content of an element.
  • value: Binds the value of form input elements.
  • submit: Binds the submit event of a form to a function in the ViewModel.
  • visible: Controls the visibility of an element.
  • foreach: Repeats a block of HTML for each element in an array.
  • attr: Sets any HTML attribute dynamically.
  • css: Dynamically adds or removes CSS classes.
  • textInput: Similar to value but tracks every character change.
  • Observables: Special JavaScript variables that Knockout tracks for changes. When an observable changes, any UI element bound to it is automatically updated, and vice versa. Observables are accessed as functions to get or set their value (variable()), although Knockout is intelligent enough to handle this automatically in some contexts (like checking truthiness). Being mindful of how many observables are created is mentioned as important.
  • Observable Arrays: Observable variables specifically for arrays, tracking when items are added, removed, or replaced. UI elements bound to an observable array (like with foreach) update automatically when the array changes.
  • Computed Observables / Pure Computed: Functions whose values are automatically calculated based on the values of other observables they depend on. They update data bindings whenever their dependencies change. pureComputed is noted for avoiding unnecessary re-evaluations. Examples include calculating totals or determining CSS classes based on state.
  • Custom Features:
  • Custom Extenders: Add reusable custom behavior to observable properties. They can perform calculations or other logic when the observable’s value changes. The subTotal extender is demonstrated.
  • Custom Bindings: Encapsulate reusable UI logic and interaction with the ViewModel that goes beyond the built-in bindings. They are registered using ko.bindingHandlers. The isDirty binding (showing a button when a value changes) and appendToHref binding (dynamically appending a value to a link’s href) are demonstrated.
  • Custom Components: Encapsulate both a piece of HTML (template) and its corresponding ViewModel into a reusable, self-contained unit. They are registered using ko.components.register and can accept parameters. The upsert-cart-item component is demonstrated.
  • Integration with ASP.NET MVC and Web API:
  • Knockout ViewModels often receive data from the server-side ASP.NET MVC application, typically by serializing MVC Models or ViewModels to JSON using Razor and a helper extension, and then instantiating the JavaScript ViewModel with this data.
  • AJAX calls, often to Web API controllers returning JSON, are used to dynamically update the data in the Knockout ViewModel, which in turn updates the UI without full page reloads. HTTP Status Codes from Web API provide feedback on these requests.
  • Usage and Best Practices:
  • Knockout.js is installed using the NuGet Package Manager in Visual Studio and its script is included in the HTML layout, often via bundling and minification.
  • Using var self = this; in JavaScript ViewModels is presented as a way to easily reference other methods or properties within the ‘class’.
  • Applying Knockout bindings to a limited scope (e.g., a specific HTML element) is possible and can be useful when adding multiple Knockout bindings on the same page.
  • While Knockout is capable of powering dynamic interfaces, it’s suggested to use it sparingly where dynamic interaction is required, rather than on every page, as standard MVC views with Razor are sufficient otherwise.
  • The concept of single-page web applications, often built with libraries like Knockout, is mentioned, along with the idea that they make sense in certain situations (single focus) but not others (when page context changes).

In summary, Knockout.js is presented as a valuable JavaScript library that simplifies building dynamic and responsive user interfaces by implementing the MVVM pattern through data binding, observables, and reusable components, particularly when integrated with ASP.NET MVC and Web API for server-side data handling.

ASP.NET Web API: Building RESTful Applications

Drawing on the provided sources and our conversation history, Web API is a technology within the ASP.NET framework used to build RESTful web applications. In this context, REST is described as a software architecture pattern commonly used for creating APIs or client-server applications.

Here’s a discussion of Web API based on the sources:

  • Purpose and Integration with MVC and Knockout.js: Web API is easily integrated into the MVC architecture pattern, allowing for reuse between your MVC and Web API projects. The book demonstrates combining ASP.NET MVC, Bootstrap, and Knockout.js to build dynamic and responsive web applications. Specifically, integrating Knockout.js with Web API allows for dynamic UI updates without full-page reloads. This results in a much smoother user interface because Web API returns only JSON data (or XML) which Knockout then uses to dynamically update UI elements by data binding to observable properties.
  • Views in Web API: Unlike traditional MVC views that render HTML, the View in Web API is often a JSON or XML representation of the resource being interacted with. Knockout works particularly well with JSON data.
  • ViewModels as a Prerequisite: ViewModels are a prerequisite for Web API controllers because models are often the view. Data models that contain a circular relationship (like an author having many books and a book having one author) cannot be used directly in the return from a Web API action.
  • Setup and Controllers:
  • Web API can be included when a new MVC project is created in Visual Studio by selecting the Web API checkbox.
  • If not included initially, it can be installed later via the NuGet Package Manager, for instance, by using the command Install-Package Microsoft.AspNet.WebApi.
  • Installing via NuGet requires manual configuration in the App_Start folder. A WebApiConfig.cs file must be created to register Web API routes, and the Global.asax.cs file needs to be updated to configure these routes on application start.
  • Web API controllers are classes that extend a base ApiController class, similar to how MVC controllers extend the Controller class.
  • Routing and HTTP Verbs:
  • A default route for Web API is configured, typically using a template like api/{controller}/{id}. This means all Web API URLs are often prefixed with api/.
  • Web API controllers utilize common HTTP verbs associated with RESTful applications, such as GET, POST, PUT, and DELETE. When interacting with a RESTful API, the URL often stays consistent, and the request type (verb) changes to indicate the desired operation (e.g., POST for creating, PUT for editing).
  • Attribute routing ([Route]) can also be applied to Web API actions.
  • HTTP Status Codes: RESTful applications built with Web API heavily rely on HTTP Status Codes to provide feedback to the integrator. Common successful requests include 200 OK, 201 Created, and 204 No Content (2xx range). Client error requests (4xx range) include 400 Bad Request (for invalid input data), 401 Unauthorized, 404 Not Found, and 405 Method Not Allowed, often accompanied by helpful error messages in the response body. Server error requests (5xx range) include 500 Internal Server Error, 501 Not Implemented, and 503 Service Unavailable, also potentially with error details.
  • Filters: Web API supports the creation of global filters, similar to MVC.
  • Action filters can be used for tasks like global Web API validation. An Action filter can check if the ModelState.IsValid and, if not, immediately terminate the request and return a 400 Bad Request with details about the validation issues.
  • Exception filters are used for error handling. A global Exception filter can intercept exceptions and build a new HTTP response with a specific HTTP Status Code and tailored content based on the type of exception that occurred (e.g., returning a 404 Not Found for an ObjectNotFoundException or a generic 500 Internal Server Error for unknown exceptions).
  • Usage in Examples: The sources demonstrate using Web API controllers for:
  • Updating the listing of authors, performing sorting and paging via an AJAX request to a Web API controller that returns only an updated list of authors (JSON data). This data is then used by Knockout bindings to dynamically redraw the table.
  • Handling the saving (add/edit) of author data via AJAX requests. These requests use the POST or PUT verbs and send data as JSON. The Web API controller accepts the ViewModel, maps it to the data model, saves it, and returns a result (like 204 No Content for updates or 201 Created with the new item’s ID for additions).
  • Handling the saving (add/update/delete) of shopping cart items via AJAX requests using POST, PUT, or DELETE verbs.

Building Data Models with Entity Framework

Based on the sources, data model building is a fundamental aspect of creating web applications, particularly within the Model-View-Controller (MVC) architecture pattern, where the Model manages the data for the application. In the context of the provided material, data model building is closely tied to using Entity Framework (EF), an ORM (Object-Relational-Mapper), to interact with a database. An ORM like Entity Framework simplifies database access by converting a database table into a model, allowing it to be used like any other class in a project.

The sources outline three different workflows for setting up and using Entity Framework within a project, which influence how you build your data models:

  • Database First: This workflow is used when you have an existing database or want complete control over database creation and maintenance. You create an EDMX file that stores your data schema, data models, and their relationships in XML. Visual Studio provides a designer for this. Creating the database tables manually is required before generating the models from it. This approach is considered very convenient when you want full control over database changes while still using an ORM.
  • Model First: Similar to Database First, models and relationships are maintained in an EDMX file. However, you manually create the models and define relationships using the Visual Studio designer, and then tell EF to create the necessary database tables, columns, and keys based on this design.
  • Code First: With Code First, you manually create your Model classes, and Entity Framework can automatically create the database and tables based on these classes if a database does not exist. You can also use EF tools to create initial Code First classes from an existing database. The power of Code First Migrations is highlighted as extremely convenient for automatically updating your database when your models change. The book’s examples primarily use the Code First approach because it translates better for demonstration purposes.

Regardless of the workflow chosen, interacting with your models (adding, editing, deleting, and fetching data) will be the same.

Specific Data Models in the Shopping Cart Example: For the practical shopping cart example, five data models are defined using the Code First approach:

  • Author Model: Contains information like Id, FirstName, LastName, and Biography. It also includes a virtual ICollection<Book> Books for the relationship where an Author can have many Books. A new feature introduced is the [NotMapped] attribute, used for a FullName property that concatenates FirstName and LastName; EF knows not to persist this property to the database.
  • Book Model: Stores details about a book including Id, AuthorId, CategoryId, Title, Isbn, Synopsis, Description, ImageUrl, ListPrice, SalePrice, and a Featured boolean. It contains foreign key properties (AuthorId, CategoryId) and virtual navigation properties (virtual Author Author, virtual Category Category) representing the relationships where a Book has one Author and one Category.
  • Category Model: Contains an Id and Name. It also includes a virtual ICollection<Book> Books for the relationship where a Category can have many Books.
  • Cart Model: Includes an Id and a SessionId. The SessionId is a unique identifier for the user’s cart. This property is decorated with [Index(IsUnique=true)] to create a unique database index for performance when searching, and [StringLength(255)] because indices are not compatible with the default nvarchar(max) for string fields. It has a virtual ICollection<CartItem> CartItems relationship.
  • CartItem Model: Contains Id, CartId, BookId, and Quantity. It primarily consists of relationships to the Cart and Book models via foreign keys and virtual navigation properties (virtual Cart Cart, virtual Book Book).

Data models typically represent one or more tables within a database. Fields named Id are automatically recognized by Entity Framework as primary keys by convention. Similarly, fields with a related class name and “Id” (like AuthorId) are created as foreign keys. Virtual properties in models, especially navigation properties, are common for enabling features like lazy loading, where related data is only fetched when it is actually accessed, reducing upfront querying.

Usage of Data Models:

  • Controllers: Controllers interact with data models to fetch or save data, often via a Database Context (DbContext) or a Service layer. They might perform data sanitation and validation based on model properties.
  • ViewModels: Data models are distinct from ViewModels. ViewModels are organized based on how the View uses the data, whereas Models represent how data is stored (e.g., in a database). Controllers are responsible for converting data models to ViewModels for the View, and vice versa when processing input. Returning a data model with a circular relationship (like Author having many Books and Book having one Author) directly from a Web API action is not possible, highlighting the need for ViewModels in such cases.
  • Services and Repositories: In a “fat model, skinny controller” architecture, services and repositories handle the business logic and data access, working with data models. The BookContext (the EF DbContext) is often owned by the service layer in this pattern.

In summary, data model building in this context involves defining classes that map to database structures, often using Entity Framework’s conventions and attributes, and understanding their role in the overall application architecture alongside controllers, services, and viewmodels.

Download PDF Book

Read or Download PDF Book – Building Dynamic Responsive Web Applications with ASP.NET MVC

By Amjad Izhar
Contact: amjad.izhar@gmail.com
https://amjadizhar.blog


Discover more from Amjad Izhar Blog

Subscribe to get the latest posts sent to your email.

Comments

Leave a comment