Structurizr for .Net
Create detailed architecture models by writing Java or C# code with a web-based software architecture tool called Structurizr.
Join the DZone community and get the full member experience.
Join For Freethe initial version of structurizr was targeted at the java ecosystem (see " structurizr for java "), for no other reason than it's what i'm most familiar with. although this works for a good portion of the organizations that i visit when doing training/consulting, an equally sized portion use the microsoft stack. for this reason, i've put together structurizr for .net , which is more or less a direct port of the java version, with some automatically generated code from swagger used as a starting point. it's by no means "feature complete" yet, especially since none of the component finder code (the part that extracts components automatically from a codebase) is present, but there's enough to create some basic diagrams. here's some example code that creates a software model for the "financial risk system" case study that i use in my workshops.
using structurizr.client;
using structurizr.io.json;
using structurizr.model;
using structurizr.view;
using system.io;
using system.linq;
namespace structurizr.examples
{
/// <summary>
/// this is a simple example of how to create a software architecture model using structurizr. the model
/// represents a sample solution for the "financial risk system" architecture kata, included in
/// "the art of visualising software architecture" book (available free from leanpub).
///
/// the live version of the diagrams can be found at https://structurizr.com/public/9481
/// </summary>
class financialrisksystem
{
private const string alerttag = "alert";
static void main(string[] args)
{
workspace workspace = new workspace("financial risk system", "a simple example c4 model based upon the financial risk system architecture kata, created using structurizr for .net");
model.model model = workspace.model;
// create the basic model
softwaresystem financialrisksystem = model.addsoftwaresystem(location.internal, "financial risk system", "calculates the bank's exposure to risk for product x");
person businessuser = model.addperson(location.internal, "business user", "a regular business user");
businessuser.uses(financialrisksystem, "views reports using");
person configurationuser = model.addperson(location.internal, "configuration user", "a regular business user who can also configure the parameters used in the risk calculations");
configurationuser.uses(financialrisksystem, "configures parameters using");
softwaresystem tradedatasystem = model.addsoftwaresystem(location.internal, "trade data system", "the system of record for trades of type x");
financialrisksystem.uses(tradedatasystem, "gets trade data from");
softwaresystem referencedatasystem = model.addsoftwaresystem(location.internal, "reference data system", "manages reference data for all counterparties the bank interacts with");
financialrisksystem.uses(referencedatasystem, "gets counterparty data from");
softwaresystem emailsystem = model.addsoftwaresystem(location.internal, "e-mail system", "microsoft exchange");
financialrisksystem.uses(emailsystem, "sends a notification that a report is ready to");
emailsystem.delivers(businessuser, "sends a notification that a report is ready to", "e-mail message", interactionstyle.asynchronous);
softwaresystem centralmonitoringservice = model.addsoftwaresystem(location.internal, "central monitoring service", "the bank-wide monitoring and alerting dashboard");
financialrisksystem.uses(centralmonitoringservice, "sends critical failure alerts to", "snmp", interactionstyle.asynchronous).addtags(alerttag);
softwaresystem activedirectory = model.addsoftwaresystem(location.internal, "active directory", "manages users and security roles across the bank");
financialrisksystem.uses(activedirectory, "uses for authentication and authorisation");
container webapplication = financialrisksystem.addcontainer("web application", "allows users to view reports and modify risk calculation parameters", "asp.net mvc");
businessuser.uses(webapplication, "views reports using");
configurationuser.uses(webapplication, "modifies risk calculation parameters using");
webapplication.uses(activedirectory, "uses for authentication and authorisation");
container batchprocess = financialrisksystem.addcontainer("batch process", "calculates the risk", "windows service");
batchprocess.uses(emailsystem, "sends a notification that a report is ready to");
batchprocess.uses(tradedatasystem, "gets trade data from");
batchprocess.uses(referencedatasystem, "gets counterparty data from");
batchprocess.uses(centralmonitoringservice, "sends critical failure alerts to", "snmp", interactionstyle.asynchronous).addtags(alerttag);
container filesystem = financialrisksystem.addcontainer("file system", "stores risk reports", "network file share");
webapplication.uses(filesystem, "consumes risk reports from");
batchprocess.uses(filesystem, "publishes risk reports to");
component scheduler = batchprocess.addcomponent("scheduler", "starts the risk calculation process at 5pm new york time", "quartz.net");
component orchestrator = batchprocess.addcomponent("orchestrator", "orchestrates the risk calculation process", "c#");
component tradedataimporter = batchprocess.addcomponent("trade data importer", "imports data from the trade data system", "c#");
component referencedataimporter = batchprocess.addcomponent("reference data importer", "imports data from the reference data system", "c#");
component riskcalculator = batchprocess.addcomponent("risk calculator", "calculates risk", "c#");
component reportgenerator = batchprocess.addcomponent("report generator", "generates a microsoft excel compatible risk report", "c# and microsoft.office.interop.excel");
component reportpublisher = batchprocess.addcomponent("report distributor", "publishes the report to the web application", "c#");
component emailcomponent = batchprocess.addcomponent("e-mail component", "sends e-mails", "c#");
component reportchecker = batchprocess.addcomponent("report checker", "checks that the report has been generated by 9am singapore time", "c#");
component alertcomponent = batchprocess.addcomponent("alert component", "sends snmp alerts", "c# and #snmp library");
scheduler.uses(orchestrator, "starts");
scheduler.uses(reportchecker, "starts");
orchestrator.uses(tradedataimporter, "imports data using");
tradedataimporter.uses(tradedatasystem, "imports data from");
orchestrator.uses(referencedataimporter, "imports data using");
referencedataimporter.uses(referencedatasystem, "imports data from");
orchestrator.uses(riskcalculator, "calculates the risk using");
orchestrator.uses(reportgenerator, "generates the risk report using");
orchestrator.uses(reportpublisher, "publishes the risk report using");
reportpublisher.uses(filesystem, "publishes the risk report to");
orchestrator.uses(emailcomponent, "sends e-mail using");
emailcomponent.uses(emailsystem, "sends a notification that a report is ready to");
reportchecker.uses(alertcomponent, "sends alerts using");
alertcomponent.uses(centralmonitoringservice, "sends alerts using", "snmp", interactionstyle.asynchronous).addtags(alerttag);
// create some views
viewset viewset = workspace.views;
systemcontextview contextview = viewset.createcontextview(financialrisksystem);
contextview.papersize = papersize.a4_landscape;
contextview.addallsoftwaresystems();
contextview.addallpeople();
containerview containerview = viewset.createcontainerview(financialrisksystem);
contextview.papersize = papersize.a4_landscape;
containerview.addallelements();
componentview componentviewforbatchprocess = viewset.createcomponentview(batchprocess);
contextview.papersize = papersize.a3_landscape;
componentviewforbatchprocess.addallelements();
componentviewforbatchprocess.remove(configurationuser);
componentviewforbatchprocess.remove(webapplication);
componentviewforbatchprocess.remove(activedirectory);
// tag and style some elements
styles styles = viewset.configuration.styles;
financialrisksystem.addtags("risk system");
styles.add(new elementstyle(tags.element) { color = "#ffffff", fontsize = 34 });
styles.add(new elementstyle("risk system") { background = "#8a458a" });
styles.add(new elementstyle(tags.softwaresystem) { width = 650, height = 400, background = "#510d51", shape = shape.box });
styles.add(new elementstyle(tags.person) { width = 550, background = "#62256e", shape = shape.person });
styles.add(new elementstyle(tags.container) { width = 650, height = 400, background = "#a46ba4", shape = shape.box });
styles.add(new elementstyle(tags.component) { width = 550, background = "#c9a1c9", shape = shape.box });
styles.add(new relationshipstyle(tags.relationship) { thickness = 4, dashed = false, fontsize = 32, width = 400 });
styles.add(new relationshipstyle(tags.synchronous) { dashed = false });
styles.add(new relationshipstyle(tags.asynchronous) { dashed = true });
styles.add(new relationshipstyle(alerttag) { color = "#ff0000" });
businessuser.relationships.tolist().foreach(r => r.addtags("https"));
// and upload the model to structurizr.com
structurizrclient structurizrclient = new structurizrclient("key", "secret");
structurizrclient.mergeworkspace(9481, workspace);
}
}
}
it creates the following context, container, and component diagrams, which you can see in structurizr .
if you want to take a look or try it out, the source code can be found on github and there's an initial version of the package on nuget . have fun!
Published at DZone with permission of Simon Brown, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments