Before you start, ensure you have created a GitHub account.
There are two approaches to contributing.
For simple changes, the GitHub web UI should suffice.
Edit Online
button. This will automatically fork the project so you can edit the file.Preview
tab.Propose File Changes
.For more complex changes you should fork and then submit a pull request. This is useful if you are proposing multiple file changes
For more information, see Collaborating on GitHub especially using GitHub pull requests.
The repository contains a devcontainer that has all the necessary tools to develop content for the documentation. The content is automatically rendered on http://localhost:55666.
For more information about devcontainers visit the official documentation. Install the pre-requirements mentioned in the getting started guide and open the repository in Code (> code .
).
[!NOTE] The docstool is currently started in the foreground. While it is possible to run it in the background with
&
or the parallel execution feature of devcontainer it might be more cumbersome to inspect the log output of the tool. The downside of starting in the foreground is that Code will continuously show a spinner with "Configuring container".
To build all samples and snippets run .\tools\build-samples-and-snippets.ps1
from the repository root folder.
If, as part of editing a page, a full review of the content is done, the reviewed header should be updated. This date is used to render the last reviewed page.
As part of a full review the following should be done:
-
delimitedAll content files (.md
, .png
, .jpg
etc) and directories must be lower case.
All links pointing to them must be lower case.
Use a dash (-
) to delimit filenames (e.g. specify-endpoint-name.md
).
Each document has a header. It is enclosed by ---
and is defined in a YAML document format.
The GitHub UI will correctly render YAML.
For example:
---
title: Auditing Messages
summary: Provides built-in message auditing for every endpoint.
versions: '[4,)'
related:
- samples/custom-checks/monitoring3rdparty
redirects:
- nservicebus/overview
---
title: Auditing With NServiceBus
Must be 70 characters or less, and 50-60 characters is recommended.
Required. Used for the web page title tag <head><title>
, displayed in the page content, and displayed in search results.
Note: When considering what is a good title keep in mind that the parent context of a given page is fairly well known by other means. ie people can see where it exists in the menu and can see where in the hierarchy it is through the breadcrumbs. So it is often not necessary to include the parent title in the current pages title. For example when documenting "Publishers name configuration", for "Azure Service Bus Transport", then "Publishers name configuration" would be a sufficient title where "Publishers name configuration in Azure Service Bus Transport" is overly verbose and partially redundant.
component: Core
Required when using partials views, recommended also when using snippets in multiple versions. Allows the rendering engine determine what versions of the given page should be generated. Specified by providing the component key.
versions: '[1,2)'
In case of components that consist of multiple packages it's also possible to explicitly specify ranges of versions for each package separately:
versions: 'PackageA:[1,2); PackageB : [3,4); PackageC :*'
Optional. Used for specifying what versions the given page covers, especially relevant for features that are not available in all supported versions. The old format 'nuget_version_range' or 'package_name: nuget_version_range; package_name_2: nuget:version_range2'.
reviewed: 2016-03-01
Optional. Used to capture the last date that a page was fully reviewed. Format is yyyy-MM-dd
.
summary: Provides built-in message auditing for every endpoint.
Optional. Used for the meta description tag (<meta name="description" />
) and displaying the search results.
hidden: true
Causes two things:
<meta name="robots" content="noindex" />
.previewImage: preview-image.png
Populates a feature image for the Open Graph and Twitter Card meta tags for social sharing.
The URL should be a relative URL, usually just the filename in the same directory as the article, but ../
to go up a directory is also supported. If it works in a Markdown image tag ![](relative-url.png)
then it should work for the metadata.
related:
- samples/custom-checks/monitoring3rdparty
A list of related pages for this page. These links will be rendered at the bottom of the page. Can include both samples and articles and they will be grouped as such when rendered in html.
suppressRelated: true
No related content will be displayed at the bottom of the article, including specifically included articles in the metadata, as well as any documents discovered by traversing the directory structure. This is intended for pages where tight control over the presentation of related material is desired.
redirects:
- nservicebus/overview
When renaming an existing article to a new name, add the redirects:
section in the article header and specify the previous name for the article. If the old URL is linked anywhere, the new renamed article will automatically be served when the user clicks on it.
redirects
section must be lower case.tags
.Should be the URL relative to the root with no beginning or trailing slash padding and no .md.
To Mark something as an upgrade guide use isUpgradeGuide: true
The upgradeGuideCoreVersions
setting can optionally be used to filter which NSB core version tab the page show up in the search results
isUpgradeGuide: true
upgradeGuideCoreVersions:
- 5
- 6
To mark a page as belonging to the Particular Software Learning Path use isLearningPath: true
.
callsToAction: ['architecture-review', 'solution-architect']
Calls to action are defined in calls-to-action.yaml
.
In the following example, whenever the URLs /servicecontrol/sc-si
or /servicecontrol/debugging-servicecontrol
are being requested, the given article will be rendered.
---
title: ServiceInsight Interaction
summary: 'Using ServiceInsight Together'
redirects:
- servicecontrol/sc-si
- servicecontrol/debugging-servicecontrol
related:
- servicecontrol/installation
---
Two things are generally referred to as "components", which can be confusing:
MsmqTransport
.MsmqTransport_1
into the NuGet package NServiceBus.Transport.Msmq
. Multiple NuGet aliases can exist within a component, i.e. MSMQ will have versioned snippet directories Core_6
and MsmqTransport_1
, which are different NuGet Aliases, but both belong to the same component.When you are adding a new package, you therefore need to add new entries to both components.yaml and nugetAlias.txt, which can be a source of confusion.
"Components" is a general term used to describe a deployable set of functionality. Components exist in components/components.yaml. Note that over time a component may have moved between nugets or split into new nugets. For example, the ASB Data Bus or the Callbacks.
Sample Component:
- Key: Callbacks
Url: nservicebus/messaging/callbacks
NugetOrder:
- NServiceBus.Callbacks
- NServiceBus
When adding a new component
The component key allows for shorthand when referring to components in page headers.
The component URL is the definitive source of documentation for a given component. This will eventually be used to link back to said documentation from both NuGet usages, samples and articles.
Since components can be split over multiple different nugets, it is not possible to infer the order from the NuGet version alone. So we need to have a lookup index and the NugetOrder allows us to sensibly sort component versions. For example, NServiceBus.Callbacks.1.0.0 should sort higher than the version of Callbacks that exists in NServiceBus.5.0.0.
All NServiceBus-related NuGet packages (used in documentation) are listed in components/nugetAlias.txt. The alias part of the NuGet is the key that is used to infer the version and component for all snippets. For example, Snippets/Callbacks has, over its lifetime, existed in both the Core NuGet and the Callbacks NuGet. So the directories under Callbacks are indicative of the NuGet (alias) they exist in and then split over the multiple versions of a given NuGet.
Example aliases:
ASP: NServiceBus.Persistence.AzureStorage
Autofac: NServiceBus.Autofac
Azure: NServiceBus.Azure
Callbacks: NServiceBus.Callbacks
Samples can be targeted to multiple target frameworks. Samples can be edited and tested for multiple frameworks within this repository when using Visual Studio. When the site is rendered, separate downloads for each target framework are generated by splitting the framework list and transforming the project files before zipping.
When multi-targeting samples for NServiceBus 8 and earlier, The recommended set of frameworks is:
<TargetFrameworks>net7.0;net6.0;net48</TargetFrameworks>
For NServiceBus 9, samples can't currently be multi-targeted, so they should be singled targeted:
<TargetFramework>net8.0</TargetFramework>
Some things to keep in mind:
net8.0
) are translated to framework display names (i.e. .NET 8
) in /components/tfm-mappings.txt.
The menu is a YAML text document stored at menu/menu.yaml.
Any sub-items that are prefixed with the title of the parent item will have that prefix removed
Example content:
- Name: NServiceBus
Topics:
- Url: platform
Title: Getting Started
Articles:
- Url: platform
Title: Particular Service Platform Overview
- Title: NServiceBus Overview
Articles:
- Url: nservicebus/architecture/principles
Title: Architectural Principles
- Url: nservicebus/architecture
Title: Bus versus broker architecture
Conventions:
Name
is used for the URL.Title
is required for all nodes other than top level.The directory structure where a .md
exists is used to derive the URL for that document.
So a file existing at nservicebus\logging\nlog.md
will have a URL of https://docs.particular.net/nservicebus/logging/nlog
.
One exception to the URL rule is when a page is named index.md
. In this case the index.md
is omitted in the URL and only the directory structure is used.
So a file existing at nservicebus\logging\index.md
will have a URL of https://docs.particular.net/nservicebus/logging/
.
Like any page an index page can include related pages. However index pages will, by default, have all sibling and child pages included in the list of related pages. This is effectively a recursive walk of the file system for the directory the given index.md exists in.
Links to other documentation pages should be relative and contain the .md
extension.
The .md
allows links to work inside the GitHub web UI. The .md
will be trimmed when they are finally rendered.
Given the case of editing a page located at \nservicebus\page1.md
:
nservicebus\page2.md
, use [Page 2 Text](Page2.md)
.\servicecontrol\page3.md
, use [Page 3 Text](/servicecontrol/page3.md)
.Don't link to index.md
pages, instead link to the directory. So link to /nservicebus/logging
and NOT /nservicebus/logging/index.md
The site is rendered using GitHub Flavored Markdown
For editing markdown on the desktop (after cloning locally with Git) try MarkdownPad.
Ensure you enable GitHub Flavored Markdown (Offline)
by going to
Tools > Options > Markdown > Markdown Processor > GitHub Flavored Markdown (Offline)
Or click in the bottom left on the M
icon to "hot-switch"
Don't render YAML front-matter by going to
Tools > Options > Markdown > Markdown Settings
And checking Ignore YAML Front-matter
Enterprise Integration Patterns (EIP) is a bible of messaging. We sometimes use the same or similar patterns, but name them differently. When describing such a pattern, it's useful to reference the related EIP pattern, to make it easier to understand.
Our main goal is to provide the user with a smooth F5 experience when using the platform, and that includes samples, as it might be the user's first introduction to the platform.
Any of the following, or combination thereof, could indicate that something should be a sample
Do not write a sample when:
downloadbutton
directive in a paragraph by itself, which will be rendered as a large Download the sample now button.sample.md
-file with the platforms that are unsupported and the reasoning.ConfigureAwait(bool)
unless they are explicitly required.LangVersion
property to match the default version of the lowest .NET TFM used in the solution.Since users often use our samples to kick start their own projects, we want them to always use the latest versions of their dependencies. This is also important since we internally use our samples for smoke testing.
See the NuGet package reference guidelines for more details on how to achieve this.
When a sample is zipped the VS startup projects are also configured. This is done by using SetStartupProjects. By default startable projects are detected though interrogating the project settings. To override this convention and hard-code the list of startup projects add a file named {SolutionName}.StartupProjects.txt
in the same directory as the solution file. It should contain the relative paths to the project files you would like to use for startup projects.
For example if the solution "TheSolution.sln" contains two endpoints and you only want to start Endpoint1
the content of TheSolution.StartupProjects.txt
would be:
Endpoint1\Endpoint1.csproj
To apply this convention on your local clone of the docs repo use the set startup projects linkpad script.
At the moment the best way to get started on a sample is to copy an existing one. Ideally one that is similar to what you are trying to achieve.
A good sample to start with is the Default Logging Sample, since all it does is enable logging. You can then add the various moving pieces to the copy.
Avoid using screenshots in samples unless it adds significant value over what can be expressed in text. They have the following problems:
The most common misuse of screenshots is when capturing console output. DO NOT DO THIS. Put the text inside a formatted code section instead.
Some of our documentation provides guidance for customers and prospects to make informed decisions when faced with multiple options.
For example, when a customer decides to host an endpoint in Azure, there are multiple options, each with their pros and cons. Vendor documentation on its own is often not enough in the context of creating and running a distributed system with NServiceBus.
Guidance for these decisions is valuable to our customers and is included in our public documentation.
This is not to be confused with comparisons between various vendors or technologies from various vendors. Such comparisons are contentious and are not part of our public documentation.
Tutorials are similar to samples but optimized for new users to follow in a step-by-step fashion. Tutorials differ from samples in the following ways:
tutorial.md
downloadbutton
directive on its own line within the tutorial markdown./tutorials
directory to foster collaborative tone with userAn example directory structure for a tutorial might look like this:
{tutorial-name}/
Snippets/ (optional)
Snippets.sln
Core_6
Solution/
{SolutionName}.sln
tutorial.md
Tutorials can be grouped together in a parent directory with a normal article serving as a table of contents.
For tutorials chained together to form multiple lessons, navigation can be created to combine a button linking to the next lesson with the Download Solution link.
- !!tutorial
nextText: "Next Lesson: Sending a command"
nextUrl: tutorials/nservicebus-step-by-step/2-sending-a-command
The nextText
parameter is optional, and will default to the title of the linked page if omitted.
Partials are version-specific files that contain markdown. Partials are preferable for situations where quite a bit of content differs, or there there will be multiple variants for multiple different versions. For simpler situations, such as a 1-3 line note or aside only for one range of versions, see inline version conditionals below instead.
They are only rendered in the target page when the version filter matches the convention for a give file.
Partial Convention: filePrefix_key_nugetAlias_version.partial.md
Make sure to use component alias (as defined in components.yaml file) in the partial name. For most components component alias will be identical to NuGet alias, however it's not always the case, e.g. the Callbacks feature has been moved out of core package to the dedicated NServiceBus.Callbacks package, so the there are two NuGet aliases that are related to this feature, but it's still the same component and has a single component alias.
The NuGet alias in samples should match the prefix as defined by the samples solution directories.
Partials are rendered in the target page by using the following syntax
partial: PARTIAL_KEY
So an example directory structure might be as follows
And to include the endpointname
partial can be pulled into sample.md
by including.
partial: endpointname
Inline version conditionals allow a short section of markdown to only apply to a specific version range. This is perfect for situations like an alert for all versions less than version N, where using a partial file might be too heavy-handed and harder to comprehend.
It's important to remember that neither partials nor inline conditionals can create an item in the versions dropdown—only Snippets can do that.
#if-version [7.7, )
This content only displays for versions 7.7 and up
#end-if
#if-version [, 8)
This content only displays for versions less than 8.0
#end-if
#if-version SqlTransportLegacySystemClient [4, 6)
On pages where the snippets span more than one [NuGet package alias](https://github.com/Particular/docs.particular.net/blob/version-conditionals/components/nugetAlias.txt), version expressions must include the version expression.
#end-if
A full NuGet-style version expression is required. #if-version 6
is not allowed because ultimately it would not be clear if that meant version 6 and above [6, )
or only version 6 [6, 7)
.
Markdown includes are pulled into the document prior to passing the content through the markdown conversion.
Add a file anywhere in the docs repository that is suffixed with .include.md
. For example, the file might be named theKey.include.md
.
Add the following to the markdown:
include: theKey
There is a some code located here. Any directory containing an _excludesnippets
file will have its snippets ignored.
File extensions scanned for snippets include:
.config
.cs
.cscfg
.csdef
csproj
.html
.sql
.txt
.xml
.xsd
ps1
.ps
.json
.proto
.config
.yml
.yaml
Dockerfile
language | key |
---|---|
c# | cs |
xml | xml |
command line | dos |
powershell | ps |
json | json |
sql | sql |
Always use fenced code blocks with a language. If no language is defined then highlightjs will guess the language and it regularly gets it wrong.
NOTE: For
.razor
files, since the#region
keyword that is used to identify snippets can only be used inside of a razor code block, the language of the snippet will be changed fromrazor
tocs
, due to the current limitations of highlightjs for.razor
files.
Any code wrapped in a convention-based comment will be picked up. The comment needs to start with startcode
which is followed by the key.
// startcode ConfigureWith
var configure = Configure.With();
// endcode
For non-code snippets apply a similar approach as in code, using comments appropriate for a given file type. For plain-text files an extra empty line is required before endcode
tag.
Tag | XML-based | PowerShell | SQL script | Plain text | Dockerfile / Compose / YAML |
---|---|---|---|---|---|
Open | <!-- startcode name --> |
# startcode name |
-- startcode name |
startcode name |
# startcode name |
Content | |||||
Close | <!-- endcode --> |
# endcode |
-- endcode |
endcode |
# endcode |
Any code wrapped in a named C# region will be picked up. The name of the region is used as the key.
#region ConfigureWith
var configure = Configure.With();
#endregion
Snippets are versioned. These versions are used to render snippets in a tabbed manner.
Versions follow the NuGet versioning convention. If either Minor
or Patch
is not defined they will be rendered as an x
. For example, version 3.3
would be rendered as 3.3.x
and version 3
would be rendered as 3.x
.
Snippet versions are derived in two ways
Appending a version to the end of a snippet definition as follows:
#region ConfigureWith 4.5
var configure = Configure.With();
#endregion
Or version range:
#region MySnippetName [1.0,2.0]
// My Snippet Code
#endregion
If a snippet has no version defined then the version will be derived by walking up the directory tree until if finds a directory that is suffixed with _Version
or _VersionRange
. For example:
docs.particular.net\Snippets\Snippets_4\TheClass.cs
would have a default version of (≥ 4.0.0 && < 5.0.0)
.docs.particular.net\Snippets\Snippets_4\Special_4.3\TheClass.cs
would have a default version of (≥ 4.3.0 && < 5.0.0)
.docs.particular.net\Snippets\Special_(1.0,2.0)\TheClass.cs
would have a default version of (> 1.0.0 && < 2.0.0)
.If a file named prerelease.txt
exists in a versioned directory then a -pre
will be added to the version.
For example, if there is a directory docs.particular.net\Snippets\{Component}\Snippets_6\
and it contains a prerelease.txt
file then the version will be (≥ 6.0.0-pre)
The keyed snippets can then be used in any documentation .md
file by adding the text
snippet: KEY
Then snippets with the key (all versions) will be rendered in a tabbed manner. If there is only a single version then it will be rendered as a simple code block with no tabs.
For example:
To configure the bus call
snippet: ConfigureWith
The resulting markdown will be:
To configure the bus call
var configure = Configure.With();
```
#### Code indentation
The code snippets will do smart trimming of snippet indentation.
For example, given this snippet:
```c#
••#region DataBus
••var configure = Configure.With()
••••.FileShareDataBus(databusPath);
••#endregion
The two leading spaces (••) will be trimmed and the result will be
var configure = Configure.With()
••.FileShareDataBus(databusPath)
The same behavior will apply to leading tabs.
If tabs and spaces are mixed there is no way for the snippets to work out what to trim.
So given this snippet:
••#region DataBus
••var configure = Configure.With()
➙➙.FileShareDataBus(databusPath);
•#endregion
where ➙ is a tab, the resulting markdown will be
var configure = Configure.With()
➙➙.FileShareDataBus(databusPath)
Note that none of the tabs have been trimmed.
Use var
everywhere.
The code used by snippets and samples is compiled on the build server. The compilation is done against the versions of the packages referenced in the samples and snippets projects. When a snippet doesn't compile, the build will break so make sure snippets are compiling properly. Samples and snippets should not reference unreleased NuGet packages.
NuGet package references should use the the most greedy wildcard that is safe for that reference. In most cases that is "current minor":
<PackageReference Include="NServiceBus.Serilog" Version="4.*" />
This applies to snippets and samples.
In some cases, usually where a package has significant new API in a minor, it may be necessary to version snippets down to the "current patch".
<PackageReference Include="NServiceBus.Persistence.Sql" Version="2.0.*" />
<PackageReference Include="NServiceBus.Persistence.Sql" Version="2.1.*" />
Note that this should be a temporary state and in the next major default back to "current minor".
<PackageReference Include="NServiceBus.Persistence.Sql" Version="3.*" />
Also this generally only applies to snippets. It is usually not necessary to go to that level of version granularity for samples.
All samples pull in one extra level of package dependency. So, for example, in the Rabbit samples it would be sufficient to have:
<PackageReference Include="NServiceBus.RabbitMQ" Version="4.*" />
The reference to NServiceBus
and RabbitMQ.Client
would then be inferred. However, since the dependencies in NServiceBus.RabbitMQ
are:
NServiceBus (>= 6.0.0 && < 7.0.0)
RabbitMQ.Client (>= 5.0.1 && < 5.1.0)
NuGet will then resolve the lowest within those ranges. This make it more difficult to smoke test new versions of those dependencies using samples. As such, for all dependencies that are important to use the latest, the extra dependencies are explicitly included with wildcards.
<PackageReference Include="NServiceBus.RabbitMQ" Version="4.*" />
<ItemGroup Label="Required to force the latest version of transitive dependencies">
<PackageReference Include="NServiceBus" Version="6.*" />
<PackageReference Include="RabbitMQ.Client" Version="5.0.*" />
</ItemGroup>
There are some scenarios where documentation may require unreleased or beta NuGet packages. For example, when creating a PR against documentation for a feature that is not yet released. In this case, it is ok for a PR to reference an unreleased NuGet and have that PR fail to build on the build server. Once the NuGet packages have been released that PR can be merged.
In some cases it may be necessary to have merged documentation for unreleased features. In this case the NuGet packages should be pushed to the Particular feed on feedz.io. The feed is included by default in the repository's nuget.config.
When documenting an unstable feature, those unstable packages must be explicitly included using the exact prerelease package version using -
.
<PackageReference Include="NServiceBus.RabbitMQ" Version="4.3.1-alpha.XYZ" />
Wildcard patterns, like 4.3.1-*
, 8.0.0-any-pre-release-version.*
are not allowed for pre-releases since they tend to break the snippet and sample builds.
In snippets this can be safely done at any point in time. Note that when for applied to samples this can have side effects on a user who downloads a sample during that period. As such it is generally only done for samples that are marked with a prerelease.txt
marker.
This is a temporary state and once a stable is released it is changed back to the "current minor".
<PackageReference Include="NServiceBus.RabbitMQ" Version="4.*" />
Avoid using version ranges for package references. The integrity tests will enforce this.
A number of integrity tests validate that samples and snippets conform to conventions that make the documentation easier to maintain. Pull requests that fail these tests can not be merged.
The integrity tests include:
<TargetFrameworks>
(plural) element if they are multi-targeted.Version="*"
as this can cause a package restore operation to sometimes fail and yield old, incorrect, or mismatched versions.Core_7
) must contain a prerelease.txt
file only when the contained projects use a prerelease version of that component's NuGet package. This is verified in two ways:
prerelease.txt
files, parse the component name out of the parent directory name, find the related NuGet packages from component metadata, and then scan all child project files for prerelease package references of those NuGet packages, flagging prerelease.txt
files with no associated prerelease package reference.prerelease.txt
file.GitHub style alert boxes are supported and rendered as bootstrap alerts.
The first (and all top level) headers in a .md
page should be a h2
(i.e. ##
) with sub-headings under it being h3
, h4
, etc.
One addition to standard markdown is the auto creation of anchors for headings.
So if you have a heading like this:
## My Heading
it will be converted to this:
<h2>
<a name="my-heading"/>
My Heading
</h2>
Which means elsewhere in the page you can link to it with this:
[Goto My Heading](#My-Heading)
Images can be added using the following markdown syntax
![Alt text](/path/to/img.jpg "Optional title")
With the minimal syntax being
![](/path/to/img.jpg)
Image size can be controlled by adding the text width=x
to the end of the title
For example
![Alt text](/path/to/img.jpg "Optional title width=x")
With the minimal syntax being
![](/path/to/img.jpg "width=x")
This will result in the image being re-sized with the following parameters
width="x" height="auto"
It will also wrap the image in a clickable lightbox so the full image can be accessed.
Whenever possible, use Mermaid to create images, so that the source of the image is part of the document in which it appears.
If you create an image using another tool, always keep the source so that the image can be updated later.
The support for Mermaid is provided as an extension to Markdig. Markdig converts the diagram definition from .md to HTML, and then the Mermaid JavaScript library converts the definition to SVG format on the fly.
Diagram images are generated using the using a pseudocode syntax like this:
```mermaid
_mermaid_diagram_definition_
For example:
```markdown
```mermaid
graph TB
A[ExchangeA] --> B[ExchangeB]
A --> D[ExchangeD]
B --> C[ExchangeC]
B --> Q1[Queue1]
D --> Q2[Queue2]
The diagrams can be created and verified using the [online editor](http://knsv.github.io/mermaid/live_editor/).
##### Messaging Graph Style
Diagrams that represent messages and events being passed between endpoint should follow some basic style rules.
Endpoints should be represented as nodes with rounded corners. Messages should be represented as nodes. To show an endpoint sending a message to another endpoint use two edges. The first edge goes from the sender to the message being sent. The second edge goes from the message to the receiver. Like this:
```markdown
```mermaid
graph LR
a(EndpointA)
b(EndpointB)
a-->SomeCommand
SomeCommand-->b
Showing an endpoint publishing an event is similar but should use a dotted edge. Events can be delivered to multiple recipients. Use a separate edge for each one. Like this:
```markdown
```mermaid
graph LR
a(EndpointA)
b(EndpointB)
c(EndpointC)
a-.->AnEvent
AnEvent-->b
AnEvent-->c
There are two css classes (`event` and `message`) that should be applied to message nodes in these diagrams. To apply these, use the `class` keyword in mermaid:
```markdown
```mermaid
graph LR
Endpoint1-->SomeCommand
Command-->Endpoint2
Endpoint2-.->AnEvent
AnEvent-.->Endpoint3
Endpoint3 -.->AnotherEvent
AnotherEvent -.->Endpoint1
AnotherEvent -.->Endpoint4
class SomeCommand message;
class AnEvent,AnotherEvent event;
#### Miro
Another option is [Miro](https://miro.com/). Miro allows the creation of diagrams on a whiteboard. A board can be saved as a board backup file (.rtb) and can be used to create images. Within Miro, we create draw.io diagrams, as these can be exported as PNG images.
To create an image:
- Double-click the draw.io diagram to open the diagram in the draw.io editor
- From the "File" menu:
- Click "Export as"
- Click "PNG.."
- Set Zoom to 200% to cater for scaled-up high resolution screens.
- Do NOT select "Transparent Background", as this makes the visibility of elements in the image dependent on the user's theme (e.g. light or dark).
- Choose the file location and click "Export"
To allow images to be updated later, they must be committed to this repository along with the board backup file(s) use to create them.
### Some Useful Characters
* Ticks are done with `✔` ✔
* Crosses are done with `✖` ✖
### More Information
* [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)
## Writing style
### Language Preferences
For consistency, prefer American English.
No personal voice. I.e. no "we", "you", "your", "our" etc.
### Version language
Avoid ambiguity.
* Range: **version X and above** and **version Y and below** and **version X to version Y**.
* Singular: **version X** and NOT **VX**.
Don't capitalize "version" unnecessarily.
* **NServiceBus version 6** and NOT **NServiceBus Version 6**
* **NServiceBus version 5 and below** and NOT **NServiceBus Version 5 and below**
Don't assume the latest version of a product is the only one being used
* Instead of "Prior to NServiceBus version 6.5, sagas could not...", say "In NServiceBus 6.4.x and below, sagas can not..."
### Embedding videos
A YouTube video can be embedded in Markdown using the `youtube` command at the beginning of a line:
Here's an example that embeds the Rick Roll video:
```md
Paragraph before…
youtube: https://www.youtube.com/watch?v=eBGIQ7ZuuiU
Paragraph after…
The engine will parse the video ID out of the YouTube URL and create a properly styled embed.
The word Bus
should be avoided in documentation. Some replacements include:
federated
(for which the opposite term is centralized
)endpoint instance
or endpoint
(when it is clear from the context that you are talking about an instance rather than a logical concept)IBus
interface use message session
or message context
(depending if you are talking about just sending a messages from external component or from inside a handler)The word Bus
is allowed when a particular piece of documentation refers specifically to version 5 or below and discusses low level implementation details.
The word core
as a synonym for NServiceBus
or NServiceBus Core
should be avoided in the documentation. Prefer using NServiceBus
or NServiceBus package
.
Avoid deep link into the RavenDB documentation since it is a maintenance pain. For example don't link to https://ravendb.net/docs/article-page/3.0/Csharp/client-api//session/transaction-support/dtc-transactions#transaction-storage-recovery
. When RavenDB 4 was released, article-page/3.0/Csharp
became invalid and required an update. Also the RavenDB documentation does not maintain structure between versions. e.g. https://ravendb.net/docs/article-page/2.0/Csharp/client-api//session/transaction-support/dtc-transactions#transaction-storage-recovery
is a 404. So we can't trust that "just change the version" will work. Instead link to the RavenDB docs search: https://ravendb.net/docs/search/latest/csharp?searchTerm=THE-SEARCH-TERM
. So for the above example it would be https://ravendb.net/docs/search/latest/csharp?searchTerm=Transaction-storage-recovery
.
Under tools there are several utilities to help with the management of this repository. All are in the form of LINQPad scripts.
Remove redundant content from sln and csproj files.
Sets the correct startup projects for every solution. This is persisted in an .suo
file for each solution. Since .suo
files are not committed to source control, if a re-clone is done this script will need to be re-run.
In general the quality of the git history is not important in this repository. The reason for this is that the standard usages of a clean history (blame, supporting old versions, support branches etc) do not apply to a documentation repository. As such there are several recommendations based on that:
So if following the Git pretty flow chart you should usually end in the "It's safest to let it stay ugly" end point.