You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

标准化Blazor启动流程:类库中使用Application Builder的疑问

问题背景

我们用Blazor开发软件系统,同时想复用通用组件和页面开发桌面应用。目前Web服务器启动代码都是复制粘贴的,很不规范。我尝试用Application Builder标准化启动流程,核心通过继承实现通用Builder的定制来满足客户化需求,示例代码如下:

// Common implementation
class CommonAppBuilder
{
    public virtual Application CreateApplication()
    {
        var builder = MauiAppBuilder.CreateBuilder(); // Or some other builder for Blazor Server for example...

        // Configuration of something like a MauiAppBuilder or IConfiguration or our IServiceCollection is done in other methods of this builder that will be invoked at some point in here
    }

    // More stuff ...
}


// Application A implementation (application specific, still a standard application)
class ApplicationAAppBuilder : CommonAppBuilder
{
    public override Application CreateApplication()
    {
        var builder = base.CreateApplication();

        // Here I want to be able to add or intercept (simply override and differ from) the common, standard implementation of configuring and settings up our startup
    }

    // Maybe more overrides if need be...
}

// Customized application A implementation (application and customer specific)
class CustomApplicationAAppBuilder : ApplicationAAppBuilder
{
    public override Application CreateApplication()
    {
        var builder = base.CreateApplication();

        // Same story, I want to be able to inherit and override the respective standard, so I can replace standard parts with parts that need to be customized or simply add more...
    }
}

// Main(string[])
class Program
{
    public static void Main(string[] args)
    {
        // Everything about the applications configuration takes place in my application builder, so it can be standartized and override if need be
        new CustomApplicationAAppBuilder(args)
            .CreateApplication()
            .Run();
    }
}

现在已经实现了这个Builder,但项目结构冗余:要分别维护仅含Builder的MAUI Blazor项目、Blazor Server项目,存放通用扩展方法的常规C#项目,还有实际的Blazor Server和MAUI Blazor Desktop项目。现提出三个疑问:

  1. 是否可通过NuGet包将MauiAppBuilder和WebAppBuilder添加到常规Razor类库,合并三个项目?
  2. 这种Application Builder是否会引发问题?
  3. 是否有更优方案实现需求?
解答

1. 能否通过NuGet合并项目?

可以。常规Razor类库可以通过引用对应的NuGet包引入MauiAppBuilder和WebAppBuilder:

  • 引入Microsoft.AspNetCore.Components.Web包可获取Blazor Server相关的WebApplicationBuilder(需.NET 6+的WebApplication模型)
  • 引入Microsoft.Maui和Microsoft.Maui.Controls包可获取MauiAppBuilder

注意事项:

  • 配置类库的多目标框架,确保兼容net6.0/net7.0/net8.0及对应的MAUI目标框架(如net6.0-android、net6.0-ios等)
  • 仅引入启动相关的基础包,避免不必要的UI组件依赖,减少类库体积

这样就能把通用Builder、扩展方法统一放到同一个Razor类库中,消除项目冗余。

2. 这种Application Builder会引发问题吗?

基于继承的Builder模式本身可行,但要警惕几个潜在风险:

  • 继承层级过深:如果后续定制层级持续增加,会导致逻辑追踪困难,调试和维护成本上升
  • 基类变更影响范围广:CommonAppBuilder的核心逻辑修改会波及所有子类,容易引发意外问题
  • 职责混杂:如果Builder中同时包含配置、服务注册、中间件设置等多种逻辑,会违反单一职责原则,导致类过于臃肿

只要控制继承层级(最多2-3层),并将不同职责拆分到独立的虚方法(如ConfigureServices、ConfigureMiddleware)而非仅重载CreateApplication,就能规避大部分问题。

3. 更优方案有哪些?

方案一:基于组合的Builder模式

放弃继承,改用组合方式封装通用配置,通过扩展方法或委托注入定制逻辑:

public class CommonAppBuilder
{
    private readonly List<Action<IServiceCollection>> _serviceConfigurators = new();
    private readonly List<Action<IApplicationBuilder>> _middlewareConfigurators = new();

    public CommonAppBuilder AddServices(Action<IServiceCollection> configure)
    {
        _serviceConfigurators.Add(configure);
        return this;
    }

    public CommonAppBuilder AddMiddleware(Action<IApplicationBuilder> configure)
    {
        _middlewareConfigurators.Add(configure);
        return this;
    }

    public Application CreateApplication()
    {
        var builder = MauiAppBuilder.CreateBuilder();
        // 通用服务配置
        builder.Services.AddCommonServices();
        // 执行自定义服务配置
        foreach (var configure in _serviceConfigurators)
        {
            configure(builder.Services);
        }
        // 通用中间件配置
        var app = builder.Build();
        app.UseCommonMiddleware();
        // 执行自定义中间件配置
        foreach (var configure in _middlewareConfigurators)
        {
            configure(app);
        }
        return app;
    }
}

// 使用方式
new CommonAppBuilder()
    .AddServices(services => services.AddApplicationASpecificServices())
    .AddMiddleware(app => app.UseApplicationASpecificMiddleware())
    .CreateApplication()
    .Run();

这种方式更灵活,避免了继承的层级问题,定制逻辑更清晰。

方案二:宿主构建器扩展方法

直接针对WebApplicationBuilder和MauiAppBuilder编写通用扩展方法,封装通用配置:

public static class AppBuilderExtensions
{
    public static WebApplicationBuilder ConfigureCommonBlazorServer(this WebApplicationBuilder builder)
    {
        // 通用服务配置
        builder.Services.AddRazorPages();
        builder.Services.AddServerSideBlazor();
        builder.Services.AddCommonServices();
        return builder;
    }

    public static MauiAppBuilder ConfigureCommonMauiBlazor(this MauiAppBuilder builder)
    {
        builder.Services.AddMauiBlazorWebView();
#if DEBUG
        builder.Services.AddBlazorWebViewDeveloperTools();
#endif
        builder.Services.AddCommonServices();
        return builder;
    }

    public static IServiceCollection AddCommonServices(this IServiceCollection services)
    {
        // 通用服务注册
        services.AddSingleton<IMyService, MyService>();
        return services;
    }
}

项目中直接使用:

// Blazor Server项目
var builder = WebApplication.CreateBuilder(args);
builder.ConfigureCommonBlazorServer();
// 项目特定配置
builder.Services.AddApplicationAServices();
var app = builder.Build();
app.UseCommonMiddleware();
// 项目特定中间件
app.Run();

// MAUI Blazor项目
var builder = MauiApp.CreateBuilder(args);
builder.ConfigureCommonMauiBlazor();
// 项目特定配置
builder.Services.AddApplicationAServices();
var app = builder.Build();
app.Run();

这种方式轻量化,直接复用官方Builder模型,没有额外抽象层,学习和维护成本低。

方案三:自定义项目模板

用.NET模板引擎创建团队内部的自定义项目模板,把通用启动代码、项目结构封装进去,新项目通过dotnet new命令快速生成,彻底避免复制粘贴代码的问题。


内容的提问来源于stack exchange,提问作者Nico1395

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 15:02:01