首先我們需要建立一個MasaFramework
模板的專案,專案名稱TokenDemo
,專案型別如圖所示
刪除Web/TokenDemo.Admin
專案,新建Masa Blazor Pro
專案模板
專案,專案位置在src/Web
專案
專案型別選擇ServerAndWasm
,為了讓我們支援倆種模式
建立完成以後的目錄,然後在TokenDemo.Admin
中新增專案參照TokenDemo.Caller
EntityFrameworkCore
和Sqlite
修改TokenDemo.Service
專案的包依賴為預覽版
<ItemGroup>
<PackageReference Include="Masa.BuildingBlocks.Dispatcher.Events" Version="1.0.0-preview.18" />
<PackageReference Include="Masa.Contrib.Data.Contracts" Version="1.0.0-preview.18" />
<PackageReference Include="Masa.Contrib.Data.EFCore.Sqlite" Version="1.0.0-preview.18" />
<PackageReference Include="Masa.Contrib.Dispatcher.Events" Version="1.0.0-preview.18" />
<PackageReference Include="Masa.Contrib.Dispatcher.IntegrationEvents.EventLogs.EFCore" Version="1.0.0-preview.18" />
<PackageReference Include="FluentValidation" Version="11.5.1" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.2.2" />
<PackageReference Include="Masa.Utils.Extensions.DependencyInjection" Version="1.0.0-preview.18" />
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0-preview.18" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
Masa.Contrib.Data.Contracts
提供了資料過濾的能力, 但它不是必須的
然後會出現報錯
LogMiddleware
將程式碼修改為以下程式碼
namespace TokenDemo.Service.Infrastructure.Middleware;
public class LogMiddleware<TEvent> : EventMiddleware<TEvent>
where TEvent : notnull, IEvent
{
private readonly ILogger<LogMiddleware<TEvent>> _logger;
public LogMiddleware(ILogger<LogMiddleware<TEvent>> logger)
{
_logger = logger;
}
public override async Task HandleAsync(TEvent action, EventHandlerDelegate next)
{
var typeName = action.GetType().FullName;
_logger.LogInformation("----- command {CommandType}", typeName);
await next();
}
}
ValidatorMiddleware
將程式碼修改為以下程式碼
namespace TokenDemo.Service.Infrastructure.Middleware;
public class ValidatorMiddleware<TEvent> : EventMiddleware<TEvent>
where TEvent : notnull, IEvent
{
private readonly ILogger<ValidatorMiddleware<TEvent>> _logger;
private readonly IEnumerable<IValidator<TEvent>> _validators;
public ValidatorMiddleware(IEnumerable<IValidator<TEvent>> validators, ILogger<ValidatorMiddleware<TEvent>> logger)
{
_validators = validators;
_logger = logger;
}
public override async Task HandleAsync(TEvent action, EventHandlerDelegate next)
{
var typeName = action.GetType().FullName;
_logger.LogInformation("----- Validating command {CommandType}", typeName);
var failures = _validators
.Select(v => v.Validate(action))
.SelectMany(result => result.Errors)
.Where(error => error != null)
.ToList();
if (failures.Any())
{
_logger.LogWarning("Validation errors - {CommandType} - Command: {@Command} - Errors: {@ValidationErrors}", typeName, action, failures);
throw new ValidationException("Validation exception", failures);
}
await next();
}
}
OrderEventHandler
將程式碼修改為以下程式碼
namespace TokenDemo.Service.Infrastructure.Handlers;
public class OrderEventHandler
{
readonly IOrderRepository _orderRepository;
public OrderEventHandler(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
[EventHandler(Order = 1)]
public async Task HandleAsync(QueryOrderListEvent @event)
{
@event.Orders = await _orderRepository.GetListAsync();
}
}
public class OrderEventAfterHandler : IEventHandler<QueryOrderListEvent>
{
public async Task HandleAsync(QueryOrderListEvent @event, CancellationToken cancellationToken = new CancellationToken())
{
await Task.CompletedTask;
}
}
修改appsettings.json
新增Sqlite
地址
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Data Source=Catalog.db;"
}
}
修改Program.cs
程式碼
using TokenDemo.Service.Infrastructure;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddAuthorization()
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = "";
options.RequireHttpsMetadata = false;
options.Audience = "";
});
builder.Services.AddMasaDbContext<ShopDbContext>(dbContextBuilder =>
{
dbContextBuilder
.UseSqlite() //使用Sqlite資料庫
.UseFilter(); //資料資料過濾
});
builder.Services.AddAutoInject();
var app = builder.Services
.AddEndpointsApiExplorer()
.AddSwaggerGen(options =>
{
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Name = "Authorization",
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer xxxxxxxxxxxxxxx\"",
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] {}
}
});
})
.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters()
.AddEventBus(eventBusBuilder =>
{
eventBusBuilder.UseMiddleware(typeof(ValidatorMiddleware<>));
eventBusBuilder.UseMiddleware(typeof(LogMiddleware<>));
})
.AddServices(builder);
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseHttpsRedirection();
app.Run();
新增EFCore遷移依賴
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.15">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.15">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
在程式包管理器控制檯
中輸入 Add-Migration Init
生成Init
的遷移檔案(如果出現 error NETSDK1082: Microsoft.AspNetCore.App 沒有執行時包可用於指定的 RuntimeIdentifier「browser-wasm」
這個錯誤的話就先把TokenDemo.Admin.WebAssembly
專案移除)
使用Update-Database
生成Sqlitem
然後就可以看到專案中生成了Catalog.db
檔案
啟動TokenDemo.Service.Order
我們就可以看到Swagger的介面了
開啟TokenDemo.Caller
專案中的``Callers\OrderCaller.cs`檔案
修改BaseAdderss
為TokenDemo.Service.Order
的服務地址
開啟TokenDemo.Service.Order
專案的Services\OrderService.cs
檔案並且修改程式碼
namespace TokenDemo.Service.Services;
public class OrderService : ServiceBase
{
public OrderService(IServiceCollection services) : base(services)
{
App.MapGet("/order/list", QueryList).Produces<List<Infrastructure.Entities.Order>>()
.WithName("GetOrders");
}
public async Task<IResult> QueryList(IEventBus eventBus)
{
var orderQueryEvent = new QueryOrderListEvent();
await eventBus.PublishAsync(orderQueryEvent);
return Results.Ok(orderQueryEvent.Orders);
}
}
然後在通過命令列啟動TokenDemo.Service.Order
專案
開啟TokenDemo\Admin
專案的Pages\Home\Index.razor
檔案並且修改程式碼
@page "/"
@using TokenDemo.Caller.Callers
@inherits LayoutComponentBase
@inject NavigationManager Nav
@inject OrderCaller OrderCaller
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
Nav.NavigateTo(GlobalVariables.DefaultRoute,true);
var data = await OrderCaller.GetListAsync();
await base.OnAfterRenderAsync(firstRender);
}
}
並且在await base.OnAfterRenderAsync(firstRender);
這裡打一個斷點用於檢視是否獲取到訊息
開啟TokenDemo.Admin.Server
專案的Program.cs
,新增以下程式碼
builder.Services.AddCaller(typeof(TokenDemo.Caller.Callers.OrderCaller).Assembly);
然後啟動TokenDemo.Admin.Server
專案,進入斷點
得到結果
通過上文我們可以基本將MasaFramework
的使用掌握,前端和後端的介面也掌握了
當前是MasaFramework
的第三篇入門,我會繼續學習MasaFramework
並且分享給大家
來自token的分享
學習交流:737776595