<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blazor &#8211; 岁月细碎点滴快查</title>
	<atom:link href="https://blog.mutadecheng.com/category/blazor/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.mutadecheng.com</link>
	<description></description>
	<lastBuildDate>Wed, 31 Dec 2025 00:58:56 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>
	<item>
		<title>Blazor项目编译Docker问题汇总</title>
		<link>https://blog.mutadecheng.com/2025/10/25/blazor%e9%a1%b9%e7%9b%ae%e7%bc%96%e8%af%91docker%e9%97%ae%e9%a2%98%e6%b1%87%e6%80%bb/</link>
					<comments>https://blog.mutadecheng.com/2025/10/25/blazor%e9%a1%b9%e7%9b%ae%e7%bc%96%e8%af%91docker%e9%97%ae%e9%a2%98%e6%b1%87%e6%80%bb/#respond</comments>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Sat, 25 Oct 2025 08:12:55 +0000</pubDate>
				<category><![CDATA[Blazor]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[编程疑难杂症]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=403</guid>

					<description><![CDATA[1.Debug可以但是编译时候报语法错误找不到某些函数 答: 有概率是window下blazor文件格式不对, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<ul class="wp-block-list"></ul>



<h2 class="wp-block-heading">1.Debug可以但是编译时候报语法错误找不到某些函数</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="error CS0103: The name 'xxx' does not exist in the current context
error CS1002: ; expected
error CS1513: } expected
error: File not found
error: Invalid character in source file" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #DCDCAA">error</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">CS0103:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">The</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">name</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;xxx&#39;</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">does</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">not</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">exist</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">in</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">the</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">current</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">context</span></span>
<span class="line"><span style="color: #DCDCAA">error</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">CS1002:</span><span style="color: #D4D4D4"> ; </span><span style="color: #DCDCAA">expected</span></span>
<span class="line"><span style="color: #DCDCAA">error</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">CS1513:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">}</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">expected</span></span>
<span class="line"><span style="color: #DCDCAA">error:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">File</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">not</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">found</span></span>
<span class="line"><span style="color: #DCDCAA">error:</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Invalid</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">character</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">in</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">source</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">file</span></span></code></pre></div>



<p>答: 有概率是window下blazor文件格式不对,主要体现在<strong>换行符格式</strong>（Windows是CRLF，Linux是LF）导致编译/语法错误、找不到某些函数等异常, 需要<strong>统一格式和编码</strong></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.mutadecheng.com/2025/10/25/blazor%e9%a1%b9%e7%9b%ae%e7%bc%96%e8%af%91docker%e9%97%ae%e9%a2%98%e6%b1%87%e6%80%bb/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Arm 搭建一套传感器采集系统(基于docker)</title>
		<link>https://blog.mutadecheng.com/2025/09/11/arm-%e6%90%ad%e5%bb%ba%e4%b8%80%e5%a5%97%e4%bc%a0%e6%84%9f%e5%99%a8%e9%87%87%e9%9b%86%e7%b3%bb%e7%bb%9f%e5%9f%ba%e4%ba%8edocker/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Thu, 11 Sep 2025 07:28:57 +0000</pubDate>
				<category><![CDATA[Arm]]></category>
		<category><![CDATA[Blazor]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Iot]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[前端]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=362</guid>

					<description><![CDATA[架构: 数据库: questdb 前端:blazor server 后端:c#控制台(hostserver)  [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>架构:</p>



<p>数据库: questdb</p>



<p>前端:blazor server</p>



<p>后端:c#控制台(hostserver)</p>



<p>平台运维:portainer</p>



<p>容器管理</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="# 国外
docker run -d -p 9000:9000 \
  --name portainer \
  --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:alpine-sts
  
# 国内(Arm64)
docker run -d -p 9000:9000 \
  --name portainer \
  --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  registry.cn-beijing.aliyuncs.com/muta/portainer-ce:alpine-sts-arm64

# 国内(Amd64)
docker run -d -p 9000:9000 \
  --name portainer \
  --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  registry.cn-beijing.aliyuncs.com/muta/portainer-ce:alpine-sts-amd64" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955"># 国外</span></span>
<span class="line"><span style="color: #DCDCAA">docker</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-d</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">9000</span><span style="color: #CE9178">:9000</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">--name</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">portainer</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">--restart=always</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-v</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">/var/run/docker.sock:/var/run/docker.sock</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-v</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">portainer_data:/data</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #CE9178">portainer/portainer-ce:alpine-sts</span></span>
<span class="line"><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #6A9955"># 国内(Arm64)</span></span>
<span class="line"><span style="color: #DCDCAA">docker</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-d</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">9000</span><span style="color: #CE9178">:9000</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">--name</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">portainer</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">--restart=always</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-v</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">/var/run/docker.sock:/var/run/docker.sock</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-v</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">portainer_data:/data</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #CE9178">registry.cn-beijing.aliyuncs.com/muta/portainer-ce:alpine-sts-arm64</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># 国内(Amd64)</span></span>
<span class="line"><span style="color: #DCDCAA">docker</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-d</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">9000</span><span style="color: #CE9178">:9000</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">--name</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">portainer</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">--restart=always</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-v</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">/var/run/docker.sock:/var/run/docker.sock</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-v</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">portainer_data:/data</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #CE9178">registry.cn-beijing.aliyuncs.com/muta/portainer-ce:alpine-sts-amd64</span></span></code></pre></div>



<p>数据库安装</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="# 国外
docker run -d \
  --name questdb \
  -p 8812:8812 \
  -p 9080:9000 \
  -p 9009:9009 \
  -v questdb_data:/root/.questdb/db \
  questdb/questdb:nightly-rhel
  
# 国内(Arm64)
docker run -d \
  --name questdb \
  -p 8812:8812 \
  -p 9080:9000 \
  -p 9009:9009 \
  -v questdb_data:/root/.questdb/db \
  registry.cn-beijing.aliyuncs.com/muta/questdb:nightly-rhel-arm64

# 国内(Amd64)
docker run -d \
  --name questdb \
  -p 8812:8812 \
  -p 9080:9000 \
  -p 9009:9009 \
  -v questdb_data:/root/.questdb/db \
  registry.cn-beijing.aliyuncs.com/muta/questdb:nightly-rhel-amd64
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955"># 国外</span></span>
<span class="line"><span style="color: #DCDCAA">docker</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-d</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">--name</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">questdb</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">8812</span><span style="color: #CE9178">:8812</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">9080</span><span style="color: #CE9178">:9000</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">9009</span><span style="color: #CE9178">:9009</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-v</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">questdb_data:/root/.questdb/db</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #CE9178">questdb/questdb:nightly-rhel</span></span>
<span class="line"><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #6A9955"># 国内(Arm64)</span></span>
<span class="line"><span style="color: #DCDCAA">docker</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-d</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">--name</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">questdb</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">8812</span><span style="color: #CE9178">:8812</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">9080</span><span style="color: #CE9178">:9000</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">9009</span><span style="color: #CE9178">:9009</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-v</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">questdb_data:/root/.questdb/db</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #CE9178">registry.cn-beijing.aliyuncs.com/muta/questdb:nightly-rhel-arm64</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># 国内(Amd64)</span></span>
<span class="line"><span style="color: #DCDCAA">docker</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">run</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-d</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">--name</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">questdb</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">8812</span><span style="color: #CE9178">:8812</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">9080</span><span style="color: #CE9178">:9000</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-p</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">9009</span><span style="color: #CE9178">:9009</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">-v</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">questdb_data:/root/.questdb/db</span><span style="color: #D4D4D4"> </span><span style="color: #D7BA7D">\</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #CE9178">registry.cn-beijing.aliyuncs.com/muta/questdb:nightly-rhel-amd64</span></span>
<span class="line"></span></code></pre></div>



<p>rabbitmq</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="version: '3.8'

services:
  mq:
    image: registry.cn-beijing.aliyuncs.com/muta/rabbitmq:management-arm64 
    restart: always 
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq    # 持久化RabbitMQ数据
    ports:
      - &quot;5672:5672&quot;                        # AMQP协议端口，应用程序连接用
      - &quot;15672:15672&quot;                      # 管理后台端口，Web管理界面用
      # 以下端口仅在集群或特殊情况下需要，可选
      # - &quot;25672:25672&quot;                    # 节点间通信端口（集群用）
      # - &quot;4369:4369&quot;                      # Erlang节点发现端口（集群用）
    logging:
      driver: &quot;json-file&quot;
      options:
        max-size: &quot;100m&quot;
        max-file: &quot;3&quot; 

volumes:
  rabbitmq_data:                           # 定义持久化数据卷
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">version</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;3.8&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">services</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">mq</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">image</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">registry.cn-beijing.aliyuncs.com/muta/rabbitmq:management-arm64</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">restart</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">always</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">volumes</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">rabbitmq_data:/var/lib/rabbitmq</span><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># 持久化RabbitMQ数据</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">ports</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">&quot;5672:5672&quot;</span><span style="color: #D4D4D4">                        </span><span style="color: #6A9955"># AMQP协议端口，应用程序连接用</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">&quot;15672:15672&quot;</span><span style="color: #D4D4D4">                      </span><span style="color: #6A9955"># 管理后台端口，Web管理界面用</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #6A9955"># 以下端口仅在集群或特殊情况下需要，可选</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #6A9955"># - &quot;25672:25672&quot;                    # 节点间通信端口（集群用）</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #6A9955"># - &quot;4369:4369&quot;                      # Erlang节点发现端口（集群用）</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">logging</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">driver</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;json-file&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">options</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-size</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;100m&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-file</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;3&quot;</span><span style="color: #D4D4D4"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">volumes</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">rabbitmq_data</span><span style="color: #D4D4D4">:                           </span><span style="color: #6A9955"># 定义持久化数据卷</span></span>
<span class="line"></span></code></pre></div>



<p>采集程序(方案1)</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="version: '3.8'

services:
  armcollection2025masablazorapp:
    image: registry.cn-beijing.aliyuncs.com/dfzh/armcollection2025masablazorapp:latest
    ports:
      - &quot;20000:8080&quot;
    user: root
    devices:
      - /dev/ttyS3:/dev/ttyS3
    environment: 
      SqlSugar__1__ConnectionString: &quot;host=host.docker.internal;port=8812;username=admin;password=quest;database=qdb;ServerCompatibilityMode=NoTypeLoading;&quot;
    restart: always
    volumes: 
      - /home/orangepi/DataProtection-Keys/:/app/.aspnet/DataProtection-Keys
    logging:
      driver: &quot;json-file&quot;
      options:
        max-size: &quot;100m&quot;
        max-file: &quot;3&quot;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">version</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;3.8&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">services</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">armcollection2025masablazorapp</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">image</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">registry.cn-beijing.aliyuncs.com/dfzh/armcollection2025masablazorapp:latest</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">ports</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">&quot;20000:8080&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">user</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">root</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">devices</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">/dev/ttyS3:/dev/ttyS3</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">environment</span><span style="color: #D4D4D4">: </span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">SqlSugar__1__ConnectionString</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;host=host.docker.internal;port=8812;username=admin;password=quest;database=qdb;ServerCompatibilityMode=NoTypeLoading;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">restart</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">always</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">volumes</span><span style="color: #D4D4D4">: </span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">/home/orangepi/DataProtection-Keys/:/app/.aspnet/DataProtection-Keys</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">logging</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">driver</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;json-file&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">options</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-size</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;100m&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-file</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;3&quot;</span></span></code></pre></div>



<p>采集程序(方案2)</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="version: '3.8'

services:
  app:
    image: registry.cn-beijing.aliyuncs.com/dfzh/armcollectblazorapp:latest
    network_mode: &quot;host&quot; 
    environment:  
      Urls: &quot;http://*:20000&quot;
    restart: always 
    logging:
      driver: &quot;json-file&quot;
      options:
        max-size: &quot;100m&quot;
        max-file: &quot;3&quot;
        
  serialport2questdb:
    image: registry.cn-beijing.aliyuncs.com/dfzh/armcollectserialport2questdb:latest
    network_mode: &quot;host&quot; 
    user: root
    devices:
      - /dev/ttyS3:/dev/ttyS3
    environment:  
      ComPortName : &quot;/dev/ttyS3&quot;
      Urls: &quot;http://*:20002&quot; 
    restart: always 
    logging:
      driver: &quot;json-file&quot;
      options:
        max-size: &quot;100m&quot;
        max-file: &quot;3&quot;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">version</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;3.8&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">services</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">app</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">image</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">registry.cn-beijing.aliyuncs.com/dfzh/armcollectblazorapp:latest</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">network_mode</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;host&quot;</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">environment</span><span style="color: #D4D4D4">:  </span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">Urls</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;http://*:20000&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">restart</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">always</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">logging</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">driver</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;json-file&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">options</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-size</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;100m&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-file</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;3&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">serialport2questdb</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">image</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">registry.cn-beijing.aliyuncs.com/dfzh/armcollectserialport2questdb:latest</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">network_mode</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;host&quot;</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">user</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">root</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">devices</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">/dev/ttyS3:/dev/ttyS3</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">environment</span><span style="color: #D4D4D4">:  </span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">ComPortName</span><span style="color: #D4D4D4"> : </span><span style="color: #CE9178">&quot;/dev/ttyS3&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">Urls</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;http://*:20002&quot;</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">restart</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">always</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">logging</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">driver</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;json-file&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">options</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-size</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;100m&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-file</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;3&quot;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="version: '3.8'

services:
  app:
    image: registry.cn-beijing.aliyuncs.com/dfzh/staticforcecalibration-blazorserver:arm64
    restart: always 
    volumes:
      - /home/bjgrst/staticforcecalibration_data:/app/App_Data     
      - /home/bjgrst/DefaultSeedsJsonFiles/:/app/DefaultSeedsJsonFiles
      - /dev:/dev
    ports:
      - &quot;8080:8080&quot;      
    user: root
    privileged: true
    logging:
      driver: &quot;json-file&quot;
      options:
        max-size: &quot;100m&quot;
        max-file: &quot;3&quot; 
 
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">version</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&#39;3.8&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">services</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #569CD6">app</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">image</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">registry.cn-beijing.aliyuncs.com/dfzh/staticforcecalibration-blazorserver:arm64</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">restart</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">always</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">volumes</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">/home/bjgrst/staticforcecalibration_data:/app/App_Data</span><span style="color: #D4D4D4">     </span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">/home/bjgrst/DefaultSeedsJsonFiles/:/app/DefaultSeedsJsonFiles</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">/dev:/dev</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">ports</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      - </span><span style="color: #CE9178">&quot;8080:8080&quot;</span><span style="color: #D4D4D4">      </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">user</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">root</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">privileged</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">logging</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">driver</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;json-file&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #569CD6">options</span><span style="color: #D4D4D4">:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-size</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;100m&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">max-file</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;3&quot;</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4"> </span></span>
<span class="line"></span></code></pre></div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Blazor 项目中集成 NPM 包与 TypeScript，并用 ESBuild 打包的实战与原理</title>
		<link>https://blog.mutadecheng.com/2025/07/14/blazor-%e9%a1%b9%e7%9b%ae%e4%b8%ad%e9%9b%86%e6%88%90-npm-%e5%8c%85%e4%b8%8e-typescript%ef%bc%8c%e5%b9%b6%e7%94%a8-esbuild-%e6%89%93%e5%8c%85%e7%9a%84%e5%ae%9e%e6%88%98%e4%b8%8e%e5%8e%9f%e7%90%86/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Mon, 14 Jul 2025 09:22:13 +0000</pubDate>
				<category><![CDATA[Blazor]]></category>
		<category><![CDATA[前端]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=339</guid>

					<description><![CDATA[一、ESM 与 UMD 模块格式的区别 现代 JavaScript 生态主要有两种流行的模块格式：ESM（EC [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">一、ESM 与 UMD 模块格式的区别</h3>



<p>现代 JavaScript 生态主要有两种流行的模块格式：ESM（ECMAScript Module）和 UMD（Universal Module Definition）。</p>



<h4 class="wp-block-heading">1. ESM（ECMAScript Module）</h4>



<ul class="wp-block-list">
<li>使用 <code>import</code> 和 <code>export</code> 关键字进行模块组织。</li>



<li>加载方式为静态加载，编译时即可确定依赖关系。</li>



<li>适用于现代浏览器和支持 ES Module 的 Node.js 版本。</li>



<li>支持 Tree Shaking，未被引用的代码可在打包时去除，减小体积。</li>



<li>依赖关系明确，易于优化和静态分析。</li>



<li>原生支持异步加载（浏览器端）。</li>



<li>常见扩展名为 <code>.mjs</code> 或 <code>.js</code>。</li>
</ul>



<p><strong>示例：</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="// a.js
export function foo() {}

// b.js
import { foo } from './a.js';" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// a.js</span></span>
<span class="line"><span style="color: #C586C0">export</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">foo</span><span style="color: #D4D4D4">() {}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// b.js</span></span>
<span class="line"><span style="color: #C586C0">import</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">foo</span><span style="color: #D4D4D4"> } </span><span style="color: #C586C0">from</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&#39;./a.js&#39;</span><span style="color: #D4D4D4">;</span></span></code></pre></div>



<h4 class="wp-block-heading">2. UMD（Universal Module Definition）</h4>



<ul class="wp-block-list">
<li>兼容 CommonJS、AMD 和浏览器全局变量等多种模块系统。</li>



<li>运行时自动判断当前环境（Node.js、浏览器、AMD）。</li>



<li>几乎可在所有 JS 环境下直接使用，包括老旧浏览器。</li>



<li>最大的优点是兼容性好，可以直接用 <code>&lt;script&gt;</code> 标签引入。</li>



<li>缺点是不能静态分析依赖，Tree Shaking 效果差，体积略大。</li>
</ul>



<p><strong>示例：</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="(function (root, factory) {
  if (typeof define === 'function' &amp;&amp; define.amd) {
    define([], factory);
  } else if (typeof module === 'object' &amp;&amp; module.exports) {
    module.exports = factory();
  } else {
    root.myLib = factory();
  }
}(this, function () {
  return {};
}));" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">(</span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">root</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">factory</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">typeof</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">define</span><span style="color: #D4D4D4"> === </span><span style="color: #CE9178">&#39;function&#39;</span><span style="color: #D4D4D4"> &amp;&amp; </span><span style="color: #9CDCFE">define</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">amd</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">define</span><span style="color: #D4D4D4">([], </span><span style="color: #9CDCFE">factory</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">  } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #569CD6">typeof</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">module</span><span style="color: #D4D4D4"> === </span><span style="color: #CE9178">&#39;object&#39;</span><span style="color: #D4D4D4"> &amp;&amp; </span><span style="color: #4EC9B0">module</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">exports</span><span style="color: #D4D4D4">) {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #4EC9B0">module</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">exports</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">factory</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">  } </span><span style="color: #C586C0">else</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">root</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">myLib</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">factory</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span>
<span class="line"><span style="color: #D4D4D4">}(</span><span style="color: #569CD6">this</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">function</span><span style="color: #D4D4D4"> () {</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> {};</span></span>
<span class="line"><span style="color: #D4D4D4">}));</span></span></code></pre></div>



<h4 class="wp-block-heading">3. 对比总结</h4>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>特点</th><th>ESM</th><th>UMD</th></tr></thead><tbody><tr><td>兼容性</td><td>现代浏览器/Node.js</td><td>各种环境（浏览器、Node等）</td></tr><tr><td>语法</td><td>import/export</td><td>兼容多种模块系统</td></tr><tr><td>Tree Shaking</td><td>支持</td><td>不支持</td></tr><tr><td>用途</td><td>新项目推荐</td><td>兼容老环境或全局变量场景</td></tr></tbody></table></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">二、Blazor 与 ESM/UMD 的集成限制</h3>



<p>Blazor 是微软推出的 Web 前端开发框架，支持 C# 编写客户端逻辑，分为 Blazor WebAssembly 和 Blazor Server 两种模式。Blazor 本身可以通过 JS interop 机制与 JavaScript 交互，但在集成现代 JS 库时存在以下局限：</p>



<h4 class="wp-block-heading">1. Blazor 的 JS 交互方式</h4>



<ul class="wp-block-list">
<li>只能通过 JS interop 调用全局作用域下的 JS 函数（即挂在 <code>window</code> 上的方法）。</li>



<li>无法直接使用 <code>import</code> 语法动态加载 ESM 模块（除非用 <code>&lt;script type="module"&gt;</code> 并手动挂载到 <code>window</code>）。</li>



<li>不能像 React/Vue 那样直接使用 NPM 包或通过模块系统自动管理依赖。</li>
</ul>



<h4 class="wp-block-heading">2. ESM/UMD 直接集成的障碍</h4>



<ul class="wp-block-list">
<li>ESM 格式的库必须通过 <code>import</code> 加载，Blazor 无法直接识别，也无法在 C# 代码中直接调用。</li>



<li>UMD 虽可全局挂载，但许多 UMD 库默认不会主动把 API 挂到 <code>window</code>，需要额外封装。</li>



<li>Blazor 的 JS interop 通信方式决定了只能通过全局对象与 JS 交互，无法像前端框架一样灵活集成 NPM 生态。</li>
</ul>



<h4 class="wp-block-heading">3. 正确的集成方式</h4>



<ul class="wp-block-list">
<li>手动引入 JS 文件：在 <code>wwwroot/index.html</code> 用 <code>&lt;script&gt;</code> 标签引入 UMD 格式库，并确保需要的 API 挂载到 <code>window</code>。</li>



<li>封装全局 JS 方法：写一段 JS 代码，把第三方库的核心方法挂到 <code>window</code>，便于 Blazor 调用。</li>



<li>如果必须使用 ESM，需用 <code>&lt;script type="module"&gt;</code> 并手动挂到 <code>window</code>，否则 Blazor 访问不到。</li>
</ul>



<p><strong>示例：</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="<script src=&quot;your-umd-lib.js&quot;&gt;</script&gt;
<script&gt;
  window.myLib = window.myLib || {}; // 确保全局可访问
</script&gt;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #808080">&lt;</span><span style="color: #569CD6">script</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">src</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;your-umd-lib.js&quot;</span><span style="color: #808080">&gt;&lt;/</span><span style="color: #569CD6">script</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #808080">&lt;</span><span style="color: #569CD6">script</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">window</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">myLib</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">window</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">myLib</span><span style="color: #D4D4D4"> || {}; </span><span style="color: #6A9955">// 确保全局可访问</span></span>
<span class="line"><span style="color: #808080">&lt;/</span><span style="color: #569CD6">script</span><span style="color: #808080">&gt;</span></span></code></pre></div>



<p>Blazor 代码则通过 JS interop 调用 <code>window.myLib.xxx</code> 方法。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">三、在 Blazor 中集成 NPM 包与 TypeScript 的现代实践</h3>



<p>面对 ESM/UMD 集成难题，推荐以下现代化方案：</p>



<div class="wp-block-visualize-mermaid"><pre class="visualizeMermaid__content js-visualize-content">上述</pre><pre class="visualizeMermaid__error visualizeMermaid__error--hidden js-visualize-error">Parse error on line 1:
上述
^
Expecting 'NEWLINE', 'SPACE', 'GRAPH', got 'UNICODE_TEXT'</pre><div class="visualizeMermaid__canvas"></div></div>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[开始：Blazor 项目] --> B[NPM 安装 esbuild 和所需 JS 库]
    B --> C[编写 TypeScript 文件&lt;br>（如 Scripts/components.ts）]
    C --> D[在 package.json 配置 esbuild 打包脚本]
    D --> E[运行 npm run debugBuild / releaseBuild]
    E --> F[esbuild 打包 TypeScript 和 NPM 依赖&lt;br>输出到 wwwroot/js/components.js]
    F --> G[Blazor 组件中通过 JS Interop 动态 import]
    G --> H[调用 JS 方法实现 C# 与 JS 互操作]
    H --> I[自动化集成到 .csproj 构建流程]
    I --> J[完成]
</pre></div>



<h4 class="wp-block-heading">1. 使用 ESBuild 编译 TypeScript 和打包 NPM 依赖</h4>



<div class="wp-block-visualize-mermaid"><pre class="visualizeMermaid__content js-visualize-content">的法国队</pre><pre class="visualizeMermaid__error visualizeMermaid__error--hidden js-visualize-error">Parse error on line 1:
的法国队
^
Expecting 'NEWLINE', 'SPACE', 'GRAPH', got 'UNICODE_TEXT'</pre><div class="visualizeMermaid__canvas"></div></div>



<ul class="wp-block-list">
<li>在项目根目录下用 NPM 安装 ESBuild 和所需的 JS 库。</li>



<li>在 <code>Scripts</code> 目录下编写 TypeScript 集成代码，导入 NPM 包并封装为供 Blazor 调用的全局方法。</li>



<li>在 <code>package.json</code> 配置 ESBuild 打包脚本，输出为 ESM 格式的单一 JS 文件到 <code>wwwroot/js</code>。</li>



<li>Blazor 组件通过 <code>IJSRuntime</code> 动态导入打包后的模块，直接调用自定义方法。</li>
</ul>



<p><strong>关键脚本示例：</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&quot;scripts&quot;: {
    &quot;debugBuild&quot;: &quot;esbuild ./Scripts/components.ts --format=esm --bundle --sourcemap --outdir=wwwroot/js&quot;,
    &quot;releaseBuild&quot;: &quot;esbuild ./Scripts/components.ts --format=esm --bundle --sourcemap --minify --outdir=wwwroot/js&quot;
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #CE9178">&quot;scripts&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;debugBuild&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;esbuild ./Scripts/components.ts --format=esm --bundle --sourcemap --outdir=wwwroot/js&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;releaseBuild&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;esbuild ./Scripts/components.ts --format=esm --bundle --sourcemap --minify --outdir=wwwroot/js&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h4 class="wp-block-heading">2. 自动化集成到 .NET 构建流程</h4>



<ul class="wp-block-list">
<li>在 <code>.csproj</code> 文件中添加 NPM 安装和打包任务，确保每次 <code>dotnet build</code> 或 <code>dotnet run</code> 时自动完成依赖安装和打包。</li>
</ul>



<p><strong>示例：</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="<Target Name=&quot;NPM Install&quot; AfterTargets=&quot;PreBuildEvent&quot;&gt;
    <Exec Command=&quot;npm install&quot; /&gt;
</Target&gt;
<Target Name=&quot;NPM Debug Build&quot; AfterTargets=&quot;NPM Install&quot; Condition=&quot;$(Configuration) == 'DEBUG'&quot;&gt;
    <Exec Command=&quot;npm run debugBuild&quot; /&gt;
</Target&gt;
<Target Name=&quot;NPM Release Build&quot; AfterTargets=&quot;NPM Install&quot; Condition=&quot;$(Configuration) == 'RELEASE'&quot;&gt;
    <Exec Command=&quot;npm run releaseBuild&quot; /&gt;
</Target&gt;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">Target</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;NPM Install&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">AfterTargets</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;PreBuildEvent&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #9CDCFE">Exec</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Command</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;npm install&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">Target</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">Target</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;NPM Debug Build&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">AfterTargets</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;NPM Install&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Condition</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;$(Configuration) == &#39;DEBUG&#39;&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #9CDCFE">Exec</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Command</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;npm run debugBuild&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">Target</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">Target</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;NPM Release Build&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">AfterTargets</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;NPM Install&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Condition</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;$(Configuration) == &#39;RELEASE&#39;&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #9CDCFE">Exec</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Command</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;npm run releaseBuild&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">Target</span><span style="color: #D4D4D4">&gt;</span></span></code></pre></div>



<h4 class="wp-block-heading">3. Blazor 组件调用方式</h4>



<ul class="wp-block-list">
<li>通过 <code>IJSRuntime.InvokeAsync&lt;IJSObjectReference&gt;("import", "./js/components.js")</code> 动态加载模块。</li>



<li>直接调用打包后暴露的 JS 方法，实现 C# 与 JS 的高效互操作。</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">四、总结</h3>



<p>ESM 格式适合现代前端开发，支持静态分析和 Tree Shaking，但不支持直接在 Blazor 中模块化调用。UMD 格式兼容性强，可通过全局变量方式间接集成到 Blazor，但需要手动挂载 API。通过引入 ESBuild 工具，将 TypeScript 和所有 NPM 依赖打包为适合 Blazor 动态加载的 ESM 文件，并结合 JS interop 机制，Blazor 项目能够高效利用现代 JavaScript 生态，实现类型安全、依赖清晰的前后端集成开发。</p>



<h3 class="wp-block-heading">五、引用资料</h3>



<p>1.博客:<a href="https://blog.dymaptic.com/using-esbuild-with-blazor">Using ESBuild with Blazor</a></p>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Blazor 之 [Parameter] 和 @bind- 用法区别</title>
		<link>https://blog.mutadecheng.com/2025/04/25/blazor-%e4%b9%8b-parameter-%e5%92%8c-bind-%e7%94%a8%e6%b3%95%e5%8c%ba%e5%88%ab/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Fri, 25 Apr 2025 03:20:37 +0000</pubDate>
				<category><![CDATA[Blazor]]></category>
		<category><![CDATA[c#]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=325</guid>

					<description><![CDATA[在 C# Blazor 中，[Parameter] 和 @bind- 是用于不同目的的特性和绑定机制。它们在组 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>在 C# Blazor 中，<code>[Parameter]</code> 和 <code>@bind-</code> 是用于不同目的的特性和绑定机制。它们在组件之间传递数据时扮演不同的角色。下面是它们的区别和用法：</p>



<h3 class="wp-block-heading"><code>[Parameter]</code></h3>



<ol class="wp-block-list">
<li><strong>用途</strong>：<code>[Parameter]</code> 特性用于定义一个组件的参数。它允许父组件向子组件传递数据。</li>



<li><strong>用法</strong>：在子组件中，你可以通过在属性上使用 <code>[Parameter]</code> 特性来声明该属性是一个参数。例如：</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="   public class MyComponent : ComponentBase
   {
       [Parameter]
       public string Title { get; set; }
   }" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">   </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">MyComponent</span><span style="color: #D4D4D4"> : </span><span style="color: #4EC9B0">ComponentBase</span></span>
<span class="line"><span style="color: #D4D4D4">   {</span></span>
<span class="line"><span style="color: #D4D4D4">       [</span><span style="color: #4EC9B0">Parameter</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">       </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Title</span><span style="color: #D4D4D4"> { </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4">; </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">   }</span></span></code></pre></div>



<ol start="3" class="wp-block-list">
<li><strong>数据流向</strong>：数据流是<strong><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">单向的</mark></strong>，即从父组件流向子组件。父组件可以设置子组件的参数值，但子组件不能直接修改父组件的数据。</li>



<li><strong>示例</strong>：在父组件中使用子组件时，可以这样传递参数：</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="   <MyComponent Title=&quot;Hello, World!&quot; /&gt;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">   &lt;</span><span style="color: #4EC9B0">MyComponent</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Title</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Hello, World!&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span></code></pre></div>



<h3 class="wp-block-heading"><code>@bind-</code></h3>



<ol class="wp-block-list">
<li><strong>用途</strong>：<code>@bind-</code> 是用于<strong><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">双向数据绑定</mark></strong>的语法糖。它允许在组件和其属性之间进行双向数据绑定。</li>



<li><strong>用法</strong>：<code>@bind-</code> 通常用于绑定输入控件的值，使得控件的值和组件的属性保持同步。例如：</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="   <input @bind-Value=&quot;name&quot; /&gt;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">   &lt;</span><span style="color: #9CDCFE">input</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">@bind</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">Value</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;name&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span></code></pre></div>



<p>这里，<code>name</code> 是一个组件中的属性，<code>@bind-Value</code> 会自动处理输入控件的 <code>value</code> 和 <code>onchange</code> 事件，以实现双向绑定。</p>



<ol start="3" class="wp-block-list">
<li><strong>数据流向</strong>：双向数据绑定意味着数据可以从组件流向控件，也可以从控件流回组件。</li>



<li><strong>示例</strong>：在组件中定义一个属性，然后在 Razor 页面中使用：</li>
</ol>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="   @code {
       private string name;
   }" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">   </span><span style="color: #9CDCFE">@code</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">       </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">   }</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="   <input @bind-Value=&quot;name&quot; /&gt;
   <p&gt;You entered: @name</p&gt;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">   &lt;</span><span style="color: #9CDCFE">input</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">@bind</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">Value</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;name&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">   &lt;</span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">You</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">entered</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">@name</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">&gt;</span></span></code></pre></div>



<h3 class="wp-block-heading">总结</h3>



<ul class="wp-block-list">
<li><code>[Parameter]</code> 用于定义组件的输入参数，数据流是单向的。</li>



<li><code>@bind-</code> 用于实现双向数据绑定，通常用于表单控件，使得控件的值和组件的属性保持同步。</li>
</ul>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Blazor示例 之 通用定时器 TimerComponent.razor</title>
		<link>https://blog.mutadecheng.com/2024/12/14/blazor%e7%a4%ba%e4%be%8b-%e4%b9%8b-%e9%80%9a%e7%94%a8%e5%ae%9a%e6%97%b6%e5%99%a8-timercomponent-razor/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Sat, 14 Dec 2024 07:59:19 +0000</pubDate>
				<category><![CDATA[Blazor]]></category>
		<category><![CDATA[c#]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=275</guid>

					<description><![CDATA[使用 TimerComponent 然后二次封装 调用,(这样linq在前端的,网络压力大,最好还是后端ser [&#8230;]]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="@implements IDisposable
@using System.Timers

@code {
    private Timer? _timer;
    [Parameter] public double Interval { get; set; } = 2000;
    [Parameter] public EventCallback&lt;ElapsedEventArgs&gt; OnElapsed { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        if (_timer == null)
        {
            _timer = new Timer
            {
                Interval = Interval
            };

            _timer.Elapsed += async (sender, args) =&gt; await OnElapsed.InvokeAsync(args);

            _timer.Start();
        }
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">@implements</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IDisposable</span></span>
<span class="line"><span style="color: #9CDCFE">@using</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">System</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Timers</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">@code</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Timer</span><span style="color: #D4D4D4">? </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #9CDCFE">Parameter</span><span style="color: #D4D4D4">] </span><span style="color: #9CDCFE">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">double</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Interval</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">get</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">set</span><span style="color: #D4D4D4">; } = </span><span style="color: #B5CEA8">2000</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #9CDCFE">Parameter</span><span style="color: #D4D4D4">] </span><span style="color: #9CDCFE">public</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">EventCallback</span><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">ElapsedEventArgs</span><span style="color: #D4D4D4">&gt; </span><span style="color: #9CDCFE">OnElapsed</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">get</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">protected</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">override</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">OnInitialized</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">base</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">OnInitialized</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4"> == </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Timer</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">Interval</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">Interval</span></span>
<span class="line"><span style="color: #D4D4D4">            };</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Elapsed</span><span style="color: #D4D4D4"> += </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">sender</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">args</span><span style="color: #D4D4D4">) =&gt; </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">OnElapsed</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">InvokeAsync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">args</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Start</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Dispose</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4">?.</span><span style="color: #DCDCAA">Dispose</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">使用 TimerComponent</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="@page &quot;/example&quot;
@inject SensorParamService sensorParamService

&lt;TimerComponent Interval=&quot;2000&quot; OnElapsed=&quot;TimerOnElapsed&quot; /&gt;

&lt;MECharts Option=&quot;_option&quot; Height=&quot;400&quot; IncludeFunctionsInOption&gt;&lt;/MECharts&gt;

@code {
    private object _option = GenOption(0);

    private void TimerOnElapsed(ElapsedEventArgs e)
    {
        InvokeAsync(() =&gt;
        {
            var res = sensorParamService.SensorParamDic.FirstOrDefault(it =&gt; it.Value.Name == &quot;电器房_风向&quot;);
            _option = GenOption(res.Value.DiffValue);
            StateHasChanged();
        });
    }

    private static object GenOption(double value)
    {
        return new
        {
            Tooltip = new
            {
                Formatter = &quot;{a} &lt;br/&gt;{b}: {c}°&quot;
            },
            Series = new[]
            {
                new
                {
                    Name = &quot;风向&quot;,
                    Type = &quot;gauge&quot;,
                    StartAngle = 90,
                    EndAngle = -269.9999,
                    AxisLine = new
                    {
                        LineStyle = new
                        {
                            Width = 10
                        }
                    },
                    Pointer = new
                    {
                        Length = &quot;70%&quot;,
                        Width = 6
                    },
                    SplitLine = new
                    {
                        Length = 15,
                        LineStyle = new
                        {
                            Width = 2
                        }
                    },
                    AxisLabel = new
                    {
                        Distance = 20,
                        Formatter = &quot;(value) =&gt; { const directions = ['北', '东北', '东', '东南', '南', '西南', '西', '西北']; return directions[Math.floor(value / 45) % 8]; }&quot;
                    },
                    AxisTick = new
                    {
                        SplitNumber = 4
                    },
                    Detail = new
                    {
                        Formatter = &quot;{value}°&quot;
                    },
                    Data = new[]
                    {
                        new { Value = value, Name = &quot;风向&quot; }
                    }
                }
            }
        };
    }
}
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">@page</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;/example&quot;</span></span>
<span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">SensorParamService</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sensorParamService</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">TimerComponent</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Interval</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;2000&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">OnElapsed</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;TimerOnElapsed&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">MECharts</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Option</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;_option&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Height</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;400&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IncludeFunctionsInOption</span><span style="color: #D4D4D4">&gt;&lt;/</span><span style="color: #9CDCFE">MECharts</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">@code</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">object</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_option</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">GenOption</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">TimerOnElapsed</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ElapsedEventArgs</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">e</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">InvokeAsync</span><span style="color: #D4D4D4">(() =&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">res</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">sensorParamService</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">SensorParamDic</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">FirstOrDefault</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">it</span><span style="color: #D4D4D4"> =&gt; </span><span style="color: #9CDCFE">it</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Value</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4"> == </span><span style="color: #CE9178">&quot;电器房_风向&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">_option</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">GenOption</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">res</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Value</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">DiffValue</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">StateHasChanged</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">static</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">object</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">GenOption</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">double</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">Tooltip</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">Formatter</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;{a} &lt;br/&gt;{b}: {c}°&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">            },</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">Series</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4">[]</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                {</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;风向&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Type</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;gauge&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">StartAngle</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">90</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">EndAngle</span><span style="color: #D4D4D4"> = -</span><span style="color: #B5CEA8">269.9999</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">AxisLine</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">LineStyle</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                        {</span></span>
<span class="line"><span style="color: #D4D4D4">                            </span><span style="color: #9CDCFE">Width</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">10</span></span>
<span class="line"><span style="color: #D4D4D4">                        }</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Pointer</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Length</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;70%&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Width</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">6</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">SplitLine</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Length</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">15</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">LineStyle</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                        {</span></span>
<span class="line"><span style="color: #D4D4D4">                            </span><span style="color: #9CDCFE">Width</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">2</span></span>
<span class="line"><span style="color: #D4D4D4">                        }</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">AxisLabel</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Distance</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Formatter</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;(value) =&gt; { const directions = [&#39;北&#39;, &#39;东北&#39;, &#39;东&#39;, &#39;东南&#39;, &#39;南&#39;, &#39;西南&#39;, &#39;西&#39;, &#39;西北&#39;]; return directions[Math.floor(value / 45) % 8]; }&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">AxisTick</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">SplitNumber</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">4</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Detail</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Formatter</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;{value}°&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Data</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4">[]</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">Value</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;风向&quot;</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">                    }</span></span>
<span class="line"><span style="color: #D4D4D4">                }</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">        };</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">然后二次封装</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="@inject SensorParamService SensorParamService
@implements IDisposable
@using System.Timers

@code {
    private Timer? _timer;
    [Parameter] public double Interval { get; set; } = 2000;
    [Parameter] public Func&lt;IDictionary&lt;string, SensorParam&gt;, IEnumerable&lt;SensorParam&gt;&gt; QueryExpression { get; set; }
    [Parameter] public EventCallback&lt;IEnumerable&lt;SensorParam&gt;&gt; OnDataFetched { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        if (_timer == null)
        {
            _timer = new Timer
            {
                Interval = Interval
            };

            _timer.Elapsed += async (sender, args) =&gt; await FetchData();

            _timer.Start();
        }
    }

    private async Task FetchData()
    {
        var results = QueryExpression(SensorParamService.SensorParamDic);
        await InvokeAsync(() =&gt; OnDataFetched.InvokeAsync(results));
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">SensorParamService</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">SensorParamService</span></span>
<span class="line"><span style="color: #9CDCFE">@implements</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IDisposable</span></span>
<span class="line"><span style="color: #9CDCFE">@using</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">System</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Timers</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">@code</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Timer</span><span style="color: #D4D4D4">? </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #9CDCFE">Parameter</span><span style="color: #D4D4D4">] </span><span style="color: #9CDCFE">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">double</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Interval</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">get</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">set</span><span style="color: #D4D4D4">; } = </span><span style="color: #B5CEA8">2000</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #9CDCFE">Parameter</span><span style="color: #D4D4D4">] </span><span style="color: #9CDCFE">public</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Func</span><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">IDictionary</span><span style="color: #D4D4D4">&lt;</span><span style="color: #569CD6">string</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">SensorParam</span><span style="color: #D4D4D4">&gt;, </span><span style="color: #9CDCFE">IEnumerable</span><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">SensorParam</span><span style="color: #D4D4D4">&gt;&gt; </span><span style="color: #9CDCFE">QueryExpression</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">get</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #9CDCFE">Parameter</span><span style="color: #D4D4D4">] </span><span style="color: #9CDCFE">public</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">EventCallback</span><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">IEnumerable</span><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">SensorParam</span><span style="color: #D4D4D4">&gt;&gt; </span><span style="color: #9CDCFE">OnDataFetched</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">get</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">protected</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">override</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">OnInitialized</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">base</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">OnInitialized</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4"> == </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Timer</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">Interval</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">Interval</span></span>
<span class="line"><span style="color: #D4D4D4">            };</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Elapsed</span><span style="color: #D4D4D4"> += </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">sender</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">args</span><span style="color: #D4D4D4">) =&gt; </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">FetchData</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Start</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Task</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">FetchData</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">results</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">QueryExpression</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">SensorParamService</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">SensorParamDic</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">InvokeAsync</span><span style="color: #D4D4D4">(() =&gt; </span><span style="color: #9CDCFE">OnDataFetched</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">InvokeAsync</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">results</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Dispose</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">_timer</span><span style="color: #D4D4D4">?.</span><span style="color: #DCDCAA">Dispose</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p>调用,(这样linq在前端的,网络压力大,最好还是后端servser有委托方法)</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="@page &quot;/example&quot;

&lt;TimerComponent Interval=&quot;2000&quot; 
                QueryExpression=&quot;GetSensorParams&quot; 
                OnDataFetched=&quot;HandleDataFetched&quot; /&gt;

&lt;MECharts Option=&quot;_option&quot; Height=&quot;400&quot; IncludeFunctionsInOption&gt;&lt;/MECharts&gt;

@code {
    private object _option = GenOption(0);

    private IEnumerable&lt;SensorParam&gt; GetSensorParams(IDictionary&lt;string, SensorParam&gt; sensorParamDic)
    {
        // 完整的 LINQ 查询逻辑在这里定义
        return sensorParamDic.Values.Where(it =&gt; it.Name.Contains(&quot;风向&quot;));
    }

    private void HandleDataFetched(IEnumerable&lt;SensorParam&gt; sensorParams)
    {
        InvokeAsync(() =&gt;
        {
            // 处理多个传感器参数，例如更新图表数据
            var firstParam = sensorParams.FirstOrDefault();
            if (firstParam != null)
            {
                _option = GenOption(firstParam.DiffValue);
            }
            else
            {
                // 处理结果为空的情况
                Console.WriteLine(&quot;未找到匹配的传感器参数。&quot;);
            }
            StateHasChanged();
        });
    }

    private static object GenOption(double value)
    {
        return new
        {
            Tooltip = new
            {
                Formatter = &quot;{a} &lt;br/&gt;{b}: {c}°&quot;
            },
            Series = new[]
            {
                new
                {
                    Name = &quot;风向&quot;,
                    Type = &quot;gauge&quot;,
                    StartAngle = 90,
                    EndAngle = -269.9999,
                    AxisLine = new
                    {
                        LineStyle = new
                        {
                            Width = 10
                        }
                    },
                    Pointer = new
                    {
                        Length = &quot;70%&quot;,
                        Width = 6
                    },
                    SplitLine = new
                    {
                        Length = 15,
                        LineStyle = new
                        {
                            Width = 2
                        }
                    },
                    AxisLabel = new
                    {
                        Distance = 20,
                        Formatter = &quot;(value) =&gt; { const directions = ['北', '东北', '东', '东南', '南', '西南', '西', '西北']; return directions[Math.floor(value / 45) % 8]; }&quot;
                    },
                    AxisTick = new
                    {
                        SplitNumber = 4
                    },
                    Detail = new
                    {
                        Formatter = &quot;{value}°&quot;
                    },
                    Data = new[]
                    {
                        new { Value = value, Name = &quot;风向&quot; }
                    }
                }
            }
        };
    }
}
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">@page</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;/example&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">TimerComponent</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Interval</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;2000&quot;</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">QueryExpression</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;GetSensorParams&quot;</span><span style="color: #D4D4D4"> </span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">OnDataFetched</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;HandleDataFetched&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">MECharts</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Option</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;_option&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Height</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;400&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IncludeFunctionsInOption</span><span style="color: #D4D4D4">&gt;&lt;/</span><span style="color: #9CDCFE">MECharts</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">@code</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">object</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_option</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">GenOption</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IEnumerable</span><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">SensorParam</span><span style="color: #D4D4D4">&gt; </span><span style="color: #DCDCAA">GetSensorParams</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">IDictionary</span><span style="color: #D4D4D4">&lt;</span><span style="color: #569CD6">string</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">SensorParam</span><span style="color: #D4D4D4">&gt; </span><span style="color: #9CDCFE">sensorParamDic</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #6A9955">        // 完整的 LINQ 查询逻辑在这里定义</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sensorParamDic</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Values</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Where</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">it</span><span style="color: #D4D4D4"> =&gt; </span><span style="color: #9CDCFE">it</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Contains</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;风向&quot;</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">HandleDataFetched</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">IEnumerable</span><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">SensorParam</span><span style="color: #D4D4D4">&gt; </span><span style="color: #9CDCFE">sensorParams</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">InvokeAsync</span><span style="color: #D4D4D4">(() =&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #6A9955">            // 处理多个传感器参数，例如更新图表数据</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">firstParam</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">sensorParams</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">FirstOrDefault</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">firstParam</span><span style="color: #D4D4D4"> != </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">_option</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">GenOption</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">firstParam</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">DiffValue</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">else</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #6A9955">                // 处理结果为空的情况</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">Console</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">WriteLine</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;未找到匹配的传感器参数。&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">StateHasChanged</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">        });</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">static</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">object</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">GenOption</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">double</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">Tooltip</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">Formatter</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;{a} &lt;br/&gt;{b}: {c}°&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">            },</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">Series</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4">[]</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                {</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;风向&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Type</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;gauge&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">StartAngle</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">90</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">EndAngle</span><span style="color: #D4D4D4"> = -</span><span style="color: #B5CEA8">269.9999</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">AxisLine</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">LineStyle</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                        {</span></span>
<span class="line"><span style="color: #D4D4D4">                            </span><span style="color: #9CDCFE">Width</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">10</span></span>
<span class="line"><span style="color: #D4D4D4">                        }</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Pointer</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Length</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;70%&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Width</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">6</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">SplitLine</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Length</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">15</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">LineStyle</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                        {</span></span>
<span class="line"><span style="color: #D4D4D4">                            </span><span style="color: #9CDCFE">Width</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">2</span></span>
<span class="line"><span style="color: #D4D4D4">                        }</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">AxisLabel</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Distance</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">20</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Formatter</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;(value) =&gt; { const directions = [&#39;北&#39;, &#39;东北&#39;, &#39;东&#39;, &#39;东南&#39;, &#39;南&#39;, &#39;西南&#39;, &#39;西&#39;, &#39;西北&#39;]; return directions[Math.floor(value / 45) % 8]; }&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">AxisTick</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">SplitNumber</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">4</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Detail</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #9CDCFE">Formatter</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;{value}°&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">                    },</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">Data</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4">[]</span></span>
<span class="line"><span style="color: #D4D4D4">                    {</span></span>
<span class="line"><span style="color: #D4D4D4">                        </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">Value</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;风向&quot;</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">                    }</span></span>
<span class="line"><span style="color: #D4D4D4">                }</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">        };</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span>
<span class="line"></span></code></pre></div>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Blazor Server 前后端不分离项目简单身份验证</title>
		<link>https://blog.mutadecheng.com/2024/10/25/blazor-server-%e5%89%8d%e5%90%8e%e7%ab%af%e4%b8%8d%e5%88%86%e7%a6%bb%e9%a1%b9%e7%9b%ae%e7%ae%80%e5%8d%95%e8%ba%ab%e4%bb%bd%e9%aa%8c%e8%af%81/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Fri, 25 Oct 2024 03:37:17 +0000</pubDate>
				<category><![CDATA[Blazor]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[身份验证与授权]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=239</guid>

					<description><![CDATA[此基于Blazor Server 应用通过使用 SignalR 创建的实时连接运行。建立连接时，将处理基于 S [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>此基于Blazor Server 应用通过使用 SignalR 创建的实时连接运行。建立连接时，将处理基于 SignalR 的应用中的身份验证。身份验证可以基于 Cookie 或其他一些不记名令牌。Blazor Server 应用的安全性配置方式与 ASP.NET Core 应用相同。</p>



<p>Blazor Server 应用的内置 AuthenticationStateProvider 服务从 ASP.NET Core 的 HttpContext.User 获取身份验证状态数据。这就是身份验证状态与现有 ASP.NET Core 身份验证机制集成的方式</p>



<h3 class="wp-block-heading">项目结构</h3>



<ol class="wp-block-list">
<li><strong>解决方案</strong>
<ul class="wp-block-list">
<li><code>MyBlazorApp.sln</code></li>
</ul>
</li>



<li><strong>Blazor Server项目</strong>
<ul class="wp-block-list">
<li><code>MyBlazorApp</code> (Blazor Server项目)</li>



<li><code>Pages/</code> &#8211; 包含所有的页面组件（<code>*.razor</code>）</li>



<li><code>Components/</code> &#8211; 可复用的UI组件</li>



<li><code>Authentication/</code> &#8211; 身份验证服务相关文件夹
<ul class="wp-block-list">
<li><code>CustomAuthenticationStateProvider.cs/</code> &#8211; 自定义的认证状态提供器类</li>



<li><code>UserAccount.cs/</code> &#8211; 用户Dto</li>



<li><code>UserAccountService.cs/</code> &#8211; 用户服务</li>



<li><code>UserSession.cs/</code> &#8211; 用户的会话信息</li>
</ul>
</li>



<li><code>Shared/</code> &#8211; 前后端共享的组件或代码</li>



<li><code>Data/</code> &#8211; 数据访问层和业务逻辑</li>



<li><code>Models/</code> &#8211; 数据模型</li>



<li><code>wwwroot/</code> &#8211; 静态文件，如CSS、JavaScript和图像</li>



<li><code>Program.cs</code> &#8211; 配置Blazor Server应用程序的启动</li>



<li><code>Startup.cs</code> &#8211; 配置服务和中间件（如果使用Startup类）</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">详细说明</h3>



<ul class="wp-block-list">
<li><strong>Pages</strong>: 包含Blazor应用的页面，每个页面都由一个<code>.razor</code>文件组成。这些页面负责用户界面的展示和用户交互。</li>



<li><strong>Components</strong>: 存放可复用的UI组件，组件可以在多个页面中使用，帮助减少代码重复。</li>



<li><strong>Shared</strong>: 用于存放前后端共享的代码，如共享的组件或帮助类。</li>



<li><strong>Data</strong>: 负责数据访问和业务逻辑。可以在这里实现与数据库的交互逻辑（如使用Entity Framework Core），以及任何必要的业务规则。</li>



<li><strong>Models</strong>: 定义应用程序使用的数据模型。这些模型通常用于表示数据库中的实体或其他数据结构。</li>



<li><strong>wwwroot</strong>: 包含所有的静态资源，如CSS样式表、JavaScript文件和图像文件。Blazor Server会将这些文件直接提供给浏览器。</li>



<li><strong>Program.cs</strong>: 定义应用程序的入口点，配置服务（如依赖注入）和应用程序生命周期。</li>



<li><strong>Startup.cs</strong>: 配置应用程序的请求管道和服务（如果使用Startup类）。包括中间件配置、路由设置等。</li>
</ul>



<h3 class="wp-block-heading">身份验证详解</h3>



<p>Authentication/<code><strong>CustomAuthenticationStateProvider.cs</strong></code></p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="// 定义一个自定义的认证状态提供器类，继承自AuthenticationStateProvider
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
    // 使用ProtectedSessionStorage来安全地存储用户会话信息
    private readonly ProtectedSessionStorage _sessionStorage;
    // 定义一个匿名用户的ClaimsPrincipal对象，表示未认证的用户
    private ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity());

    // 构造函数，初始化会话存储对象
    public CustomAuthenticationStateProvider(ProtectedSessionStorage sessionStorage)
    {
        _sessionStorage = sessionStorage;
    }

    // 重写基类的GetAuthenticationStateAsync方法，用于获取当前用户的认证状态
    public override async Task&lt;AuthenticationState&gt; GetAuthenticationStateAsync()
    {
        try
        {
            // 从会话存储中异步获取用户会话信息
            var userSessionStorageResult = await _sessionStorage.GetAsync&lt;UserSession&gt;(&quot;UserSession&quot;);
            // 检查获取结果是否成功，如果成功则获取用户会话信息，否则为null
            var userSession = userSessionStorageResult.Success ? userSessionStorageResult.Value : null;

            // 如果用户会话信息为null，返回匿名用户的认证状态
            if (userSession == null)
                return await Task.FromResult(new AuthenticationState(_anonymous));

            // 如果用户会话信息存在，创建一个包含用户名和角色的ClaimsPrincipal对象
            var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List&lt;Claim&gt;
            {
                new Claim(ClaimTypes.Name, userSession.UserName), // 用户名声明
                new Claim(ClaimTypes.Role, userSession.Role) // 角色声明
            }, &quot;CustomAuth&quot;)); // 使用自定义认证类型

            // 返回包含用户信息的认证状态
            return await Task.FromResult(new AuthenticationState(claimsPrincipal));
        }
        catch
        {
            // 如果发生异常，返回匿名用户的认证状态
            return await Task.FromResult(new AuthenticationState(_anonymous));
        }
    }

    // 更新认证状态的方法，接收一个用户会话对象作为参数
    public async Task UpdateAuthenticationState(UserSession userSession)
    {
        ClaimsPrincipal claimsPrincipal;

        if (userSession != null)
        {
            // 如果用户会话信息不为null，将其存储到会话存储中
            await _sessionStorage.SetAsync(&quot;UserSession&quot;, userSession);
            // 创建包含用户名和角色的ClaimsPrincipal对象
            claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List&lt;Claim&gt;
            {
                new Claim(ClaimTypes.Name, userSession.UserName), // 用户名声明
                new Claim(ClaimTypes.Role, userSession.Role) // 角色声明
            }));
        }
        else
        {
            // 如果用户会话信息为null，删除存储的会话信息
            await _sessionStorage.DeleteAsync(&quot;UserSession&quot;);
            // 设置为匿名用户
            claimsPrincipal = _anonymous;
        }

        // 通知认证状态已更改，传递新的认证状态
        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(claimsPrincipal)));
    }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">// 定义一个自定义的认证状态提供器类，继承自AuthenticationStateProvider</span></span>
<span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">CustomAuthenticationStateProvider</span><span style="color: #D4D4D4"> : </span><span style="color: #4EC9B0">AuthenticationStateProvider</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #6A9955">    // 使用ProtectedSessionStorage来安全地存储用户会话信息</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">readonly</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ProtectedSessionStorage</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_sessionStorage</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #6A9955">    // 定义一个匿名用户的ClaimsPrincipal对象，表示未认证的用户</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">private</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ClaimsPrincipal</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_anonymous</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ClaimsPrincipal</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ClaimsIdentity</span><span style="color: #D4D4D4">());</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">    // 构造函数，初始化会话存储对象</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">CustomAuthenticationStateProvider</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">ProtectedSessionStorage</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sessionStorage</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">_sessionStorage</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">sessionStorage</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">    // 重写基类的GetAuthenticationStateAsync方法，用于获取当前用户的认证状态</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">override</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Task</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">AuthenticationState</span><span style="color: #D4D4D4">&gt; </span><span style="color: #DCDCAA">GetAuthenticationStateAsync</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">try</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #6A9955">            // 从会话存储中异步获取用户会话信息</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">userSessionStorageResult</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_sessionStorage</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetAsync</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">UserSession</span><span style="color: #D4D4D4">&gt;(</span><span style="color: #CE9178">&quot;UserSession&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #6A9955">            // 检查获取结果是否成功，如果成功则获取用户会话信息，否则为null</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">userSession</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">userSessionStorageResult</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Success</span><span style="color: #D4D4D4"> ? </span><span style="color: #9CDCFE">userSessionStorageResult</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Value</span><span style="color: #D4D4D4"> : </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">            // 如果用户会话信息为null，返回匿名用户的认证状态</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">userSession</span><span style="color: #D4D4D4"> == </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Task</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">FromResult</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">AuthenticationState</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">_anonymous</span><span style="color: #D4D4D4">));</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">            // 如果用户会话信息存在，创建一个包含用户名和角色的ClaimsPrincipal对象</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">claimsPrincipal</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ClaimsPrincipal</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ClaimsIdentity</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">List</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">Claim</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Claim</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ClaimTypes</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">userSession</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4">), </span><span style="color: #6A9955">// 用户名声明</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Claim</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ClaimTypes</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">userSession</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4">) </span><span style="color: #6A9955">// 角色声明</span></span>
<span class="line"><span style="color: #D4D4D4">            }, </span><span style="color: #CE9178">&quot;CustomAuth&quot;</span><span style="color: #D4D4D4">)); </span><span style="color: #6A9955">// 使用自定义认证类型</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">            // 返回包含用户信息的认证状态</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Task</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">FromResult</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">AuthenticationState</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">claimsPrincipal</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">catch</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #6A9955">            // 如果发生异常，返回匿名用户的认证状态</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Task</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">FromResult</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">AuthenticationState</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">_anonymous</span><span style="color: #D4D4D4">));</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">    // 更新认证状态的方法，接收一个用户会话对象作为参数</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Task</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">UpdateAuthenticationState</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">UserSession</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">userSession</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #4EC9B0">ClaimsPrincipal</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">claimsPrincipal</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">userSession</span><span style="color: #D4D4D4"> != </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #6A9955">            // 如果用户会话信息不为null，将其存储到会话存储中</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_sessionStorage</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">SetAsync</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;UserSession&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">userSession</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #6A9955">            // 创建包含用户名和角色的ClaimsPrincipal对象</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">claimsPrincipal</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ClaimsPrincipal</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ClaimsIdentity</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">List</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">Claim</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Claim</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ClaimTypes</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">userSession</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4">), </span><span style="color: #6A9955">// 用户名声明</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Claim</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ClaimTypes</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">userSession</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4">) </span><span style="color: #6A9955">// 角色声明</span></span>
<span class="line"><span style="color: #D4D4D4">            }));</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">else</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #6A9955">            // 如果用户会话信息为null，删除存储的会话信息</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_sessionStorage</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">DeleteAsync</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;UserSession&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #6A9955">            // 设置为匿名用户</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">claimsPrincipal</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">_anonymous</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">        // 通知认证状态已更改，传递新的认证状态</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">NotifyAuthenticationStateChanged</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">Task</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">FromResult</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">AuthenticationState</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">claimsPrincipal</span><span style="color: #D4D4D4">)));</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p><code>Authentication</code>/UserAccount.cs</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="public class UserAccount
{
    public string UserName { get; set; }
    public string Password { get; set; }
    public string Role { get; set; }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UserAccount</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4"> { </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4">; </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Password</span><span style="color: #D4D4D4"> { </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4">; </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4"> { </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4">; </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p><code>Authentication</code>/UserAccountService.cs</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="public class UserAccountService
{
    private List&lt;UserAccount&gt; _users;

    public UserAccountService()
    {
        _users = new List&lt;UserAccount&gt;
        {
            new UserAccount{ UserName = &quot;admin&quot;, Password = &quot;admin&quot;, Role = &quot;Administrator&quot; },
            new UserAccount{ UserName = &quot;user&quot;, Password = &quot;user&quot;, Role = &quot;User&quot; }
        };
    }

    public UserAccount? GetByUserName(string userName)
    {
        return _users.FirstOrDefault(x =&gt; x.UserName == userName);
    }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UserAccountService</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">private</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">List</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">UserAccount</span><span style="color: #D4D4D4">&gt; </span><span style="color: #9CDCFE">_users</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">UserAccountService</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">_users</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">List</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">UserAccount</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UserAccount</span><span style="color: #D4D4D4">{ </span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;admin&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">Password</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;admin&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Administrator&quot;</span><span style="color: #D4D4D4"> },</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UserAccount</span><span style="color: #D4D4D4">{ </span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;user&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">Password</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;user&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;User&quot;</span><span style="color: #D4D4D4"> }</span></span>
<span class="line"><span style="color: #D4D4D4">        };</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UserAccount</span><span style="color: #D4D4D4">? </span><span style="color: #DCDCAA">GetByUserName</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">userName</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_users</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">FirstOrDefault</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4"> =&gt; </span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4"> == </span><span style="color: #9CDCFE">userName</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p><code>Authentication</code>/UserSession.cs</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="public class UserSession
{
    public string UserName { get; set; }
    public string Role { get; set; }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UserSession</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4"> { </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4">; </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4"> { </span><span style="color: #569CD6">get</span><span style="color: #D4D4D4">; </span><span style="color: #569CD6">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p>Pages/Login.razor</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="@page &quot;/login&quot;
@using MyBlazorApp.Authentication
@inject UserAccountService userAccountService
@inject IJSRuntime js
@inject AuthenticationStateProvider authStateProvider
@inject NavigationManager navManager

&lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-lg-4 offset-lg-4 pt-4 pb-4 border&quot;&gt;
        &lt;div class=&quot;mb-3 text-center&quot;&gt;
            &lt;h3&gt;LOGIN&lt;/h3&gt;
        &lt;/div&gt;
        &lt;div class=&quot;mb-3&quot;&gt;
            &lt;label&gt;User Name&lt;/label&gt;
            &lt;input @bind=&quot;model.UserName&quot; class=&quot;form-control&quot; placeholder=&quot;User Name&quot; /&gt;
        &lt;/div&gt;
        &lt;div class=&quot;mb-3&quot;&gt;
            &lt;label&gt;Password&lt;/label&gt;
            &lt;input @bind=&quot;model.Password&quot; type=&quot;password&quot; class=&quot;form-control&quot; placeholder=&quot;Password&quot; /&gt;
        &lt;/div&gt;
        &lt;div class=&quot;mb-3 d-grid gap-2&quot;&gt;
            &lt;button @onclick=&quot;Authenticate&quot; class=&quot;btn btn-primary&quot;&gt;Login&lt;/button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

@code {
    private class Model
    {
        public string UserName { get; set; } 
        public string Password { get; set; }
    } 
    private Model model = new Model(); 
    private async Task Authenticate()
    {
        var userAccount = userAccountService.GetByUserName(model.UserName); 
        if (userAccount == null || userAccount.Password != model.Password)
        {
            await js.InvokeVoidAsync(&quot;alert&quot;, &quot;Invalid User Name or Password&quot;);
            return;
        } 
        var customAuthStateProvider = (CustomAuthenticationStateProvider)authStateProvider;
        await customAuthStateProvider.UpdateAuthenticationState(new UserSession
            {
                UserName = userAccount.UserName,
                Role = userAccount.Role
            });
        navManager.NavigateTo(&quot;/&quot;, true);
    }
} " style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">@page</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;/login&quot;</span></span>
<span class="line"><span style="color: #9CDCFE">@using</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">MyBlazorApp</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Authentication</span></span>
<span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">UserAccountService</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">userAccountService</span></span>
<span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IJSRuntime</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">js</span></span>
<span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">AuthenticationStateProvider</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">authStateProvider</span></span>
<span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">NavigationManager</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">navManager</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;row&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;col-lg-4 offset-lg-4 pt-4 pb-4 border&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;mb-3 text-center&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">h3</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">LOGIN</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">h3</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;mb-3&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">label</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">User</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Name</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">label</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">input</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">@bind</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;model.UserName&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;form-control&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">placeholder</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;User Name&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;mb-3&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">label</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">Password</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">label</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">input</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">@bind</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;model.Password&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">type</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;password&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;form-control&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">placeholder</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Password&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;mb-3 d-grid gap-2&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">button</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">@onclick</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Authenticate&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;btn btn-primary&quot;</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">Login</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">button</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">@code</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Model</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">get</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">set</span><span style="color: #D4D4D4">; } </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Password</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">get</span><span style="color: #D4D4D4">; </span><span style="color: #9CDCFE">set</span><span style="color: #D4D4D4">; }</span></span>
<span class="line"><span style="color: #D4D4D4">    } </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Model</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">model</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Model</span><span style="color: #D4D4D4">(); </span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">async</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Task</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Authenticate</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">userAccount</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">userAccountService</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetByUserName</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">model</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4">); </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">userAccount</span><span style="color: #D4D4D4"> == </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4"> || </span><span style="color: #9CDCFE">userAccount</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Password</span><span style="color: #D4D4D4"> != </span><span style="color: #9CDCFE">model</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Password</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">js</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">InvokeVoidAsync</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;alert&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;Invalid User Name or Password&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">return</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        } </span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">customAuthStateProvider</span><span style="color: #D4D4D4"> = (</span><span style="color: #4EC9B0">CustomAuthenticationStateProvider</span><span style="color: #D4D4D4">)</span><span style="color: #9CDCFE">authStateProvider</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">customAuthStateProvider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">UpdateAuthenticationState</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UserSession</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">userAccount</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">UserName</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">userAccount</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Role</span></span>
<span class="line"><span style="color: #D4D4D4">            });</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">navManager</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">NavigateTo</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;/&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">} </span></span></code></pre></div>



<p>Shared/RedirectToLogin</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="@inject AuthenticationStateProvider AuthStateProvider
@inject NavigationManager Navigation

&lt;p&gt;用户未授权，正在重定向到登录页面...&lt;/p&gt;

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var authState = await AuthStateProvider.GetAuthenticationStateAsync();
            var user = authState.User; 
            if (user.Identity == null || !user.Identity.IsAuthenticated)
            {
                // 用户未认证，重定向到登录页面
                Navigation.NavigateTo(&quot;/login&quot;, true);
            }
        } 
    }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">AuthenticationStateProvider</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">AuthStateProvider</span></span>
<span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">NavigationManager</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Navigation</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">用户未授权</span><span style="color: #D4D4D4">，</span><span style="color: #9CDCFE">正在重定向到登录页面</span><span style="color: #D4D4D4">...&lt;/</span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">@code</span><span style="color: #D4D4D4"> {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">protected</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">override</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">async</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Task</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">OnAfterRenderAsync</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">bool</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">firstRender</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">firstRender</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">authState</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">AuthStateProvider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetAuthenticationStateAsync</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">user</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">authState</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">User</span><span style="color: #D4D4D4">; </span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">user</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Identity</span><span style="color: #D4D4D4"> == </span><span style="color: #569CD6">null</span><span style="color: #D4D4D4"> || !</span><span style="color: #9CDCFE">user</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Identity</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">IsAuthenticated</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">            {</span></span>
<span class="line"><span style="color: #6A9955">                // 用户未认证，重定向到登录页面</span></span>
<span class="line"><span style="color: #D4D4D4">                </span><span style="color: #9CDCFE">Navigation</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">NavigateTo</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;/login&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">            }</span></span>
<span class="line"><span style="color: #D4D4D4">        } </span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p>Shared/MainLayout.razor</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="@using MyBlazorApp.Authentication
@inherits LayoutComponentBase
@inject AuthenticationStateProvider authStateProvider
@inject NavigationManager navManager

&lt;PageTitle&gt;MyBlazorApp&lt;/PageTitle&gt;

&lt;div class=&quot;page&quot;&gt;
    &lt;div class=&quot;sidebar&quot;&gt;
        &lt;NavMenu /&gt;
    &lt;/div&gt;

    &lt;main&gt;
        &lt;div class=&quot;top-row px-4&quot;&gt;
            &lt;a href=&quot;https://docs.microsoft.com/aspnet/&quot; target=&quot;_blank&quot;&gt;About&lt;/a&gt;
            &lt;AuthorizeView&gt;
                &lt;Authorized&gt;
                    &lt;a @onclick=&quot;Logout&quot; href=&quot;javascript:void(0)&quot;&gt;Logout&lt;/a&gt;
                &lt;/Authorized&gt;
                &lt;NotAuthorized&gt;
                    &lt;a href=&quot;/login&quot;&gt;Login&lt;/a&gt;
                &lt;/NotAuthorized&gt;
            &lt;/AuthorizeView&gt;
        &lt;/div&gt;

        &lt;article class=&quot;content px-4&quot;&gt;
            @Body
        &lt;/article&gt;
    &lt;/main&gt;
&lt;/div&gt;

@code{
    private async Task Logout()
    {
        var customAuthStateProvider = (CustomAuthenticationStateProvider)authStateProvider;
        await customAuthStateProvider.UpdateAuthenticationState(null);
        navManager.NavigateTo(&quot;/&quot;, true);
    }
}" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">@using</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">MyBlazorApp</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Authentication</span></span>
<span class="line"><span style="color: #9CDCFE">@inherits</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">LayoutComponentBase</span></span>
<span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">AuthenticationStateProvider</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">authStateProvider</span></span>
<span class="line"><span style="color: #9CDCFE">@inject</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">NavigationManager</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">navManager</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">PageTitle</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">MyBlazorApp</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">PageTitle</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;page&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;sidebar&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">NavMenu</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #9CDCFE">main</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;top-row px-4&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">href</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;https://docs.microsoft.com/aspnet/&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">target</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;_blank&quot;</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">About</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">AuthorizeView</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;</span><span style="color: #9CDCFE">Authorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                    &lt;</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">@onclick</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Logout&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">href</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;javascript:void(0)&quot;</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">Logout</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;/</span><span style="color: #9CDCFE">Authorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;</span><span style="color: #9CDCFE">NotAuthorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                    &lt;</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">href</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;/login&quot;</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">Login</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">a</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;/</span><span style="color: #9CDCFE">NotAuthorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;/</span><span style="color: #9CDCFE">AuthorizeView</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">article</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;content px-4&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">@Body</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">article</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/</span><span style="color: #9CDCFE">main</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">@code</span><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">private</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">async</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Task</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Logout</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">customAuthStateProvider</span><span style="color: #D4D4D4"> = (</span><span style="color: #4EC9B0">CustomAuthenticationStateProvider</span><span style="color: #D4D4D4">)</span><span style="color: #9CDCFE">authStateProvider</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">await</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">customAuthStateProvider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">UpdateAuthenticationState</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">null</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">navManager</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">NavigateTo</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;/&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<p>App.razor</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;CascadingAuthenticationState&gt;
    &lt;Router AppAssembly=&quot;@typeof(App).Assembly&quot;&gt;
        &lt;Found Context=&quot;routeData&quot;&gt;
            &lt;AuthorizeRouteView RouteData=&quot;@routeData&quot; DefaultLayout=&quot;@typeof(MainLayout)&quot;&gt;
                &lt;NotAuthorized&gt;
                    &lt;RedirectToLogin /&gt;
                &lt;/NotAuthorized&gt;
                &lt;Authorizing&gt;
                    You are getting authorized  
                &lt;/Authorizing&gt;
            &lt;/AuthorizeRouteView&gt;
            &lt;FocusOnNavigate RouteData=&quot;@routeData&quot; Selector=&quot;h1&quot; /&gt;
        &lt;/Found&gt;
        &lt;NotFound&gt;
            &lt;PageTitle&gt;Not found&lt;/PageTitle&gt;
            &lt;LayoutView Layout=&quot;@typeof(MainLayout)&quot;&gt;
                &lt;p role=&quot;alert&quot;&gt;Sorry, there's nothing at this address.&lt;/p&gt;
            &lt;/LayoutView&gt;
        &lt;/NotFound&gt;
    &lt;/Router&gt;
&lt;/CascadingAuthenticationState&gt;
" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">CascadingAuthenticationState</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #4EC9B0">Router</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">AppAssembly</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;@typeof(App).Assembly&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">Found</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Context</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;routeData&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">AuthorizeRouteView</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">RouteData</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;@routeData&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">DefaultLayout</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;@typeof(MainLayout)&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;</span><span style="color: #9CDCFE">NotAuthorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                    &lt;</span><span style="color: #9CDCFE">RedirectToLogin</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;/</span><span style="color: #9CDCFE">NotAuthorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;</span><span style="color: #9CDCFE">Authorizing</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                    </span><span style="color: #9CDCFE">You</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">are</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">getting</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">authorized</span><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;/</span><span style="color: #9CDCFE">Authorizing</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;/</span><span style="color: #9CDCFE">AuthorizeRouteView</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">FocusOnNavigate</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">RouteData</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;@routeData&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Selector</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;h1&quot;</span><span style="color: #D4D4D4"> /&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">Found</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">NotFound</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">PageTitle</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">Not</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">found</span><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">PageTitle</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">LayoutView</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Layout</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;@typeof(MainLayout)&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;</span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">role</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;alert&quot;</span><span style="color: #D4D4D4">&gt;</span><span style="color: #9CDCFE">Sorry</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">there</span><span style="color: #D4D4D4">&#39;</span><span style="color: #9CDCFE">s</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">nothing</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">at</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">this</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">address</span><span style="color: #D4D4D4">.&lt;/</span><span style="color: #9CDCFE">p</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;/</span><span style="color: #9CDCFE">LayoutView</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">NotFound</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/</span><span style="color: #9CDCFE">Router</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">CascadingAuthenticationState</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"></span></code></pre></div>



<p>Program.cs</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="var builder = WebApplication.CreateBuilder(args); 
builder.Services.AddAuthenticationCore();
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped&lt;ProtectedSessionStorage&gt;();
builder.Services.AddScoped&lt;AuthenticationStateProvider, CustomAuthenticationStateProvider&gt;();
builder.Services.AddSingleton&lt;UserAccountService&gt;();
builder.Services.AddSingleton&lt;WeatherForecastService&gt;();

var app = builder.Build(); 
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler(&quot;/Error&quot;);
}  
app.UseStaticFiles(); 
app.UseRouting(); 
app.MapBlazorHub();
app.MapFallbackToPage(&quot;/_Host&quot;); 
app.Run();" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">WebApplication</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">CreateBuilder</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">args</span><span style="color: #D4D4D4">); </span></span>
<span class="line"><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddAuthenticationCore</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddRazorPages</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddServerSideBlazor</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddScoped</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">ProtectedSessionStorage</span><span style="color: #D4D4D4">&gt;();</span></span>
<span class="line"><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddScoped</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">AuthenticationStateProvider</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">CustomAuthenticationStateProvider</span><span style="color: #D4D4D4">&gt;();</span></span>
<span class="line"><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddSingleton</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">UserAccountService</span><span style="color: #D4D4D4">&gt;();</span></span>
<span class="line"><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddSingleton</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">WeatherForecastService</span><span style="color: #D4D4D4">&gt;();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">app</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Build</span><span style="color: #D4D4D4">(); </span></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Environment</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">IsDevelopment</span><span style="color: #D4D4D4">())</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">UseExceptionHandler</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;/Error&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"><span style="color: #D4D4D4">}  </span></span>
<span class="line"><span style="color: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">UseStaticFiles</span><span style="color: #D4D4D4">(); </span></span>
<span class="line"><span style="color: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">UseRouting</span><span style="color: #D4D4D4">(); </span></span>
<span class="line"><span style="color: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">MapBlazorHub</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">MapFallbackToPage</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;/_Host&quot;</span><span style="color: #D4D4D4">); </span></span>
<span class="line"><span style="color: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Run</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<p></p>



<h3 class="wp-block-heading">使用方式</h3>



<p>在页面中使用</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="@page &quot;/counter&quot;
@attribute [Authorize(Roles = &quot;Administrator,User&quot;)]" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #9CDCFE">@page</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;/counter&quot;</span></span>
<span class="line"><span style="color: #9CDCFE">@attribute</span><span style="color: #D4D4D4"> [</span><span style="color: #DCDCAA">Authorize</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">Roles</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Administrator,User&quot;</span><span style="color: #D4D4D4">)]</span></span></code></pre></div>



<p>在组件中使用</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;AuthorizeView Roles=&quot;Administrator,User&quot;&gt;
    &lt;Authorized&gt;
        &lt;div class=&quot;nav-item px-3&quot;&gt;
            &lt;NavLink class=&quot;nav-link&quot; href=&quot;counter&quot;&gt;
                &lt;span class=&quot;oi oi-plus&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt; Counter
            &lt;/NavLink&gt;
        &lt;/div&gt;
    &lt;/Authorized&gt;
&lt;/AuthorizeView&gt;
&lt;AuthorizeView Roles=&quot;Administrator&quot;&gt;
    &lt;Authorized&gt;
        &lt;div class=&quot;nav-item px-3&quot;&gt;
            &lt;NavLink class=&quot;nav-link&quot; href=&quot;fetchdata&quot;&gt;
                &lt;span class=&quot;oi oi-list-rich&quot; aria-hidden=&quot;true&quot;&gt;&lt;/span&gt; Fetch data
            &lt;/NavLink&gt;
        &lt;/div&gt;
    &lt;/Authorized&gt;
&lt;/AuthorizeView&gt;" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">AuthorizeView</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Roles</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Administrator,User&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #9CDCFE">Authorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;nav-item px-3&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">NavLink</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;nav-link&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">href</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;counter&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;</span><span style="color: #9CDCFE">span</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;oi oi-plus&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">aria</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">hidden</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;true&quot;</span><span style="color: #D4D4D4">&gt;&lt;/</span><span style="color: #9CDCFE">span</span><span style="color: #D4D4D4">&gt; </span><span style="color: #9CDCFE">Counter</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;/</span><span style="color: #9CDCFE">NavLink</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/</span><span style="color: #9CDCFE">Authorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">AuthorizeView</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;</span><span style="color: #9CDCFE">AuthorizeView</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Roles</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;Administrator&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;</span><span style="color: #9CDCFE">Authorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;nav-item px-3&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;</span><span style="color: #9CDCFE">NavLink</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;nav-link&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">href</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;fetchdata&quot;</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">                &lt;</span><span style="color: #9CDCFE">span</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">class</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;oi oi-list-rich&quot;</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">aria</span><span style="color: #D4D4D4">-</span><span style="color: #9CDCFE">hidden</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;true&quot;</span><span style="color: #D4D4D4">&gt;&lt;/</span><span style="color: #9CDCFE">span</span><span style="color: #D4D4D4">&gt; </span><span style="color: #9CDCFE">Fetch</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">data</span></span>
<span class="line"><span style="color: #D4D4D4">            &lt;/</span><span style="color: #9CDCFE">NavLink</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">        &lt;/</span><span style="color: #9CDCFE">div</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    &lt;/</span><span style="color: #9CDCFE">Authorized</span><span style="color: #D4D4D4">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">&lt;/</span><span style="color: #9CDCFE">AuthorizeView</span><span style="color: #D4D4D4">&gt;</span></span></code></pre></div>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Blazor Server 前后端不分离项目结构简介</title>
		<link>https://blog.mutadecheng.com/2024/10/25/blazor-server-%e5%89%8d%e5%90%8e%e7%ab%af%e4%b8%8d%e5%88%86%e7%a6%bb%e9%a1%b9%e7%9b%ae%e7%bb%93%e6%9e%84%e7%ae%80%e4%bb%8b/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Fri, 25 Oct 2024 02:53:04 +0000</pubDate>
				<category><![CDATA[Blazor]]></category>
		<category><![CDATA[c#]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=236</guid>

					<description><![CDATA[在Blazor Server项目中，前后端不分离的结构是将用户界面和业务逻辑结合在一个项目中。这种方式适合于中 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>在Blazor Server项目中，前后端不分离的结构是将用户界面和业务逻辑结合在一个项目中。这种方式适合于中小型应用程序，简化了项目的管理和部署。以下是一个典型的Blazor Server项目结构示例，其中前后端不分离：</p>



<h3 class="wp-block-heading">项目结构</h3>



<ol class="wp-block-list">
<li><strong>解决方案</strong>
<ul class="wp-block-list">
<li><code>MyBlazorApp.sln</code></li>
</ul>
</li>



<li><strong>Blazor Server项目</strong>
<ul class="wp-block-list">
<li><code>MyBlazorApp</code> (Blazor Server项目)</li>



<li><code>Pages/</code> &#8211; 包含所有的页面组件（<code>*.razor</code>）</li>



<li><code>Components/</code> &#8211; 可复用的UI组件</li>



<li><code>Shared/</code> &#8211; 前后端共享的组件或代码</li>



<li><code>Data/</code> &#8211; 数据访问层和业务逻辑</li>



<li><code>Models/</code> &#8211; 数据模型</li>



<li><code>wwwroot/</code> &#8211; 静态文件，如CSS、JavaScript和图像</li>



<li><code>Program.cs</code> &#8211; 配置Blazor Server应用程序的启动</li>



<li><code>Startup.cs</code> &#8211; 配置服务和中间件（如果使用Startup类）</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">详细说明</h3>



<ul class="wp-block-list">
<li><strong>Pages</strong>: 包含Blazor应用的页面，每个页面都由一个<code>.razor</code>文件组成。这些页面负责用户界面的展示和用户交互。</li>



<li><strong>Components</strong>: 存放可复用的UI组件，组件可以在多个页面中使用，帮助减少代码重复。</li>



<li><strong>Shared</strong>: 用于存放前后端共享的代码，如共享的组件或帮助类。</li>



<li><strong>Data</strong>: 负责数据访问和业务逻辑。可以在这里实现与数据库的交互逻辑（如使用Entity Framework Core），以及任何必要的业务规则。</li>



<li><strong>Models</strong>: 定义应用程序使用的数据模型。这些模型通常用于表示数据库中的实体或其他数据结构。</li>



<li><strong>wwwroot</strong>: 包含所有的静态资源，如CSS样式表、JavaScript文件和图像文件。Blazor Server会将这些文件直接提供给浏览器。</li>



<li><strong>Program.cs</strong>: 定义应用程序的入口点，配置服务（如依赖注入）和应用程序生命周期。</li>



<li><strong>Startup.cs</strong>: 配置应用程序的请求管道和服务（如果使用Startup类）。包括中间件配置、路由设置等。</li>
</ul>



<h3 class="wp-block-heading">特点</h3>



<ul class="wp-block-list">
<li><strong>单一项目</strong>: 前后端代码在同一项目中，简化了项目结构和管理。</li>



<li><strong>集成开发</strong>: 开发人员可以在一个项目中同时处理UI和业务逻辑，这对于小型团队或个人项目来说非常方便。</li>



<li><strong>快速部署</strong>: 由于所有代码都在一个项目中，部署只需处理一个应用程序，减少了复杂性。</li>
</ul>



<h3 class="wp-block-heading">注意事项</h3>



<ul class="wp-block-list">
<li><strong>代码组织</strong>: 由于所有代码都在一个项目中，良好的代码组织和模块化设计仍然是必要的，以确保项目的可维护性。</li>



<li><strong>性能与扩展性</strong>: 对于大型应用，可能需要考虑前后端分离，以提高性能和扩展性。</li>
</ul>



<p>这种前后端不分离的结构适用于快速开发和部署小型到中型应用程序，尤其是在不需要复杂的服务器端API或微服务架构时。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Blazor Server 前后端分离项目结构简介</title>
		<link>https://blog.mutadecheng.com/2024/10/25/blazor-server-%e5%89%8d%e5%90%8e%e7%ab%af%e5%88%86%e7%a6%bb%e9%a1%b9%e7%9b%ae%e7%bb%93%e6%9e%84%e7%ae%80%e4%bb%8b/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Fri, 25 Oct 2024 02:52:11 +0000</pubDate>
				<category><![CDATA[Blazor]]></category>
		<category><![CDATA[c#]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=234</guid>

					<description><![CDATA[在Blazor Server项目中实现前后端分离是一种常见的架构方式，可以提高项目的可维护性和扩展性。下面是一 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>在Blazor Server项目中实现前后端分离是一种常见的架构方式，可以提高项目的可维护性和扩展性。下面是一个推荐的项目结构，帮助实现Blazor Server前后端分离：</p>



<h3 class="wp-block-heading">项目结构</h3>



<ol class="wp-block-list">
<li><strong>解决方案</strong>
<ul class="wp-block-list">
<li><code>MySolution.sln</code></li>
</ul>
</li>



<li><strong>前端项目</strong>
<ul class="wp-block-list">
<li><code>MyApp.Client</code> (Blazor Server项目)</li>



<li><code>Pages/</code> &#8211; 包含所有的页面组件（<code>*.razor</code>）</li>



<li><code>Components/</code> &#8211; 可复用的UI组件</li>



<li><code>wwwroot/</code> &#8211; 静态文件，如CSS、JavaScript和图像</li>



<li><code>Shared/</code> &#8211; 前后端共享的组件或代码</li>



<li><code>Program.cs</code> &#8211; 配置Blazor Server应用程序的启动</li>



<li><code>Startup.cs</code> &#8211; 配置服务和中间件（如果使用Startup类）</li>
</ul>
</li>



<li><strong>后端项目</strong>
<ul class="wp-block-list">
<li><code>MyApp.Server</code> (ASP.NET Core Web API项目)</li>



<li><code>Controllers/</code> &#8211; Web API控制器，处理HTTP请求</li>



<li><code>Models/</code> &#8211; 数据模型</li>



<li><code>Repositories/</code> &#8211; 数据访问层，处理数据库操作</li>



<li><code>Services/</code> &#8211; 业务逻辑层</li>



<li><code>Data/</code> &#8211; 数据上下文类（如EF Core的DbContext）</li>



<li><code>Program.cs</code> &#8211; 配置ASP.NET Core应用程序的启动</li>



<li><code>Startup.cs</code> &#8211; 配置服务和中间件（如果使用Startup类）</li>
</ul>
</li>



<li><strong>共享项目</strong>
<ul class="wp-block-list">
<li><code>MyApp.Shared</code> (类库项目)</li>



<li><code>DTOs/</code> &#8211; 数据传输对象（Data Transfer Objects）</li>



<li><code>Models/</code> &#8211; 共享的数据模型</li>



<li><code>Utilities/</code> &#8211; 工具类或辅助方法</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">详细说明</h3>



<ul class="wp-block-list">
<li><strong>MyApp.Client</strong>: 该项目是Blazor Server应用，负责处理用户界面。它通过调用后端API获取和提交数据。Pages文件夹中包含应用的页面，Components文件夹中则是可复用的组件。Shared文件夹用于存放前后端共享的代码。</li>



<li><strong>MyApp.Server</strong>: 该项目是一个ASP.NET Core Web API项目，负责提供数据服务和业务逻辑。Controllers文件夹中的控制器处理来自客户端的HTTP请求，并调用Services中的业务逻辑。Repositories用于与数据库交互。</li>



<li><strong>MyApp.Shared</strong>: 这是一个类库项目，存放前后端共享的代码，如DTOs和模型。这样可以确保前后端在数据结构上的一致性。</li>
</ul>



<h3 class="wp-block-heading">配置通信</h3>



<ul class="wp-block-list">
<li><strong>API调用</strong>: 在Blazor Server中，可以使用<code>HttpClient</code>调用后端的API。可以在<code>Program.cs</code>中配置<code>HttpClient</code>，以便在应用中注入使用。</li>



<li><strong>身份验证与授权</strong>: 可以使用ASP.NET Core Identity或其他身份验证机制来保护API，并在Blazor应用中使用授权组件。</li>
</ul>



<h3 class="wp-block-heading">部署与调试</h3>



<ul class="wp-block-list">
<li><strong>调试</strong>: 可以通过Visual Studio或VS Code同时启动前后端项目进行调试。确保在调试配置中启动多个项目。</li>



<li><strong>部署</strong>: 部署时，可以将Blazor Server和Web API项目作为一个整体部署到同一服务器上，或者分别部署到不同的服务器上，根据具体需求进行选择。</li>
</ul>



<p></p>



<p></p>



<p></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
