我正在构建 ASP.NET Core 8.0 Blazor 解决方案。该解决方案有 3 个项目。第一个是包含
iStar.Framework.dll
的 Model Classes
项目。第二个是 iStar.Framework.ModelIRepos.dll
,其中包含 Interface
存储库类。第三个是iStar.Framework.Application.dll
,其中包含用于执行数据库操作的存储库类。
iStar.Framework.dll
有一个名为 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>();
}
}
它还有一个名为
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
有一个 Company
的界面
public interface ICompanyRepo : IModelRepo<Company> { }
iStar.Framework.Application
有 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();
}
}
}
同一解决方案中的另一个 Blazor Server 应用程序以这种方式使用上述所有详细信息。
这是
program.css
类代码。
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);
});
.
.
以下是
CompanyList.razor
代码。
@* @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;
}
}
以下是
_imports.razor
代码
@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.Models
当我运行这个应用程序时,一切都很顺利,直到我单击加载
CompanyList.razor
页面的叮当声。它显示以下错误。
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'.
我已经检查了所有路径、参考资料等。我已经多次清理和重建解决方案,但错误并没有消失。请记住,应用程序使用 Microsoft Identity Core 基础设施登录。
确保您已在
CompanyRepo
文件中注册了 ICompanyRepo
和 Program.cs
,如下所示。
...
builder.Services.AddDbContextFactory<FrameworkDbContext>(options =>
{
options.UseSqlServer(connectionString);
});
// Make sure you have this line
builder.Services.AddScoped<ICompanyRepo, CompanyRepo>();
var app = builder.Build();
...
同时找到
CompanyList.razor
文件,修改这一行
@inject CompanyRepo _companyRepo
到
@inject ICompanyRepo _companyRepo