Blazor web App的结构——(二)

一  创建解决方案及项目架构

     1  创建解决方案

         dotnet new sln -o KBlazorWebAppDemo
         将在目录KBlazorWebAppDemo下生成一个解决方案文件KBlazorWebAppDemo.sln

     2  创建项目

         进入子目录:cd  KBlazorWebAppDemo

         创建新项目:dotnet new web -o KBWebApp
     3 将项目加到解决方案

         dotnet sln add KBWebApp\KBWebApp.csproj
     4 查看目录结构

        tree /f        

    查看program.cs文件

Minimal API使用四行代码构建一个web程序;默认监听7238和5174端口;     

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

 

   

这就是最基础的项目架构了,接下来丰富内容;

      

二   添加Blazor服务

     1  添加Razor服务        

        builder.Services.AddRazorComponents().AddInteractiveServerComponents();

     2  添加静态文件使用并添加静态文件目录wwwroot

        app.UseStaticFiles();

    3  加入路由

        添加目录components, components/pages

        在components目录下添加App.razor

     4 在Pages目录下创建一个页面

        Home.razor(可以任意命名),修改Home.razor: 添加路由     @page "/"

      5 加入razor交互模式

         app.MapRazorComponents<App>().AddInteractiveServerRenderMode();

至此,Blazer最基本框架已经创建。

三    定义组件(页面)特定样式

       1 样式隔离的作用

         将 CSS 样式隔离到各个页面、视图和组件以减少或避免:依赖难以维护的全局样式,嵌套内容中样式冲突;

       2  定义组件特定的样式

           相同文件夹中创建一个.razor.css,例如创建MainLayout.razor.css;

       3  启用样式隔离

           3.1 CSS隔离捆绑

                 在App.razor中添加引用表样式:

       3.2 programs.cs中添加对静态资源文件使用的支持

             app.MapStaticAssets();             

  到此,一个最简单的Blazor Web App就创建出来了。

四   其中的问题

      1  图标不显示

          <link rel="icon" type="image/png" href="Kerry.png" />

          解决方法:将图标文件小写<link rel="icon" type="image/png" href="kerry.png" />

      2  注册组件——密码合规验证

           在Blazor密码合规验证时,如果密码不合规会跳到注册确认组件;相关原始代码如下:

var result = await UserManager.CreateAsync(user, Input.Password);

if (!result.Succeeded)
{
    identityErrors = result.Errors;
}

Logger.LogInformation("User created a new account with password.");
var userId = await UserManager.GetUserIdAsync(user);
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user);

var callbackUrl = NavigationManager.GetUriWithQueryParameters(
NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri,
new Dictionary<string, object?>() { ["userId"] = userId, ["code"] = code,
["returnUrl"] = ReturnUrl });

await EmailSender.SendConfirmationLinkAsync(user, Input.Email,
    HtmlEncoder.Default.Encode(callbackUrl));

Dictionary<string, object?> input = new Dictionary<string, object?>() 
    { ["email"] = Input.Email, ["returnUrl"] = ReturnUrl};

if (UserManager.Options.SignIn.RequireConfirmedAccount)
{
    RedirectManager.RedirectTo("Account/RegisterConfirmation",
    input);
} 
View Code

           个人认为,如果密码合规,应该给出相关提示,代码如下:

 ApplicationUser user = CreateUser();
 await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
 IUserEmailStore<ApplicationUser> emailStore = GetEmailStore();
 await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
 var result = await UserManager.CreateAsync(user, Input.Password);

 if (!result.Succeeded)
 {
     identityErrors = result.Errors;
     return;
 }

      即在执行result = await UserManager.CreateAsync(user, Input.Password)后,得到失败结果后,应该直接返回显示相关信息。

五   NavMenu

    1  菜单图标        

        以下代码中<span>中的class定义菜单图标

       <NavLink class="nav-link" href="todo">

      <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span>Todo
      </NavLink>

    2  关于logout

        其中action="Account/Logout",当在菜单上点击[Logout]时,会执行await signInManager.SignOutAsync();

<div class="nav-item px-3">
    <form action="Account/Logout" method="post">
        <AntiforgeryToken/>
        <input type="hidden" name="ReturnUrl" value="@currentUrl" />
        <button type="submit" class="nav-link">
            <span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true"/>Logout
        </button>
    </form>
</div>

        这个方法在IdentityComponentsEndpointRouteBuilderExtensions.cs文件MapAdditionalIdentityEndpoints()方法中以委托方式进行注册。

        方法的签名为public static IEndpointConventionBuilder MapAdditionalIdentityEndpoints(this IEndpointRouteBuilder endpoints),其中使用了this表明是接口IEndpointRouteBuilder的扩展方法,而WebApplication继承了IEndpointRouteBuilder,因此WebApplication的实例可以直接调用。

accountGroup.MapPost("/Logout", async (
    ClaimsPrincipal user,
    SignInManager<ApplicationUser> signInManager,
    [FromForm] string returnUrl) =>
{
    await signInManager.SignOutAsync();
    return TypedResults.LocalRedirect($"~/{returnUrl}");
});

       因而在program.cs中可以直接调用:app.MapAdditionalIdentityEndpoints();

       

 

          

 

 

 

      

 

 

 

    

 

          

posted on 2025-04-24 15:56  博观约取*厚积薄发  阅读(129)  评论(0)    收藏  举报