top of page
Writer's pictureThe Tech Platform

Understanding ASP.NET Core web UI models

When it comes to developing web applications, ASP.NET Core stands out as a versatile and powerful framework that enables you to create dynamic and interactive user interfaces. At the heart of many web applications lies the concept of web UI models. These models act as the backbone for rendering web pages, handling user input, and ultimately delivering a seamless user experience.


In this article, we will explore ASP.NET Core web UI models, what they are, how they work, and why they are pivotal in modern web development. This journey through web UI models will provide you with valuable insights and practical knowledge.


Table of Contents:

Role of Models in MVC Architecture

Server Rendered UI

Client Rendered UI

Hybrid App


Understanding ASP.NET Core Web UI Models

Web UI Models in ASP.NET Core are part of the MVC (Model-View-Controller) architecture, where the Model represents the application’s data and business logic.


In ASP.NET Core, a model is a set of classes that represent the data that the app manages. The model classes use validation logic to enforce business rules for that data. A model is an object representing data or even activity, such as a database table or even some plant-floor production-machine process.


The main purpose of a model in ASP.NET Core is:

  • To include all the data-related logic that the user works with.

  • This can represent either the data being transferred between the View and Controller components or any other business logic-related data.

  • For example, a Product object might retrieve information from a database, operate on it, and then write updated information back to a Products table in SQL Server.

Web UI models in ASP.NET Core provide a way to handle data and business logic. They serve as a bridge between the view and controller, helping to process and manage application data.


Role of Models in MVC architecture

In the MVC architecture, the model represents the data that is being displayed on the page. The view is the user interface that displays the data from the model. The controller handles user input and updates the model accordingly. The view and controller communicate with each other through the model.


The above diagram shows the following relationships between the model, view, and controller:

  • The view displays data from the model.

  • The controller updates the model based on user input.

  • The controller updates the view based on changes to the model.

The MVC architecture is a popular design pattern for developing web applications. It is also used in other types of software applications, such as desktop applications and mobile applications.


Here is a brief explanation of each component in the MVC architecture:

Understanding ASP.NET Core web UI models

Model

The model represents the data that is being displayed on the page. The model can be a simple object, such as a string or a number, or it can be a complex object, such as a database table.


View

The view is the user interface that displays the data from the model. The view can be a simple HTML page or a complex web application.


Controller

The controller handles user input and updates the model accordingly. The controller also updates the view based on changes to the model. The controller can be a simple class or a complex class that uses various design patterns.


Types of ASP.NET Core Web UI Models

ASP.NET Core provides three general approaches to building modern web UI:

  1. Server Rendered UI

  2. Client Rendered UI

  3. Hybrid App (Both Server and Client Rendered UI )

1. Server Rendered UI:

In a server-rendered UI model, web pages are generated dynamically on the server-side before being sent to the user's browser. This process involves converting HTML files on the server into a fully-rendered web page that can be displayed in a web browser. When you visit a website that uses server-side rendering, your web browser sends a request to the server, asking for the contents of the website.

Understanding ASP.NET Core web UI models

Here's a simplified example using ASP.NET Core MVC, a popular web framework:

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

In this example, we have a controller named HomeController with an action method called Index. When a user navigates to the website's home page, their browser sends a request to the server. The server then invokes the Index action, which typically corresponds to a specific route or URL.


Inside the Index action, the server renders an "Index view" (a template for generating HTML content). This view is like a blueprint for the final web page. Once the view is rendered, the server returns it to the client's browser as a fully-formed HTML page. This HTML can include data from a database, computed values, or any other dynamic content.


Server-rendered UI is beneficial for SEO (Search Engine Optimization) because search engines can easily read and index the HTML content. It's also efficient for initial page loads since users receive a complete web page from the server. However, interactions that require frequent updates or real-time data typically involve additional client-side JavaScript to enhance user experiences.

When to use:

  1. This approach is great for low-end devices and low-bandwidth connections and allows for a broad range of browser versions for the client.

  2. It’s suitable for dynamic sites such as those that provide personalized pages, data, and forms.

Advantages:

  1. Quick initial page load times

  2. Minimal to no JavaScript to pull to the client

  3. Flexibility of access to protected server resources such as database access and access to secrets.

  4. It also has static site analysis advantages, such as search engine optimization.

Disadvantages:

  1. The cost of compute and memory use is concentrated on the server, rather than each client.

  2. User interactions require a round trip to the server to generate UI updates.


2. Client Rendered UI

Imagine you have a web page that you want to update and change without having to refresh the whole page. This is where "Client Rendered UI" comes in.


Client-rendered applications are designed to dynamically generate web UI right in the user's browser. This means that the logic, data fetching, templating, and even routing are all handled by JavaScript code that runs directly in the browser.

Understanding ASP.NET Core web UI models

Here’s a simple example of a client-rendered UI using React:

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(element, document.getElementById('root'));
}

setInterval(tick, 1000);

In this example, the HTML consists of just one <div> tag, while JavaScript takes care of everything else. No need for a server round trip - the rendered HTML is updated right in place. This approach enables real-time updates, whether it's displaying the current time, exchange rates, or stock prices.


Client-rendered UI offers incredibly responsive and interactive experiences. UI event handling and logic run locally on the user's device, minimizing delays. It also supports incremental updates, allowing users to save their progress without submitting forms. Plus, it can work in disconnected modes, syncing data back to the server when a connection is restored.

When to use:

  1. This approach is suitable for applications that require rich interactivity that is nearly instant, without requiring a round trip to the server.

  2. It’s ideal for an interactive dashboard or an app featuring drag-and-drop functionality.

Advantages:

  1. UI event handling and logic run locally on the user’s device with minimal latency.

  2. Supports incremental updates, saving partially completed forms or documents without the user having to select a button to submit a form.

  3. Reduced server load and cost as the work is offloaded to the client.

Disadvantages:

  1. Requires more powerful client devices and good internet connectivity.

  2. Also, it may not be suitable for SEO purposes as search engines may not fully render and index client-side content.


3. Hybrid Apps (Server and Client Rendered UI)

Hybrid apps take advantage of both server and client UI rendering methods to provide a balanced approach to web development. In this model, the majority of the web user interface (UI) is generated on the server, while client-rendered components are added as needed for enhanced interactivity.


One way to create hybrid applications, especially in the ASP.NET Core ecosystem, is by using Blazor. Blazor is a framework that enables the development of interactive client-side web UI using .NET. In a Blazor Hybrid app, Razor components run natively on the user's device. These components render within an embedded Web View control through a local interop channel. Unlike pure client-side rendering with WebAssembly, Blazor Hybrid components do not execute in the browser.


The hybrid approach works with:

  1. Razor Components: Razor components are a fundamental part of Blazor. They load and execute quickly, and they have full access to the native capabilities of the user's device through the .NET platform. This allows for seamless integration with device features.

  2. Styling Considerations: When components render within a Web View, the styling can be platform-dependent. Differences across platforms may require custom stylesheets to ensure consistent and visually appealing rendering.

For example, you can implement Blazor Hybrid within the .NET MAUI (Multi-platform App UI) framework. .NET MAUI includes the BlazorWebView control, which facilitates the rendering of Razor components within an embedded Web View. By combining .NET MAUI and Blazor, you can reuse the same set of web UI components across various platforms, such as mobile, desktop, and web applications. This promotes code reusability and streamlines development efforts.


Here's a simplified example of a Blazor Hybrid app using ASP.NET Core:


STEP 1: Create a Blazor Hybrid App Project You can use the dotnet CLI or Visual Studio to create a Blazor Hybrid app project. Here's an example using the CLI:

dotnet new blazorhybrid -n MyBlazorHybridApp 

STEP 2: Define a Razor Component Create a Razor component that you want to render within the hybrid app. For example, you can create a component called MyComponent.razor:

<!-- MyComponent.razor --> 
<h3>Hello from MyComponent!</h3> 

STEP 3: Add the Razor Component to a Blazor Page In a Blazor page (e.g., Index.razor), include the Razor component you created:

<!-- Index.razor --> 
@page "/" 
<h1>Welcome to My Blazor Hybrid App</h1> 
<MyComponent /> 

STEP 4: Build the App Build the Blazor Hybrid app using the dotnet build command:

dotnet build 

STEP 5: Run the App Launch the app using the dotnet run command:

dotnet run 

Your Blazor Hybrid app should now be running locally.


This is a simplified example to illustrate the concept of combining server-rendered and client-rendered UI in a Blazor Hybrid app.


In a real-world scenario, you would likely have more complex components and interactions, as well as styling considerations for different platforms. Additionally, integrating with .NET MAUI for cross-platform support may require additional setup and configuration.

When to use:

  1. When you want to reuse one set of web UI components across mobile, desktop, and web.

  2. When you want to add new UI to your existing Windows desktop apps that can be reused across platforms with .NET MAUI or on the web.

Advantages:

  • Razor components in a Blazor Hybrid app run natively on the device, load and execute code quickly, and have full access to the native capabilities of the device through the .NET platform.

  • By using .NET MAUI and Blazor together, you can reuse one set of web UI components across mobile, desktop, and web.

  • Hybrid apps can be built with Windows Presentation Foundation (WPF) and Windows Forms.

Disadvantages:

  • Component styles rendered in a Web View are platform-dependent and may require you to account for rendering differences across platforms using custom stylesheets.

  • Managing logical barriers between tenants can add complexity to the codebase, require more data modeling, and ultimately sharing resources can exhaust allocated infrastructure more quickly.

  • Developing a hybrid app can prove up to 30% cheaper compared to native apps. However, this increases the need for extra customization, and the fees for looking after the app on both platforms increase.


Working with ASP.NET Core Web UI Models

Here, we will provide a simplified example to create a pizza inventory management app. Creating a complete pizza inventory management app is a complex task that requires multiple components and functionality. This includes database management, user interfaces, and more.


However, I can provide you with a simplified example of how to create a basic pizza inventory app using ASP.NET Core Razor Pages and Entity Framework Core for data access.


The below example has the following components:

  1. Models: The Pizza class represents the data model for pizzas.

  2. Database Context: The AppDbContext class serves as the database context for interacting with the database. It's configured to use Entity Framework Core for data access.

  3. Razor Pages: The application includes Razor Pages in the Pages/Pizzas folder, which defines the web UI for managing pizzas. These pages include both HTML content and C# code-behind to handle user interactions.

  4. CRUD Operations: The code-behind for the Razor Pages includes logic for performing CRUD (Create, Read, Update, Delete) operations on pizza data. For example, the Index page lists pizzas, and there are other pages for creating, editing, and deleting pizzas.

  5. Dependency Injection: The AppDbContext is registered for dependency injection in the Startup.cs file, allowing it to be easily used by the Razor Pages.


Step 1: Create a New ASP.NET Core Razor Pages Project

If you haven't already, create a new ASP.NET Core Razor Pages project in Visual Studio or Visual Studio Code.


Step 2: Define the Pizza Model

Create a Pizza class in the Models folder to represent pizza data:

// Models/Pizza.cs
public class Pizza
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
}

Step 3: Create a Database Context

Define a database context class that will handle interactions with the database. In this example, we'll use Entity Framework Core and SQLite as the database:

// Data/AppDbContext.cs
using Microsoft.EntityFrameworkCore;

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<Pizza> Pizzas { get; set; }
}

Step 4: Configure Database Connection

In the Startup.cs file, configure the database connection and dependency injection:

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
    
    // ... Other services ...
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ...
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Step 5: Create Razor Pages

Create Razor Pages for managing pizza inventory, such as listing pizzas, adding new pizzas, editing, and deleting:

  • Create a Pages/Pizzas folder.

  • Inside the Pages/Pizzas folder, create Razor Pages like Index.cshtml, Create.cshtml, Edit.cshtml, and Delete.cshtml.


Step 6: Implement CRUD Operations

In the Razor Page code-behind (.cshtml.cs files), implement CRUD (Create, Read, Update, Delete) operations for pizzas. Here's an example for listing pizzas:

// Pages/Pizzas/Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;

public class IndexModel : PageModel
{
    private readonly AppDbContext _context;

    public IndexModel(AppDbContext context)
    {
        _context = context;
    }

    public IList<Pizza> Pizzas { get; set; }

    public async Task<IActionResult> OnGetAsync()
    {
        Pizzas = await _context.Pizzas.ToListAsync();
        return Page();
    }
}

Step 7: Add Migration and Update Database

In the terminal, run the following commands to create and apply database migrations:

dotnet ef migrations add InitialCreate
dotnet ef database update

Step 8: Run the Application

Start the application and navigate to the pizza management pages (e.g., /Pizzas/Index) to manage your pizza inventory.


Advanced Concepts

Advanced development often involves handling complex models, which are data structures comprising multiple properties, including nested objects and collections. Efficiently managing these complex models, along with ensuring their data integrity through model validation, is a fundamental aspect of building robust web applications.


The advanced concepts are:

  1. Working with Complex Models

  2. Model Validation in ASP.NET Core

Working with complex models

Working with complex models in ASP.NET Core involves handling models that have multiple properties, including nested objects and collections. These complex models are common when dealing with forms, APIs, or database interactions that require structured data.


Below are some steps that you can follow to work with complex models in ASP.NET Core:


1. Defining Complex Models

Complex models are defined as classes with multiple properties, including other objects or collections. For example:

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string ZipCode { get; set; }
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address HomeAddress { get; set; }
    public List<string> Hobbies { get; set; }
}

In this example, the Person class is a complex model that includes an Address object and a list of hobbies.


2. Model Binding

ASP.NET Core's model binding system automatically maps incoming data from HTTP requests (e.g., form submissions or JSON payloads) to complex model properties based on property names.


Example: Model Binding in Controller Action

[HttpPost]
public IActionResult Create(Person person)
{
    // 'person' parameter will be automatically populated with data from the request
    // Access properties like person.FirstName, person.HomeAddress.Street, etc.
    
    // Process and save the data to a database
    return RedirectToAction("Success");
}

3. Binding to Nested Objects

You can bind to nested objects (like the HomeAddress property in the Person class) by naming form fields or JSON properties following the dot notation or square brackets:

<!-- Form Fields with Nested Object Names -->
<input type="text" name="HomeAddress.Street" />
<input type="text" name="HomeAddress.City" />
<input type="text" name="HomeAddress.ZipCode" />

4. Binding to Collections

To bind to collections within complex models (like the Hobbies property), use an index notation in form field names:

<!-- Form Fields for a List Property -->
<input type="text" name="Hobbies[0]" />
<input type="text" name="Hobbies[1]" />
<input type="text" name="Hobbies[2]" />

5. Displaying Complex Models in Views

To display complex model properties in views, you can use Razor syntax. For example, to display the person's first name and address in a Razor view:

<p>First Name: @Model.FirstName</p>
<p>Street: @Model.HomeAddress.Street</p>
<p>City: @Model.HomeAddress.City</p>

6. Validation with Complex Models

You can use data annotations and validation attributes on complex model properties to perform validation. The validation process works the same way as with simple models.


Example: Adding Validation Attributes to Complex Model

public class Person
{
    [Required(ErrorMessage = "First Name is required.")]
    public string FirstName { get; set; }
    
    [Required(ErrorMessage = "Last Name is required.")]
    public string LastName { get; set; }
    
    public Address HomeAddress { get; set; }
    
    public List<string> Hobbies { get; set; }
}

7. Handling Complex Model Errors

When model validation fails, error messages can be accessed using the ModelState dictionary in the controller:

if (!ModelState.IsValid)
{
    // Handle validation errors
    var errors = ModelState.Values.SelectMany(v => v.Errors);
    // ...
}

Working with complex models in ASP.NET Core enables you to build applications that handle structured data effectively, whether you're working with forms, APIs, or databases. ASP.NET Core's model binding and validation mechanisms make it easier to manage complex data structures in your applications.


Model validation in ASP.NET Core

Model validation in ASP.NET Core ensures that the data submitted by users through forms or API requests is valid and safe to process. It helps you to prevent invalid or malicious data from entering your application.


ASP.NET Core provides various mechanisms for model validation, including

  1. Data annotations

  2. Custom validation

  3. Automatic validation

1. Data Annotations

Data annotations are attributes that you can apply to model properties to define validation rules. ASP.NET Core provides a variety of built-in data annotation attributes that cover common validation scenarios.


Example: Using Data Annotations for Model Validation

Let's say you have a simple registration model with data annotations for validation:

using System.ComponentModel.DataAnnotations;

public class RegistrationModel
{
    [Required(ErrorMessage = "The Username field is required.")]
    [StringLength(50, MinimumLength = 3, ErrorMessage = "Username must be between 3 and 50 characters.")]
    public string Username { get; set; }

    [Required(ErrorMessage = "The Email field is required.")]
    [EmailAddress(ErrorMessage = "Invalid Email Address.")]
    public string Email { get; set; }

    [Required(ErrorMessage = "The Password field is required.")]
    [StringLength(100, MinimumLength = 6, ErrorMessage = "Password must be at least 6 characters long.")]
    public string Password { get; set; }
}

In this example:

  • [Required]: Ensures that the property is not null or empty.

  • [StringLength]: Specifies the minimum and maximum length of a string property.

  • [EmailAddress]: Validates that the property is a valid email address.

2. ModelState Validation

In your controller action methods, you can check the ModelState to see if any validation errors occurred during model binding. If there are errors, you can handle them accordingly.


Example: Handling ModelState Validation in a Controller

public IActionResult Register(RegistrationModel model)
{
    if (ModelState.IsValid)
    {
        // Model is valid, process the registration.
        // ...
        return RedirectToAction("Success");
    }

    // Model is invalid, return the view with error messages.
    return View(model);
}

3. Validation Summary

You can use the ValidationSummary HTML helper to display validation error messages in your views.


Example: Displaying Validation Errors in a View

@model RegistrationModel

<form asp-action="Register" method="post">
    <!-- Form fields here -->

    <div asp-validation-summary="All" class="text-danger"></div>

    <button type="submit">Register</button>
</form>

4. Custom Validation

You can create custom validation logic by implementing the IValidatableObject interface on your model class.


Example: Custom Validation in Model

using System.Collections.Generic;

public class CustomValidationModel : IValidatableObject
{
    public string SomeProperty { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var results = new List<ValidationResult>();

        if (!string.IsNullOrEmpty(SomeProperty) && SomeProperty.Contains("example"))
        {
            results.Add(new ValidationResult("SomeProperty cannot contain 'example'.", new[] { nameof(SomeProperty) }));
        }

        return results;
    }
}

In this example, we implement custom validation logic that checks if SomeProperty contains the word "example."


5. Remote Validation

Remote validation allows you to perform validation on the server asynchronously, without a full page refresh, by making an AJAX call to the server.


Example: Remote Validation in Model

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;

public class RemoteValidationModel
{
    [Remote("IsUsernameAvailable", "Account", ErrorMessage = "Username is already taken.")]
    public string Username { get; set; }
}

In this example, we use the [Remote] attribute to specify that the Username property should be validated on the server by calling the IsUsernameAvailable action in the Account controller.


These are some of the key aspects of model validation in ASP.NET Core. By applying validation attributes, checking ModelState, and handling validation errors, you can ensure that your application processes are valid and safe data. Custom validation logic allows you to handle complex validation scenarios specific to your application.


Conclusion

ASP.NET Core web UI models are the foundation of dynamic web interfaces, empowering developers to create strong and organized web applications. Armed with this understanding, you can enhance your web projects, delivering engaging user interfaces that stand out online. Embrace ASP.NET Core web UI models and shape the web's future with confidence.

Comments


bottom of page