C4Sharp (C4S
) is a .net library for building diagram as code, based on C4 Model. It's works
like a superset of C4-PlantUML through which developers can create,
share, and consume C4 Model diagrams as code (C#) such as Context, Container, Component and
Deployment diagrams. The library generates the following diagram types:
GETTING STARTED
The C4 model is an easy to learn, developer friendly approach to software architecture diagramming. Good software architecture diagrams assist with communication inside/outside of software development/product teams, efficient onboarding of new staff, architecture reviews/evaluations, risk identification (e.g. risk-storming), threat modelling (e.g. STRIDE/LINDDUN), etc.
SIMON BROWN
Installing
Fist, you will need the .NET 5.0+ and Java to run C4Sharp. Also, you should install C4Sharp package in your project. This package is available through Nuget Packages.
Package | Description | Version | Downloads | Maintainability | Status |
---|---|---|---|---|---|
C4SHARP |
dotnet library for building diagrams | ||||
C4SCLI |
cli for compiling C4S projects |
DIAGRAM AS CODE
There are benefits to using these tools over the heavier alternatives, including easy version control and the ability to generate the DSLs from many sources. ools in this space that we like include Diagrams, Structurizr DSL, AsciiDoctor Diagram and stables such as WebSequenceDiagrams, PlantUML and the venerable Graphviz. It's also fairly simple to generate your own SVG these days, so don't rule out quickly writing your own tool either. One of our authors wrote a small Ruby script to quickly create SVGs, for example.
Thoughtworks Technology Radar
Coding
To build a diagram using the C4S library we need to identify the structures and their relationships through a class that inherits properties directly from DiagramBuildRunner. See the following example of building a container diagram:
namespace C4Bank.Deposit.Architecure;
public class ContainerDiagram : DiagramBuildRunner
{
protected override string Title => "C4Bank Context of Deposit Area";
protected override DiagramType DiagramType => DiagramType.Container;
protected override IEnumerable<Structure> Structures => new Structure[]
{
new Person("Customer", "Customer", "Bank Customer"),
new SoftwareSystem("OTBank.Finance", "Finance", "OTBank Finance System", Boundary.External),
new SoftwareSystem("C4Bank.Account", "Account", "C4Bank Account System"),
new Api<DepositReceived>("Aspnet/C#", "ACL"),
new EventStreaming<RegisteredAccount>("kafka", "Partition 01"),
SoftwareSystemBoundary.New("Deposit",
new Api<DepositoProcessingWorker>("C#"),
new Database<IDepositRepository>("SQL Server", "Deposit Data Base"),
new ServerConsole<SynchronizeNewAccountConsumer>("C#", "Kafka Consumer"),
new Database<IAccountRepository>("SQL Server", "Account Data Base")
),
};
protected override IEnumerable<Relationship> Relationships => new[]
{
It("Customer") > It("OTBank.Finance") | "send deposit",
It("OTBank.Finance") > It<DepositReceived>() | ("POST", "HTTP"),
It<DepositoProcessingWorker>() < It<DepositReceived>() | ("POST", "HTTP"),
It<DepositoProcessingWorker>() > It<IDepositRepository>(),
It("Customer") > It("C4Bank.Account") | "register",
It("C4Bank.Account") > It<RegisteredAccount>() | "produces",
It<SynchronizeNewAccountConsumer>() > It<RegisteredAccount>() | "consumes",
It<SynchronizeNewAccountConsumer>() > It<IAccountRepository>(),
It<DepositoProcessingWorker>() > It<IAccountRepository>(),
};
}
Code 1 - container diagram as code
Compiling
There are two strategies for compiling diagrams in your project: self-compiling and using the C4SCLI
tool.
a) self-compiling approach:
Code the following structure into program.cs
. In this approach, it is preferable that you use a separate project.
internal static class Program
{
private static void Main()
{
var diagrams = new[]
{
new ContainerDiagram().Build(),
};
new PlantumlSession()
.UseDiagramImageBuilder()
.UseDiagramSvgImageBuilder()
.Export(diagrams);
}
}
Code 2 - self-compiling approach
see the complete code here
b) Using the C4SCLI tool:
The C4SCLI
can be used in DevOps pipelines, removing the need to manually compile diagrams. For this, install C4SCLI
tool and execute de the following command:
$ c4scli build <solution path> [-o <output path>]
see the following sample
$ mkdir assets
$ c4scli build /src/c4sharp.sln -o /c4
...
C4 diagram PNG files
C4 diagram generated: file:////c4/internet-banking-system-api-application-c4component.png
C4 diagram generated: file:////c4/system-context-diagram-for-internet-banking-system-c4context.png
C4 diagram generated: file:////c4/container-diagram-for-internet-banking-system-c4container.png
C4 diagram generated: file:////c4/system-context-diagram-for-internet-banking-system-c4deployment.png
C4 diagram generated: file:////c4/system-enterprise-diagram-for-internet-banking-system-c4context.png
C4 diagram SVG files
C4 diagram generated: file:////c4/internet-banking-system-api-application-c4component.svg
C4 diagram generated: file:////c4/system-enterprise-diagram-for-internet-banking-system-c4context.svg
C4 diagram generated: file:////c4/system-context-diagram-for-internet-banking-system-c4deployment.svg
C4 diagram generated: file:////c4/container-diagram-for-internet-banking-system-c4container.svg
C4 diagram generated: file:////c4/system-context-diagram-for-internet-banking-system-c4context.svg
C4 diagram MD files
C4 diagram generated: file:////c4/internet-banking-system-api-application-c4component.mermaid.md
C4 diagram generated: file:////c4/system-context-diagram-for-internet-banking-system-c4context.mermaid.md
C4 diagram generated: file:////c4/container-diagram-for-internet-banking-system-c4container.mermaid.md
C4 diagram generated: file:////c4/system-enterprise-diagram-for-internet-banking-system-c4context.mermaid.md
C4 diagram PUML files
C4 diagram generated: file:////c4/system-enterprise-diagram-for-internet-banking-system-c4context.puml
C4 diagram generated: file:////c4/internet-banking-system-api-application-c4component.puml
C4 diagram generated: file:////c4/system-context-diagram-for-internet-banking-system-c4context.puml
C4 diagram generated: file:////c4/container-diagram-for-internet-banking-system-c4container.puml
C4 diagram generated: file:////c4/system-context-diagram-for-internet-banking-system-c4deployment.puml
The Result
The previous steps will result in the following image:
You can customize the diagram by implementing the SetStyle() method, as in the following example:
protected override IElementStyle? SetStyle()
{
return new ElementStyle()
.UpdateElementStyle(ElementName.Person, "#000000", "#000000")
.UpdateElementStyle(ElementName.Container, "#ffffff", "#000000", "#000000", false, Shape.RoundedBoxShape)
.UpdateElementStyle(ElementName.System, "#f4f4f4", "#000000", "#000000", false, Shape.RoundedBoxShape)
.UpdateElementStyle(ElementName.ExternalSystem, "#f4f4f4", "#000000", "#000000", false, Shape.RoundedBoxShape);
}
Compiling Mermaid Markdown
Now, C4Sharp can compile the Mermaid markdown file. For this, you should use the function UseDiagramMermaidBuilder()
. The following code shows how to compile these files.
context
.UseDiagramImageBuilder()
.UseDiagramSvgImageBuilder()
.UseDiagramMermaidBuilder()
.Export(diagrams);
Using the code above you'll have the following result:
C4Context
title System Enterprise diagram for Internet Banking System
Person_Ext(customer, "Personal Banking Customer", "A customer of the bank, with personal bank accounts.")
Enterprise_Boundary(enterprise.boundary, "Domain A") {
System(BankingSystem, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.", $tags="services")
Enterprise_Boundary(enterprise.boundary.1, "Domain Internal Users") {
Person(internalcustomer, "Personal Banking Customer", "An internal customer of the bank, with personal bank accounts.")
}
Enterprise_Boundary(enterprise.boundary.2, "Domain Managers") {
Person(manager, "Manager Banking Customer", "A manager of the bank, with personal bank accounts.")
}
}
System_Ext(Mainframe, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
System_Ext(MailSystem, "E-mail system", "The internal Microsoft Exchange e-mail system.")
Rel(customer, BankingSystem, "uses")
Rel(internalcustomer, BankingSystem, "uses")
Rel(manager, BankingSystem, "uses")
Rel_Back(customer, MailSystem, "Sends e-mails to")
Rel(BankingSystem, MailSystem, "Sends e-mails", "SMTP")
Rel(BankingSystem, Mainframe, "uses")
See the complete code here.
LEARN
- See more in our sample code:
- To learn more about
C4S
access our wiki.
THANKS
C4 community
π Simon Brownπ PlantUML Teamπ C4-PlantUML Team
Contributors
π₯ Alberto Monteiroπ₯ Nino Dioses
Colleagues
π€ AbraΓ£o HonΓ³rioπ€ Daniel Martinsπ€ Rafael Santosπ€ Marcus Vinicius Santana Silva
Guide to contributing to a GitHub project
This is a guide to contributing to this open source project that uses GitHub. Itβs mostly based on how many open sorce projects operate. Thatβs all there is to it. The fundamentals are:
- Fork the project & clone locally.
- Create an upstream remote and sync your local copy before you branch.
- Branch for each separate piece of work.
- Do the work, write good commit messages, and read the CONTRIBUTING file if there is one.
- Push to your origin repository.
- Create a new PR in GitHub.
- Respond to any code review feedback.
If you want to contribute to an open source project, the best one to pick is one that you are using yourself. The maintainers will appreciate it!