【asp.net core】在blazor中获取 http 上下文信息_东邪独孤-编程思维

今天咱们来扯一下 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 参数。就得到传递的数据。

 

版权声明:本文版权归作者所有,遵循 CC 4.0 BY-SA 许可协议, 转载请注明原文链接
https://www.cnblogs.com/tcjiaan/p/16654364.html

.net 7 性能改进 -- 至今为止最快的.net平台_张善友-编程思维

2022年8月31日 Stephen Toub 发布的关于 .NET 7 性能改进的博客, 核心主题是 .NET 7 速度很快。 这篇博客非常的长,我尝试将它拷贝到Word 里,拷贝的时间都花了几分钟,通过Word 统计的字数是超过了76000 个字, 如果您每秒可以阅读三个单词,则需要 6 到 7 个小时才能完成阅读

配置iconfiguration_磊_磊-编程思维

前言 配置是我们必不可少的功能,我们在开发中,经常会遇到需要获取配置信息的需求,那么如何才能优雅的获取配置信息? 我们希望新的配置: 支持强类型 配置变更后通知 学习难度低 快速入门 根据使用场景我们将配置分为本地配置以及远程配置,下面我们就来看一下本地配置与远程配置是如何来使用的? 安装.Net 6.0 本

nuget 多项目复合打包_唐宋元明清2188-编程思维

问题描述 我这里有个进程间通信组件,用于提供多应用间通信的解决方案。 进程间通信,分为客户端和服务端,俩端肯定会有些共性代码,所以加了个H3C.Channel.Core项目 因为之前还不太了解nuget这块,然后我就踩到了坑: 引用H3C.Channel.Client包后,H3C.Channel.Core代码竟然没有

在opencloudos 上安装.net 6_张善友-编程思维

开源操作系统社区 OpenCloudOS 由腾讯与合作伙伴共同倡议发起,是完全中立、全面开放、安全稳定、高性能的操作系统及生态。OpenCloudOS 沉淀了多家厂商在软件和开源生态的优势,继承了腾讯在操作系统和内核层面超过10年的技术积累,在云原生、稳定性、性能、硬件支持等方面均有坚实支撑,可以平等全面地支持所有硬件

des加密_深入学习ing-编程思维

DES加密是第一次使用,现在已经是一种过时的加密方式了,由于需求用到,这里列举一个示例: 核心代码: /// <summary> /// DES加密 /// </summary> /// <param name="data">加密字符串</param> /// <

用vs code搞qt6:至简窗口部件——qwidget_东邪独孤-编程思维

在正题开始之前,老周照例扯点别的。嗯,咱们扯一下在 VS 2022 下结合 CMake 开发 Qt6 时的环境变量设置问题。在VS Code 中,通够通过 CMake Tools 扩展的配置来设置环境,但在VS 里面,CMake 项目只是一个文件夹,然后通过 .json 文件来配置一些参数,不能像 VS Code 那样

用vs code搞qt6:编译附加模块_东邪独孤-编程思维

上一次水文中,老周所介绍的是编译 Qt 的基础模块—— qtbase。一次性编译所有代码可以一劳永逸,但体积相当大,编译时间较长,CPU负载大发热大,风扇转得猛,电费交得多。因此老周更喜欢分开来编译。 qtbase 模块已经能完成一般的 Qt 开发了,毕竟它包含了铁三角—— Core、Gui、Widgets。有这三个硬

【wcf】自定义错误处理(ierrorhandler接口的用法)_东邪独孤-编程思维

当被调用的服务操作发生异常时,可以直接把异常的原始内容传回给客户端。在WCF中,服务器传回客户端的异常,通常会使用 FaultException,该异常由这么几个东东组成: 1、Action:在服务调用中,action标头比较重要,它是塞在SOAP消息的Headers元素下面的,是消息头的一部分,action用来对服务

【asp.net core】自定义session的存储方式_东邪独孤-编程思维

在开始今天的表演之前,老周先跟大伙伴们说一句:“中秋节快乐”。 今天咱们来聊一下如何自己动手,实现会话(Session)的存储方式。默认是存放在分布式内存中。由于HTTP消息是无状态的,所以,为了让服务器能记住用户的一些信息,就用到了会话。但会话数据毕竟是临时性的,不宜长久存放,所以它会有过期时间。过期了数据就无法使用

用 vs code 搞qt6:使用 pyside 6_东邪独孤-编程思维

一般来说,用C++写 Qt 应用才是正宗的,不过,为了让小学生也能体验 Qt 的开发过程,或者官方为了增加开发者人数,推出了可用 Python 来编程的 Qt 版本。此版本命名比较奇葩,叫 PySide,与 Qt 6 配套的是 PySide 6。当前最新版本是 6.3.2。 PySide 的优势在于它是官方维护的,完全