I am building an ASP.NET Core 8.0 Blazor solution. This solution has 3 projects. 1st is an iStar.Framework.dll project that contains Model Classes. 2nd is iStar.Framework.ModelIRepos.dll that contains Interface repository classes. 3rd is iStar.Framework.Application.dll which contains repository classes to perform database operations.
iStar.Framework.dll has a model class named Company.
using System.ComponentModel.DataAnnotations.Schema;using System.ComponentModel.DataAnnotations;namespace iStar.Framework.Models{ public class Company { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] [StringLength(150)] public string Name { get; set; } = string.Empty; [DataType(DataType.Url)] public string? NavBarLogoUrl { get; set; } public bool UseNavBarLogoUrl { get; set; } = true; /// <summary> /// A collection of workplaces managed by this company /// </summary> public virtual ICollection<WorkStation> Workstations { get; set; } = new HashSet<WorkStation>(); }}It also has an interface named IModelRepo
namespace iStar.Framework{ public interface IModelRepo<T> where T : class { /// <summary> /// GetOne a list of all instances of the <typeparamref name="T"/> satisfying the set of values passed through parameters /// </summary> /// <returns>List<typeparamref name="T"/></returns> Task<List<T>?> GetAllAsync(); /// <summary> /// GetOne a list of all instances of the <typeparamref name="T"/> satisfying the set of values passed through parameters /// </summary> /// <returns>List<typeparamref name="T"/></returns> Task<List<T>?> GetActiveOnly(); /// <summary> /// GetOne an instance of <typeparamref name="T"/> with provided primary key value <paramref name="id"/> /// </summary> /// <param name="id">Primary Key value</param> /// <returns></returns> Task<T>? GetOneAsync(int id); /// <summary> /// GetOne a list of all the instances contining the string <paramref name="name"/> in its name value. /// </summary> /// <param name="name"></param> /// <returns>list of <typeparamref name="T"/></returns> Task<List<T>?> GetAllByNameAsync(string name); /// <summary> /// Adds <paramref name="item"/> of type <typeparamref name="T"/> to the end of relevant database table /// </summary> /// <param name="item">An instance of <typeparamref name="T"/></param> /// <returns></returns> Task AddAsync(T item); /// <summary> /// Updates the changes to the database made to the <paramref name="item"/> of type <typeparamref name="T"/> /// </summary> /// <param name="model">An already saved instance of <typeparamref name="T"/> with changes</param> /// <returns></returns> Task UpdateAsync(T item); /// <summary> /// Attempts to perform a dellete operation on database against an instances of <typeparamref name="T"/> with provided primary key value <paramref name="id"/> /// </summary> /// <param name="id">Primary key value of the instance of <typeparamref name="T"/> to be delleted</param> /// <returns></returns> Task DeleteAsync(int id); /// <summary> /// Attempts to dellete the provided instance of <typeparamref name="T"/> /// </summary> /// <param name="item">An instance of <typeparamref name="T"/> to be delleted</param> /// <returns></returns> Task DeleteAsync(T item); /// <summary> /// GetOne a list of all instances of the <typeparamref name="T"/> satisfying the set of values passed through parameters /// </summary> /// <param name="all">Returns all instances if set to True</param> /// <param name="ActiveOnly">Returns only active instances</param> /// <returns>List<typeparamref name="T"/></returns> List<T>? Get(bool all = true, bool ActiveOnly = false); /// <summary> /// GetOne an instance of <typeparamref name="T"/> with provided primary key value <paramref name="id"/> /// </summary> /// <param name="id">Primary Key value</param> /// <returns></returns> T? GetOne(int id); /// <summary> /// GetOne a list of all the instances contining the string <paramref name="name"/> in its name value. /// </summary> /// <param name="name"></param> /// <returns>list of <typeparamref name="T"/></returns> List<T>? GetAllByName(string name); /// <summary> /// Adds <paramref name="item"/> of type <typeparamref name="T"/> to the end of relevant database table /// </summary> /// <param name="item">An instance of <typeparamref name="T"/></param> /// <returns></returns> void Add(T item); /// <summary> /// Updates the changes to the database made to the <paramref name="item"/> of type <typeparamref name="T"/> /// </summary> /// <param name="model">An already saved instance of <typeparamref name="T"/> with changes</param> /// <returns></returns> void Updatec(T item); /// <summary> /// Attempts to perform a dellete operation on database against an instances of <typeparamref name="T"/> with provided primary key value <paramref name="id"/> /// </summary> /// <param name="id">Primary key value of the instance of <typeparamref name="T"/> to be delleted</param> /// <returns></returns> void Delete(int id); /// <summary> /// Attempts to dellete the provided instance of <typeparamref name="T"/> /// </summary> /// <param name="item">An instance of <typeparamref name="T"/> to be delleted</param> /// <returns></returns> void Delete(T item); }}iStar.Framework.IModelRepo has an interface for Company
public interface ICompanyRepo : IModelRepo<Company> { }iStar.Framework.Application has repository class for Company
using iStar.Framework.Application.Data;using iStar.Framework.ModelIRepos;using iStar.Framework.Models;using Microsoft.EntityFrameworkCore;namespace iStar.Framework.Application.Repositories{ public class CompanyRepo : ICompanyRepo { private readonly IDbContextFactory<FrameworkDbContext> _contextFactory; public CompanyRepo(IDbContextFactory<FrameworkDbContext> contextFactory) { _contextFactory = contextFactory; } public void Add(Company item) { throw new NotImplementedException(); } public async Task AddAsync(Company item) { using var context = _contextFactory.CreateDbContext(); context.Companies.Add(item); await context.SaveChangesAsync(); } public void Delete(int id) { throw new NotImplementedException(); } public void Delete(Company item) { throw new NotImplementedException(); } public Task DeleteAsync(int id) { throw new NotImplementedException(); } public Task DeleteAsync(Company item) { throw new NotImplementedException(); } public List<Company>? Get(bool all = true, bool ActiveOnly = false) { throw new NotImplementedException(); } public Task<List<Company>?> GetActiveOnly() { throw new NotImplementedException(); } public async Task<List<Company>?> GetAllAsync() { using var context = _contextFactory.CreateDbContext(); var lst = await context.Companies.ToListAsync(); return lst; } public List<Company>? GetAllByName(string name) { throw new NotImplementedException(); } public Task<List<Company>?> GetAllByNameAsync(string name) { throw new NotImplementedException(); } public Company GetOne(int id) { throw new NotImplementedException(); } public async Task<Company>? GetOneAsync(int id) { using var context = _contextFactory.CreateDbContext(); var cpy = await context.Companies .Where(c => c.Id == id) .FirstOrDefaultAsync(); if (cpy is not null) return cpy; else return null; } public Task UpdateAsync(Company item) { throw new NotImplementedException(); } public void Updatec(Company item) { throw new NotImplementedException(); } }}Another Blazor Server app in the same solution uses all above details in this way.
Here is the program.css class code.
using iStar.Framework.Application.Data;using iStar.Framework.Application.Repositories;using iStar.Framework.Application.Repositories.Identity;using iStar.Framework.ModelIRepos;using iStar.Framework.Models.Identity;..var builder = WebApplication.CreateBuilder(args);..builder.Services.AddScoped<ICompanyRepo, CompanyRepo>();..builder.Services.AddDbContextFactory<FrameworkDbContext>(options => { //options.UseLazyLoadingProxies(); options.UseSqlServer(connectionString); });..Below is CompanyList.razor code.
@* @page "/companies/list" *@@page "/cmpnylist"@using Microsoft.EntityFrameworkCore@inject CompanyRepo _companyRepo<div class="container-fluid bg-light py-2"><button class="btn btn-primary" @onclick="ShowAddCompanyModal">Add Company</button></div><h3>Company List</h3>@if (companies == null){<p><em>Loading...</em></p>}else{<table class="table table-hover"><thead><tr><th @onclick="() => SortCompanies(nameof(Company.Name))">Name</th><th @onclick="() => SortCompanies(nameof(Company.NavBarLogoUrl))">NavBar Logo URL</th><th @onclick="() => SortCompanies(nameof(Company.UseNavBarLogoUrl))">Use NavBar Logo URL</th></tr></thead><tbody> @foreach (var company in companies) {<tr><td>@company.Name</td><td>@company.NavBarLogoUrl</td><td>@company.UseNavBarLogoUrl</td></tr> }</tbody></table>}<div class="container-fluid bg-light py-2"><button class="btn btn-primary" @onclick="ShowAddCompanyModal">Add Company</button></div>@if (showModal){<div class="modal fade show d-block" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Add New Company</h5><button type="button" class="btn-close" @onclick="HideAddCompanyModal"></button></div><div class="modal-body"><EditForm Model="newCompany" OnValidSubmit="AddCompany"><DataAnnotationsValidator /><ValidationSummary /><div class="mb-3"><label for="name" class="form-label">Name</label><InputText id="name" class="form-control" @bind-Value="newCompany.Name" /></div><div class="mb-3"><label for="navBarLogoUrl" class="form-label">Nav Bar Logo URL</label><InputText id="navBarLogoUrl" class="form-control" @bind-Value="newCompany.NavBarLogoUrl" /></div><div class="form-check"><InputCheckbox id="useNavBarLogoUrl" class="form-check-input" @bind-Value="newCompany.UseNavBarLogoUrl" /><label for="useNavBarLogoUrl" class="form-check-label">Use Nav Bar Logo URL</label></div><button type="submit" class="btn btn-success mt-3">Save</button></EditForm></div></div></div></div>}@code { private List<Company>? companies; private bool ascending = true; private string currentSortColumn; private bool showModal = false; private Company newCompany = new Company(); protected override async Task OnInitializedAsync() { companies = await _companyRepo.GetAllAsync(); } private void SortCompanies(string columnName) { if (currentSortColumn == columnName) { ascending = !ascending; } else { currentSortColumn = columnName; ascending = true; } companies = ascending ? companies!.OrderBy(c => EF.Property<object>(c, columnName)).ToList() : companies!.OrderByDescending(c => EF.Property<object>(c, columnName)).ToList(); } private void ShowAddCompanyModal() { newCompany = new Company(); showModal = true; } private void HideAddCompanyModal() { showModal = false; } private async Task AddCompany() { await _companyRepo.AddAsync(newCompany); companies = await _companyRepo.GetAllAsync(); showModal = false; }}Below is _imports.razor code
@using System.Net.Http@using System.Net.Http.Json@using Microsoft.AspNetCore.Components.Authorization@using Microsoft.AspNetCore.Components.Forms@using Microsoft.AspNetCore.Components.Routing@using Microsoft.AspNetCore.Components.Web@using static Microsoft.AspNetCore.Components.Web.RenderMode@using Microsoft.AspNetCore.Components.Web.Virtualization@using Microsoft.JSInterop@using TutorsOnlinePortal@using TutorsOnlinePortal.Client@using TutorsOnlinePortal.Components@using iStar.Framework.Models.Identity@using iStar.Framework.Application.Repositories@using iStar.Framework.ModelsWhen I run this app, everything goes fine until I click the clink that loads CompanyList.razor page. It shows the following error.
InvalidOperationException: Cannot provide a value for property '_companyRepo' on type 'TutorsOnlinePortal.Components.Framework.Company.CompanyList'. There is no registered service of type 'iStar.Framework.Application.Repositories.CompanyRepo'.I have checked all the paths, refferences etc. I have cleaned and rebuilt solution many times but the error does not go away. Remember that app logs in using Microsoft Identity Core infratscture.