├── .env ├── .github └── workflows │ └── publish-nuget.yml ├── .gitignore ├── Aspnext.sln ├── Makefile ├── README.md └── src └── template ├── Aspnext.Template.csproj └── Template ├── .editorconfig ├── .gitignore ├── .template.config ├── dotnetcli.host.json └── template.json ├── AspnextTemplate.sln ├── Makefile ├── README.md ├── infra ├── docker-compose-grafana.yaml ├── docker-compose-jaeger.yaml ├── docker-compose-kafka.yaml ├── docker-compose-postgres.yaml ├── docker-compose-prometheus.yaml ├── docker-compose-zitadel.yaml └── prometheus.yml └── src ├── AspnextTemplate.Api ├── AspnextTemplate.Api.csproj ├── Controllers │ └── ExampleController.cs ├── Dockerfile ├── Extensions │ └── ServiceCollectionExtensions.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── appsettings.Development.json └── appsettings.json ├── AspnextTemplate.Domain ├── AspnextTemplate.Domain.csproj ├── Notification │ ├── IExampleConsumer.cs │ └── IExampleProducer.cs └── Observability │ └── IMetricsProvider.cs └── Infrastructure ├── AspnextTemplate.Infrastructure.Data ├── AspnextTemplate.Infrastructure.Data.csproj ├── Kafka │ ├── Configuration │ │ └── ExampleProduderConfiguration.cs │ ├── Consumers │ │ └── ExampleConsumer.cs │ └── Producers │ │ └── ExampleProducer.cs └── Repositories │ └── AspnextTemplateDbContext.cs ├── AspnextTemplate.Infrastructure.Observability ├── AspnextTemplate.Infrastructure.Observability.csproj ├── MetricsProvider.cs └── ServiceCollectionExtensions.cs └── AspnextTemplate.Infrastructure.Zitadel ├── AspnextTemplate.Infrastructure.Zitadel.csproj ├── AuthConstants.cs ├── ServiceCollectionExtensions.cs ├── ZitadelConfiguration.cs └── ZitadelRoleHandler.cs /.env: -------------------------------------------------------------------------------- 1 | TEST_PROJ_NAME=MyProject 2 | TEMPL_DOTNET_NAME=aspnext 3 | NUGET_FILE=Aspnext.Template.8.3.0.nupkg 4 | NUGET_API_KEY= -------------------------------------------------------------------------------- /.github/workflows/publish-nuget.yml: -------------------------------------------------------------------------------- 1 | name: Publish .NET Template 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Setup .NET SDK 16 | uses: actions/setup-dotnet@v4 17 | with: 18 | dotnet-version: 8.0.x 19 | 20 | - name: Restore dependencies 21 | run: dotnet restore src/template/Aspnext.Template.csproj 22 | 23 | - name: Build the project 24 | run: dotnet build src/template/Aspnext.Template.csproj --no-restore --configuration Release 25 | 26 | - name: Pack the project 27 | run: dotnet pack src/template/Aspnext.Template.csproj --no-build --configuration Release --output ./nupkg 28 | 29 | - name: Publish to NuGet 30 | env: 31 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} 32 | run: dotnet nuget push "./nupkg/*.nupkg" --api-key $NUGET_API_KEY --source https://api.nuget.org/v3/index.json --skip-duplicate 33 | 34 | - name: Publish to Github Nuget Registry 35 | env: 36 | NUGET_GH_API_KEY: ${{ secrets.GITHUB_TOKEN }} 37 | run: dotnet nuget push "./nupkg/*.nupkg" --api-key $NUGET_GH_API_KEY --source https://nuget.pkg.github.com/MadL1me/index.json --skip-duplicate 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | .idea 4 | .idea 5 | MainTemplate/.vs 6 | MainTemplate/nupkg 7 | Level X/.vs 8 | Level X/nupkg 9 | .env.prod 10 | AspnextTemplate/nupkg 11 | AspnextTemplate/Template/react-vite/node_modules 12 | **/.DS_Store 13 | experiments 14 | src/template/nupkg 15 | -------------------------------------------------------------------------------- /Aspnext.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspnext.Template", "src\template\Aspnext.Template.csproj", "{768CB4F3-FE8B-4865-B3B2-015B2A23262C}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".config", ".config", "{303FD465-E4F3-446F-9F1D-A4CE5E08E2D7}" 9 | ProjectSection(SolutionItems) = preProject 10 | Makefile = Makefile 11 | .env.prod = .env.prod 12 | .env = .env 13 | README.md = README.md 14 | .gitignore = .gitignore 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {768CB4F3-FE8B-4865-B3B2-015B2A23262C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {768CB4F3-FE8B-4865-B3B2-015B2A23262C}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {768CB4F3-FE8B-4865-B3B2-015B2A23262C}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {768CB4F3-FE8B-4865-B3B2-015B2A23262C}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Define environment variables 2 | TEMPL_DIR := src/template 3 | DOTENV := .env.prod 4 | TEST_PROJ_OUT := "experiments/Rule" 5 | include $(DOTENV) 6 | export $(shell sed 's/=.*//' $(DOTENV)) 7 | 8 | .PHONY: remove create create_release install new run-dotnet run all list info deploy 9 | 10 | all: uninstall clean remove pack install new 11 | 12 | clean: 13 | cd experiments && \ 14 | rm -rf * 15 | 16 | install: 17 | dotnet new install ./ 18 | 19 | uninstall: 20 | dotnet new uninstall ./ 21 | 22 | remove: 23 | cd $(TEMPL_DIR)/nupkg && \ 24 | pwd && \ 25 | dotnet new --uninstall $$TEMPL_NAME && \ 26 | rm -rf * 27 | 28 | pack: 29 | cd $(TEMPL_DIR) && \ 30 | dotnet pack 31 | 32 | pack-release: 33 | cd $(TEMPL_DIR) && \ 34 | dotnet pack --configuration Release 35 | 36 | new: 37 | rm -rf $(TEST_PROJ_OUT) 38 | dotnet new $(TEMPL_DOTNET_NAME) -o $(TEST_PROJ_OUT) 39 | 40 | run-dotnet: 41 | cd $(TEST_PROJ_OUT) && \ 42 | dotnet run 43 | 44 | info: 45 | dotnet new $$TEMPL_DOTNET_NAME -h 46 | 47 | deploy: remove pack-release 48 | cd $(TEMPL_DIR)/nupkg && \ 49 | dotnet nuget push $(NUGET_FILE) --api-key $(NUGET_API_KEY) --source https://api.nuget.org/v3/index.json 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Dotnet foundation](https://img.shields.io/badge/-.NET%20Template-blueviolet)](https://dotnetfoundation.org/) 2 | ![Version](https://img.shields.io/badge/version-8.3.0-blue) 3 | [![Nuget package](https://img.shields.io/badge/Nuget%20-Package-red)](https://www.nuget.org/packages/Aspnext.Template/8.2.0) 4 | 5 | # Asset 1@2x AspNext 6 | 7 | ASP.NET 8 Opinionated template for fast development. **_Write code, not Configs._** 8 | 9 | ## Where to start 10 | 11 | Currently, main repository contains `Aspnext.Template` template - template with ASP.NET Core, Zitadel and many other things. 12 | 13 | Each _Template_ is easy runs in docker, have its own _README_ which contains info about project Stack, documentation and useful commands list. 14 | 15 | If you don't want to use it, you can start with __main__ template like this: 16 | 17 | 1. Install template: 18 | 19 | ```sh 20 | dotnet new install Aspnext.Template::8.3.0 21 | ``` 22 | 23 | 2. Create template with dotnet new: 24 | 25 | ```sh 26 | dotnet new aspnext -o "MyAwesomeProjectName" 27 | ``` 28 | 29 | 3. Use your template! (For example, go to Aspnext.Template template [README](https://github.com/MadL1me/aspnet-awesome-templates/blob/master/Asp.AwesomeTemplates.Spa/Template/README.md), it will have all required commands with your configuration) 30 | 31 | ## Contribute 32 | 33 | You can contribute by issue proposals, and making pull requests. 34 | 35 | Your ideas about how we can make this simpler, more easy etc are very much needed. 36 | -------------------------------------------------------------------------------- /src/template/Aspnext.Template.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Template 5 | 8.3.0 6 | Aspnext.Template 7 | ASP.NET 8 awesome SPA template 8 | Ilya Klimenko (MadL1me) 9 | ASP.NET 8 Easy-to-use, modern and awesome template. 10 | dotnet-new;templates;aspnet;webapp;aspnet-react;aspnet-next;aspnext;template 11 | net8.0 12 | true 13 | true 14 | true 15 | false 16 | content 17 | ./nupkg 18 | AspnextTemplate 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/template/Template/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # top-most EditorConfig file 4 | # Don't use tabs for indentation. 5 | # noinspection EditorConfigKeyCorrectness 6 | [*] 7 | end_of_line = lf 8 | indent_style = space 9 | max_line_length = 140 10 | guidelines = 140 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | indent_size = 4 15 | 16 | [*.json] 17 | indent_size = 2 18 | 19 | # Microsoft .NET properties 20 | csharp_remove_blank_lines_near_braces_in_declarations = true 21 | csharp_blank_lines_around_type = 1 22 | csharp_blank_lines_before_single_line_comment = 1 23 | csharp_keep_blank_lines_in_declarations = 1 24 | 25 | csharp_new_line_before_members_in_object_initializers = true 26 | csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion 27 | csharp_space_after_cast = false 28 | csharp_style_var_elsewhere = true:suggestion 29 | csharp_style_var_for_built_in_types = true:suggestion 30 | csharp_style_var_when_type_is_apparent = true:suggestion 31 | csharp_wrap_parameters_style = chop_if_long 32 | dotnet_naming_rule.unity_serialized_field_rule.import_to_resharper = True 33 | dotnet_naming_rule.unity_serialized_field_rule.resharper_description = Unity serialized field 34 | dotnet_naming_rule.unity_serialized_field_rule.resharper_guid = 5f0fdb63-c892-4d2c-9324-15c80b22a7ef 35 | dotnet_naming_rule.unity_serialized_field_rule.severity = warning 36 | dotnet_naming_rule.unity_serialized_field_rule.style = lower_camel_case_style 37 | dotnet_naming_rule.unity_serialized_field_rule.symbols = unity_serialized_field_symbols 38 | dotnet_naming_style.lower_camel_case_style.capitalization = camel_case 39 | dotnet_naming_symbols.unity_serialized_field_symbols.applicable_accessibilities = * 40 | dotnet_naming_symbols.unity_serialized_field_symbols.applicable_kinds = 41 | dotnet_naming_symbols.unity_serialized_field_symbols.resharper_applicable_kinds = unity_serialised_field 42 | dotnet_naming_symbols.unity_serialized_field_symbols.resharper_required_modifiers = instance 43 | dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none 44 | dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none 45 | dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none 46 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 47 | dotnet_style_predefined_type_for_member_access = true:suggestion 48 | dotnet_style_qualification_for_event = false:suggestion 49 | dotnet_style_qualification_for_field = false:suggestion 50 | dotnet_style_qualification_for_method = false:suggestion 51 | dotnet_style_qualification_for_property = false:suggestion 52 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 53 | 54 | # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview 55 | dotnet_diagnostic.IDE0055.severity = warning 56 | dotnet_diagnostic.IDE0161.severity = error 57 | 58 | # StyleCop Rules 59 | dotnet_diagnostic.SA0001.severity = none # SA0001: All diagnostics of XML documentation comments has been disabled due to the current project configuration. 60 | dotnet_diagnostic.SA1000.severity = none # SA1000: The spacing around a C# keyword is incorrect. 61 | dotnet_diagnostic.SA1005.severity = none # SA1005: A single-line comment within a C# code file does not begin with a single space. 62 | dotnet_diagnostic.SA1009.severity = none # SA1009: A closing parenthesis within a C# statement is not spaced correctly. 63 | dotnet_diagnostic.SA1028.severity = none # SA1028: A line of code ends with a space, tab, or other whitespace characters before the end of line character(s). 64 | dotnet_diagnostic.SA1100.severity = none # SA1100: A call to a member from an inherited class begins with base., and the local class does not contain an override or implementation of the member. 65 | dotnet_diagnostic.SA1101.severity = none # SA1101: A call to an instance member of the local class or a base class is not prefixed with 'this.', within a C# code file. 66 | dotnet_diagnostic.SA1111.severity = none # SA1111: The closing parenthesis or bracket in a call to a C# method or indexer, or the declaration of a method or indexer, is not placed on the same line as the last parameter. 67 | dotnet_diagnostic.SA1117.severity = none # SA1117: The parameters to a C# method or indexer call or declaration are not all on the same line or each on a separate line. 68 | dotnet_diagnostic.SA1118.severity = none # SA1118: A parameter to a C# method or indexer, other than the first parameter, spans across multiple lines. 69 | dotnet_diagnostic.SA1122.severity = none # SA1122: The C# code includes an empty string, written as "". 70 | dotnet_diagnostic.SA1124.severity = none # SA1124: The C# code contains a region. 71 | dotnet_diagnostic.SA1126.severity = none # SA1126: A call to a member is not prefixed with the 'this.', 'base.', 'object.' or 'typename.' prefix to indicate the intended method call, within a C# code file. 72 | dotnet_diagnostic.SA1127.severity = none # SA1127: A generic constraint on a type or method declaration is on the same line as the declaration, within a C# code file. 73 | dotnet_diagnostic.SA1128.severity = none # SA1128: A constructor initializer is on the same line as the constructor declaration, within a C# code file. 74 | dotnet_diagnostic.SA1131.severity = none # SA1131: A comparison was made between a variable and a literal or constant value, and the variable appeared on the right-hand side of the expression. 75 | dotnet_diagnostic.SA1133.severity = none # SA1133: Two or more fields were declared in the same field declaration syntax. 76 | dotnet_diagnostic.SA1134.severity = none # SA1134: Two or more attributes appeared within the same set of square brackets. 77 | dotnet_diagnostic.SA1200.severity = none # SA1200: A C# using directive is placed outside of a namespace element. 78 | dotnet_diagnostic.SA1201.severity = none # SA1201: An element within a C# code file is out of order in relation to the other elements in the code. 79 | dotnet_diagnostic.SA1202.severity = none # SA1202: An element within a C# code file is out of order within regard to access level, in relation to other elements in the code. 80 | dotnet_diagnostic.SA1203.severity = none # SA1203: A constant field is placed beneath a non-constant field. 81 | dotnet_diagnostic.SA1204.severity = none # SA1204: A static element is positioned beneath an instance element of the same type. 82 | dotnet_diagnostic.SA1206.severity = none # SA1206: The keywords within the declaration of an element do not follow a standard ordering scheme. 83 | dotnet_diagnostic.SA1214.severity = none # SA1214: A readonly field is positioned beneath a non-readonly field. 84 | dotnet_diagnostic.SA1306.severity = none # SA1306: The name of a field in C# does not begin with a lower-case letter. 85 | dotnet_diagnostic.SA1309.severity = none # SA1309: A field name in C# begins with an underscore. 86 | dotnet_diagnostic.SA1310.severity = none # SA1310: A field name in C# contains an underscore. 87 | dotnet_diagnostic.SA1413.severity = none # SA1413: A multi-line initializer should use a comma on the last item. 88 | dotnet_diagnostic.SA1512.severity = none # SA1512: A single-line comment within C# code is followed by a blank line. 89 | dotnet_diagnostic.SA1515.severity = none # SA1515: A single-line comment within C# code is not preceded by a blank line. 90 | dotnet_diagnostic.SA1516.severity = none # SA1516: Adjacent C# elements are not separated by a blank line. 91 | dotnet_diagnostic.SA1518.severity = none # SA1518: The line endings at the end of a file do not match the settings for the project. 92 | dotnet_diagnostic.SA1600.severity = none # SA1600: A C# code element is missing a documentation header. 93 | dotnet_diagnostic.SA1601.severity = none # SA1601: A C# partial element is missing a documentation header. 94 | dotnet_diagnostic.SA1602.severity = none # SA1602: An item within a C# enumeration is missing an Xml documentation header. 95 | dotnet_diagnostic.SA1604.severity = none # SA1604: The Xml header documentation for a C# element is missing a tag. 96 | dotnet_diagnostic.SA1605.severity = none # SA1605: The or tag within the documentation header for a C# code element is missing or empty. 97 | dotnet_diagnostic.SA1606.severity = none # SA1606: The tag within the documentation header for a C# code element is empty. 98 | dotnet_diagnostic.SA1607.severity = none # SA1607: The or tag within the documentation header for a C# code element is empty. 99 | dotnet_diagnostic.SA1608.severity = none # SA1608: The tag within an element's Xml header documentation contains the default text generated by Visual Studio during the creation of the element. 100 | dotnet_diagnostic.SA1609.severity = none # SA1609: The Xml header documentation for a C# property does not contain a tag. 101 | dotnet_diagnostic.SA1610.severity = none # SA1610: The Xml header documentation for a C# property contains an empty tag. 102 | dotnet_diagnostic.SA1611.severity = none # SA1611: A C# method, constructor, delegate or indexer element is missing documentation for one or more of its parameters. 103 | dotnet_diagnostic.SA1613.severity = none # SA1613: A tag within a C# element's documentation header is missing a name attribute containing the name of the parameter. 104 | dotnet_diagnostic.SA1614.severity = none # SA1614: A tag within a C# element's documentation header is empty. 105 | dotnet_diagnostic.SA1615.severity = none # SA1615: A C# element is missing documentation for its return value. 106 | dotnet_diagnostic.SA1616.severity = none # SA1616: The tag within a C# element's documentation header is empty. 107 | dotnet_diagnostic.SA1617.severity = none # SA1617: A C# code element does not contain a return value, or returns void, but the documentation header for the element contains a tag. 108 | dotnet_diagnostic.SA1618.severity = none # SA1618: A generic C# element is missing documentation for one or more of its generic type parameters. 109 | dotnet_diagnostic.SA1619.severity = none # SA1619: A generic, partial C# element is missing documentation for one or more of its generic type parameters, and the documentation for the element contains a tag. 110 | dotnet_diagnostic.SA1620.severity = none # SA1620: The tags within the Xml header documentation for a generic C# element do not match the generic type parameters on the element. 111 | dotnet_diagnostic.SA1621.severity = none # SA1621: A tag within the Xml header documentation for a generic C# element is missing a name attribute, or contains an empty name attribute. 112 | dotnet_diagnostic.SA1622.severity = none # SA1622: A tag within the Xml header documentation for a generic C# element is empty. 113 | dotnet_diagnostic.SA1623.severity = none # SA1623: The documentation text within a C# property's tag does not match the accessors within the property. 114 | dotnet_diagnostic.SA1624.severity = none # SA1624: The documentation text within a C# property's tag takes into account all of the accessors within the property, but one of the accessors has limited access. 115 | dotnet_diagnostic.SA1625.severity = none # SA1625: The Xml documentation for a C# element contains two or more identical entries, indicating that the documentation has been copied and pasted. 116 | dotnet_diagnostic.SA1627.severity = none # SA1627: The Xml header documentation for a C# code element contains an empty tag. 117 | dotnet_diagnostic.SA1629.severity = none # SA1629: A section of the Xml header documentation for a C# element does not end with a period (also known as a full stop). 118 | dotnet_diagnostic.SA1630.severity = none # SA1630: A section of the Xml header documentation for a C# element does not contain any whitespace between words. 119 | dotnet_diagnostic.SA1631.severity = none # SA1631: A section of the Xml header documentation for a C# element does not contain enough alphabetic characters. 120 | dotnet_diagnostic.SA1633.severity = none # SA1633: A C# code file is missing a standard file header. 121 | dotnet_diagnostic.SA1634.severity = none # SA1634: The file header at the top of a C# code file is missing a copyright tag. 122 | dotnet_diagnostic.SA1635.severity = none # SA1635: The file header at the top of a C# code file is missing copyright text. 123 | dotnet_diagnostic.SA1636.severity = none # SA1636: The file header at the top of a C# code file does not contain the appropriate copyright text. 124 | dotnet_diagnostic.SA1637.severity = none # SA1637: The file header at the top of a C# code file is missing the file name. 125 | dotnet_diagnostic.SA1638.severity = none # SA1638: The file tag within the file header at the top of a C# code file does not contain the name of the file. 126 | dotnet_diagnostic.SA1639.severity = none # SA1639: The file header at the top of a C# code file does not contain a filled-in summary tag. 127 | dotnet_diagnostic.SA1640.severity = none # SA1640: The file header at the top of a C# code file does not contain company name text. 128 | dotnet_diagnostic.SA1641.severity = none # SA1641: The file header at the top of a C# code file does not contain the appropriate company name text. 129 | dotnet_diagnostic.SA1642.severity = none # SA1642: The XML documentation header for a C# constructor does not contain the appropriate summary text. 130 | dotnet_diagnostic.SA1643.severity = none # SA1643: The Xml documentation header for a C# finalizer does not contain the appropriate summary text. 131 | dotnet_diagnostic.SA1649.severity = none # SA1649: The file name of a C# code file does not match the first type declared in the file. 132 | 133 | dotnet_diagnostic.SA1507.severity = error 134 | # dotnet_diagnostic.SA1505.severity = error # Blank line immediately before or after a { line: remove it. SA1505, SA1509 135 | # dotnet_diagnostic.SA1509.severity = error # Blank line immediately before or after a { line: remove it. SA1505, SA1509 136 | # dotnet_diagnostic.SA1508.severity = error # Blank line immediately before a } line: remove it. SA1508 137 | 138 | # Meziantou.Analyzer 139 | dotnet_diagnostic.MA0001.severity = suggestion # MA0001: StringComparison is missing 140 | dotnet_diagnostic.MA0002.severity = none # MA0002: IEqualityComparer or IComparer is missing 141 | dotnet_diagnostic.MA0003.severity = suggestion # MA0003: Add parameter name to improve readability 142 | dotnet_diagnostic.MA0004.severity = none # MA0004: Use Task.ConfigureAwait(false) 143 | dotnet_diagnostic.MA0005.severity = warning # MA0005: Use Array.Empty() 144 | dotnet_diagnostic.MA0006.severity = none # MA0006: Use String.Equals instead of equality operator 145 | dotnet_diagnostic.MA0007.severity = none # MA0007: Add a comma after the last value 146 | dotnet_diagnostic.MA0008.severity = none # MA0008: Add StructLayoutAttribute 147 | dotnet_diagnostic.MA0009.severity = warning # MA0009: Add regex evaluation timeout 148 | dotnet_diagnostic.MA0010.severity = warning # MA0010: Mark attributes with AttributeUsageAttribute 149 | dotnet_diagnostic.MA0011.severity = none # MA0011: IFormatProvider is missing 150 | dotnet_diagnostic.MA0012.severity = warning # MA0012: Do not raise reserved exception type 151 | dotnet_diagnostic.MA0013.severity = warning # MA0013: Types should not extend System.ApplicationException 152 | dotnet_diagnostic.MA0014.severity = warning # MA0014: Do not raise System.ApplicationException type 153 | dotnet_diagnostic.MA0015.severity = none # MA0015: Specify the parameter name in ArgumentException 154 | dotnet_diagnostic.MA0016.severity = none # MA0016: Prefer returning collection abstraction instead of implementation 155 | dotnet_diagnostic.MA0017.severity = warning # MA0017: Abstract types should not have public or internal constructors 156 | dotnet_diagnostic.MA0018.severity = none # MA0018: Do not declare static members on generic types 157 | dotnet_diagnostic.MA0019.severity = warning # MA0019: Use EventArgs.Empty 158 | dotnet_diagnostic.MA0020.severity = suggestion # MA0020: Use direct methods instead of LINQ methods 159 | dotnet_diagnostic.MA0021.severity = warning # MA0021: Use StringComparer.GetHashCode instead of string.GetHashCode 160 | dotnet_diagnostic.MA0022.severity = warning # MA0022: Return Task.FromResult instead of returning null 161 | dotnet_diagnostic.MA0023.severity = warning # MA0023: Add RegexOptions.ExplicitCapture 162 | dotnet_diagnostic.MA0024.severity = warning # MA0024: Use an explicit StringComparer when possible 163 | dotnet_diagnostic.MA0025.severity = none # MA0025: Implement the functionality instead of throwing NotImplemented Exception 164 | dotnet_diagnostic.MA0026.severity = none # MA0026: Fix wip comment 165 | dotnet_diagnostic.MA0027.severity = warning # MA0027: Do not remove original exception 166 | dotnet_diagnostic.MA0028.severity = suggestion # MA0028: Optimize StringBuilder usage 167 | dotnet_diagnostic.MA0029.severity = suggestion # MA0029: Combine LINQ methods 168 | dotnet_diagnostic.MA0030.severity = warning # MA0030: Remove useless OrderBy call 169 | dotnet_diagnostic.MA0031.severity = suggestion # MA0031: Optimize Enumerable.Count() usage 170 | dotnet_diagnostic.MA0032.severity = none # MA0032: Use an overload with a CancellationToken argument 171 | dotnet_diagnostic.MA0033.severity = warning # MA0033: Do not tag instance fields with ThreadStaticAttribute 172 | dotnet_diagnostic.MA0035.severity = warning # MA0035: Do not use dangerous threading methods 173 | dotnet_diagnostic.MA0036.severity = suggestion # MA0036: Make class static 174 | dotnet_diagnostic.MA0037.severity = error # MA0037: Remove empty statement 175 | dotnet_diagnostic.MA0038.severity = suggestion # MA0038: Make method static 176 | dotnet_diagnostic.MA0039.severity = error # MA0039: Do not write your own certificate validation method 177 | dotnet_diagnostic.MA0040.severity = warning # MA0040: Flow the cancellation token 178 | dotnet_diagnostic.MA0041.severity = suggestion # MA0041: Make property static 179 | dotnet_diagnostic.MA0042.severity = suggestion # MA0042: Do not use blocking calls in an async method 180 | dotnet_diagnostic.MA0043.severity = suggestion # MA0043: Use nameof operator in ArgumentException 181 | dotnet_diagnostic.MA0044.severity = suggestion # MA0044: Remove useless ToString call 182 | dotnet_diagnostic.MA0045.severity = none # MA0045: Do not use blocking call in a sync method (need to make containing method async) 183 | dotnet_diagnostic.MA0046.severity = warning # MA0046: Use EventHandler to declare events 184 | dotnet_diagnostic.MA0047.severity = warning # MA0047: Declare types in namespaces 185 | dotnet_diagnostic.MA0048.severity = none # MA0048: File name must match type name 186 | dotnet_diagnostic.MA0049.severity = none # MA0049: Type name should not match containing namespace 187 | dotnet_diagnostic.MA0050.severity = suggestion # MA0050: Validate arguments correctly in iterator methods 188 | dotnet_diagnostic.MA0051.severity = none # MA0051: Method is too long 189 | dotnet_diagnostic.MA0052.severity = warning # MA0052: Replace constant Enum.ToString with nameof 190 | dotnet_diagnostic.MA0053.severity = suggestion # MA0053: Make class sealed 191 | dotnet_diagnostic.MA0054.severity = warning # MA0054: Embed the caught exception as innerException 192 | dotnet_diagnostic.MA0055.severity = warning # MA0055: Do not use finalizer 193 | dotnet_diagnostic.MA0056.severity = warning # MA0056: Do not call overridable members in constructor 194 | dotnet_diagnostic.MA0057.severity = suggestion # MA0057: Class name should end with 'Attribute' 195 | dotnet_diagnostic.MA0058.severity = suggestion # MA0058: Class name should end with 'Exception' 196 | dotnet_diagnostic.MA0059.severity = suggestion # MA0059: Class name should end with 'EventArgs' 197 | dotnet_diagnostic.MA0060.severity = warning # MA0060: The value returned by Stream.Read/Stream.ReadAsync is not used 198 | dotnet_diagnostic.MA0061.severity = warning # MA0061: Method overrides should not change parameter defaults 199 | dotnet_diagnostic.MA0062.severity = warning # MA0062: Non-flags enums should not be marked with "FlagsAttribute" 200 | dotnet_diagnostic.MA0063.severity = suggestion # MA0063: Use Where before OrderBy 201 | dotnet_diagnostic.MA0064.severity = warning # MA0064: Avoid locking on publicly accessible instance 202 | dotnet_diagnostic.MA0065.severity = warning # MA0065: Default ValueType.Equals or HashCode is used for struct's equality 203 | dotnet_diagnostic.MA0066.severity = warning # MA0066: Hash table unfriendly type is used in a hash table 204 | dotnet_diagnostic.MA0067.severity = suggestion # MA0067: Use Guid.Empty 205 | dotnet_diagnostic.MA0068.severity = warning # MA0068: Invalid parameter name for nullable attribute 206 | dotnet_diagnostic.MA0069.severity = warning # MA0069: Non-constant static fields should not be visible 207 | dotnet_diagnostic.MA0070.severity = warning # MA0070: Obsolete attributes should include explanations 208 | dotnet_diagnostic.MA0071.severity = suggestion # MA0071: Avoid using redundant else 209 | dotnet_diagnostic.MA0072.severity = warning # MA0072: Do not throw from a finally block 210 | dotnet_diagnostic.MA0073.severity = suggestion # MA0073: Avoid comparison with bool constant 211 | dotnet_diagnostic.MA0074.severity = none # MA0074: Avoid implicit culture-sensitive methods 212 | dotnet_diagnostic.MA0075.severity = suggestion # MA0075: Do not use implicit culture-sensitive ToString 213 | dotnet_diagnostic.MA0076.severity = suggestion # MA0076: Do not use implicit culture-sensitive ToString in interpolated strings 214 | dotnet_diagnostic.MA0077.severity = warning # MA0077: A class that provides Equals(T) should implement IEquatable 215 | dotnet_diagnostic.MA0078.severity = suggestion # MA0078: Use 'Cast' instead of 'Select' to cast 216 | dotnet_diagnostic.MA0079.severity = suggestion # MA0079: Flow the cancellation token using .WithCancellation() 217 | dotnet_diagnostic.MA0080.severity = none # MA0080: Use a cancellation token using .WithCancellation() 218 | dotnet_diagnostic.MA0081.severity = warning # MA0081: Method overrides should not omit params keyword 219 | dotnet_diagnostic.MA0082.severity = warning # MA0082: NaN should not be used in comparisons 220 | dotnet_diagnostic.MA0083.severity = warning # MA0083: ConstructorArgument parameters should exist in constructors 221 | dotnet_diagnostic.MA0084.severity = warning # MA0084: Local variable should not hide other symbols 222 | dotnet_diagnostic.MA0085.severity = warning # MA0085: Anonymous delegates should not be used to unsubscribe from Events 223 | dotnet_diagnostic.MA0086.severity = warning # MA0086: Do not throw from a finalizer 224 | dotnet_diagnostic.MA0087.severity = warning # MA0087: Parameters with [DefaultParameterValue] attributes should also be marked [Optional] 225 | dotnet_diagnostic.MA0088.severity = warning # MA0088: Use [DefaultParameterValue] instead of [DefaultValue] 226 | dotnet_diagnostic.MA0089.severity = suggestion # MA0089: Optimize string method usage 227 | dotnet_diagnostic.MA0090.severity = suggestion # MA0090: Remove empty else/finally block 228 | dotnet_diagnostic.MA0091.severity = warning # MA0091: Sender should be 'this' for instance events 229 | dotnet_diagnostic.MA0092.severity = warning # MA0092: Sender should be 'null' for static events 230 | dotnet_diagnostic.MA0093.severity = warning # MA0093: EventArgs should not be null 231 | dotnet_diagnostic.MA0094.severity = warning # MA0094: A class that provides CompareTo(T) should implement IComparable 232 | dotnet_diagnostic.MA0095.severity = warning # MA0095: A class that implements IEquatable should override Equals(object) 233 | dotnet_diagnostic.MA0096.severity = warning # MA0096: A class that implements IComparable should also implement IEquatable 234 | dotnet_diagnostic.MA0097.severity = warning # MA0097: A class that implements IComparable or IComparable should override comparison operators 235 | dotnet_diagnostic.MA0098.severity = suggestion # MA0098: Use indexer instead of LINQ methods 236 | dotnet_diagnostic.MA0099.severity = warning # MA0099: Use Explicit enum value instead of 0 237 | dotnet_diagnostic.MA0100.severity = warning # MA0100: Await task before disposing of resources 238 | dotnet_diagnostic.MA0101.severity = silent # MA0101: String contains an implicit end of line character 239 | dotnet_diagnostic.MA0102.severity = suggestion # MA0102: Make member readonly 240 | dotnet_diagnostic.MA0103.severity = warning # MA0103: Use SequenceEqual instead of equality operator 241 | dotnet_diagnostic.MA0104.severity = none # MA0104: Do not create a type with a name from the BCL 242 | dotnet_diagnostic.MA0105.severity = suggestion # MA0105: Use the lambda parameters instead of using a closure 243 | dotnet_diagnostic.MA0106.severity = suggestion # MA0106: Avoid closure by using an overload with the 'factoryArgument' parameter 244 | dotnet_diagnostic.MA0107.severity = none # MA0107: Do not use culture-sensitive object.ToString 245 | dotnet_diagnostic.MA0108.severity = suggestion # MA0108: Remove redundant argument value 246 | dotnet_diagnostic.MA0109.severity = none # MA0109: Consider adding an overload with a Span or Memory 247 | dotnet_diagnostic.MA0110.severity = suggestion # MA0110: Use the Regex source generator 248 | 249 | # XML project files 250 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] 251 | ij_xml_space_inside_empty_tag = true 252 | csharp_indent_labels = one_less_than_current 253 | csharp_using_directive_placement = outside_namespace:silent 254 | csharp_prefer_simple_using_statement = true:suggestion 255 | csharp_prefer_braces = true:silent 256 | csharp_style_namespace_declarations = block_scoped:silent 257 | csharp_style_prefer_method_group_conversion = true:silent 258 | csharp_style_prefer_top_level_statements = true:silent 259 | csharp_style_prefer_primary_constructors = true:suggestion 260 | csharp_style_expression_bodied_methods = false:silent 261 | csharp_style_expression_bodied_constructors = false:silent 262 | csharp_style_expression_bodied_operators = false:silent 263 | csharp_style_expression_bodied_properties = true:silent 264 | csharp_style_expression_bodied_indexers = true:silent 265 | csharp_style_expression_bodied_accessors = true:silent 266 | csharp_style_expression_bodied_lambdas = true:silent 267 | csharp_style_expression_bodied_local_functions = false:silent 268 | csharp_space_around_binary_operators = before_and_after 269 | 270 | # XML config files 271 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] 272 | indent_size = 2 273 | ij_xml_space_inside_empty_tag = true 274 | 275 | # Dotnet code style settings: 276 | [*.{cs,vb}] 277 | ############################### 278 | # Naming Conventions # 279 | ############################### 280 | # Style Definitions 281 | 282 | ## start with underscore style 283 | dotnet_naming_style.start_with_underscore_style.required_prefix = _ 284 | dotnet_naming_style.start_with_underscore_style.capitalization = camel_case 285 | 286 | ## Pascal style 287 | dotnet_naming_style.pascal_style.capitalization = pascal_case 288 | 289 | ## Camelcase style 290 | dotnet_naming_style.camel_case_style.capitalization = camel_case 291 | 292 | ## Private readonly fields 293 | dotnet_naming_symbols.private_readonly_fields.applicable_kinds = field 294 | dotnet_naming_symbols.private_readonly_fields.applicable_accessibilities = private 295 | dotnet_naming_symbols.private_readonly_fields.required_modifiers = readonly 296 | 297 | dotnet_naming_rule.private_readonly_fields_should_start_with_underscore.severity = suggestion 298 | dotnet_naming_rule.private_readonly_fields_should_start_with_underscore.symbols = private_readonly_fields 299 | dotnet_naming_rule.private_readonly_fields_should_start_with_underscore.style = start_with_underscore_style 300 | 301 | ## Private const fields 302 | dotnet_naming_symbols.private_const_fields.applicable_kinds = field 303 | dotnet_naming_symbols.private_const_fields.applicable_accessibilities = private 304 | dotnet_naming_symbols.private_const_fields.required_modifiers = const 305 | 306 | dotnet_naming_rule.private_const_should_be_pascal_case.severity = suggestion 307 | dotnet_naming_rule.private_const_should_be_pascal_case.symbols = private_const_fields 308 | dotnet_naming_rule.private_const_should_be_pascal_case.style = pascal_style 309 | 310 | ## Public const fields 311 | dotnet_naming_symbols.public_const_fields.applicable_kinds = field 312 | dotnet_naming_symbols.public_const_fields.applicable_accessibilities = public 313 | dotnet_naming_symbols.public_const_fields.required_modifiers = const 314 | 315 | dotnet_naming_rule.public_const_should_be_pascal_case.severity = suggestion 316 | dotnet_naming_rule.public_const_should_be_pascal_case.symbols = public_const_fields 317 | dotnet_naming_rule.public_const_should_be_pascal_case.style = pascal_style 318 | 319 | ## Private methods 320 | dotnet_naming_symbols.private_methods.applicable_kinds = method 321 | dotnet_naming_symbols.private_methods.applicable_accessibilities = private 322 | 323 | ## parameters 324 | dotnet_naming_symbols.parameters.applicable_kinds = parameter 325 | 326 | dotnet_naming_rule.parameters_should_be_camelcase.severity = warning 327 | dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters 328 | dotnet_naming_rule.parameters_should_be_camelcase.style = lower_camel_case_style 329 | 330 | # ReSharper properties 331 | resharper_wrap_object_and_collection_initializer_style = chop_always 332 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 333 | tab_width = 4 334 | dotnet_style_coalesce_expression = true:suggestion 335 | dotnet_style_null_propagation = true:suggestion 336 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 337 | dotnet_style_prefer_auto_properties = true:silent 338 | dotnet_style_object_initializer = true:suggestion 339 | 340 | [*.yml] 341 | indent_size = 2 342 | 343 | -------------------------------------------------------------------------------- /src/template/Template/.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 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | 33 | # Visual Studio 2015/2017 cache/options directory 34 | .vs/ 35 | # Uncomment if you have tasks that create the project's static files in wwwroot 36 | #wwwroot/ 37 | 38 | # Visual Studio 2017 auto generated files 39 | Generated\ Files/ 40 | 41 | # MSTest test Results 42 | [Tt]est[Rr]esult*/ 43 | [Bb]uild[Ll]og.* 44 | 45 | # NUNIT 46 | *.VisualState.xml 47 | TestResult.xml 48 | 49 | # Build Results of an ATL Project 50 | [Dd]ebugPS/ 51 | [Rr]eleasePS/ 52 | dlldata.c 53 | 54 | # Benchmark Results 55 | BenchmarkDotNet.Artifacts/ 56 | 57 | # .NET Core 58 | project.lock.json 59 | project.fragment.lock.json 60 | artifacts/ 61 | 62 | # StyleCop 63 | StyleCopReport.xml 64 | 65 | # Files built by Visual Studio 66 | *_i.c 67 | *_p.c 68 | *_h.h 69 | *.ilk 70 | *.meta 71 | *.obj 72 | *.iobj 73 | *.pch 74 | *.pdb 75 | *.ipdb 76 | *.pgc 77 | *.pgd 78 | *.rsp 79 | *.sbr 80 | *.tlb 81 | *.tli 82 | *.tlh 83 | *.tmp 84 | *.tmp_proj 85 | *_wpftmp.csproj 86 | *.log 87 | *.vspscc 88 | *.vssscc 89 | .builds 90 | *.pidb 91 | *.svclog 92 | *.scc 93 | 94 | # Chutzpah Test files 95 | _Chutzpah* 96 | 97 | # Visual C++ cache files 98 | ipch/ 99 | *.aps 100 | *.ncb 101 | *.opendb 102 | *.opensdf 103 | *.sdf 104 | *.cachefile 105 | *.VC.db 106 | *.VC.VC.opendb 107 | 108 | # Visual Studio profiler 109 | *.psess 110 | *.vsp 111 | *.vspx 112 | *.sap 113 | 114 | # Visual Studio Trace Files 115 | *.e2e 116 | 117 | # TFS 2012 Local Workspace 118 | $tf/ 119 | 120 | # Guidance Automation Toolkit 121 | *.gpState 122 | 123 | # ReSharper is a .NET coding add-in 124 | _ReSharper*/ 125 | *.[Rr]e[Ss]harper 126 | *.DotSettings.user 127 | 128 | # JustCode is a .NET coding add-in 129 | .JustCode 130 | 131 | # TeamCity is a build add-in 132 | _TeamCity* 133 | 134 | # DotCover is a Code Coverage Tool 135 | *.dotCover 136 | 137 | # AxoCover is a Code Coverage Tool 138 | .axoCover/* 139 | !.axoCover/settings.json 140 | 141 | # Visual Studio code coverage results 142 | *.coverage 143 | *.coveragexml 144 | 145 | # NCrunch 146 | _NCrunch_* 147 | .*crunch*.local.xml 148 | nCrunchTemp_* 149 | 150 | # MightyMoose 151 | *.mm.* 152 | AutoTest.Net/ 153 | 154 | # Web workbench (sass) 155 | .sass-cache/ 156 | 157 | # Installshield output folder 158 | [Ee]xpress/ 159 | 160 | # DocProject is a documentation generator add-in 161 | DocProject/buildhelp/ 162 | DocProject/Help/*.HxT 163 | DocProject/Help/*.HxC 164 | DocProject/Help/*.hhc 165 | DocProject/Help/*.hhk 166 | DocProject/Help/*.hhp 167 | DocProject/Help/Html2 168 | DocProject/Help/html 169 | 170 | # Click-Once directory 171 | publish/ 172 | 173 | # Publish Web Output 174 | *.[Pp]ublish.xml 175 | *.azurePubxml 176 | # Note: Comment the next line if you want to checkin your web deploy settings, 177 | # but database connection strings (with potential passwords) will be unencrypted 178 | *.pubxml 179 | *.publishproj 180 | 181 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 182 | # checkin your Azure Web App publish settings, but sensitive information contained 183 | # in these scripts will be unencrypted 184 | PublishScripts/ 185 | 186 | # NuGet Packages 187 | *.nupkg 188 | # The packages folder can be ignored because of Package Restore 189 | **/[Pp]ackages/* 190 | # except build/, which is used as an MSBuild target. 191 | !**/[Pp]ackages/build/ 192 | # Uncomment if necessary however generally it will be regenerated when needed 193 | #!**/[Pp]ackages/repositories.config 194 | # NuGet v3's project.json files produces more ignorable files 195 | *.nuget.props 196 | *.nuget.targets 197 | 198 | # Microsoft Azure Build Output 199 | csx/ 200 | *.build.csdef 201 | 202 | # Microsoft Azure Emulator 203 | ecf/ 204 | rcf/ 205 | 206 | # Windows Store app package directories and files 207 | AppPackages/ 208 | BundleArtifacts/ 209 | Package.StoreAssociation.xml 210 | _pkginfo.txt 211 | *.appx 212 | *.appxbundle 213 | *.appxupload 214 | 215 | # Visual Studio cache files 216 | # files ending in .cache can be ignored 217 | *.[Cc]ache 218 | # but keep track of directories ending in .cache 219 | !?*.[Cc]ache/ 220 | 221 | # Others 222 | ClientBin/ 223 | ~$* 224 | *~ 225 | *.dbmdl 226 | *.dbproj.schemaview 227 | *.jfm 228 | *.pfx 229 | *.publishsettings 230 | orleans.codegen.cs 231 | 232 | # Including strong name files can present a security risk 233 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 234 | #*.snk 235 | 236 | # Since there are multiple workflows, uncomment next line to ignore bower_components 237 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 238 | #bower_components/ 239 | 240 | # RIA/Silverlight projects 241 | Generated_Code/ 242 | 243 | # Backup & report files from converting an old project file 244 | # to a newer Visual Studio version. Backup files are not needed, 245 | # because we have git ;-) 246 | _UpgradeReport_Files/ 247 | Backup*/ 248 | UpgradeLog*.XML 249 | UpgradeLog*.htm 250 | ServiceFabricBackup/ 251 | *.rptproj.bak 252 | 253 | # SQL Server files 254 | *.mdf 255 | *.ldf 256 | *.ndf 257 | 258 | # Business Intelligence projects 259 | *.rdl.data 260 | *.bim.layout 261 | *.bim_*.settings 262 | *.rptproj.rsuser 263 | *- Backup*.rdl 264 | 265 | # Microsoft Fakes 266 | FakesAssemblies/ 267 | 268 | # GhostDoc plugin setting file 269 | *.GhostDoc.xml 270 | 271 | # Node.js Tools for Visual Studio 272 | .ntvs_analysis.dat 273 | node_modules/ 274 | 275 | # Visual Studio 6 build log 276 | *.plg 277 | 278 | # Visual Studio 6 workspace options file 279 | *.opt 280 | 281 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 282 | *.vbw 283 | 284 | # Visual Studio LightSwitch build output 285 | **/*.HTMLClient/GeneratedArtifacts 286 | **/*.DesktopClient/GeneratedArtifacts 287 | **/*.DesktopClient/ModelManifest.xml 288 | **/*.Server/GeneratedArtifacts 289 | **/*.Server/ModelManifest.xml 290 | _Pvt_Extensions 291 | 292 | # Paket dependency manager 293 | .paket/paket.exe 294 | paket-files/ 295 | 296 | # FAKE - F# Make 297 | .fake/ 298 | 299 | # CodeRush personal settings 300 | .cr/personal 301 | 302 | # Python Tools for Visual Studio (PTVS) 303 | __pycache__/ 304 | *.pyc 305 | 306 | # Cake 307 | tools/** 308 | !tools/packages.config 309 | 310 | # Tabs Studio 311 | *.tss 312 | 313 | # Telerik's JustMock configuration file 314 | *.jmconfig 315 | 316 | # BizTalk build output 317 | *.btp.cs 318 | *.btm.cs 319 | *.odx.cs 320 | *.xsd.cs 321 | 322 | # OpenCover UI analysis results 323 | OpenCover/ 324 | 325 | # Azure Stream Analytics local run output 326 | ASALocalRun/ 327 | 328 | # MSBuild Binary and Structured Log 329 | *.binlog 330 | 331 | # NVidia Nsight GPU debugger configuration file 332 | *.nvuser 333 | 334 | # MFractors (Xamarin productivity tool) working folder 335 | .mfractor/ 336 | 337 | # Local History for Visual Studio 338 | .localhistory/ 339 | 340 | # BeatPulse healthcheck temp database 341 | healthchecksdb 342 | 343 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 344 | MigrationBackup/ 345 | 346 | ## 347 | ## Visual studio for Mac 348 | ## 349 | 350 | 351 | # globs 352 | Makefile.in 353 | *.userprefs 354 | *.usertasks 355 | config.make 356 | config.status 357 | aclocal.m4 358 | install-sh 359 | autom4te.cache/ 360 | *.tar.gz 361 | tarballs/ 362 | test-results/ 363 | 364 | # Mac bundle stuff 365 | *.dmg 366 | *.app 367 | 368 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 369 | # General 370 | .DS_Store 371 | .AppleDouble 372 | .LSOverride 373 | 374 | # Icon must end with two \r 375 | Icon 376 | 377 | 378 | # Thumbnails 379 | ._* 380 | 381 | # Files that might appear in the root of a volume 382 | .DocumentRevisions-V100 383 | .fseventsd 384 | .Spotlight-V100 385 | .TemporaryItems 386 | .Trashes 387 | .VolumeIcon.icns 388 | .com.apple.timemachine.donotpresent 389 | 390 | # Directories potentially created on remote AFP share 391 | .AppleDB 392 | .AppleDesktop 393 | Network Trash Folder 394 | Temporary Items 395 | .apdisk 396 | 397 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 398 | # Windows thumbnail cache files 399 | Thumbs.db 400 | ehthumbs.db 401 | ehthumbs_vista.db 402 | 403 | # Dump file 404 | *.stackdump 405 | 406 | # Folder config file 407 | [Dd]esktop.ini 408 | 409 | # Recycle Bin used on file shares 410 | $RECYCLE.BIN/ 411 | 412 | # Windows Installer files 413 | *.cab 414 | *.msi 415 | *.msix 416 | *.msm 417 | *.msp 418 | 419 | # Windows shortcuts 420 | *.lnk 421 | 422 | # JetBrains Rider 423 | .idea/ 424 | *.sln.iml 425 | 426 | ## 427 | ## Visual Studio Code 428 | ## 429 | .vscode/* 430 | !.vscode/settings.json 431 | !.vscode/tasks.json 432 | !.vscode/launch.json 433 | !.vscode/extensions.json 434 | -------------------------------------------------------------------------------- /src/template/Template/.template.config/dotnetcli.host.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/dotnetcli.host", 3 | "symbolInfo": { 4 | "AddDatabase": { 5 | "longName": "database", 6 | "shortName": "db" 7 | }, 8 | "AddExamples": { 9 | "longName": "examples", 10 | "shortName": "e" 11 | }, 12 | "AddObservability": { 13 | "longName": "observability", 14 | "shortName": "o" 15 | }, 16 | "AddZitadelAuth": { 17 | "longName": "auth" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/template/Template/.template.config/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/template", 3 | "author": "Ilya Klimenko (MadL1me)", 4 | "classifications": ["WebApp", "ASP.NET 8", ".NET 8"], 5 | "identity": "Aspnext.Template", 6 | "name": "ASP.NET 8 Easy-to-use and modern template", 7 | "shortName": "aspnext", 8 | "sourceName": "AspnextTemplate", 9 | "tags": { 10 | "type": "solution", 11 | "language": "C#" 12 | }, 13 | "guids": [ 14 | "94618EED-2AEA-44A5-AC03-9A3B9AC0DBC4" 15 | ], 16 | "symbols": { 17 | "AddExamples": { 18 | "type": "parameter", 19 | "descriptions": "Adds examples and code-samples for both frontend and backend", 20 | "datatype": "bool", 21 | "defaultValue": "true" 22 | }, 23 | "AddDatabase": { 24 | "type": "parameter", 25 | "description": "Adds Database with Entity Framework and docker compose", 26 | "datatype": "choice", 27 | "defaultValue": "pgsql", 28 | "choices": [ 29 | { 30 | "choice": "pgsql", 31 | "description": "Use PostgreSQL database inside docker compose with PgAdmin" 32 | }, 33 | { 34 | "choice": "none", 35 | "description": "Do not use any database provider" 36 | } 37 | ] 38 | }, 39 | "AddZitadelAuth": { 40 | "type": "parameter", 41 | "description": "Adds 'Zitadel' identity provider setup with docker compose", 42 | "datatype": "bool", 43 | "defaultValue": "true" 44 | }, 45 | "AddObservability": { 46 | "type": "parameter", 47 | "description": "Adds OpenTelemetry tracing and metrics support with docker compose", 48 | "datatype": "bool", 49 | "defaultValue": "true" 50 | }, 51 | "AddKafka": { 52 | "type": "parameter", 53 | "description": "Adds Kafka support with docker compose", 54 | "datatype": "bool", 55 | "defaultValue": "false" 56 | }, 57 | "UsePostgreSql": { 58 | "type": "computed", 59 | "value": "(AddDatabase == \"pgsql\")" 60 | }, 61 | "UseInfraProject": { 62 | "type": "computed", 63 | "value": "(UsePostgreSql || AddKafka)" 64 | } 65 | }, 66 | "sources": [ 67 | { 68 | "modifiers": [ 69 | { 70 | "condition": "(!AddExamples)", 71 | "exclude": ["AspnextTemplate/Controllers/ExampleController.cs"] 72 | }, 73 | { 74 | "condition": "(!UsePostgreSql)", 75 | "exclude": [ 76 | "AspnextTemplate/Data/AspnextTemplateDbContext.cs", 77 | "infra/docker-compose-postgres.yaml" 78 | ] 79 | }, 80 | { 81 | "condition": "(!AddZitadelAuth)", 82 | "exclude": [ 83 | "infra/docker-compose-zitadel.yaml", 84 | "src/Infrastructure/AspnextTemplate.Infrastructure.Zitadel/**" 85 | ] 86 | }, 87 | { 88 | "condition": "(!AddObservability)", 89 | "exclude": [ 90 | "infra/docker-compose-grafana.yaml", 91 | "infra/docker-compose-jaeger.yaml", 92 | "infra/docker-compose-prometheus.yaml", 93 | "infra/prometheus.yaml", 94 | "src/Infrastructure/AspnextTemplate.Infrastructure.Observability", 95 | "src/AspnextTemplate.Domain/Observability/**" 96 | ] 97 | }, 98 | { 99 | "condition": "(!UseInfraProject)", 100 | "exclude": [ 101 | "src/Infrastructure/AspnextTemplate.Infrastructure.Data" 102 | ] 103 | }, 104 | { 105 | "condition": "(UseInfraProject && !UsePostgreSql)", 106 | "exclude": [ 107 | "src/Infrastructure/AspnextTemplate.Infrastructure.Data/Repositories" 108 | ] 109 | }, 110 | { 111 | "condition": "(UseInfraProject && !AddKafka)", 112 | "exclude": [ 113 | "src/Infrastructure/AspnextTemplate.Infrastructure.Data/Kafka/**", 114 | "src/Infrastructure/AspnextTemplate.Infrastructure.Data/Kafka" 115 | ] 116 | }, 117 | { 118 | "condition": "(!AddKafka)", 119 | "exclude": [ 120 | "src/AspnextTemplate.Domain/Notification/**", 121 | "src/AspnextTemplate.Domain/Notification" 122 | ] 123 | } 124 | ] 125 | } 126 | ] 127 | } 128 | -------------------------------------------------------------------------------- /src/template/Template/AspnextTemplate.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 17 3 | VisualStudioVersion = 17.0.31903.59 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".config", ".config", "{DF2D14C0-66F0-408F-8BA2-CBFBDDD4FC07}" 6 | ProjectSection(SolutionItems) = preProject 7 | README.md = README.md 8 | Makefile = Makefile 9 | src\AspnextTemplate.Api\Dockerfile = src\AspnextTemplate.Api\Dockerfile 10 | .editorconfig = .editorconfig 11 | infra\docker-compose-postgres.yaml = infra\docker-compose-postgres.yaml 12 | infra\docker-compose-zitadel.yaml = infra\docker-compose-zitadel.yaml 13 | infra\docker-compose-prometheus.yaml = infra\docker-compose-prometheus.yaml 14 | infra\docker-compose-jaeger.yaml = infra\docker-compose-jaeger.yaml 15 | infra\prometheus.yml = infra\prometheus.yml 16 | infra\docker-compose-grafana.yaml = infra\docker-compose-grafana.yaml 17 | infra\docker-compose-kafka.yaml = infra\docker-compose-kafka.yaml 18 | EndProjectSection 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspnextTemplate", "src\AspnextTemplate.Api\AspnextTemplate.Api.csproj", "{94618EED-2AEA-44A5-AC03-9A3B9AC0DBC4}" 21 | EndProject 22 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D3BD39A8-2835-4B2A-8E74-A3E59B387D36}" 23 | EndProject 24 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{CB4A4877-AA40-425D-A401-01441508E756}" 25 | EndProject 26 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{FBCC38CB-1EEE-40FD-AA02-FB26B23E7FE2}" 27 | EndProject 28 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastructure", "{3E0E9C11-D112-41DF-8029-57F996829E87}" 29 | EndProject 30 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspnextTemplate.Infrastructure.Zitadel", "src\Infrastructure\AspnextTemplate.Infrastructure.Zitadel\AspnextTemplate.Infrastructure.Zitadel.csproj", "{A142CFBD-9B0E-4B10-8A16-7404886A3DC3}" 31 | EndProject 32 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspnextTemplate.Domain", "src\AspnextTemplate.Domain\AspnextTemplate.Domain.csproj", "{61833C02-5273-4A5D-A7CC-1DD695D35475}" 33 | EndProject 34 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspnextTemplate.Infrastructure.Observability", "src\Infrastructure\AspnextTemplate.Infrastructure.Observability\AspnextTemplate.Infrastructure.Observability.csproj", "{2480637A-E46B-4338-995C-18574CD4118A}" 35 | EndProject 36 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspnextTemplate.Infrastructure.Data", "src\Infrastructure\AspnextTemplate.Infrastructure.Data\AspnextTemplate.Infrastructure.Data.csproj", "{8C82FB76-B16F-4E2D-8E6B-42501F282F8B}" 37 | EndProject 38 | Global 39 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 40 | Debug|Any CPU = Debug|Any CPU 41 | Release|Any CPU = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 47 | {94618EED-2AEA-44A5-AC03-9A3B9AC0DBC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 48 | {94618EED-2AEA-44A5-AC03-9A3B9AC0DBC4}.Debug|Any CPU.Build.0 = Debug|Any CPU 49 | {94618EED-2AEA-44A5-AC03-9A3B9AC0DBC4}.Release|Any CPU.ActiveCfg = Release|Any CPU 50 | {94618EED-2AEA-44A5-AC03-9A3B9AC0DBC4}.Release|Any CPU.Build.0 = Release|Any CPU 51 | {A142CFBD-9B0E-4B10-8A16-7404886A3DC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {A142CFBD-9B0E-4B10-8A16-7404886A3DC3}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {A142CFBD-9B0E-4B10-8A16-7404886A3DC3}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {A142CFBD-9B0E-4B10-8A16-7404886A3DC3}.Release|Any CPU.Build.0 = Release|Any CPU 55 | {61833C02-5273-4A5D-A7CC-1DD695D35475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 56 | {61833C02-5273-4A5D-A7CC-1DD695D35475}.Debug|Any CPU.Build.0 = Debug|Any CPU 57 | {61833C02-5273-4A5D-A7CC-1DD695D35475}.Release|Any CPU.ActiveCfg = Release|Any CPU 58 | {61833C02-5273-4A5D-A7CC-1DD695D35475}.Release|Any CPU.Build.0 = Release|Any CPU 59 | {2480637A-E46B-4338-995C-18574CD4118A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 60 | {2480637A-E46B-4338-995C-18574CD4118A}.Debug|Any CPU.Build.0 = Debug|Any CPU 61 | {2480637A-E46B-4338-995C-18574CD4118A}.Release|Any CPU.ActiveCfg = Release|Any CPU 62 | {2480637A-E46B-4338-995C-18574CD4118A}.Release|Any CPU.Build.0 = Release|Any CPU 63 | {8C82FB76-B16F-4E2D-8E6B-42501F282F8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 64 | {8C82FB76-B16F-4E2D-8E6B-42501F282F8B}.Debug|Any CPU.Build.0 = Debug|Any CPU 65 | {8C82FB76-B16F-4E2D-8E6B-42501F282F8B}.Release|Any CPU.ActiveCfg = Release|Any CPU 66 | {8C82FB76-B16F-4E2D-8E6B-42501F282F8B}.Release|Any CPU.Build.0 = Release|Any CPU 67 | EndGlobalSection 68 | GlobalSection(NestedProjects) = preSolution 69 | {94618EED-2AEA-44A5-AC03-9A3B9AC0DBC4} = {D3BD39A8-2835-4B2A-8E74-A3E59B387D36} 70 | {3E0E9C11-D112-41DF-8029-57F996829E87} = {D3BD39A8-2835-4B2A-8E74-A3E59B387D36} 71 | {A142CFBD-9B0E-4B10-8A16-7404886A3DC3} = {3E0E9C11-D112-41DF-8029-57F996829E87} 72 | {61833C02-5273-4A5D-A7CC-1DD695D35475} = {D3BD39A8-2835-4B2A-8E74-A3E59B387D36} 73 | {2480637A-E46B-4338-995C-18574CD4118A} = {3E0E9C11-D112-41DF-8029-57F996829E87} 74 | {8C82FB76-B16F-4E2D-8E6B-42501F282F8B} = {3E0E9C11-D112-41DF-8029-57F996829E87} 75 | EndGlobalSection 76 | EndGlobal 77 | -------------------------------------------------------------------------------- /src/template/Template/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | //#if (UsePostgreSql) 3 | DB_TASK = run_db 4 | //#endif 5 | HOME := $(shell echo $$HOME) 6 | PASSWORD := YOUR_PASSWORD # Replace with actual password 7 | 8 | .PHONY: init init_frontend init_backend init_db init_certs run_backend $(DB_TASK) run_frontend run_auth run \ 9 | run_tracing run_metrics run_grafana 10 | 11 | init_certs: 12 | @echo "Generate self-signed certificates" 13 | dotnet dev-certs https -ep $(HOME)/.aspnet/https/AspnextTemplate.pfx -p $(PASSWORD) 14 | dotnet dev-certs https --trust 15 | # openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost" 16 | 17 | //#if (UsePostgreSql) 18 | run_db: 19 | @echo "Run the database" 20 | docker compose --file infra/docker-compose-postgres.yaml up -d 21 | //#endif 22 | 23 | //#if (AddZitadelAuth) 24 | run_auth: 25 | @echo "Run Zitadel identity provider" 26 | docker compose --file infra/docker-compose-zitadel.yaml up -d 27 | //#endif 28 | 29 | //#if (AddObservability) 30 | run_tracing: 31 | docker compose --file infra/docker-compose-jaeger.yaml up -d 32 | 33 | run_metrics: 34 | docker compose --file infra/docker-compose-prometheus.yaml up -d 35 | 36 | run_grafana: 37 | docker compose --file infra/docker-compose-grafana.yaml up -d 38 | //#endif 39 | 40 | //#if (AddKafka) 41 | run_kafka: 42 | docker compose --file infra/docker-compose-kafka.yaml up -d 43 | //#endif 44 | -------------------------------------------------------------------------------- /src/template/Template/README.md: -------------------------------------------------------------------------------- 1 | # AspnextTemplate Project 2 | 3 | ## Develop 4 | 5 | --- 6 | 7 | ### Stack 8 | 9 | Backend: 10 | 11 | - .NET 8 12 | - ASP.NET Core 13 | - Entity Framework 14 | - Docker 15 | - Swagger 16 | 17 | - EF PostgreSql driver 18 | 19 | 20 | ### Prerequisites 21 | 22 | Before you start, make sure you have installed all of the following prerequisites on your development machine: 23 | 24 | - [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) 25 | - [Docker](https://www.docker.com/) 26 | - [Make]() 27 | 28 | ### Initialize Project 29 | 30 | Firslty, you need to initialise your project. It will create developemnt certificate, install all required packages and pull docker images. 31 | 32 | ```sh 33 | make init 34 | ``` 35 | 36 | --- 37 | 38 | ### Run 39 | 40 | Now, you can simply run your app commands in interactive mode: 41 | 42 | task/run to run all services (both frontend and backend) 43 | 44 | ```sh 45 | make run 46 | ``` 47 | 48 | ### Links 49 | 50 | Back-end Swagger docs: https://localhost:443/swagger 51 | 52 | 53 | Run PostgreSQL in docker: 54 | ```sh 55 | make run-db 56 | ``` 57 | 58 | PostgreSql: http://localhost:5432/ 59 | PdAdmin: https://localhost:5050 60 | 61 | To connect to PostgreSql from PgAdmin use the following credentials: 62 | 63 | - Login: postgres 64 | - Password: changeme 65 | 66 | (P.s если используешь PgViewer по localhost:5050 вместо DataGrip, то надо добавить сервер - через addServer: 67 | host: postgres, user: postgres, pass: changeme); 68 | 69 | 70 | 71 | --- 72 | 73 | 74 | Run Zitadel in docker: 75 | ```sh 76 | make run-auth 77 | ``` 78 | 79 | Local ui: http://localhost:8080/ui/login/login?authRequestID=253013912000193539 80 | 81 | - Login: zitadel-admin@zitadel.localhost 82 | - Pass: Password1! 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/template/Template/infra/docker-compose-grafana.yaml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | grafana: 5 | image: grafana/grafana 6 | environment: 7 | - GF_SECURITY_ADMIN_PASSWORD=admin 8 | restart: always 9 | ports: 10 | - 3000:3000 11 | volumes: 12 | - grafana-data:/var/lib/grafana 13 | networks: 14 | - localconnect 15 | 16 | volumes: 17 | grafana-data: {} 18 | 19 | networks: 20 | localconnect: 21 | 22 | -------------------------------------------------------------------------------- /src/template/Template/infra/docker-compose-jaeger.yaml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | # To run a specific version of Jaeger, use environment variable, e.g.: 4 | # JAEGER_VERSION=1.52 docker compose up 5 | 6 | services: 7 | jaeger: 8 | image: jaegertracing/all-in-one:${JAEGER_VERSION:-latest} 9 | ports: 10 | - "16686:16686" 11 | - "4318:4318" 12 | - 5775:5775/udp 13 | - 6831:6831/udp 14 | - 6832:6832/udp 15 | - 5778:5778 16 | - 16686:16686 17 | - 14250:14250 18 | - 14268:14268 19 | - 14269:14269 20 | - 4317:4317 21 | - 4318:4318 22 | - 9411:9411 23 | environment: 24 | - LOG_LEVEL=debug 25 | networks: 26 | - jaeger-example 27 | hotrod: 28 | image: jaegertracing/example-hotrod:${JAEGER_VERSION:-latest} 29 | # To run the latest trunk build, find the tag at Docker Hub and use the line below 30 | # https://hub.docker.com/r/jaegertracing/example-hotrod-snapshot/tags 31 | #image: jaegertracing/example-hotrod-snapshot:0ab8f2fcb12ff0d10830c1ee3bb52b745522db6c 32 | ports: 33 | - "8085:8085" 34 | - "8083:8083" 35 | command: ["all"] 36 | environment: 37 | - OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4318 38 | networks: 39 | - jaeger-example 40 | depends_on: 41 | - jaeger 42 | 43 | networks: 44 | jaeger-example: 45 | -------------------------------------------------------------------------------- /src/template/Template/infra/docker-compose-kafka.yaml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | zookeeper: 5 | image: confluentinc/cp-zookeeper:7.2.1 6 | hostname: zookeeper 7 | container_name: zookeeper 8 | ports: 9 | - "2181:2181" 10 | environment: 11 | ZOOKEEPER_CLIENT_PORT: 2181 12 | ZOOKEEPER_TICK_TIME: 2000 13 | 14 | kafka-ui: 15 | container_name: kafka-ui 16 | image: provectuslabs/kafka-ui:latest 17 | ports: 18 | - 8081:8080 19 | depends_on: 20 | - kafka 21 | environment: 22 | KAFKA_CLUSTERS_0_NAME: local 23 | KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092 24 | KAFKA_CLUSTERS_0_METRICS_PORT: 9997 25 | DYNAMIC_CONFIG_ENABLED: 'true' 26 | 27 | kafka: 28 | image: confluentinc/cp-server:7.2.1 29 | hostname: kafka 30 | container_name: kafka 31 | depends_on: 32 | - zookeeper 33 | ports: 34 | - "9092:9092" 35 | - "9997:9997" 36 | environment: 37 | KAFKA_BROKER_ID: 1 38 | KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' 39 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT 40 | KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 41 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 42 | KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 43 | KAFKA_CONFLUENT_LICENSE_TOPIC_REPLICATION_FACTOR: 1 44 | KAFKA_CONFLUENT_BALANCER_TOPIC_REPLICATION_FACTOR: 1 45 | KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 46 | KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 47 | KAFKA_JMX_PORT: 9997 48 | KAFKA_JMX_HOSTNAME: kafka 49 | 50 | kafka-init-topics: 51 | image: confluentinc/cp-kafka:7.2.1 52 | volumes: 53 | - ./data/message.json:/data/message.json 54 | depends_on: 55 | - kafka 56 | command: "bash -c 'echo Waiting for Kafka to be ready... && \ 57 | cub kafka-ready -b kafka:29092 1 30 && \ 58 | kafka-topics --create --topic AspnextTemplate-topic --partitions 3 --replication-factor 1 --if-not-exists --bootstrap-server kafka:29092'" 59 | -------------------------------------------------------------------------------- /src/template/Template/infra/docker-compose-postgres.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | postgres: 4 | image: postgres 5 | environment: 6 | POSTGRES_USER: ${POSTGRES_USER:-postgres} 7 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme} 8 | PGDATA: /data/postgres 9 | volumes: 10 | - postgres:/data/postgres 11 | ports: 12 | - "5432:5432" 13 | networks: 14 | - postgres 15 | restart: unless-stopped 16 | 17 | pgadmin: 18 | image: dpage/pgadmin4 19 | environment: 20 | PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.org} 21 | PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-admin} 22 | PGADMIN_CONFIG_SERVER_MODE: "False" 23 | volumes: 24 | - pgadmin:/var/lib/pgadmin 25 | ports: 26 | - "${PGADMIN_PORT:-5050}:80" 27 | networks: 28 | - postgres 29 | restart: unless-stopped 30 | 31 | networks: 32 | postgres: 33 | name: "postgres_db" 34 | driver: bridge 35 | 36 | volumes: 37 | postgres: 38 | pgadmin: 39 | -------------------------------------------------------------------------------- /src/template/Template/infra/docker-compose-prometheus.yaml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | prometheus: 5 | image: prom/prometheus 6 | restart: always 7 | ports: 8 | - 9090:9090 9 | volumes: 10 | - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro 11 | networks: 12 | - localconnect 13 | 14 | networks: 15 | localconnect: 16 | 17 | -------------------------------------------------------------------------------- /src/template/Template/infra/docker-compose-zitadel.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | zitadel: 5 | restart: 'always' 6 | networks: 7 | - 'zitadel' 8 | image: 'ghcr.io/zitadel/zitadel:latest' 9 | command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled' 10 | environment: 11 | - 'ZITADEL_DATABASE_COCKROACH_HOST=crdb' 12 | - 'ZITADEL_EXTERNALSECURE=false' 13 | depends_on: 14 | crdb: 15 | condition: 'service_healthy' 16 | ports: 17 | - '8080:8080' 18 | 19 | crdb: 20 | restart: 'always' 21 | networks: 22 | - 'zitadel' 23 | image: 'cockroachdb/cockroach:latest' 24 | command: 'start-single-node --insecure' 25 | healthcheck: 26 | test: ["CMD", "curl", "-f", "http://localhost:8080/health?ready=1"] 27 | interval: '10s' 28 | timeout: '30s' 29 | retries: 5 30 | start_period: '20s' 31 | ports: 32 | - '9090:8080' 33 | - '26257:26257' 34 | 35 | networks: 36 | zitadel: 37 | -------------------------------------------------------------------------------- /src/template/Template/infra/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 10s # By default, scrape targets every 5 seconds. 3 | 4 | # Attach these labels to any time series or alerts when communicating with 5 | # external systems (federation, remote storage, Alertmanager). 6 | # external_labels: 7 | # monitor: 'nats-openrmf-server' 8 | 9 | # A scrape configuration containing exactly one endpoint to scrape: 10 | scrape_configs: 11 | # The job name is added as a label `job=` to any timeseries scraped from this config. 12 | - job_name: 'localhost-read-prometheus' 13 | # metrics_path defaults to '/metrics' 14 | static_configs: 15 | - targets: ['host.docker.internal:5214'] 16 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Api/AspnextTemplate.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | Linux 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Api/Controllers/ExampleController.cs: -------------------------------------------------------------------------------- 1 | #if (AddZitadelAuth) 2 | using System.Security.Claims; 3 | using AspnextTemplate.Infrastructure.Zitadel; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Zitadel.Authentication; 6 | using System.Security.Claims; 7 | #endif 8 | using Microsoft.AspNetCore.Mvc; 9 | #if (AddObservability) 10 | using AspnextTemplate.Domain.Observability; 11 | using OpenTelemetry.Trace; 12 | #endif 13 | 14 | namespace AspnextTemplate.Api.Controllers; 15 | 16 | public record ExampleUserDto 17 | { 18 | public string Name { get; init; } 19 | public int Age { get; init; } 20 | public DateTime DateOfBirth { get; init; } 21 | } 22 | 23 | [ApiController] 24 | [Route("[controller]")] 25 | public class ExampleController : ControllerBase 26 | { 27 | private static readonly string[] Names = { "John", "Albert", "Mark " }; 28 | 29 | private readonly ILogger _logger; 30 | #if (AddObservability) 31 | private readonly Tracer _tracer; 32 | private readonly IMetricsProvider _metricsProvider; 33 | #endif 34 | 35 | // In this controller we're using service provider just for convinience and 36 | // ease of template development 37 | // In real controllers, inject interfaces directly. 38 | public ExampleController(IServiceProvider serviceProvider) 39 | { 40 | _logger = serviceProvider.GetService>() ?? throw new ArgumentNullException(); 41 | #if (AddObservability) 42 | _tracer = serviceProvider.GetService() ?? throw new ArgumentNullException(); 43 | _metricsProvider = serviceProvider.GetService() ?? throw new ArgumentNullException(); 44 | #endif 45 | } 46 | 47 | // Example of synchronous Http.Get request pipeline with users/{userId} route 48 | [HttpGet("users/{userId}")] 49 | public ActionResult> GetUser(int userId) 50 | { 51 | // default OK function 52 | return Ok(Enumerable.Range(1, 5).Select(index => new ExampleUserDto 53 | { 54 | Age = Random.Shared.Next(0, 55), 55 | DateOfBirth = DateTime.Now.AddDays(index), 56 | Name = Names[Random.Shared.Next(Names.Length)] 57 | }) 58 | .ToArray()); 59 | } 60 | 61 | // Example of asynchronous Http.Post request pipeline with body params users/{userId} route and IActionResult 62 | [HttpPost("users/{userId}")] 63 | public async Task UpdateUser([FromBody] ExampleUserDto userDto) // [FromBody] attribute allows body http params 64 | { 65 | await Task.Delay(1000); // waits for 1 second, async C# example 66 | 67 | if (userDto is null) 68 | return BadRequest(); // predefined status codes 69 | 70 | // custom status code returns with data 71 | return StatusCode(StatusCodes.Status200OK, new { Value1 = true, Value2 = "Yay!"}); 72 | } 73 | 74 | #if (AddZitadelAuth) 75 | #region Zitadel 76 | 77 | // Endpoint without auth 78 | [HttpPost("non-authorize")] 79 | public object NonAuthorize() => Result(); 80 | 81 | // Goes to Introspect endpoint of Zitadel to validate token 82 | [HttpPost("introspect/valid")] 83 | [Authorize(AuthenticationSchemes = AuthConstants.Schema)] 84 | public object IntrospectValidToken() => Result(); 85 | 86 | // Authorization by custom PolicyName 87 | // For this example, Role should be exact name to be passed 88 | [HttpPost("introspect/requires-role")] 89 | [Authorize(Policy = AuthConstants.SomePolicyName)] 90 | public object IntrospectRequiresRole() => Result(); 91 | 92 | private object Result() => new 93 | { 94 | Ping = "Pong", 95 | Timestamp = DateTime.Now, 96 | AuthType = User.Identity?.AuthenticationType, 97 | UserName = User.Identity?.Name, 98 | UserId = User.FindFirstValue(OidcClaimTypes.Subject), 99 | Claims = User.Claims.Select(c => new { c.Type, c.Value }).ToList(), 100 | IsInAdminRole = User.IsInRole("Admin"), 101 | IsInUserRole = User.IsInRole("User"), 102 | InChargeRole = User.IsInRole("charge"), 103 | }; 104 | 105 | #endregion 106 | #endif 107 | 108 | #if (AddObservability) 109 | // Showcase of tracing and metrics in action 110 | [HttpPost("observe")] 111 | public object ObserveAndTrace() 112 | { 113 | using var span = _tracer.StartActiveSpan("Observe-Parent"); 114 | 115 | using (var child1 = _tracer.StartActiveSpan("child1")) 116 | { 117 | child1.SetAttribute("test", "some value"); 118 | _logger.LogInformation("child1 trace information"); 119 | } 120 | 121 | using (var child2 = _tracer.StartActiveSpan("child2")) 122 | { 123 | child2.SetAttribute("test", "another value"); 124 | _logger.LogInformation("child2 trace information"); 125 | } 126 | 127 | _metricsProvider.IncTestMetric(12345); 128 | 129 | return Ok(); 130 | } 131 | #endif 132 | } 133 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:8.0-bullseye-slim AS base 2 | WORKDIR /app 3 | EXPOSE 80 4 | EXPOSE 443 5 | 6 | FROM mcr.microsoft.com/dotnet/sdk:8.0-bullseye-slim AS build 7 | WORKDIR /src 8 | COPY ["AspnextTemplate.csproj", "AspnextTemplate/"] 9 | RUN dotnet restore "AspnextTemplate/AspnextTemplate.csproj" 10 | COPY . ./AspnextTemplate 11 | WORKDIR "/src/AspnextTemplate" 12 | RUN dotnet build "AspnextTemplate.csproj" -c Release -o /app/build 13 | 14 | FROM build AS publish 15 | RUN dotnet publish "AspnextTemplate.csproj" -c Release -o /app/publish 16 | 17 | FROM base AS final 18 | WORKDIR /app 19 | COPY --from=publish /app/publish . 20 | ENTRYPOINT ["dotnet", "AspnextTemplate.dll"] 21 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Api/Extensions/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.OpenApi.Models; 2 | 3 | namespace AspnextTemplate.Api.Extensions; 4 | 5 | public static class ServiceCollectionExtensions 6 | { 7 | public static IServiceCollection AddSwaggerSetup(this IServiceCollection services) 8 | { 9 | services.AddSwaggerGen(c => 10 | { 11 | c.SwaggerDoc("v1", new OpenApiInfo { Title = "AspnextTemplate", Version = "v1" }); 12 | 13 | #if (AddZitadelAuth) 14 | c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme 15 | { 16 | Description = "Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", 17 | Name = "Authorization", 18 | In = ParameterLocation.Header, 19 | Type = SecuritySchemeType.Http, 20 | Scheme = "bearer", 21 | BearerFormat = "Access Token (PAN or JWT)" 22 | }); 23 | 24 | c.AddSecurityRequirement(new OpenApiSecurityRequirement 25 | { 26 | { 27 | new OpenApiSecurityScheme 28 | { 29 | Reference = new OpenApiReference 30 | { 31 | Type = ReferenceType.SecurityScheme, 32 | Id = "Bearer" 33 | } 34 | }, 35 | Array.Empty() 36 | } 37 | }); 38 | #endif 39 | }); 40 | 41 | services.AddEndpointsApiExplorer(); 42 | 43 | return services; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using AspnextTemplate.Api.Extensions; 2 | using AspnextTemplate.Infrastructure.Observability; 3 | #if (AddZitadelAuth) 4 | using AspnextTemplate.Infrastructure.Zitadel; 5 | #endif 6 | #if (UsePostgreSql) 7 | using Microsoft.EntityFrameworkCore; 8 | using AspnextTemplate.Infrastructure.Data.Repositories; 9 | #endif 10 | 11 | var builder = WebApplication.CreateBuilder(args); 12 | 13 | // Add services to the container. 14 | builder.Services.AddControllers(); 15 | 16 | // Add custom swagger extension method 17 | builder.Services.AddSwaggerSetup(); 18 | #if (AddZitadelAuth) 19 | 20 | // Add custom zitadel authentication 21 | builder.Services.AddZitadelAuthentication(builder.Configuration); 22 | #endif 23 | #if (AddObservability) 24 | 25 | // Add custom observability 26 | builder.Services.AddObservability(new ObservabilityOptions( 27 | "your_env", 28 | "AspnextTemplate", 29 | "AspnextTemplate")); 30 | #endif 31 | #if (UsePostgreSql) 32 | 33 | builder.Services.AddDbContext( 34 | options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); 35 | #endif 36 | 37 | var app = builder.Build(); 38 | 39 | // Configure the HTTP request pipeline. 40 | if (app.Environment.IsDevelopment()) 41 | { 42 | app.UseSwagger(); 43 | app.UseSwaggerUI(); 44 | } 45 | 46 | app.UseHttpsRedirection(); 47 | 48 | app.UseAuthorization(); 49 | app.MapControllers(); 50 | 51 | app.Run(); 52 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:47166", 8 | "sslPort": 44370 9 | } 10 | }, 11 | "profiles": { 12 | "AspnextTemplate": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "https://localhost:7214;http://localhost:5214", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "IIS Express": { 23 | "commandName": "IISExpress", 24 | "launchBrowser": true, 25 | "launchUrl": "swagger", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | //#if (AddZitadelAuth) 9 | "ZitadelConfiguration": { 10 | "ClientId": "", 11 | "ClientSecret": "", 12 | "ZitadelHostUrl": "http://localhost:8080/" 13 | }, 14 | //#endif (AddZitadelAuth) 15 | //#if (AddKafka) 16 | "Kafka": { 17 | "BootstrapServers": "localhost:9092" 18 | }, 19 | //#endif (AddKafka) 20 | "ConnectionStrings": { 21 | "DefaultConnection": "Host=postgres;User ID=postgres;Password=changeme;Port=5432;Database=postgres" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | //#if (AddZitadelAuth) 10 | "ZitadelConfiguration": { 11 | "ClientId": "", 12 | "ClientSecret": "", 13 | "ZitadelHostUrl": "" 14 | }, 15 | //#endif 16 | "ConnectionStrings": { 17 | "DefaultConnection": "Host=postgres;User ID=postgres;Password=changeme;Port=5432;Database=postgres" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Domain/AspnextTemplate.Domain.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Domain/Notification/IExampleConsumer.cs: -------------------------------------------------------------------------------- 1 | namespace AspnextTemplate.Domain.Notification; 2 | 3 | public interface IExampleConsumer 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Domain/Notification/IExampleProducer.cs: -------------------------------------------------------------------------------- 1 | namespace AspnextTemplate.Domain.Producers; 2 | 3 | public interface IExampleProducer 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/template/Template/src/AspnextTemplate.Domain/Observability/IMetricsProvider.cs: -------------------------------------------------------------------------------- 1 | namespace AspnextTemplate.Domain.Observability; 2 | 3 | public interface IMetricsProvider 4 | { 5 | void IncTestMetric(long metricLabel); 6 | } 7 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Data/AspnextTemplate.Infrastructure.Data.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Data/Kafka/Configuration/ExampleProduderConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace AspnextTemplate.Infrastructure.Data.Kafka.Configuration; 2 | 3 | public class ExampleProducerConfiguration 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Data/Kafka/Consumers/ExampleConsumer.cs: -------------------------------------------------------------------------------- 1 | using AspnextTemplate.Domain.Notification; 2 | 3 | namespace AspnextTemplate.Infrastructure.Data.Kafka.Consumers; 4 | 5 | public class ExampleConsumer : IExampleConsumer 6 | { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Data/Kafka/Producers/ExampleProducer.cs: -------------------------------------------------------------------------------- 1 | using AspnextTemplate.Domain.Producers; 2 | using Confluent.Kafka; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace AspnextTemplate.Infrastructure.Data.Kafka.Producers; 7 | 8 | public class ExampleProducer : IExampleProducer 9 | { 10 | private readonly IConfiguration _configuration; 11 | private readonly IProducer _producer; 12 | 13 | public ExampleProducer(IConfiguration configuration) 14 | { 15 | _configuration = configuration; 16 | 17 | var producerconfig = new ProducerConfig 18 | { 19 | BootstrapServers = _configuration["Kafka:BootstrapServers"] 20 | }; 21 | 22 | _producer = new ProducerBuilder(producerconfig).Build(); 23 | } 24 | 25 | public Task Finish(CancellationToken cancellationToken) 26 | { 27 | // some producing logic 28 | return Task.CompletedTask; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Data/Repositories/AspnextTemplateDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace AspnextTemplate.Infrastructure.Data.Repositories; 4 | 5 | public sealed class AspnextTemplateDbContext : DbContext 6 | { 7 | public AspnextTemplateDbContext(DbContextOptions options) : base(options) 8 | { 9 | 10 | } 11 | 12 | protected override void OnModelCreating(ModelBuilder modelBuilder) 13 | { 14 | base.OnModelCreating(modelBuilder); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Observability/AspnextTemplate.Infrastructure.Observability.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Observability/MetricsProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Diagnostics.Metrics; 3 | using AspnextTemplate.Domain.Observability; 4 | 5 | namespace AspnextTemplate.Infrastructure.Observability; 6 | 7 | public class MetricsProvider : IMetricsProvider 8 | { 9 | private readonly Counter _testMetricCounter; 10 | 11 | public MetricsProvider(IMeterFactory meterFactory) 12 | { 13 | var meter = meterFactory.Create(MetricsConstants.AppMeterName); 14 | _testMetricCounter = meter.CreateCounter("AspnextTemplate_test_counter"); 15 | } 16 | 17 | public void IncTestMetric(long metricLabel) 18 | { 19 | _testMetricCounter.Add(1, new TagList 20 | { 21 | new("test_label", metricLabel), 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Observability/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AspnextTemplate.Domain.Observability; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using OpenTelemetry; 5 | using OpenTelemetry.Metrics; 6 | using OpenTelemetry.Resources; 7 | using OpenTelemetry.Trace; 8 | 9 | namespace AspnextTemplate.Infrastructure.Observability; 10 | 11 | public static class MetricsConstants 12 | { 13 | public const string AppMeterName = "AspnextTemplate.Meter"; 14 | } 15 | 16 | public record ObservabilityOptions( 17 | string Environment, 18 | string ServiceNamespace, 19 | string ServiceName, 20 | string OtlpEndpoint = "http://localhost:4317"); 21 | 22 | public static class ServiceCollectionExtensions 23 | { 24 | public static OpenTelemetryBuilder AddObservability(this IServiceCollection services, ObservabilityOptions options) 25 | { 26 | var serviceVersion = Assembly.GetEntryAssembly()?.GetName().Version?.ToString(); 27 | 28 | services.AddSingleton(); 29 | services.AddSingleton(TracerProvider.Default.GetTracer(options.ServiceName)); 30 | 31 | return services.AddOpenTelemetry() 32 | .ConfigureResource(resource => resource.AddService( 33 | serviceName: options.ServiceName, 34 | serviceNamespace: options.ServiceNamespace, 35 | serviceVersion: serviceVersion, 36 | serviceInstanceId: Environment.MachineName 37 | ).AddAttributes(new Dictionary 38 | { 39 | { "deployment.environment", options.Environment } 40 | })) 41 | .WithTracing(tracing => tracing 42 | .AddSource(options.ServiceName) 43 | .SetResourceBuilder( 44 | ResourceBuilder.CreateDefault() 45 | .AddService(serviceName: options.ServiceName, serviceVersion: serviceVersion)) 46 | .AddAspNetCoreInstrumentation() 47 | .AddOtlpExporter(opts => 48 | { 49 | opts.Endpoint = new Uri(options.OtlpEndpoint); 50 | })) 51 | .WithMetrics(metrics => metrics.AddAspNetCoreInstrumentation() 52 | .AddRuntimeInstrumentation() 53 | .AddMeter(MetricsConstants.AppMeterName) 54 | .AddPrometheusExporter() 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Zitadel/AspnextTemplate.Infrastructure.Zitadel.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Zitadel/AuthConstants.cs: -------------------------------------------------------------------------------- 1 | namespace AspnextTemplate.Infrastructure.Zitadel; 2 | 3 | public static class AuthConstants 4 | { 5 | public const string Schema = "ZitadelIntrospect"; 6 | 7 | public const string SomePolicyName = "ZitadelRolePolicy"; 8 | } 9 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Zitadel/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Zitadel.Extensions; 5 | 6 | namespace AspnextTemplate.Infrastructure.Zitadel; 7 | 8 | public static class ServiceCollectionExtensions 9 | { 10 | public static IServiceCollection AddZitadelAuthentication(this IServiceCollection services, IConfiguration configuration) 11 | { 12 | var authConfig = configuration.GetSection(nameof(ZitadelConfiguration)).Get(); 13 | 14 | if (authConfig is null) 15 | { 16 | throw new ApplicationException("Auth configuration cannot be null: " + 17 | "Setup ZitadelConfiguration section with required data"); 18 | } 19 | 20 | services.AddSingleton(); 21 | 22 | services 23 | .AddAuthorization(options => 24 | { 25 | options.AddPolicy("ZitadelRolePolicy", policy => 26 | policy.Requirements.Add(new HasZitadelRoleRequirement("test"))); 27 | }) 28 | .AddAuthentication(o => { }) 29 | .AddZitadelIntrospection( 30 | AuthConstants.Schema, 31 | o => 32 | { 33 | o.Authority = authConfig.ZitadelHostUrl; 34 | o.ClientId = authConfig.ClientId; 35 | o.ClientSecret = authConfig.ClientSecret; 36 | o.EnableCaching = false; 37 | o.Validate(); 38 | }); 39 | 40 | return services; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Zitadel/ZitadelConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace AspnextTemplate.Infrastructure.Zitadel; 2 | 3 | public class ZitadelConfiguration 4 | { 5 | public string ClientId { get; init; } = null!; 6 | 7 | public string ClientSecret { get; init; } = null!; 8 | 9 | public string ZitadelHostUrl { get; init; } = null!; 10 | } 11 | -------------------------------------------------------------------------------- /src/template/Template/src/Infrastructure/AspnextTemplate.Infrastructure.Zitadel/ZitadelRoleHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using Microsoft.AspNetCore.Authorization; 3 | 4 | namespace AspnextTemplate.Infrastructure.Zitadel; 5 | 6 | public class HasZitadelRoleRequirement : IAuthorizationRequirement 7 | { 8 | public string Role { get; } 9 | 10 | public HasZitadelRoleRequirement(string role) 11 | { 12 | Role = role; 13 | } 14 | } 15 | 16 | public class ZitadelRoleHandler : AuthorizationHandler 17 | { 18 | protected override Task HandleRequirementAsync( 19 | AuthorizationHandlerContext context, 20 | HasZitadelRoleRequirement requirement) 21 | { 22 | var rolesClaim = context.User.Claims.FirstOrDefault(c => c.Type == "urn:zitadel:iam:org:project:roles"); 23 | if (rolesClaim != null) 24 | { 25 | var rolesData = JsonSerializer.Deserialize>(rolesClaim.Value); 26 | if (rolesData?.ContainsKey(requirement.Role) ?? false) 27 | { 28 | context.Succeed(requirement); 29 | } 30 | } 31 | 32 | return Task.CompletedTask; 33 | } 34 | } 35 | --------------------------------------------------------------------------------