├── demo.gif
├── azure-vote
├── azure-vote
│ ├── wwwroot
│ │ ├── favicon.ico
│ │ └── css
│ │ │ └── site.css
│ ├── Pages
│ │ ├── _Host.cshtml
│ │ ├── _Layout.cshtml
│ │ ├── Error.cshtml.cs
│ │ ├── Error.cshtml
│ │ └── Index.razor
│ ├── VoteAppSettings.cs
│ ├── Data
│ │ ├── Vote.cs
│ │ └── VoteService.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── _Imports.razor
│ ├── App.razor
│ ├── appsettings.json
│ ├── AzureVote.csproj
│ ├── .vscode
│ │ ├── tasks.json
│ │ └── launch.json
│ ├── Program.cs
│ └── .gitignore
├── .dockerignore
└── Dockerfile
├── charts
└── azure-voting-app
│ ├── Chart.yaml
│ ├── .helmignore
│ ├── templates
│ ├── azure-vote-app-back-svc.yaml
│ ├── azure-vote-app-front-svc.yaml
│ ├── azure-vote-app-back.yaml
│ ├── _helpers.tpl
│ └── azure-vote-app-front.yaml
│ └── values.yaml
├── docker-compose.yml
├── README.md
├── kubernetes-manifests
└── all-in-one.yaml
└── .github
└── workflows
└── docker-publish.yaml
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rahulrai-in/azure-voting-app-dotnet/HEAD/demo.gif
--------------------------------------------------------------------------------
/azure-vote/azure-vote/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rahulrai-in/azure-voting-app-dotnet/HEAD/azure-vote/azure-vote/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/charts/azure-voting-app/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | description: A Helm chart for Azure Voting App
3 | name: azure-voting-app
4 | version: 0.1.0
5 | appVersion: 1.0.0
6 |
--------------------------------------------------------------------------------
/azure-vote/azure-vote/Pages/_Host.cshtml:
--------------------------------------------------------------------------------
1 | @page "/"
2 | @namespace AzureVote.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 | @{
5 | Layout = "_Layout";
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/azure-vote/azure-vote/VoteAppSettings.cs:
--------------------------------------------------------------------------------
1 | namespace AzureVote;
2 |
3 | public class VoteAppSettings
4 | {
5 | public string Title { get; set; } = "Azure Vote App";
6 | public string Vote1Label { get; set; } = "Candidate1";
7 | public string Vote2Label { get; set; } = "Candidate2";
8 | }
--------------------------------------------------------------------------------
/azure-vote/azure-vote/Data/Vote.cs:
--------------------------------------------------------------------------------
1 | namespace AzureVote.Data;
2 |
3 | public class Vote
4 | {
5 | public Vote(string label, long count)
6 | {
7 | Label = label;
8 | Count = count;
9 | }
10 |
11 | public string Label { get; set; }
12 | public long Count { get; set; }
13 | }
--------------------------------------------------------------------------------
/azure-vote/azure-vote/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "AzureVote": {
4 | "commandName": "Project",
5 | "dotnetRunMessages": true,
6 | "launchBrowser": true,
7 | "applicationUrl": "https://localhost:7172;http://localhost:5180",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | }
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/azure-vote/azure-vote/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using System.Net.Http
2 | @using Microsoft.AspNetCore.Authorization
3 | @using Microsoft.AspNetCore.Components.Authorization
4 | @using Microsoft.AspNetCore.Components.Forms
5 | @using Microsoft.AspNetCore.Components.Routing
6 | @using Microsoft.AspNetCore.Components.Web
7 | @using Microsoft.AspNetCore.Components.Web.Virtualization
8 | @using Microsoft.JSInterop
9 | @using AzureVote
--------------------------------------------------------------------------------
/azure-vote/azure-vote/App.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Not found
8 | Sorry, there's nothing at this address.
9 |
10 |
--------------------------------------------------------------------------------
/azure-vote/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.classpath
2 | **/.dockerignore
3 | **/.env
4 | **/.git
5 | **/.gitignore
6 | **/.project
7 | **/.settings
8 | **/.toolstarget
9 | **/.vs
10 | **/.vscode
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/bin
15 | **/charts
16 | **/docker-compose*
17 | **/compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | README.md
25 |
--------------------------------------------------------------------------------
/charts/azure-voting-app/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *~
18 | # Various IDEs
19 | .project
20 | .idea/
21 | *.tmproj
22 |
--------------------------------------------------------------------------------
/charts/azure-voting-app/templates/azure-vote-app-back-svc.yaml:
--------------------------------------------------------------------------------
1 | {{- $serviceName := include "name" . -}}
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: {{ $serviceName }}-{{ .Values.azureVoteBack.service.name }}
6 | labels:
7 | {{ include "labels.standard" . | indent 4 }}
8 | spec:
9 | type: {{ .Values.azureVoteBack.service.type }}
10 | ports:
11 | - port: 6379
12 | selector:
13 | app: {{ include "name" . }}
14 | component: {{ $serviceName }}-{{ .Values.azureVoteBack.deployment.name }}
15 | release: {{ .Release.Name }}
--------------------------------------------------------------------------------
/charts/azure-voting-app/templates/azure-vote-app-front-svc.yaml:
--------------------------------------------------------------------------------
1 | {{- $serviceName := include "name" . -}}
2 | apiVersion: v1
3 | kind: Service
4 | metadata:
5 | name: {{ $serviceName }}-{{ .Values.azureVoteFront.service.name }}
6 | labels:
7 | {{ include "labels.standard" . | indent 4 }}
8 | spec:
9 | type: {{ .Values.azureVoteFront.service.type }}
10 | ports:
11 | - port: {{ .Values.azureVoteFront.service.externalPort }}
12 | selector:
13 | app: {{ include "name" . }}
14 | component: {{ $serviceName }}-{{ .Values.azureVoteFront.service.name }}
15 | release: {{ .Release.Name }}
--------------------------------------------------------------------------------
/azure-vote/azure-vote/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*",
9 | "EnableOTLPExporter": false,
10 | "VoteAppSettings": {
11 | "Vote1Label": "Cats",
12 | "Vote2Label": "Dogs",
13 | "Title": "Azure Vote App"
14 | },
15 | "ConnectionStrings": {
16 | "RedisHost": "localhost:6379",
17 | "OTLPMetricsExporterEndpoint": "http://localhost:4318/v1/metrics",
18 | "OTLPTracesExporterEndpoint": "http://localhost:4318/v1/traces"
19 | }
20 | }
--------------------------------------------------------------------------------
/azure-vote/azure-vote/Pages/_Layout.cshtml:
--------------------------------------------------------------------------------
1 | @using Microsoft.AspNetCore.Components.Web
2 | @namespace AzureVote.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | @RenderBody()
16 |
17 |
18 |
--------------------------------------------------------------------------------
/azure-vote/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/dotnet/aspnet:6.0-focal AS base
2 | WORKDIR /app
3 | EXPOSE 80
4 | EXPOSE 443
5 |
6 | ENV ASPNETCORE_URLS=http://+:80
7 |
8 | FROM mcr.microsoft.com/dotnet/sdk:6.0-focal AS build
9 | WORKDIR /src
10 | COPY ["azure-vote/AzureVote.csproj", "./"]
11 | RUN dotnet restore "AzureVote.csproj"
12 | COPY azure-vote/. .
13 | WORKDIR "/src/."
14 | RUN dotnet build "AzureVote.csproj" -c Release -o /app/build
15 |
16 | FROM build AS publish
17 | RUN dotnet publish "AzureVote.csproj" -c Release -o /app/publish /p:UseAppHost=false
18 |
19 | FROM base AS final
20 | WORKDIR /app
21 | COPY --from=publish /app/publish .
22 | ENTRYPOINT ["dotnet", "AzureVote.dll"]
23 |
--------------------------------------------------------------------------------
/azure-vote/azure-vote/Pages/Error.cshtml.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using Microsoft.AspNetCore.Mvc.RazorPages;
3 |
4 | namespace AzureVote.Pages;
5 |
6 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
7 | [IgnoreAntiforgeryToken]
8 | public class ErrorModel : PageModel
9 | {
10 | private readonly ILogger _logger;
11 |
12 | public ErrorModel(ILogger logger)
13 | {
14 | _logger = logger;
15 | }
16 |
17 | public string? RequestId { get; set; }
18 |
19 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
20 |
21 | public void OnGet()
22 | {
23 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
24 | }
25 | }
--------------------------------------------------------------------------------
/charts/azure-voting-app/values.yaml:
--------------------------------------------------------------------------------
1 | # Default values for azure-voting-app.
2 | # This is a YAML-formatted file.
3 | # Declare variables to be passed into your templates.
4 |
5 | azureVoteFront:
6 | service:
7 | name: front
8 | type: LoadBalancer
9 | externalPort: 80
10 |
11 | deployment:
12 | replicas: 1
13 | name: front
14 | image: ghcr.io/rahulrai-in/azure-voting-app-dotnet
15 | imageTag: latest
16 | imagePullPolicy: Always
17 | internalPort: 80
18 | resources:
19 | limits:
20 | cpu: 500m
21 | memory: 128Mi
22 | requests:
23 | cpu: 250m
24 | memory: 128Mi
25 |
26 | azureVoteBack:
27 | service:
28 | name: back
29 | type: ClusterIP
30 |
31 | deployment:
32 | name: back
33 | imageTag: latest
34 | imagePullPolicy: IfNotPresent
35 | resources:
36 | limits:
37 | cpu: 500m
38 | memory: 500Mi
39 | requests:
40 | cpu: 500m
41 | memory: 500Mi
42 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.9"
2 | services:
3 | azure-vote-back:
4 | image: redis:latest
5 | container_name: azure-vote-back
6 | environment:
7 | ALLOW_EMPTY_PASSWORD: "yes"
8 | ports:
9 | - 6379:6379
10 |
11 | azure-vote-front:
12 | image: azure-vote-front
13 | container_name: azure-vote-front
14 | depends_on:
15 | - azure-vote-back
16 | build:
17 | context: azure-vote
18 | dockerfile: ./Dockerfile
19 | environment:
20 | ConnectionStrings__RedisHost: azure-vote-back
21 | # Set the following parameter to true if you want to send traces and metrics to the local OTEL collector
22 | EnableOTLPExporter: false
23 | ConnectionStrings__OTLPMetricsExporterEndpoint: http://azure-vote-collector:4318/v1/metrics
24 | ConnectionStrings__OTLPTracesExporterEndpoint: http://azure-vote-collector:4318/v1/traces
25 | ports:
26 | - 80:80
27 |
28 | azure-vote-collector:
29 | image: otel/opentelemetry-collector:latest
30 | container_name: azure-vote-collector
31 | ports:
32 | - 4318:4318
33 | profiles:
34 | - local-collector
35 |
--------------------------------------------------------------------------------
/azure-vote/azure-vote/AzureVote.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/charts/azure-voting-app/templates/azure-vote-app-back.yaml:
--------------------------------------------------------------------------------
1 | {{- $serviceName := include "name" . -}}
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: {{ $serviceName }}-{{ .Values.azureVoteBack.deployment.name }}
6 | labels:
7 | {{ include "labels.standard" . | indent 4 }}
8 | component: {{ $serviceName }}-{{ .Values.azureVoteBack.deployment.name }}
9 | spec:
10 | replicas: 1
11 | selector:
12 | matchLabels:
13 | component: {{ $serviceName }}-{{ .Values.azureVoteBack.deployment.name }}
14 | template:
15 | metadata:
16 | labels:
17 | {{ include "labels.standard" . | indent 8 }}
18 | component: {{ $serviceName }}-{{ .Values.azureVoteBack.deployment.name }}
19 | spec:
20 | nodeSelector:
21 | beta.kubernetes.io/os: linux
22 | containers:
23 | - name: {{ $serviceName }}-{{ .Values.azureVoteBack.deployment.name }}
24 | image: "redis:{{ .Values.azureVoteBack.deployment.imageTag }}"
25 | imagePullPolicy: {{ .Values.azureVoteBack.deployment.imagePullPolicy }}
26 | ports:
27 | - containerPort: 6379
28 | name: redis
29 | env:
30 | - name: ALLOW_EMPTY_PASSWORD
31 | value: "yes"
32 | resources:
33 | {{ toYaml .Values.azureVoteBack.deployment.resources | indent 10 }}
34 |
--------------------------------------------------------------------------------
/azure-vote/azure-vote/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/AzureVote.csproj",
11 | "/property:GenerateFullPaths=true",
12 | "/consoleloggerparameters:NoSummary"
13 | ],
14 | "problemMatcher": "$msCompile"
15 | },
16 | {
17 | "label": "publish",
18 | "command": "dotnet",
19 | "type": "process",
20 | "args": [
21 | "publish",
22 | "${workspaceFolder}/AzureVote.csproj",
23 | "/property:GenerateFullPaths=true",
24 | "/consoleloggerparameters:NoSummary"
25 | ],
26 | "problemMatcher": "$msCompile"
27 | },
28 | {
29 | "label": "watch",
30 | "command": "dotnet",
31 | "type": "process",
32 | "args": [
33 | "watch",
34 | "run",
35 | "--project",
36 | "${workspaceFolder}/AzureVote.csproj"
37 | ],
38 | "problemMatcher": "$msCompile"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/azure-vote/azure-vote/Pages/Error.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model AzureVote.Pages.ErrorModel
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Error
11 |
12 |
13 |
14 |
15 |
16 |
Error.
17 |
An error occurred while processing your request.
18 |
19 | @if (Model.ShowRequestId)
20 | {
21 |
22 | Request ID: @Model.RequestId
23 |
24 | }
25 |
26 |
Development Mode
27 |
28 | Swapping to the Development environment displays detailed information about the error that occurred.
29 |
30 |
31 | The Development environment shouldn't be enabled for deployed applications.
32 | It can result in displaying sensitive information from exceptions to end users.
33 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
34 | and restarting the app.
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/charts/azure-voting-app/templates/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/* vim: set filetype=mustache: */}}
2 | {{/*
3 | Expand the name of the chart.
4 | */}}
5 | {{- define "name" -}}
6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
7 | {{- end -}}
8 |
9 | {{/*
10 | Create a default fully qualified app name.
11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
12 | */}}
13 | {{- define "fullname" -}}
14 | {{- $name := default .Chart.Name .Values.nameOverride -}}
15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
16 | {{- end -}}
17 |
18 | {{- /*
19 | Credit: @technosophos
20 | https://github.com/technosophos/common-chart/
21 | labels.standard prints the standard Helm labels.
22 | The standard labels are frequently used in metadata.
23 | */ -}}
24 | {{- define "labels.standard" -}}
25 | app: {{ template "name" . }}
26 | heritage: {{ .Release.Service | quote }}
27 | release: {{ .Release.Name | quote }}
28 | chart: {{ template "chartref" . }}
29 | {{- end -}}
30 |
31 | {{- /*
32 | Credit: @technosophos
33 | https://github.com/technosophos/common-chart/
34 | chartref prints a chart name and version.
35 | It does minimal escaping for use in Kubernetes labels.
36 | Example output:
37 | zookeeper-1.2.3
38 | wordpress-3.2.1_20170219
39 | */ -}}
40 | {{- define "chartref" -}}
41 | {{- replace "+" "_" .Chart.Version | printf "%s-%s" .Chart.Name -}}
42 | {{- end -}}
--------------------------------------------------------------------------------
/azure-vote/azure-vote/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | // Use IntelliSense to find out which attributes exist for C# debugging
6 | // Use hover for the description of the existing attributes
7 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
8 | "name": ".NET Core Launch (web)",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | // If you have changed target frameworks, make sure to update the program path.
13 | "program": "${workspaceFolder}/bin/Debug/net6.0/AzureVote.dll",
14 | "args": [],
15 | "cwd": "${workspaceFolder}",
16 | "stopAtEntry": false,
17 | // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
18 | "serverReadyAction": {
19 | "action": "openExternally",
20 | "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
21 | },
22 | "env": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | },
25 | "sourceFileMap": {
26 | "/Views": "${workspaceFolder}/Views"
27 | }
28 | },
29 | {
30 | "name": ".NET Core Attach",
31 | "type": "coreclr",
32 | "request": "attach"
33 | }
34 | ]
35 | }
--------------------------------------------------------------------------------
/charts/azure-voting-app/templates/azure-vote-app-front.yaml:
--------------------------------------------------------------------------------
1 | {{- $serviceName := include "name" . -}}
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: {{ $serviceName }}-{{ .Values.azureVoteFront.deployment.name }}
6 | labels:
7 | {{ include "labels.standard" . | indent 4 }}
8 | component: {{ $serviceName }}-{{ .Values.azureVoteFront.deployment.name }}
9 | spec:
10 | replicas: {{ .Values.azureVoteFront.deployment.replicas }}
11 | selector:
12 | matchLabels:
13 | component: {{ $serviceName }}-{{ .Values.azureVoteFront.deployment.name }}
14 | strategy:
15 | rollingUpdate:
16 | maxSurge: 1
17 | maxUnavailable: 1
18 | minReadySeconds: 5
19 | template:
20 | metadata:
21 | labels:
22 | {{ include "labels.standard" . | indent 8 }}
23 | component: {{ $serviceName }}-{{ .Values.azureVoteFront.deployment.name }}
24 | spec:
25 | nodeSelector:
26 | beta.kubernetes.io/os: linux
27 | containers:
28 | - name: {{ $serviceName }}-{{ .Values.azureVoteFront.deployment.name }}
29 | image: "{{ .Values.azureVoteFront.deployment.image }}:{{ .Values.azureVoteFront.deployment.imageTag }}"
30 | imagePullPolicy: {{ .Values.azureVoteFront.deployment.imagePullPolicy }}
31 | ports:
32 | - containerPort: {{ .Values.azureVoteFront.deployment.internalPort }}
33 | env:
34 | - name: ConnectionStrings__RedisHost
35 | value: {{ $serviceName }}-{{ .Values.azureVoteBack.service.name }}
36 | resources:
37 | {{ toYaml .Values.azureVoteFront.deployment.resources | indent 10 }}
--------------------------------------------------------------------------------
/azure-vote/azure-vote/Pages/Index.razor:
--------------------------------------------------------------------------------
1 | @page "/"
2 |
3 | @inject VoteService VoteService
4 |
5 | @_title
6 |
7 | @if (_votes == default)
8 | {
9 |
10 | Loading...
11 |
12 | }
13 | else
14 | {
15 |
16 |
17 |
@_title
18 |
19 |
27 |
28 |
29 | }
30 |
31 | @code {
32 | (Vote Vote1, Vote Vote2) _votes;
33 | string _title = "Title";
34 |
35 | protected override async Task OnInitializedAsync()
36 | {
37 | _votes = await VoteService.GetVotesAsync();
38 | _title = VoteService.GetTitle();
39 | }
40 |
41 | private async Task IncrementVoteAsync(int candidateId)
42 | {
43 | _votes = await VoteService.IncrementVoteAsync(candidateId);
44 | }
45 |
46 | private async Task ResetVotesAsync()
47 | {
48 | _votes = await VoteService.ResetVotesAsync();
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Azure Voting App (.NET)
2 |
3 | This sample is the .NET implementation of the [official Azure Voting App](https://github.com/Azure-Samples/azure-voting-app-redis). This sample creates a multi-container application in a Kubernetes cluster like the original one.
4 |
5 | The application interface is built using ASP.NET Core Blazor Server. The data component uses Redis.
6 |
7 | This sample also includes the following features:
8 |
9 | 1. Instrumented to produce OpenTelemetry traces and export the traces to the console.
10 | 2. Request to GET `/traced-exception` endpoint will throw an exception. It shows how unhandled exceptions are logged in the active OpenTelemtry span.
11 | 3. Instrumented to emit built-in .NET metrics and custom metrics with the [OpenTelemetry Metrics SDK](https://github.com/open-telemetry/opentelemetry-dotnet).
12 | 4. Deployment with Helm, Kubernetes manifest, or Docker compose.
13 |
14 | ## Note
15 |
16 | 1. The previous version of this application used [prometheus-net](https://github.com/prometheus-net/prometheus-net) to expose metrics to Prometheus on the `/metrics` endpoint. The main branch uses OTEL Metrics SDK to send metrics to the destination. You can use the commit tagged [prometheus-metrics](https://github.com/rahulrai-in/azure-voting-app-dotnet/tree/prometheus-metrics) to refer to the previous version of the application.
17 | 2. The application sends traces and metrics to the console exporter by default. You can set the environment variable `EnableOtlpExporter` to `true` to send traces and metrics to the local OTEL collector. Update the values of the connection strings `OTLPMetricsExporterEndpoint` and `OTLPTracesExporterEndpoint` if you want to send the metrics and traces to a remote OTLP endpoint. You can launch the application and the local OTEL collector with the following command:
18 |
19 | ```bash
20 | docker-compose --profile local-collector up
21 | ```
22 |
23 | ## Demo
24 |
25 | 
26 |
--------------------------------------------------------------------------------
/azure-vote/azure-vote/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | body { background-color: #F8F8F8; }
2 |
3 | div#container { margin-top: 5%; }
4 |
5 | div#space {
6 | display: block;
7 | height: 10px;
8 | margin: 0 auto;
9 | width: 500px;
10 | }
11 |
12 | div#logo {
13 | display: block;
14 | font-family: Helvetica;
15 | font-size: 30px;
16 | margin: 0 auto;
17 | text-align: center;
18 | width: 500px;
19 | /*border-bottom: 1px solid black;*/
20 | }
21 |
22 | div#form {
23 | border-bottom: 1px solid black;
24 | border-top: 1px solid black;
25 | display: block;
26 | font-family: Helvetica;
27 | font-size: 30px;
28 | margin: 0 auto;
29 | padding: 20px;
30 | padding-right: 20px;
31 | padding-top: 20px;
32 | text-align: center;
33 | width: 500px;
34 | }
35 |
36 | div#results {
37 | display: block;
38 | font-family: Helvetica;
39 | font-size: 30px;
40 | margin: 0 auto;
41 | text-align: center;
42 | width: 500px;
43 | }
44 |
45 | .button {
46 | -webkit-transition-duration: 0.4s;
47 | background-color: #4CAF50;
48 | /* Green */
49 | border: none;
50 | color: white;
51 | cursor: pointer;
52 | display: inline-block;
53 | font-size: 16px;
54 | margin: 4px 2px;
55 | padding: 16px 32px;
56 | text-align: center;
57 | text-decoration: none;
58 | /* Safari */
59 | transition-duration: 0.4s;
60 | width: 250px;
61 | }
62 |
63 | .button1 {
64 | background-color: white;
65 | border: 2px solid #008CBA;
66 | color: black;
67 | }
68 |
69 | .button1:hover {
70 | background-color: #008CBA;
71 | color: white;
72 | }
73 |
74 | .button2 {
75 | background-color: white;
76 | border: 2px solid #555555;
77 | color: black;
78 | }
79 |
80 | .button2:hover {
81 | background-color: #555555;
82 | color: white;
83 | }
84 |
85 | .button3 {
86 | background-color: white;
87 | border: 2px solid #f44336;
88 | color: black;
89 | }
90 |
91 | .button3:hover {
92 | background-color: #f44336;
93 | color: white;
94 | }
--------------------------------------------------------------------------------
/kubernetes-manifests/all-in-one.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: azure-vote-back
5 | spec:
6 | replicas: 1
7 | selector:
8 | matchLabels:
9 | app: azure-vote-back
10 | template:
11 | metadata:
12 | labels:
13 | app: azure-vote-back
14 | spec:
15 | nodeSelector:
16 | beta.kubernetes.io/os: linux
17 | containers:
18 | - name: azure-vote-back
19 | image: redis:latest
20 | env:
21 | - name: ALLOW_EMPTY_PASSWORD
22 | value: "yes"
23 | ports:
24 | - containerPort: 6379
25 | name: redis
26 | resources:
27 | requests:
28 | cpu: 250m
29 | limits:
30 | cpu: 500m
31 | memory: 500M
32 | ---
33 | apiVersion: v1
34 | kind: Service
35 | metadata:
36 | name: azure-vote-back
37 | spec:
38 | ports:
39 | - port: 6379
40 | selector:
41 | app: azure-vote-back
42 | ---
43 | apiVersion: apps/v1
44 | kind: Deployment
45 | metadata:
46 | name: azure-vote-front
47 | spec:
48 | replicas: 1
49 | selector:
50 | matchLabels:
51 | app: azure-vote-front
52 | strategy:
53 | rollingUpdate:
54 | maxSurge: 1
55 | maxUnavailable: 1
56 | minReadySeconds: 5
57 | template:
58 | metadata:
59 | labels:
60 | app: azure-vote-front
61 | spec:
62 | nodeSelector:
63 | beta.kubernetes.io/os: linux
64 | containers:
65 | - name: azure-vote-front
66 | image: ghcr.io/rahulrai-in/azure-voting-app-dotnet:latest
67 | ports:
68 | - containerPort: 80
69 | resources:
70 | requests:
71 | cpu: 250m
72 | limits:
73 | cpu: 500m
74 | memory: 500M
75 | env:
76 | - name: ConnectionStrings__RedisHost
77 | value: "azure-vote-back"
78 | ---
79 | apiVersion: v1
80 | kind: Service
81 | metadata:
82 | name: azure-vote-front
83 | spec:
84 | type: LoadBalancer
85 | ports:
86 | - port: 80
87 | selector:
88 | app: azure-vote-front
89 |
--------------------------------------------------------------------------------
/.github/workflows/docker-publish.yaml:
--------------------------------------------------------------------------------
1 | name: GH CR Publish
2 |
3 | on: [push]
4 |
5 | env:
6 | # Use docker.io for Docker Hub if empty
7 | REGISTRY: ghcr.io
8 | # github.repository as /
9 | IMAGE_NAME: ${{ github.repository }}
10 |
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 | permissions:
15 | contents: read
16 | packages: write
17 | # This is used to complete the identity challenge
18 | # with sigstore/fulcio when running outside of PRs.
19 | id-token: write
20 |
21 | steps:
22 | - name: Checkout repository
23 | uses: actions/checkout@v2
24 |
25 | # Workaround: https://github.com/docker/build-push-action/issues/461
26 | - name: Setup Docker buildx
27 | uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
28 |
29 | # Login against a Docker registry except on PR
30 | # https://github.com/docker/login-action
31 | - name: Log into registry ${{ env.REGISTRY }}
32 | if: github.event_name != 'pull_request'
33 | uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
34 | with:
35 | registry: ${{ env.REGISTRY }}
36 | username: ${{ github.actor }}
37 | password: ${{ secrets.CR_PAT }}
38 |
39 | # Extract metadata (tags, labels) for Docker
40 | # https://github.com/docker/metadata-action
41 | - name: Extract Docker metadata
42 | id: meta
43 | uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
44 | with:
45 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
46 | tags: |
47 | type=raw,value=latest
48 |
49 | # Build and push Docker image with Buildx (don't push on PR)
50 | # https://github.com/docker/build-push-action
51 | - name: Build and push Docker image
52 | id: build-and-push
53 | uses: docker/build-push-action@v2.9.0
54 | with:
55 | context: ./azure-vote
56 | push: ${{ github.event_name != 'pull_request' }}
57 | tags: ${{ steps.meta.outputs.tags }}
58 | labels: ${{ steps.meta.outputs.labels }}
59 |
--------------------------------------------------------------------------------
/azure-vote/azure-vote/Data/VoteService.cs:
--------------------------------------------------------------------------------
1 | namespace AzureVote.Data;
2 |
3 | public class VoteService
4 | {
5 | private const string Vote1Key = "VOTE1";
6 | private const string Vote2Key = "VOTE2";
7 | private readonly ActivitySource _activitySource;
8 | private readonly IConnectionMultiplexer _multiplexer;
9 | private readonly Counter _resetCounter;
10 | private readonly VoteAppSettings _settings;
11 | private readonly Counter _votesCounter;
12 |
13 | public VoteService(IConnectionMultiplexer multiplexer, IOptions settings,
14 | ActivitySource activitySource, Meter meter)
15 | {
16 | _multiplexer = multiplexer;
17 | _activitySource = activitySource;
18 | _settings = settings.Value;
19 | _votesCounter = meter.CreateCounter("vote_count", description: "Counts number of votes cast");
20 | _resetCounter = meter.CreateCounter("reset_count", description: "Counts number of resets");
21 | }
22 |
23 | public async Task<(Vote vote1, Vote vote2)> GetVotesAsync()
24 | {
25 | using var activity = _activitySource.StartActivity(nameof(GetVotesAsync), ActivityKind.Server);
26 | var redis = _multiplexer.GetDatabase();
27 | return await GetVotes(redis);
28 | }
29 |
30 | public async Task<(Vote vote1, Vote vote2)> IncrementVoteAsync(int? candidate)
31 | {
32 | using var activity = _activitySource.StartActivity(nameof(IncrementVoteAsync), ActivityKind.Server);
33 | activity?.AddEvent(new("Vote added"));
34 | activity?.SetTag(nameof(candidate), candidate);
35 | var redis = _multiplexer.GetDatabase();
36 | switch (candidate)
37 | {
38 | case 1:
39 | await redis.StringIncrementAsync(Vote1Key);
40 | _votesCounter.Add(1, tag: new("candidate", Vote1Key));
41 | break;
42 | case 2:
43 | await redis.StringIncrementAsync(Vote2Key);
44 | _votesCounter.Add(1, tag: new("candidate", Vote2Key));
45 | break;
46 | }
47 |
48 | return await GetVotes(redis);
49 | }
50 |
51 | public async Task<(Vote vote1, Vote vote2)> ResetVotesAsync()
52 | {
53 | using var activity = _activitySource.StartActivity(nameof(ResetVotesAsync), ActivityKind.Server);
54 | activity?.AddEvent(new("Reset event"));
55 | var redis = _multiplexer.GetDatabase();
56 | await redis.StringSetAsync(Vote1Key, 0);
57 | await redis.StringSetAsync(Vote2Key, 0);
58 | _resetCounter.Add(1);
59 | return await GetVotes(redis);
60 | }
61 |
62 | public string GetTitle()
63 | {
64 | return _settings.Title;
65 | }
66 |
67 | private async Task<(Vote vote1, Vote vote2)> GetVotes(IDatabaseAsync redis)
68 | {
69 | var vote1Count = await redis.StringGetAsync(Vote1Key);
70 | var vote2Count = await redis.StringGetAsync(Vote2Key);
71 | return (new(_settings.Vote1Label, vote1Count.TryParse(out long val1) ? val1 : 0),
72 | new(_settings.Vote2Label, vote2Count.TryParse(out long val2) ? val2 : 0));
73 | }
74 | }
--------------------------------------------------------------------------------
/azure-vote/azure-vote/Program.cs:
--------------------------------------------------------------------------------
1 | var builder = WebApplication.CreateBuilder(args);
2 |
3 | // Add services to the container.
4 | builder.Services.AddRazorPages();
5 | builder.Services.AddServerSideBlazor();
6 | builder.Services.AddSingleton();
7 |
8 | // Add Redis service
9 | var redisConnection = ConnectionMultiplexer.Connect(builder.Configuration.GetConnectionString("RedisHost"));
10 | builder.Services.AddSingleton(redisConnection);
11 |
12 | // Application settings
13 | builder.Services.Configure(builder.Configuration.GetSection(nameof(VoteAppSettings)));
14 |
15 | // Configure OpenTelemetry tracing
16 | builder.Services.AddOpenTelemetryTracing(tracerProviderBuilder =>
17 | {
18 | tracerProviderBuilder
19 | // Customize the traces gathered by the HTTP request handler
20 | .AddAspNetCoreInstrumentation(options =>
21 | {
22 | options.RecordException = true;
23 | // Add metadata for the request such as the HTTP method and response length
24 | options.Enrich = (activity, eventName, rawObject) =>
25 | {
26 | switch (eventName)
27 | {
28 | case "OnStartActivity":
29 | {
30 | if (rawObject is not HttpRequest httpRequest)
31 | {
32 | return;
33 | }
34 |
35 | activity.SetTag("requestProtocol", httpRequest.Protocol);
36 | activity.SetTag("requestMethod", httpRequest.Method);
37 | break;
38 | }
39 | case "OnStopActivity":
40 | {
41 | if (rawObject is HttpResponse httpResponse)
42 | {
43 | activity.SetTag("responseLength", httpResponse.ContentLength);
44 | }
45 |
46 | break;
47 | }
48 | }
49 | };
50 | })
51 | // Instrument Redis client
52 | .AddRedisInstrumentation(redisConnection, opt =>
53 | {
54 | opt.FlushInterval = TimeSpan.FromSeconds(1);
55 | opt.SetVerboseDatabaseStatements = true;
56 | })
57 | .AddSource("my-corp.azure-vote.vote-app")
58 | // Create resources (key-value pairs) that describe your service such as service name and version
59 | .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("vote-app")
60 | .AddAttributes(new[] { new KeyValuePair("service.version", "1.0.0.0") }))
61 | // Ensures that all activities are recorded and sent to exporter
62 | .SetSampler(new AlwaysOnSampler())
63 | // Displays traces on the console. Useful for debugging.
64 | .AddConsoleExporter();
65 | if (builder.Configuration.GetValue("EnableOtlpExporter"))
66 | {
67 | // Exports spans to an OTLP endpoint. Use this for exporting traces to collector or a backend that support OTLP over HTTP
68 | tracerProviderBuilder.AddOtlpExporter(otlpOptions =>
69 | {
70 | otlpOptions.Endpoint = new(builder.Configuration.GetConnectionString("OTLPTracesExporterEndpoint"));
71 | otlpOptions.Protocol = OtlpExportProtocol.HttpProtobuf;
72 | });
73 | }
74 | }
75 | );
76 |
77 | builder.Services.AddSingleton(new ActivitySource("my-corp.azure-vote.vote-app"));
78 |
79 | // Configure OpenTelemetry metrics
80 | builder.Services.AddOpenTelemetryMetrics(meterProviderBuilder =>
81 | {
82 | meterProviderBuilder.AddAspNetCoreInstrumentation()
83 | .AddMeter("my-corp.azure-vote.vote-app")
84 | // Create resources (key-value pairs) that describe your service such as service name and version
85 | .SetResourceBuilder(
86 | ResourceBuilder.CreateDefault().AddService("vote-app")
87 | .AddAttributes(new[] { new KeyValuePair("service.version", "1.0.0.0") }))
88 | // Displays metrics on the console. Useful for debugging.
89 | .AddConsoleExporter();
90 | if (builder.Configuration.GetValue("EnableOtlpExporter"))
91 | {
92 | // Exports metrics to an OTLP endpoint. Use this for exporting metrics to collector or a backend that support OTLP over HTTP
93 | meterProviderBuilder.AddOtlpExporter(otlpOptions =>
94 | {
95 | otlpOptions.Endpoint = new(builder.Configuration.GetConnectionString("OTLPMetricsExporterEndpoint"));
96 | otlpOptions.Protocol = OtlpExportProtocol.HttpProtobuf;
97 | });
98 | }
99 | }
100 | );
101 |
102 | builder.Services.AddSingleton(new Meter("my-corp.azure-vote.vote-app"));
103 |
104 | var app = builder.Build();
105 |
106 | // Configure the HTTP request pipeline.
107 | if (!app.Environment.IsDevelopment())
108 | {
109 | app.UseExceptionHandler("/Error");
110 | app.UseHsts();
111 | }
112 |
113 | app.UseHttpsRedirection();
114 |
115 | app.UseStaticFiles();
116 |
117 | app.UseRouting();
118 |
119 | app.MapBlazorHub();
120 |
121 | app.MapFallbackToPage("/_Host");
122 |
123 | app.MapGet("/traced-exception/", (ActivitySource activitySource) =>
124 | {
125 | using var activity = activitySource.StartActivity("Error endpoint", ActivityKind.Server);
126 | throw new ApplicationException("Error processing the request");
127 | })
128 | .WithName("TracedException")
129 | .Produces()
130 | .Produces(StatusCodes.Status500InternalServerError);
131 |
132 | app.Run();
--------------------------------------------------------------------------------
/azure-vote/azure-vote/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # Tye
66 | .tye/
67 |
68 | # ASP.NET Scaffolding
69 | ScaffoldingReadMe.txt
70 |
71 | # StyleCop
72 | StyleCopReport.xml
73 |
74 | # Files built by Visual Studio
75 | *_i.c
76 | *_p.c
77 | *_h.h
78 | *.ilk
79 | *.meta
80 | *.obj
81 | *.iobj
82 | *.pch
83 | *.pdb
84 | *.ipdb
85 | *.pgc
86 | *.pgd
87 | *.rsp
88 | *.sbr
89 | *.tlb
90 | *.tli
91 | *.tlh
92 | *.tmp
93 | *.tmp_proj
94 | *_wpftmp.csproj
95 | *.log
96 | *.vspscc
97 | *.vssscc
98 | .builds
99 | *.pidb
100 | *.svclog
101 | *.scc
102 |
103 | # Chutzpah Test files
104 | _Chutzpah*
105 |
106 | # Visual C++ cache files
107 | ipch/
108 | *.aps
109 | *.ncb
110 | *.opendb
111 | *.opensdf
112 | *.sdf
113 | *.cachefile
114 | *.VC.db
115 | *.VC.VC.opendb
116 |
117 | # Visual Studio profiler
118 | *.psess
119 | *.vsp
120 | *.vspx
121 | *.sap
122 |
123 | # Visual Studio Trace Files
124 | *.e2e
125 |
126 | # TFS 2012 Local Workspace
127 | $tf/
128 |
129 | # Guidance Automation Toolkit
130 | *.gpState
131 |
132 | # ReSharper is a .NET coding add-in
133 | _ReSharper*/
134 | *.[Rr]e[Ss]harper
135 | *.DotSettings.user
136 |
137 | # TeamCity is a build add-in
138 | _TeamCity*
139 |
140 | # DotCover is a Code Coverage Tool
141 | *.dotCover
142 |
143 | # AxoCover is a Code Coverage Tool
144 | .axoCover/*
145 | !.axoCover/settings.json
146 |
147 | # Coverlet is a free, cross platform Code Coverage Tool
148 | coverage*.json
149 | coverage*.xml
150 | coverage*.info
151 |
152 | # Visual Studio code coverage results
153 | *.coverage
154 | *.coveragexml
155 |
156 | # NCrunch
157 | _NCrunch_*
158 | .*crunch*.local.xml
159 | nCrunchTemp_*
160 |
161 | # MightyMoose
162 | *.mm.*
163 | AutoTest.Net/
164 |
165 | # Web workbench (sass)
166 | .sass-cache/
167 |
168 | # Installshield output folder
169 | [Ee]xpress/
170 |
171 | # DocProject is a documentation generator add-in
172 | DocProject/buildhelp/
173 | DocProject/Help/*.HxT
174 | DocProject/Help/*.HxC
175 | DocProject/Help/*.hhc
176 | DocProject/Help/*.hhk
177 | DocProject/Help/*.hhp
178 | DocProject/Help/Html2
179 | DocProject/Help/html
180 |
181 | # Click-Once directory
182 | publish/
183 |
184 | # Publish Web Output
185 | *.[Pp]ublish.xml
186 | *.azurePubxml
187 | # Note: Comment the next line if you want to checkin your web deploy settings,
188 | # but database connection strings (with potential passwords) will be unencrypted
189 | *.pubxml
190 | *.publishproj
191 |
192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
193 | # checkin your Azure Web App publish settings, but sensitive information contained
194 | # in these scripts will be unencrypted
195 | PublishScripts/
196 |
197 | # NuGet Packages
198 | *.nupkg
199 | # NuGet Symbol Packages
200 | *.snupkg
201 | # The packages folder can be ignored because of Package Restore
202 | **/[Pp]ackages/*
203 | # except build/, which is used as an MSBuild target.
204 | !**/[Pp]ackages/build/
205 | # Uncomment if necessary however generally it will be regenerated when needed
206 | #!**/[Pp]ackages/repositories.config
207 | # NuGet v3's project.json files produces more ignorable files
208 | *.nuget.props
209 | *.nuget.targets
210 |
211 | # Microsoft Azure Build Output
212 | csx/
213 | *.build.csdef
214 |
215 | # Microsoft Azure Emulator
216 | ecf/
217 | rcf/
218 |
219 | # Windows Store app package directories and files
220 | AppPackages/
221 | BundleArtifacts/
222 | Package.StoreAssociation.xml
223 | _pkginfo.txt
224 | *.appx
225 | *.appxbundle
226 | *.appxupload
227 |
228 | # Visual Studio cache files
229 | # files ending in .cache can be ignored
230 | *.[Cc]ache
231 | # but keep track of directories ending in .cache
232 | !?*.[Cc]ache/
233 |
234 | # Others
235 | ClientBin/
236 | ~$*
237 | *~
238 | *.dbmdl
239 | *.dbproj.schemaview
240 | *.jfm
241 | *.pfx
242 | *.publishsettings
243 | orleans.codegen.cs
244 |
245 | # Including strong name files can present a security risk
246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
247 | #*.snk
248 |
249 | # Since there are multiple workflows, uncomment next line to ignore bower_components
250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
251 | #bower_components/
252 |
253 | # RIA/Silverlight projects
254 | Generated_Code/
255 |
256 | # Backup & report files from converting an old project file
257 | # to a newer Visual Studio version. Backup files are not needed,
258 | # because we have git ;-)
259 | _UpgradeReport_Files/
260 | Backup*/
261 | UpgradeLog*.XML
262 | UpgradeLog*.htm
263 | ServiceFabricBackup/
264 | *.rptproj.bak
265 |
266 | # SQL Server files
267 | *.mdf
268 | *.ldf
269 | *.ndf
270 |
271 | # Business Intelligence projects
272 | *.rdl.data
273 | *.bim.layout
274 | *.bim_*.settings
275 | *.rptproj.rsuser
276 | *- [Bb]ackup.rdl
277 | *- [Bb]ackup ([0-9]).rdl
278 | *- [Bb]ackup ([0-9][0-9]).rdl
279 |
280 | # Microsoft Fakes
281 | FakesAssemblies/
282 |
283 | # GhostDoc plugin setting file
284 | *.GhostDoc.xml
285 |
286 | # Node.js Tools for Visual Studio
287 | .ntvs_analysis.dat
288 | node_modules/
289 |
290 | # Visual Studio 6 build log
291 | *.plg
292 |
293 | # Visual Studio 6 workspace options file
294 | *.opt
295 |
296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
297 | *.vbw
298 |
299 | # Visual Studio LightSwitch build output
300 | **/*.HTMLClient/GeneratedArtifacts
301 | **/*.DesktopClient/GeneratedArtifacts
302 | **/*.DesktopClient/ModelManifest.xml
303 | **/*.Server/GeneratedArtifacts
304 | **/*.Server/ModelManifest.xml
305 | _Pvt_Extensions
306 |
307 | # Paket dependency manager
308 | .paket/paket.exe
309 | paket-files/
310 |
311 | # FAKE - F# Make
312 | .fake/
313 |
314 | # CodeRush personal settings
315 | .cr/personal
316 |
317 | # Python Tools for Visual Studio (PTVS)
318 | __pycache__/
319 | *.pyc
320 |
321 | # Cake - Uncomment if you are using it
322 | # tools/**
323 | # !tools/packages.config
324 |
325 | # Tabs Studio
326 | *.tss
327 |
328 | # Telerik's JustMock configuration file
329 | *.jmconfig
330 |
331 | # BizTalk build output
332 | *.btp.cs
333 | *.btm.cs
334 | *.odx.cs
335 | *.xsd.cs
336 |
337 | # OpenCover UI analysis results
338 | OpenCover/
339 |
340 | # Azure Stream Analytics local run output
341 | ASALocalRun/
342 |
343 | # MSBuild Binary and Structured Log
344 | *.binlog
345 |
346 | # NVidia Nsight GPU debugger configuration file
347 | *.nvuser
348 |
349 | # MFractors (Xamarin productivity tool) working folder
350 | .mfractor/
351 |
352 | # Local History for Visual Studio
353 | .localhistory/
354 |
355 | # BeatPulse healthcheck temp database
356 | healthchecksdb
357 |
358 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
359 | MigrationBackup/
360 |
361 | # Ionide (cross platform F# VS Code tools) working folder
362 | .ionide/
363 |
364 | # Fody - auto-generated XML schema
365 | FodyWeavers.xsd
366 |
367 | ##
368 | ## Visual studio for Mac
369 | ##
370 |
371 |
372 | # globs
373 | Makefile.in
374 | *.userprefs
375 | *.usertasks
376 | config.make
377 | config.status
378 | aclocal.m4
379 | install-sh
380 | autom4te.cache/
381 | *.tar.gz
382 | tarballs/
383 | test-results/
384 |
385 | # Mac bundle stuff
386 | *.dmg
387 | *.app
388 |
389 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
390 | # General
391 | .DS_Store
392 | .AppleDouble
393 | .LSOverride
394 |
395 | # Icon must end with two \r
396 | Icon
397 |
398 |
399 | # Thumbnails
400 | ._*
401 |
402 | # Files that might appear in the root of a volume
403 | .DocumentRevisions-V100
404 | .fseventsd
405 | .Spotlight-V100
406 | .TemporaryItems
407 | .Trashes
408 | .VolumeIcon.icns
409 | .com.apple.timemachine.donotpresent
410 |
411 | # Directories potentially created on remote AFP share
412 | .AppleDB
413 | .AppleDesktop
414 | Network Trash Folder
415 | Temporary Items
416 | .apdisk
417 |
418 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
419 | # Windows thumbnail cache files
420 | Thumbs.db
421 | ehthumbs.db
422 | ehthumbs_vista.db
423 |
424 | # Dump file
425 | *.stackdump
426 |
427 | # Folder config file
428 | [Dd]esktop.ini
429 |
430 | # Recycle Bin used on file shares
431 | $RECYCLE.BIN/
432 |
433 | # Windows Installer files
434 | *.cab
435 | *.msi
436 | *.msix
437 | *.msm
438 | *.msp
439 |
440 | # Windows shortcuts
441 | *.lnk
442 |
443 | # JetBrains Rider
444 | .idea/
445 | *.sln.iml
446 |
447 | ##
448 | ## Visual Studio Code
449 | ##
450 | .vscode/*
451 | !.vscode/settings.json
452 | !.vscode/tasks.json
453 | !.vscode/launch.json
454 | !.vscode/extensions.json
455 |
--------------------------------------------------------------------------------