<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Theodoros Bebekis</title>
    <description>The latest articles on DEV Community by Theodoros Bebekis (@tbebekis).</description>
    <link>https://dev.to/tbebekis</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1711126%2F9a43edc2-8b17-4a3b-b80b-93fa344e16b1.png</url>
      <title>DEV Community: Theodoros Bebekis</title>
      <link>https://dev.to/tbebekis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tbebekis"/>
    <language>en</language>
    <item>
      <title>Fundamental Concepts of Business Applications IV: Building a Locator</title>
      <dc:creator>Theodoros Bebekis</dc:creator>
      <pubDate>Tue, 07 Jul 2026 12:04:31 +0000</pubDate>
      <link>https://dev.to/tbebekis/fundamental-concepts-of-business-applications-iv-building-a-locator-4m1m</link>
      <guid>https://dev.to/tbebekis/fundamental-concepts-of-business-applications-iv-building-a-locator-4m1m</guid>
      <description>&lt;h2&gt;
  
  
  From declaration to runtime
&lt;/h2&gt;

&lt;p&gt;In the previous parts we examined the problem: a business application needs a reliable way to turn a human reference into a business entity.&lt;/p&gt;

&lt;p&gt;A user types a customer code, a product name, a tax number, an external identifier, or a fragment of a description. The application needs to arrive at something stable: the canonical identity of the record.&lt;/p&gt;

&lt;p&gt;That is the role of the Locator.&lt;/p&gt;

&lt;p&gt;In the previous article we saw how a Locator can be described declaratively. We described fields, search fields, result fields, key field, and policies. But a definition by itself is just data. It needs a runtime.&lt;/p&gt;

&lt;p&gt;In this article we move to the practical part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Locator Definition
        ↓
Runtime Request
        ↓
Execution Engine
        ↓
Locator Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will see which objects are needed, what their roles are, how they cooperate, and how a declarative definition becomes an executable mechanism.&lt;/p&gt;

&lt;p&gt;The article uses the Locator as a case study, but the idea is broader. Many business frameworks follow the same path: we describe something declaratively and then build a runtime that can execute it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The problem solved by the Locator
&lt;/h2&gt;

&lt;p&gt;In a sales application, the user may type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALFKI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Alfreds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or select a row from a result list.&lt;/p&gt;

&lt;p&gt;For the UI, these look like text input or a dropdown selection. For the business layer, they are something else: an attempt to resolve a reference.&lt;/p&gt;

&lt;p&gt;The application wants to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which record does this refer to?&lt;/li&gt;
&lt;li&gt;Is there exactly one record?&lt;/li&gt;
&lt;li&gt;Are there multiple records and should the user choose one?&lt;/li&gt;
&lt;li&gt;Is the search too broad?&lt;/li&gt;
&lt;li&gt;Is the request invalid?&lt;/li&gt;
&lt;li&gt;Is there a context problem, such as wrong company or permissions?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this logic stays inside event handlers, SQL snippets, or controllers, the system fills with repetition and special cases. The Locator provides a stable runtime contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The basic runtime pieces
&lt;/h2&gt;

&lt;p&gt;A Locator needs five basic objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LocatorDefinition
LocatorRequest
LocatorContext
LocatorEngine
LocatorResult
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Their roles are clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;LocatorDefinition&lt;/code&gt;: describes what the locator knows.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LocatorRequest&lt;/code&gt;: describes what the caller is asking for now.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LocatorContext&lt;/code&gt;: carries runtime information.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LocatorEngine&lt;/code&gt;: executes the process.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LocatorResult&lt;/code&gt;: returns outcome and data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These objects are the minimum runtime model. They are more than classes for organizing code: they are the boundaries of the mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. LocatorDefinition
&lt;/h2&gt;

&lt;p&gt;The definition is the declarative part.&lt;/p&gt;

&lt;p&gt;A simple shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LocatorDefinition&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ClassName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;KeyField&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LocatorFieldDefinition&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Fields&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SearchFields&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ResultFields&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;MinimumSearchLength&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;MaximumResultCount&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;OrderBy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;customerLocator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LocatorDefinition&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ClassName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SqlLocator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;KeyField&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;OrderBy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;MinimumSearchLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;MaximumResultCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;customerLocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FieldType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;customerLocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FieldType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;customerLocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FieldType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;customerLocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSearchField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;customerLocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSearchField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;customerLocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddResultField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;customerLocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddResultField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Code"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;customerLocator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddResultField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code describes the Locator. Search, connection, UI, and result state belong to the runtime.&lt;/p&gt;

&lt;p&gt;The definition answers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the locator name?&lt;/li&gt;
&lt;li&gt;Which engine will execute it?&lt;/li&gt;
&lt;li&gt;Which source will the engine use?&lt;/li&gt;
&lt;li&gt;Which field is the canonical identity?&lt;/li&gt;
&lt;li&gt;Which fields participate in search?&lt;/li&gt;
&lt;li&gt;Which fields are returned?&lt;/li&gt;
&lt;li&gt;Which policies apply?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The definition stays stable. The request and context change on every execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Name, ClassName, and Source
&lt;/h2&gt;

&lt;p&gt;The three fields &lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;ClassName&lt;/code&gt;, and &lt;code&gt;Source&lt;/code&gt; are easy to confuse, so it is worth separating them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name
    locator identity in the registry

ClassName
    engine/handler type that will execute the definition

Source
    provider-specific source used by the engine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Name&lt;/code&gt; is the registry key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The runtime uses it to find the definition.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ClassName&lt;/code&gt; selects the engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SqlLocator
ServiceLocator
ObjectLocator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Source&lt;/code&gt; is input to the engine. For a SQL engine it may be a table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or a select:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;Customer&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;IsActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a service engine it may be an endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/customers/search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an object engine it may be the name of an in-memory collection.&lt;/p&gt;

&lt;p&gt;The architecture remains provider-neutral. Interpreting &lt;code&gt;Source&lt;/code&gt; belongs to the engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. LocatorRequest
&lt;/h2&gt;

&lt;p&gt;The request is the runtime intention of the caller.&lt;/p&gt;

&lt;p&gt;A simple shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LocatorRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;KeyValue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;SearchTerm&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;SearchField&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsMultiRow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;LocatorContext&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;KeyValue&lt;/code&gt; is used when the caller already has a possible canonical identity and wants to load or verify it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SearchTerm&lt;/code&gt; is used for text search.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SearchField&lt;/code&gt; optionally limits the search to a specific field.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;IsMultiRow&lt;/code&gt; gives a hint about the UI scenario, for example a grid lookup instead of a simple editor.&lt;/p&gt;

&lt;p&gt;The request expresses the caller's intention. Fields, policies, and source belong to the definition.&lt;/p&gt;

&lt;p&gt;The request says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I want to resolve this now.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. LocatorContext
&lt;/h2&gt;

&lt;p&gt;The context carries runtime conditions.&lt;/p&gt;

&lt;p&gt;The same search may produce different results per company, branch, tenant, language, connection, date, or user permissions.&lt;/p&gt;

&lt;p&gt;A practical shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LocatorContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;LocatorName&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Parameters&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocatorName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Customer"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"CompanyId"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentCompanyId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Language"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentLanguage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ConnectionName"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connectionName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dictionary is a practical choice. The context works as a runtime carrier, not as an entity schema. It needs room for parameters that vary per application or provider.&lt;/p&gt;

&lt;p&gt;In stricter implementations there may be a strongly typed context. The basic contract remains the same: the context brings information that affects execution.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;LocatorName&lt;/code&gt; in the context is registry identity. The runtime uses it to find the definition.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. LocatorResult
&lt;/h2&gt;

&lt;p&gt;The result is an outcome, not just a list.&lt;/p&gt;

&lt;p&gt;A search function usually returns rows. A Locator must return the state of the resolution attempt.&lt;/p&gt;

&lt;p&gt;A simple shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LocatorResult&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;LocatorResultStatus&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The basic states:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;LocatorResultStatus&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;InvalidRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;InvalidContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;NoResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SingleResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;MultipleResults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;TooManyResults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The distinction has practical value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NoResult&lt;/code&gt;: the request was valid, but the search returned an empty result.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SingleResult&lt;/code&gt;: one record was found and the reference was resolved.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MultipleResults&lt;/code&gt;: a small set of records was found and the user can choose.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TooManyResults&lt;/code&gt;: the search was too broad.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;InvalidRequest&lt;/code&gt;: input is missing or invalid.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;InvalidContext&lt;/code&gt;: the runtime context is incomplete or incompatible.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Error&lt;/code&gt;: a technical or unexpected failure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The UI can react differently to each state.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SingleResult
    write CustomerId and related fields

MultipleResults
    show selection list

TooManyResults
    ask for more characters

NoResult
    show message or allow new record
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where the Locator becomes a business mechanism instead of a simple search helper.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. LocatorEngine
&lt;/h2&gt;

&lt;p&gt;The engine executes.&lt;/p&gt;

&lt;p&gt;A clean contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;LocatorResult&lt;/span&gt; &lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;LocatorDefinition&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;LocatorRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The engine receives a definition and a request. The context is inside the request.&lt;/p&gt;

&lt;p&gt;Its role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Validate Request
Read Definition
Apply Context
Resolve
Produce Canonical Identity
Produce Projection
Determine Result State
Return Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation may be SQL, service, object, cache, directory, or something else.&lt;/p&gt;

&lt;p&gt;The contract remains the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Facade, Registry, and Factory
&lt;/h2&gt;

&lt;p&gt;The caller needs a simple entry point.&lt;/p&gt;

&lt;p&gt;The facade takes responsibility for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find definition
validate definition
create engine
execute engine
interpret result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It needs an application-level service.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Locators&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;LocatorResult&lt;/span&gt; &lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LocatorRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;LocatorResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InvalidContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing locator context."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocatorName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;LocatorResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InvalidContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Missing locator name."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;LocatorDefinition&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="n"&gt;LocatorRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocatorName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Check&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;Locator&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="n"&gt;LocatorFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClassName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;locator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Registry: finds a definition by locator name.&lt;/li&gt;
&lt;li&gt;Factory: creates an engine based on &lt;code&gt;ClassName&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Facade: gives the caller a simple entry point.&lt;/li&gt;
&lt;li&gt;Engine: executes resolution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps UI and callers clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. The execution pipeline
&lt;/h2&gt;

&lt;p&gt;Now let us look at the pipeline as practical steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Caller
  ↓
LocatorRequest
  ↓
LocatorContext.LocatorName
  ↓
LocatorRegistry
  ↓
LocatorDefinition
  ↓
LocatorFactory
  ↓
LocatorEngine
  ↓
LocatorResult
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Validate Request
&lt;/h3&gt;

&lt;p&gt;The engine checks input first.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KeyValue&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SearchTerm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SearchTerm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinimumSearchLength&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;LocatorResult&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LocatorResultStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvalidRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"The search term is too short."&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The limit lives in the definition. The check happens at runtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read Definition
&lt;/h3&gt;

&lt;p&gt;The engine reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source
KeyField
SearchFields
ResultFields
Policies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The definition provides materials and rules. The engine decides how to use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apply Context
&lt;/h3&gt;

&lt;p&gt;The context may select connection, company, tenant, language, or permissions.&lt;/p&gt;

&lt;p&gt;The same definition can execute differently per context.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolve
&lt;/h3&gt;

&lt;p&gt;This is the provider-specific part.&lt;/p&gt;

&lt;p&gt;In a SQL engine, a query is produced.&lt;/p&gt;

&lt;p&gt;In a service engine, a service call is made.&lt;/p&gt;

&lt;p&gt;In an object engine, a collection is searched.&lt;/p&gt;

&lt;p&gt;The result of this step is raw resolved data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Produce Canonical Identity
&lt;/h3&gt;

&lt;p&gt;The Locator targets canonical identity.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;KeyField&lt;/code&gt; declares which field plays that role.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KeyField = Id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user may have typed a code or name. The system ultimately wants &lt;code&gt;Id&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Produce Projection
&lt;/h3&gt;

&lt;p&gt;Often the caller needs additional fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Id
Code
Name
TaxNumber
PaymentTermId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ResultFields&lt;/code&gt; define that projection.&lt;/p&gt;

&lt;p&gt;The projection belongs to the result.&lt;/p&gt;

&lt;p&gt;Applying those fields to a target row or target object is the job of another component, usually a mapper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Determine Result State
&lt;/h3&gt;

&lt;p&gt;The engine decides the status.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LocatorResultStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LocatorResultStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SingleResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaximumResultCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LocatorResultStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TooManyResults&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LocatorResultStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MultipleResults&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result state drives the UI and the workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Return Result
&lt;/h3&gt;

&lt;p&gt;The result returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Status
Message
Data
Count
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Data&lt;/code&gt; may be a table, DTO list, object list, or another container. That is an implementation concern.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. SQL-based engine
&lt;/h2&gt;

&lt;p&gt;In many business applications the first engine will be SQL-based.&lt;/p&gt;

&lt;p&gt;That is practical, while the architecture remains provider-neutral.&lt;/p&gt;

&lt;p&gt;For a SQL engine, &lt;code&gt;Source&lt;/code&gt; may be a table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or a select:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;Customer&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;IsActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A SELECT as source is a convenience of the SQL implementation. It fits because SQL is a declarative language. It describes a result, not imperative steps.&lt;/p&gt;

&lt;p&gt;Other engines will interpret &lt;code&gt;Source&lt;/code&gt; differently.&lt;/p&gt;

&lt;p&gt;The shared contract stays stable.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. Declarative policies
&lt;/h2&gt;

&lt;p&gt;Policies belong to the definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MinimumSearchLength
MaximumResultCount
OrderBy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The engine applies them.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MinimumSearchLength&lt;/code&gt; protects against overly short searches.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MaximumResultCount&lt;/code&gt; protects the UI and backend from oversized result sets.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OrderBy&lt;/code&gt; determines presentation.&lt;/p&gt;

&lt;p&gt;The definition declares. The engine executes.&lt;/p&gt;

&lt;p&gt;That is the essence of the runtime model.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. Resolution states in practice
&lt;/h2&gt;

&lt;p&gt;The states deserve special attention because they directly affect the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  NoResult
&lt;/h3&gt;

&lt;p&gt;The request executed and the search returned an empty result.&lt;/p&gt;

&lt;p&gt;The UI may show a message, clear the field, or suggest creating a new record.&lt;/p&gt;

&lt;h3&gt;
  
  
  SingleResult
&lt;/h3&gt;

&lt;p&gt;The reference was resolved cleanly.&lt;/p&gt;

&lt;p&gt;The caller receives canonical identity and result fields.&lt;/p&gt;

&lt;h3&gt;
  
  
  MultipleResults
&lt;/h3&gt;

&lt;p&gt;There are multiple records, but the count is manageable.&lt;/p&gt;

&lt;p&gt;The UI shows choices.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SearchTerm = John
Result count = 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  TooManyResults
&lt;/h3&gt;

&lt;p&gt;There are many records and the search is too broad.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SearchTerm = s
Result count = 500
MaximumResultCount = 50
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI asks for more specific input.&lt;/p&gt;

&lt;p&gt;The distinction from &lt;code&gt;MultipleResults&lt;/code&gt; is critical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MultipleResults
    show choices

TooManyResults
    ask for narrower search
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  InvalidRequest
&lt;/h3&gt;

&lt;p&gt;The input is invalid.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Search term too short
Unknown search field
Missing required input
Invalid key value type
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  InvalidContext
&lt;/h3&gt;

&lt;p&gt;The context is missing, incomplete, or incompatible with execution.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Missing company
Missing tenant
Invalid connection
Insufficient permissions
Unsupported language context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Error
&lt;/h3&gt;

&lt;p&gt;A technical or unexpected failure.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database error
Service unavailable
Timeout
Serialization error
Unexpected exception
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Business states and technical errors should stay separate.&lt;/p&gt;

&lt;h2&gt;
  
  
  14. Extensibility
&lt;/h2&gt;

&lt;p&gt;Extensibility comes from the boundaries.&lt;/p&gt;

&lt;p&gt;The definition is declarative.&lt;/p&gt;

&lt;p&gt;The request is runtime input.&lt;/p&gt;

&lt;p&gt;The context is runtime environment.&lt;/p&gt;

&lt;p&gt;The result is outcome.&lt;/p&gt;

&lt;p&gt;The engine is interpreter.&lt;/p&gt;

&lt;p&gt;With these boundaries, we can have many engines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SqlLocator
ServiceLocator
ObjectLocator
CacheLocator
DirectoryLocator
GraphLocator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of them implement the same basic contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Locator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;LocatorResult&lt;/span&gt; &lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;LocatorDefinition&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;LocatorRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application continues to call &lt;code&gt;Locators.Execute(request)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The engine change happens behind the definition.&lt;/p&gt;

&lt;p&gt;This is practical extensibility. The caller stays free of if/else logic for every provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  15. Mapper: a neighboring component
&lt;/h2&gt;

&lt;p&gt;When the user selects a record, more than one field is often updated.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CustomerId
CustomerCode
CustomerName
PaymentTermId
VatRegimeId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Locator answers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which record corresponds to this reference?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Mapper answers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How are the result fields written to the consumer?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Mapper consumes &lt;code&gt;LocatorResult&lt;/code&gt;. It is a neighboring mechanism, outside the Locator core.&lt;/p&gt;

&lt;p&gt;It deserves a separate article because it has its own concerns: field mapping, target object, target row, validation, overwrite policy, and transactional behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  16. Result materialization
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Data&lt;/code&gt; of the result is an implementation detail.&lt;/p&gt;

&lt;p&gt;In a SQL engine it may be a table.&lt;/p&gt;

&lt;p&gt;In a service engine it may be a DTO list.&lt;/p&gt;

&lt;p&gt;In an object engine it may be an object list.&lt;/p&gt;

&lt;p&gt;The contract asks for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Status
Message
Data
Count
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The container is selected by the implementation.&lt;/p&gt;

&lt;p&gt;This keeps the pattern clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  17. Conclusion
&lt;/h2&gt;

&lt;p&gt;The Locator starts from a practical business problem: how a user reference becomes a stable business identity.&lt;/p&gt;

&lt;p&gt;The solution needs more than a search function.&lt;/p&gt;

&lt;p&gt;It needs a runtime contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LocatorDefinition
        ↓
LocatorRequest
        ↓
LocatorContext
        ↓
LocatorEngine
        ↓
LocatorResult
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The definition declares.&lt;/p&gt;

&lt;p&gt;The request asks.&lt;/p&gt;

&lt;p&gt;The context carries runtime conditions.&lt;/p&gt;

&lt;p&gt;The engine interprets and executes.&lt;/p&gt;

&lt;p&gt;The result returns outcome and data.&lt;/p&gt;

&lt;p&gt;This model gives clear boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UI sends a request and reads a result.&lt;/li&gt;
&lt;li&gt;The registry finds the definition.&lt;/li&gt;
&lt;li&gt;The factory creates an engine.&lt;/li&gt;
&lt;li&gt;The engine applies policies and provider-specific logic.&lt;/li&gt;
&lt;li&gt;The result says what happened.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same grammar appears in many parts of a business application framework:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Problem
        ↓
Architectural Concept
        ↓
Declarative Definition
        ↓
Executable Runtime Model
        ↓
Concrete Implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Locator is a good example because it is small, useful, and complex enough to show the pattern clearly.&lt;/p&gt;

&lt;p&gt;A Locator is only one example. The important idea is the transformation itself: a declarative description becomes an executable runtime model. Once that pattern is established, the same architecture can be applied to forms, reports, workflows, validation rules, document handlers, and many other business components. The Locator simply provides a compact case study of a much broader architectural principle.&lt;/p&gt;

&lt;p&gt;In the end, the goal is something larger than another helper class: a mechanism that can be reused, extended, and integrated into different UIs, data sources, and business workflows.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>softwareengineering</category>
      <category>design</category>
    </item>
    <item>
      <title>Fundamental Concepts of Business Applications III: Locator Definitions</title>
      <dc:creator>Theodoros Bebekis</dc:creator>
      <pubDate>Mon, 06 Jul 2026 09:37:25 +0000</pubDate>
      <link>https://dev.to/tbebekis/fundamental-concepts-of-business-applications-iii-locator-definitions-k18</link>
      <guid>https://dev.to/tbebekis/fundamental-concepts-of-business-applications-iii-locator-definitions-k18</guid>
      <description>&lt;p&gt;In the previous article, we argued that a Locator is neither a UI control nor a search mechanism. It is an architectural concept that resolves business references within a specific business context and transforms them into canonical business identities.&lt;/p&gt;

&lt;p&gt;If that is true, however, an obvious question immediately follows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can a Locator be described?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not how it is implemented.&lt;/p&gt;

&lt;p&gt;Not how it is executed.&lt;/p&gt;

&lt;p&gt;But how it can be described independently of any particular implementation.&lt;/p&gt;

&lt;p&gt;This question is more important than it may seem at first glance. If two different development teams decide to implement a Locator, how can they be sure they are implementing the same concept? How can we discuss a Locator without referring to a particular library, programming language, or framework?&lt;/p&gt;

&lt;p&gt;The answer is that, like any mature architectural concept, a Locator must first be separated from its implementation.&lt;/p&gt;




&lt;p&gt;This distinction appears repeatedly throughout the history of software engineering.&lt;/p&gt;

&lt;p&gt;Relational theory existed before relational database systems.&lt;/p&gt;

&lt;p&gt;SQL does not describe &lt;em&gt;how&lt;/em&gt; a query will be executed. It describes only the result we want to obtain. The choice of indexes, execution plans, and optimization algorithms is the responsibility of the query optimizer.&lt;/p&gt;

&lt;p&gt;Exactly the same principle applies here.&lt;/p&gt;

&lt;p&gt;A Locator should not be defined by the mechanism that implements it.&lt;/p&gt;

&lt;p&gt;It should be possible to describe it independently of that mechanism.&lt;/p&gt;




&lt;p&gt;This naturally leads to three distinct levels of abstraction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Locator Pattern
        │
        ▼
Locator Definition
        │
        ▼
Execution Engine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;Locator Pattern&lt;/strong&gt; is the architectural concept itself.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Locator Definition&lt;/strong&gt; is the declarative description of a particular resolution process.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Execution Engine&lt;/strong&gt; is the component responsible for interpreting that description and performing the actual resolution.&lt;/p&gt;

&lt;p&gt;Each level has a different responsibility, and they should never be confused with one another.&lt;/p&gt;




&lt;p&gt;This means that a &lt;strong&gt;Locator Definition&lt;/strong&gt; is not an implementation artifact. It is neither a class, an API, a SQL query, nor a UI component.&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;declarative description&lt;/strong&gt; of a business reference resolution process.&lt;/p&gt;

&lt;p&gt;Or, if you prefer, it is the contract that defines what it means to resolve a particular business reference without describing how that resolution should be performed.&lt;/p&gt;




&lt;p&gt;This naturally leads to the next question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the minimum amount of information required to describe a Locator completely?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer is that every Locator Definition must answer a small number of fundamental questions.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What can be resolved?
&lt;/h2&gt;

&lt;p&gt;Which business entity is being resolved?&lt;/p&gt;

&lt;p&gt;A Product?&lt;/p&gt;

&lt;p&gt;A Customer?&lt;/p&gt;

&lt;p&gt;A Warehouse?&lt;/p&gt;

&lt;p&gt;An Account?&lt;/p&gt;

&lt;p&gt;Notice that we are not talking about database tables or object-oriented classes.&lt;/p&gt;

&lt;p&gt;We are talking about business concepts.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. How can it be referenced?
&lt;/h2&gt;

&lt;p&gt;How can users refer to that entity?&lt;/p&gt;

&lt;p&gt;By code?&lt;/p&gt;

&lt;p&gt;By name?&lt;/p&gt;

&lt;p&gt;By barcode?&lt;/p&gt;

&lt;p&gt;By registration number?&lt;/p&gt;

&lt;p&gt;By account number?&lt;/p&gt;

&lt;p&gt;These references represent the user's language rather than the internal language of the information system.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Under which business context?
&lt;/h2&gt;

&lt;p&gt;The same business reference may represent different entities depending on the business context in which the resolution takes place.&lt;/p&gt;

&lt;p&gt;The company.&lt;/p&gt;

&lt;p&gt;The warehouse.&lt;/p&gt;

&lt;p&gt;The customer.&lt;/p&gt;

&lt;p&gt;The transaction date.&lt;/p&gt;

&lt;p&gt;The active price list.&lt;/p&gt;

&lt;p&gt;The actual values of this context belong to runtime. A Locator Definition does not contain those values. It merely describes that the resolution process may depend on them.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. What is the canonical result?
&lt;/h2&gt;

&lt;p&gt;If the resolution succeeds, what is the canonical business identity that is produced?&lt;/p&gt;

&lt;p&gt;From that point onward, the rest of the application can safely use this identity without knowing how it was obtained.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. What information becomes available after successful resolution?
&lt;/h2&gt;

&lt;p&gt;Successful resolution produces more than a business identity.&lt;/p&gt;

&lt;p&gt;It also makes available the information required for the business process to continue.&lt;/p&gt;

&lt;p&gt;For example, resolving a product may also provide its description, unit of measure, VAT rate, or any other information required by the current business process.&lt;/p&gt;

&lt;p&gt;The important point is that a Locator Definition does not describe specific fields. Instead, it defines the contract of the information that becomes available after a successful resolution.&lt;/p&gt;




&lt;p&gt;Optionally, a Locator Definition may also describe the abstract source from which entities are resolved. That source is not necessarily a relational database. It may be a service, an object collection, or any other provider capable of participating in the resolution process. Even this information remains part of the description rather than the implementation.&lt;/p&gt;




&lt;p&gt;It is equally important to understand the boundaries of a Locator Definition.&lt;/p&gt;

&lt;p&gt;Its purpose is not to describe the technical details of execution. It does not define SQL, indexes, execution plans, caching strategies, or search algorithms. Nor does it dictate dialogs, combo boxes, grid controls, or any other user interface elements.&lt;/p&gt;

&lt;p&gt;Those are the responsibility of the &lt;strong&gt;Execution Engine&lt;/strong&gt;, which is free to choose the most appropriate implementation as long as it honors the contract defined by the Locator Definition.&lt;/p&gt;




&lt;p&gt;In this sense, a Locator Definition resembles a small declarative language more than it resembles a class or an API.&lt;/p&gt;

&lt;p&gt;It does not describe objects, algorithms, or implementations.&lt;/p&gt;

&lt;p&gt;It describes a business intent.&lt;/p&gt;

&lt;p&gt;It answers only one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What does it mean to resolve this business reference?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everything else is the responsibility of the mechanism that interprets and executes that description.&lt;/p&gt;




&lt;p&gt;So far, we have not written a single line of code.&lt;/p&gt;

&lt;p&gt;And yet, we have already defined an architectural concept, the language used to describe it, and the information that such a description must contain.&lt;/p&gt;

&lt;p&gt;This is perhaps the most important characteristic of a declarative architecture. The concept comes first. The description remains stable, while the mechanism that executes it may evolve, be replaced, or be completely redesigned without changing the concept itself.&lt;/p&gt;

&lt;p&gt;The next natural question is therefore no longer &lt;strong&gt;what&lt;/strong&gt; a Locator is, nor &lt;strong&gt;how&lt;/strong&gt; it is described, but &lt;strong&gt;how such a declarative description can be transformed into a real, working software component&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is the software engineering problem we will explore in the next article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fundamental Concepts of Business Applications IV: Building a Locator&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>softwareengineering</category>
      <category>design</category>
    </item>
    <item>
      <title>Fundamental Concepts of Business Applications II: The Locator Pattern</title>
      <dc:creator>Theodoros Bebekis</dc:creator>
      <pubDate>Sat, 04 Jul 2026 11:00:26 +0000</pubDate>
      <link>https://dev.to/tbebekis/fundamental-concepts-of-business-applications-ii-the-locator-pattern-3i0d</link>
      <guid>https://dev.to/tbebekis/fundamental-concepts-of-business-applications-ii-the-locator-pattern-3i0d</guid>
      <description>&lt;p&gt;In the previous article, we argued that a ComboBox is not enough.&lt;/p&gt;

&lt;p&gt;Not because there is anything wrong with the control itself, but because the problem it is designed to solve is much smaller than the actual problem faced by a business application.&lt;/p&gt;

&lt;p&gt;That, however, is where we stopped.&lt;/p&gt;

&lt;p&gt;We did not answer the next question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If the problem is not selecting a value, then what exactly is it?&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Let us put frameworks aside for a moment.&lt;/p&gt;

&lt;p&gt;Forget about controls.&lt;/p&gt;

&lt;p&gt;Forget even the word &lt;em&gt;Locator&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Imagine we are editing a line in a sales order.&lt;/p&gt;

&lt;p&gt;The user moves to the product field and types:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PROD-001&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What should happen next?&lt;/p&gt;

&lt;p&gt;The first answer seems obvious.&lt;/p&gt;

&lt;p&gt;"The product should be found."&lt;/p&gt;

&lt;p&gt;Agreed.&lt;/p&gt;

&lt;p&gt;But is that really enough?&lt;/p&gt;




&lt;p&gt;Let us assume the product has been found.&lt;/p&gt;

&lt;p&gt;Are we finished?&lt;/p&gt;

&lt;p&gt;Not at all.&lt;/p&gt;

&lt;p&gt;The application still does not know which sales price applies, which unit of measure should be used, which VAT rate is applicable, or even whether the item is currently available in stock.&lt;/p&gt;

&lt;p&gt;And in many cases, it must know even more.&lt;/p&gt;

&lt;p&gt;Perhaps a different pricing policy applies to this particular customer.&lt;/p&gt;

&lt;p&gt;Perhaps a different price list is currently active.&lt;/p&gt;

&lt;p&gt;Perhaps even the document date changes the result.&lt;/p&gt;

&lt;p&gt;This leads to the first truly interesting question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where does all this information come from?&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Suddenly, the product is no longer simply the product.&lt;/p&gt;

&lt;p&gt;It is the same product &lt;strong&gt;within a specific business context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And that context is not an implementation detail.&lt;/p&gt;

&lt;p&gt;It is not an internal state maintained by whatever mechanism performs the resolution.&lt;/p&gt;

&lt;p&gt;It is an explicit input to the problem itself.&lt;/p&gt;




&lt;p&gt;There is another important observation.&lt;/p&gt;

&lt;p&gt;The user did not enter a ProductId.&lt;/p&gt;

&lt;p&gt;They did not enter a GUID.&lt;/p&gt;

&lt;p&gt;In fact, they are probably unaware that such an identifier even exists.&lt;/p&gt;

&lt;p&gt;They entered:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PROD-001&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In other words, they entered a business reference.&lt;/p&gt;

&lt;p&gt;This is perfectly natural.&lt;/p&gt;

&lt;p&gt;People do not think in terms of technical identifiers.&lt;/p&gt;

&lt;p&gt;They think in product codes.&lt;/p&gt;

&lt;p&gt;Names.&lt;/p&gt;

&lt;p&gt;Barcodes.&lt;/p&gt;

&lt;p&gt;Account numbers.&lt;/p&gt;

&lt;p&gt;Concepts that carry meaning within the business itself.&lt;/p&gt;

&lt;p&gt;That is their language.&lt;/p&gt;




&lt;p&gt;The information system, however, operates differently.&lt;/p&gt;

&lt;p&gt;Its relationships rely on unique, stable identities.&lt;/p&gt;

&lt;p&gt;Primary keys.&lt;/p&gt;

&lt;p&gt;GUIDs.&lt;/p&gt;

&lt;p&gt;Surrogate keys.&lt;/p&gt;

&lt;p&gt;Someone must therefore translate the language of the user into the language of the system.&lt;/p&gt;

&lt;p&gt;And that translation must be correct.&lt;/p&gt;

&lt;p&gt;Within the appropriate business context.&lt;/p&gt;




&lt;p&gt;Up to this point, one could argue that we are simply describing a search.&lt;/p&gt;

&lt;p&gt;I would probably agree.&lt;/p&gt;

&lt;p&gt;At least until the first real business scenario appears.&lt;/p&gt;

&lt;p&gt;Because a search merely returns results.&lt;/p&gt;

&lt;p&gt;Here, however, we are not simply searching.&lt;/p&gt;

&lt;p&gt;We are trying to answer a much more specific question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which business entity does the user actually mean?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a fundamentally different question.&lt;/p&gt;

&lt;p&gt;It is not about discovering information.&lt;/p&gt;

&lt;p&gt;It is about &lt;strong&gt;resolving a business reference&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;Let us now give names to the individual steps of this process.&lt;/p&gt;

&lt;p&gt;The user provides a business reference.&lt;/p&gt;

&lt;p&gt;The application evaluates it within the current business context.&lt;/p&gt;

&lt;p&gt;It attempts to resolve it.&lt;/p&gt;

&lt;p&gt;It arrives at a canonical business identity.&lt;/p&gt;

&lt;p&gt;Finally, it returns the information required for the task to continue.&lt;/p&gt;

&lt;p&gt;Conceptually, the process looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Business Reference
        │
        ▼
 Business Context
        │
        ▼
    Resolution
        │
        ▼
Canonical Identity
        │
        ▼
   Projection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice something interesting.&lt;/p&gt;

&lt;p&gt;There is no ComboBox.&lt;/p&gt;

&lt;p&gt;No Grid.&lt;/p&gt;

&lt;p&gt;No Dialog.&lt;/p&gt;

&lt;p&gt;In fact, there is no user interface at all.&lt;/p&gt;

&lt;p&gt;There is only a process.&lt;/p&gt;




&lt;p&gt;That process does not always produce the same outcome.&lt;/p&gt;

&lt;p&gt;It may find no matching entity.&lt;/p&gt;

&lt;p&gt;It may find exactly one.&lt;/p&gt;

&lt;p&gt;It may find a small number of possible candidates.&lt;/p&gt;

&lt;p&gt;Or it may find so many that the result is no longer useful.&lt;/p&gt;

&lt;p&gt;The last case deserves special attention.&lt;/p&gt;

&lt;p&gt;If the system returns five products, we are dealing with normal business ambiguity.&lt;/p&gt;

&lt;p&gt;The user can easily choose the correct one.&lt;/p&gt;

&lt;p&gt;If, however, it returns five thousand products, we are no longer dealing with ambiguity.&lt;/p&gt;

&lt;p&gt;We are dealing with a business reference that is simply too broad to be resolved.&lt;/p&gt;

&lt;p&gt;The problem is not the list.&lt;/p&gt;

&lt;p&gt;The problem is the reference itself.&lt;/p&gt;

&lt;p&gt;The application should not ask the user to choose one product out of five thousand.&lt;/p&gt;

&lt;p&gt;It should ask for a better business reference.&lt;/p&gt;

&lt;p&gt;This distinction is fundamental.&lt;/p&gt;

&lt;p&gt;Business ambiguity and resolution failure are not the same thing.&lt;/p&gt;




&lt;p&gt;The more closely we examine this process, the harder it becomes to view it as just another UI control.&lt;/p&gt;

&lt;p&gt;The same process can be used by a desktop application.&lt;/p&gt;

&lt;p&gt;A web application.&lt;/p&gt;

&lt;p&gt;A service.&lt;/p&gt;

&lt;p&gt;A data import process.&lt;/p&gt;

&lt;p&gt;An automated workflow.&lt;/p&gt;

&lt;p&gt;The interaction changes.&lt;/p&gt;

&lt;p&gt;The resolution process does not.&lt;/p&gt;

&lt;p&gt;And when the same concept appears in exactly the same form regardless of the application type or user interface, it stops looking like a UI detail and starts looking like an architectural concept.&lt;/p&gt;

&lt;p&gt;Perhaps this is the real meaning of the word &lt;strong&gt;Locator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not as a control.&lt;/p&gt;

&lt;p&gt;Not as a search mechanism.&lt;/p&gt;

&lt;p&gt;But as the name of an architectural concept.&lt;/p&gt;

&lt;p&gt;A concept with one—and only one—purpose:&lt;/p&gt;

&lt;p&gt;To transform human business references into canonical business identities within a specific business context.&lt;/p&gt;

&lt;p&gt;This is what, in this article, we call &lt;strong&gt;The Locator Pattern&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;If the Locator is indeed an architectural pattern, another question immediately follows.&lt;/p&gt;

&lt;p&gt;How should it be described?&lt;/p&gt;

&lt;p&gt;What is the minimum information required to define a Locator?&lt;/p&gt;

&lt;p&gt;How can that description remain independent of the mechanism that executes it?&lt;/p&gt;

&lt;p&gt;In other words,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can a Locator be defined declaratively?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is precisely what we will examine in the next article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fundamental Concepts of Business Applications III: Locator Definitions&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Closing Question
&lt;/h3&gt;

&lt;p&gt;Does this concept already exist, perhaps under a different name, in the framework or platform you use?&lt;/p&gt;

&lt;p&gt;If so, I would genuinely like to learn about it.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>softwareengineering</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Fundamental Concepts of Business Applications I: Why a ComboBox Is Not Enough</title>
      <dc:creator>Theodoros Bebekis</dc:creator>
      <pubDate>Fri, 03 Jul 2026 11:53:16 +0000</pubDate>
      <link>https://dev.to/tbebekis/-fundamental-concepts-of-business-applications-i-why-a-combobox-is-not-enough-pb4</link>
      <guid>https://dev.to/tbebekis/-fundamental-concepts-of-business-applications-i-why-a-combobox-is-not-enough-pb4</guid>
      <description>&lt;h2&gt;
  
  
  Introducing the Locator
&lt;/h2&gt;

&lt;p&gt;If you have developed even a single business application, chances are you have solved the same problem many times.&lt;/p&gt;

&lt;p&gt;You have built a customer search dialog.&lt;/p&gt;

&lt;p&gt;You have implemented product autocomplete.&lt;/p&gt;

&lt;p&gt;You have written a custom editor for a data grid.&lt;/p&gt;

&lt;p&gt;You have created a selection popup.&lt;/p&gt;

&lt;p&gt;Every time, you were essentially solving the same problem.&lt;/p&gt;

&lt;p&gt;Yet most UI libraries do not treat this requirement as a distinct concept. It usually appears as a lookup, an autocomplete, a popup dialog, or some other widget. The implementation changes, but the underlying problem remains exactly the same.&lt;/p&gt;

&lt;p&gt;In this article, I would like to suggest that this recurring requirement deserves to be recognized as a fundamental concept of business applications. I will call it a &lt;strong&gt;Locator&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Problem Found in Every Business Application
&lt;/h2&gt;

&lt;p&gt;Almost every business application contains fields that reference other business entities.&lt;/p&gt;

&lt;p&gt;A sales order references a customer.&lt;/p&gt;

&lt;p&gt;An invoice references a supplier.&lt;/p&gt;

&lt;p&gt;A warehouse transaction references a product.&lt;/p&gt;

&lt;p&gt;A journal entry references an account.&lt;/p&gt;

&lt;p&gt;In the database, these relationships are stored as stable identifiers. Users, however, never think in terms of &lt;code&gt;CustomerId&lt;/code&gt; or &lt;code&gt;ProductId&lt;/code&gt;. They think in terms of customer codes, names, tax numbers, barcodes, and other business identifiers that are meaningful to them.&lt;/p&gt;

&lt;p&gt;The real problem is therefore not how to store an identifier.&lt;/p&gt;

&lt;p&gt;The real problem is how users can locate the correct business entity using the information they already know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a ComboBox Is Not Enough
&lt;/h2&gt;

&lt;p&gt;When the dataset is small, a ComboBox is an excellent solution.&lt;/p&gt;

&lt;p&gt;Countries.&lt;/p&gt;

&lt;p&gt;Currencies.&lt;/p&gt;

&lt;p&gt;Units of Measure.&lt;/p&gt;

&lt;p&gt;Payment Methods.&lt;/p&gt;

&lt;p&gt;These are reference tables containing a few dozen or perhaps a few hundred rows. Loading them into memory is perfectly reasonable, and selecting an item from a list is both fast and convenient.&lt;/p&gt;

&lt;p&gt;The picture changes completely when we talk about Customers, Products, Suppliers, or General Ledger Accounts. Here the number of records may reach thousands—or even hundreds of thousands.&lt;/p&gt;

&lt;p&gt;At this point, the problem is no longer selecting an item from a list.&lt;/p&gt;

&lt;p&gt;The problem is &lt;strong&gt;locating&lt;/strong&gt; the correct record.&lt;/p&gt;

&lt;p&gt;And that is an entirely different problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Locator
&lt;/h2&gt;

&lt;p&gt;Most UI libraries provide general-purpose controls such as TextBox, ComboBox, ListBox, DataGrid, and TreeView.&lt;/p&gt;

&lt;p&gt;Business applications, however, need something different.&lt;/p&gt;

&lt;p&gt;They need a mechanism that allows users to locate a business entity using the information they naturally recognize, rather than its technical identifier.&lt;/p&gt;

&lt;p&gt;This mechanism is what I call a &lt;strong&gt;Locator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its purpose is not to display a list.&lt;/p&gt;

&lt;p&gt;Its purpose is not to suggest possible values.&lt;/p&gt;

&lt;p&gt;Its purpose is to &lt;strong&gt;resolve a business reference&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl53v1asuj92snsewx7zx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl53v1asuj92snsewx7zx.png" alt=" " width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Locator Does Not Simply Return a Value
&lt;/h2&gt;

&lt;p&gt;At first glance, a Locator may look like an advanced lookup control or an autocomplete widget.&lt;/p&gt;

&lt;p&gt;In reality, it does something far more important.&lt;/p&gt;

&lt;p&gt;It does not simply return a value.&lt;/p&gt;

&lt;p&gt;It resolves a business reference.&lt;/p&gt;

&lt;p&gt;Consider a sales order line containing a &lt;code&gt;ProductId&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;The user searches for a product by typing its code or description.&lt;/p&gt;

&lt;p&gt;Once the correct product has been selected, the application usually needs much more than the &lt;code&gt;ProductId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It may need the unit price.&lt;/p&gt;

&lt;p&gt;The unit of measure.&lt;/p&gt;

&lt;p&gt;The VAT rate.&lt;/p&gt;

&lt;p&gt;The discount category.&lt;/p&gt;

&lt;p&gt;It may even need different information depending on the customer, the company, the warehouse, or any other business context in which the search takes place.&lt;/p&gt;

&lt;p&gt;A Locator therefore does not simply return a value.&lt;/p&gt;

&lt;p&gt;It returns the result of resolving a business reference within a specific business context.&lt;/p&gt;

&lt;p&gt;That is why it is much more than an advanced lookup control.&lt;/p&gt;

&lt;h2&gt;
  
  
  It Is Not a Control. It Is a Behavior.
&lt;/h2&gt;

&lt;p&gt;This is perhaps the most important idea.&lt;/p&gt;

&lt;p&gt;A Locator is not a particular user interface control.&lt;/p&gt;

&lt;p&gt;It is a behavior.&lt;/p&gt;

&lt;p&gt;In a desktop form, it may appear as two searchable fields.&lt;/p&gt;

&lt;p&gt;In a data grid, it may be implemented as a custom cell editor.&lt;/p&gt;

&lt;p&gt;In a web application, it may appear as an autocomplete field with a popup results list.&lt;/p&gt;

&lt;p&gt;In a mobile application, it may open a dedicated search screen.&lt;/p&gt;

&lt;p&gt;The appearance changes.&lt;/p&gt;

&lt;p&gt;The behavior remains exactly the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User input

Code
Name
VAT
Barcode

        │
        ▼

     Locator

Searches
Disambiguates
Resolves

        │
        ▼

Target Context

Key
Display values
Business values
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The User Experience
&lt;/h2&gt;

&lt;p&gt;Experienced business application users work almost entirely with the keyboard.&lt;/p&gt;

&lt;p&gt;A good Locator should never interrupt that workflow.&lt;/p&gt;

&lt;p&gt;When a search produces a unique match, the selection should be completed immediately.&lt;/p&gt;

&lt;p&gt;Only when multiple possible matches exist should the user be asked to choose the correct business entity.&lt;/p&gt;

&lt;p&gt;A Locator is not only about searching.&lt;/p&gt;

&lt;p&gt;It is also about disambiguation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Every UI Library Should Include a Locator
&lt;/h2&gt;

&lt;p&gt;Every serious business application solves this problem every day.&lt;/p&gt;

&lt;p&gt;Yet most UI libraries do not recognize it as a fundamental abstraction.&lt;/p&gt;

&lt;p&gt;Instead, every application ends up implementing search dialogs, autocomplete controls, custom editors, and selection popups over and over again.&lt;/p&gt;

&lt;p&gt;The functionality is essentially the same.&lt;/p&gt;

&lt;p&gt;Only the implementation differs.&lt;/p&gt;

&lt;p&gt;I believe that the Locator represents a fundamental concept of business applications, one that is still treated primarily as a collection of unrelated UI widgets.&lt;/p&gt;

&lt;p&gt;Perhaps it is time to recognize it for what it really is: a fundamental abstraction for building data-entry and business applications.&lt;/p&gt;

&lt;p&gt;Because in business applications, the critical concept is not displaying a list.&lt;/p&gt;

&lt;p&gt;It is enabling users to locate the correct business reference.&lt;/p&gt;




&lt;p&gt;In the next article, I will leave philosophy behind and move on to architecture.&lt;/p&gt;

&lt;p&gt;What information should a Locator know?&lt;/p&gt;

&lt;p&gt;How should it be described?&lt;/p&gt;

&lt;p&gt;And how can the same definition be reused across forms, data grids, and different user interface technologies?&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>softwareengineering</category>
      <category>design</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Serialize and deserialize JSON using JsonSerializer</title>
      <dc:creator>Theodoros Bebekis</dc:creator>
      <pubDate>Wed, 04 Jun 2025 12:16:53 +0000</pubDate>
      <link>https://dev.to/tbebekis/serialize-and-deserialize-json-using-jsonserializer-1k4e</link>
      <guid>https://dev.to/tbebekis/serialize-and-deserialize-json-using-jsonserializer-1k4e</guid>
      <description>&lt;p&gt;This text explores the use of the &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer" rel="noopener noreferrer"&gt;JsonSerializer&lt;/a&gt; .Net class in serializing and deserializing .Net classes to &lt;a href="https://www.json.org/json-en.html" rel="noopener noreferrer"&gt;JSON&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;.Net types related to serialization are found in the following namespaces&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json" rel="noopener noreferrer"&gt;System.Text.Json&lt;/a&gt;. Contains the &lt;code&gt;JsonSerializer&lt;/code&gt;, the &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions" rel="noopener noreferrer"&gt;JsonSerializerOptions&lt;/a&gt; and other main types.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization" rel="noopener noreferrer"&gt;System.Text.Json.Serialization&lt;/a&gt;. Contains attributes, converters and similar auxiliary classes used in customizing serialization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is of course the excellent &lt;a href="https://www.newtonsoft.com/json" rel="noopener noreferrer"&gt;Newtonsoft.Json&lt;/a&gt; library but &lt;code&gt;JsonSerializer&lt;/code&gt; is worth using it since it is the native solution provided by .Net and there is no need to install any &lt;a href="https://www.nuget.org/" rel="noopener noreferrer"&gt;NuGet&lt;/a&gt; package in order to use it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;JsonSerializer&lt;/code&gt; can be used with .Net Core 3.0 and later and with .Net Standard 2.0.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The full text and demo project can be found on &lt;a href="https://github.com/tbebekis/Tutorial-JsonSerializer" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Basics
&lt;/h2&gt;

&lt;p&gt;The following code entities are used in this text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public enum Status
{
    None,
    Pending,
    InProgress,
    AllCompleted
}

public class Part
{
    public string Code { get; set; }
    public decimal Amount { get; set; } 
    public bool IsCompleted { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;JsonSerializer&lt;/code&gt; is a &lt;em&gt;static&lt;/em&gt; class. No need to create an instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// serialization
Part P = new(); 
string JsonText =  JsonSerializer.Serialize(P);

// de-serialization
Part P2 = JsonSerializer.Deserialize&amp;lt;Part&amp;gt;(JsonText);

// or
P2 = JsonSerializer.Deserialize(JsonText, typeof(Part)) as Part;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  JsonSerializerOptions
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Serialize()&lt;/code&gt; and &lt;code&gt;Deserialize()&lt;/code&gt; methods accept a &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions" rel="noopener noreferrer"&gt;JsonSerializerOptions&lt;/a&gt; parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonSerializerOptions JsonOptions = new();

// serialization
Part P = new(); 
string JsonText = JsonSerializer.Serialize(P, JsonOptions);

// de-serialization
Part P2 = JsonSerializer.Deserialize&amp;lt;Part&amp;gt;(JsonText, JsonOptions);

// or
P2 = JsonSerializer.Deserialize(JsonText, typeof(Part), JsonOptions) as Part;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;JsonSerializerOptions&lt;/code&gt; controls the behavior of the &lt;code&gt;JsonSerializer&lt;/code&gt;. It provides a great number of properties in order to customize the serialization operation.&lt;/p&gt;

&lt;p&gt;Notable properties worth exploring are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.converters" rel="noopener noreferrer"&gt;Converters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.defaultignorecondition" rel="noopener noreferrer"&gt;DefaultIgnoreCondition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.dictionarykeypolicy" rel="noopener noreferrer"&gt;DictionaryKeyPolicy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.ignorereadonlyproperties" rel="noopener noreferrer"&gt;IgnoreReadOnlyProperties&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.includefields" rel="noopener noreferrer"&gt;IncludeFields&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.numberhandling" rel="noopener noreferrer"&gt;NumberHandling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.propertynamecaseinsensitive" rel="noopener noreferrer"&gt;PropertyNameCaseInsensitive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.propertynamingpolicy" rel="noopener noreferrer"&gt;PropertyNamingPolicy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.readcommenthandling" rel="noopener noreferrer"&gt;ReadCommentHandling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.referencehandler" rel="noopener noreferrer"&gt;ReferenceHandler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.typeinforesolver" rel="noopener noreferrer"&gt;TypeInfoResolver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.web" rel="noopener noreferrer"&gt;Web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.writeindented" rel="noopener noreferrer"&gt;WriteIndented&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example of creating a &lt;code&gt;JsonSerializerOptions&lt;/code&gt; instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonSerializerOptions Result = new();

Result.PropertyNamingPolicy = null;
Result.PropertyNameCaseInsensitive = true;
Result.WriteIndented = true;
Result.IgnoreReadOnlyProperties = true;
Result.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;  
Result.ReadCommentHandling = JsonCommentHandling.Skip;
Result.AllowTrailingCommas = true;
Result.NumberHandling = JsonNumberHandling.AllowReadingFromString;
Result.ReferenceHandler = ReferenceHandler.Preserve;  

return Result;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Attributes
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization" rel="noopener noreferrer"&gt;System.Text.Json.Serialization&lt;/a&gt; namespace provides a great number of attributes that can be used with properties or classes in order to control the serialization.&lt;/p&gt;

&lt;p&gt;Notable attributes worth exploring are:&lt;/p&gt;

&lt;h4&gt;
  
  
  [JsonConstructor]
&lt;/h4&gt;

&lt;p&gt;Indicates a constructor that should be used by the serializer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Part
{
    public Part() 
    {
    }
    [JsonConstructor]
    public Part(string code) 
    {
       Code = code;
    }
    public string Code { get; set; }  
    public decimal Amount { get; set; }  
    public bool IsCompleted { get; set; } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  [JsonConverter]
&lt;/h4&gt;

&lt;p&gt;Specifies what converter type to be used in serialization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonConverter(typeof(JsonStringEnumConverter))]
public Status Status { get; set; }

[JsonConverter(typeof(DateOnlyConverter))]
public DateOnly BirthDate { get; set; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;[JsonConverter(typeof(JsonStringEnumConverter))]&lt;/code&gt; can be used with &lt;em&gt;enum&lt;/em&gt; types also.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Status
{
    None,
    Pending,
    InProgress,
    AllCompleted
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  [JsonIgnore]
&lt;/h4&gt;

&lt;p&gt;Indicates that the property should be ignored in serialization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonIgnore]
public string Secret { get; set; }

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Message { get; set; } // ignored when null, the default

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int Value { get; set; } // ignored when 0, the default

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int Value2 { get; set; } =  123; // ignored when 123, the default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  [JsonInclude]
&lt;/h4&gt;

&lt;p&gt;Forces serialization of a public field or a public property even when it has just a private setter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonInclude]
public int Age;

[JsonInclude]
public string ReadOnlyProperty { get; private set; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  [JsonNumberHandling]
&lt;/h4&gt;

&lt;p&gt;Controls how a number is serialized or deserialized by using a &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonnumberhandling" rel="noopener noreferrer"&gt;JsonNumberHandling&lt;/a&gt; setting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
public int Amount { get; set; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  [JsonPropertyName]
&lt;/h4&gt;

&lt;p&gt;Controls the name under which the property is serialized to or deserialized from.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonPropertyName("user_name")]
public string UserName { get; set; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  [JsonPropertyOrder]
&lt;/h4&gt;

&lt;p&gt;Controls the serialization order of the property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonPropertyOrder(5)]
public string Name { get; set; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  [JsonRequired]
&lt;/h4&gt;

&lt;p&gt;Dictates that the property must be present.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonRequired]
public string Name { get; set; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Attributes from other namespaces
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;None of the following attributes&lt;/strong&gt; is used in &lt;code&gt;System.Text.Json&lt;/code&gt; serialization. &lt;/p&gt;

&lt;p&gt;Only the attributes found in &lt;code&gt;System.Text.Json.Serialization&lt;/code&gt; are taken into account. The &lt;code&gt;System.Text.Json&lt;/code&gt; namespace has its own attributes, all with &lt;code&gt;Json&lt;/code&gt; as prefix.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Except of the &lt;code&gt;System.Text.Json&lt;/code&gt; there are some other namespaces providing validation attributes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;System.ComponentModel.DataAnnotations&lt;/code&gt; namespace. Provides a number of attributes such as &lt;code&gt;[MaxLength]&lt;/code&gt;, &lt;code&gt;[Required]&lt;/code&gt;, &lt;code&gt;[Range]&lt;/code&gt;, etc. Used in &lt;code&gt;Binary Serialization&lt;/code&gt; or &lt;code&gt;SOAP Serialization&lt;/code&gt;. Also used in Asp.Net Core &lt;code&gt;MVC&lt;/code&gt; and &lt;code&gt;WebAPI&lt;/code&gt; model validation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;System.Runtime.Serialization&lt;/code&gt; namespace. Provides  attributes such as &lt;code&gt;[DataContract]&lt;/code&gt; and &lt;code&gt;[DataMember]&lt;/code&gt;. Used by &lt;code&gt;DataContractSerializer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;System.Xml.Serialization&lt;/code&gt; namespace. Provides attributes such as &lt;code&gt;[XmlRoot]&lt;/code&gt;, &lt;code&gt;[XmlElement]&lt;/code&gt;, &lt;code&gt;[XmlAttribute]&lt;/code&gt;. Used in &lt;code&gt;XML Serialization&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The static &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.validator" rel="noopener noreferrer"&gt;System.ComponentModel.DataAnnotations.Validator&lt;/a&gt; class can be used to manually validate classes annotated with &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.validationattribute" rel="noopener noreferrer"&gt;ValidationAttribute&lt;/a&gt; derived attributes, such as &lt;code&gt;MaxLength&lt;/code&gt; and &lt;code&gt;Range&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MyModel Model = JsonSerializer.Deserialize&amp;lt;MyModel&amp;gt;(JsonText);

List&amp;lt;string&amp;gt; ErrorList = Validate(Model);

...

public List&amp;lt;string&amp;gt; Validate(object Instance)
{
    List&amp;lt;string&amp;gt; ErrorList = new();
    var validationContext = new ValidationContext(Instance);
    var validationResults = new List&amp;lt;ValidationResult&amp;gt;();

    // not valid?
    // collect validation errors in a list
    if (!Validator.TryValidateObject(Instance, validationContext, validationResults, true))
    {
        foreach (var validationResult in validationResults)
        {
            ErrorList.Add(validationResult.ErrorMessage);
        }        
    }

    return ErrorList; // empty list means Instance is valid
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Asp.Net Core MVC or WebAPI controllers the &lt;code&gt;ModelState.IsValid&lt;/code&gt; is used to validate attributes based on &lt;code&gt;System.ComponentModel.DataAnnotations&lt;/code&gt; namespace annotations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customize serialization with Converters
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/converters-how-to" rel="noopener noreferrer"&gt;converter&lt;/a&gt; converts an object or a value to and from JSON text.  &lt;/p&gt;

&lt;p&gt;A custom converter can also be used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonConverter(typeof(CustomDateOnlyConverter))]
public DateOnly BirthDate { get; set; }

...

public class CustomDateOnlyConverter : JsonConverter&amp;lt;DateOnly&amp;gt;
{
    public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return DateOnly.Parse(reader.GetString());
    }

    public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString("yyyy-MM-dd"));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two patterns in creating a custom converter&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/converters-how-to#sample-basic-converter" rel="noopener noreferrer"&gt;Basic pattern&lt;/a&gt;. The custom converter derives from &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverter-1" rel="noopener noreferrer"&gt;&lt;code&gt;JsonConverter&amp;lt;TValue&amp;gt;&lt;/code&gt;&lt;/a&gt; class.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/converters-how-to#sample-factory-pattern-converter" rel="noopener noreferrer"&gt;Factory pattern&lt;/a&gt;. The custom converter derives from &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverterfactory" rel="noopener noreferrer"&gt;JsonConverterFactory&lt;/a&gt; class.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A custom converter can be registered&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;by adding an instance of the custom converter to &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.converters" rel="noopener noreferrer"&gt;JsonSerializerOptions.Converters&lt;/a&gt; collection&lt;/li&gt;
&lt;li&gt;by applying the &lt;code&gt;[JsonConverter]&lt;/code&gt; to a class that represents a custom value type&lt;/li&gt;
&lt;li&gt;by applying the &lt;code&gt;[JsonConverter]&lt;/code&gt; to properties that require the custom converter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When there are multiple converters applied then there are &lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/converters-how-to#converter-registration-precedence" rel="noopener noreferrer"&gt;rules that dictate the order&lt;/a&gt; by which a converter is chosen in serialization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customize serialization with a Resolver and Modifier functions
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.typeinforesolver" rel="noopener noreferrer"&gt;JsonSerializerOptions.TypeInfoResolver&lt;/a&gt; property provides a way to plug &lt;code&gt;modifier&lt;/code&gt; functions of the type &lt;code&gt;Action&amp;lt;JsonTypeInfo&amp;gt;&lt;/code&gt; into serialization.&lt;/p&gt;

&lt;p&gt;Inline modifiers with lambda functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonSerializerOptions JsonOptions = new()
{
    TypeInfoResolver = new DefaultJsonTypeInfoResolver
    {
        Modifiers =
        {
            (TypeInfo) =&amp;gt; {
                //...
            },
            (TypeInfo) =&amp;gt; {
                //...
            }
        }
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or usual methods in a class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static public class Helper
{
    static public void ModifierFunc1(JsonTypeInfo TypeInfo)
    {
        //...
    }
    static public void ModifierFunc2(JsonTypeInfo TypeInfo)
    {
        //...
    }
}

JsonSerializerOptions JsonOptions = new();
Json.Options.Modifiers.Add(Helper.ModifierFunc1);
Json.Options.Modifiers.Add(Helper.ModifierFunc2);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a custom resolver that excludes a list of specified properties from serialization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ExcludePropertiesTypeInfoResolver : DefaultJsonTypeInfoResolver
{
    string[] ExcludeProperties = new string[0];

    static void RemoveAll&amp;lt;T&amp;gt;(IList&amp;lt;T&amp;gt; list, Predicate&amp;lt;T&amp;gt; predicate)
    {
        for (int i = 0; i &amp;lt; list.Count; i++)
        {
            if (predicate(list[i]))
            {
                list.RemoveAt(i--);
            }
        }
    }
    void ModifierFunc(JsonTypeInfo TypeInfo)
    {
        if (TypeInfo.Kind != JsonTypeInfoKind.Object)
            return;

        RemoveAll(TypeInfo.Properties, prop =&amp;gt; ExcludeProperties.Contains(prop.Name)); 
    }

    public ExcludePropertiesTypeInfoResolver(string[] ExcludeProperties)
    {
        this.ExcludeProperties = ExcludeProperties;
        this.Modifiers.Insert(0, ModifierFunc);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is how to use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var ExcludeProperties = new[] { "Prop1", "Prop2"};

JsonSerializerOptions JsonOptions = new()
{
    TypeInfoResolver = new ExcludePropertiesTypeInfoResolver(ExcludeProperties)
}; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.metadata.jsontypeinfo" rel="noopener noreferrer"&gt;JsonTypeInfo&lt;/a&gt; provides metadata about the type being serialized.&lt;/p&gt;

&lt;p&gt;Regarding modifier functions .Net Core docs provide a number of &lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/custom-contracts#modifiers" rel="noopener noreferrer"&gt;examples&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Property Name Casing
&lt;/h2&gt;

&lt;p&gt;The casing of a property name, such as camel-casing, is controlled by the &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.propertynamingpolicy" rel="noopener noreferrer"&gt;JsonSerializerOptions.PropertyNamingPolicy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PropertyNamingPolicy&lt;/code&gt; property is a &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonnamingpolicy" rel="noopener noreferrer"&gt;JsonNamingPolicy&lt;/a&gt; derived class. When it is &lt;strong&gt;null&lt;/strong&gt;, the default, property names remain unchanged.&lt;/p&gt;

&lt;p&gt;That &lt;code&gt;JsonNamingPolicy&lt;/code&gt; class provides a number of static properties that return a &lt;code&gt;JsonNamingPolicy&lt;/code&gt; derived class instance, such as &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonnamingpolicy.camelcase" rel="noopener noreferrer"&gt;CamelCase&lt;/a&gt; or &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonnamingpolicy.snakecaselower" rel="noopener noreferrer"&gt;SnakeCaseLower&lt;/a&gt;. Each one for a specific casing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonSerializerOptions JsonOptions = new();

JsonOptions.PropertyNamingPolicy = JsonNamingPolicy.CameCase; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The PopulateObject() problem.
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;System.Text.Json&lt;/code&gt; provides a solution under the title &lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/populate-properties" rel="noopener noreferrer"&gt;Populate initialized properties&lt;/a&gt; which is far from what is actully needed.&lt;/p&gt;

&lt;p&gt;Frequently there are cases where there is an already constructed instance that needs to be populated using data coming as json text. This is a problem that the &lt;code&gt;System.Text.Json&lt;/code&gt; has no solution to offer yet.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;JsonSerializer.Deserialize()&lt;/code&gt; methods always create and return a new instance. This is not always what an application needs. &lt;/p&gt;

&lt;p&gt;But deep in the .Net source code there is a class containing a method that do just that. The &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.graph.derivedtypeconverter" rel="noopener noreferrer"&gt;Microsoft.Graph.DerivedTypeConverter&lt;/a&gt; contains a &lt;strong&gt;private&lt;/strong&gt; method, named &lt;a href="https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/blob/57861dc4aea6c33908838915c97fc02105b6e788/src/Microsoft.Graph.Core/Serialization/DerivedTypeConverter.cs#L112-L114" rel="noopener noreferrer"&gt;PopulateObject()&lt;/a&gt; which does exactly what it says.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The project that accompanies this text contains a static class under the name &lt;code&gt;NetJson&lt;/code&gt; which provides, among other useful utilities, a &lt;code&gt;PopulateObject()&lt;/code&gt; method. This &lt;code&gt;PopulateObject()&lt;/code&gt; method is just the code from the &lt;code&gt;Microsoft.Graph.DerivedTypeConverter.PopulateObject()&lt;/code&gt; private method.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;static public void PopulateObject(object Instance, string JsonText, JsonSerializerOptions Options)&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Document Object Model (DOM) of System.Text.Json
&lt;/h2&gt;

&lt;p&gt;Except of the &lt;code&gt;JsonSerializer&lt;/code&gt; the .Net Core serialization sub-system provides a &lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/use-dom" rel="noopener noreferrer"&gt;DOM model&lt;/a&gt; too.&lt;/p&gt;

&lt;p&gt;The system provides two ways in building a DOM model.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.nodes.jsonobject" rel="noopener noreferrer"&gt;System.Text.Json.JsonObject&lt;/a&gt; class, along with &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.nodes.jsonnode" rel="noopener noreferrer"&gt;JsonNode&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.nodes.jsonarray" rel="noopener noreferrer"&gt;JsonArray&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.nodes.jsonvalue" rel="noopener noreferrer"&gt;JsonValue&lt;/a&gt; classes&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsondocument" rel="noopener noreferrer"&gt;System.Text.Json.JsonDocument&lt;/a&gt; along with &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement" rel="noopener noreferrer"&gt;JsonElement&lt;/a&gt; class.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  JsonObject, JsonNode, JsonArray and JsonValue
&lt;/h2&gt;

&lt;p&gt;These are mutable classes, meaning the application may add, modify or remove elements in the DOM tree.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;JsonNode&lt;/code&gt; is an abstract class. Besides that it provides a great number of &lt;strong&gt;static&lt;/strong&gt; helper methods for adding elements to the DOM tree. It also serves as the base class for the others in this group.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JsonObject&lt;/code&gt; represents a mutable DOM object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JsonArray&lt;/code&gt; represents a mutable DOM array object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JsonValue&lt;/code&gt; represents a mutable DOM value object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the above provide the following properties &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an integer indexer property &lt;code&gt;Item[Int32]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a string indexer property &lt;code&gt;Item[String]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;Count&lt;/code&gt; property&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the above provide the following methods &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AsObject()&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AsArray()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AsValue()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetPath()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetPropertyName()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetType()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GetValue&amp;lt;T&amp;gt;()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GetValueKind()&lt;/code&gt; which returns a value of the &lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonvaluekind" rel="noopener noreferrer"&gt;JsonValueKind&lt;/a&gt; enum&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ReplaceWith&amp;lt;T&amp;gt;(T)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToJsonString()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;JsonObject&lt;/code&gt; and &lt;code&gt;JsonArray&lt;/code&gt; provide the following methods too&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Add()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Clear()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Remove()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RemoveAt()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Primitive Values using JsonValue.Create(AnyPrimitiveValue)
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;JsonObject&lt;/code&gt; properties are &lt;code&gt;Key-Value&lt;/code&gt; pairs, i.e. &lt;code&gt;JORoot.Add(PropertyName, PropertyValue)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;JsonValue.Create(AnyPrimitiveValue)&lt;/code&gt; is used with primitive Types such as string and integer, in creating new &lt;code&gt;JsonValue&lt;/code&gt; objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonObject JORoot = new();
JORoot.Add("String", JsonValue.Create("This is a JsonValue"));
JORoot.Add("DateTime", JsonValue.Create(DateTime.Now));
JORoot.Add("Integer", JsonValue.Create(123));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Removing a Property
&lt;/h4&gt;

&lt;p&gt;Using the &lt;code&gt;Remove(PropertyName)&lt;/code&gt; removes the property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JORoot.Remove("DateTime");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  JsonObject is a Dictionary-like object
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;JsonObject&lt;/code&gt; instances are &lt;code&gt;Dictionary-like&lt;/code&gt; objects and a new &lt;code&gt;JsonObject&lt;/code&gt; can be initialized as following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonObject JORoot = new JsonObject
{
    ["Key1"] = "This is a string",
    ["Key2"] = DateTime.Now,
    ["Key3"] = false,
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The JsonNode.Parse() method
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;JsonNode.Parse(JsonText)&lt;/code&gt; &lt;strong&gt;static&lt;/strong&gt; method parses text and returns a &lt;code&gt;JsonNode&lt;/code&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonObject JORoot = new();
JORoot.Add("Person", JsonNode.Parse("""{ "Name": "John Doe", "Age": 30 }"""));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using the JsonValue.Create&amp;lt;T&amp;gt;() with non-primitive Types
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;JsonValue.Create&amp;lt;T&amp;gt;()&lt;/code&gt; is used with non-primitive Types such as user defined classes, in creating new &lt;code&gt;JsonValue&lt;/code&gt; objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonObject JORoot = new();
JORoot.Add("Part", JsonValue.Create&amp;lt;Part&amp;gt;(new Part()));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Initializing a JsonArray
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonObject JORoot = new();
JsonArray JOArray = new JsonArray() { 123, true, DateTime.Now, "string value" };
JORoot.Add("Array", JOArray);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using a Dictionary
&lt;/h4&gt;

&lt;p&gt;A &lt;code&gt;Dictionary&amp;lt;string, JsonNode&amp;gt;&lt;/code&gt; can be used in adding a property to a &lt;code&gt;JsonObject&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Dictionary&amp;lt;string, JsonNode&amp;gt;&lt;/code&gt; dictionary has to be converted to a &lt;code&gt;JsonObject&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;This can be done because &lt;code&gt;JsonObject&lt;/code&gt; provides a suitable constructor.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;public JsonObject(IEnumerable&amp;lt;KeyValuePair&amp;lt;string, JsonNode?&amp;gt;&amp;gt; properties, JsonNodeOptions? options = null)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JsonObject JORoot = new();

var Dictionary = new Dictionary&amp;lt;string, JsonNode&amp;gt;
{
    ["Key1"] = "This is a string",
    ["Key2"] = DateTime.Now,
    ["Key3"] = false,
    ["Key4"] = JsonValue.Create&amp;lt;Status&amp;gt;(Status.InProgress),
};

JsonObject DicNode = new JsonObject(Dictionary);
JORoot.Add("Dictionary", DicNode);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Accessing Properties and Values
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;string DemoJsonText = """
        {
            "Id": 1,
            "Name": "Model 1",
            "Status": "InProgress",
            "Active": true,
            "Parts": [
                {
                "Code": "001",
                "Amount": 1.2,
                "IsCompleted": true
                },
                {
                "Code": "002",
                "Amount": 3.4,
                "IsCompleted": false
                }
            ],
            "Properties": {
            "John": "Doe",
            "NiceCar": "Volvo"
            },
            "DT": "2025-06-04T00:59:25.6948527+03:00"
        }
        """;

JsonNode RootNode = JsonNode.Parse(DemoJsonText);

// accessing array
JsonNode PartsNode = RootNode["Parts"];
JsonNode FirstPartNode = PartsNode[0]; 

// adding new property
JsonObject ThirdPartNode = new();
ThirdPartNode["Code"] = "003";
ThirdPartNode["Amount"] = 12.3;
ThirdPartNode["IsCompleted"] = true;

// get node as array
JsonArray ArrayNode = PartsNode.AsArray();
ArrayNode.Add(ThirdPartNode);

// typecasting nodes
JsonNode PropNode = ThirdPartNode["Amount"];
double V = (double)PropNode;
// 12.3

string S = (string)ThirdPartNode["Code"];
// 003

// using the GetValue&amp;lt;T&amp;gt;()
DateTime DateTimeNode = RootNode["DT"].GetValue&amp;lt;DateTime&amp;gt;();

// get the path
string S2 = RootNode["Parts"][0].GetPath();
// $.Parts[0]   where $ denotes the root node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  JsonDocument
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;JsonDocument&lt;/code&gt; is used in building a &lt;strong&gt;read-only&lt;/strong&gt; DOM. It provides the &lt;code&gt;RootElement&lt;/code&gt; of type &lt;code&gt;JsonElement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;JsonDocument&lt;/code&gt; elements are accessed using the &lt;code&gt;JsonElement&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;JsonElement&lt;/code&gt; class provides enumerators in order to iterate over its elements.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;JsonElement&lt;/code&gt; class provides methods such as &lt;code&gt;GetInt32()&lt;/code&gt; and &lt;code&gt;TryGetInt32()&lt;/code&gt; which convert JSON text to .Net primitive types.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: &lt;code&gt;JsonElement&lt;/code&gt; is an &lt;code&gt;IDisposable&lt;/code&gt; type.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;double Total = 0;

using (JsonDocument Doc = JsonDocument.Parse(DemoJsonText))
{
    JsonElement Root = Doc.RootElement;
    JsonElement PartsProperty = Root.GetProperty("Parts");
    foreach (JsonElement PartProperty in PartsProperty.EnumerateArray())
    {
        if (PartProperty.TryGetProperty("Amount", out JsonElement AmountElement))
        {
            Total += AmountElement.GetDouble();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
