# Documentation This is a baseline for documentation best practises. # Basic pracises All descriptions should end with a `.`. #### Summary ```csharp /// <summary> /// Simple description. /// </summary> ``` #### Remarks ```csharp /// <remarks> /// More detailed description or additional information. /// </remarks> ``` A remark can be split into multiple paras: ```csharp /// <remarks> /// <para> /// Temporal information is stored in UTC format on the database, so any <see cref="DateTime" /> arguments in local time may lead to /// unexpected results. /// </para> /// <para> /// Temporal queries are always set as 'NoTracking'. /// </para> /// <para> /// See <see href="https://aka.ms/efcore-docs-temporal">Using SQL Server temporal tables with EF Core</see> /// for more information and examples. /// </para> /// </remarks> ``` #### Params A param with a self-explainable name can look like this. ```csharp /// <param name="selfExplainable">The selfExplainable param.</param> ``` If the purpose of a param can not immediatly be derived from its name, a more detailed description should be used. ```csharp /// <param name="utcFrom">Point in time representing the start of the period for which results should be returned.</param> ``` #### Returns Functions/methods that return a value should have a `<returns>` tag. A `<see />` tag should be used to describe the type returned. ```csharp /// <returns>The <see cref="Foo" /> for doing bar.</returns> ``` If a type of a generic type is returned a `<see/>` tag should be added for both. ```csharp /// <returns>The <see cref="Type{TFoo}"/> of <see cref="Foo"/> representing blahblabh.</returns> ``` If the return value is a boolean a description should be added given `true`: ```csharp /// <returns><see langword="true" /> if the key is clustered.</returns> ``` #### Responses For api-endpoints `<response />` tags should be added for every expected response code. ```csharp /// <response code="400">Bad request</response> ``` ## Entity/Models Example from [stripe dotnet](https://github.com/stripe/stripe-dotnet/blob/master/src/Stripe.net/Entities/Accounts/Account.cs). ```csharp /// <summary> /// This is an object representing a Stripe account. You can retrieve it to see properties /// on the account like its current e-mail address or if the account is enabled yet to make /// live charges. /// /// Some properties, marked below, are available only to platforms that want to <a /// href="https://stripe.com/docs/connect/accounts">create and manage Express or Custom /// accounts</a>. /// </summary> public class Account { /// <summary> /// Unique identifier for the object. /// </summary> public string Id { get; set; } /// <summary> /// String representing the object's type. Objects of the same type share the same value. /// </summary> public string Object { get; set; } /// <summary> /// Business information about the account. /// </summary> public AccountBusinessProfile BusinessProfile { get; set; } /// <summary> /// The business type. /// One of: <c>company</c>, <c>government_entity</c>, <c>individual</c>, or /// <c>non_profit</c>. /// </summary> public string BusinessType { get; set; } /// <summary> /// Whether the account can create live charges. /// </summary> public bool ChargesEnabled { get; set; } /// <summary> /// The account's country. /// </summary> public string Country { get; set; } ``` ## Interfaces Example: ```csharp /// <summary> /// Representing an event handler context that decides which event handler should be called given an event type. /// </summary> public interface IEventHandlerContext { /// <summary> /// Handles a stripe event. /// </summary> /// <remarks> /// A stripe event indicates that something has happened in the stripe account. /// For more information, see the <a href="https://stripe.com/docs/api/events"> documentation</a>. /// <remarks> /// <param name="stripeEvent">The stripe event.</param> /// <param name="connectionId">The connection Id, representing a <see cref="SettlementConnection"/>.</param> /// <param name="apiKey">The api key for authenticating requests to the stripe API.</param> /// <param name="token">A <see cref="CancellationToken"/> cancellation token.</param> /// <returns>A <see cref="Task{bool}"/> True if handler succeeds; false otherwise.</returns> public Task<bool> Handle(Event stripeEvent, Guid connectionId, string apiKey, CancellationToken token = default); } ``` ## Extensions Examples from https://github.com/dotnet/efcore/blob/main/src/EFCore.SqlServer/Extensions/SqlServerDbSetExtensions.cs ```csharp= /// <summary> /// Applies temporal 'ContainedIn' operation on the given DbSet, which only returns elements that were present in the database between /// two points in time. /// </summary> /// <remarks> /// <para> /// Elements that were created at the starting point as well as elements that were removed at the end point are included in the /// results. /// </para> /// <para> /// All versions of entities in that were present within the time range are returned, so it is possible to return multiple entities /// with the same key. /// </para> /// <para> /// Temporal information is stored in UTC format on the database, so any <see cref="DateTime" /> arguments in local time may lead to /// unexpected results. /// </para> /// <para> /// Temporal queries are always set as 'NoTracking'. /// </para> /// <para> /// See <see href="https://aka.ms/efcore-docs-temporal">Using SQL Server temporal tables with EF Core</see> /// for more information and examples. /// </para> /// </remarks> /// <param name="source">Source DbSet on which the temporal operation is applied.</param> /// <param name="utcFrom">Point in time representing the start of the period for which results should be returned.</param> /// <param name="utcTo">Point in time representing the end of the period for which results should be returned.</param> /// <returns>An <see cref="IQueryable{T}" /> representing the entities present in a given time range.</returns> public static IQueryable<TEntity> TemporalContainedIn<TEntity>( this DbSet<TEntity> source, DateTime utcFrom, DateTime utcTo) where TEntity : class { ... } ``` ## Endpoints ```csharp /// <summary> /// Get a list of todos /// </summary> /// <remarks> /// Retrieves list of todos, that blahblah. /// </remarks> /// <param name="page">The page number.</param> /// <param name="limit">The amount of items on each page.</param> /// <returns>A <see cref="Page{T}"/> paged result of <see cref="Todos"/> todos. </returns> /// <response code="200">Returns a paged result of todos</response> /// <response code="400">Bad request</response> /// <response code="401">Unauthorized</response> [HttpGet("todos")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Page<Todos>))] public async Task<IActionResult> GetPagedListOfTodos(int page = 1, int limit = 100) { ... } ``` Example with paramref: ```csharp /// <summary> /// Delete an approval /// </summary> /// <remarks> /// Deletes an approval, and reports for approval if <paramref name="deleteReport"/> is true. /// </remarks> /// <param name="approvalId">The approval id.</param> /// <param name="deleteReport">Deletes report for approval if true.</param> /// <response code="202">Accepted</response> /// <response code="400">Invalid approvalId supplied</response> /// <response code="404">Not Found</response> [HttpDelete("approvals/{approvalId:guid}")] [ProducesResponseType(StatusCodes.Status202Accepted, Type = typeof(IEnumerable<Guid>))] public async Task<IActionResult> DeleteApproval(Guid approvalId, bool deleteReport) ```