Code Monkey home page Code Monkey logo

c4sharp's Introduction

logo

C4Sharp (C4S) is a .net library for building diagrams as code, based on C4 Model. It 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: PNG, SVG, PUML, MERMAID

Note

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 modeling (e.g. STRIDE/LINDDUN), etc.
SIMON BROWN

Important

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

Getting Started

First, you will need the .NET 5.0+ and Java to run C4Sharp. Also, you should install the C4Sharp package in your project. This package is available through Nuget Packages.

Package Description Version Downloads Maintainability Status
C4SHARP dotnet library for building diagrams NuGet Nuget Codacy Badge .NET
C4SCLI cli for compiling C4S projects NuGet Nuget Codacy Badge .NET

Create a new diagram from scratch

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 DiagramBuilder (ContainerDiagram, ComponentDiagram, ContextDiagram, SequenceDiagram, DeploymentDiagram). See the following example of building a container diagram:

public class ContainerDiagramSample : ContainerDiagram
{
    protected override string Title => "Container diagram for Internet Banking System";

    protected override IEnumerable<Structure> Structures => new Structure[]
    {
        Person.None | Boundary.External 
                    | ("Customer", "Personal Banking Customer", "A customer of the bank, with personal bank accounts."),
        
        SoftwareSystem.None | ("BankingSystem", "Internet Banking System", 
            "Allows customers to view information about their bank accounts, and make payments."),
        
        SoftwareSystem.None | Boundary.External 
                            | ("MailSystem", "E-mail system", "The internal Microsoft Exchange e-mail system."),
        
        Bound("c1", "Internet Banking",
            Container.None | (WebApplication, "WebApp", "WebApp", "C#, WebApi", 
                "Delivers the static content and the Internet banking SPA"),
            
            Container.None | (Spa, "Spa", "Spa", "JavaScript, Angular", 
                "Delivers the static content and the Internet banking SPA"),
            
            Container.None | (Mobile, "MobileApp", "Mobile App", "C#, Xamarin", 
                "Provides a mobile banking experience"),
            
            Container.None | (Database, "SqlDatabase", "SqlDatabase", "SQL Database", 
                "Stores user registration information, hashed auth credentials, access logs, etc."),   
            
            Container.None | (Queue, "RabbitMQ", "RabbitMQ", "RabbitMQ", 
                "Stores user registration information, hashed auth credentials, access logs, etc."),
            
            Container.None | (Api, "BackendApi", "BackendApi", "Dotnet, Docker Container", 
                "Provides Internet banking functionality via API.")
        )
    };

    protected override IEnumerable<Relationship> Relationships => new[]
    {
        this["Customer"] > this["WebApp"] | ("Uses", "HTTPS"),
        this["Customer"] > this["Spa"] | ("Uses", "HTTPS"),
        this["Customer"] > this["MobileApp"] | "Uses",
        
        this["WebApp"] > this["Spa"] | "Delivers" | Position.Neighbor,
        this["Spa"] > this["BackendApi"] | ("Uses", "async, JSON/HTTPS"),
        this["MobileApp"] > this["BackendApi"] | ("Uses", "async, JSON/HTTPS"),
        this["SqlDatabase"] < this["BackendApi"] | ("Uses", "async, JSON/HTTPS") | Position.Neighbor,
        this["RabbitMQ"] < this["BackendApi"] | ("Uses", "async, JSON"),
        
        this["Customer"] < this["MailSystem"] | "Sends e-mails to",
        this["MailSystem"] < this["BackendApi"] | ("Sends e-mails using", "sync, SMTP"),
        this["BackendApi"] > this["BankingSystem"] | ("Uses", "sync/async, XML/HTTPS") | Position.Neighbor
    };
}

Create a new diagram from existing code

you can create structures that will be used in the diagram, as in the following example:

//Person
public static Person Customer => new ("customer", "Personal Banking Customer", 
    "A customer of the bank, with personal bank accounts.", Boundary.External);

public static Person InternalCustomer => new Person("internalcustomer", "Personal Banking Customer", 
    "An customer of the bank, with personal bank accounts.");

public static Person Manager => new ("manager", "Manager Banking Customer", 
    "A manager of the bank, with personal bank accounts.");

//SoftwareSystem
public static SoftwareSystem BankingSystem => new("BankingSystem", "Internet Banking System",
    "Allows customers to view information about their bank accounts, and make payments.");

public static SoftwareSystem Mainframe => new("Mainframe", "Mainframe Banking System",
    "Stores all of the core banking information about customers, accounts, transactions, etc.", Boundary.External);

public static SoftwareSystem MailSystem => new ("MailSystem", "E-mail system", 
    "The internal Microsoft Exchange e-mail system.", Boundary.External);
public class ContextDiagramSample : ContextDiagram
{
    protected override string Title => "Component diagram for Internet Banking System";
    
    protected override IEnumerable<Structure> Structures => new Structure[]
    {
        Customer,
        BankingSystem,
        Mainframe,
        MailSystem
    };

    protected override IEnumerable<Relationship> Relationships => new[]
    {
        Customer > BankingSystem,
        Customer < MailSystem | "Sends e-mails to",
        BankingSystem > MailSystem | ("Sends e-mails", "SMTP") | Neighbor,
        BankingSystem > Mainframe
    };
}

Compiling the diagram

There are two strategies for compiling diagrams in your project: self-compiling and using the C4SCLI tool. The following code shows how to compile the diagram:

Self-compiling approach:

using C4Sharp.Diagrams;
using C4Sharp.Diagrams.Plantuml;
using C4Sharp.Diagrams.Themes;
using ModelDiagrams.Diagrams;

var diagrams = new DiagramBuilder[]
{
    new ContextDiagramSample(),
    new ComponentDiagramSample(),
    new ContainerDiagramSample(),
    new EnterpriseDiagramSample(),
    new SequenceDiagramSample(),
    new DeploymentDiagramSample()
};

var path = Path.Combine("..", "..", "..", "..", "..", "docs", "images");
        
new PlantumlContext()
    .UseDiagramImageBuilder()
    .Export(path, diagrams, new DefaultTheme());

The result of the previous code is the following diagram: img

Using the C4SCLI tool:

Tip

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>]

Customizing the diagram

Using Themes

Themes are used to customize the diagram. The following code shows how to use the ParadisoTheme theme to compile the diagram:

new PlantumlContext()
    .UseDiagramImageBuilder()
    .Export(path, diagrams, new ParadisoTheme());

The result of the previous code is the following diagram: img

Creating a custom theme

You can create a custom theme by implementing the ITheme interface. The following code shows how to create a custom theme:

public class DefaultTheme: IDiagramTheme
{
    private const string ComponentBackground = "#85bbf0";
    private const string ComponentBorder = "#78a8d9";
    private const string ComponentText = "#000000";
    
    private const string ContainerBackground = "#438dd4";
    private const string ContainerBorder = "#3e82c5";
    private const string ContainerText = "#FFFFFF";
    
    private const string PersonBackground = "#0d437b";
    private const string PersonBorder = "#0d437b";
    private const string PersonText = "#FFFFFF";
    
    private const string ExternalBackground = "#999999";
    private const string ExternalBorder = "#8a8a8a";
    private const string ExternalText = "#FFFFFF";

    private const string SystemBackground = "#1a67be";
    private const string SystemBorder = "#175eaa";
    private const string SystemText = "#FFFFFF";

    public IElementStyle? Style => new ElementStyle()
        .UpdateElementStyle(ElementName.System, SystemBackground, SystemText, SystemBorder, false, Shape.RoundedBoxShape, BorderStyle.SolidLine, 2)
        .UpdateElementStyle(ElementName.ExternalSystem, ExternalBackground, ExternalText, ExternalBorder, false, Shape.RoundedBoxShape, BorderStyle.SolidLine, 1)
        .UpdateElementStyle(ElementName.Person, PersonBackground, PersonText, PersonBorder, false, Shape.RoundedBoxShape, BorderStyle.SolidLine, 2)
        .UpdateElementStyle(ElementName.Component, ComponentBackground, ComponentText, ComponentBorder, false, Shape.RoundedBoxShape, BorderStyle.SolidLine, 2)
        .UpdateElementStyle(ElementName.ExternalComponent, ExternalBackground, ExternalText, ExternalBorder, false, Shape.RoundedBoxShape, BorderStyle.SolidLine, 1)
        .UpdateElementStyle(ElementName.Container, ContainerBackground, ContainerText, ContainerBorder, false, Shape.RoundedBoxShape, BorderStyle.SolidLine, 2)
        .UpdateElementStyle(ElementName.ExternalContainer, ExternalBackground, ExternalText, ExternalBorder, false, Shape.RoundedBoxShape, BorderStyle.SolidLine, 1);

    public IBoundaryStyle? BoundaryStyle => new BoundaryStyle()
        .UpdateBoundaryStyle(ElementName.System, "#FFFFFF", "#000000", "#000000", false, Shape.RoundedBoxShape)
        .UpdateBoundaryStyle(ElementName.Container, "#FFFFFF", "#000000", "#000000", false, Shape.RoundedBoxShape)
        .UpdateBoundaryStyle(ElementName.Enterprise, "#FFFFFF", "#000000", "#000000", false, Shape.RoundedBoxShape);

    public IElementTag? Tags { get; } = null;
    public IRelationshipTag? RelTags { get; } = null;
}

Customizing the diagram through the SetStyle method

Using the C4S library, 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);
}    

img

Exporting the diagram to different formats

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")

Learn

Thanks

C4 community

Contributors

Colleagues

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!

c4sharp's People

Contributors

albertomonteiro avatar dbraaten42 avatar nino-dioses avatar wss-rbunning avatar yanjustino avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

c4sharp's Issues

C4SCLI not compatible with .NET 5.0 or .NET 6.0

When trying to install the C4SCLI nuget package on any net5.0 or net6.0 project, error NU1202 happens.

NU1202 Package c4scli 2.1.166 is not compatible with net5.0 (.NETCoreApp,Version=v5.0). Package c4scli 2.1.166 supports:

  • net5.0 (.NETCoreApp,Version=v5.0) / any
  • net6.0 (.NETCoreApp,Version=v6.0) / any

This clearly states that it supports any version of net5.0 or net6.0, but every project I've tried to install it on so far, this error appears.

Security improvement

We going to improve the jar file loading creating the PluntumlSession. With this, we'll fix two current problems:

  • Open more than one process of plantumljar
  • Create plantumljar as temporary file

Upgrade the C4-PlantUML code to 2.8.0

As I see in the code, the version of the C4-PlantUML code is "2.6.0beta1" whereas the official release is now up to the "2.8.0" version.
These are the release notes:

image

image

Would it be possible to update the code here to use the latest additions ?

Adjust size final image

Is it possible to control the width of the generated image?

Also, can I control the height and width of each box and the position of their arrows?

Thanks

What would you think about additional functionality from the standard C4 library?

One thing I really like on the base Plantuml-stdlib is the ability to add version tags to show systems changing (planned deprecation, future systems). I think we could leverage this right out of the box with some additional configuration options on c4sharp's API but I wasn't sure if you were trying to keep this library super simple or not.

image

Or

image

Doesn't download c4 files

Bug Reported

Doesn't download c4 files!

Alternative Fix

The fast alternative to fix this is download /bin folder from repository and folder and past in the same path that c4 folder in your project.

Add unit tests

This project needs unit tests. The code samples worked so far for my development, but that was more or a less a giant integration test.

You can assign this issue to me.

New improvements

Deployment Node

  • Create Method Overload DeploymentNode(string alias, Container container)

    • Uses Label and Description of Container
  • Create static method CreateNodes(string alias, Containers[] containers)

    • Creates a container with embendded containers nodes)
  • Fix External Person, External Container

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.