├── .editorconfig
├── .gitattributes
├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FUNDING.yml
└── workflows
│ ├── ci.yml
│ ├── pull_request.yml
│ └── release.yml
├── .gitignore
├── LICENSE.txt
├── README.md
├── SimpleHosting.sln
├── coverlet.runsettings
├── global.json
├── icon.jpg
└── src
├── WorldDomination.SimpleHosting.SampleHostedServiceApplication
├── CustomHostedService.cs
├── HostedService1.cs
├── HostedService2.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
├── WorldDomination.SimpleHosting.SampleHostedServiceApplication.csproj
├── appsettings.Development.json
└── appsettings.json
├── WorldDomination.SimpleHosting.SampleWebApplication.Tests
├── CustomWebApplicationFactory.cs
├── WeatherForecastControllerTests
│ └── GetTests.cs
└── WorldDomination.SimpleHosting.SampleWebApplication.Tests.csproj
├── WorldDomination.SimpleHosting.SampleWebApplication
├── Controllers
│ └── WeatherForecastController.cs
├── CustomHostedService.cs
├── HostedBackgroundService.cs
├── HostedService1.cs
├── HostedService2.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Services
│ ├── IWeatherService.cs
│ └── WeatherService.cs
├── Startup.cs
├── WeatherForecast.cs
├── WorldDomination.SimpleHosting.SampleWebApplication.csproj
├── appsettings.Development.json
└── appsettings.json
└── WorldDomination.SimpleHosting
├── MainOptions.cs
├── Program.cs
├── Properties
└── launchSettings.json
└── WorldDomination.SimpleHosting.csproj
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome:
2 | http://EditorConfig.org
3 |
4 |
5 | #### How to manually clean up code in an IDE?
6 |
7 | #### - Visual Studio: CTRL + K + D
8 | #### - VSCode: SHIFT + ALT + F
9 |
10 |
11 |
12 | ####################################################################################################
13 |
14 | ### VS Settings Reference: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
15 |
16 |
17 |
18 |
19 | # top-most EditorConfig file
20 | root = true
21 |
22 | # Default settings:
23 | # A newline ending every file
24 | # Use 4 spaces as indentation
25 | [*]
26 | insert_final_newline = true
27 | indent_style = space
28 | indent_size = 4
29 | end_of_line = crlf
30 | charset = utf-8
31 | trim_trailing_whitespace = true
32 |
33 | # C# files
34 | [*.cs]
35 | # New line preferences
36 | csharp_new_line_before_open_brace = all
37 | csharp_new_line_before_else = true
38 | csharp_new_line_before_catch = true
39 | csharp_new_line_before_finally = true
40 | csharp_new_line_before_members_in_object_initializers = true
41 | csharp_new_line_before_members_in_anonymous_types = true
42 | csharp_new_line_between_query_expression_clauses = true
43 |
44 | # Indentation preferences
45 | csharp_indent_block_contents = true
46 | csharp_indent_braces = false
47 | csharp_indent_case_contents = true
48 | csharp_indent_switch_labels = true
49 | csharp_indent_labels = one_less_than_current
50 |
51 | # avoid this. unless absolutely necessary
52 | dotnet_style_qualification_for_field = false:suggestion
53 | dotnet_style_qualification_for_property = false:suggestion
54 | dotnet_style_qualification_for_method = false:suggestion
55 | dotnet_style_qualification_for_event = false:suggestion
56 |
57 | # only use var when it's obvious what the variable type is
58 | csharp_style_var_for_built_in_types = true:suggestion
59 | csharp_style_var_when_type_is_apparent = true:suggestion
60 | csharp_style_var_elsewhere = true:suggestion
61 |
62 | # use language keywords instead of BCL types
63 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
64 | dotnet_style_predefined_type_for_member_access = true:suggestion
65 |
66 | # name all constant fields using PascalCase
67 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
68 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
69 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
70 |
71 | dotnet_naming_symbols.constant_fields.applicable_kinds = field
72 | dotnet_naming_symbols.constant_fields.required_modifiers = const
73 |
74 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case
75 |
76 | # internal and private fields should be _camelCase
77 | dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
78 | dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
79 | dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
80 |
81 | dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
82 | dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
83 |
84 | dotnet_naming_style.camel_case_underscore_style.required_prefix = _
85 | dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
86 |
87 | # Code style defaults
88 | dotnet_sort_system_directives_first = true
89 | csharp_preserve_single_line_blocks = true
90 | csharp_preserve_single_line_statements = false
91 |
92 | # Expression-level preferences
93 | dotnet_style_object_initializer = true:suggestion
94 | dotnet_style_collection_initializer = true:suggestion
95 | dotnet_style_explicit_tuple_names = true:suggestion
96 | dotnet_style_coalesce_expression = true:suggestion
97 | dotnet_style_null_propagation = true:suggestion
98 |
99 | # Expression-bodied members
100 | csharp_style_expression_bodied_methods = false:none
101 | csharp_style_expression_bodied_constructors = false:none
102 | csharp_style_expression_bodied_operators = false:none
103 | csharp_style_expression_bodied_properties = true:none
104 | csharp_style_expression_bodied_indexers = true:none
105 | csharp_style_expression_bodied_accessors = true:none
106 |
107 | # Pattern matching
108 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
109 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
110 | csharp_style_inlined_variable_declaration = true:suggestion
111 |
112 | # Null checking preferences
113 | csharp_style_throw_expression = true:suggestion
114 | csharp_style_conditional_delegate_call = true:suggestion
115 |
116 | # Space preferences
117 | csharp_space_after_cast = false
118 | csharp_space_after_colon_in_inheritance_clause = true
119 | csharp_space_after_comma = true
120 | csharp_space_after_dot = false
121 | csharp_space_after_keywords_in_control_flow_statements = true
122 | csharp_space_after_semicolon_in_for_statement = true
123 | csharp_space_around_binary_operators = before_and_after
124 | csharp_space_around_declaration_statements = do_not_ignore
125 | csharp_space_before_colon_in_inheritance_clause = true
126 | csharp_space_before_comma = false
127 | csharp_space_before_dot = false
128 | csharp_space_before_open_square_brackets = false
129 | csharp_space_before_semicolon_in_for_statement = false
130 | csharp_space_between_empty_square_brackets = false
131 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
132 | csharp_space_between_method_call_name_and_opening_parenthesis = false
133 | csharp_space_between_method_call_parameter_list_parentheses = false
134 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
135 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
136 | csharp_space_between_method_declaration_parameter_list_parentheses = false
137 | csharp_space_between_parentheses = false
138 | csharp_space_between_square_brackets = false
139 |
140 | [*.{asm,inc}]
141 | indent_size = 8
142 |
143 | # Xml project files
144 | [*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
145 | indent_size = 2
146 |
147 | # Xml config files
148 | [*.{props,targets,config,nuspec}]
149 | indent_size = 2
150 |
151 | [CMakeLists.txt]
152 | indent_size = 2
153 |
154 | [*.cmd]
155 | indent_size = 2
156 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * -text
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at help@world-domination.com.au. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | One of the easiest ways to contribute is to participate in discussions and discuss issues. You can also contribute by submitting pull requests with code changes.
4 |
5 | ## Filing issues
6 | - Don't be afraid to ask any question about the project, including suggestions to change how things currently are.
7 | - Keep the conversation polite and respectful. This way, all parties will take an interest in your question and will be more proactive into helping.
8 | - For bugs, the best way to get your bug fixed is to be as detailed as you can be about the problem. Providing a minimal project with steps to reproduce the problem is ideal. Even though this might be frustrating, it can speed up the resolution to the problem.
9 |
10 | Helpful tip: GitHub supports [markdown](https://help.github.com/articles/github-flavored-markdown/), so when filing bugs make sure you check the formatting before clicking submit.
11 |
12 | ## Contributing code and content
13 |
14 | **Identifying the scale**
15 |
16 | If you would like to contribute to the project, first identify the "scale" of what you would like to contribute. If it is small (grammar/spelling or a bug fix) feel free to start working on a fix. If you are submitting a feature or substantial code contribution, please discuss it with the team, via an Issue.
17 |
18 | You might also read these two blogs posts on contributing code: [Open Source Contribution Etiquette](http://tirania.org/blog/archive/2010/Dec-31.html) by Miguel de Icaza and [Don't "Push" Your Pull Requests](https://www.igvita.com/2011/12/19/dont-push-your-pull-requests/) by Ilya Grigorik. Note that all code submissions will be reviewed and tested by team members. Of course (where appropriate), tests will be required.
19 |
20 | **Obtaining the source code**
21 |
22 | If you are an outside contributer, please fork the repository to your own GitHub account. See the GitHub documentation for [forking a repo](https://help.github.com/articles/fork-a-repo/) if you have any questions about this.
23 |
24 | **Submitting a Pull Request**
25 |
26 | If you don't know what a Pull Request is read then please read the article [Using Pull Requests](https://help.github.com/articles/using-pull-requests) to get up-to-speed. Make sure the respository can build and all tests pass. Familiarize yourself with the project workflow and our coding conventions.
27 |
28 | Pull Requests should all be done to the `master` branch.
29 |
30 | **Commit/Pull Request Format**
31 |
32 | ```
33 | Summary of the changes (Less than 80 chars)
34 | - Detail 1
35 | - Detail 2
36 |
37 | Addresses #bugnumber (in this specific format)
38 | ```
39 |
40 | **Tests**
41 |
42 | - Tests need to be provided for every bug/feature that is completed.
43 | - Tests only need to be present for issues that need to be verified by QA (e.g. not tasks)
44 | - If there is a scenario that is far _too hard*_ to test there does not need to be a test for it.
45 |
46 |
47 | *"_Too hard_" is determined by the team as a whole.
48 |
49 | ---
50 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: PureKrome
2 | custom: ['https://paypal.me/purekrome']
3 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | paths-ignore:
7 | - 'ReadMe.md'
8 |
9 | permissions:
10 | packages: write
11 |
12 | env:
13 | DOTNET_NOLOGO: true
14 |
15 | jobs:
16 | build:
17 | runs-on: ubuntu-latest
18 |
19 | steps:
20 | - name: Checkout repository
21 | uses: actions/checkout@v3
22 |
23 | - name: Build version suffix
24 | run: echo "VERSION_SUFFIX=beta.${{ github.run_number }}" >> $GITHUB_ENV
25 |
26 | - name: Setup .NET
27 | uses: actions/setup-dotnet@v3
28 |
29 | - run: dotnet restore --verbosity minimal
30 |
31 | - run: dotnet build --configuration Release /p:ContinuousIntegrationBuild=true
32 |
33 | - run: dotnet test --configuration Release --no-build
34 |
35 | - run: dotnet pack --configuration Release --no-build --output ./artifacts --version-suffix $VERSION_SUFFIX
36 |
37 | - name: Publish artifacts
38 | uses: actions/upload-artifact@v3
39 | with:
40 | name: WorldDomination.SimpleHosting.1.0.0-${{ env.VERSION_SUFFIX }}
41 | path: ./artifacts/
42 |
43 | - name: List contents of the Artifacts directory
44 | run: ls -al ./artifacts
45 |
46 | - name: Publish to GPR
47 | run: |
48 | dotnet nuget push "./artifacts/*.nupkg" \
49 | --no-symbols \
50 | --api-key ${{ secrets.GITHUB_TOKEN }} \
51 | --source https://nuget.pkg.github.com/${{ github.repository_owner }}
52 |
53 | test:
54 | runs-on: ubuntu-latest
55 |
56 | steps:
57 | - name: Checkout repo
58 | uses: actions/checkout@v3
59 |
60 | - name: Setup .NET
61 | uses: actions/setup-dotnet@v3
62 |
63 | - run: dotnet restore --verbosity minimal
64 |
65 | - run: dotnet build --configuration Debug
66 |
67 | - run: dotnet test --configuration Debug --verbosity minimal --no-build --collect:"XPlat Code Coverage" --results-directory "./.codecoverage"
68 |
69 | - name: Code coverage
70 | uses: codecov/codecov-action@v3
71 | with:
72 | token: "${{ secrets.CODECOV_TOKEN }}"
73 | directory: "./.codecoverage"
74 | fail_ci_if_error: true
75 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request.yml:
--------------------------------------------------------------------------------
1 | name: Pull Request
2 |
3 | on:
4 | pull_request:
5 | paths-ignore:
6 | - 'ReadMe.md'
7 |
8 | env:
9 | DOTNET_NOLOGO: true
10 |
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 |
15 | strategy:
16 | matrix:
17 | config:
18 | - debug
19 | - release
20 |
21 | steps:
22 | - name: Checkout repository
23 | uses: actions/checkout@v3
24 |
25 | - name: Build version suffix
26 | run: echo "VERSION_SUFFIX=alpha.${{ github.event.number }}" >> $GITHUB_ENV
27 |
28 | - name: Setup .NET
29 | uses: actions/setup-dotnet@v3
30 |
31 | - run: dotnet restore --verbosity minimal
32 |
33 | - run: dotnet build --configuration ${{ matrix.config }} /p:ContinuousIntegrationBuild=true
34 |
35 | - run: dotnet test --configuration ${{ matrix.config }} --no-build
36 | if: matrix.config == 'release'
37 |
38 | - run: dotnet test --configuration ${{ matrix.config }} --verbosity minimal --no-build --collect:"XPlat Code Coverage" --results-directory "./.codecoverage"
39 | if: matrix.config == 'debug'
40 |
41 | - run: dotnet pack --configuration ${{ matrix.config }} --no-build --output ./artifacts --version-suffix $VERSION_SUFFIX
42 | if: matrix.config == 'release'
43 |
44 | - name: Code coverage
45 | if: matrix.config == 'debug'
46 | uses: codecov/codecov-action@v3
47 | with:
48 | directory: "./.codecoverage"
49 | fail_ci_if_error: true
50 |
51 | - name: Publish artifacts
52 | if: matrix.config == 'release'
53 | uses: actions/upload-artifact@v3
54 | with:
55 | name: WorldDomination.SimpleHosting.1.0.0-${{ env.VERSION_SUFFIX }}
56 | path: ./artifacts/
57 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - "v*.*.*"
7 | - "*.*.*"
8 |
9 | permissions:
10 | contents: write
11 | packages: write
12 |
13 | env:
14 | DOTNET_NOLOGO: true
15 |
16 | jobs:
17 | build:
18 | runs-on: ubuntu-latest
19 |
20 | steps:
21 |
22 | - name: Calculate version from the Commit Tag
23 | run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
24 |
25 | - name: Checkout repository
26 | uses: actions/checkout@v3
27 |
28 | - name: Setup .NET
29 | uses: actions/setup-dotnet@v3
30 |
31 | - run: dotnet restore --verbosity minimal
32 |
33 | - run: dotnet build --configuration Release /p:ContinuousIntegrationBuild=true /p:version=${{ env.RELEASE_VERSION }}
34 |
35 | - run: dotnet pack --configuration Release --no-build --output ./artifacts /p:version=${{ env.RELEASE_VERSION }}
36 |
37 | - name: Publish artifacts
38 | uses: actions/upload-artifact@v3
39 | with:
40 | name: WorldDomination.SimpleHosting.${{ env.RELEASE_VERSION }}
41 | path: ./artifacts/
42 |
43 | - name: Upload release assets
44 | uses: softprops/action-gh-release@v1
45 | env:
46 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47 | with:
48 | files: ./artifacts/*
49 |
50 | - name: Publish to GPR
51 | run: |
52 | dotnet nuget push "./artifacts/*.nupkg" \
53 | --no-symbols \
54 | --api-key ${{ secrets.GITHUB_TOKEN }} \
55 | --source https://nuget.pkg.github.com/${{ github.repository_owner }}
56 |
57 | - name: Publish to nuget.org
58 | run: |
59 | dotnet nuget push "./artifacts/*.nupkg" \
60 | --api-key ${{ secrets.NUGET_TOKEN }} \
61 | --source https://api.nuget.org/v3/index.json
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.obj
2 | *.pdb
3 | *.user
4 | *.aps
5 | *.pch
6 | *.vspscc
7 | *.vssscc
8 | *_i.c
9 | *_p.c
10 | *.ncb
11 | *.suo
12 | *.tlb
13 | *.tlh
14 | *.bak
15 | *.cache
16 | *.ilk
17 | *.log
18 | *.lib
19 | *.sbr
20 | *.scc
21 | [Bb]in
22 | [Dd]ebug*/
23 | obj/
24 | [Rr]elease*/
25 | _ReSharper*/
26 | *.[Pp]ublish.xml
27 | *.resharper*
28 | AppData/
29 | App_Data/
30 | *.log.*
31 | [Ll]ogs/
32 | [Dd]ata/
33 | [Pp]ackages/
34 | [Tt]humbs.db
35 | [Tt]est[Rr]esult*
36 | [Bb]uild[Ll]og.*
37 | *.sln.DotSettings.*
38 | *.ncrunchproject
39 | *.ncrunchsolution
40 | *.nupkg
41 | *.vs
42 | *.vscode
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-2019 Homely.com.au (Original code I did, based from that)
4 |
5 | Copyright (c) 2020 Pure Krome
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Simple: Hosting
2 |
3 |
4 | Making it simple to customize Hosting for your ASP.NET Core 6.x+ application
5 |
6 |
7 |
8 |
9 |
19 |
20 | ## Key Points
21 |
22 | - :rocket: Reduces boilerplate ceremony for your `program.cs` file.
23 | - :white_check_mark: Sets up Serilog _around_ the entire application. (:wrench: Configure all settings via your `appsettings.json` file(s))
24 | - :white_check_mark: Simple to add some extra (helpful) log header/footer.
25 | - :white_check_mark: Can also add logging to your `Startup` class (new with ASP.NET Core 6+)
26 |
27 | In summary: this library makes is SIMPLE (by abstracting away most of the boring ceremony) to setup your ASP.NET Core application.
28 |
29 | ---
30 | ## Installation
31 |
32 | Package is available via NuGet.
33 |
34 | ```sh
35 | dotnet add package WorldDomination.SimpleHosting
36 | ```
37 |
38 | ---
39 | ## More Information:
40 |
41 | Basically, turn your `program.cs` into this :
42 |
43 | ```
44 | public static Task Main(string[] args)
45 | {
46 | return WorldDomination.SimpleHosting.Program.Main(args);
47 | }
48 | ```
49 |
50 | and you've now got some Serilog all wired up along with some nice application-wide error handling.
51 |
52 | For more custom settings:
53 |
54 | ```
55 | public static Task Main(string[] args)
56 | {
57 | // Every Option here is optional.
58 | // Set what you want.
59 | var options = new MainOptions
60 | {
61 | CommandLineArguments = args,
62 | FirstLoggingInformationMessage = "~~ Sample Web Application ~~",
63 | LogAssemblyInformation = true,
64 | LastLoggingInformationMessage = "-- Sample Web Application has ended/terminated --",
65 | StartupActivation = new System.Func((context, logger) => new Startup(context.Configuration, logger))
66 | };
67 |
68 | return SimpleHosting.Program.Main(options);
69 | }
70 | ```
71 |
72 | ---
73 |
74 | ## Contribute
75 | Yep - contributions are always welcome. Please read the contribution guidelines first.
76 |
77 | ## Code of Conduct
78 |
79 | If you wish to participate in this repository then you need to abide by the code of conduct.
80 |
81 | ## Feedback
82 |
83 | Yes! Please use the Issues section to provide feedback - either good or needs improvement :cool:
84 |
85 | ---
86 |
87 |
--------------------------------------------------------------------------------
/SimpleHosting.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 = 15.0.26124.0
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorldDomination.SimpleHosting", "src\WorldDomination.SimpleHosting\WorldDomination.SimpleHosting.csproj", "{112DA850-B52E-49B6-811D-73237C5A7792}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorldDomination.SimpleHosting.SampleWebApplication", "src\WorldDomination.SimpleHosting.SampleWebApplication\WorldDomination.SimpleHosting.SampleWebApplication.csproj", "{013F5235-D334-4770-82E4-350BA00F676C}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorldDomination.SimpleHosting.SampleWebApplication.Tests", "src\WorldDomination.SimpleHosting.SampleWebApplication.Tests\WorldDomination.SimpleHosting.SampleWebApplication.Tests.csproj", "{BB527810-A846-43A8-8AD8-A1C2B191C2AE}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{3F8381EE-2CFD-4533-8141-5C6EA41E3275}"
13 | ProjectSection(SolutionItems) = preProject
14 | .editorconfig = .editorconfig
15 | global.json = global.json
16 | README.md = README.md
17 | EndProjectSection
18 | EndProject
19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B77C557B-74CB-457F-AB66-B0BBCF93FA5C}"
20 | EndProject
21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorldDomination.SimpleHosting.SampleHostedServiceApplication", "src\WorldDomination.SimpleHosting.SampleHostedServiceApplication\WorldDomination.SimpleHosting.SampleHostedServiceApplication.csproj", "{F8A89E7A-90A2-454C-9982-67B359A55E22}"
22 | EndProject
23 | Global
24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
25 | Debug|Any CPU = Debug|Any CPU
26 | Release|Any CPU = Release|Any CPU
27 | EndGlobalSection
28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
29 | {112DA850-B52E-49B6-811D-73237C5A7792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {112DA850-B52E-49B6-811D-73237C5A7792}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {112DA850-B52E-49B6-811D-73237C5A7792}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {112DA850-B52E-49B6-811D-73237C5A7792}.Release|Any CPU.Build.0 = Release|Any CPU
33 | {013F5235-D334-4770-82E4-350BA00F676C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {013F5235-D334-4770-82E4-350BA00F676C}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {013F5235-D334-4770-82E4-350BA00F676C}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {013F5235-D334-4770-82E4-350BA00F676C}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {BB527810-A846-43A8-8AD8-A1C2B191C2AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {BB527810-A846-43A8-8AD8-A1C2B191C2AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {BB527810-A846-43A8-8AD8-A1C2B191C2AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {BB527810-A846-43A8-8AD8-A1C2B191C2AE}.Release|Any CPU.Build.0 = Release|Any CPU
41 | {F8A89E7A-90A2-454C-9982-67B359A55E22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {F8A89E7A-90A2-454C-9982-67B359A55E22}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {F8A89E7A-90A2-454C-9982-67B359A55E22}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {F8A89E7A-90A2-454C-9982-67B359A55E22}.Release|Any CPU.Build.0 = Release|Any CPU
45 | EndGlobalSection
46 | GlobalSection(SolutionProperties) = preSolution
47 | HideSolutionNode = FALSE
48 | EndGlobalSection
49 | GlobalSection(NestedProjects) = preSolution
50 | {112DA850-B52E-49B6-811D-73237C5A7792} = {B77C557B-74CB-457F-AB66-B0BBCF93FA5C}
51 | {013F5235-D334-4770-82E4-350BA00F676C} = {B77C557B-74CB-457F-AB66-B0BBCF93FA5C}
52 | {BB527810-A846-43A8-8AD8-A1C2B191C2AE} = {B77C557B-74CB-457F-AB66-B0BBCF93FA5C}
53 | {F8A89E7A-90A2-454C-9982-67B359A55E22} = {B77C557B-74CB-457F-AB66-B0BBCF93FA5C}
54 | EndGlobalSection
55 | GlobalSection(ExtensibilityGlobals) = postSolution
56 | SolutionGuid = {D2610FC5-400C-462E-8BEC-028ECC97A1EF}
57 | EndGlobalSection
58 | EndGlobal
59 |
--------------------------------------------------------------------------------
/coverlet.runsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | cobertura
8 | [Sample*]*
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "6.0.100",
4 | "rollForward": "latestFeature"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PureKrome/SimpleHosting/5eac0ab1902b096d9378fa67c2022dce4a5d8a70/icon.jpg
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleHostedServiceApplication/CustomHostedService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.Extensions.Hosting;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace WorldDomination.SimpleHosting.SampleHostedServiceApplication
8 | {
9 | public abstract class CustomHostedService : IHostedService
10 | {
11 | private readonly string _name;
12 | private readonly ILogger _logger;
13 |
14 | public CustomHostedService(string name, ILogger logger)
15 | {
16 | _name = name;
17 | _logger = logger;
18 | }
19 |
20 | public async Task StartAsync(CancellationToken cancellationToken)
21 | {
22 | _logger.LogInformation("Starting executing {name} worker.", _name);
23 |
24 | // Just delay for a bit .. then finish.
25 | // E.g. Doing some Database preparation.
26 | _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now.ToString());
27 | await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
28 |
29 | _logger.LogInformation("Finishing StartAsync {name} worker.", _name);
30 | }
31 |
32 | public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleHostedServiceApplication/HostedService1.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace WorldDomination.SimpleHosting.SampleHostedServiceApplication
4 | {
5 | public class HostedService1 : CustomHostedService
6 | {
7 | public HostedService1(ILogger logger) : base("HostedService-1", logger)
8 | {
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleHostedServiceApplication/HostedService2.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace WorldDomination.SimpleHosting.SampleHostedServiceApplication
4 | {
5 | public class HostedService2 : CustomHostedService
6 | {
7 | public HostedService2(ILogger logger) : base("HostedService-2", logger)
8 | {
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleHostedServiceApplication/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.Extensions.Hosting;
5 |
6 | namespace WorldDomination.SimpleHosting.SampleHostedServiceApplication
7 | {
8 | public class Program
9 | {
10 | public static Task Main(string[] args)
11 | {
12 | var options = new MainOptions
13 | {
14 | CommandLineArguments = args,
15 | FirstLoggingInformationMessage = "~~ Sample Hosted Services Application ~~",
16 | LogAssemblyInformation = true,
17 | LastLoggingInformationMessage = "-- Sample Hosted Services Application has ended/terminated --",
18 | ConfigureCustomServices = new Action((hostContext, services) =>
19 | {
20 | services.AddHostedService();
21 | services.AddHostedService();
22 | })
23 | };
24 |
25 | return SimpleHosting.Program.Main(options);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleHostedServiceApplication/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "SampleBackgroundTask": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "DOTNET_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleHostedServiceApplication/WorldDomination.SimpleHosting.SampleHostedServiceApplication.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleHostedServiceApplication/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleHostedServiceApplication/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Serilog": {
3 | "MinimumLevel": {
4 | "Default": "Debug"
5 | },
6 | "WriteTo": [
7 | {
8 | "Name": "Console"
9 | }
10 | ],
11 | "Enrich": [ "FromLogContext" ],
12 | "Properties": {
13 | "ApplicationName": "SampleBackgroundTask"
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication.Tests/CustomWebApplicationFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using FizzWare.NBuilder;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.AspNetCore.Mvc.Testing;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.Hosting;
7 | using Moq;
8 | using WorldDomination.SimpleHosting.SampleWebApplication.Services;
9 |
10 | namespace WorldDomination.SimpleHosting.SampleWebApplication.Tests
11 | {
12 | public class CustomWebApplicationFactory : WebApplicationFactory
13 | {
14 | protected override IHostBuilder CreateHostBuilder() => SimpleHosting.Program.CreateHostBuilder(new MainOptions());
15 |
16 | public MainOptions MainOptions{ get; set; }
17 |
18 | protected override void ConfigureWebHost(IWebHostBuilder builder)
19 | {
20 | builder.ConfigureServices(services =>
21 | {
22 | // Remove the existing registration for an IWeatherService.
23 | var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(IWeatherService));
24 | if (descriptor != null)
25 | {
26 | services.Remove(descriptor);
27 | }
28 |
29 | // Use a mocked IWeatherService.
30 | var weatherForcasts = Builder.CreateListOfSize(5).Build();
31 | var weatherService = new Mock();
32 | weatherService.Setup(x => x.GetWeatherAsync()).ReturnsAsync(weatherForcasts);
33 | services.AddTransient(_ => weatherService.Object);
34 | });
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication.Tests/WeatherForecastControllerTests/GetTests.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.Logging;
4 | using Shouldly;
5 | using Xunit;
6 |
7 | namespace WorldDomination.SimpleHosting.SampleWebApplication.Tests.WeatherForecastControllerTests
8 | {
9 | public class GetTests : IClassFixture
10 | {
11 | private readonly CustomWebApplicationFactory _factory;
12 |
13 | public GetTests(CustomWebApplicationFactory factory)
14 | {
15 | _factory = factory;
16 | }
17 |
18 | public static TheoryData> Data => new TheoryData>
19 | {
20 | {
21 | new MainOptions()
22 | },
23 | {
24 | new MainOptions
25 | {
26 | StartupActivation = new System.Func((context, logger) => new Startup(context.Configuration, logger))
27 | }
28 | }
29 | };
30 |
31 | [Theory]
32 | [MemberData(nameof(Data))]
33 | public async Task GivenAValidRequest_Get_ReturnsAnHttpStatus200OK(MainOptions mainOptions)
34 | {
35 | _factory.MainOptions = mainOptions;
36 |
37 | var client = _factory.CreateClient();
38 |
39 | // Act.
40 | var result = await client.GetAsync("/WeatherForecast");
41 |
42 | // Assert.
43 | result.StatusCode.ShouldBe(System.Net.HttpStatusCode.OK);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication.Tests/WorldDomination.SimpleHosting.SampleWebApplication.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | all
17 | runtime; build; native; contentfiles; analyzers; buildtransitive
18 |
19 |
20 | all
21 | runtime; build; native; contentfiles; analyzers; buildtransitive
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/Controllers/WeatherForecastController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNetCore.Mvc;
5 | using WorldDomination.SimpleHosting.SampleWebApplication.Services;
6 |
7 | namespace WorldDomination.SimpleHosting.SampleWebApplication.Controllers
8 | {
9 | [ApiController]
10 | [Route("[controller]")]
11 | public class WeatherForecastController : ControllerBase
12 | {
13 | private readonly IWeatherService _weatherService;
14 |
15 | public WeatherForecastController(IWeatherService weatherService)
16 | {
17 | _weatherService = weatherService ?? throw new ArgumentNullException(nameof(weatherService));
18 | }
19 |
20 | [HttpGet]
21 | public async Task> Get()
22 | {
23 | return await _weatherService.GetWeatherAsync();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/CustomHostedService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.Extensions.Hosting;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace WorldDomination.SimpleHosting.SampleWebApplication
8 | {
9 | public abstract class CustomHostedService : IHostedService
10 | {
11 | private readonly string _name;
12 | private readonly ILogger _logger;
13 |
14 | public CustomHostedService(string name, ILogger logger)
15 | {
16 | _name = name;
17 | _logger = logger;
18 | }
19 |
20 | public async Task StartAsync(CancellationToken cancellationToken)
21 | {
22 | _logger.LogInformation($"Starting executing {_name} worker.");
23 |
24 | // Just delay for a bit .. then finish.
25 | // E.g. Doing some Database preparation.
26 | _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now.ToString());
27 | await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
28 |
29 | _logger.LogInformation($"Finishing StartAsync {_name} worker.");
30 | }
31 |
32 | public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/HostedBackgroundService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.Extensions.Hosting;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace WorldDomination.SimpleHosting.SampleWebApplication
8 | {
9 | public class HostedBackgroundService : BackgroundService
10 | {
11 | private readonly IServiceProvider _services;
12 | private readonly ILogger _logger;
13 |
14 | public HostedBackgroundService(IServiceProvider services, ILogger logger)
15 | {
16 | _services = services ?? throw new ArgumentNullException(nameof(services));
17 | _logger = logger ?? throw new ArgumentNullException(nameof(logger));
18 | }
19 |
20 | protected override async Task ExecuteAsync(CancellationToken cancellationToken)
21 | {
22 | _logger.LogInformation("Consume Scoped Service Hosted Service running.");
23 |
24 | while (!cancellationToken.IsCancellationRequested)
25 | {
26 | _logger.LogDebug("Doing stuff that takes a while (like checking a queue) ...");
27 |
28 | await Task.Delay(1000 * 5, cancellationToken);
29 |
30 | _logger.LogDebug("Doing stuff - finisihed.");
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/HostedService1.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace WorldDomination.SimpleHosting.SampleWebApplication
4 | {
5 | public class HostedService1 : CustomHostedService
6 | {
7 | public HostedService1(ILogger logger) : base("HostedService-1 (e.g. Database setup / seeding)", logger)
8 | {
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/HostedService2.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Logging;
2 |
3 | namespace WorldDomination.SimpleHosting.SampleWebApplication
4 | {
5 | public class HostedService2 : CustomHostedService
6 | {
7 | public HostedService2(ILogger logger) : base("HostedService-2 (e.g. Database migrations)", logger)
8 | {
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.Logging;
4 |
5 | namespace WorldDomination.SimpleHosting.SampleWebApplication
6 | {
7 | public class Program
8 | {
9 | public static Task Main(string[] args)
10 | {
11 | var options = new MainOptions
12 | {
13 | CommandLineArguments = args,
14 | FirstLoggingInformationMessage = "~~ Sample Web Application ~~",
15 | LogAssemblyInformation = true,
16 | LastLoggingInformationMessage = "-- Sample Web Application has ended/terminated --",
17 | StartupActivation = new System.Func((context, logger) => new Startup(context.Configuration, logger))
18 | };
19 |
20 | return SimpleHosting.Program.Main(options);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "Kestrel": {
5 | "commandName": "Project",
6 | "launchBrowser": true,
7 | "launchUrl": "weatherforecast",
8 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
9 | "environmentVariables": {
10 | "ASPNETCORE_ENVIRONMENT": "Development"
11 | }
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/Services/IWeatherService.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace WorldDomination.SimpleHosting.SampleWebApplication.Services
5 | {
6 | public interface IWeatherService
7 | {
8 | Task> GetWeatherAsync();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/Services/WeatherService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace WorldDomination.SimpleHosting.SampleWebApplication.Services
7 | {
8 | public class WeatherService : IWeatherService
9 | {
10 | private static readonly string[] Summaries = new[]
11 | {
12 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
13 | };
14 |
15 | public async Task> GetWeatherAsync()
16 | {
17 | var rng = new Random();
18 | var result = Enumerable.Range(1, 5).Select(index => new WeatherForecast
19 | {
20 | Date = DateTime.Now.AddDays(index),
21 | TemperatureC = rng.Next(-20, 55),
22 | Summary = Summaries[rng.Next(Summaries.Length)]
23 | })
24 | .ToArray();
25 |
26 | return await Task.FromResult(result);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.AspNetCore.Builder;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.AspNetCore.Http;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 | using WorldDomination.SimpleHosting.SampleWebApplication.Services;
10 |
11 | namespace WorldDomination.SimpleHosting.SampleWebApplication
12 | {
13 | public class Startup
14 | {
15 | private readonly ILogger _logger;
16 | private readonly IConfiguration _configuration;
17 |
18 | public Startup(IConfiguration configuration)
19 | {
20 | _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
21 | }
22 |
23 | public Startup(IConfiguration configuration, ILogger logger)
24 | {
25 | _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
26 | _logger = logger ?? throw new ArgumentNullException(nameof(logger));
27 | }
28 |
29 | // This method gets called by the runtime. Use this method to add services to the container.
30 | public void ConfigureServices(IServiceCollection services)
31 | {
32 | if (_logger != null)
33 | {
34 | _logger.LogInformation("Configuring services");
35 | }
36 |
37 | services.AddControllers();
38 |
39 | // Some fake database migration service.
40 | services.AddHostedService();
41 | services.AddHostedService();
42 | services.AddHostedService();
43 |
44 | // This is a -real- Weather Service.
45 | services.AddTransient();
46 | }
47 |
48 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
49 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
50 | {
51 | if (_logger != null)
52 | {
53 | _logger.LogInformation("Configuring Middleware");
54 | }
55 |
56 | if (env.IsDevelopment())
57 | {
58 | app.UseDeveloperExceptionPage();
59 | }
60 |
61 | app.UseHttpsRedirection();
62 |
63 | app.UseRouting();
64 |
65 | app.UseAuthorization();
66 |
67 | app.UseEndpoints(endpoints =>
68 | {
69 | // Root/default route.
70 | endpoints.MapGet("/", async context =>
71 | {
72 | await context.Response.WriteAsync("Hello World!");
73 | });
74 |
75 | endpoints.MapControllers();
76 | });
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace WorldDomination.SimpleHosting.SampleWebApplication
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/WorldDomination.SimpleHosting.SampleWebApplication.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Debug",
6 | "Microsoft": "Debug"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting.SampleWebApplication/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | "Serilog": {
4 | "MinimumLevel": {
5 | "Default": "Debug"
6 | },
7 | "WriteTo": [
8 | {
9 | "Name": "Console"
10 | }
11 | ],
12 | "Enrich": [ "FromLogContext" ],
13 | "Properties": {
14 | "ApplicationName": "SampleWebApplication"
15 | }
16 | },
17 |
18 | "Logging": {
19 | "LogLevel": {
20 | "Default": "Warning"
21 | }
22 | },
23 |
24 |
25 | "AllowedHosts": "*"
26 | }
27 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting/MainOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.Extensions.Hosting;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace WorldDomination.SimpleHosting
8 | {
9 | public class MainOptions where TStartup : class
10 | {
11 | ///
12 | /// Command line arguments.
13 | ///
14 | public string[] CommandLineArguments { get; set; }
15 |
16 | ///
17 | /// Optional text which is first displayed when the application starts.
18 | ///
19 | /// This can be useful to help determine if things have started and are working ok.
20 | public string FirstLoggingInformationMessage { get; set; }
21 |
22 | ///
23 | /// Write the assembly name, version and date information to the logger?
24 | ///
25 | /// Default: true.
26 | public bool LogAssemblyInformation { get; set; } = true;
27 |
28 | ///
29 | /// Write the .NET SDK Framework to the logger?
30 | ///
31 | /// Default: true.
32 | public bool LogFrameworkInformation { get; set; } = true;
33 |
34 | ///
35 | /// Write the OS platform to the logger?
36 | ///
37 | /// Default: true.
38 | public bool LogOSDesriptionInformation { get; set; } = true;
39 |
40 | ///
41 | /// Optional text which is last displayed when the application stops.
42 | ///
43 | /// This could be useful to help determine when things are finally stopping.
44 | public string LastLoggingInformationMessage { get; set; }
45 |
46 | ///
47 | /// Adds services to the container. This can be called multiple times and the results will be additive.
48 | ///
49 | /// This is required for Background Hosted Services, where there is no ConfigureService method to override, such as with a Web host.
50 | public Action ConfigureCustomServices { get; set; }
51 |
52 | public Func StartupActivation { get; set; }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using System.Runtime.InteropServices;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.Extensions.Configuration;
8 | using Microsoft.Extensions.Hosting;
9 | using Microsoft.Extensions.Logging;
10 | using Serilog;
11 | using Serilog.Core;
12 | using Serilog.Extensions.Logging;
13 |
14 | namespace WorldDomination.SimpleHosting
15 | {
16 | public class Program
17 | {
18 | private static readonly string _explosion = @"" + Environment.NewLine +
19 | "" + Environment.NewLine +
20 | "" + Environment.NewLine +
21 | " ____" + Environment.NewLine +
22 | " __,-~~/~ `---." + Environment.NewLine +
23 | " _/_,---( , )" + Environment.NewLine +
24 | " __ / < / ) \\___" + Environment.NewLine +
25 | "- ------===;;;'====------------------===;;;===----- - -" + Environment.NewLine +
26 | " \\/ ~\"~\"~\"~\"~\"~\\~\"~)~\"/" + Environment.NewLine +
27 | " (_ ( \\ ( > \\)" + Environment.NewLine +
28 | " \\_(_<> _>'" + Environment.NewLine +
29 | " ~ `-i' ::>|--\"" + Environment.NewLine +
30 | " I;|.|.|" + Environment.NewLine +
31 | " <|i::|i|`." + Environment.NewLine +
32 | " (` ^'\"`-' \")" + Environment.NewLine +
33 | "------------------------------------------------------------------" + Environment.NewLine +
34 | "[Nuclear Explosion Mushroom by Bill March]" + Environment.NewLine +
35 | "" + Environment.NewLine +
36 | "------------------------------------------------" + Environment.NewLine +
37 | "";
38 |
39 | ///
40 | /// The program's main start/entry point. Hold on to your butts .... here we go!
41 | ///
42 | /// Startup class type.
43 | /// Optional command line arguments.
44 | /// Task of this Main application run.
45 | public static async Task Main(string[] args) where TStartup : class
46 | {
47 | var options = new MainOptions
48 | {
49 | CommandLineArguments = args
50 | };
51 |
52 | await Main(options);
53 | }
54 |
55 | ///
56 | /// The program's main start/entry point. Hold on to your butts .... here we go!
57 | ///
58 | /// Startup class type.
59 | /// Options to help setup/configure your program.
60 | /// Task of this Main application run.
61 | public static async Task Main(MainOptions options) where TStartup : class
62 | {
63 | try
64 | {
65 | if (options is null)
66 | {
67 | throw new ArgumentNullException(nameof(options));
68 | }
69 |
70 | // Before we do _ANYTHING_ we need to have a logger so we can start
71 | // seeing what is going on ... good or bad.
72 | Log.Logger = new LoggerConfiguration()
73 | .ReadFrom.Configuration(GetConfigurationBuilder())
74 | .Enrich.FromLogContext()
75 | .CreateLogger();
76 |
77 | // Display any (optional) initial banner / opening text to define the start of this application now starting.
78 | if (!string.IsNullOrWhiteSpace(options.FirstLoggingInformationMessage))
79 | {
80 | Log.Information(options.FirstLoggingInformationMessage);
81 | }
82 |
83 | if (options.LogAssemblyInformation)
84 | {
85 | var assembly = typeof(TStartup).Assembly;
86 | var assemblyDate = string.IsNullOrWhiteSpace(assembly.Location)
87 | ? "-- unknown --"
88 | : File.GetLastWriteTime(assembly.Location).ToString("u");
89 |
90 | var assemblyInfo = $"Name: {assembly.GetName().Name} | Version: {assembly.GetName().Version} | Date: {assemblyDate}";
91 |
92 | Log.Information(assemblyInfo);
93 | }
94 |
95 | if (options.LogFrameworkInformation)
96 | {
97 | Log.Information($"Framework: {RuntimeInformation.FrameworkDescription}");
98 | }
99 |
100 | if (options.LogOSDesriptionInformation)
101 | {
102 | Log.Information($"OS Platform: {RuntimeInformation.OSDescription}");
103 | }
104 |
105 | var host = CreateHostBuilder(options).Build();
106 |
107 | // Ok, now lets go and start!
108 | await host.RunAsync();
109 | }
110 | catch (Exception exception)
111 | {
112 | const string errorMessage = "Something seriously unexpected has occurred while preparing the Host. Sadness :~(";
113 |
114 | // We might NOT have created a logger ... because we might be _trying_ to create the logger but
115 | // we have some bad setup-configuration-data and boom!!! No logger successfully setup/created.
116 | // So, if we do have a logger created, then use it.
117 | if (Log.Logger is Logger)
118 | {
119 | // TODO: Add metrics (like Application Insights?) to log telemetry failures -IF- Serilog can't do this adequately.
120 | Log.Logger.Fatal(exception, errorMessage);
121 | }
122 | else
123 | {
124 | // Nope - failed to create a logger and we have a serious error. So lets
125 | // just fall back to the Console and _hope_ someone can read/access that.
126 | Console.WriteLine(_explosion);
127 | Console.WriteLine(errorMessage);
128 | Console.WriteLine();
129 | Console.WriteLine();
130 | Console.WriteLine($"Error: {exception.Message}");
131 | Console.WriteLine();
132 | }
133 | }
134 | finally
135 | {
136 | var shutdownMessage = string.IsNullOrWhiteSpace(options.LastLoggingInformationMessage)
137 | ? "Application has now shutdown."
138 | : options.LastLoggingInformationMessage;
139 |
140 | // Again: did we successfully create a logger?
141 | if (Log.Logger is Logger)
142 | {
143 | Log.Information(shutdownMessage);
144 |
145 | // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
146 | Log.CloseAndFlush();
147 | }
148 | else
149 | {
150 | Console.WriteLine(shutdownMessage);
151 | }
152 | }
153 | }
154 |
155 | // This is only to help load the SERILOG information.
156 | // - appsettings.json
157 | // - appsettings..json
158 | // - environmental variables
159 | // Strongly based off/from: https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.host.createdefaultbuilder?view=dotnet-plat-ext-5.0
160 | private static IConfiguration GetConfigurationBuilder()
161 | {
162 | var builder = new ConfigurationBuilder()
163 | .SetBasePath(Directory.GetCurrentDirectory())
164 | .AddJsonFile("appsettings.json", optional: false);
165 |
166 | // Check any 'Environment' json files, like appsettings.Development.json.
167 | // REF: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?#environmentname
168 | var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ??
169 | Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ??
170 | "Production";
171 |
172 | return builder
173 | .AddJsonFile($"appsettings.{environment}.json", optional: true)
174 | .AddEnvironmentVariables()
175 | .Build();
176 | }
177 |
178 | public static IHostBuilder CreateHostBuilder(MainOptions options) where TStartup : class
179 | {
180 | var hostBuilder = Host
181 | .CreateDefaultBuilder(options.CommandLineArguments)
182 | .ConfigureLogging((context, logging) =>
183 | {
184 | // Don't want any of the default crap.
185 | logging.ClearProviders();
186 | })
187 | .UseSerilog();
188 |
189 | if (options.ConfigureCustomServices != null)
190 | {
191 | hostBuilder.ConfigureServices(options.ConfigureCustomServices);
192 | }
193 |
194 | var logger = new SerilogLoggerProvider(Log.Logger).CreateLogger(nameof(Program));
195 |
196 | hostBuilder
197 | .ConfigureWebHostDefaults(webBuilder =>
198 | {
199 | if (options.StartupActivation is null)
200 | {
201 | // Normal startup class with default constructor.
202 | webBuilder.UseStartup();
203 | }
204 | else
205 | {
206 | // Use the custom startup activation function, instead.
207 | // REF: https://docs.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-5.0?view=aspnetcore-5.0#control-startup-class-activation
208 | // (Pro Tip: this is a great way to add logging, to Startup.cs !!! YES!!!! )
209 | //webBuilder.UseStartup(c => new TStartup(c));
210 | webBuilder.UseStartup(context => options.StartupActivation(context, logger));
211 |
212 | // The startup class (activated, above) will be activated in _this_ assmebly and not the main host/app assembly.
213 | // This means that when things like 'MapControllers' tries to do an assembly scan (the default functionality)
214 | // in the host/app assembly, it will FAIL to find any.
215 | // As such, we actually need to really reset the main ApplicationKey to say it's for the provided startup class.
216 | // Hat tip to: @aarondandy, @buildstarted and @xt0rted
217 | var startupAssemblyName = options.StartupActivation.GetMethodInfo().DeclaringType!.GetTypeInfo().Assembly.GetName().Name;
218 | webBuilder.UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName);
219 | }
220 | });
221 |
222 | return hostBuilder;
223 | }
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:54134/",
7 | "sslPort": 44317
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "SimpleHosting": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "environmentVariables": {
22 | "ASPNETCORE_ENVIRONMENT": "Development"
23 | },
24 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/WorldDomination.SimpleHosting/WorldDomination.SimpleHosting.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | latest
6 | WorldDomination.SimpleHosting
7 | Pure Krome
8 | World Domination Technologies
9 | Simple : Hosting
10 | Making it simple to customize Hosting for your ASP.NET Core 6.x+ application
11 | 2020
12 | Library
13 | https://github.com/PureKrome/SimpleHosting
14 | LICENSE.txt
15 | README.md
16 | https://github.com/PureKrome/SimpleHosting
17 | .net c# .net-core
18 | .net dotnet c# netcore aspnetcore aspnet-core hosting world-domination unicorn magicalunicorn magical-unicorn
19 |
20 |
22 | true
23 |
24 |
25 | true
26 | true
27 | true
28 | snupkg
29 | icon.jpg
30 |
31 |
32 |
33 |
34 |
35 |
36 | all
37 | runtime; build; native; contentfiles; analyzers; buildtransitive
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | True
46 |
47 |
48 |
49 | True
50 |
51 |
52 |
53 | True
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------