Archived
deploy.
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>DictionaryService and DictionaryHub Pattern | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="DictionaryService and DictionaryHub Pattern | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="Anatomy-DictionaryServicePattern">
|
||||
<h1 id="dictionaryservice-and-dictionaryhub-pattern">DictionaryService and DictionaryHub Pattern</h1>
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>A connection-scoped indexing pattern for referencing backend objects across hierarchical SignalR hub connections.</p>
|
||||
<h2 id="core-components">Core Components</h2>
|
||||
<p><code>DictionaryService</code>: Manages connection-scoped index dictionaries</p>
|
||||
<ul>
|
||||
<li>First layer key: Hub connectionId (auto-generated by SignalR)</li>
|
||||
<li>Second layer key: LocalId (resource name)</li>
|
||||
<li>Value: References to backend objects (functions, getters/setters)</li>
|
||||
</ul>
|
||||
<p><code>DictionaryHub</code>: Base hub that auto-cleans index entries on disconnect</p>
|
||||
<h2 id="architecture">Architecture</h2>
|
||||
<pre><code>Root-Hub
|
||||
└── Child-Hub - has parent's connectionId
|
||||
└── Grandchild-Hub - has parent's connectionId
|
||||
</code></pre>
|
||||
<p>Each hub gets a unique system-generated hub-connectionId. Child hubs receive parent's connectionId to access parent data.</p>
|
||||
<h2 id="key-patterns">Key Patterns</h2>
|
||||
<ol>
|
||||
<li><strong>Parent ConnectionId Passing</strong>: Child hubs copy parent's function references via connectionId</li>
|
||||
<li><strong>Frontend ConnectionId Chain</strong>: Components pass connectionId down the hierarchy</li>
|
||||
<li><strong>Wrapper Function Pattern</strong>: Child hubs should create wrapper functions that dynamically retrieve and invoke parent functions at runtime, rather than directly copying references. This ensures type safety through runtime checking and supports dynamic function updates from the parent.</li>
|
||||
</ol>
|
||||
<h2 id="benefits">Benefits</h2>
|
||||
<ul>
|
||||
<li><strong>Isolation</strong>: Each component has its own connection/index space</li>
|
||||
<li><strong>Nesting Support</strong>: Same components can be nested without conflicts</li>
|
||||
<li><strong>Auto-cleanup</strong>: Index entries cleaned on disconnect</li>
|
||||
<li><strong>Data Inheritance</strong>: Access parent's backend objects via connectionId chain</li>
|
||||
</ul>
|
||||
<h2 id="best-practices">Best Practices</h2>
|
||||
<ul>
|
||||
<li>Apply or inherit from DictionaryHub for auto-cleanup</li>
|
||||
<li>Use meaningful key names (e.g., “transformer-getter”)</li>
|
||||
<li>Always setup dictionary functions unconditionally during initialization - put condition checks inside the functions, not around the setup. This ensures child panels can access functions even when parent objects temporarily don't meet the conditions.</li>
|
||||
</ul>
|
||||
<h2 id="common-pitfalls">Common Pitfalls</h2>
|
||||
<ul>
|
||||
<li>Don't use child's connectionId to index parent's data</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,158 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>GUI File Path Assignment | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="GUI File Path Assignment | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="Anatomy-GuiFilePathAssignment">
|
||||
<h1 id="gui-file-path-assignment">GUI File Path Assignment</h1>
|
||||
|
||||
<p>See the remarks of <a class="xref" href="../../api/Hi.Common.XmlUtils.IMakeXmlSource.html#Hi_Common_XmlUtils_IMakeXmlSource_MakeXmlSource_System_String_System_String_System_Boolean_">MakeXmlSource(string, string, bool)</a> to know the design pattern of file path treatment.</p>
|
||||
<p>if the assigned file path is descendent of the configuration directory, it is straight forward that set the <code>baseDirectory</code> to the configuration directory and apply relative path to <code>relFile</code>; if not, set <code>baseDirectory</code> to null and set <code>relFile</code> to absolute path.</p>
|
||||
<p>GUI that needs to assign file generally requires a code-behind <code>BaseDirectory</code> property as assistent model. The property is assigned by the parent model from the parent GUI.</p>
|
||||
<p>In most cases, the first <code>BaseDirectory</code> is the project directory if the project has assigned (created or loaded).</p>
|
||||
<h2 id="portability">Portability</h2>
|
||||
<p>To maintain For the portability of project or the other folder-based unit, if the sub-item is loaded by absolute path outside the folder-based unit directory, redirect the saving path to the folder-based unit directory, i.e. the SubItemFile below.</p>
|
||||
<div class="NOTE">
|
||||
<h5>Note</h5>
|
||||
<p>You have no need to do an additional action to create a duplicate in the folder-based unit directory. Since the file-writing pattern of <a class="xref" href="../../api/Hi.Common.XmlUtils.IMakeXmlSource.html#Hi_Common_XmlUtils_IMakeXmlSource_MakeXmlSource_System_String_System_String_System_Boolean_">MakeXmlSource(string, string, bool)</a> create files when user call to save. In other perspective, if user does not call to save, the local duplicate should be created.</p>
|
||||
</div>
|
||||
<p>The design pattern is usually saw in the HiAPI program, a object contains the properties:</p>
|
||||
<ul>
|
||||
<li>object SubItem;</li>
|
||||
<li>string SubItemFile;</li>
|
||||
</ul>
|
||||
<p>Then you should keep the Protability.</p>
|
||||
<h2 id="file-path-of-load-button-and-save-button">File Path of Load Button and Save Button</h2>
|
||||
<p>The genneral convention of the File Path of Load and Save is different by the single-user desktop application and web page application.</p>
|
||||
<div class="TIP">
|
||||
<h5>Tip</h5>
|
||||
<p>Always preserve an empty filter ( * . * ) for the browser.</p>
|
||||
</div>
|
||||
<h3 id="single-user-desktop-application">Single-User Desktop Application</h3>
|
||||
<p>The default directory of the Save/Load button are generally:</p>
|
||||
<ul>
|
||||
<li>System Default Directory or Project Directory (default, if not explicitly indicated)
|
||||
The initial directory is the project directory.</li>
|
||||
<li>Resource Directory
|
||||
The path always point to <code><application path>/Resource/<classification></code> directory.
|
||||
The button label has to explicitly show ‘Load Resource’.</li>
|
||||
</ul>
|
||||
<p>The kinds of buttons are not exclusive, they can be existed on the same tool bar.</p>
|
||||
<p>If the selected file path is under the project directory, apply the relative path from the project, i.e. baseDirectory is project directory and relFile is the relative path.</p>
|
||||
<h3 id="web-page-application">Web Page Application</h3>
|
||||
<p>The default directory of the Save/Load button are generally:</p>
|
||||
<ul>
|
||||
<li>Admin Directory</li>
|
||||
<li>Project Directory</li>
|
||||
<li>Resource Directory</li>
|
||||
</ul>
|
||||
<p>The Resource Directory and Project Directory are generally under the Admin Directory. And the admin directory is generally set in the appsettings.json file.</p>
|
||||
<h2 id="typical-action-if-exhibitiononly-false">Typical Action if <code>exhibitionOnly</code> false</h2>
|
||||
<p>On <a class="xref" href="../../api/Hi.Common.XmlUtils.IMakeXmlSource.html">IMakeXmlSource</a>.<a class="xref" href="../../api/Hi.Common.XmlUtils.IMakeXmlSource.html#Hi_Common_XmlUtils_IMakeXmlSource_MakeXmlSource_System_String_System_String_System_Boolean_">MakeXmlSource(string, string, bool)</a> with <code>exhibitionOnly</code> false, the argument (<code>baseDirectory</code> and <code>relFile</code>) should be the same from object's host (if exist) XML output function.</p>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,157 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Conventions | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Conventions | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="Anatomy-GeneralRules">
|
||||
<h1 id="conventions">Conventions</h1>
|
||||
|
||||
<p>The rules and shared contracts every Anatomy page assumes. A page in this folder describes
|
||||
something that is true across screens rather than something a reader can point at: how a message
|
||||
reaches the user, how a control behaves when its model is wrong, how a file path is stored, how a
|
||||
component releases what it indexed on the server.</p>
|
||||
<p>Ordered from the rules that bind every page in both applications, through the two shared UI
|
||||
contracts, down to the service patterns and the canvas transport beneath them.</p>
|
||||
<h2 id="rules-that-bind-every-page">Rules That Bind Every Page</h2>
|
||||
<h3 id="message-and-exception-handling">Message and Exception Handling</h3>
|
||||
<p>HiNC uses three independent message categories: <strong>Diagnostic</strong> (<code>IProgress<object></code>), <strong>UI
|
||||
Notification</strong> (<code>MessageBoardUtil</code>), and <strong>App Log</strong> (<code>ILogger</code>). See
|
||||
<a class="xref" href="../../technique/api-foundations/message-management.html">Message Management</a> for the full design pattern.</p>
|
||||
<p>For async exception handling, use <code>CatchExceptions</code> with a caller-provided handler:</p>
|
||||
<pre><code class="lang-csharp">await task.CatchExceptions(ex => progress?.Report(ex));
|
||||
</code></pre>
|
||||
<p>The <a class="xref" href="../shell/bottom-message-bar.html">Bottom Message Bar</a> displays UI-level notifications. The
|
||||
<a class="xref" href="../shell/session-message-panel.html">Session Message Panel</a> displays session diagnostic messages.</p>
|
||||
<h3 id="loose-manner">Loose Manner</h3>
|
||||
<p>The Loose Manner pattern handles rapidly-called synchronous actions where only the last call needs
|
||||
to be effective.</p>
|
||||
<p>The <a class="xref" href="../../api/Hi.Common.LooseRunner.html">LooseRunner</a> class manages skippable rapid-calling synchronous actions. When an
|
||||
action is called rapidly, only the last call is executed while previous calls are safely skipped.
|
||||
The <a class="xref" href="../../api/Hi.Common.LooseRunner.html#Hi_Common_LooseRunner_TryRun_">TryRun</a> method is used to execute actions in this manner.</p>
|
||||
<p>The <a class="xref" href="../../api/Hi.Common.LooseRunner.html">LooseRunner</a> should be disposed when its owner is disposed to ensure proper
|
||||
resource cleanup.</p>
|
||||
<h3 id="loose-couple">Loose Couple</h3>
|
||||
<p>If the model of a UI component is null or mismatched, apply a status badge instead of throwing an
|
||||
exception, so the rest of the UI keeps working.</p>
|
||||
<h2 id="pages">Pages</h2>
|
||||
<ul>
|
||||
<li><a href="translation-remarks.html">Translation Remarks</a> — The terminology every translated UI label is held to, so the same concept keeps the same word across screens and languages</li>
|
||||
<li><a href="gui-file-path-assignment.html">GUI File Path Assignment</a> — How a control stores a chosen file: relative to the configuration directory when it sits inside it, absolute when it does not</li>
|
||||
<li><a href="numeric-io-utilities.html">Numeric Input/Output Utilities</a> — Handling Infinity, -Infinity and NaN across the JavaScript / C# boundary, where plain JSON cannot carry them</li>
|
||||
<li><a href="dictionary-service-pattern.html">DictionaryService and DictionaryHub Pattern</a> — Connection-scoped indexing that lets a hierarchical component reference a backend object across hub connections</li>
|
||||
<li><a href="webapi-hub-cleanup-pattern.html">Webapi with Hub-Cleanup Assistance Pattern</a> — Which component owns an index key and where it releases it, so a component never cleans a key it did not create</li>
|
||||
<li><a href="rendering-canvas-web-service.html">Rendering Canvas on the Web Service</a> — The SignalR transport that puts a server-rendered 3D canvas on a browser page</li>
|
||||
</ul>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a href="../platform/index.html">Platform</a> — the other cross-screen folder: the machinery these rules are applied on top of, including the host process that starts HiAPI</li>
|
||||
<li><a href="../shell/index.html">App Shell</a> — the window frame these conventions are applied inside</li>
|
||||
<li><a href="../widget/index.html">Widgets</a> — the reusable controls that implement two of them</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,202 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Numeric Input/Output | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Numeric Input/Output | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="Anatomy-NumericIoUtilities">
|
||||
<h1 id="numeric-inputoutput">Numeric Input/Output</h1>
|
||||
|
||||
<p><code>NaN</code>, <code>Infinity</code> and <code>-Infinity</code> are ordinary values in a geometry model and ordinary things for a
|
||||
user to type, but JSON has no encoding for any of them. This page describes how the web application
|
||||
carries them across the boundary in both directions.</p>
|
||||
<h2 id="the-server-half">The Server Half</h2>
|
||||
<p>One line of configuration does it. <code>Program.cs</code> sets</p>
|
||||
<pre><code class="lang-csharp">options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals;
|
||||
</code></pre>
|
||||
<p>so the ASP.NET Core serializer reads and writes the three values as the JSON string literals
|
||||
<code>"NaN"</code>, <code>"Infinity"</code> and <code>"-Infinity"</code> instead of failing. It sits on the <code>AddControllers</code> JSON
|
||||
options, so every controller inherits it and no DTO, converter or endpoint has to opt in. Without it
|
||||
a <code>double.NaN</code> anywhere in a response throws during serialization, which is why the setting is
|
||||
load-bearing rather than a convenience.</p>
|
||||
<p>The reach stops at the controllers. Hub payloads are serialized by SignalR's own protocol options,
|
||||
and nothing configures them: <code>AddSignalR()</code> is registered bare and the service contains no
|
||||
<code>AddJsonProtocol</code> call, so the named literals are a controller-JSON contract rather than a
|
||||
service-wide one.</p>
|
||||
<h2 id="the-client-half">The Client Half</h2>
|
||||
<p>There is no shared numeric module. Each input widget formats and parses the special values itself,
|
||||
and the three that ship do not agree on all of it. The widgets are also not the only readers of this
|
||||
boundary: an API module that has to put a non-finite number on the wire converts it in place, as
|
||||
<code>wwwroot-src/src/api/mission.ts</code> does for the mission command fields. That conversion is not
|
||||
symmetric — it writes all three literals but recognises only the two infinity spellings on the way
|
||||
back — so a <code>NaN</code> returned by those endpoints resolves to the caller's supplied default instead.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><code>NumericInput.vue</code></th>
|
||||
<th><code>Vec3Input.vue</code></th>
|
||||
<th><code>Mat4Input.vue</code></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>NaN</code> displays as</td>
|
||||
<td>empty field</td>
|
||||
<td><code>NaN</code></td>
|
||||
<td><code>0</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Infinity</code> / <code>-Infinity</code> display as</td>
|
||||
<td>literal text</td>
|
||||
<td>literal text</td>
|
||||
<td>literal text</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>An empty field parses to</td>
|
||||
<td><code>null</code>, under the default <code>allowEmpty</code></td>
|
||||
<td><code>0</code></td>
|
||||
<td><code>0</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unparseable text on blur</td>
|
||||
<td>stays in the box under an error message</td>
|
||||
<td>reverts to the last valid value</td>
|
||||
<td>reverts to the last valid value</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>All three accept the same spellings on the way in: <code>infinity</code>, <code>-infinity</code> and <code>nan</code>
|
||||
case-insensitively. The <code>∞</code> and <code>-∞</code> glyphs are where they part: the single-value field and the
|
||||
three-axis editor take them, the matrix grid does not. All three commit on blur or Enter rather than
|
||||
per keystroke, but only the vector and matrix editors compare the parsed value against the model
|
||||
before emitting. The single-value field carries no such guard and emits on every accepted commit, so
|
||||
committing with Enter and then leaving the field writes the same value twice.</p>
|
||||
<p>The consequence worth knowing: <strong><code>NaN</code> does not survive a round trip through the matrix editor.</strong>
|
||||
<code>Mat4Input.vue</code> renders it as <code>0</code>, so re-committing a cell that held <code>NaN</code> writes a real zero.</p>
|
||||
<p><code>NumericInput.vue</code> is the input the rest of the app reaches for: no other component in the client is
|
||||
embedded by anywhere near as many editors, so a new numeric field should embed it rather than repeat
|
||||
the parse. Its own props, bounds and validation messages are documented at
|
||||
<a class="xref" href="../widget/numeric-input.html">Numeric Input</a>.</p>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
<p>See <a class="xref" href="../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
||||
<h3 id="web-page-application-source-code-path">Web Page Application Source Code Path</h3>
|
||||
<ul>
|
||||
<li><code>wwwroot-src/src/components/widgets/NumericInput.vue</code> — the shared single-value numeric field: local <code>formatValue</code> / <code>parseValue</code>, blur-and-Enter commit, and the rejected text left standing under an error message when a commit fails.</li>
|
||||
<li><code>wwwroot-src/src/components/widgets/Vec3Input.vue</code> — the three-axis editor; carries its own copy of the same format and parse pair, plus a <code>(x, y, z)</code> text form.</li>
|
||||
<li><code>wwwroot-src/src/components/widgets/Mat4Input.vue</code> — the sixteen-cell matrix grid; the same pair again without the glyph spellings, and with the <code>NaN</code>-to-zero behaviour above.</li>
|
||||
<li><code>wwwroot-src/src/api/mission.ts</code> — a non-widget reader of the same boundary: <code>numericToApiString</code> writes all three literals for the mission command fields, <code>parseMaybeInfiniteNumber</code> reads only the two infinity spellings back.</li>
|
||||
<li><code>Program.cs</code> — the <code>AllowNamedFloatingPointLiterals</code> setting on the controller JSON options that lets the three values cross as JSON at all, and the bare <code>AddSignalR()</code> registration that does not share it.</li>
|
||||
</ul>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../widget/vec3d-control.html">Vec3dControl Component</a> — the three-axis editor, one of the three inputs that carries its own format and parse</li>
|
||||
<li><a class="xref" href="../widget/mat4d-control.html">Mat4dControl Component</a> — the sixteen-cell grid, the one input that renders NaN as zero</li>
|
||||
<li><a class="xref" href="../widget/numeric-input.html">Numeric Input</a> — the single-value field, and the widget that carries this contract to the most callers</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,241 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Rendering Canvas on Web Service Application | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Rendering Canvas on Web Service Application | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="Anatomy-RenderingCanvasWebService">
|
||||
<h1 id="rendering-canvas-on-web-service-application">Rendering Canvas on Web Service Application</h1>
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>The web application's 3D canvas is rendered on the server and streamed to the browser over a
|
||||
SignalR hub connection at <code>/renderingHub</code>. <code>Disp/RenderingHub.cs</code> serves that hub, <code>Program.cs</code>
|
||||
maps it, and the singleton in <code>Disp/RenderingService.cs</code> owns one native display engine per hub
|
||||
connection. The browser paints the frames that arrive and forwards the user's input back.</p>
|
||||
<h2 id="core-component">Core Component</h2>
|
||||
<ul>
|
||||
<li><strong>Location</strong>: <code>wwwroot-src/src/components/RenderingCanvas.vue</code></li>
|
||||
<li><strong>Purpose</strong>: owns one hub connection, forwards input to the server engine, and paints the frames
|
||||
the server streams back</li>
|
||||
</ul>
|
||||
<p>Its <code>hubUrl</code> prop defaults to <code>/renderingHub</code>, and it exposes <code>connect</code>, <code>disconnect</code>, the eight
|
||||
view commands and <code>clearCache</code> — the surface through which
|
||||
<code>wwwroot-src/src/components/RenderingCanvasToolBar.vue</code> drives the canvas instance it is bound to.</p>
|
||||
<h2 id="connection-management">Connection Management</h2>
|
||||
<h3 id="signalr-hub-connection">SignalR Hub Connection</h3>
|
||||
<p>Each <code>RenderingCanvas</code> instance opens its own hub connection and therefore owns one connection ID;
|
||||
the server keeps one display engine per connection ID, so several canvases can be live at the same
|
||||
time. On initialization the hub sends the connection ID back to the caller as <code>CanvasInitialized</code>,
|
||||
and the component re-emits it as <code>serverInitialized</code>. It is re-emitted after every reconnect,
|
||||
because the server disposes the engine on disconnect and a reconnect gets a new ID — the parent
|
||||
page answers by registering its content against that new ID.</p>
|
||||
<p>The connection ID is the index for every canvas operation. <code>Disp/RenderingService.cs</code> keys the
|
||||
engine dictionary, the last-input time, the last lossless-frame hash and the negotiated frame
|
||||
format by it, and <code>Disp/RenderingHub.cs</code> keys its own sketch-view cache the same way.</p>
|
||||
<h3 id="engine-lifetime">Engine Lifetime</h3>
|
||||
<p>The engine's life is the connection's: <code>GetOrCreateEngine</code> creates it when the canvas initializes,
|
||||
and <code>RemoveEngine</code> — called from <code>OnDisconnectedAsync</code> — disposes it and raises <code>EngineRemoved</code>.
|
||||
An HTTP endpoint therefore resolves an engine through the non-creating <code>GetEngine</code>; creating one
|
||||
for an ID that has already disconnected would orphan an engine no disconnect can ever clean up.
|
||||
<code>Disp/StlPreviewService.cs</code> subscribes to <code>EngineRemoved</code> to release the per-connection native
|
||||
topology the engine itself does not own.</p>
|
||||
<h3 id="frame-encoding">Frame Encoding</h3>
|
||||
<p>The frame encoding is negotiated at initialization. <code>InitializeCanvasV2(width, height, formats)</code>
|
||||
with <code>jpeg</code> in the accepted list selects SkiaSharp JPEG frames delivered on <code>ImageUpdateV2</code> at an
|
||||
adaptive quality — interactive frames compress harder and a still frame refines once — and adding
|
||||
<code>png</code> lets that refine be encoded lossless. A browser without <code>createImageBitmap</code>, or a server that
|
||||
does not carry the V2 method, falls back to <code>InitializeCanvas</code> and the gzip-RGBA frames delivered
|
||||
on <code>ImageUpdate</code>.</p>
|
||||
<h3 id="connection-id-naming-convention">Connection ID Naming Convention</h3>
|
||||
<p>One value carries two names on the frontend:</p>
|
||||
<ul>
|
||||
<li><code>renderingConnectionId</code> — the parameter name used throughout the API wrappers under
|
||||
<code>wwwroot-src/src/api</code>, and the route-parameter name on most display controllers</li>
|
||||
<li><code>renderingConnId</code> — how the Execution page holds it (<code>wwwroot-src/src/pages/ExecutionPage.vue</code>),
|
||||
filled from the canvas's <code>@server-initialized</code> and passed to the typed wrappers in
|
||||
<code>wwwroot-src/src/api/execution.ts</code>, whose parameter is <code>renderingConnectionId</code></li>
|
||||
</ul>
|
||||
<h2 id="data-flow-architecture">Data Flow Architecture</h2>
|
||||
<h3 id="frontend-responsibilities">Frontend Responsibilities</h3>
|
||||
<p>The component owns the connection and its reconnect schedule, forwards pointer, wheel, key, touch,
|
||||
resize and visibility events to the hub, and paints each frame as it arrives. A canvas the layout
|
||||
has hidden keeps its connection open and tells the engine to pause rendering instead, so a hidden
|
||||
canvas costs nothing while a simulation runs.</p>
|
||||
<h3 id="backend-integration">Backend Integration</h3>
|
||||
<p>Rendering and frame encoding happen on the server; a controller decides only what the engine shows,
|
||||
by resolving the engine from the connection ID and assigning its displayee. That is why any feature
|
||||
can put its own content on a canvas without touching the transport.</p>
|
||||
<h4 id="example-execution-controller">Example: Execution Controller</h4>
|
||||
<ul>
|
||||
<li><strong>File</strong>: <code>Execution/ExecutionController.cs</code></li>
|
||||
<li><strong>Method</strong>: <code>InitializeExecution</code> (<code>POST /api/Execution/initialize/{connectionId}</code>)</li>
|
||||
<li><strong>Purpose</strong>: resolves the engine with <code>RenderingService.GetEngine(connectionId)</code> and assigns the
|
||||
Execution displayee to it</li>
|
||||
</ul>
|
||||
<p>Six further controllers bind content the same way — the STL preview, the Tool House, the General
|
||||
Setup equipment, the machine tool, the Mech Builder general mechanism and the Controller page —
|
||||
each with its own route and its own displayee, all reaching the engine through the same connection
|
||||
ID.</p>
|
||||
<h2 id="key-points">Key Points</h2>
|
||||
<ul>
|
||||
<li>Every canvas data-stream operation is indexed by the connection ID.</li>
|
||||
<li>Rendering and frame encoding happen on the server; the frontend owns the connection, the input
|
||||
events and the painting of received frames.</li>
|
||||
<li>The engine is created and destroyed with the hub connection, so anything else that holds
|
||||
per-connection resources releases them from <code>EngineRemoved</code>.</li>
|
||||
</ul>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
<p>See <a class="xref" href="../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
||||
<h3 id="web-service-source-code-path">Web Service Source Code Path</h3>
|
||||
<ul>
|
||||
<li><code>Disp/RenderingHub.cs</code> — the hub: creates the per-connection engine, encodes and pumps frames,
|
||||
handles mouse, wheel, key, touch, resize and visibility, and disposes the engine on disconnect.</li>
|
||||
<li><code>Disp/RenderingService.cs</code> — the singleton holding the per-connection maps, the playback render
|
||||
throttle and the <code>EngineRemoved</code> event.</li>
|
||||
<li><code>Disp/StlPreviewService.cs</code> — the <code>EngineRemoved</code> subscriber that frees the File Explorer
|
||||
preview's native topology.</li>
|
||||
<li><code>Program.cs</code> — registers SignalR and maps the hub at <code>/renderingHub</code>.</li>
|
||||
<li><code>Execution/ExecutionController.cs</code> — the worked example above: <code>InitializeExecution</code> assigns the
|
||||
Execution displayee to the engine named by the connection ID.</li>
|
||||
<li><code>Disp/StlPreviewController.cs</code> — binds an STL preview to a canvas (<code>api/stl-preview</code>).</li>
|
||||
<li><code>Mech/ToolHouseDisplayController.cs</code> — the Tool House canvas binding
|
||||
(<code>api/mech/tool-house-display</code>).</li>
|
||||
<li><code>Mech/EquipmentSetupDisplayController.cs</code> — the General Setup canvas binding
|
||||
(<code>api/mech/equipment-setup-display</code>).</li>
|
||||
<li><code>Mech/MachineToolDisplayController.cs</code> — the machine-tool canvas binding
|
||||
(<code>api/mech/machine-tool/display</code>).</li>
|
||||
<li><code>Mech/MechBuilder/GeneralMechanismDisplayController.cs</code> — the Mech Builder canvas binding
|
||||
(<code>api/general-mechanism/display</code>).</li>
|
||||
<li><code>Controller/ControllerController.cs</code> — the Controller page's canvas binding
|
||||
(<code>initialize-display/{connectionId}</code>).</li>
|
||||
</ul>
|
||||
<h3 id="web-page-application-source-code-path">Web Page Application Source Code Path</h3>
|
||||
<ul>
|
||||
<li><code>wwwroot-src/src/components/RenderingCanvas.vue</code> — the client half: one hub connection per
|
||||
instance, encoding negotiation, frame painting, input forwarding and the reconnect loop.</li>
|
||||
<li><code>wwwroot-src/src/components/RenderingCanvasToolBar.vue</code> — the view-control bar bound to one
|
||||
canvas instance through its exposed methods.</li>
|
||||
<li><code>wwwroot-src/src/pages/ExecutionPage.vue</code> — mounts the main canvas, stores the ID as
|
||||
<code>renderingConnId</code> and initializes the Execution content from <code>@server-initialized</code>.</li>
|
||||
<li><code>wwwroot-src/src/api/execution.ts</code> — the typed wrappers whose <code>renderingConnectionId</code> parameter
|
||||
addresses that canvas.</li>
|
||||
<li><code>wwwroot-src/src/components/execution/StepVolumePanel.vue</code> — a second canvas on the Execution
|
||||
page, with its own connection and its own engine.</li>
|
||||
<li><code>wwwroot-src/src/components/mech/EquipmentSetupPanel.vue</code> — the General Setup page's canvas
|
||||
column.</li>
|
||||
<li><code>wwwroot-src/src/components/toolhouse/ToolHouseSetupPanel.vue</code> — the Tool House page's canvas
|
||||
column.</li>
|
||||
<li><code>wwwroot-src/src/components/StlPreviewPane.vue</code> — the File Explorer STL preview canvas.</li>
|
||||
</ul>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../widget/renderingcanvas-tool-bar.html">RenderingCanvas Tool Bar</a> — the <code>View</code> menu that drives the hub, and the <code>Scene</code> menu beside it</li>
|
||||
<li><a class="xref" href="../platform/program-and-hosting.html">Program and Hosting</a> — the host that maps this hub and registers the services behind it</li>
|
||||
<li><a class="xref" href="../util/stl-preview-pane.html">STL Preview Pane</a> — the one caller that opens a rendering connection outside a project</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
<div id="sidetoggle">
|
||||
<div>
|
||||
<div class="sidefilter">
|
||||
<form class="toc-filter">
|
||||
<span class="glyphicon glyphicon-filter filter-icon"></span>
|
||||
<span class="glyphicon glyphicon-remove clear-icon" id="toc_filter_clear"></span>
|
||||
<input type="text" id="toc_filter_input" placeholder="Filter by title" onkeypress="if(event.keyCode==13) {return false;}">
|
||||
</form>
|
||||
</div>
|
||||
<div class="sidetoc">
|
||||
<div class="toc" id="toc">
|
||||
|
||||
<ul class="nav level1">
|
||||
<li>
|
||||
<a href="index.html" name="" title="Overview">Overview</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="translation-remarks.html" name="" title="Translation Remarks">Translation Remarks</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="gui-file-path-assignment.html" name="" title="GUI File Path Assignment">GUI File Path Assignment</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="numeric-io-utilities.html" name="" title="Numeric Input/Output Utilities">Numeric Input/Output Utilities</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="dictionary-service-pattern.html" name="" title="DictionaryService and DictionaryHub Pattern">DictionaryService and DictionaryHub Pattern</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="webapi-hub-cleanup-pattern.html" name="" title="Webapi with Hub-Cleanup Assistance Pattern">Webapi with Hub-Cleanup Assistance Pattern</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="rendering-canvas-web-service.html" name="" title="Rendering Canvas on the Web Service">Rendering Canvas on the Web Service</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"Translation Remarks","href":"translation-remarks.html","topicHref":"translation-remarks.html"},{"name":"GUI File Path Assignment","href":"gui-file-path-assignment.html","topicHref":"gui-file-path-assignment.html"},{"name":"Numeric Input/Output Utilities","href":"numeric-io-utilities.html","topicHref":"numeric-io-utilities.html"},{"name":"DictionaryService and DictionaryHub Pattern","href":"dictionary-service-pattern.html","topicHref":"dictionary-service-pattern.html"},{"name":"Webapi with Hub-Cleanup Assistance Pattern","href":"webapi-hub-cleanup-pattern.html","topicHref":"webapi-hub-cleanup-pattern.html"},{"name":"Rendering Canvas on the Web Service","href":"rendering-canvas-web-service.html","topicHref":"rendering-canvas-web-service.html"}]}
|
||||
@@ -0,0 +1,230 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Translation Remarks | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Translation Remarks | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="Anatomy-TranslationRemarks">
|
||||
<h1 id="translation-remarks">Translation Remarks</h1>
|
||||
|
||||
<p>Terminology is a contract: one concept keeps one word on every screen and in every locale. Three
|
||||
locales ship together — <code>en</code>, <code>zh-Hant</code> and <code>zh-Hans</code> — and the English bundle is the schema the
|
||||
Chinese bundles are typed against, so a key missing from a Chinese locale is a build error. The
|
||||
readings below are the ones the zh-Hant bundle ships.</p>
|
||||
<h2 id="tool-house-and-mechanism-terms">Tool House and Mechanism Terms</h2>
|
||||
<ul>
|
||||
<li><p>Anchor 錨點</p>
|
||||
</li>
|
||||
<li><p>Tool 刀具</p>
|
||||
</li>
|
||||
<li><p>Cutter 刀具本體</p>
|
||||
<ul>
|
||||
<li>Insert-End Cutter 刀片式刀具本體</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>Holder 刀把</p>
|
||||
<ul>
|
||||
<li>Cylindroid Holder 柱狀刀把</li>
|
||||
<li>Freeform Holder 任意形刀把</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>Shank 刀柄</p>
|
||||
</li>
|
||||
<li><p>Fixture 夾具</p>
|
||||
</li>
|
||||
<li><p>Milling Cutter 銑刀</p>
|
||||
</li>
|
||||
<li><p>Freeform Remover 任意移除工具</p>
|
||||
</li>
|
||||
<li><p>Flute 刀刃</p>
|
||||
<ul>
|
||||
<li>Flute Profile 刃包絡形</li>
|
||||
<li>Flute Contours 刃雕
|
||||
<ul>
|
||||
<li>Baseline Contour 基準刃雕</li>
|
||||
<li>Side Contour 側向刃雕</li>
|
||||
<li>Bottom Contour 底部刃雕</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>Upper Beam 夾持柱</p>
|
||||
</li>
|
||||
<li><p>Integral Mode 刀頭形式</p>
|
||||
<ul>
|
||||
<li>Solid End 一體式</li>
|
||||
<li>Insert End 刀片式</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>Preset 預設</p>
|
||||
<ul>
|
||||
<li>Datum Preset 基準點預設</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>General Config 一般組態 — the mission tree's label for the <code>presetting</code> command kind</p>
|
||||
</li>
|
||||
<li><p>Meshed Geometry 網格幾何</p>
|
||||
</li>
|
||||
<li><p>Machining Resolution 加工解析度</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="words-that-carry-more-than-one-sense">Words That Carry More Than One Sense</h2>
|
||||
<p><code>Contour</code> is the sharpest case: in the cutter namespace it is 刃雕 (Flute Contours 刃雕, Baseline
|
||||
Contour 基準刃雕), and in the spindle-capability namespace it is 等值線 (Power Contours 功率等值線,
|
||||
Torque Contours 扭矩等值線). Each sense keeps its own entry rather than one compromise word.</p>
|
||||
<p><code>Fluting</code> is a cutter's whole set of flute contours — one shared baseline or one per flute — and
|
||||
translates as 刃雕構型: Uniform Fluting 對稱刃雕構型, Free Fluting 自由刃雕構型.</p>
|
||||
<p><code>Program</code> is the UI-layer word and does translate: 程式 in zh-Hant, 程序 in zh-Hans. <code>Control</code> in
|
||||
the frontend names the Control Tree UI, 控制樹, and never takes 程式.</p>
|
||||
<h2 id="never-translate">Never Translate</h2>
|
||||
<p><code>HiNC</code> · <code>hincproj</code> · <code>SoftNc</code> · <code>MachiningStep</code> · brand names (Fanuc, Heidenhain, Mazak, Siemens,
|
||||
Syntec) · NC codes (<code>G54</code>, <code>M128</code>, <code>CYCLE800</code>, <code>TRAORI</code>, <code>RTCP</code>, <code>TCPM</code>) · file extensions and
|
||||
MIME-ish strings (<code>STL</code>, <code>*.hincproj</code>) · units (<code>mm</code>, <code>rpm</code>, <code>mm/min</code>, <code>N</code>, <code>Nm</code>, <code>kW</code>, <code>KB</code>, <code>MB</code>,
|
||||
<code>GB</code>) · the keyboard shortcuts embedded in tooltip sentences · route names, enum keys,
|
||||
localStorage keys and series identifiers — anything a machine compares. Language self-names
|
||||
(English, 简体中文, 繁體中文) stay in their own language in every locale. The full list lives with
|
||||
the bundles, in the i18n folder's README.</p>
|
||||
<h2 id="terms-carried-by-the-desktop-client">Terms Carried by the Desktop Client</h2>
|
||||
<p>Three milling-cutter surfaces exist only on the WPF client, and their terms belong to the same
|
||||
contract, so none of the words is reused elsewhere:</p>
|
||||
<ul>
|
||||
<li>Insert-Cutter 刀片 — a tab on <code>Mech/ToolHouse/MillingCutterPanel.xaml</code></li>
|
||||
<li>Flute-Inner-Beam 刃中芯 — the tab served by <code>Mech/ToolHouse/FluteInnerBeamPanel.xaml</code></li>
|
||||
<li>Cutter Integral Mode 刀頭形式 — a labelled tab there as well; the web application carries the
|
||||
same choice as the <code>integralMode</code> datum, which decides whether the Tool House material section
|
||||
offers a separate shank material, and shows no label of its own</li>
|
||||
</ul>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
<p>See <a class="xref" href="../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
||||
<ul>
|
||||
<li><code>wwwroot-src/src/i18n/en/toolhouse.ts</code> and <code>wwwroot-src/src/i18n/zh-Hant/toolhouse.ts</code> — the Tool
|
||||
House control-tree node names and editor labels: Cutter, Holder, Flute Profile, Flute Contours,
|
||||
Upper Beam, and the cutter and holder types.</li>
|
||||
<li><code>wwwroot-src/src/i18n/en/mech.ts</code> and <code>wwwroot-src/src/i18n/zh-Hant/mech.ts</code> — the General Setup
|
||||
rendering flags and the anchor labels.</li>
|
||||
<li><code>wwwroot-src/src/i18n/en/tree.ts</code> and <code>wwwroot-src/src/i18n/zh-Hant/tree.ts</code> — the shared
|
||||
control-tree node names and the mission command kinds.</li>
|
||||
<li><code>wwwroot-src/src/i18n/zh-Hant/mission.ts</code> — the PreSetting command fields, including Machining
|
||||
Resolution and the meshed-geometry file picker.</li>
|
||||
<li><code>wwwroot-src/src/i18n/zh-Hant/controller.ts</code> and <code>wwwroot-src/src/i18n/zh-Hant/softNc.ts</code> — the
|
||||
Datum Preset tab, its table, and the runner's datum-preset row.</li>
|
||||
<li><code>wwwroot-src/src/i18n/zh-Hant/execution.ts</code> — the Execution rendering flags, where Meshed
|
||||
Geometry and Fixture appear together.</li>
|
||||
<li><code>wwwroot-src/src/i18n/index.ts</code> — <code>createI18n()</code>, <code>applyLocale()</code> and <code>SUPPORTED_LOCALES</code>, the
|
||||
only place a locale switch happens.</li>
|
||||
<li><code>wwwroot-src/src/i18n/schema.ts</code> — the English bundle as the schema that types the Chinese ones.</li>
|
||||
<li><code>wwwroot-src/src/i18n/glossary.yaml</code> — generated data, never imported by the application: the
|
||||
harvested legacy corpus with an adjudicated head term per concept, used to settle a reading
|
||||
before it is written into a bundle.</li>
|
||||
</ul>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../shell/language-selection-submenu.html">Language Selection SubMenu</a> — the sub-menu that switches the locale these terms are written for</li>
|
||||
<li><a class="xref" href="../platform/i18n.html">Internationalization</a> — the bundle layout these terms are written into, and the lint that holds them to it</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,129 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Webapi with Hub-Cleanup Assistance Pattern | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Webapi with Hub-Cleanup Assistance Pattern | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../toc.html">
|
||||
<meta name="docfx:tocrel" content="toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="Anatomy-WebapiHubCleanupPattern">
|
||||
<h1 id="webapi-with-hub-cleanup-assistance-pattern">Webapi with Hub-Cleanup Assistance Pattern</h1>
|
||||
|
||||
<p>any of the index key should be registerForCleanup. i.e. any of indexXxx should follow the registerForCleanup.</p>
|
||||
<p>clean the indexed key which indexed by the host component in beforeUnmount. And so that the component doesn't clean the key that doesn't create by the component itself.</p>
|
||||
<p>The hub is not a second, redundant path that would make this web-api cleanup a mere demonstration.
|
||||
<code>Common/CleanupHub.cs</code> keeps its key registry in an ordinary instance property, and SignalR builds a
|
||||
fresh hub instance for every invocation, so the entry <code>Add</code> records is discarded with the instance
|
||||
that received it and <code>OnDisconnectedAsync</code> always walks an empty registry. The index-remove calls
|
||||
<code>wwwroot-src/src/composables/useCleanupHub.ts</code> makes — on unmount and on every key replacement — are
|
||||
the only ones that actually free a key, which is why registering a key without releasing it there
|
||||
leaks it for the life of the process.</p>
|
||||
<h2 id="notice">Notice</h2>
|
||||
<ol>
|
||||
<li>before current key modified, the previous key should be called this.cleanupKey.</li>
|
||||
<li>A twin key should be made from the outside key to keep the lifecycle maintained.</li>
|
||||
</ol>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user