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

【ASP.NET Core】在Blazor中获取 HTTP 上下文信息的更多相关文章

  1. 在ASP.NET Core 2.x中获取客户端IP地址

    一.前言 大家也知道服务端请求时我们获取的IP地址是包含在请求头中,因此这也大大便利了IP的获取. 在ASP.NET中,可以通过以下方式获取客户端的IP地址. HttpContext.Current. ...

  2. .NET Core 3.0 Preview 6中对ASP.NET Core和Blazor的更新

    我们都知道在6月12日的时候微软发布了.NET Core 3.0的第6个预览版.针对.NET Core 3.0的发布我们国内的微软MVP-汪宇杰还发布的官翻版的博文进行了详细的介绍.具体的可以关注&q ...

  3. .NET Core 3.0预览版7中的ASP.NET Core和Blazor更新

    .NET Core 3.0 Preview 7现已推出,它包含一系列ASP.NET Core和Blazor的新更新. 以下是此预览中的新功能列表: 最新的Visual Studio预览包括.NET C ...

  4. ASP.NET Core 1.0 中的依赖项管理

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  5. 在ASP.NET Core 1.0中如何发送邮件

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:目前.NET Core 1.0中并没有提供SMTP相关的类库,那么要如何从ASP.NE ...

  6. 在ASP.NET Core Web API中为RESTful服务增加对HAL的支持

    HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务 ...

  7. [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了

    [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 本文首发自:博客园 文章地址: https://www.cnblogs.com/yilezhu/p/ ...

  8. ASP.NET Core 2.2中的Endpoint路由

    Endpoint路由 在ASP.NET Core 2.2中,新增了一种路由,叫做Endpoint(终结点)路由.本文将以往的路由系统称为传统路由. 本文通过源码的方式介绍传统路由和Endpoint路由 ...

  9. C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志

    C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...

随机推荐

  1. numpy学习笔记02

    简介 numpy.array() 数组对象,可以表示普通的一维数组,或者二维矩阵,或者任意数据:并且它可以对数组中的数据进行非常高效的运算,如:数据统计.图像处理.线性代数等 numpy 之所以能运行 ...

  2. dubbox、zookeeper BUG记录

    主要错误信息: dubbo:com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method... Caused by: com.alib ...

  3. zabbix-5.0自动发现

    1. 安装zabbix5.0 rpm -Uvh https://repo.zabbix.com/zabbix/5.0/rhel/7/x86_64/zabbix-release-5.0-1.el7.no ...

  4. UiPath官方视频Level2

    [UiPath官方视频Level2]Lesson Orchestrator-第5部分 https://www.bilibili.com/video/av81414017 [UiPath官方视频Leve ...

  5. centos 7安装gitlab及使用

    GitLab 概述: 是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的 Git 项目仓库,可通过 Web界面迚行访问公开的戒者私人项目.Ruby on Rails 是一个可 ...

  6. 浏览器中的原生base64方法

    在web开发中,经常涉及到对文本.文件等进行base64编码处理,在之前的开发中,使用js-base64来进行处理,但其实浏览器已经原生包含了处理方法.性能更好,兼容性也更高. atob() - AS ...

  7. 用cmd命令进行磁盘清理(主要是系统盘)

    作用:清理磁盘(主要是系统盘)中不需要的垃圾文件操作方法: 第一步:Windows键+R键 调出cmd命令窗口(窗口图如下:) 第二步:输入框中输入cmd命令,按下Enter键,进入如下图界面: 第三 ...

  8. 5-17 ELK 日志采集查询保存

    ELK简介 什么是ELK ELK: E:Elasticsearch 全文搜索引擎 L:logstash 日志采集工具 K:Kibana ES的可视化工具 ELK是当今业界非常流行的日志采集保存和查询的 ...

  9. docker容器数据管理

    Docker容器数据卷 Docker中的数据可以存储在类似于虚拟机磁盘的介质中,在Docker中称为数据卷(Data Volume). 数据卷可以用来存储Docker应用的数据,也可以用来在Docke ...

  10. Note -「数论 定理及结论整合」

    数学素养 low,表达可能存在不严谨,见谅.我准备慢慢补上证明? Theorems. 裴蜀定理:关于 \(x, y\) 的线性方程 \(ax + by = c\) 有解,当且仅当 \(\gcd (a, ...