Documentation Portal for .NET Microservices
A concise, executive-friendly guide to a centralized API documentation portal using ReDoc for .NET microservices, with detailed engineer appendices.
· 6 min read
1. Summary #
A centralized API documentation portal brings all your microservices together in one place—easy to find, easy to read, and easy to trust. Using ReDoc over OpenAPI across your .NET estate gives you a branded, searchable hub that lowers onboarding time, cuts support friction, and standardizes how APIs are presented. The result: faster delivery, fewer questions, clearer ownership.
Key outcomes:
- Faster API discovery and adoption for internal teams and partners.
- Consistent, branded documentation at scale across services.
- Clear ownership and quality gates via CI checks on API specs.
2. Who this is for and when to use #
- Audiences: engineering, product, support, partner enablement, technical writers.
- Use when you have 3+ APIs across teams and want one source of truth for consumers.
- Fit checklist:
- Each service can emit OpenAPI (e.g., Swashbuckle in .NET).
- You have a repo or artifact feed for centralizing specs.
- You can host a static site (e.g., storage + CDN) and run a simple CI.
3. Capabilities and non-goals #
Capabilities:
- Unified portal for all APIs with navigation, search, and theming.
- Versioning and grouping by domain or product.
- Works well with large specs; fast, responsive UI.
Non-goals:
- Not an API gateway (no auth, routing, or throttling).
- Not an SLO/SLA layer.
- Not a replacement for design governance (complements, does not replace).
4. How it works (at a glance) #
- Services publish OpenAPI → specs are centralized (repo or pipeline artifacts) → ReDoc builds a static portal → users browse a single, branded site.
- Keep service autonomy; standardize how documentation is produced and consumed.
You can implement the portal either as:
- Option A: .NET-hosted portal (fits teams that want a web app host).
- Option B: Redocly CLI + static site (fastest to roll out; simple hosting). Recommended.
flowchart TB S1[User Service API] --> O1[OpenAPI Spec] S2[Order Service API] --> O2[OpenAPI Spec] S3[Payment Service API] --> O3[OpenAPI Spec] S4[Inventory Service API] --> O4[OpenAPI Spec] O1 --> R[Specs Repo or Artifact Feed] O2 --> R O3 --> R O4 --> R R --> B[ReDoc Build] B --> H[Static Site + CDN] H --> U1[Internal Users] H --> U2[Partners]
5. Requirements to adopt #
- Services: OpenAPI 3.x output, basic metadata (title, version, contact).
- Platform: Git repository or artifact feed for specs; storage + CDN or static hosting.
- CI: validate specs, publish to central location, build and deploy the portal.
6 FAQs #
Is this an API gateway?
- No. It’s documentation and discovery, not request routing or auth.
Can we secure internal APIs?
- Yes. Host internally or front with your SSO and access controls.
Do we need to change our APIs?
- No. Ensure valid OpenAPI and follow naming/convention guidance.
Why ReDoc?
- Strong UX, scales to large specs, easy theming, works well with static hosting.
What about non-.NET services?
- If they publish OpenAPI, they’re first-class citizens in the portal.
Appendix A — Service setup (.NET OpenAPI) #
Use Swashbuckle to emit complete OpenAPI with XML comments, security, and stable schema IDs.
1// Program.cs (excerpt) — .NET 8 minimal hosting
2builder.Services.AddControllers();
3builder.Services.AddEndpointsApiExplorer();
4
5builder.Services.AddSwaggerGen(options =>
6{
7 options.SwaggerDoc("v1", new OpenApiInfo
8 {
9 Title = builder.Configuration["ServiceInfo:Name"] ?? "API Service",
10 Version = builder.Configuration["ServiceInfo:Version"] ?? "v1",
11 Description = builder.Configuration["ServiceInfo:Description"] ?? "Microservice API",
12 Contact = new OpenApiContact { Name = "API Support Team", Email = "api-support@company.com" },
13 License = new OpenApiLicense { Name = "MIT License", Url = new Uri("https://opensource.org/licenses/MIT") }
14 });
15
16 // XML comments (if available)
17 var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
18 var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
19 if (File.Exists(xmlPath))
20 {
21 options.IncludeXmlComments(xmlPath);
22 }
23
24 // Security: JWT bearer (example)
25 options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
26 {
27 Description = "JWT Authorization header using the Bearer scheme",
28 Name = "Authorization",
29 In = ParameterLocation.Header,
30 Type = SecuritySchemeType.ApiKey,
31 Scheme = "Bearer"
32 });
33
34 options.AddSecurityRequirement(new OpenApiSecurityRequirement
35 {
36 {
37 new OpenApiSecurityScheme
38 {
39 Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
40 },
41 Array.Empty<string>()
42 }
43 });
44
45 // Stable schema IDs to avoid conflicts across merged specs
46 options.CustomSchemaIds(type => type.FullName?.Replace("+", "."));
47});
48
49// Expose OpenAPI JSON for external consumption
50app.UseSwagger(options => { options.RouteTemplate = "api-docs/{documentName}/openapi.json"; });
Controller annotations (excerpt):
1/// <summary>Retrieves a paginated list of users.</summary>
2[HttpGet]
3[ProducesResponseType(typeof(PagedResult<UserDto>), StatusCodes.Status200OK)]
4[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
5public async Task<ActionResult<PagedResult<UserDto>>> GetUsers(
6 [FromQuery, Range(1, int.MaxValue)] int pageNumber = 1,
7 [FromQuery, Range(1, 100)] int pageSize = 20,
8 [FromQuery] string? searchTerm = null)
9{
10 // ...
11}
Appendix B — Centralizing specs (CI options) #
Four-step flow:
- Generate OpenAPI in each microservice
- Standardize output location (e.g.,
api-docs/v1/openapi.json) - Collect into a centralized repo or artifact feed
- Consumers (portal) read from the central location
Options:
- Option A — Central Git repo: services publish via PRs/automation.
- Option B — Pipeline artifacts: services publish to a feed; portal pulls on build.
Guidance:
- Enforce naming:
domain.service/version/openapi.json. - Validate on PR: schema validity, required metadata, contact/owner.
Appendix C — Portal implementation options #
Recommended: Redocly CLI + static hosting.
Suggested repository layout:
1portal/
2 redocly.yaml
3 specs/
4 customer/
5 users/v1/openapi.json
6 billing/v1/openapi.json
7 order/
8 orders/v2/openapi.json
9 dist/ # build output
Example redocly.yaml (excerpt):
1apis:
2 users@v1:
3 root: ./specs/customer/users/v1/openapi.json
4 orders@v2:
5 root: ./specs/order/orders/v2/openapi.json
6
7theme:
8 openapi:
9 htmlTemplate: "./templates/index.html"
10 theme:
11 colors:
12 primary:
13 main: "#0f6fff"
14 typography:
15 fontSize: 16
16navigation:
17 links:
18 - label: "Guides"
19 url: "/guides"
20 - label: "Changelog"
21 url: "/changelog"
Local development:
1npx -y @redocly/cli preview-docs redocly.yaml
2npx -y @redocly/cli build-docs redocly.yaml -o dist
CI/CD (Azure DevOps example — build + deploy):
1trigger:
2 branches: { include: [ main ] }
3
4pool: { vmImage: 'ubuntu-latest' }
5
6steps:
7 - task: NodeTool@0
8 inputs: { versionSpec: '20.x' }
9
10 - script: |
11 npm init -y
12 npx -y @redocly/cli build-docs redocly.yaml -o dist
13 displayName: 'Build ReDoc portal'
14
15 - task: AzureCLI@2
16 inputs:
17 azureSubscription: 'YOUR-SERVICE-CONNECTION'
18 scriptType: 'bash'
19 scriptLocation: 'inlineScript'
20 inlineScript: |
21 az storage blob upload-batch --destination $web --account-name $(storageAccount) --source dist --overwrite
22 az cdn endpoint purge --profile-name $(cdnProfile) --name $(cdnEndpoint) --resource-group $(rg) --content-paths '/*'
Hosting options:
- Static website on object storage + CDN (Azure Storage + Azure CDN, AWS S3 + CloudFront, etc.).
- Internal portal behind SSO for private APIs.
Appendix D — Reference and conventions #
- Naming:
domain.service/version, e.g.,customer.users/v1. - Required OpenAPI metadata:
title,version,description,contact.name,contact.email. - Linting suggestions: Spectral rules for consistent tags, operationIds, and security schemes.
- Contribution guide:
- Service owners update specs per release.
- CI validates and publishes.
- Portal auto-builds on changes to
specs/.