(3)Part 3 of Introduction to MasaFramework, Using MasaFramework

(3)Part 3 of Introduction to MasaFramework, Using MasaFramework

Using MasaFramework

最后更新 3/26/2023 10:54 AM
token的技术分享
预计阅读 7 分钟
分类
.NET
标签
.NET C# MASA Framework

First, we need to create a MasaFramework template project. The project name is TokenDemo, and the project type is as shown in the figure:

Delete the Web/TokenDemon.Admin project and create a new Masa Blazor Pro project template project. The project location is src/Web project:

The project type chose ServerAndWasm, in order to allow us to support two models:

Create the directory after completion, and then add the project reference TokenDemon.Caller to TokenDemon.Admin.

Configure EntityFrameworkCore and Sqlite

Modify the package dependence of TokenDemon.Service project to preview version

<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 changes the code to the following code:

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 modifies the code to the following code:

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;
    }
}

Modify appsettings.json and add Sqlite address:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=Catalog.db;"
  }
}

Modify the Program.cs code:

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();

Add EFCore migration dependencies:

<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文件。

Start TokenDemon.Service.Order and we can see the Swagger interface.

How to connect interfaces

打开 TokenDemo.Caller 项目中的Callers\OrderCaller.cs文件,修改BaseAdderssTokenDemo.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);

Then start the TokenDemon.Admin. Server project and enter the breakpoint:

Get results.

end

Through the above, we can basically master the use of MasaFramework, as well as the front-end and back-end interfaces.

This is the third introduction to MasaFramework. I will continue to learn MasaFramework and share it with you.

Sharing from token.

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 4/22/2026

Support for. NET by operating system versions (250707 update)

Use virtual machines and test machines to test the support of each version of the operating system for. NET. After installing the operating system, it is passed by measuring the corresponding running time of the installation and being able to run the Stardust Agent.

继续阅读