Build Master Detail CRUD in ASP.NET Core 3.1 Blazor

Build-Master-Detail-CRUD-in-ASP.NET-Core-3.1-Blazor image

Master-Detail is a page that manages two related information in which the master present items and the detail page presents details about the item. This article explains how to build simple master-detail in APS.NET Core 3.1 Blazor.
At the end of this article, you should be able to:
  1. Build a master-detail in Blazor. 
  2. Use Blazor components.
  3. Use IJSRuntime to call JavaScript functions from .NET methods.
  4. Call Web APIs in Blazor.
  5. Interact with Database.
  6. Run Blazor Application from ASP.NET Core Application.

Prerequisites
  1. Visual Studio 2019
  2. .NET Core 3.1 SDK Installed
  3. Blazor WebAssembly template installed
Create The Project
  • Create a new project
  • Select Blazor App
  • Name the project MasterDetailCRUD
  • Select Blazor WebAssembly App template then click create
  • Build, and run the default application.
Modify the NavMenu.razor file in the shared folder like so:
1:  <div class="top-row pl-4 navbar navbar-dark">  
2:    <a class="navbar-brand" href="">Master Detail CRUD</a>  
3:    <button class="navbar-toggler" @onclick="ToggleNavMenu">  
4:      <span class="navbar-toggler-icon"></span>  
5:    </button>  
6:  </div>  
7:  <div class="@NavMenuCssClass" @onclick="ToggleNavMenu">  
8:    <ul class="nav flex-column">  
9:      <li class="nav-item px-3">  
10:        <NavLink class="nav-link" href="" Match="NavLinkMatch.All">  
11:          <span class="oi oi-home" aria-hidden="true"></span> Home  
12:        </NavLink>  
13:      </li>  
14:    </ul>  
15:  </div>  
16:  @code {  
17:    private bool collapseNavMenu = true;  
18:    private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;  
19:    private void ToggleNavMenu()  
20:    {  
21:      collapseNavMenu = !collapseNavMenu;  
22:    }  
23:  }  

Also, modify the MainLayout.razor like so:
1:  @inherits LayoutComponentBase  
2:  <div class="sidebar">  
3:    <NavMenu />  
4:  </div>  
5:  <div class="main">  
6:    <div class="top-row px-4">  
7:    </div>  
8:    <div class="content px-4">  
9:      @Body  
10:    </div>  
11:  </div>  

Add Models
  • Right-click the project solution > Add > New project
  • Select Class Library (.NET Framework) from the templates
  • Name the project MasterDetailCRUD.Models.
Create OrderDetail model like so:
1:  namespace MasterDetailCRUD.Models  
2:  {  
3:    public class OrderDetail  
4:    {  
5:      public int OrderDetailId { get; set; }  
6:      public decimal Price { get; set; }  
7:      public int Quantity { get; set; }  
8:      public string Item { get; set; }  
9:      public int OrderId { get; set; }  
10:     public decimal TotalPerItem { get => Quantity * Price; }  
11:    }  
12:  }  

Add Order and OrderViewModel model like so:
1:  using System;  
2:  using System.Collections.Generic;  
3:  namespace MasterDetailCRUD.Models  
4:  {  
5:    public class Order  
6:    {  
7:      public int OrderId { get; set; }  
8:      public string OrderNumber { get; set; }  
9:      public string CustomerName { get; set; }  
10:     public string PaymentMethod { get; set; }  
11:     public DateTime DateCreated { get; set; }  
12:     public decimal Total { get; set; }  
13:     public string Status { get; set; }  
14:     public IEnumerable<OrderDetail> OrderDetails { get; set; }  
15:     public Order()  
16:     {  
17:       OrderDetails = new List<OrderDetail>();  
18:     }  
19:    }  
20:    public class OrderViewModel  
21:    {  
22:      public bool ShowDetail { get; set; }  
23:      public string DetailIcon { get; set; } = "oi-caret-right";  
24:      public int OrderId { get; set; }  
25:      public string OrderNumber { get; set; }  
26:      public string CustomerName { get; set; }  
27:      public string PaymentMethod { get; set; }  
28:      public DateTime DateCreated { get; set; }  
29:      public decimal Total { get; set; }  
30:      public string Status { get; set; }  
31:      public IEnumerable<OrderDetail> OrderDetails { get; set; }  
32:      public OrderViewModel()  
33:      {  
34:        OrderDetails = new List<OrderDetail>();  
35:      }  
36:    }  
37:  }  

Setup Database
  • Right-click on the solution > Add >New project
  • Select ASP.NET Core Web Application 
  • Name the project MasterDetailCRUD.Server and click create
  • Select the Empty project template and click create
  • Add reference to the MasterDetail.models project
  • Right-click on the MasterDetailCRUD.Server > Add  > Class
  • Name the dbcontext class  CustomerOderContext.
Modify the CustomerOderContext like so:
1:  using MasterDetailCRUD.Models;  
2:  using Microsoft.EntityFrameworkCore;  
3:  namespace MasterDetailCRUD.Server  
4:  {  
5:    public class CustomerOderContext : DbContext  
6:    {  
7:      public CustomerOderContext()  
8:      {  
9:      }  
10:      public CustomerOderContext(DbContextOptions options):base(options)  
11:      {  
12:      }  
13:      public DbSet<Order> Orders { get; set; }  
14:      public DbSet<OrderDetail> OrderDetails { get; set; }  
15:    }  
16:  }  

Create Seed Data
Add new class named SeedData to the MasterDetailCRUD.Server Project
Modify the SeedData class like so:
1:  using MasterDetailCRUD.Models;  
2:  using System;  
3:  namespace MasterDetailCRUD.Server  
4:  {  
5:    public class SeedData  
6:    {  
7:      public static void Initialize(CustomerOderContext db)  
8:      {  
9:        var order = new Order()  
10:        {  
11:          CustomerName = "Test Customer",  
12:          PaymentMethod = "Cash",  
13:          DateCreated = DateTime.Now,  
14:          Status = "P",  
15:          Total = 67000.00m,  
16:          OrderNumber = "456712",  
17:        };  
18:        db.Orders.Add(order);  
19:        db.SaveChanges();  
20:        var orderdetail = new OrderDetail()  
21:        {  
22:          Item = "Iphone X max",  
23:          Quantity = 2,  
24:          OrderId = order.OrderId,  
25:          Price = 32.00m,  
26:        };  
27:        db.OrderDetails.Add(orderdetail);  
28:        db.SaveChanges();  
29:      }  
30:    }  
31:  }  
The seed data will be used to initialize the empty database. This ensure the database have default record.
Modify the Program.cs file to use the seed data when the database is created like so:
1:  using Microsoft.AspNetCore.Hosting;  
2:  using Microsoft.Extensions.DependencyInjection;  
3:  using Microsoft.Extensions.Hosting;  
4:  namespace MasterDetailCRUD.Server  
5:  {  
6:    public class Program  
7:    {  
8:      public static void Main(string[] args)  
9:      {  
10:        var host = CreateHostBuilder(args).Build();  
11:        var scopeFactory = host.Services.GetRequiredService<IServiceScopeFactory>();  
12:        using (var scope = scopeFactory.CreateScope())  
13:        {  
14:          var db = scope.ServiceProvider.GetRequiredService<CustomerOderContext>();  
15:          if (db.Database.EnsureCreated())  
16:          {  
17:            SeedData.Initialize(db);  
18:          }  
19:        }  
20:        host.Run();  
21:      }  
22:      public static IHostBuilder CreateHostBuilder(string[] args) =>  
23:        Host.CreateDefaultBuilder(args)  
24:          .ConfigureWebHostDefaults(webBuilder =>  
25:          {  
26:            webBuilder.UseStartup<Startup>();  
27:          });  
28:    }  
29:  }  

Next, configure the services in application startup to use the CustomerOderContext class like so:
1:  using Microsoft.AspNetCore.Builder;  
2:  using Microsoft.AspNetCore.Hosting;  
3:  using Microsoft.EntityFrameworkCore;  
4:  using Microsoft.Extensions.DependencyInjection;  
5:  using Microsoft.Extensions.Hosting;  
6:  namespace MasterDetailCRUD.Server  
7:  {  
8:    public class Startup  
9:    {  
10:      // This method gets called by the runtime. Use this method to add services to the container.  
11:      // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940  
12:      public void ConfigureServices(IServiceCollection services)  
13:      {  
14:        services.AddMvc();  
15:        services.AddDbContext<CustomerOderContext>(option => option.UseSqlite("Data Source=CustomerOrder.db"));  
16:      }  
17:      // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
18:      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
19:      {  
20:        if (env.IsDevelopment())  
21:        {  
22:          app.UseDeveloperExceptionPage();  
23:        }  
24:        app.UseStaticFiles();  
25:        app.UseRouting();  
26:        app.UseEndpoints(endpoints =>  
27:        {  
28:          endpoints.MapControllers();  
29:        });  
30:      }  
31:    }  
32:  }  

The above uses Sqlite and create CustomerOrder database.

Add OrderController
Right click the MasterDetailCRUD.Server project, add a new class called OrderController.cs.
Modify the class like so.
1:  using MasterDetailCRUD.Models;  
2:  using Microsoft.AspNetCore.Mvc;  
3:  using Microsoft.EntityFrameworkCore;  
4:  using System;  
5:  using System.Collections.Generic;  
6:  using System.Threading.Tasks;  
7:  namespace MasterDetailCRUD.Server  
8:  {  
9:    [Route("Orders")]  
10:    [ApiController]  
11:    public class OrderController : Controller  
12:    {  
13:      private readonly CustomerOderContext db;  
14:      public OrderController(CustomerOderContext _db)  
15:      {  
16:        db = _db;  
17:      }  
18:      [HttpGet]  
19:      public async Task<List<OrderViewModel>> GetOrders()  
20:      {  
21:        var model = new List<OrderViewModel>();  
22:        try  
23:        {  
24:          var data =await db.Orders.Include(j => j.OrderDetails).ToListAsync();  
25:          foreach (var item in data)  
26:          {  
27:            model.Add(new OrderViewModel()  
28:            {  
29:              DateCreated = item.DateCreated,  
30:              CustomerName = item.CustomerName,  
31:              PaymentMethod = item.PaymentMethod,  
32:              OrderDetails = item.OrderDetails,  
33:              OrderNumber = item.OrderNumber,  
34:              Status = item.Status,  
35:              OrderId = item.OrderId,  
36:              Total = item.Total,  
37:            });  
38:          }  
39:        }  
40:        catch (Exception)  
41:        {  
42:        }  
43:        return model;  
44:      }  
45:      [HttpPost]  
46:      public async Task<ActionResult<int>> PostOrder(Order order)  
47:      {  
48:        try  
49:        {  
50:          order.Status = "P";  
51:          order.DateCreated = DateTime.Now;  
52:          var OrderDetails = order.OrderDetails;  
53:          order.OrderDetails = null;  
54:          await db.Orders.AddAsync(order);  
55:          await db.SaveChangesAsync();  
56:          var orderdetail = new List<OrderDetail>();  
57:          foreach (var detail in OrderDetails)  
58:          {  
59:            detail.OrderDetailId = 0;  
60:            detail.OrderId = order.OrderId;  
61:            orderdetail.Add(detail);  
62:          }  
63:          await db.OrderDetails.AddRangeAsync(orderdetail);  
64:          await db.SaveChangesAsync();  
65:        }  
66:        catch (Exception)  
67:        {  
68:          return -1;  
69:        }  
70:        return order.OrderId;  
71:      }  
72:    }  
73:  }  

The OrderController inherits from Controller class and it is decorated with ApiController attribute. It has two methods, the GetOrders method that retrieves list of customer orders and the PostOrder method which persists new customer order to the CustmerOrder database.

Configure ASP.NET Core project to run the Blazor Application
We want to be able to run MasterDetailCRUD blazor project using the MasterDetailCRUD.Server  ASP.NET Core project.
In the MasterDetailCRUD.Server project, use package manager console to install the following:

 Install-Package Microsoft.AspNetCore.Blazor.Server -Version 3.1.0-preview3.19555.2  

Add project reference of MasterDetailCRUD blazor project to MasterDetailCRUD.Server.
Modify the Startup file like so:
1:  using Microsoft.AspNetCore.Builder;  
2:  using Microsoft.AspNetCore.Hosting;  
3:  using Microsoft.EntityFrameworkCore;  
4:  using Microsoft.Extensions.DependencyInjection;  
5:  using Microsoft.Extensions.Hosting;  
6:  namespace MasterDetailCRUD.Server  
7:  {  
8:    public class Startup  
9:    {  
10:      // This method gets called by the runtime. Use this method to add services to the container.  
11:      // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940  
12:      public void ConfigureServices(IServiceCollection services)  
13:      {  
14:        services.AddMvc();  
15:        services.AddDbContext<CustomerOderContext>(option => option.UseSqlite("Data Source=CustomerOrder.db"));  
16:      }  
17:      // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
18:      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
19:      {  
20:        if (env.IsDevelopment())  
21:        {  
22:          app.UseDeveloperExceptionPage();  
23:        }  
24:        app.UseStaticFiles();  
25:        app.UseRouting();  
26:        app.UseClientSideBlazorFiles<MasterDetailCRUD.Startup>();  
27:        app.UseEndpoints(endpoints =>  
28:        {  
29:          endpoints.MapControllers();  
30:          endpoints.MapFallbackToClientSideBlazor<MasterDetailCRUD.Startup>("index.html");  
31:        });  
32:      }  
33:    }  
34:  }  

Set MasterDetailCRUD.Server as the start project, build and run the project.

Lets take a break so as to keep the article as simple as possible.
The second part concludes this article.

Download Source Code
                                         
                                                                                                                                   Part II >>
Build Master Detail CRUD in ASP.NET Core 3.1 Blazor Build Master Detail CRUD in ASP.NET Core 3.1  Blazor Reviewed by Akintunde Toba on February 26, 2020 Rating: 5

No comments:

Home Ads

Powered by Blogger.