Software: Which Design is Architectural?

“Not all design is architectural” is widely repeated. Non-circular answers to “which design is architectural?” are less common. Here's one:

A design or decision is architectural if it impacts the system as a Whole, not merely in part.

(from @visarch 2004, http://www.bredemeyer.com/pdf_files/WhitePapers/ArchitectureAsBusinessCompetency.PDF )

C# nullable refs and virtual vs abstract properties

Consider:

public class InitialStep2Sqlite : ScriptMigration
{
    protected override string UpPath => "Sqlite2.Up.sql";
    protected override string DownPath => "Sqlite2.Down.sql";
}

public abstract class ScriptMigration : Migration
{
  protected virtual string UpPath {get;}
  protected virtual string DownPath {get;}

  protected override void Up(MigrationBuilder mb) 
    => mb.RunSqlFile(UpPath);
  protected override void Down(MigrationBuilder mb) 
    => mb.RunSqlFile(DownPath);
}

which, compiled under nullable enable, says “[CS8618] Non-nullable property 'UpPath' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.”

Changing the property's virtual to abstact removes the warning.

The lesson: If your non-null proof of a property depends crucially on the subclass making it non-null, then making the parent property abstract not virtual is the correct statement of intent.

Generally, if a parent Member depends on the subclass for correctness – if the parent can't provide a correct implementation itself – then, logically, its correctness requires it to be abstract not virtual.

Model Binding an Array from a Form Post | Asp.Net MVC & Asp.Net Core

if you form post html form fields:

<li>
  <label for="name">Your name<span>*</span></label>
  <input type="text" id="name" name="Name" />
</li>
<li>
  <label for="phoneNumber">Telephone<span>*</span></label>
  <input type="tel" id="phoneNumber" name="PhoneNumber" />
</li>

to a Controller using the [FromForm] attribute, AspNet will modelbind the form fields to your parameters by matching the name= attribute of the input elements to Property names on the parameter class:

class MyController : Controller
{
    public IActionResult Index([FromForm]Contact contact){ ... }
}

// ----
public class Contact
{
    public string Name {get;set;}
    public string PhoneNumber {get;set;}
}

But what about model binding an array — for instance, if you have a list of question inputs, and want to store the answers in a list?

If you name each field as if it were an array element:

 <fieldset id="q1">
     <label class="question">Question 1</label>
     <ul class="form-style">
        <li>
            <input type="radio" id="c1" name="answers[0]" value="@c1"/>
            <label for="c1">@c1</label>
        </li>
        <li>
            <input type="radio" id="c2" name="answers[0]" value="@c2"/>
            <label for="c2">@c2</label>
        </li>
    </ul>
  </fieldset>
    <fieldset id="q2">
        <label class="question">Question 1?</label>
        <ul class="form-style">
            <li>
                <input type="radio" id="b1" name="answers[1]" value="@b1"/>
                <label for="b1">@b1</label>
            </li>
            <li>
                <input type="radio" id="b2" name="answers[1]" value="@b2"/>
                <label for="b2">@b2</label>
            </li>
            <li>
                <input type="radio" id="b3" name="answers[1]" value="@b3"/>
                <label for="b3">@b3</label>
            </li>
            <li>
                <input type="radio" id="b4" name="answers[1]" value="@b4"/>
                <label for="b4">@b4</label>
            </li>
        </ul>
    </fieldset>

then AspNet will bind the submitted fields named answers[0], answers[1], ... to an array Property in your class with the matching name:

public class Questions
{
    public string[] Answers {get;set;}
}

.Net Core Strong Typed Configuration Binding for Arrays | Microsoft.Extensions.Configuration

The .Net Core Microsoft.Extensions.Configuration package includes the ConfigurationBinder.Get<>() method which can read a config file and bind name-value entries to a class. This gives you strongly typed configuration:

public class FromTo
{
    public string From { get; init; }
    public string To { get; init; }
}

The method is an extension method for Configuration so you can call it straight off a Configuration instance. In an Asp.Net Startup.cs class, for instance:

services.AddSingleton(
    s=>Configuration
            .GetSection("fromto").Get<FromTo>());

will result in your services collection knowing to provide an FromTo class with the Properties populated from the configuration entries, matched by section:propertyname :

{
  "fromto:from": "[email protected]",
  "fromto:to": "[email protected]"
}

or if you use secrets:

cd <projectdirectory>
dotnet user-secrets init
dotnet user-secrets set fromto:from [email protected]
dotnet user-secrets set fromto:to [email protected]

That works great for the usual primitives - string, numbers, boolean — but what about binding an Array?

public class FromTo
{
    public string From { get; init; }
    public string To[] { get; init; }
}

the From field is still bound but the To field silently fails and results in a null value.

The magic trick is to add a colon-separated number suffix to each setting name:

{
  "fromto:from": "[email protected]",
  "fromto:to:0": "[email protected]",
  "fromto:to:1": "[email protected]",
  "fromto:to:2": "[email protected]",
}

Now Configuration.GetSection("fromto").Get<FromTo>() will successfully bind all 3 rows for "fromto:to into the public string To[] array.