Quick Start¶
A step-by-step guide to building a .NET equipment application with Port.
1. Overview¶
The Port Framework aims to enable flexible service architecture by seamlessly integrating physical documentation with system design.
In traditional development environments, we often encounter communication bottlenecks caused by:
- Inconsistent variable naming between hardware specifications and software code.
- The manual overhead of re-allocating variables whenever documentation changes.
- Ambiguous service designs that lead to development delays.
To resolve these issues, Port Framework automates the bridge between your specifications (.docx, .xlsx, *.csv) and implementation (.cs), ensuring a "Single Source of Truth."
2. Document Conversion (DOCX to Code)¶
The framework translates your specification tables into structured data models.
2.1 Source Specification¶
Assume a table exists in C:\Users\admin\Documents\IO.docx as follows:
| IO.No | Description | Model |
|---|---|---|
| D0.01 | Bulb1.OnOff | IODevice |
| D0.02 | Bulb2.OnOff | IODevice |
| A0.01 | Bulb1.Temp | IODevice |
| A0.02 | Bulb2.Temp | IODevice |
Figure 1: Sample Specification Table
2.2 Define Document Model¶
Map the table columns to a C# class using attributes.
public class IOModel
{
[ColumnHeader("IO.No"), EntryProperty]
public string IONo { get; set; } = null!;
[ColumnHeader("Description"), EntryKey]
public string Description { get; set; } = null!;
[ColumnHeader("Model"), EntryProperty]
public string Model { get; set; } = null!;
}
2.3 Execution: Conversion & Generation¶
The Convert() function processes the document and generates the necessary configuration and constant files.
public void Convert()
{
try
{
if (!Directory.Exists("C:\\Users\\admin\\Documents\\Sample"))
{
Port.Repository.New("C:\\Users\\admin\\Documents\\Sample", "sample");
}
var doc = Port.Document<IOModel>(@"C:\Users\admin\Documents\IO.docx");
doc.Where(v => v.Key.Contains("OnOff")).ToList().ForEach(v => v.DataType = "Enum.OnOff");
doc.Where(v => v.Key.Contains("Temp")).ToList().ForEach(v => v.DataType = "f8");
if (doc.Count > 0)
{
doc.New(@"C:\Users\admin\Documents\sample\port\device\io.page");
doc.New(@"C:\Users\admin\Documents\sample\.net\io.cs");
}
Port.Push("C:\\Users\\admin\\Documents\\Sample\\port", "sample", "v0.0.1");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
3. Project Configuration¶
3.1 Initialize Project¶
3.2 Page Files (.page)¶
The .page file is a collection of Entry definitions. Packages are referenced using the pkg: prefix.
[io.page]
Bulb1OnOff Enum.OnOff property:{"IO.No":"D0.01","Model":"IODevice"}
Bulb2OnOff Enum.OnOff property:{"IO.No":"D0.02","Model":"IODevice"}
Bulb1Temp f8 property:{"IO.No":"A0.01","Model":"IODevice"}
Bulb2Temp f8 property:{"IO.No":"A0.02","Model":"IODevice"}
3.3 Custom User Entries¶
You can define additional entries that are not part of the hardware document (e.g., logic setpoints) by creating localized .page files.
[bulb1/.page]
3.4 Generated Code Files (.cs)¶
The .cs file contains constant definitions for the entries, which can be used in your application code.
[io.cs]
// Auto-generated by Port. Do not edit manually.
namespace sample
{
public static class Io
{
public const string Bulb1OnOff = "Bulb1OnOff";
public const string Bulb2OnOff = "Bulb2OnOff";
public const string Bulb1Temp = "Bulb1Temp";
public const string Bulb2Temp = "Bulb2Temp";
}
}
4. MCF Pattern (Model, Controller, Flow)¶
The MCF pattern decouples data (Model) from logic (Flow) via a centralized Controller.
4.1 Binding the Model¶
Models use [Binding] attributes to link software properties to the Entry keys defined in your documents.
[Model]
public class BulbModel
{
// Bind multiple instances (Bulb1, Bulb2) to the same property structure
[Binding("Bulb1", io.Bulb1_OnOff)]
[Binding("Bulb2", io.Bulb2_OnOff)]
public Entry OnOff { get; set; }
[Binding("Bulb1", io.Bulb1_Temp)]
[Binding("Bulb2", io.Bulb2_Temp)]
public Entry Temp { get; set; }
[Binding("Bulb1", io.Bulb1_TargetTemp)]
[Binding("Bulb2", io.Bulb2_TargetTemp)]
public Entry TargetTemp { get; set; }
}
4.2 Defining Logic with Flows¶
A Controller contains Flows, which are sequences of FlowSteps.
[Controller]
public class BulbController
{
[Flow("BulbOn")]
public class BulbOn
{
[FlowHandler]
public IFlowHandler handler { get; set; } = null!;
[FlowStep(0)] // Validation Step
public void CheckInitialState(BulbModel model)
{
if (model.Temp.Value <= 100)
{
handler?.Next();
}
}
[FlowStep(1)] // Action Step
public void TurnOn(BulbModel model)
{
model.OnOff.Set("On");
handler?.Next();
}
[FlowStep(2)] // Monitoring Step
public void MonitorTemperature(BulbModel model)
{
if (model.Temp.Value >= model.TargetTemp.Value)
{
model.OnOff.Set("Off");
handler?.Next(); // Marks Flow as Completed
}
}
}
}
5. Runtime & Repository Management¶
5.1 Loading the Repository¶
Synchronize the repository and initialize the runtime components.
if (Port.Repository.Load("sample"))
{
try
{
// Add controllers with unique identifiers
Port.Add<BulbController, BulbModel>("Bulb1");
Port.Add<BulbController, BulbModel>("Bulb2");
Port.Run();
Port.OnReady += (s, e) => { /* Initialization Logic */ };
}
catch (Exception ex)
{
Console.WriteLine($"Initialization Failed: {ex.Message}");
}
}
5.2 Fast In-Memory Access¶
Access and control entries in real-time with high performance.