<?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>c# &#8211; 岁月细碎点滴快查</title>
	<atom:link href="https://blog.mutadecheng.com/category/c/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>winform 改依赖注入</title>
		<link>https://blog.mutadecheng.com/2025/11/10/winform-%e6%94%b9%e4%be%9d%e8%b5%96%e6%b3%a8%e5%85%a5/</link>
					<comments>https://blog.mutadecheng.com/2025/11/10/winform-%e6%94%b9%e4%be%9d%e8%b5%96%e6%b3%a8%e5%85%a5/#respond</comments>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Mon, 10 Nov 2025 01:52:09 +0000</pubDate>
				<category><![CDATA[c#]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=425</guid>

					<description><![CDATA[]]></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="internal static class Program
{
    /// &lt;summary&gt;
    ///  The main entry point for the application.
    /// &lt;/summary&gt;
    [STAThread]
    static void Main()
    {
        ApplicationConfiguration.Initialize();

        // 读取配置文件
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile(&quot;appsettings.json&quot;, optional: true, reloadOnChange: true)
            .Build(); 

        // 创建服务容器
        var services = new ServiceCollection();

        // 注册 IConfiguration
        services.AddSingleton&lt;IConfiguration&gt;(configuration);

        // 注册日志服务
        services.AddLogging(builder =&gt;
        {
            builder.AddConsole();
        });
        
        // 注册服务  
        services.AddSingleton&lt;MultiMqttService&gt;();
        services.AddSingleton&lt;RabbitMqService&gt;(); 
        services.AddSingleton&lt;IMutaCacheRepository&lt;DeviceInfo&gt;, DeviceInfoRepository&gt;();

        // 注册Form1为瞬时（每次都新建），如果你希望Form1也是单例，可以用AddSingleton
        services.AddTransient&lt;Form1&gt;();

        // 构建服务提供器
        var serviceProvider = services.BuildServiceProvider();
         
        // 解析Form1并运行
        var form = serviceProvider.GetRequiredService&lt;Form1&gt;();
        Application.Run(form);
    }
}" 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">internal</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Program</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #6A9955">    /// </span><span style="color: #808080">&lt;</span><span style="color: #569CD6">summary</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #6A9955">    ///  The main entry point for the application.</span></span>
<span class="line"><span style="color: #6A9955">    /// </span><span style="color: #808080">&lt;/</span><span style="color: #569CD6">summary</span><span style="color: #808080">&gt;</span></span>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #4EC9B0">STAThread</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">static</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">void</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Main</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">ApplicationConfiguration</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Initialize</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">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">configuration</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ConfigurationBuilder</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">SetBasePath</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">Directory</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetCurrentDirectory</span><span style="color: #D4D4D4">())</span></span>
<span class="line"><span style="color: #D4D4D4">            .</span><span style="color: #DCDCAA">AddJsonFile</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;appsettings.json&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">optional</span><span style="color: #D4D4D4">: </span><span style="color: #569CD6">true</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">reloadOnChange</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 style="color: #DCDCAA">Build</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">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">services</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ServiceCollection</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">        // 注册 IConfiguration</span></span>
<span class="line"><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">IConfiguration</span><span style="color: #D4D4D4">&gt;(</span><span style="color: #9CDCFE">configuration</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: #9CDCFE">services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddLogging</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">builder</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: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddConsole</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: #6A9955">        // 注册服务  </span></span>
<span class="line"><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">MultiMqttService</span><span style="color: #D4D4D4">&gt;();</span></span>
<span class="line"><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">RabbitMqService</span><span style="color: #D4D4D4">&gt;(); </span></span>
<span class="line"><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">IMutaCacheRepository</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">DeviceInfo</span><span style="color: #D4D4D4">&gt;, </span><span style="color: #4EC9B0">DeviceInfoRepository</span><span style="color: #D4D4D4">&gt;();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">        // 注册Form1为瞬时（每次都新建），如果你希望Form1也是单例，可以用AddSingleton</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddTransient</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">Form1</span><span style="color: #D4D4D4">&gt;();</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">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">serviceProvider</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">services</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">BuildServiceProvider</span><span style="color: #D4D4D4">();</span></span>
<span class="line"><span style="color: #D4D4D4">         </span></span>
<span class="line"><span style="color: #6A9955">        // 解析Form1并运行</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">form</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">serviceProvider</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetRequiredService</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">Form1</span><span style="color: #D4D4D4">&gt;();</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">Application</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Run</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">form</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>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.mutadecheng.com/2025/11/10/winform-%e6%94%b9%e4%be%9d%e8%b5%96%e6%b3%a8%e5%85%a5/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<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>C# WebAPI Token 生成与账号密码登录实现</title>
		<link>https://blog.mutadecheng.com/2025/06/18/c-webapi-token-%e7%94%9f%e6%88%90%e4%b8%8e%e8%b4%a6%e5%8f%b7%e5%af%86%e7%a0%81%e7%99%bb%e5%bd%95%e5%ae%9e%e7%8e%b0/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Wed, 18 Jun 2025 01:45:45 +0000</pubDate>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[身份验证与授权]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=336</guid>

					<description><![CDATA[此为一个简单的且完整的 C# WebAPI 实现，用于基于账号密码的 Token 生成和验证系统。这个实现使用 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>此为一个简单的且完整的 C# WebAPI 实现，用于基于账号密码的 Token 生成和验证系统。这个实现使用 JWT (JSON Web Token) 作为认证机制。</p>



<h2 class="wp-block-heading">1. 创建项目</h2>



<p>首先创建一个 ASP.NET Core WebAPI 项目。</p>



<h2 class="wp-block-heading">2. 安装必要 NuGet 包</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="Microsoft.AspNetCore.Authentication.JwtBearer
System.IdentityModel.Tokens.Jwt
Microsoft.EntityFrameworkCore (如果使用数据库)
Microsoft.EntityFrameworkCore.SqlServer (如果使用SQL Server)" 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">Microsoft</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">AspNetCore</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Authentication</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">JwtBearer</span></span>
<span class="line"><span style="color: #9CDCFE">System</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">IdentityModel</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Tokens</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Jwt</span></span>
<span class="line"><span style="color: #9CDCFE">Microsoft</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">EntityFrameworkCore</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">如果使用数据库</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #9CDCFE">Microsoft</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">EntityFrameworkCore</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">SqlServer</span><span style="color: #D4D4D4"> (</span><span style="color: #9CDCFE">如果使用SQL</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Server</span><span style="color: #D4D4D4">)</span></span></code></pre></div>



<h2 class="wp-block-heading">3. 完整实现代码</h2>



<h3 class="wp-block-heading">3.1 配置类 (appsettings.json)</h3>



<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;Jwt&quot;: {
    &quot;Key&quot;: &quot;YourSuperSecretKeyHereAtLeast32CharactersLong&quot;,
    &quot;Issuer&quot;: &quot;YourAppIssuer&quot;,
    &quot;Audience&quot;: &quot;YourAppAudience&quot;,
    &quot;ExpireMinutes&quot;: 60
  },
  &quot;Logging&quot;: {
    &quot;LogLevel&quot;: {
      &quot;Default&quot;: &quot;Information&quot;,
      &quot;Microsoft.AspNetCore&quot;: &quot;Warning&quot;
    }
  },
  &quot;AllowedHosts&quot;: &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: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #CE9178">&quot;Jwt&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;Key&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;YourSuperSecretKeyHereAtLeast32CharactersLong&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;Issuer&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;YourAppIssuer&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;Audience&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;YourAppAudience&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;ExpireMinutes&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #B5CEA8">60</span></span>
<span class="line"><span style="color: #D4D4D4">  },</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #CE9178">&quot;Logging&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;LogLevel&quot;</span><span style="color: #D4D4D4">: {</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #CE9178">&quot;Default&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;Information&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #CE9178">&quot;Microsoft.AspNetCore&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;Warning&quot;</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: #CE9178">&quot;AllowedHosts&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;*&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">3.2 用户模型 (Models/User.cs)</h3>



<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 User
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string Password { get; set; } // 实际应用中应该存储哈希值
    public string Role { get; set; } // 例如 &quot;Admin&quot;, &quot;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: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">User</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">int</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Id</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">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 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">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 style="color: #6A9955">// 例如 &quot;Admin&quot;, &quot;User&quot; 等</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">3.3 Token 响应模型 (Models/TokenResponse.cs)</h3>



<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 TokenResponse
{
    public string Token { get; set; }
    public DateTime Expiration { get; set; }
    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">TokenResponse</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">Token</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: #4EC9B0">DateTime</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Expiration</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">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>



<h3 class="wp-block-heading">3.4 登录请求模型 (Models/LoginRequest.cs)</h3>



<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 LoginRequest
{
    public string Username { get; set; }
    public string Password { 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">LoginRequest</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></code></pre></div>



<h3 class="wp-block-heading">3.5 JWT 服务 (Services/JwtService.cs)</h3>



<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 System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;

public class JwtService
{
    private readonly IConfiguration _configuration;

    public JwtService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public string GenerateToken(User user)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration[&quot;Jwt:Key&quot;]));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, user.Username),
            new Claim(ClaimTypes.Role, user.Role)
        };

        var token = new JwtSecurityToken(
            _configuration[&quot;Jwt:Issuer&quot;],
            _configuration[&quot;Jwt:Audience&quot;],
            claims,
            expires: DateTime.Now.AddMinutes(Convert.ToDouble(_configuration[&quot;Jwt:ExpireMinutes&quot;])),
            signingCredentials: credentials);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}" 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: #C586C0">using</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">System</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">IdentityModel</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Tokens</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Jwt</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">using</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">System</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Security</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Claims</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">using</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">System</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">using</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Microsoft</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">IdentityModel</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Tokens</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></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">JwtService</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: #569CD6">readonly</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">IConfiguration</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_configuration</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">JwtService</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">IConfiguration</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">configuration</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">_configuration</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">configuration</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: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">string</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">GenerateToken</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">User</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>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">securityKey</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">SymmetricSecurityKey</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">Encoding</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">UTF8</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetBytes</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">_configuration</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&quot;Jwt:Key&quot;</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">credentials</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">SigningCredentials</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">securityKey</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">SecurityAlgorithms</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">HmacSha256</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">claims</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: #4EC9B0">Claim</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">ClaimTypes</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">NameIdentifier</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">user</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: #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">user</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Role</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: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">token</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">JwtSecurityToken</span><span style="color: #D4D4D4">(</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">_configuration</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&quot;Jwt:Issuer&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">_configuration</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&quot;Jwt:Audience&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">claims</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">expires</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">DateTime</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Now</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddMinutes</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">Convert</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">ToDouble</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">_configuration</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&quot;Jwt:ExpireMinutes&quot;</span><span style="color: #D4D4D4">])),</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">signingCredentials</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">credentials</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">JwtSecurityTokenHandler</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">WriteToken</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">token</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>



<h3 class="wp-block-heading">3.6 用户服务 (Services/UserService.cs)</h3>



<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 UserService
{
    // 实际应用中应该从数据库获取用户
    private readonly List<User&gt; _users = new List<User&gt;
    {
        new User { Id = 1, Username = &quot;admin&quot;, Password = &quot;admin123&quot;, Role = &quot;Admin&quot; },
        new User { Id = 2, Username = &quot;user&quot;, Password = &quot;user123&quot;, Role = &quot;User&quot; }
    };

    public User Authenticate(string username, string password)
    {
        // 实际应用中应该验证密码哈希
        var user = _users.SingleOrDefault(x =&gt; x.Username == username &amp;&amp; x.Password == password);

        // 如果用户不存在或密码错误返回null
        if (user == null)
            return null;

        // 认证成功返回用户详情 (不包含密码)
        return user;
    }
}" 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">UserService</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">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">readonly</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">List</span><span style="color: #D4D4D4">&lt;</span><span style="color: #4EC9B0">User</span><span style="color: #D4D4D4">&gt; </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">User</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">User</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">Id</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">1</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;admin123&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">Role</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Admin&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">User</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">Id</span><span style="color: #D4D4D4"> = </span><span style="color: #B5CEA8">2</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;user123&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>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">public</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">User</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Authenticate</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">string</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: #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">user</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">_users</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">SingleOrDefault</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"> &amp;&amp; </span><span style="color: #9CDCFE">x</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Password</span><span style="color: #D4D4D4"> == </span><span style="color: #9CDCFE">password</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">user</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">null</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: #C586C0">return</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>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">3.7 认证控制器 (Controllers/AuthController.cs)</h3>



<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 Microsoft.AspNetCore.Mvc;

[Route(&quot;api/[controller]&quot;)]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly UserService _userService;
    private readonly JwtService _jwtService;

    public AuthController(UserService userService, JwtService jwtService)
    {
        _userService = userService;
        _jwtService = jwtService;
    }

    [HttpPost(&quot;login&quot;)]
    public IActionResult Login([FromBody] LoginRequest request)
    {
        var user = _userService.Authenticate(request.Username, request.Password);

        if (user == null)
            return Unauthorized(new { message = &quot;用户名或密码错误&quot; });

        var token = _jwtService.GenerateToken(user);

        return Ok(new TokenResponse
        {
            Token = token,
            Expiration = DateTime.Now.AddMinutes(Convert.ToDouble(_configuration[&quot;Jwt:ExpireMinutes&quot;])),
            Username = user.Username,
            Role = user.Role
        });
    }
}" 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: #C586C0">using</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Microsoft</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">AspNetCore</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Mvc</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">[</span><span style="color: #4EC9B0">Route</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;api/[controller]&quot;</span><span style="color: #D4D4D4">)]</span></span>
<span class="line"><span style="color: #D4D4D4">[</span><span style="color: #4EC9B0">ApiController</span><span style="color: #D4D4D4">]</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">AuthController</span><span style="color: #D4D4D4"> : </span><span style="color: #4EC9B0">ControllerBase</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: #569CD6">readonly</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">UserService</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_userService</span><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: #569CD6">readonly</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">JwtService</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_jwtService</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">AuthController</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">UserService</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">userService</span><span style="color: #D4D4D4">, </span><span style="color: #4EC9B0">JwtService</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">jwtService</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">_userService</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">userService</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">_jwtService</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">jwtService</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: #4EC9B0">HttpPost</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;login&quot;</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: #4EC9B0">IActionResult</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Login</span><span style="color: #D4D4D4">([</span><span style="color: #4EC9B0">FromBody</span><span style="color: #D4D4D4">] </span><span style="color: #4EC9B0">LoginRequest</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">request</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">user</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">_userService</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Authenticate</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Username</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">request</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Password</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">user</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: #DCDCAA">Unauthorized</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">message</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;用户名或密码错误&quot;</span><span style="color: #D4D4D4"> });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">token</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">_jwtService</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GenerateToken</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">user</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Ok</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">TokenResponse</span></span>
<span class="line"><span style="color: #D4D4D4">        {</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">Token</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">token</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">Expiration</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">DateTime</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Now</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">AddMinutes</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">Convert</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">ToDouble</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">_configuration</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&quot;Jwt:ExpireMinutes&quot;</span><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">user</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">user</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>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">3.8 受保护资源控制器 (Controllers/ProtectedController.cs)</h3>



<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 Microsoft.AspNetCore.Authorization;

[Authorize]
[Route(&quot;api/[controller]&quot;)]
[ApiController]
public class ProtectedController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        // 可以从HttpContext.User获取用户信息
        var username = User.Identity.Name;
        var role = User.FindFirst(ClaimTypes.Role)?.Value;

        return Ok(new { 
            Message = $&quot;你好 {username}, 你的角色是 {role}&quot;,
            Data = &quot;这是受保护的数据&quot; 
        });
    }

    [Authorize(Roles = &quot;Admin&quot;)]
    [HttpGet(&quot;admin&quot;)]
    public IActionResult AdminOnly()
    {
        return Ok(new { Message = &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: #C586C0">using</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Microsoft</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">AspNetCore</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Authorization</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">[</span><span style="color: #4EC9B0">Authorize</span><span style="color: #D4D4D4">]</span></span>
<span class="line"><span style="color: #D4D4D4">[</span><span style="color: #4EC9B0">Route</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;api/[controller]&quot;</span><span style="color: #D4D4D4">)]</span></span>
<span class="line"><span style="color: #D4D4D4">[</span><span style="color: #4EC9B0">ApiController</span><span style="color: #D4D4D4">]</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">ProtectedController</span><span style="color: #D4D4D4"> : </span><span style="color: #4EC9B0">ControllerBase</span></span>
<span class="line"><span style="color: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #4EC9B0">HttpGet</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: #4EC9B0">IActionResult</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Get</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #6A9955">        // 可以从HttpContext.User获取用户信息</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">username</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">Name</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">role</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">User</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">FindFirst</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">Value</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Ok</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 style="color: #9CDCFE">Message</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">$&quot;你好 {</span><span style="color: #9CDCFE">username</span><span style="color: #CE9178">}, 你的角色是 {</span><span style="color: #9CDCFE">role</span><span style="color: #CE9178">}&quot;</span><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: #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>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #4EC9B0">Authorize</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">Roles</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;Admin&quot;</span><span style="color: #D4D4D4">)]</span></span>
<span class="line"><span style="color: #D4D4D4">    [</span><span style="color: #4EC9B0">HttpGet</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;admin&quot;</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: #4EC9B0">IActionResult</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">AdminOnly</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: #DCDCAA">Ok</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> { </span><span style="color: #9CDCFE">Message</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></code></pre></div>



<h3 class="wp-block-heading">3.9 Program.cs 配置</h3>



<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 Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// 添加服务到容器
builder.Services.AddControllers();

// 配置JWT认证
builder.Services.AddAuthentication(options =&gt;
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =&gt;
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = builder.Configuration[&quot;Jwt:Issuer&quot;],
        ValidAudience = builder.Configuration[&quot;Jwt:Audience&quot;],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration[&quot;Jwt:Key&quot;]))
    };
});

// 注册自定义服务
builder.Services.AddScoped<UserService&gt;();
builder.Services.AddScoped<JwtService&gt;();

var app = builder.Build();

// 配置HTTP请求管道
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();

// 添加认证和授权中间件
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

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: #C586C0">using</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Microsoft</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">AspNetCore</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Authentication</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">JwtBearer</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">using</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">Microsoft</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">IdentityModel</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Tokens</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #C586C0">using</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">System</span><span style="color: #D4D4D4">.</span><span style="color: #4EC9B0">Text</span><span style="color: #D4D4D4">;</span></span>
<span class="line"></span>
<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>
<span class="line"><span style="color: #6A9955">// 添加服务到容器</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">AddControllers</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// 配置JWT认证</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">AddAuthentication</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">options</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: #9CDCFE">options</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">DefaultAuthenticateScheme</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">JwtBearerDefaults</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">AuthenticationScheme</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">options</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">DefaultChallengeScheme</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">JwtBearerDefaults</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">AuthenticationScheme</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">AddJwtBearer</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">options</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: #9CDCFE">options</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">TokenValidationParameters</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">TokenValidationParameters</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">ValidateIssuer</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 style="color: #9CDCFE">ValidateAudience</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 style="color: #9CDCFE">ValidateLifetime</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 style="color: #9CDCFE">ValidateIssuerSigningKey</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 style="color: #9CDCFE">ValidIssuer</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Configuration</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&quot;Jwt:Issuer&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">ValidAudience</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Configuration</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&quot;Jwt:Audience&quot;</span><span style="color: #D4D4D4">],</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">IssuerSigningKey</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">SymmetricSecurityKey</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">Encoding</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">UTF8</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetBytes</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">builder</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Configuration</span><span style="color: #D4D4D4">[</span><span style="color: #CE9178">&quot;Jwt:Key&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: #6A9955">// 注册自定义服务</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">UserService</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">JwtService</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>
<span class="line"><span style="color: #6A9955">// 配置HTTP请求管道</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">UseDeveloperExceptionPage</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: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">UseHttpsRedirection</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: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">UseAuthentication</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">UseAuthorization</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #9CDCFE">app</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">MapControllers</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></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>



<h2 class="wp-block-heading">4. 使用说明</h2>



<h3 class="wp-block-heading">4.1 获取Token</h3>



<p>发送POST请求到 <code>/api/auth/login</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="{
    &quot;username&quot;: &quot;admin&quot;,
    &quot;password&quot;: &quot;admin123&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: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;username&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;admin&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;password&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;admin123&quot;</span></span>
<span class="line"><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="{
    &quot;token&quot;: &quot;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&quot;,
    &quot;expiration&quot;: &quot;2023-05-01T12:00:00&quot;,
    &quot;username&quot;: &quot;admin&quot;,
    &quot;role&quot;: &quot;Admin&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: #D4D4D4">{</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;token&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;expiration&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;2023-05-01T12:00:00&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;username&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;admin&quot;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #CE9178">&quot;role&quot;</span><span style="color: #D4D4D4">: </span><span style="color: #CE9178">&quot;Admin&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">4.2 访问受保护资源</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="Authorization: Bearer <your_token&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: #C8C8C8">Authorization</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">Bearer</span><span style="color: #D4D4D4"> &lt;</span><span style="color: #9CDCFE">your_token</span><span style="color: #D4D4D4">&gt;</span></span></code></pre></div>



<p>然后访问 <code>/api/protected</code></p>



<h3 class="wp-block-heading">4.3 访问管理员资源</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="Authorization: Bearer <your_token&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: #C8C8C8">Authorization</span><span style="color: #D4D4D4">: </span><span style="color: #9CDCFE">Bearer</span><span style="color: #D4D4D4"> &lt;</span><span style="color: #9CDCFE">your_token</span><span style="color: #D4D4D4">&gt;</span></span></code></pre></div>



<p>然后访问 <code>/api/protected/admin</code> (需要管理员角色)</p>



<h2 class="wp-block-heading">5. 安全建议</h2>



<ol class="wp-block-list">
<li><strong>密码存储</strong>：实际应用中不要明文存储密码，应该使用密码哈希加盐</li>



<li><strong>HTTPS</strong>：确保所有认证请求都通过HTTPS</li>



<li><strong>Token过期</strong>：设置合理的Token过期时间</li>



<li><strong>密钥保护</strong>：保护JWT密钥，不要硬编码在代码中</li>



<li><strong>刷新Token</strong>：考虑实现刷新Token机制</li>
</ol>



<h2 class="wp-block-heading">6. 扩展功能</h2>



<ol class="wp-block-list">
<li>添加用户注册功能</li>



<li>实现密码重置</li>



<li>添加多因素认证</li>



<li>实现Token刷新机制</li>



<li>添加日志记录和监控</li>
</ol>



<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>RESTful设计原则 HTTP状态码</title>
		<link>https://blog.mutadecheng.com/2025/04/23/restful%e8%ae%be%e8%ae%a1%e5%8e%9f%e5%88%99-http%e7%8a%b6%e6%80%81%e7%a0%81/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Wed, 23 Apr 2025 05:36:49 +0000</pubDate>
				<category><![CDATA[c#]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=320</guid>

					<description><![CDATA[1xx &#8211; 信息性状态码 这些状态码表示请求已被接收，继续处理。 2xx &#8211; 成功状态 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">1xx &#8211; 信息性状态码</h3>



<p>这些状态码表示请求已被接收，继续处理。</p>



<ul class="wp-block-list">
<li><strong>100 Continue</strong>：表示到目前为止一切正常，客户端应继续请求。如果请求已经完成，则忽略此响应。</li>



<li><strong>101 Switching Protocols</strong>：表示服务器正在根据客户端的请求切换协议。服务器将以Upgrade头部来指示所用的新协议。</li>
</ul>



<h3 class="wp-block-heading">2xx &#8211; 成功状态码</h3>



<p>表示请求已成功被服务器接收、理解，并接受。</p>



<ul class="wp-block-list">
<li><strong>200 OK</strong>：请求成功。响应将根据请求的方法而有所不同。例如，GET请求的响应将包含请求的资源。</li>



<li><strong>201 Created</strong>：请求成功，并且服务器创建了新的资源。通常用于POST请求，响应会包含新资源的URI。</li>



<li><strong>202 Accepted</strong>：请求已被接受用于处理，但尚未完成。没有任何保证服务器会完成处理。</li>



<li><strong>203 Non-Authoritative Information</strong>：服务器已成功处理请求，但返回的信息可能来自另一来源。</li>



<li><strong>204 No Content</strong>：服务器成功处理了请求，但没有返回任何内容。通常用于更新操作。</li>



<li><strong>205 Reset Content</strong>：告诉用户代理重置发送此请求的文档视图。</li>



<li><strong>206 Partial Content</strong>：服务器成功处理了部分GET请求。用于支持断点续传。</li>
</ul>



<h3 class="wp-block-heading">3xx &#8211; 重定向状态码</h3>



<p>表示要完成请求，需要进一步操作。</p>



<ul class="wp-block-list">
<li><strong>300 Multiple Choices</strong>：请求的资源有多种表示形式。用户或用户代理可以选择一个。</li>



<li><strong>301 Moved Permanently</strong>：请求的资源已被永久移动到新的URI。响应应包含新的URI。</li>



<li><strong>302 Found</strong>：请求的资源临时从不同的URI响应请求。与301不同，客户端应继续使用原始URI。</li>



<li><strong>303 See Other</strong>：对请求的响应可以在另一个URI上找到，客户端应使用GET方法请求该资源。</li>



<li><strong>304 Not Modified</strong>：资源未被修改，客户端可以继续使用缓存版本。</li>



<li><strong>307 Temporary Redirect</strong>：请求的资源临时从不同的URI响应请求。客户端应继续使用原始URI。</li>



<li><strong>308 Permanent Redirect</strong>：资源已被永久移动到新的URI，客户端应使用新的URI。</li>
</ul>



<h3 class="wp-block-heading">4xx &#8211; 客户端错误状态码</h3>



<p>表示请求包含错误，阻止服务器处理。</p>



<ul class="wp-block-list">
<li><strong>400 Bad Request</strong>：请求格式不正确，服务器无法理解请求。</li>



<li><strong>401 Unauthorized</strong>：请求需要用户验证。可能需要提供身份验证凭据。</li>



<li><strong>402 Payment Required</strong>：保留状态码，用于将来可能的支付需求。</li>



<li><strong>403 Forbidden</strong>：服务器理解请求但拒绝执行。通常是权限问题。</li>



<li><strong>404 Not Found</strong>：请求的资源不存在。</li>



<li><strong>405 Method Not Allowed</strong>：请求方法不支持该资源。例如，使用POST请求一个只读资源。</li>



<li><strong>406 Not Acceptable</strong>：请求的资源无法使用请求的内容特性响应。</li>



<li><strong>407 Proxy Authentication Required</strong>：客户端必须先通过代理进行身份验证。</li>



<li><strong>408 Request Timeout</strong>：请求超时，服务器等待请求时超出了允许的时间。</li>



<li><strong>409 Conflict</strong>：请求与资源的当前状态冲突。常用于并发更新。</li>



<li><strong>410 Gone</strong>：请求的资源不再可用，并且没有可用的转发地址。</li>



<li><strong>411 Length Required</strong>：服务器拒绝接受没有定义Content-Length头的请求。</li>



<li><strong>412 Precondition Failed</strong>：服务器不满足请求中设置的某个前提条件。</li>



<li><strong>413 Payload Too Large</strong>：请求实体过大，服务器无法处理。</li>



<li><strong>414 URI Too Long</strong>：请求的URI过长，服务器无法处理。</li>



<li><strong>415 Unsupported Media Type</strong>：请求的格式不受服务器支持。</li>



<li><strong>416 Range Not Satisfiable</strong>：请求的范围无法满足。</li>



<li><strong>417 Expectation Failed</strong>：服务器无法满足Expect请求头中的要求。</li>



<li><strong>418 I&#8217;m a teapot</strong>：这个是一个愚人节笑话状态码，表示“我是一个茶壶”。</li>
</ul>



<h3 class="wp-block-heading">5xx &#8211; 服务器错误状态码</h3>



<p>表示服务器在处理请求时发生了错误。</p>



<ul class="wp-block-list">
<li><strong>500 Internal Server Error</strong>：服务器遇到未预料的情况，无法完成请求。</li>



<li><strong>501 Not Implemented</strong>：服务器不支持请求的功能。通常是因为服务器无法识别请求的方法。</li>



<li><strong>502 Bad Gateway</strong>：服务器作为网关或代理，从上游服务器收到无效响应。</li>



<li><strong>503 Service Unavailable</strong>：服务器当前无法处理请求，通常是由于过载或维护。</li>



<li><strong>504 Gateway Timeout</strong>：服务器作为网关或代理，未能及时从上游服务器接收请求。</li>



<li><strong>505 HTTP Version Not Supported</strong>：服务器不支持请求中使用的HTTP协议版本。</li>
</ul>



<p>这些状态码帮助客户端理解请求的处理结果，并采取相应的后续操作。选择合适的状态码对于构建符合RESTful设计原则的API至关重要。</p>



<h2 class="wp-block-heading">ASP.NET Core 中使用</h2>



<p>在ASP.NET Core中，内置了多种结果类型（Result Types），用于在控制器中返回不同的HTTP响应。这些结果类型实现了<code>IActionResult</code>接口，可以帮助你更方便地返回合适的HTTP状态码和内容。以下是一些常用的内置结果类型：</p>



<h3 class="wp-block-heading">成功结果类型</h3>



<ul class="wp-block-list">
<li><strong>OkResult</strong>：返回HTTP 200 OK状态码，通常用于表示请求成功。</li>
</ul>



<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="  return Ok();" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Ok</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>OkObjectResult</strong>：返回HTTP 200 OK状态码，并包含一个对象作为响应体。</li>
</ul>



<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="  return Ok(object);" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Ok</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">object</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>CreatedResult</strong>：返回HTTP 201 Created状态码，并包含一个URI和对象作为响应体。</li>
</ul>



<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="  return Created(uri, object);" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Created</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">uri</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">object</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>CreatedAtRouteResult</strong>：返回HTTP 201 Created状态码，使用指定的路由名称和参数生成URI。</li>
</ul>



<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="  return CreatedAtRoute(&quot;RouteName&quot;, routeValues, object);" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">CreatedAtRoute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;RouteName&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">routeValues</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">object</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>NoContentResult</strong>：返回HTTP 204 No Content状态码，表示请求成功但没有内容返回。</li>
</ul>



<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="  return NoContent();" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">NoContent</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<h3 class="wp-block-heading">重定向结果类型</h3>



<ul class="wp-block-list">
<li><strong>RedirectResult</strong>：返回HTTP 302 Found状态码，重定向到指定的URL。</li>
</ul>



<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="  return Redirect(&quot;https://example.com&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: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Redirect</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;https://example.com&quot;</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>RedirectToActionResult</strong>：重定向到指定的控制器动作。</li>
</ul>



<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="  return RedirectToAction(&quot;ActionName&quot;, &quot;ControllerName&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: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">RedirectToAction</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ActionName&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;ControllerName&quot;</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>RedirectToRouteResult</strong>：重定向到指定的路由。</li>
</ul>



<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="  return RedirectToRoute(&quot;RouteName&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: #D4D4D4">  </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">RedirectToRoute</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;RouteName&quot;</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<h3 class="wp-block-heading">客户端错误结果类型</h3>



<ul class="wp-block-list">
<li><strong>BadRequestResult</strong>：返回HTTP 400 Bad Request状态码，表示请求格式错误。</li>
</ul>



<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="  return BadRequest();" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">BadRequest</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>BadRequestObjectResult</strong>：返回HTTP 400 Bad Request状态码，并包含错误信息。</li>
</ul>



<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="  return BadRequest(errorObject);" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">BadRequest</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">errorObject</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>UnauthorizedResult</strong>：返回HTTP 401 Unauthorized状态码，表示需要身份验证。</li>
</ul>



<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="  return Unauthorized();" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Unauthorized</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>ForbidResult</strong>：返回HTTP 403 Forbidden状态码，表示服务器拒绝请求。</li>
</ul>



<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="  return Forbid();" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Forbid</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>NotFoundResult</strong>：返回HTTP 404 Not Found状态码，表示资源未找到。</li>
</ul>



<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="  return NotFound();" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">NotFound</span><span style="color: #D4D4D4">();</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>NotFoundObjectResult</strong>：返回HTTP 404 Not Found状态码，并包含错误信息。</li>
</ul>



<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="  return NotFound(errorObject);" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">NotFound</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">errorObject</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<h3 class="wp-block-heading">服务器错误结果类型</h3>



<ul class="wp-block-list">
<li><strong>StatusCodeResult</strong>：返回指定的HTTP状态码。</li>
</ul>



<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="  return StatusCode(500);" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">StatusCode</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">500</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>ObjectResult</strong>：返回指定的HTTP状态码，并包含一个对象作为响应体。</li>
</ul>



<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="  return StatusCode(500, object);" 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: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">StatusCode</span><span style="color: #D4D4D4">(</span><span style="color: #B5CEA8">500</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">object</span><span style="color: #D4D4D4">);</span></span></code></pre></div>



<p>这些内置结果类型使得在ASP.NET Core中处理HTTP响应变得更加简洁和直观。可以根据具体需求选择合适的结果类型来返回HTTP响应。</p>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Microsoft.IdentityModel.Tokens 命名空间中的 TokenValidationParameters 类</title>
		<link>https://blog.mutadecheng.com/2025/04/23/microsoft-identitymodel-tokens-%e5%91%bd%e5%90%8d%e7%a9%ba%e9%97%b4%e4%b8%ad%e7%9a%84-tokenvalidationparameters-%e7%b1%bb/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Wed, 23 Apr 2025 01:38:55 +0000</pubDate>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[身份验证与授权]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=316</guid>

					<description><![CDATA[Microsoft.IdentityModel.Tokens 命名空间中的 TokenValidationPa [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p><code>Microsoft.IdentityModel.Tokens</code> 命名空间中的 <code>TokenValidationParameters</code> 类，用于配置和控制令牌验证的行为。以下是每个参数的含义和作用, 包括其在 JWT 令牌验证过程中的具体作用和可能的使用场景： </p>



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



<h3 class="wp-block-heading">Token Validation Parameters</h3>



<h4 class="wp-block-heading">1. AlgorithmValidator</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, TokenValidationParameters, bool></code></li>



<li><strong>作用</strong>: 验证令牌签名算法是否符合预期。</li>



<li><strong>使用场景</strong>: 限制使用不安全的算法，确保符合安全策略。</li>
</ul>



<h4 class="wp-block-heading">2. ActorValidationParameters</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>TokenValidationParameters</code></li>



<li><strong>作用</strong>: 提供用于验证嵌套 actor token 的参数。</li>



<li><strong>使用场景</strong>: 在 OAuth 2.0 委托场景中验证代表用户的服务。</li>
</ul>



<h4 class="wp-block-heading">3. AudienceValidator</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;IEnumerable&lt;string>, SecurityToken, TokenValidationParameters, bool></code></li>



<li><strong>作用</strong>: 自定义受众验证逻辑。</li>



<li><strong>使用场景</strong>: 实现复杂的受众验证规则。</li>
</ul>



<h4 class="wp-block-heading">4. _authenticationType</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>string</code></li>



<li><strong>作用</strong>: 标识身份验证类型。</li>



<li><strong>使用场景</strong>: 用于标记或区分不同的身份验证过程。</li>
</ul>



<h4 class="wp-block-heading">5. ClockSkew</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>TimeSpan</code></li>



<li><strong>作用</strong>: 定义允许的时间偏移量。</li>



<li><strong>使用场景</strong>: 解决服务器间时钟不同步的问题。</li>
</ul>



<h4 class="wp-block-heading">6. ConfigurationManager</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>IConfigurationManager&lt;OpenIdConnectConfiguration></code></li>



<li><strong>作用</strong>: 管理和获取动态配置。</li>



<li><strong>使用场景</strong>: 动态获取远程服务器的配置。</li>
</ul>



<h4 class="wp-block-heading">7. CryptoProviderFactory</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>CryptoProviderFactory</code></li>



<li><strong>作用</strong>: 提供加密操作的工厂类。</li>



<li><strong>使用场景</strong>: 创建加密器、解密器、签名器等。</li>
</ul>



<h4 class="wp-block-heading">8. DebugId</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>string</code></li>



<li><strong>作用</strong>: 用于调试的标识符。</li>



<li><strong>使用场景</strong>: 在调试或日志记录过程中，帮助识别和追踪特定的验证请求。</li>
</ul>



<h4 class="wp-block-heading">9. IncludeTokenOnFailedValidation</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示在验证失败时是否包含令牌。</li>



<li><strong>使用场景</strong>: 调试和记录，但需注意安全性。</li>
</ul>



<h4 class="wp-block-heading">10. IgnoreTrailingSlashWhenValidatingAudience</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示在验证受众时是否忽略 URL 的尾部斜杠。</li>



<li><strong>使用场景</strong>: 允许在验证受众时忽略 URL 尾部斜杠的差异。</li>
</ul>



<h4 class="wp-block-heading">11. IssuerSigningKey</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>SecurityKey</code></li>



<li><strong>作用</strong>: 用于验证令牌签名的单个密钥。</li>



<li><strong>使用场景</strong>: 提供签名密钥进行验证。</li>
</ul>



<h4 class="wp-block-heading">12. IssuerSigningKeyResolver</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, string, TokenValidationParameters, IEnumerable&lt;SecurityKey>></code></li>



<li><strong>作用</strong>: 动态解析签名密钥的委托。</li>



<li><strong>使用场景</strong>: 签名密钥动态变化时解析正确的密钥。</li>
</ul>



<h4 class="wp-block-heading">13. IssuerSigningKeyResolverUsingConfiguration</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, string, TokenValidationParameters, IEnumerable&lt;SecurityKey>></code></li>



<li><strong>作用</strong>: 使用配置解析签名密钥的委托。</li>



<li><strong>使用场景</strong>: 依赖配置管理器的动态变化来解析签名密钥。</li>
</ul>



<h4 class="wp-block-heading">14. IssuerSigningKeys</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>IEnumerable&lt;SecurityKey></code></li>



<li><strong>作用</strong>: 用于验证令牌签名的密钥集合。</li>



<li><strong>使用场景</strong>: 当支持多个签名密钥时，提供一个密钥列表供选择。</li>
</ul>



<h4 class="wp-block-heading">15. IssuerSigningKeyValidator</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;SecurityKey, SecurityToken, TokenValidationParameters, bool></code></li>



<li><strong>作用</strong>: 自定义签名密钥验证逻辑。</li>



<li><strong>使用场景</strong>: 对签名密钥进行额外验证（如检查密钥来源）。</li>
</ul>



<h4 class="wp-block-heading">16. IssuerSigningKeyValidatorUsingConfiguration</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;SecurityKey, SecurityToken, TokenValidationParameters, bool></code></li>



<li><strong>作用</strong>: 使用配置的签名密钥验证委托。</li>



<li><strong>使用场景</strong>: 依赖配置进行密钥验证。</li>
</ul>



<h4 class="wp-block-heading">17. IssuerValidator</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, TokenValidationParameters, string></code></li>



<li><strong>作用</strong>: 自定义颁发者验证逻辑。</li>



<li><strong>使用场景</strong>: 实现复杂的颁发者验证规则。</li>
</ul>



<h4 class="wp-block-heading">18. IssuerValidatorAsync</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, TokenValidationParameters, Task&lt;string>></code></li>



<li><strong>作用</strong>: 异步自定义颁发者验证逻辑。</li>



<li><strong>使用场景</strong>: 当颁发者验证涉及异步操作时，使用此委托。</li>
</ul>



<h4 class="wp-block-heading">19. IssuerValidatorUsingConfiguration</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, TokenValidationParameters, string></code></li>



<li><strong>作用</strong>: 使用配置的颁发者验证委托。</li>



<li><strong>使用场景</strong>: 依赖配置的动态变化来验证颁发者。</li>
</ul>



<h4 class="wp-block-heading">20. LifetimeValidator</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;DateTime?, DateTime?, SecurityToken, TokenValidationParameters, bool></code></li>



<li><strong>作用</strong>: 自定义令牌有效期验证逻辑。</li>



<li><strong>使用场景</strong>: 实现特定的有效期验证规则。</li>
</ul>



<h4 class="wp-block-heading">21. LogTokenId</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否记录令牌 ID。</li>



<li><strong>使用场景</strong>: 用于审计和日志记录，以便在日志中跟踪特定令牌。</li>
</ul>



<h4 class="wp-block-heading">22. LogValidationExceptions</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否记录验证异常。</li>



<li><strong>使用场景</strong>: 用于调试和监控，记录验证过程中发生的异常。</li>
</ul>



<h4 class="wp-block-heading">23. NameClaimType</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>string</code></li>



<li><strong>作用</strong>: 指定从令牌中提取用户名称的声明类型。</li>



<li><strong>使用场景</strong>: 指定哪个声明用于标识用户名称。</li>
</ul>



<h4 class="wp-block-heading">24. NameClaimTypeRetriever</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;IEnumerable&lt;Claim>, string></code></li>



<li><strong>作用</strong>: 自定义名称声明类型的检索逻辑。</li>



<li><strong>使用场景</strong>: 动态决定使用哪个名称声明时，通过此委托实现。</li>
</ul>



<h4 class="wp-block-heading">25. PropertyBag</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>IDictionary&lt;string, object></code></li>



<li><strong>作用</strong>: 用于存储额外属性的字典。</li>



<li><strong>使用场景</strong>: 在验证过程中传递和存储自定义数据，如上下文信息。</li>
</ul>



<h4 class="wp-block-heading">26. RefreshBeforeValidation</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示在验证令牌之前是否刷新配置。</li>



<li><strong>使用场景</strong>: 在配置可能更新的环境中，确保使用最新的配置进行验证。</li>
</ul>



<h4 class="wp-block-heading">27. RequireAudience</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示验证过程中是否需要受众声明。</li>



<li><strong>使用场景</strong>: 确保令牌有明确的受众，防止令牌被误用。</li>
</ul>



<h4 class="wp-block-heading">28. RequireExpirationTime</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示验证过程中是否需要过期时间声明。</li>



<li><strong>使用场景</strong>: 确保令牌有明确的有效期，防止无期限令牌被长期使用。</li>
</ul>



<h4 class="wp-block-heading">29. RequireSignedTokens</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示验证过程中是否需要令牌是签名的。</li>



<li><strong>使用场景</strong>: 确保令牌的完整性和真实性。</li>
</ul>



<h4 class="wp-block-heading">30. RoleClaimType</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>string</code></li>



<li><strong>作用</strong>: 指定从令牌中提取用户角色的声明类型。</li>



<li><strong>使用场景</strong>: 指定哪个声明用于标识用户角色。</li>
</ul>



<h4 class="wp-block-heading">31. RoleClaimTypeRetriever</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;IEnumerable&lt;Claim>, string></code></li>



<li><strong>作用</strong>: 自定义角色声明类型的检索逻辑。</li>



<li><strong>使用场景</strong>: 动态决定使用哪个角色声明时，通过此委托实现。</li>
</ul>



<h4 class="wp-block-heading">32. SaveSigninToken</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示在身份验证成功后是否保存令牌。</li>



<li><strong>使用场景</strong>: 用于后续处理或审计目的，保存成功验证的令牌。</li>
</ul>



<h4 class="wp-block-heading">33. SignatureValidator</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, TokenValidationParameters, SecurityToken></code></li>



<li><strong>作用</strong>: 自定义签名验证逻辑。</li>



<li><strong>使用场景</strong>: 实现特定的签名验证策略。</li>
</ul>



<h4 class="wp-block-heading">34. SignatureValidatorUsingConfiguration</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, TokenValidationParameters, SecurityToken></code></li>



<li><strong>作用</strong>: 使用配置的签名验证委托。</li>



<li><strong>使用场景</strong>: 依赖配置的动态变化来进行签名验证。</li>
</ul>



<h4 class="wp-block-heading">35. TokenDecryptionKey</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>SecurityKey</code></li>



<li><strong>作用</strong>: 用于解密令牌的单个密钥。</li>



<li><strong>使用场景</strong>: 提供解密密钥进行验证。</li>
</ul>



<h4 class="wp-block-heading">36. TokenDecryptionKeyResolver</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, string, TokenValidationParameters, IEnumerable&lt;SecurityKey>></code></li>



<li><strong>作用</strong>: 动态解析解密密钥的委托。</li>



<li><strong>使用场景</strong>: 解密密钥动态变化时，通过此委托解析正确的密钥。</li>
</ul>



<h4 class="wp-block-heading">37. TokenDecryptionKeys</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>IEnumerable&lt;SecurityKey></code></li>



<li><strong>作用</strong>: 用于解密令牌的密钥集合。</li>



<li><strong>使用场景</strong>: 当支持多个解密密钥时，提供一个密钥列表供选择。</li>
</ul>



<h4 class="wp-block-heading">38. TokenReader</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken></code></li>



<li><strong>作用</strong>: 自定义令牌读取逻辑。</li>



<li><strong>使用场景</strong>: 在解析和处理令牌时需要特定的读取逻辑。</li>
</ul>



<h4 class="wp-block-heading">39. TokenReplayCache</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>ITokenReplayCache</code></li>



<li><strong>作用</strong>: 用于存储令牌重放信息的缓存。</li>



<li><strong>使用场景</strong>: 防止令牌重放攻击，通过缓存已使用的令牌 ID。</li>
</ul>



<h4 class="wp-block-heading">40. TokenReplayValidator</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, DateTime, TokenValidationParameters, bool></code></li>



<li><strong>作用</strong>: 自定义令牌重放验证逻辑。</li>



<li><strong>使用场景</strong>: 需要特定的重放攻击防护策略时，通过此委托实现。</li>
</ul>



<h4 class="wp-block-heading">41. TransformBeforeSignatureValidation</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, TokenValidationParameters, string></code></li>



<li><strong>作用</strong>: 在签名验证之前对令牌进行转换。</li>



<li><strong>使用场景</strong>: 需要对令牌进行预处理以便验证时使用。</li>
</ul>



<h4 class="wp-block-heading">42. TryAllIssuerSigningKeys</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否尝试使用所有提供的签名密钥进行验证。</li>



<li><strong>使用场景</strong>: 当有多个潜在的签名密钥时，尝试所有可能的密钥进行验证。</li>
</ul>



<h4 class="wp-block-heading">43. TypeValidator</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>Func&lt;string, SecurityToken, TokenValidationParameters, bool></code></li>



<li><strong>作用</strong>: 自定义令牌类型验证逻辑。</li>



<li><strong>使用场景</strong>: 确保令牌类型符合预期，防止不正确类型的令牌被使用。</li>
</ul>



<h4 class="wp-block-heading">44. ValidateActor</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否应该验证嵌套令牌。</li>



<li><strong>使用场景</strong>: 在处理嵌套令牌时，确保其有效性和真实性。</li>
</ul>



<h4 class="wp-block-heading">45. ValidateAudience</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否应该验证令牌的受众声明。</li>



<li><strong>使用场景</strong>: 确保令牌的受众与预期一致，防止令牌被不当使用。</li>
</ul>



<h4 class="wp-block-heading">46. ValidateIssuer</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否应该验证令牌的颁发者声明。</li>



<li><strong>使用场景</strong>: 确保令牌的颁发者是可信的，防止伪造的令牌。</li>
</ul>



<h4 class="wp-block-heading">47. ValidateIssuerSigningKey</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否应该验证令牌的签名密钥。</li>



<li><strong>使用场景</strong>: 确保使用正确的密钥进行签名验证，防止签名被伪造。</li>
</ul>



<h4 class="wp-block-heading">48. ValidateLifetime</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否应该验证令牌的有效期。</li>



<li><strong>使用场景</strong>: 确保令牌在有效期内使用，防止过期令牌被使用。</li>
</ul>



<h4 class="wp-block-heading">49. ValidateSignatureLast</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否应该在最后进行签名验证。</li>



<li><strong>使用场景</strong>: 当有特定的验证顺序需求时，确保签名验证在其他验证之后进行。</li>
</ul>



<h4 class="wp-block-heading">50. ValidateTokenReplay</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否应该验证令牌是否被重放。</li>



<li><strong>使用场景</strong>: 防止令牌重放攻击，确保每个令牌仅被使用一次。</li>
</ul>



<h4 class="wp-block-heading">51. ValidateWithLKG</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>bool</code></li>



<li><strong>作用</strong>: 指示是否应该使用最后已知良好的配置进行验证。</li>



<li><strong>使用场景</strong>: 在配置更新失败的情况下，使用最后已知的有效配置进行验证。</li>
</ul>



<h4 class="wp-block-heading">52. ValidAlgorithms</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>IEnumerable&lt;string></code></li>



<li><strong>作用</strong>: 指定允许的签名算法。</li>



<li><strong>使用场景</strong>: 限制令牌签名算法，以确保使用符合安全策略的算法。</li>
</ul>



<h4 class="wp-block-heading">53. ValidAudience</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>string</code></li>



<li><strong>作用</strong>: 指定允许的单个受众。</li>



<li><strong>使用场景</strong>: 确保令牌的受众与预期的单个受众匹配。</li>
</ul>



<h4 class="wp-block-heading">54. ValidAudiences</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>IEnumerable&lt;string></code></li>



<li><strong>作用</strong>: 指定允许的受众集合。</li>



<li><strong>使用场景</strong>: 当令牌可能有多个受众时，提供一个受众列表进行匹配。</li>
</ul>



<h4 class="wp-block-heading">55. ValidIssuer</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>string</code></li>



<li><strong>作用</strong>: 指定允许的单个颁发者。</li>



<li><strong>使用场景</strong>: 确保令牌的颁发者与预期的单个颁发者匹配。</li>
</ul>



<h4 class="wp-block-heading">56. ValidIssuers</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>IEnumerable&lt;string></code></li>



<li><strong>作用</strong>: 指定允许的颁发者集合。</li>



<li><strong>使用场景</strong>: 当令牌可能来自多个颁发者时，提供一个颁发者列表进行匹配。</li>
</ul>



<h4 class="wp-block-heading">57. ValidTypes</h4>



<ul class="wp-block-list">
<li><strong>属性类型</strong>: <code>IEnumerable&lt;string></code></li>



<li><strong>作用</strong>: 指定允许的令牌类型。</li>



<li><strong>使用场景</strong>: 确保令牌类型符合预期，防止不符合要求的令牌被使用。</li>
</ul>



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



<p>这些参数用于配置和控制令牌验证过程，确保应用程序的安全性和可靠性。通过合理配置这些参数，可以应对不同的业务需求和安全要求。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Quartz.NET 基础概念</title>
		<link>https://blog.mutadecheng.com/2025/03/19/quartz-net-%e5%9f%ba%e7%a1%80%e6%a6%82%e5%bf%b5/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Wed, 19 Mar 2025 08:30:10 +0000</pubDate>
				<category><![CDATA[c#]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=304</guid>

					<description><![CDATA[在 Quartz.NET 中，Job 和 Trigger 是两个核心概念，它们通过调度器（Scheduler） [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>在 Quartz.NET 中，Job 和 Trigger 是两个核心概念，它们通过调度器（Scheduler）进行管理和执行。为了帮助你理解它们之间的关系，以及任务组和触发器组的关系，我将通过文字描述一个思维导图的结构：</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="Quartz.NET
├── Scheduler
│   ├── Job
│   │   ├── JobDetail
│   │   │   ├── JobKey (JobName, JobGroup)
│   │   │   └── JobDataMap
│   │   └── IJob (Job Interface)
│   ├── Trigger
│   │   ├── TriggerDetail
│   │   │   ├── TriggerKey (TriggerName, TriggerGroup)
│   │   │   ├── TriggerDataMap
│   │   │   └── Schedule (Cron, Simple, etc.)
│   └── Listener
│       ├── JobListener
│       └── TriggerListener" 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">Quartz.NET</span></span>
<span class="line"><span style="color: #DCDCAA">├──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Scheduler</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">├──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Job</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">├──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">JobDetail</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">├──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">JobKey</span><span style="color: #D4D4D4"> (JobName, </span><span style="color: #CE9178">JobGroup</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">└──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">JobDataMap</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">└──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">IJob</span><span style="color: #D4D4D4"> (Job </span><span style="color: #CE9178">Interface</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">├──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Trigger</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">├──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">TriggerDetail</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">├──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">TriggerKey</span><span style="color: #D4D4D4"> (TriggerName, </span><span style="color: #CE9178">TriggerGroup</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">├──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">TriggerDataMap</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">└──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Schedule</span><span style="color: #D4D4D4"> (Cron, </span><span style="color: #CE9178">Simple,</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">etc.</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">   </span><span style="color: #CE9178">└──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">Listener</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">       </span><span style="color: #CE9178">├──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">JobListener</span></span>
<span class="line"><span style="color: #DCDCAA">│</span><span style="color: #D4D4D4">       </span><span style="color: #CE9178">└──</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">TriggerListener</span></span></code></pre></div>



<h3 class="wp-block-heading">解释：</h3>



<ol class="wp-block-list">
<li><strong>Scheduler（调度器）</strong>：</li>
</ol>



<ul class="wp-block-list">
<li>管理和协调 Job 和 Trigger 的执行。</li>



<li>可以注册多个 Job 和 Trigger。</li>
</ul>



<ol class="wp-block-list">
<li><strong>Job（任务）</strong>：</li>
</ol>



<ul class="wp-block-list">
<li><strong>JobDetail</strong>：包含 Job 的定义信息。
<ul class="wp-block-list">
<li><strong>JobKey</strong>：由 JobName 和 JobGroup 组成，用于唯一标识一个 Job。</li>



<li><strong>JobDataMap</strong>：用于存储 Job 的参数和数据。</li>
</ul>
</li>



<li><strong>IJob</strong>：所有任务必须实现的接口，定义了 <code>Execute</code> 方法。</li>
</ul>



<ol class="wp-block-list">
<li><strong>Trigger（触发器）</strong>：</li>
</ol>



<ul class="wp-block-list">
<li><strong>TriggerDetail</strong>：包含 Trigger 的定义信息。
<ul class="wp-block-list">
<li><strong>TriggerKey</strong>：由 TriggerName 和 TriggerGroup 组成，用于唯一标识一个 Trigger。</li>



<li><strong>TriggerDataMap</strong>：用于存储 Trigger 的参数和数据。</li>



<li><strong>Schedule</strong>：定义触发器的调度策略，比如 Cron 表达式或简单时间间隔。</li>
</ul>
</li>
</ul>



<ol class="wp-block-list">
<li><strong>Listener（监听器）</strong>：</li>
</ol>



<ul class="wp-block-list">
<li><strong>JobListener</strong> 和 <strong>TriggerListener</strong>：用于监听 Job 和 Trigger 的执行事件。</li>
</ul>



<h3 class="wp-block-heading">关系：</h3>



<ul class="wp-block-list">
<li>一个 <strong>Job</strong> 可以与一个或多个 <strong>Trigger</strong> 关联。</li>



<li><strong>JobGroup</strong> 和 <strong>TriggerGroup</strong> 是用于组织和管理 Job 和 Trigger 的逻辑分组。</li>



<li><strong>Scheduler</strong> 负责协调 Job 和 Trigger 的执行，确保在指定的时间和条件下执行 Job。</li>
</ul>



<p>这种结构允许灵活地定义和管理任务调度逻辑，支持复杂的调度需求。</p>



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



<div class="wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-8cf370e7 wp-block-group-is-layout-flex">
<p>我有一个webapi 功能是:<br>定时启用运行多个dll, dll 是随时增加改变的</p>



<p>用户想创建一个任务定时运行dll, 下面哪种方式好?好在哪?</p>



<p>1.创造一个job同时创建触发器,用户数据存在JobDataMap中<br>2.不创建新的job,只创建Trigger,用户数据存在TriggerDataMap中</p>
</div>



<p>在 Quartz.NET 中，选择如何存储用户数据以及如何管理任务和触发器的关系，取决于你的具体需求和应用场景。对于你的用例，即需要定时运行多个 DLL，并且这些 DLL 是动态增加和变化的，下面是对两种方案的分析：</p>



<h3 class="wp-block-heading">方案1：创建一个Job同时创建触发器，用户数据存在JobDataMap中</h3>



<p><strong>优点：</strong></p>



<ul class="wp-block-list">
<li><strong>清晰的职责分离</strong>：Job 负责执行逻辑，Trigger 负责调度。这种分离使得代码结构更清晰。</li>



<li><strong>易于管理和扩展</strong>：每个 Job 可以有自己的逻辑和数据，这使得管理不同的任务变得更加灵活。</li>



<li><strong>单一责任原则</strong>：Job 只需关注执行任务的逻辑，而不需要关心何时执行。</li>
</ul>



<p><strong>适用场景：</strong></p>



<ul class="wp-block-list">
<li>当每个 DLL 的执行逻辑较为复杂，需要单独的配置和数据。</li>



<li>当需要对不同的 Job 进行独立的管理和监控时。</li>
</ul>



<h3 class="wp-block-heading">方案2：不创建新的Job，只创建Trigger，用户数据存在TriggerDataMap中</h3>



<p><strong>优点：</strong></p>



<ul class="wp-block-list">
<li><strong>减少Job的数量</strong>：如果所有 DLL 的执行逻辑相似或相同，可以通过一个通用的 Job 来执行所有任务。</li>



<li><strong>更少的资源占用</strong>：减少 Job 的数量可能会减少调度器的管理开销。</li>
</ul>



<p><strong>适用场景：</strong></p>



<ul class="wp-block-list">
<li>当所有 DLL 的执行逻辑相同或非常相似，只是数据不同。</li>



<li>当系统资源有限，需要尽可能减少 Job 的数量。</li>
</ul>



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



<p>如果每个 DLL 的执行逻辑可能不同，或者需要不同的配置和数据，建议使用<strong>方案1</strong>。这种方式提供了更高的灵活性和可维护性。</p>



<p>如果所有 DLL 的执行逻辑基本相同，并且你希望通过一个通用的机制来处理所有任务，<strong>方案2</strong> 可能更为合适。这种方式可以减少管理的复杂性和资源占用。 </p>



<p></p>



<h2 class="wp-block-heading">关于多个触发器的探讨</h2>



<p>当一个作业有多个触发器，并且每个触发器都使用 <code>.UsingJobData("ExampleKey", "ExampleValue")</code> 来传递不同的数据时，作业执行时使用的是触发当前执行的触发器所提供的数据。</p>



<h3 class="wp-block-heading">具体行为</h3>



<ol class="wp-block-list">
<li><strong>触发器级别的数据优先</strong>：当作业被一个触发器触发时，Quartz.NET 会将该触发器的 <code>JobDataMap</code> 合并到作业的 <code>JobDataMap</code> 中。因此，如果触发器和作业都定义了同一个键，触发器的数据将覆盖作业的数据。</li>



<li><strong>访问数据</strong>：在作业的 <code>Execute</code> 方法中，使用 <code>context.Trigger.JobDataMap</code> 可以直接访问触发器级别的数据，而使用 <code>context.MergedJobDataMap</code> 可以访问合并后的数据（触发器数据优先）。</li>
</ol>



<h3 class="wp-block-heading">示例</h3>



<p>假设你有以下两个触发器，它们分别设置了不同的 <code>ExampleKey</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="// 触发器1
var trigger1 = TriggerBuilder.Create()
    .WithIdentity(&quot;trigger1&quot;, &quot;group1&quot;)
    .ForJob(jobKey)
    .UsingJobData(&quot;ExampleKey&quot;, &quot;ValueFromTrigger1&quot;)
    .Build();

// 触发器2
var trigger2 = TriggerBuilder.Create()
    .WithIdentity(&quot;trigger2&quot;, &quot;group1&quot;)
    .ForJob(jobKey)
    .UsingJobData(&quot;ExampleKey&quot;, &quot;ValueFromTrigger2&quot;)
    .Build();" 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">// 触发器1</span></span>
<span class="line"><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">trigger1</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">TriggerBuilder</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Create</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    .</span><span style="color: #DCDCAA">WithIdentity</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;trigger1&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;group1&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    .</span><span style="color: #DCDCAA">ForJob</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">jobKey</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    .</span><span style="color: #DCDCAA">UsingJobData</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ExampleKey&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;ValueFromTrigger1&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    .</span><span style="color: #DCDCAA">Build</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955">// 触发器2</span></span>
<span class="line"><span style="color: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">trigger2</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">TriggerBuilder</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">Create</span><span style="color: #D4D4D4">()</span></span>
<span class="line"><span style="color: #D4D4D4">    .</span><span style="color: #DCDCAA">WithIdentity</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;trigger2&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;group1&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    .</span><span style="color: #DCDCAA">ForJob</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">jobKey</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    .</span><span style="color: #DCDCAA">UsingJobData</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ExampleKey&quot;</span><span style="color: #D4D4D4">, </span><span style="color: #CE9178">&quot;ValueFromTrigger2&quot;</span><span style="color: #D4D4D4">)</span></span>
<span class="line"><span style="color: #D4D4D4">    .</span><span style="color: #DCDCAA">Build</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="public class MyJob : IJob
{
    public Task Execute(IJobExecutionContext context)
    {
        // 获取触发器数据
        var exampleValueFromTrigger = context.Trigger.JobDataMap.GetString(&quot;ExampleKey&quot;);

        // 获取合并后的数据（触发器数据优先）
        var exampleValueMerged = context.MergedJobDataMap.GetString(&quot;ExampleKey&quot;);

        Console.WriteLine($&quot;Trigger Data: {exampleValueFromTrigger}&quot;);
        Console.WriteLine($&quot;Merged Data: {exampleValueMerged}&quot;);

        return Task.CompletedTask;
    }
}" 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">MyJob</span><span style="color: #D4D4D4"> : </span><span style="color: #4EC9B0">IJob</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: #4EC9B0">Task</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">Execute</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">IJobExecutionContext</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">context</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: #569CD6">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">exampleValueFromTrigger</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">context</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Trigger</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">JobDataMap</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetString</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ExampleKey&quot;</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">var</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">exampleValueMerged</span><span style="color: #D4D4D4"> = </span><span style="color: #9CDCFE">context</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">MergedJobDataMap</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">GetString</span><span style="color: #D4D4D4">(</span><span style="color: #CE9178">&quot;ExampleKey&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></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;Trigger Data: {</span><span style="color: #9CDCFE">exampleValueFromTrigger</span><span style="color: #CE9178">}&quot;</span><span style="color: #D4D4D4">);</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;Merged Data: {</span><span style="color: #9CDCFE">exampleValueMerged</span><span style="color: #CE9178">}&quot;</span><span style="color: #D4D4D4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">Task</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">CompletedTask</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>trigger1</code> 触发时，<code>ExampleKey</code> 的值将是 <code>ValueFromTrigger1</code>。当被 <code>trigger2</code> 触发时，值将是 <code>ValueFromTrigger2</code>。因此，作业执行时使用的是当前触发的触发器所提供的数据。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>高并发的 IoT 环境中，处理共享的“总配置表”的探讨</title>
		<link>https://blog.mutadecheng.com/2025/02/18/%e9%ab%98%e5%b9%b6%e5%8f%91%e7%9a%84-iot-%e7%8e%af%e5%a2%83%e4%b8%ad%ef%bc%8c%e5%a4%84%e7%90%86%e5%85%b1%e4%ba%ab%e7%9a%84%e6%80%bb%e9%85%8d%e7%bd%ae%e8%a1%a8%e7%9a%84%e6%8e%a2/</link>
		
		<dc:creator><![CDATA[木它]]></dc:creator>
		<pubDate>Tue, 18 Feb 2025 13:57:32 +0000</pubDate>
				<category><![CDATA[c#]]></category>
		<category><![CDATA[Iot]]></category>
		<guid isPermaLink="false">https://blog.mutadecheng.com/?p=287</guid>

					<description><![CDATA[在高并发的 IoT 环境中，处理共享的“总配置表”可能会面临挑战，特别是当多个设备需要实时访问和修改这些配置时 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>在高并发的 IoT 环境中，处理共享的“总配置表”可能会面临挑战，特别是当多个设备需要实时访问和修改这些配置时。为了有效地管理这种环境，可以考虑以下策略：</p>



<h3 class="wp-block-heading">1. <strong>分区配置</strong></h3>



<p>将“总配置表”按设备或设备组进行分区，从而减少单个配置对象的访问争用。每个设备或设备组拥有自己的配置实例，这样可以减少锁争用，提高并发访问的性能。</p>



<h3 class="wp-block-heading">2. <strong>读写锁（ReaderWriterLockSlim）</strong></h3>



<p>使用 <code>ReaderWriterLockSlim</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="private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

private async Task<SensorHisEntity?&gt; ProcessPerDataAsync(SensorParamData sensorParamData)
{
    SensorHisEntity? result = null;
    _lock.EnterWriteLock();
    try
    {
        if (!_sensorParamConfigDic.TryGetValue(sensorParamData.Id, out SensorParamConfig config))
        {
            return default;
        }

        // 处理逻辑
        result = ProcessConfig(sensorParamData, config);
    }
    finally
    {
        _lock.ExitWriteLock();
    }
    return result;
}" 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">private</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">readonly</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ReaderWriterLockSlim</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">_lock</span><span style="color: #D4D4D4"> = </span><span style="color: #569CD6">new</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">ReaderWriterLockSlim</span><span style="color: #D4D4D4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #569CD6">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">&lt;</span><span style="color: #4EC9B0">SensorHisEntity</span><span style="color: #D4D4D4">?&gt; </span><span style="color: #DCDCAA">ProcessPerDataAsync</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">SensorParamData</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">sensorParamData</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">SensorHisEntity</span><span style="color: #D4D4D4">? </span><span style="color: #9CDCFE">result</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">_lock</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">EnterWriteLock</span><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: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> (!</span><span style="color: #9CDCFE">_sensorParamConfigDic</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">TryGetValue</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">sensorParamData</span><span style="color: #D4D4D4">.</span><span style="color: #9CDCFE">Id</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">out</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">SensorParamConfig</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">config</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: #569CD6">default</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: #9CDCFE">result</span><span style="color: #D4D4D4"> = </span><span style="color: #DCDCAA">ProcessConfig</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">sensorParamData</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">config</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">finally</span></span>
<span class="line"><span style="color: #D4D4D4">    {</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #9CDCFE">_lock</span><span style="color: #D4D4D4">.</span><span style="color: #DCDCAA">ExitWriteLock</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">result</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">}</span></span></code></pre></div>



<h3 class="wp-block-heading">3. <strong>乐观并发控制</strong></h3>



<p>使用乐观并发控制策略，例如版本号或时间戳。每次读取配置时，记录当前的版本号或时间戳，在更新时检查配置是否发生了变化。如果配置已被其他线程修改，则重新读取并重试。</p>



<h3 class="wp-block-heading">4. <strong>缓存与异步更新</strong></h3>



<p>利用缓存机制来减少对“总配置表”的直接访问。将配置加载到内存中，并在内存中进行读取和部分计算。在后台异步地将更改写回数据库或持久化存储中。</p>



<h3 class="wp-block-heading">5. <strong>消息队列</strong></h3>



<p>使用消息队列（如 Kafka、RabbitMQ）来分发配置更新事件。每个设备可以订阅相关的配置更新消息，这样可以减少直接对“总配置表”的频繁访问。</p>



<h3 class="wp-block-heading">6. <strong>分布式配置管理</strong></h3>



<p>对于大规模 IoT 部署，使用分布式配置管理工具（如 Consul、Etcd、Zookeeper）来管理配置。这些工具提供了强大的一致性和可用性保证，适合处理复杂的配置管理需求。</p>



<h3 class="wp-block-heading">7. <strong>数据库优化</strong></h3>



<p>在数据库层面进行优化，确保配置表的索引和查询性能。使用专门的数据库方案（如 NoSQL 数据库）来处理高并发的读写操作。</p>



<p>选择适合具体需求的策略，通常需要结合多种方案来达到最佳效果。特别是在 IoT 环境中，设备数量多，数据流量大，系统需要在性能、可扩展性和数据一致性之间找到平衡。</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>
	</channel>
</rss>
