ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【ASP.NET Core】在Blazor中获取 HTTP 上下文信息

2022-09-04 11:32:21  阅读:243  来源: 互联网

标签:Core ASP HTTP App Version 参数 组件 Blazor HttpContext


今天咱们来扯一下 Blazor 应用程序怎么访问 HttpContext。其实这句话有坑,为了避免大伙伴们掉茅坑,老周直接说明:Blazor 是不能访问 HttpContext 的。哪怕你在服务容器中注册了 IHttpContextAccessor 也不行,无法返回有效的上下文。

为啥?这得从 Blazor 的运行方式说起。银河系周知,Blazor 允许用 .NET 代码编写客户端逻辑,在某种程度(注意,是某种程度)上替代“奸商”……哦不,是 JS。Javascript 虽然语法上很像C某某,但和C某某比还是差得很远,代码阅读起来总感觉XYZ。尽管不能完全替换,但能实现一部分也是很好的。Blazor 主要是照顾像老周这种屌丝程序猴,一旦来项目了,一个人承担后台前台,连美工、图片处理都要一手包。所以用写后台代码的方式写前台更习惯。

上面一段全是废话!Blazor 只是在第一次运行的时候(不管是 Server 版还是 WASM 版)才会产生 HTTP 请求,之后的交互都由 Web Socket 来担任。往上说一层就是 SignalR。说直白一点就是,它只有第一次访问服务器才有 HttpContext,因为 Blazor 应用还没加载。一旦它加载成功了,后面就没 HttpContext 的事了。

结论:要取得 HttpContext 中需要的数据,只能在第一次请求时获得,然后你想尽办法让这些数据传给 Blazor 应用程序。本文老周将演示两种方法——基本能对付过去。

 方法一:级联参数

Blazor 需要一个HTML页面来承载,然后 Page 之间的切换都在这个HTML页面上进行。项目模板默认使用 Razor Pages—— 生成一个名为 _Host 的页面(当然你改用 MVC 的视图来加载也可以,一样的原理)。然后使用 component 标记帮助器来加载 Blazor 应用程序。Blazor 应用是通过组件来构建的,一般会有一个名为 App 的组件,充当根组件。

<component type="typeof(App)" render-mode="ServerPrerendered" />

App 组件放个 Router,作用无非就是能找到 Blazor 应用页面就呈现,找不到就显示反馈。

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

其实,Blazor 页面元素就是显示在 RouteView 组件下面的。所以,要使用级联参数组件,就可以把 CascadingValue 组件作为 RouteView 父级。

咱们先看一下数据的传递顺序:

1、要读 HttpContext 对象里的东西,获取数据的代码得在 _Host 页面上写;

2、在用 component 组件加载 App 组件时通过参数把数据传递给 App 内部;

3、App 组件内将数据传递给 CascadingValue;

4、各个 Blazor 页面组件都能够从 CascadingValue 组件中获取到数据。

HttpContext --> _Host.cshtml --> App.razor --> CascadingValue  --> XXX

下面是实现过程:(假设我们要获取 URL 查询参数)

1、在 App 组件中定义名为 Version 的属性,字符串类型。要应用 Parameter 特性,说明它是一个组件参数,在 component 标记帮助器中可以传参。

2、把 RouteView 组件放到 CascadingValue 组件下面,并让它的值(Value)引用 Version 属性的值。

// App.razor 文件

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <CascadingValue Name="ver" TValue="string" Value="@Version">
            <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        </CascadingValue>
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

@code
{
    [Parameter]
    public string? Version { get; set; }
}

3、在 _Host.cshtml 文件中(或你自己定义的 MVC 视图文件)中,读取 URL 查询中的 “v” 字段的值,然后通过 component 组件把值传递 App 组件。

……
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    Layout = "_Layout";

    // 从URL参数中读参数
    if(!HttpContext.Request.Query.TryGetValue("v",out var value))
    {
        value = "0.0.0";
    }
}

<component type="typeof(App)" render-mode="ServerPrerendered" param-Version="@value.ToString()" />

用 component 组件传递参数,可以用 param-* 特性,后面的 * 表示 App 组件接收参数的成员名称,这里是我们前面定义的 Version 属性,直接写成 param-Version 即可。如果属性名为 Name,那就写成 param-Name。

4、假设现在 Index.razor 组件要使用数据。需要在 Index 组件中定义一个属性成员,一定要应用 CascadingParameter 特性。注意这里 Name = "ver"。这个名字和刚才 App 组件中 CascadingValue 的 Name 是匹配的。

<p>接收到的数据:@Data</p>

@code
{
    [CascadingParameter(Name = "ver")]
    public string? Data{ get; set; }
}

要呈现 Data 属性的内容,只需在 HTML 中引用即可。

在运行程序后,访问时加上 v=5.0.3,这个字段的值就能传到 Index 组件中。

 

 

二、单实例服务

这个方案是运用了依赖注入的功能,咱们定义一个类,它的属性用于存储参数。

    public class PassDataService
    {
        public int Key1 { get; set; }
        public string? Key2 { get; set; }
    }

然后把它注册为单实例服务。

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
……
builder.Services.AddSingleton<PassDataService>();

var app = builder.Build();

在 _Host.cshtml 文件或你自定义的 MVC 视图文件中,读出 HttpContext 中数据,然后设置到 PassDataService 实例的属性上。

@page "/"
@namespace TestApp.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@inject PassDataService _datasv;
@{
    Layout = "_Layout";

    // 读取URL查询
    if(!HttpContext.Request.Query.TryGetValue("key1", out var kVal1))
    {
        kVal1 = "0";
    }
    if(!HttpContext.Request.Query.TryGetValue("key2", out var kVal2))
    {
        kVal2 = string.Empty;
    }
    // 赋值
    _datasv.Key1 = int.TryParse(kVal1, out int k1) ? k1 : 0;
    _datasv.Key2 = kVal2;
}

<component type="typeof(App)" render-mode="ServerPrerendered" />

@inject 指令可以注入需要的服务实例。

@inject <类型> <变量名>

 

在 Index 组件中,只要注入 PassDataService 服务实例,就能获取到数据。

@page "/"
@inject PassDataService _datasv

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

<p>获取到的数据:</p>
<div>Key1 = @_datasv.Key1</div>
<div>Key2 = @_datasv.Key2</div>

运行应用程序,在 URL 后面加上 key1 和 key2 参数。就得到传递的数据。

 

标签:Core,ASP,HTTP,App,Version,参数,组件,Blazor,HttpContext
来源: https://www.cnblogs.com/tcjiaan/p/16654364.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有