├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── AspNetScaffolding3.DemoApi ├── AspNetScaffolding3.DemoApi.csproj ├── Controllers │ ├── CustomerController.cs │ ├── PersonController.cs │ └── ProxyController.cs ├── DOCS.md ├── Entities │ └── Customer.cs ├── Models │ ├── Address.cs │ ├── CustomerRequest.cs │ └── Person.cs ├── Profiles │ └── CustomerProfile.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── appsettings.Development.json ├── appsettings.json └── wwwroot │ └── done.html ├── AspNetScaffolding3.DemoWorker ├── AspNetScaffolding3.DemoWorker.csproj ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── Workers │ └── WorkerRunner.cs ├── appsettings.Development.json └── appsettings.json ├── AspNetScaffolding3.sln ├── AspNetScaffolding3 ├── Api.cs ├── AspNetScaffolding3.csproj ├── Controllers │ ├── BaseController.cs │ └── HomeController.cs ├── Extensions │ ├── AccountId │ │ ├── AccountId.cs │ │ ├── AccountIdMiddleware.cs │ │ └── AccountIdService.cs │ ├── Cache │ │ ├── CacheService.cs │ │ ├── CacheSettings.cs │ │ └── LockerFactory.cs │ ├── Configuration │ │ └── ConfigurationExtension.cs │ ├── Cors │ │ ├── CorsMiddleware.cs │ │ └── CorsService.cs │ ├── CultureInfo │ │ └── CultureInfoMiddleware.cs │ ├── Docs │ │ ├── DocsMiddleware.cs │ │ ├── DocsService.cs │ │ ├── DocsSettings.cs │ │ └── QueryAndPathCaseOperationFilter.cs │ ├── ExceptionHandler │ │ └── ExceptionHandlerMiddleware.cs │ ├── GracefullShutdown │ │ ├── GracefullShutdownExtensions.cs │ │ ├── GracefullShutdownMiddleware.cs │ │ ├── GracefullShutdownState.cs │ │ ├── IRequestsCountProvider.cs │ │ └── ShutdownSettings.cs │ ├── Healthcheck │ │ ├── HealthcheckMiddleware.cs │ │ ├── HealthcheckService.cs │ │ └── HealthcheckSettings.cs │ ├── JsonFieldSelector │ │ └── JsonFieldSelectorMiddleware.cs │ ├── JsonSerializer │ │ ├── CaseUtility.cs │ │ ├── JsonSerializerEnum.cs │ │ └── JsonSerializerService.cs │ ├── Logger │ │ ├── Formatters │ │ │ ├── SnakeCaseJsonValueFormatter.cs │ │ │ └── SnakeCaseRenderedCompactJsonFormatter.cs │ │ ├── ISimpleLogger.cs │ │ ├── LoggerBuilderExtension.cs │ │ ├── LoggerService.cs │ │ ├── LoggerSettings.cs │ │ ├── SimpleLogger.cs │ │ └── StaticSimpleLogger.cs │ ├── Mapper │ │ ├── MapperExtension.cs │ │ └── MapperService.cs │ ├── Mvc │ │ └── MvcBuilderExtension.cs │ ├── QueryFormatter │ │ ├── PathFormatterSettings.cs │ │ └── QueryFormatterSettings.cs │ ├── Queue │ │ ├── ChannelFactory.cs │ │ ├── Interfaces │ │ │ ├── IQueueClient.cs │ │ │ └── IQueueProcessor.cs │ │ ├── QueueClient.cs │ │ ├── QueueHealthcheck.cs │ │ ├── QueueProcessor.cs │ │ ├── QueueService.cs │ │ └── QueueSettings.cs │ ├── RequestKey │ │ ├── RequestKey.cs │ │ ├── RequestKeyMiddleware.cs │ │ └── RequestKeyService.cs │ ├── RequestLimit │ │ ├── CustomRateLimitConfiguration.cs │ │ ├── IpRateLimitingAdditional.cs │ │ ├── IpRateLimitingService.cs │ │ ├── RateLimitingAdditional.cs │ │ └── UrlResourceRateLimitContributor.cs │ ├── RoutePrefix │ │ ├── IgnoreRoutePrefixAttribute.cs │ │ ├── RoutePrefixAttribute.cs │ │ └── RoutePrefixExtensions.cs │ ├── StreamExt │ │ └── StreamExtension.cs │ ├── TimeElapsed │ │ ├── TimeElapsedMiddleware.cs │ │ └── TimeElapsedService.cs │ └── Worker │ │ ├── BaseWorkerRunner.cs │ │ ├── Interface │ │ └── IWorkerRunner.cs │ │ ├── WorkerService.cs │ │ └── WorkerSettings.cs ├── Models │ ├── ApiBasicConfiguration.cs │ ├── ApiSettings.cs │ ├── DatabaseSettings.cs │ └── ExceptionContainer.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── Utilities │ ├── CQRSExtensions.cs │ ├── EnvironmentUtility.cs │ ├── ObjectMappingExtension.cs │ ├── PipelineRExtension.cs │ └── RestsharpEasyExtension.cs └── appsettings.json ├── AspNetScaffolding3Tests ├── AspNetScaffolding3Tests.csproj └── Extensions │ └── Logger │ └── LoggerSettingsTest.cs ├── LICENSE ├── README.md ├── README.md.bak ├── Template └── src │ ├── AspNetScaffoldingTemplate.Api │ ├── AspNetScaffoldingTemplate.Api.csproj │ ├── Docs.md │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ └── appsettings.json │ ├── AspNetScaffoldingTemplate.Core.Tests │ ├── AspNetScaffoldingTemplate.Core.Tests.csproj │ └── UnitTest1.cs │ ├── AspNetScaffoldingTemplate.Core │ ├── AspNetScaffoldingTemplate.Core.csproj │ ├── Models │ │ └── Person │ │ │ ├── Composition │ │ │ ├── Address.cs │ │ │ └── PersonType.cs │ │ │ ├── Person.cs │ │ │ └── Validator │ │ │ └── CreatePersonValidator.cs │ └── Services │ │ ├── Interfaces │ │ └── IPersonService.cs │ │ └── PersonService.cs │ ├── AspNetScaffoldingTemplate.sln │ ├── AspNetScaffoldingTemplate │ ├── AspNetScaffoldingAdditionalData.Designer.cs │ ├── AspNetScaffoldingAdditionalData.cs │ ├── AspNetScaffoldingAdditionalData.resx │ ├── AspNetScaffoldingTemplate.csproj │ ├── ProjectTemplates │ │ └── AspNetScaffolding3.zip │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── Wizard.cs │ ├── aspnetscaffolding-wizard.snk │ ├── icon.png │ ├── logo.png │ └── source.extension.vsixmanifest │ └── TemplateRelease │ ├── .gitattributes │ ├── .github │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE.md │ └── PULL_REQUEST_TEMPLATE.md │ ├── .gitignore │ ├── AspNetScaffolding3.vstemplate │ ├── AspNetScaffolding3.zip │ ├── AspNetScaffoldingTemplate.Api │ ├── AspNetScaffoldingTemplate.Api.csproj │ ├── AspNetScaffoldingTemplate.Api.vstemplate │ ├── Docs.md │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── __PreviewImage.png │ ├── __TemplateIcon.png │ └── appsettings.json │ ├── AspNetScaffoldingTemplate.Core.Tests │ ├── AspNetScaffoldingTemplate.Core.Tests.csproj │ ├── AspNetScaffoldingTemplate.Core.Tests.vstemplate │ ├── UnitTest1.cs │ ├── __PreviewImage.png │ └── __TemplateIcon.png │ ├── AspNetScaffoldingTemplate.Core │ ├── AspNetScaffoldingTemplate.Core.csproj │ ├── AspNetScaffoldingTemplate.Core.vstemplate │ ├── Models │ │ └── Person │ │ │ ├── Composition │ │ │ ├── Address.cs │ │ │ └── PersonType.cs │ │ │ ├── Person.cs │ │ │ └── Validator │ │ │ └── CreatePersonValidator.cs │ ├── Services │ │ ├── Interfaces │ │ │ └── IPersonService.cs │ │ └── PersonService.cs │ ├── __PreviewImage.png │ └── __TemplateIcon.png │ ├── README.md │ ├── __PreviewImage.png │ ├── __TemplateIcon.png │ └── devops │ ├── Dockerfile │ ├── azure-pipelines.yml │ └── docker-compose.yml └── azure-pipelines.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | First off, thanks for taking the time to contribute! 4 | 5 | ### How can I contribute? 6 | 7 | * Fork this project; 8 | * Make your changes / new implementatios; 9 | * Use the pattern for git commts; 10 | * Make sure that the acceptance criteria are met (tests, docs, etc); 11 | * Create a pull request; 12 | 13 | ### Pull Requests 14 | 15 | Template [PULLREQUEST-TEMPLATE](PULLREQUEST-TEMPLATE.md) 16 | 17 | ### Git Commit Messages 18 | 19 | * Use the present tense ("Adds feature" not "Added feature") 20 | * Limit the first line to 72 characters or less 21 | * Reference issues and pull requests liberally 22 | * Consider starting the commit message with an applicable emoji: 23 | * :art: `:art:` when improving the format/structure of the code 24 | * :racehorse: `:racehorse:` when improving performance 25 | * :non-potable_water: `:non-potable_water:` when plugging memory leaks 26 | * :memo: `:memo:` when writing docs 27 | * :penguin: `:penguin:` when fixing something on Linux 28 | * :apple: `:apple:` when fixing something on Mac OS 29 | * :checkered_flag: `:checkered_flag:` when fixing something on Windows 30 | * :bug: `:bug:` when fixing a bug 31 | * :fire: `:fire:` when removing code or files 32 | * :green_heart: `:green_heart:` when fixing the CI build 33 | * :white_check_mark: `:white_check_mark:` when adding tests 34 | * :lock: `:lock:` when dealing with security 35 | * :arrow_up: `:arrow_up:` when upgrading dependencies 36 | * :arrow_down: `:arrow_down:` when downgrading dependencies 37 | * :shirt: `:shirt:` when removing linter warnings 38 | * :bulb: `:bulb:` new idea 39 | * :construction: `:construction:` work in progress 40 | * :heavy_plus_sign: `:heavy_plus_sign:` when adding features 41 | * :heavy_minus_sign: `:heavy_minus_sign:` when removing features 42 | * :speaker: `:mute:` when adding logging 43 | * :mute: `:mute:` when reducing logging 44 | * :facepunch: `:facepunch:` when resolve conflict 45 | * :wrench: `:wrench:` when modify Web.config 46 | 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ``` 2 | Please use the following template to submit your issue. 3 | Following this template will allow us to quickly investigate and help you with your issue. 4 | Please be aware that issues which do not conform to this template may be closed. 5 | 6 | DO NOT FORGET TO REMOVE THIS BLOCK 7 | ``` 8 | 9 | ### Status 10 | 11 | BUG REPORT / TASK 12 | 13 | ### Checklist 14 | 15 | Add checklist if this is a task 16 | 17 | - [x] Add slack integration 18 | - [_] Support xyz 19 | 20 | ### Steps 21 | 22 | 1. First step 23 | 2. Second step 24 | 3. Third step 25 | 26 | ### Expected behaviour 27 | 28 | How do you think the program should work? Add screenshots and code blocks if necessary. 29 | 30 | ### Actual behaviour 31 | 32 | How does the program work in its current state? 33 | 34 | ### Environment 35 | 36 | You may write here the specifications like the version of the project, services, operating system, or hardware if applicable. 37 | 38 | ### Logs / Stack trace 39 | 40 | ``` 41 | Insert your log/stack trace here 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ``` 2 | This is a guide to use this Pull Request Template. 3 | 4 | # Title 5 | [feature] Implements the crazy powerful transaction search 6 | [hotfix] Fixes login with e-mail address 7 | 8 | Add a gif that expresses your reaction to the implemented code, make it fun 9 | 10 | DO NOT FORGET TO REMOVE THIS BLOCK 11 | ``` 12 | ![Git Merge](https://media.giphy.com/media/cFkiFMDg3iFoI/giphy.gif) 13 | 14 | ### Status 15 | 16 | READY / IN DEVELOPMENT 17 | 18 | ### Whats? 19 | 20 | Describe in an objective way what has been done. 21 | 22 | ### Why? 23 | 24 | Why do you need this implementation/fix? 25 | 26 | ### How? 27 | 28 | How did you solve the problem? What are the main flows? Any technical information regarding infrastructure or architecture? 29 | 30 | ### Attachments (if appropriate) 31 | 32 | Add additional informations like screenshots, issue link, zendesk ticket link, jira task link, etc 33 | 34 | ### Definition of Done: 35 | - [ ] Increases API documentation 36 | - [ ] Implements integration tests 37 | - [ ] Implements unit tests 38 | - [ ] Is there appropriate logging included? 39 | - [ ] Does this add new dependencies? 40 | - [ ] Does need add new version in changelog? 41 | - [ ] Does need update readme, contributing, etc? 42 | - [ ] Does need change in CI server? 43 | - [ ] Will this feature require a new piece of infrastructure be implemented? 44 | - [ ] Does this PR require a blog post? If so, ensure marketing has signed off on content. 45 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/AspNetScaffolding3.DemoApi.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | false 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Always 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/Controllers/PersonController.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.DemoApi.Models; 2 | using AspNetScaffolding.Extensions.Cache; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Extensions.Caching.Distributed; 5 | using Mundipagg; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Net; 9 | using System.Threading.Tasks; 10 | using WebApi.Models.Exceptions; 11 | using WebApi.Models.Response; 12 | 13 | namespace AspNetScaffolding.Controllers 14 | { 15 | public class PersonController : BaseController 16 | { 17 | private IDistributedCache DistributedCache { get; set; } 18 | 19 | private ILocker Locker { get; set; } 20 | 21 | public PersonController(IDistributedCache cache, ILocker locker, IMundipaggApiClient client) 22 | { 23 | this.Locker = locker; 24 | this.DistributedCache = cache; 25 | } 26 | 27 | [HttpGet("persons/{id}")] 28 | [ProducesResponseType(typeof(Person), 200)] 29 | [ProducesResponseType(typeof(ErrorsResponse), 400)] 30 | [ProducesResponseType(404)] 31 | [ProducesResponseType(500)] 32 | public async Task Get() 33 | { 34 | var person = new Person 35 | { 36 | FirstName = "John", 37 | LastName = "Doe", 38 | Birthdate = DateTime.UtcNow.AddMonths(30), 39 | Email = "john.doe@email.com", 40 | Type = PersonType.PhysicalPerson 41 | }; 42 | 43 | return Ok(person); 44 | 45 | var options = new DistributedCacheEntryOptions 46 | { 47 | AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) 48 | }; 49 | 50 | await this.DistributedCache.SetStringAsync("123123", "teste", options); 51 | 52 | var locker = await this.Locker.GetDistributedLockerAsync("teste", 600); 53 | 54 | if (!locker.IsAcquired) 55 | { 56 | throw new ConflictException(); 57 | } 58 | 59 | var apiResponse = new ApiResponse 60 | { 61 | Content = person, 62 | StatusCode = HttpStatusCode.Accepted, 63 | Headers = new Dictionary 64 | { 65 | { "SomeHeader", "Test Get" } 66 | } 67 | }; 68 | 69 | return CreateJsonResponse(apiResponse); 70 | } 71 | 72 | [HttpPost("persons")] 73 | [ProducesResponseType(typeof(Person), 200)] 74 | [ProducesResponseType(typeof(ErrorsResponse), 400)] 75 | [ProducesResponseType(404)] 76 | [ProducesResponseType(500)] 77 | public IActionResult Create([FromBody]Person person) 78 | { 79 | Validate(person); 80 | 81 | var apiResponse = new ApiResponse 82 | { 83 | Content = person, 84 | StatusCode = HttpStatusCode.Created, 85 | Headers = new Dictionary 86 | { 87 | { "SomeHeader", "Test Created" } 88 | } 89 | }; 90 | 91 | return CreateJsonResponse(apiResponse); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/Controllers/ProxyController.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Controllers; 2 | using AspNetScaffolding.Extensions.RoutePrefix; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace AspNetScaffolding3.DemoApi.Controllers 6 | { 7 | [IgnoreRoutePrefix] 8 | public class ProxyController : BaseController 9 | { 10 | [HttpGet, HttpPost, HttpPut, HttpPatch, HttpDelete, HttpHead, HttpOptions] 11 | [ProducesResponseType(200)] 12 | [ProducesResponseType(201)] 13 | [ProducesResponseType(401)] 14 | [ProducesResponseType(409)] 15 | [ProducesResponseType(412)] 16 | [ProducesResponseType(422)] 17 | [ProducesResponseType(500)] 18 | public IActionResult HandleAllRequests() 19 | { 20 | return Ok(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/DOCS.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | Lorem ipsum -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/Entities/Customer.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding.DemoApi.Entities 2 | { 3 | public class Customer 4 | { 5 | 6 | public Customer(string customerId, string otherProp) 7 | { 8 | CustomerId = customerId; 9 | OtherProp = otherProp; 10 | } 11 | 12 | public string CustomerId { get; private set; } 13 | 14 | public string OtherProp { get; private set; } 15 | 16 | 17 | public string OnlyResponse { get; private set; } = "test"; 18 | 19 | 20 | public string OnlyRequest { get; private set; } = "test"; 21 | 22 | public SubTest SubTest { get; set; } = new SubTest(); 23 | 24 | public Test TestTest { get; set; } 25 | } 26 | 27 | public enum Test 28 | { 29 | TEst_TESt, 30 | TESTE_TEST, 31 | 32 | } 33 | 34 | public class SubTest 35 | { 36 | public string OnlyResponse { get; private set; } = "test"; 37 | 38 | public string OnlyRequest { get; private set; } = "test"; 39 | } 40 | } -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/Models/Address.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | 3 | namespace AspNetScaffolding.DemoApi.Models 4 | { 5 | public class Address 6 | { 7 | public string Line1 { get; set; } 8 | 9 | public string Line2 { get; set; } 10 | 11 | public string CityCode { get; set; } 12 | } 13 | 14 | public class AddressValidator : AbstractValidator
15 | { 16 | public AddressValidator() 17 | { 18 | RuleFor(p => p.Line1).NotEmpty().Length(3, 30); 19 | RuleFor(p => p.Line2).NotEmpty().Length(3, 30); 20 | RuleFor(p => p.CityCode).NotEmpty().Length(2); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/Models/CustomerRequest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using System; 3 | 4 | namespace AspNetScaffolding.DemoApi.Models 5 | { 6 | public class CustomerRequest 7 | { 8 | [FromRoute] public string CustomerId { get; set; } 9 | 10 | [FromQuery] public string ServiceId { get; set; } 11 | } 12 | 13 | public class CustomerRequest2 14 | { 15 | [FromRoute] public string CustomerId { get; set; } 16 | 17 | [FromBody] public string OtherProp { get; set; } 18 | 19 | [FromBody] public DateTime DateTest { get; set; } 20 | } 21 | 22 | public class CustomerRequest3 23 | { 24 | public string CustomerId { get; set; } 25 | 26 | public string ServiceId { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/Models/Person.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation; 2 | using Newtonsoft.Json; 3 | using PackUtils.Converters; 4 | using System; 5 | 6 | namespace AspNetScaffolding.DemoApi.Models 7 | { 8 | public class Person 9 | { 10 | public string FirstName { get; set; } 11 | 12 | public string LastName { get; set; } 13 | 14 | [JsonConverter(typeof(DateConverter))] 15 | public DateTime Birthdate { get; set; } 16 | 17 | public DateTime Now { get; set; } = DateTime.UtcNow; 18 | 19 | public string Email { get; set; } 20 | 21 | public Address Address { get; set; } 22 | 23 | public PersonType Type { get; set; } 24 | } 25 | 26 | public enum PersonType 27 | { 28 | Undefined, 29 | PhysicalPerson, 30 | LegalEntity 31 | } 32 | 33 | public class PersonValidator : AbstractValidator 34 | { 35 | public PersonValidator() 36 | { 37 | RuleFor(p => p.FirstName).NotEmpty().Length(3, 30); 38 | RuleFor(p => p.LastName).NotEmpty().Length(3, 30); 39 | RuleFor(p => p.Email).NotEmpty().EmailAddress(); 40 | RuleFor(p => p.Address).NotNull().SetValidator(new AddressValidator()); 41 | RuleFor(p => p.Type).Must(p => p != PersonType.Undefined); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/Profiles/CustomerProfile.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.DemoApi.Entities; 2 | using AspNetScaffolding.DemoApi.Models; 3 | 4 | namespace AspNetScaffolding.DemoApi.Profiles 5 | { 6 | public class CustomerProfile : AutoMapper.Profile 7 | { 8 | public CustomerProfile() 9 | { 10 | CreateMap(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/Program.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.RequestKey; 2 | using AspNetScaffolding.Models; 3 | using AspNetScaffolding3.DemoApi.Controllers; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Routing.Constraints; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Mundipagg; 8 | using System; 9 | using System.Reflection; 10 | 11 | namespace AspNetScaffolding.DemoApi 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | var config = new ApiBasicConfiguration 18 | { 19 | ApiName = "My AspNet Scaffolding", 20 | ApiPort = 8700, 21 | EnvironmentVariablesPrefix = "Prefix_", 22 | ConfigureHealthcheck = ConfigureHealthcheck, 23 | ConfigureServices = ConfigureServices, 24 | Configure = Configure, 25 | ConfigureAfter = ConfigureAfter, 26 | AutoRegisterAssemblies = new Assembly[] 27 | { Assembly.GetExecutingAssembly() } 28 | }; 29 | 30 | Api.Run(config); 31 | } 32 | 33 | public static void ConfigureHealthcheck(IHealthChecksBuilder builder, IServiceProvider provider) 34 | { 35 | // add health check configuration 36 | builder.AddUrlGroup(new Uri("https://www.google.com"), "google"); 37 | //builder.AddMongoDb("mongodb://localhost:27017"); 38 | } 39 | 40 | public static void ConfigureServices(IServiceCollection services) 41 | { 42 | var apiUrl = "https://api.mundipagg.com/core/v1"; 43 | 44 | services.AddScoped(provider => 45 | { 46 | return new MundipaggApiClient(null, provider.GetService().Value, apiUrl, 120000); 47 | }); 48 | 49 | // add services 50 | //services.AddSingleton(); 51 | } 52 | 53 | public static void Configure(IApplicationBuilder app) 54 | { 55 | // customize your app 56 | //app.UseAuthentication(); 57 | } 58 | 59 | public static void ConfigureAfter(IApplicationBuilder app) 60 | { 61 | var prefix = Api.ApiSettings.GetPathPrefixConsideringVersion(); 62 | 63 | var controllerName = nameof(ProxyController).Replace("Controller", ""); 64 | var actionName = nameof(ProxyController.HandleAllRequests); 65 | 66 | var method = "POST"; 67 | var path = prefix + "/transactions/{id}"; 68 | var resourceName = "transactions.create"; 69 | 70 | app.UseEndpoints(endpoints => 71 | { 72 | endpoints.MapControllerRoute(resourceName, path, 73 | defaults: new 74 | { 75 | controller = controllerName, 76 | action = actionName, 77 | resource = resourceName 78 | }, 79 | constraints: new 80 | { 81 | httpMethod = new HttpMethodRouteConstraint(method) 82 | }); 83 | endpoints.MapControllerRoute("xpto", prefix + "/xpto", 84 | defaults: new 85 | { 86 | controller = controllerName, 87 | action = actionName, 88 | resource = "xpto" 89 | }, 90 | constraints: new 91 | { 92 | httpMethod = new HttpMethodRouteConstraint("GET") 93 | }); 94 | }); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ApiSettings": { 3 | "AppUrl": "http://localhost:5855", 4 | "JsonSerializer": "Snakecase", 5 | "PathPrefix": "myapp/{version}", 6 | "UseStaticFiles": true, 7 | "StaticFilesPath": "assets", 8 | "Domain": "MyDomain", 9 | "Application": "MyApp", 10 | "Version": "v1", 11 | "BuildVersion": "1.0.0", 12 | "SupportedCultures": [ "en-US", "pt-BR", "es-ES" ], 13 | "UseOriginalEnumValue": true, 14 | "RequestKeyProperty": "RequestKey", 15 | "AccountIdProperty": "AccountId", 16 | "TimezoneHeader": "Timezone", 17 | "TimezoneDefault": "America/Sao_Paulo", 18 | "TimeElapsedProperty": "X-Internal-Time", 19 | "JsonFieldSelectorProperty": "fields" 20 | }, 21 | "ShutdownSettings": { 22 | "ShutdownTimeoutInSeconds": 10, 23 | "Enabled": true, 24 | "Redirect": false 25 | }, 26 | "HealthcheckSettings": { 27 | "Enabled": true, 28 | "Path": "healthcheck", 29 | "LogEnabled": false 30 | }, 31 | "DbSettings": { 32 | "ConnectionString": "mongodb://user:pass@localhost:27017/DatabaseName", 33 | "Name": "DatabaseName" 34 | }, 35 | "CacheSettings": { 36 | "Enabled": true, 37 | "UseRedis": false, 38 | "UseLocker": false, 39 | "TimeoutInMs": 1000, 40 | "Ssl": false, 41 | "Password": "RedisAuth", 42 | "Host": "localhost", 43 | "Port": 6379, 44 | "LockerPrefix": "app-locker-", 45 | "LockerTtlInSeconds": 100, 46 | "LockerDb": 0, 47 | "CachePrefix": "app-cache-", 48 | "CacheTtlInSeconds": 900, 49 | "CacheDb": 0 50 | }, 51 | "QueueSettings": { 52 | "Enabled": false, 53 | "RetryTTL": 20000, 54 | "RetryTTLFactor": 2.0, 55 | "RetryCount": 5, 56 | "QueueConnectionString": "amqp://guest:guest@localhost:5672/VHost", 57 | "VHostApi": "http://guest:guest@localhost:15672/api/queues/VHost", 58 | "QueueName": "my-queue", 59 | "ExchangeToSubscribe": "main.topic", 60 | "EventsToSubscribe": "event.something.created,event.other.#", 61 | "MaxThreads": 200, 62 | "AutoAckOnSuccess": true 63 | }, 64 | "IpRateLimiting": { 65 | "Enabled": false, 66 | "EnableEndpointRateLimiting": false, 67 | "StackBlockedRequests": false, 68 | "RealIpHeader": "X-Real-IP", 69 | "ClientIdHeader": "X-ClientId", 70 | "HttpStatusCode": 429, 71 | "IpWhitelist": [], 72 | "EndpointWhitelist": [], 73 | "ClientWhitelist": [], 74 | "GeneralRules": [ 75 | { 76 | "Endpoint": "*", 77 | "Period": "1m", 78 | "Limit": 5 79 | }, 80 | { 81 | "Endpoint": "*", 82 | "Period": "1h", 83 | "Limit": 1000 84 | } 85 | ] 86 | }, 87 | "LogSettings": { 88 | "DebugEnabled": false, 89 | "TitlePrefix": "[{Application}] ", 90 | "JsonBlacklistRequest": [ "*password", "*card.number", "*creditcardnumber", "*cvv", "*only_request" ], 91 | "JsonBlacklistResponse": [ "*password", "*card.number", "*creditcardnumber", "*cvv", "*only_response" ], 92 | "HeaderBlacklist": [ "Authorization" ], 93 | "QueryStringBlacklist": [ "customer_key" ], 94 | "SeqOptions": { 95 | "Enabled": false, 96 | "MinimumLevel": "Verbose", 97 | "Url": "http://localhost:5341", 98 | "ApiKey": "XXXX" 99 | }, 100 | "NewRelicOptions": { 101 | "Enabled": false, 102 | "AppName": "Verbose", 103 | "LicenseKey": "XXXX" 104 | }, 105 | "SplunkOptions": { 106 | "Enabled": false, 107 | "MinimumLevel": "Verbose", 108 | "Url": "http://localhost:8088/services/collector", 109 | "Token": "XXXX", 110 | "Index": "my.index", 111 | "Application": "MyApp :Ds", 112 | "ProcessName": "Domain.App", 113 | "Company": "MyCompany", 114 | "ProductVersion": "1.0.0", 115 | "SourceType": "_json" 116 | }, 117 | "DataDogOptions": { 118 | "Enabled": true, 119 | "MinimumLevel": "Verbose", 120 | "ApiKey": "xxx", 121 | "Service": null, 122 | "Source": null, 123 | "Host": null, 124 | "Tags": [] 125 | }, 126 | "ConsoleOptions": { 127 | "Enabled": true, 128 | "MinimumLevel": "Verbose" 129 | } 130 | }, 131 | "DocsSettings": { 132 | "Enabled": true, 133 | "Title": "MyApp API Reference", 134 | "AuthorName": "Thiago Barradas", 135 | "AuthorEmail": "th.barradas@gmail.com", 136 | "PathToReadme": "DOCS.md", 137 | "IgnoredEnums": [ "none", "undefined" ] 138 | } 139 | } -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoApi/wwwroot/done.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | teste 10 | 11 | 12 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoWorker/AspNetScaffolding3.DemoWorker.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoWorker/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using AspNetScaffolding; 3 | using AspNetScaffolding.Models; 4 | 5 | namespace AspNetScaffolding3.DemoWorker 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | var config = new ApiBasicConfiguration 12 | { 13 | ApiName = "Demo Worker", 14 | ApiPort = 8701, 15 | EnvironmentVariablesPrefix = "APP_", 16 | ConfigureHealthcheck = Startup.ConfigureHealthcheck, 17 | ConfigureServices = Startup.ConfigureServices, 18 | Configure = Startup.Configure, 19 | AutoRegisterAssemblies = new Assembly[] 20 | { Assembly.GetExecutingAssembly() } 21 | }; 22 | 23 | Api.Run(config); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoWorker/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:57050", 8 | "sslPort": 44385 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "weatherforecast", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "AspNetScaffolding3.DemoWorker": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "weatherforecast", 24 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoWorker/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using AspNetScaffolding.Extensions.Queue; 4 | using AspNetScaffolding3.DemoWorker.Workers; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace AspNetScaffolding3.DemoWorker 9 | { 10 | [ExcludeFromCodeCoverage] 11 | public static class Startup 12 | { 13 | public static void ConfigureHealthcheck(IHealthChecksBuilder builder, IServiceProvider provider) 14 | { 15 | QueueHealthcheck.AddRabbitMqAutomatic(builder, provider); 16 | } 17 | 18 | public static void ConfigureServices(IServiceCollection services) 19 | { 20 | services 21 | .SetupServicesConfiguration() 22 | .SetupQueueConfiguration(); 23 | } 24 | 25 | public static void Configure(IApplicationBuilder app) 26 | { 27 | } 28 | 29 | private static IServiceCollection SetupServicesConfiguration(this IServiceCollection services) 30 | { 31 | return services; 32 | } 33 | 34 | private static IServiceCollection SetupQueueConfiguration(this IServiceCollection services) 35 | { 36 | #region -- Workers -- 37 | 38 | services.SetupWorker(); 39 | 40 | #endregion 41 | 42 | return services; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoWorker/Workers/WorkerRunner.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using AspNetScaffolding.Extensions.Logger; 3 | using AspNetScaffolding.Extensions.Queue.Interfaces; 4 | using AspNetScaffolding.Extensions.RequestKey; 5 | using AspNetScaffolding.Extensions.Worker; 6 | 7 | 8 | namespace AspNetScaffolding3.DemoWorker.Workers 9 | { 10 | public class WorkerRunner : BaseWorkerRunner 11 | { 12 | public WorkerRunner(IQueueProcessor queueProcessor) : base(queueProcessor) 13 | { 14 | this.InitFunction(ExecuteAsync); 15 | } 16 | 17 | public override async Task ExecuteAsync(string message, int retryCount, ulong deliveryTag, string requestKey) 18 | { 19 | var simpleLogger = new SimpleLogger(new RequestKey(requestKey)); 20 | 21 | var teste = new 22 | { 23 | test = "1", 24 | test_1 = "123", 25 | password = "hellomyfriend", 26 | creditCard = "123456788911" 27 | }; 28 | 29 | simpleLogger 30 | .Info(nameof(WorkerRunner), "CreateTransact", "Generate cryptogram", teste); 31 | 32 | return true; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /AspNetScaffolding3.DemoWorker/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AspNetScaffolding3.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29418.71 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6BC787A5-75A6-455E-8F77-5B27EC826F05}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetScaffolding3", "AspNetScaffolding3\AspNetScaffolding3.csproj", "{C62F17AB-7EA4-4549-9C78-0618CEDC2C1F}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetScaffolding3.DemoApi", "AspNetScaffolding3.DemoApi\AspNetScaffolding3.DemoApi.csproj", "{7852D13E-020D-47CF-97A2-6E84F43AD41D}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "git", "git", "{6EF09181-69F5-4FB8-82DF-89E096007B85}" 13 | ProjectSection(SolutionItems) = preProject 14 | .gitattributes = .gitattributes 15 | .gitignore = .gitignore 16 | EndProjectSection 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "github", "github", "{472E49FE-D82F-4E41-AC5D-519C9D291CC6}" 19 | ProjectSection(SolutionItems) = preProject 20 | .github\CONTRIBUTING.md = .github\CONTRIBUTING.md 21 | .github\ISSUE_TEMPLATE.md = .github\ISSUE_TEMPLATE.md 22 | LICENSE = LICENSE 23 | .github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md 24 | README.md = README.md 25 | EndProjectSection 26 | EndProject 27 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "devops", "devops", "{F554D092-6DFC-49FB-894C-2582917C1393}" 28 | ProjectSection(SolutionItems) = preProject 29 | azure-pipelines.yml = azure-pipelines.yml 30 | EndProjectSection 31 | EndProject 32 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetScaffolding3Tests", "AspNetScaffolding3Tests\AspNetScaffolding3Tests.csproj", "{BB3602B0-49B1-43F3-A574-A10199F18204}" 33 | EndProject 34 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetScaffolding3.DemoWorker", "AspNetScaffolding3.DemoWorker\AspNetScaffolding3.DemoWorker.csproj", "{72F91E52-9B22-4EAB-B4D1-417872978836}" 35 | EndProject 36 | Global 37 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 38 | Debug|Any CPU = Debug|Any CPU 39 | Release|Any CPU = Release|Any CPU 40 | EndGlobalSection 41 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 42 | {C62F17AB-7EA4-4549-9C78-0618CEDC2C1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {C62F17AB-7EA4-4549-9C78-0618CEDC2C1F}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {C62F17AB-7EA4-4549-9C78-0618CEDC2C1F}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {C62F17AB-7EA4-4549-9C78-0618CEDC2C1F}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {7852D13E-020D-47CF-97A2-6E84F43AD41D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {7852D13E-020D-47CF-97A2-6E84F43AD41D}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {7852D13E-020D-47CF-97A2-6E84F43AD41D}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {7852D13E-020D-47CF-97A2-6E84F43AD41D}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {BB3602B0-49B1-43F3-A574-A10199F18204}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {BB3602B0-49B1-43F3-A574-A10199F18204}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {BB3602B0-49B1-43F3-A574-A10199F18204}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {BB3602B0-49B1-43F3-A574-A10199F18204}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {72F91E52-9B22-4EAB-B4D1-417872978836}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 55 | {72F91E52-9B22-4EAB-B4D1-417872978836}.Debug|Any CPU.Build.0 = Debug|Any CPU 56 | {72F91E52-9B22-4EAB-B4D1-417872978836}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {72F91E52-9B22-4EAB-B4D1-417872978836}.Release|Any CPU.Build.0 = Release|Any CPU 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(NestedProjects) = preSolution 63 | {6EF09181-69F5-4FB8-82DF-89E096007B85} = {6BC787A5-75A6-455E-8F77-5B27EC826F05} 64 | {472E49FE-D82F-4E41-AC5D-519C9D291CC6} = {6BC787A5-75A6-455E-8F77-5B27EC826F05} 65 | {F554D092-6DFC-49FB-894C-2582917C1393} = {6BC787A5-75A6-455E-8F77-5B27EC826F05} 66 | EndGlobalSection 67 | GlobalSection(ExtensibilityGlobals) = postSolution 68 | SolutionGuid = {B3368CDA-F6C0-4F7C-936A-18E5A37F6D28} 69 | EndGlobalSection 70 | EndGlobal 71 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Api.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.Cache; 2 | using AspNetScaffolding.Extensions.Docs; 3 | using AspNetScaffolding.Extensions.GracefullShutdown; 4 | using AspNetScaffolding.Extensions.Healthcheck; 5 | using AspNetScaffolding.Extensions.Logger; 6 | using AspNetScaffolding.Extensions.Queue; 7 | using AspNetScaffolding.Extensions.RequestLimit; 8 | using AspNetScaffolding.Extensions.Worker; 9 | using AspNetScaffolding.Models; 10 | using Microsoft.AspNetCore.Hosting; 11 | using Microsoft.Extensions.Configuration; 12 | using System; 13 | using System.IO; 14 | using AspNetScaffolding3.Extensions.RequestLimit; 15 | 16 | namespace AspNetScaffolding 17 | { 18 | public static class Api 19 | { 20 | public static ApiBasicConfiguration ApiBasicConfiguration { get; set; } = new ApiBasicConfiguration(); 21 | 22 | public static IConfigurationRoot ConfigurationRoot { get; set; } 23 | 24 | public static ApiSettings ApiSettings { get; set; } = new ApiSettings(); 25 | 26 | public static HealthcheckSettings HealthcheckSettings { get; set; } = new HealthcheckSettings(); 27 | 28 | public static LoggerSettings LogSettings { get; set; } = new LoggerSettings(); 29 | 30 | public static DatabaseSettings DatabaseSettings { get; set; } = new DatabaseSettings(); 31 | 32 | public static DocsSettings DocsSettings { get; set; } = new DocsSettings(); 33 | 34 | public static ShutdownSettings ShutdownSettings { get; set; } = new ShutdownSettings(); 35 | 36 | public static QueueSettings QueueSettings { get; set; } = new QueueSettings(); 37 | 38 | public static RateLimitingAdditional RateLimitingAdditional { get; set; } = new RateLimitingAdditional(); 39 | 40 | public static CacheSettings CacheSettings { get; set; } = new CacheSettings(); 41 | 42 | public static WorkerSettings WorkerSettings { get; set; } = new WorkerSettings(); 43 | 44 | public static void Run(ApiBasicConfiguration apiBasicConfiguration) 45 | { 46 | ApiBasicConfiguration = apiBasicConfiguration; 47 | 48 | Console.WriteLine("{0} is running...", ApiBasicConfiguration.ApiName); 49 | 50 | var host = new WebHostBuilder() 51 | .UseKestrel(options => options.AllowSynchronousIO = true) 52 | .UseUrls("http://*:" + ApiBasicConfiguration.ApiPort.ToString()) 53 | .UseContentRoot(Directory.GetCurrentDirectory()) 54 | .UseStartup(); 55 | 56 | host.Build().Run(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AspNetScaffolding3/AspNetScaffolding3.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | InProcess 6 | true 7 | https://i.imgur.com/Wq5D0gQ.png 8 | https://github.com/thiagobarradas/aspnet-scaffolding3 9 | aspnet, scaffolding, splunk, seq, healthcheck, timezone, requestkey, timeelapsed, api, core, json 10 | Thiago Barradas 11 | Thiago Barradas 12 | https://github.com/thiagobarradas/aspnet-scaffolding3/blob/master/LICENSE 13 | https://github.com/thiagobarradas/aspnet-scaffolding3 14 | AspNet Scaffolding with log, serializer, and all structure to work good for me :D 15 | Ⓒ Thiago Barradas 16 | false 17 | false 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Never 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Controllers/BaseController.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.Cors; 2 | using AspNetScaffolding.Extensions.GracefullShutdown; 3 | using AspNetScaffolding.Extensions.JsonSerializer; 4 | using AspNetSerilog; 5 | using Microsoft.AspNetCore.Cors; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.AspNetCore.Mvc; 8 | using Microsoft.AspNetCore.Mvc.ModelBinding; 9 | using PackUtils; 10 | using System; 11 | using System.IO; 12 | using System.Linq; 13 | using WebApi.Models.Exceptions; 14 | using WebApi.Models.Response; 15 | 16 | namespace AspNetScaffolding.Controllers 17 | { 18 | [SerilogFilter] 19 | [EnableCors(CorsServiceExtension.CorsName)] 20 | public class BaseController : ControllerBase 21 | { 22 | public BaseController() 23 | { 24 | this.ValidationShutdown(); 25 | } 26 | 27 | protected IActionResult CreateJsonResponse(ApiResponse response) 28 | { 29 | IActionResult result; 30 | 31 | if (response.Content != null) 32 | { 33 | result = new JsonResult(response.Content) 34 | { 35 | StatusCode = (int)response.StatusCode 36 | }; 37 | } 38 | else 39 | { 40 | result = new StatusCodeResult((int)response.StatusCode); 41 | Response.ContentType = "application/json"; 42 | } 43 | 44 | if (response.Headers != null) 45 | { 46 | foreach (var header in response.Headers) 47 | { 48 | Response.Headers[header.Key] = header.Value; 49 | } 50 | } 51 | 52 | return result; 53 | } 54 | 55 | protected void ValidateSignatureFromHeaderWithContent(string secretKey, string headerName) 56 | { 57 | var result = false; 58 | var signature = Request.Headers[headerName].FirstOrDefault() ?? string.Empty; 59 | 60 | if (Request.Body.CanRead && 61 | Request.Body.CanSeek) 62 | { 63 | try 64 | { 65 | Request.EnableBuffering(); 66 | } 67 | catch (Exception) { } 68 | 69 | MemoryStream stream = new MemoryStream(); 70 | Request.Body.Seek(0, SeekOrigin.Begin); 71 | Request.Body.CopyTo(stream); 72 | Request.Body.Seek(0, SeekOrigin.Begin); 73 | 74 | using (StreamReader reader = new StreamReader(stream)) 75 | { 76 | stream.Seek(0, SeekOrigin.Begin); 77 | var content = reader.ReadToEnd(); 78 | result = SignatureUtility.ValidateSignature(signature, secretKey, content); 79 | } 80 | } 81 | 82 | if (result == false) 83 | { 84 | throw new UnauthorizedException(); 85 | } 86 | } 87 | 88 | protected void Validate(TRequest request) where TRequest : class, new() 89 | { 90 | if (ModelState.IsValid == false) 91 | { 92 | ErrorsResponse errors = CastModelValidationResultToErrorsResponse(ModelState); 93 | throw new BadRequestException(errors); 94 | } 95 | } 96 | 97 | private ErrorsResponse CastModelValidationResultToErrorsResponse(ModelStateDictionary modelState) 98 | { 99 | ErrorsResponse errorsResponse = new ErrorsResponse(); 100 | 101 | foreach (var errorPerProperty in modelState) 102 | { 103 | foreach (var errorDetail in errorPerProperty.Value.Errors) 104 | { 105 | var propertyName = string.Join(".", 106 | errorPerProperty.Key.Split(".") 107 | .Select(r => r.GetValueConsideringCurrentCase())); 108 | 109 | errorsResponse.AddError(errorDetail.ErrorMessage, propertyName); 110 | } 111 | } 112 | 113 | return errorsResponse; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.GracefullShutdown; 2 | using AspNetScaffolding.Extensions.JsonSerializer; 3 | using AspNetScaffolding.Extensions.RequestKey; 4 | using AspNetScaffolding.Utilities; 5 | using AspNetSerilog.Extensions; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.AspNetCore.Mvc; 8 | using PackUtils.Converters; 9 | using System; 10 | 11 | namespace AspNetScaffolding.Controllers 12 | { 13 | public class HomeController : BaseController 14 | { 15 | protected readonly RequestKey RequestKey; 16 | 17 | protected readonly IHttpContextAccessor HttpContextAccessor; 18 | 19 | protected readonly GracefullShutdownState GracefullShutdownState; 20 | 21 | public HomeController( 22 | IHttpContextAccessor httpContextAccessor, 23 | GracefullShutdownState gracefullShutdownState, 24 | RequestKey requestKey) 25 | { 26 | HttpContextAccessor = httpContextAccessor; 27 | GracefullShutdownState = gracefullShutdownState; 28 | RequestKey = requestKey; 29 | } 30 | 31 | [HttpGet] 32 | public IActionResult GetAppInfo() 33 | { 34 | this.DisableLogging(); 35 | 36 | return Ok(new HomeDetails 37 | { 38 | RIP = GracefullShutdownState.RequestsInProgress, 39 | Service = Api.ApiBasicConfiguration?.ApiName, 40 | BuildVersion = Api.ApiSettings?.BuildVersion, 41 | Environment = EnvironmentUtility.GetCurrentEnvironment(), 42 | RequestKey = RequestKey.Value, 43 | Application = Api.ApiSettings.Application, 44 | Domain = Api.ApiSettings.Domain, 45 | JsonSerializer = Api.ApiSettings.JsonSerializer, 46 | EnvironmentPrefix = Api.ApiBasicConfiguration.EnvironmentVariablesPrefix, 47 | TimezoneInfo = new TimezoneInfo(HttpContextAccessor) 48 | }); 49 | } 50 | 51 | public class HomeDetails 52 | { 53 | public string Service { get; set; } 54 | 55 | public string BuildVersion { get; set; } 56 | 57 | public string Environment { get; set; } 58 | 59 | public string Application { get; set; } 60 | 61 | public string Domain { get; set; } 62 | 63 | public string EnvironmentPrefix { get; set; } 64 | 65 | public long RIP { get; set; } 66 | 67 | public JsonSerializerEnum JsonSerializer { get; set; } 68 | 69 | public string RequestKey { get; set; } 70 | 71 | public TimezoneInfo TimezoneInfo { get; set; } 72 | } 73 | 74 | public class TimezoneInfo 75 | { 76 | public TimezoneInfo(IHttpContextAccessor httpContextAccessor) 77 | { 78 | CurrentTimezone = DateTimeConverter.GetTimeZoneByAspNetHeader( 79 | httpContextAccessor, 80 | Api.ApiSettings.TimezoneHeader).Id; 81 | } 82 | 83 | public string UtcNow => DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss"); 84 | 85 | public DateTime CurrentNow => DateTime.UtcNow; 86 | 87 | public string DefaultTimezone => Api.ApiSettings.TimezoneDefaultInfo.Id; 88 | 89 | public string CurrentTimezone { get; set; } 90 | 91 | public string TimezoneHeader => Api.ApiSettings.TimezoneHeader; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/AccountId/AccountId.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding.Extensions.AccountId 2 | { 3 | public class AccountId 4 | { 5 | public AccountId() { } 6 | 7 | public AccountId(string value) 8 | { 9 | Value = value; 10 | } 11 | 12 | public string Value { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/AccountId/AccountIdMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Http; 3 | using System.Threading.Tasks; 4 | 5 | namespace AspNetScaffolding.Extensions.AccountId 6 | { 7 | public class AccountIdMiddleware 8 | { 9 | private readonly RequestDelegate Next; 10 | 11 | public AccountIdMiddleware(RequestDelegate next) 12 | { 13 | Next = next; 14 | } 15 | 16 | public async Task Invoke(HttpContext context, AccountId accountId) 17 | { 18 | await Next(context); 19 | 20 | context.Items.Add(AccountIdServiceExtension.AccountIdHeaderName, accountId.Value); 21 | } 22 | } 23 | 24 | public static class AccountIdMiddlewareExtension 25 | { 26 | public static void UseAccountId(this IApplicationBuilder app) 27 | { 28 | app.UseMiddleware(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/AccountId/AccountIdService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace AspNetScaffolding.Extensions.AccountId 4 | { 5 | public static class AccountIdServiceExtension 6 | { 7 | public static string AccountIdHeaderName = "AccountId"; 8 | 9 | public static void SetupAccountId(this IServiceCollection services, string headerName = null) 10 | { 11 | if (string.IsNullOrWhiteSpace(headerName) == false) 12 | { 13 | AccountIdHeaderName = headerName; 14 | } 15 | 16 | services.AddScoped(); 17 | services.AddScoped(obj => new AccountId()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Cache/CacheService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace AspNetScaffolding.Extensions.Cache 4 | { 5 | public static class CacheService 6 | { 7 | public static void SetupCache( 8 | this IServiceCollection services, 9 | CacheSettings cacheSettings) 10 | { 11 | if (cacheSettings.UseLocker) 12 | { 13 | services.AddSingleton(cacheSettings); 14 | services.AddSingleton(); 15 | } 16 | 17 | if (cacheSettings?.Enabled == true) 18 | { 19 | if (cacheSettings.UseRedis) 20 | { 21 | services.AddStackExchangeRedisCache(options => 22 | { 23 | options.Configuration = cacheSettings.GetCacheConnectionString(); 24 | options.InstanceName = cacheSettings.CachePrefix; 25 | }); 26 | } 27 | else 28 | { 29 | services.AddMemoryCache(); 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Cache/CacheSettings.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding.Extensions.Cache 2 | { 3 | public class CacheSettings 4 | { 5 | public bool Enabled { get; set; } 6 | 7 | public bool UseRedis { get; set; } 8 | 9 | public bool UseLocker { get; set; } 10 | 11 | public string Host { get; set; } 12 | 13 | public int TimeoutInMs { get; set; } 14 | 15 | public int Port { get; set; } 16 | 17 | public bool Ssl { get; set; } 18 | 19 | public string Password { get; set; } 20 | 21 | public int LockerDb { get; set; } 22 | 23 | public string LockerPrefix { get; set; } 24 | 25 | public int LockerTtlInSeconds { get; set; } 26 | 27 | public int CacheDb { get; set; } 28 | 29 | public string CachePrefix { get; set; } 30 | 31 | public int CacheTtlInSeconds { get; set; } 32 | 33 | public string GetCacheConnectionString() 34 | { 35 | return $"{this.Host}:{this.Port},ssl={this.Ssl.ToString().ToLower()},password={this.Password},defaultDatabase={this.CacheDb},syncTimeout={this.TimeoutInMs},connectTimeout={this.TimeoutInMs},abortConnect=false"; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Cache/LockerFactory.cs: -------------------------------------------------------------------------------- 1 | using RedLockNet; 2 | using RedLockNet.SERedis; 3 | using RedLockNet.SERedis.Configuration; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Net; 7 | using System.Threading.Tasks; 8 | 9 | namespace AspNetScaffolding.Extensions.Cache 10 | { 11 | public static class LockerFactory 12 | { 13 | private static readonly object Lock = new object(); 14 | 15 | private static RedLockFactory RedLockFactory { get; set; } 16 | 17 | public static RedLockFactory Get(CacheSettings cacheSettings) 18 | { 19 | try 20 | { 21 | if (RedLockFactory == null) 22 | { 23 | lock (Lock) 24 | { 25 | if (RedLockFactory == null) 26 | { 27 | var endpoint = new RedLockEndPoint 28 | { 29 | EndPoint = new DnsEndPoint(cacheSettings.Host, cacheSettings.Port), 30 | Password = cacheSettings.Password, 31 | Ssl = cacheSettings.Ssl, 32 | RedisDatabase = cacheSettings.LockerDb, 33 | SyncTimeout = cacheSettings.TimeoutInMs, 34 | ConnectionTimeout = cacheSettings.TimeoutInMs, 35 | 36 | }; 37 | 38 | var hosts = new List { endpoint }; 39 | RedLockFactory = RedLockFactory.Create(hosts); 40 | } 41 | } 42 | } 43 | } 44 | catch (Exception) 45 | { 46 | CloseConnection(); 47 | throw; 48 | } 49 | 50 | return RedLockFactory; 51 | } 52 | 53 | public static void CloseConnection() 54 | { 55 | lock (Lock) 56 | { 57 | RedLockFactory?.Dispose(); 58 | RedLockFactory = null; 59 | } 60 | } 61 | } 62 | 63 | public interface ILocker 64 | { 65 | Task GetDistributedLockerAsync(string key, int? ttlInSeconds = null); 66 | } 67 | 68 | public class Locker : ILocker 69 | { 70 | private CacheSettings CacheSettings { get; set; } 71 | 72 | public Locker(CacheSettings cacheSettings) 73 | { 74 | this.CacheSettings = cacheSettings; 75 | } 76 | 77 | public async Task GetDistributedLockerAsync(string key, int? ttlInSeconds = null) 78 | { 79 | if (ttlInSeconds == null) 80 | { 81 | ttlInSeconds = this.CacheSettings.LockerTtlInSeconds; 82 | } 83 | 84 | var lockerFactory = LockerFactory.Get(this.CacheSettings); 85 | 86 | var fullKey = (this.CacheSettings?.LockerPrefix ?? "") + key; 87 | var ttl = TimeSpan.FromSeconds(ttlInSeconds.Value); 88 | 89 | return await lockerFactory.CreateLockAsync(fullKey, ttl); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Configuration/ConfigurationExtension.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace AspNetScaffolding.Extensions.Configuration 5 | { 6 | public static class ConfigurationExtension 7 | { 8 | public static void AddSingletonConfiguration(this IServiceCollection services, string section) where T : class, new() 9 | { 10 | T currentObject = new T(); 11 | Api.ConfigurationRoot.GetSection(section).Bind(currentObject); 12 | services.AddSingleton(obj => currentObject); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Cors/CorsMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | 3 | namespace AspNetScaffolding.Extensions.Cors 4 | { 5 | public static class CorsMiddlewareExtension 6 | { 7 | public static void AllowCors(this IApplicationBuilder app) 8 | { 9 | app.UseCors(CorsServiceExtension.CorsName); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Cors/CorsService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace AspNetScaffolding.Extensions.Cors 4 | { 5 | public static class CorsServiceExtension 6 | { 7 | public const string CorsName = "EnableAll"; 8 | 9 | public static void SetupAllowCors(this IServiceCollection services) 10 | { 11 | services.AddCors(o => o.AddPolicy(CorsName, builder => 12 | { 13 | builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); 14 | })); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/CultureInfo/CultureInfoMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Localization; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace AspNetScaffolding.Extensions.CultureInfo 7 | { 8 | public static class CultureInfoMiddlewareExtension 9 | { 10 | public static void UseScaffoldingRequestLocalization(this IApplicationBuilder app, string[] acceptedsLanguages) 11 | { 12 | if (acceptedsLanguages?.Any() == true) 13 | { 14 | app.UseRequestLocalization(options => 15 | { 16 | options.AddSupportedCultures(acceptedsLanguages); 17 | options.AddSupportedUICultures(acceptedsLanguages); 18 | options.SetDefaultCulture(acceptedsLanguages.FirstOrDefault()); 19 | options.RequestCultureProviders = new List 20 | { 21 | new AcceptLanguageHeaderRequestCultureProvider { Options = options } 22 | }; 23 | }); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Docs/DocsMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | 3 | namespace AspNetScaffolding.Extensions.Docs 4 | { 5 | public static class DocsMiddlewareExtension 6 | { 7 | public static void UseScaffoldingSwagger(this IApplicationBuilder app) 8 | { 9 | if (DocsServiceExtension.DocsSettings?.Enabled == true) 10 | { 11 | var title = DocsServiceExtension.DocsSettings?.Title ?? "API Reference"; 12 | 13 | app.UseStaticFiles(); 14 | 15 | app.UseSwagger(c => 16 | { 17 | c.RouteTemplate = DocsServiceExtension.DocsSettings.SwaggerJsonTemplateUrl.TrimStart('/'); 18 | }); 19 | 20 | app.UseReDoc(c => 21 | { 22 | c.RoutePrefix = DocsServiceExtension.DocsSettings.RedocUrl.TrimStart('/'); 23 | c.SpecUrl = DocsServiceExtension.DocsSettings.SwaggerJsonUrl; 24 | c.DocumentTitle = title; 25 | }); 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Docs/DocsSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace AspNetScaffolding.Extensions.Docs 4 | { 5 | public class DocsSettings 6 | { 7 | public bool Enabled { get; set; } 8 | 9 | public string Title { get; set; } 10 | 11 | public string AuthorName { get; set; } 12 | 13 | public string AuthorEmail { get; set; } 14 | 15 | public string PathToReadme { get; set; } 16 | 17 | public string PathPrefix { get; set; } 18 | 19 | public string Version { get; set; } 20 | 21 | public string RedocUrl { get; set; } 22 | 23 | public string SwaggerJsonUrl { get; set; } 24 | 25 | public string SwaggerJsonTemplateUrl { get; set; } 26 | 27 | public List IgnoredEnums { get; set; } 28 | 29 | public IEnumerable GetDocsFinalRoutes() 30 | { 31 | return new List 32 | { 33 | SwaggerJsonUrl, 34 | RedocUrl 35 | }; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Docs/QueryAndPathCaseOperationFilter.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.JsonSerializer; 2 | using Microsoft.OpenApi.Models; 3 | using Swashbuckle.AspNetCore.SwaggerGen; 4 | using System.Linq; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace AspNetScaffolding.Extensions.Docs 8 | { 9 | public class QueryAndPathCaseOperationFilter : IOperationFilter 10 | { 11 | public QueryAndPathCaseOperationFilter() 12 | { 13 | } 14 | 15 | public void Apply(OpenApiOperation operation, OperationFilterContext context) 16 | { 17 | if (operation.Parameters != null) 18 | { 19 | foreach (var param in operation.Parameters.Where(p => p.In == ParameterLocation.Query || p.In == ParameterLocation.Path)) 20 | { 21 | param.Name = param.Name.GetValueConsideringCurrentCase(); 22 | } 23 | 24 | var grouped = operation.Parameters 25 | .Where(p => p.In == ParameterLocation.Query || p.In == ParameterLocation.Path) 26 | .GroupBy(r => r.Name); 27 | 28 | var queryAndPath = grouped.Select(r => r.OrderBy(p => p.In).First()).ToList(); 29 | 30 | operation.Parameters.ToList() 31 | .RemoveAll(p => p.In == ParameterLocation.Query || p.In == ParameterLocation.Path); 32 | 33 | operation.Parameters.ToList().AddRange(queryAndPath); 34 | } 35 | 36 | if (context.ApiDescription.ParameterDescriptions != null) 37 | { 38 | foreach (var param in context.ApiDescription.ParameterDescriptions) 39 | { 40 | param.Name = param.Name.GetValueConsideringCurrentCase(); 41 | } 42 | } 43 | 44 | var path = context.ApiDescription.RelativePath; 45 | var matches = Regex.Matches(path, @"[{]{1}[\w\\_]*[}]{1}"); 46 | 47 | foreach (var match in matches) 48 | { 49 | var oldValue = match.ToString(); 50 | var newValue = "{" + oldValue.TrimStart('{').TrimEnd('}').GetValueConsideringCurrentCase() + "}"; 51 | path = path.Replace(oldValue, newValue); 52 | } 53 | 54 | context.ApiDescription.RelativePath = path; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/ExceptionHandler/ExceptionHandlerMiddleware.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.JsonSerializer; 2 | using AspNetScaffolding.Models; 3 | using AspNetScaffolding.Utilities; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Http; 6 | using Newtonsoft.Json; 7 | using System; 8 | using System.Net; 9 | using System.Threading.Tasks; 10 | using WebApi.Models.Exceptions; 11 | using WebApi.Models.Helpers; 12 | using WebApi.Models.Response; 13 | 14 | namespace AspNetScaffolding.Extensions.ExceptionHandler 15 | { 16 | public class ExceptionHandlerMiddleware 17 | { 18 | private readonly RequestDelegate Next; 19 | 20 | private readonly bool IsDevelopment; 21 | 22 | public static Func ChangeErrorFormat; 23 | 24 | public ExceptionHandlerMiddleware(RequestDelegate next) 25 | { 26 | Next = next; 27 | 28 | IsDevelopment = EnvironmentUtility.IsDevelopment(); 29 | } 30 | 31 | public async Task Invoke(HttpContext context) 32 | { 33 | try 34 | { 35 | await Next(context); 36 | } 37 | catch (Exception ex) 38 | { 39 | await HandleExceptionAsync(context, ex, IsDevelopment); 40 | } 41 | } 42 | 43 | private static Task HandleExceptionAsync(HttpContext context, Exception exception, bool isDevelopment) 44 | { 45 | try 46 | { 47 | context.Request.Body.Position = 0; 48 | } 49 | catch { } 50 | 51 | if (exception is ApiException) 52 | { 53 | return ApiException(context, (ApiException)exception); 54 | } 55 | else 56 | { 57 | return GenericError(context, exception, isDevelopment); 58 | } 59 | } 60 | 61 | private static Task GenericError(HttpContext context, Exception exception, bool isDevelopment) 62 | { 63 | context.Items.Add("Exception", exception); 64 | 65 | if (isDevelopment) 66 | { 67 | var exceptionContainer = new ExceptionContainer(exception); 68 | context.Response.WriteAsync(JsonConvert.SerializeObject(exceptionContainer, JsonSerializerService.JsonSerializerSettings)).Wait(); 69 | context.Response.Body.Position = 0; 70 | } 71 | 72 | context.Response.ContentType = "application/json"; 73 | context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; 74 | 75 | return Task.CompletedTask; 76 | } 77 | 78 | private static Task ApiException(HttpContext context, ApiException exception) 79 | { 80 | var apiResponse = exception.ToApiResponse(); 81 | 82 | var statusCode = (int)apiResponse.StatusCode; 83 | 84 | if (exception is PermanentRedirectException) 85 | { 86 | statusCode = 308; 87 | var location = $"{Api.ApiSettings.AppUrl.Trim('/')}{context.Request.Path}{context.Request.QueryString}"; 88 | 89 | context.Response.Headers["Location"] = location; 90 | } 91 | 92 | context.Response.ContentType = "application/json"; 93 | context.Response.StatusCode = statusCode; 94 | 95 | if (apiResponse.Content != null && ChangeErrorFormat == null) 96 | { 97 | context.Response.WriteAsync(JsonConvert.SerializeObject(apiResponse.Content, JsonSerializerService.JsonSerializerSettings)).Wait(); 98 | context.Response.Body.Position = 0; 99 | } 100 | else if (ChangeErrorFormat != null) 101 | { 102 | var content = ChangeErrorFormat.Invoke(exception); 103 | context.Response.WriteAsync(JsonConvert.SerializeObject(content, JsonSerializerService.JsonSerializerSettings)).Wait(); 104 | context.Response.Body.Position = 0; 105 | } 106 | 107 | return Task.CompletedTask; 108 | } 109 | } 110 | 111 | public static class ExceptionHandlerMiddlewareExtension 112 | { 113 | public static void UseScaffoldingExceptionHandler(this IApplicationBuilder app) 114 | { 115 | app.UseMiddleware(); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/GracefullShutdown/GracefullShutdownExtensions.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using WebApi.Models.Exceptions; 6 | 7 | namespace AspNetScaffolding.Extensions.GracefullShutdown 8 | { 9 | public static class GracefullShutdownExtensions 10 | { 11 | public static void ValidationShutdown(this ControllerBase controller) 12 | { 13 | if (Api.ShutdownSettings?.Enabled == false) 14 | { 15 | if (Api.ShutdownSettings.GracefullShutdownState.StopRequested && Api.ShutdownSettings.Redirect) 16 | { 17 | throw new PermanentRedirectException(null); 18 | } 19 | else if (Api.ShutdownSettings.GracefullShutdownState.StopRequested) 20 | { 21 | throw new ServiceUnavailableException("Service is unavailable for temporary maintenance"); 22 | } 23 | } 24 | } 25 | 26 | public static IApplicationBuilder UseGracefullShutdown(this IApplicationBuilder builder) 27 | { 28 | if (Api.ShutdownSettings?.Enabled != true) 29 | { 30 | return builder; 31 | } 32 | 33 | return builder.UseMiddleware(); 34 | } 35 | 36 | public static IServiceCollection AddGracefullShutdown(this IServiceCollection services) 37 | { 38 | services.AddSingleton(Api.ShutdownSettings.GracefullShutdownState); 39 | services.AddSingleton(Api.ShutdownSettings.GracefullShutdownState); 40 | 41 | return services; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/GracefullShutdown/GracefullShutdownMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.Extensions.Hosting; 3 | using Serilog; 4 | using Serilog.Context; 5 | using System; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace AspNetScaffolding.Extensions.GracefullShutdown 10 | { 11 | public class GracefullShutdownMiddleware 12 | { 13 | private readonly RequestDelegate Next; 14 | 15 | private readonly ShutdownSettings ShutdownSettings; 16 | 17 | private readonly GracefullShutdownState State; 18 | 19 | private DateTime ShutdownStarted; 20 | 21 | public GracefullShutdownMiddleware( 22 | RequestDelegate next, 23 | IHostApplicationLifetime applicationLifetime, 24 | GracefullShutdownState state 25 | ) 26 | { 27 | if (applicationLifetime == null) 28 | { 29 | throw new ArgumentNullException(nameof(applicationLifetime)); 30 | } 31 | 32 | Next = next ?? throw new ArgumentNullException(nameof(next)); 33 | ShutdownSettings = Api.ShutdownSettings; 34 | State = state ?? throw new ArgumentNullException(nameof(state)); 35 | 36 | applicationLifetime.ApplicationStopping.Register(OnApplicationStopping); 37 | applicationLifetime.ApplicationStopped.Register(OnApplicationStopped); 38 | 39 | EventHandler waitFinish = (sender, e) => OnApplicationStopped(); 40 | AppDomain.CurrentDomain.ProcessExit += waitFinish; 41 | } 42 | 43 | public async Task Invoke(HttpContext context) 44 | { 45 | var ignoredRequest = State.StopRequested; 46 | 47 | if (!ignoredRequest) 48 | { 49 | State.NotifyRequestStarted(); 50 | } 51 | 52 | try 53 | { 54 | await Next.Invoke(context); 55 | } 56 | finally 57 | { 58 | if (!ignoredRequest) 59 | { 60 | State.NotifyRequestFinished(); 61 | } 62 | } 63 | } 64 | 65 | private void OnApplicationStopping() 66 | { 67 | ShutdownStarted = DateTime.UtcNow; 68 | State.NotifyStopRequested(); 69 | } 70 | 71 | private void OnApplicationStopped() 72 | { 73 | var shutdownLimit = ShutdownStarted.Add(ShutdownSettings.ShutdownTimeoutTimeSpan); 74 | 75 | while (State.RequestsInProgress > 0 && DateTime.UtcNow < shutdownLimit) 76 | { 77 | LogInfo("Application stopping, requests in progress: {RequestsInProgress}", State.RequestsInProgress); 78 | Thread.Sleep(1000); 79 | } 80 | 81 | if (State.RequestsInProgress > 0) 82 | { 83 | LogError("Application stopped, requests in progress: {RequestsInProgress}", State.RequestsInProgress); 84 | } 85 | else 86 | { 87 | LogInfo("Application stopped, requests in progress: {RequestsInProgress}", State.RequestsInProgress); 88 | } 89 | 90 | Log.CloseAndFlush(); 91 | } 92 | 93 | public void LogInfo(string message, long requestsInProgress) 94 | { 95 | LogContext.PushProperty("RequestsInProgress", requestsInProgress); 96 | LogContext.PushProperty("Environment", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")); 97 | 98 | Log.Logger.Information(Api.LogSettings.TitlePrefix + " " + message); 99 | } 100 | 101 | public void LogError(string message, long requestsInProgress) 102 | { 103 | LogContext.PushProperty("RequestsInProgress", requestsInProgress); 104 | LogContext.PushProperty("Environment", Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")); 105 | 106 | Log.Logger.Error(Api.LogSettings.TitlePrefix + " " + message); 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/GracefullShutdown/GracefullShutdownState.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | 3 | namespace AspNetScaffolding.Extensions.GracefullShutdown 4 | { 5 | public class GracefullShutdownState : IRequestsCountProvider 6 | { 7 | private long _requestsInProgress; 8 | public long RequestsInProgress => Volatile.Read(ref _requestsInProgress); 9 | 10 | private long _requestsProcessed; 11 | public long RequestsProcessed => Volatile.Read(ref _requestsProcessed); 12 | 13 | private bool _stopRequested; 14 | public bool StopRequested => Volatile.Read(ref _stopRequested); 15 | 16 | public void NotifyRequestStarted() 17 | { 18 | Interlocked.Increment(ref _requestsInProgress); 19 | } 20 | 21 | public void NotifyRequestFinished() 22 | { 23 | Interlocked.Decrement(ref _requestsInProgress); 24 | Interlocked.Increment(ref _requestsProcessed); 25 | } 26 | 27 | public void NotifyStopRequested() 28 | { 29 | Volatile.Write(ref _stopRequested, true); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/GracefullShutdown/IRequestsCountProvider.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding.Extensions.GracefullShutdown 2 | { 3 | public interface IRequestsCountProvider 4 | { 5 | long RequestsInProgress { get; } 6 | 7 | long RequestsProcessed { get; } 8 | 9 | void NotifyRequestStarted(); 10 | 11 | void NotifyRequestFinished(); 12 | 13 | void NotifyStopRequested(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/GracefullShutdown/ShutdownSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspNetScaffolding.Extensions.GracefullShutdown 4 | { 5 | public class ShutdownSettings 6 | { 7 | /// 8 | /// enables gracefull shutdown 9 | /// 10 | public bool Enabled { get; set; } 11 | 12 | /// 13 | /// false - incoming requests will get 500 code after shutdown initiation 14 | /// true - incoming requests will be redirected with 308 code, and same url 15 | /// 16 | public bool Redirect { get; set; } 17 | 18 | /// 19 | /// forces shutdown after X seconds 20 | /// 21 | public int ShutdownTimeoutInSeconds { get; set; } = 60; 22 | 23 | /// 24 | /// forces shutdown after X seconds - timespan format 25 | /// 26 | public TimeSpan ShutdownTimeoutTimeSpan => TimeSpan.FromSeconds(ShutdownTimeoutInSeconds); 27 | 28 | /// 29 | /// State for gracefull shutdown 30 | /// 31 | public GracefullShutdownState GracefullShutdownState { get; set; } = new GracefullShutdownState(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Healthcheck/HealthcheckMiddleware.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Models; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Diagnostics.HealthChecks; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.Extensions.Diagnostics.HealthChecks; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Linq; 8 | using System.Linq; 9 | using System.Threading.Tasks; 10 | 11 | namespace AspNetScaffolding.Extensions.Healthcheck 12 | { 13 | public static class HealthcheckkMiddlewareExtension 14 | { 15 | public static void UseHealthcheck(this IApplicationBuilder app) 16 | { 17 | if (HealthcheckServiceExtension.HealthcheckSettings?.Enabled == true) 18 | { 19 | var options = new HealthCheckOptions 20 | { 21 | AllowCachingResponses = true, 22 | ResponseWriter = WriteResponse 23 | }; 24 | 25 | app.UseHealthChecks( 26 | GetFullPath(HealthcheckServiceExtension.ApiSettings, HealthcheckServiceExtension.HealthcheckSettings), options); 27 | } 28 | } 29 | 30 | private static Task WriteResponse(HttpContext httpContext, HealthReport result) 31 | { 32 | httpContext.Response.ContentType = "application/json"; 33 | 34 | var json = new JObject( 35 | new JProperty("status", result.Status.ToString().ToLowerInvariant()), 36 | new JProperty("results", new JObject(result.Entries.Select(pair => 37 | new JProperty(pair.Key, new JObject( 38 | new JProperty("status", pair.Value.Status.ToString().ToLowerInvariant()), 39 | new JProperty("description", pair.Value.Description), 40 | new JProperty("data", new JObject(pair.Value.Data.Select( 41 | p => new JProperty(p.Key, p.Value)))))))))); 42 | 43 | return httpContext.Response.WriteAsync( 44 | json.ToString(Formatting.Indented)); 45 | } 46 | 47 | public static string GetFullPath(ApiSettings apiSettings, HealthcheckSettings healthcheckSettings) 48 | { 49 | var basePath = apiSettings.GetPathPrefixConsideringVersion(); 50 | basePath = ((string.IsNullOrWhiteSpace(basePath) == false) ? "/" + basePath.Trim('/') : ""); 51 | var finalPathPart = healthcheckSettings.Path?.Trim('/'); 52 | 53 | return (basePath ?? "") + "/" + (finalPathPart ?? "healthcheck"); 54 | } 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Healthcheck/HealthcheckService.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Models; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using System; 4 | 5 | namespace AspNetScaffolding.Extensions.Healthcheck 6 | { 7 | public static class HealthcheckServiceExtension 8 | { 9 | public static HealthcheckSettings HealthcheckSettings { get; set; } 10 | 11 | public static ApiSettings ApiSettings { get; set; } 12 | 13 | public static void SetupHealthcheck( 14 | this IServiceCollection services, 15 | ApiSettings apiSettings, 16 | HealthcheckSettings healthcheckSettings, 17 | Action builderFunction) 18 | { 19 | HealthcheckSettings = healthcheckSettings; 20 | ApiSettings = apiSettings; 21 | 22 | if (healthcheckSettings?.Enabled == true) 23 | { 24 | var builder = services.AddHealthChecks(); 25 | builderFunction?.Invoke(builder, services.BuildServiceProvider()); 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Healthcheck/HealthcheckSettings.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding.Extensions.Healthcheck 2 | { 3 | public class HealthcheckSettings 4 | { 5 | public bool Enabled { get; set; } 6 | 7 | public string Path { get; set; } 8 | 9 | public bool LogEnabled { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/JsonFieldSelector/JsonFieldSelectorMiddleware.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.StreamExt; 2 | using JsonFieldSelector; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.AspNetCore.Http; 5 | using System; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace AspNetScaffolding.Extensions.JsonFieldSelector 11 | { 12 | public class JsonFieldSelectorMiddleware 13 | { 14 | private readonly RequestDelegate Next; 15 | 16 | private readonly string PropertyName; 17 | 18 | public JsonFieldSelectorMiddleware(RequestDelegate next) 19 | { 20 | this.Next = next; 21 | this.PropertyName = "fields"; 22 | } 23 | 24 | public JsonFieldSelectorMiddleware(RequestDelegate next, string property) 25 | { 26 | if (string.IsNullOrWhiteSpace(property)) 27 | { 28 | throw new ArgumentNullException(nameof(property)); 29 | } 30 | 31 | this.Next = next; 32 | this.PropertyName = property.ToLowerInvariant(); 33 | } 34 | 35 | public async Task Invoke(HttpContext context) 36 | { 37 | await this.Next(context); 38 | 39 | if (context.Request.Query.Any(r => r.Key.ToLowerInvariant() == this.PropertyName)) 40 | { 41 | var json = context.Response.Body.AsString(); 42 | 43 | if (string.IsNullOrWhiteSpace(json)) 44 | { 45 | return; 46 | } 47 | 48 | try 49 | { 50 | var fields = context.Request.Query 51 | .FirstOrDefault(r => r.Key.ToLowerInvariant() == this.PropertyName) 52 | .Value.ToString(); 53 | 54 | if (string.IsNullOrWhiteSpace(fields)) 55 | { 56 | json = "{ }"; 57 | } 58 | else 59 | { 60 | json = JsonFieldSelectorExtension.SelectFieldsFromString(json, fields); 61 | } 62 | } 63 | catch 64 | { 65 | json = "{ }"; 66 | } 67 | 68 | var length = Encoding.UTF8.GetBytes(json ?? "").Length; 69 | context.Response.Body.SetLength(length); 70 | context.Response.ContentLength = length; 71 | await context.Response.WriteAsync(json); 72 | } 73 | } 74 | } 75 | } 76 | 77 | namespace AspNetScaffolding.Extensions.JsonFieldSelector 78 | { 79 | public static class JsonFieldSelectorMiddlewareExtension 80 | { 81 | public static void UseJsonFieldSelector(this IApplicationBuilder app, string property = "fields", bool enabled = true) 82 | { 83 | if (enabled) 84 | { 85 | app.UseMiddleware(property); 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/JsonSerializer/CaseUtility.cs: -------------------------------------------------------------------------------- 1 | using PackUtils; 2 | 3 | namespace AspNetScaffolding.Extensions.JsonSerializer 4 | { 5 | public static class CaseUtility 6 | { 7 | public static JsonSerializerEnum JsonSerializerMode { get; set; } 8 | 9 | public static string GetValueConsideringCurrentCase(this string value) 10 | { 11 | if (string.IsNullOrEmpty(value)) 12 | { 13 | return string.Empty; 14 | } 15 | 16 | return value.ToCase(JsonSerializerMode.ToString()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/JsonSerializer/JsonSerializerEnum.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding.Extensions.JsonSerializer 2 | { 3 | public enum JsonSerializerEnum 4 | { 5 | Camelcase, 6 | Snakecase, 7 | Lowercase, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/JsonSerializer/JsonSerializerService.cs: -------------------------------------------------------------------------------- 1 | using CQRS.Extensions; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Newtonsoft.Json; 5 | using Newtonsoft.Json.Converters; 6 | using Newtonsoft.Json.Serialization; 7 | using PackUtils; 8 | using PackUtils.Converters; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | 13 | namespace AspNetScaffolding.Extensions.JsonSerializer 14 | { 15 | public static class JsonSerializerService 16 | { 17 | public static JsonSerializerSettings JsonSerializerSettings { get; set; } 18 | 19 | public static Newtonsoft.Json.JsonSerializer JsonSerializer { get; set; } 20 | 21 | public static void ConfigureJsonSettings( 22 | this IMvcBuilder mvc, 23 | IServiceCollection services, 24 | JsonSerializerEnum jsonSerializerMode, 25 | string timezoneHeaderName, 26 | TimeZoneInfo defaultTimeZone) 27 | { 28 | CaseUtility.JsonSerializerMode = jsonSerializerMode; 29 | 30 | JsonSerializerSettings = null; 31 | JsonSerializer = null; 32 | 33 | EnumWithContractJsonConverter.IgnoreEnumCase = Api.ApiSettings.UseOriginalEnumValue; 34 | 35 | switch (jsonSerializerMode) 36 | { 37 | case JsonSerializerEnum.Camelcase: 38 | JsonSerializer = JsonUtility.CamelCaseJsonSerializer; 39 | JsonSerializerSettings = JsonUtility.CamelCaseJsonSerializerSettings; 40 | break; 41 | case JsonSerializerEnum.Lowercase: 42 | JsonSerializer = JsonUtility.LowerCaseJsonSerializer; 43 | JsonSerializerSettings = JsonUtility.LowerCaseJsonSerializerSettings; 44 | break; 45 | case JsonSerializerEnum.Snakecase: 46 | JsonSerializer = JsonUtility.SnakeCaseJsonSerializer; 47 | JsonSerializerSettings = JsonUtility.SnakeCaseJsonSerializerSettings; 48 | break; 49 | default: 50 | break; 51 | } 52 | 53 | // for fluent validation in cqrs extensions 54 | PropertyName.Resolver = (propertyName) => 55 | { 56 | var parts = propertyName.Split('.'); 57 | return string.Join(".", parts.Select(r => r.ToCase(jsonSerializerMode.ToString()))); 58 | }; 59 | 60 | JsonConvert.DefaultSettings = () => JsonSerializerSettings; 61 | 62 | services.AddScoped((provider) => JsonSerializer); 63 | services.AddScoped((provider) => JsonSerializerSettings); 64 | 65 | DateTimeConverter.DefaultTimeZone = defaultTimeZone; 66 | mvc.AddNewtonsoftJson(options => 67 | { 68 | options.SerializerSettings.ContractResolver = JsonSerializerSettings.ContractResolver; 69 | options.SerializerSettings.NullValueHandling = JsonSerializerSettings.NullValueHandling; 70 | options.SerializerSettings.Converters.Add(new DateTimeConverter(() => 71 | { 72 | var httpContextAccessor = services.BuildServiceProvider().GetService(); 73 | return DateTimeConverter.GetTimeZoneByAspNetHeader(httpContextAccessor, timezoneHeaderName); 74 | })); 75 | foreach (var converter in JsonSerializerSettings.Converters) 76 | { 77 | options.SerializerSettings.Converters.Add(converter); 78 | } 79 | }); 80 | } 81 | 82 | public static IList Clone(IList listToClone) where T : ICloneable 83 | { 84 | return listToClone.Select(item => (T)item.Clone()).ToList(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Logger/Formatters/SnakeCaseJsonValueFormatter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Serialization; 2 | using Serilog.Events; 3 | using Serilog.Formatting.Json; 4 | using System.IO; 5 | 6 | namespace AspNetScaffolding3.Extensions.Logger.Formatters 7 | { 8 | internal class SnakeCaseJsonValueFormatter : JsonValueFormatter 9 | { 10 | private readonly string _typeTagName; 11 | private readonly SnakeCaseNamingStrategy _strategy; 12 | 13 | public SnakeCaseJsonValueFormatter(SnakeCaseNamingStrategy snakeCaseStrategy, string typeTagName = "_typeTag") : base(typeTagName) 14 | { 15 | _typeTagName = typeTagName; 16 | _strategy = snakeCaseStrategy; 17 | } 18 | 19 | protected override bool VisitStructureValue(TextWriter state, StructureValue structure) 20 | { 21 | state.Write('{'); 22 | string value = ""; 23 | for (int i = 0; i < structure.Properties.Count; i++) 24 | { 25 | state.Write(value); 26 | value = ","; 27 | LogEventProperty logEventProperty = structure.Properties[i]; 28 | WriteQuotedJsonString(_strategy.GetPropertyName(logEventProperty.Name, false), state); 29 | state.Write(':'); 30 | Visit(state, logEventProperty.Value); 31 | } 32 | 33 | if (_typeTagName != null && structure.TypeTag != null) 34 | { 35 | state.Write(value); 36 | WriteQuotedJsonString(_typeTagName, state); 37 | state.Write(':'); 38 | WriteQuotedJsonString(structure.TypeTag, state); 39 | } 40 | 41 | state.Write('}'); 42 | return false; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Logger/Formatters/SnakeCaseRenderedCompactJsonFormatter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Serialization; 2 | using Serilog.Events; 3 | using Serilog.Formatting.Compact; 4 | using Serilog.Formatting.Json; 5 | using Serilog.Formatting; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | using System; 9 | 10 | namespace AspNetScaffolding3.Extensions.Logger.Formatters 11 | { 12 | internal class SnakeCaseRenderedCompactJsonFormatter : ITextFormatter 13 | { 14 | private readonly SnakeCaseJsonValueFormatter _valueFormatter; 15 | private static readonly SnakeCaseNamingStrategy _strategy = new SnakeCaseNamingStrategy(); 16 | 17 | // 18 | // Summary: 19 | // Construct a Serilog.Formatting.Compact.CompactJsonFormatter, optionally supplying 20 | // a formatter for Serilog.Events.LogEventPropertyValues on the event. 21 | // 22 | // Parameters: 23 | // valueFormatter: 24 | // A value formatter, or null. 25 | public SnakeCaseRenderedCompactJsonFormatter(SnakeCaseJsonValueFormatter valueFormatter = null) 26 | { 27 | _valueFormatter = valueFormatter ?? new SnakeCaseJsonValueFormatter(_strategy, "$type"); 28 | } 29 | 30 | // 31 | // Summary: 32 | // Format the log event into the output. Subsequent events will be newline-delimited. 33 | // 34 | // 35 | // Parameters: 36 | // logEvent: 37 | // The event to format. 38 | // 39 | // output: 40 | // The output. 41 | public void Format(LogEvent logEvent, TextWriter output) 42 | { 43 | FormatEvent(logEvent, output, _valueFormatter); 44 | output.WriteLine(); 45 | } 46 | 47 | // 48 | // Summary: 49 | // Format the log event into the output. 50 | // 51 | // Parameters: 52 | // logEvent: 53 | // The event to format. 54 | // 55 | // output: 56 | // The output. 57 | // 58 | // valueFormatter: 59 | // A value formatter for Serilog.Events.LogEventPropertyValues on the event. 60 | public static void FormatEvent(LogEvent logEvent, TextWriter output, SnakeCaseJsonValueFormatter valueFormatter) 61 | { 62 | if (logEvent == null) 63 | { 64 | throw new ArgumentNullException("logEvent"); 65 | } 66 | 67 | if (output == null) 68 | { 69 | throw new ArgumentNullException("output"); 70 | } 71 | 72 | if (valueFormatter == null) 73 | { 74 | throw new ArgumentNullException("valueFormatter"); 75 | } 76 | 77 | output.Write("{\"@t\":\""); 78 | output.Write(logEvent.Timestamp.UtcDateTime.ToString("O")); 79 | output.Write("\",\"@m\":"); 80 | JsonValueFormatter.WriteQuotedJsonString(logEvent.MessageTemplate.Render(logEvent.Properties), output); 81 | output.Write(",\"@i\":\""); 82 | output.Write(EventIdHash.Compute(logEvent.MessageTemplate.Text).ToString("x8")); 83 | output.Write('"'); 84 | if (logEvent.Level != LogEventLevel.Information) 85 | { 86 | output.Write(",\"@l\":\""); 87 | output.Write(logEvent.Level); 88 | output.Write('"'); 89 | } 90 | 91 | if (logEvent.Exception != null) 92 | { 93 | output.Write(",\"@x\":"); 94 | JsonValueFormatter.WriteQuotedJsonString(logEvent.Exception.ToString(), output); 95 | } 96 | 97 | foreach (KeyValuePair property in logEvent.Properties) 98 | { 99 | string text = _strategy.GetPropertyName(property.Key, false); 100 | if (text.Length > 0 && text[0] == '@') 101 | { 102 | text = "@" + text; 103 | } 104 | 105 | output.Write(','); 106 | JsonValueFormatter.WriteQuotedJsonString(text, output); 107 | output.Write(':'); 108 | valueFormatter.Format(property.Value, output); 109 | } 110 | 111 | output.Write('}'); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Logger/ISimpleLogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace AspNetScaffolding.Extensions.Logger 7 | { 8 | public interface ISimpleLogger 9 | { 10 | void Error(string controller, string operation, string message, Exception exception, object additionalData = null); 11 | 12 | void Warning(string controller, string operation, string message, Exception exception, object additionalData = null); 13 | 14 | void Fatal(string controller, string operation, string message, Exception exception, object additionalData = null); 15 | 16 | void Info(string controller, string operation, string message, object additionalData = null); 17 | 18 | void Verbose(string controller, string operation, string message, object additionalData = null); 19 | 20 | void Debug(string controller, string operation, string message, object additionalData = null); 21 | 22 | void Error(string message, Exception exception, object additionalData = null); 23 | 24 | void Warning(string message, Exception exception, object additionalData = null); 25 | 26 | void Fatal(string message, Exception exception, object additionalData = null); 27 | 28 | void Info(string message, object additionalData = null); 29 | 30 | void Verbose(string message, object additionalData = null); 31 | 32 | void Debug(string message, object additionalData = null); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Logger/LoggerBuilderExtension.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.Logger; 2 | 3 | using AspNetScaffolding3.Extensions.Logger.Formatters; 4 | 5 | using Serilog; 6 | using Serilog.Builder; 7 | using Serilog.Formatting.Json; 8 | 9 | namespace AspNetScaffolding3.Extensions.Logger 10 | { 11 | public static class LoggerBuilderExtension 12 | { 13 | public static LoggerBuilder DisableConsoleIfConsoleSinkIsEnabled(this LoggerBuilder loggerBuilder, ScaffoldingConsoleOptions? consoleOptions = null) 14 | { 15 | if (consoleOptions?.Enabled ?? false) 16 | { 17 | loggerBuilder.DisableConsole(); 18 | } 19 | 20 | return loggerBuilder; 21 | } 22 | 23 | public static LoggerConfiguration EnableStdOutput(this LoggerConfiguration loggerConfiguration, ScaffoldingConsoleOptions consoleOptions = null) 24 | { 25 | if (consoleOptions?.Enabled ?? false) 26 | { 27 | var minimmumLevel = consoleOptions.MinimumLevel ?? Serilog.Events.LogEventLevel.Verbose; 28 | return consoleOptions.FormatterType switch 29 | { 30 | EConsoleEnricherFormatter.SnakeCase => loggerConfiguration.WriteTo.Console(new SnakeCaseRenderedCompactJsonFormatter(), minimmumLevel).Enrich.FromLogContext(), 31 | _ => loggerConfiguration.WriteTo.Console(formatter: new JsonFormatter(), minimmumLevel).Enrich.FromLogContext(), 32 | }; 33 | } 34 | 35 | return loggerConfiguration; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Logger/LoggerService.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.AccountId; 2 | using AspNetScaffolding.Extensions.RequestKey; 3 | using AspNetScaffolding.Extensions.TimeElapsed; 4 | using AspNetScaffolding.Utilities; 5 | using AspNetSerilog; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Serilog; 8 | using Serilog.Builder; 9 | using System; 10 | using System.Collections.Generic; 11 | using AspNetScaffolding3.Extensions.Logger; 12 | 13 | namespace AspNetScaffolding.Extensions.Logger 14 | { 15 | public static class LoggerServiceExtension 16 | { 17 | public static void SetupSerilog( 18 | this IServiceCollection services, 19 | string domain, 20 | string application, 21 | LoggerSettings settings, 22 | List ignoredRoutes) 23 | { 24 | var loggerBuilder = new LoggerBuilder(); 25 | 26 | if (settings?.NewRelicOptions?.Enabled == true && string.IsNullOrWhiteSpace(settings?.NewRelicOptions?.LicenseKey)) 27 | { 28 | settings.NewRelicOptions.LicenseKey = Environment.GetEnvironmentVariable("NEW_RELIC_LICENSE_KEY"); 29 | } 30 | 31 | Log.Logger = loggerBuilder 32 | .UseSuggestedSetting(domain, application) 33 | .SetupSeq(settings?.SeqOptions) 34 | .SetupSplunk(settings?.SplunkOptions) 35 | .SetupNewRelic(settings?.NewRelicOptions) 36 | .SetupDataDog(settings?.DataDogOptions) 37 | .SetupLapi(settings?.LapiOptions) 38 | .DisableConsoleIfConsoleSinkIsEnabled(settings?.ConsoleOptions) 39 | .BuildConfiguration() 40 | .EnableStdOutput(settings?.ConsoleOptions) 41 | .CreateLogger(); 42 | 43 | if (settings?.DebugEnabled ?? false) 44 | { 45 | loggerBuilder.EnableDebug(); 46 | } 47 | 48 | var config = new SerilogConfiguration 49 | { 50 | Version = Api.ApiSettings.BuildVersion, 51 | InformationTitle = settings?.TitlePrefix + settings?.GetInformationTitle(), 52 | ErrorTitle = settings?.TitlePrefix + settings?.GetErrorTitle(), 53 | BlacklistRequest = settings?.GetJsonBlacklistRequest(), 54 | BlacklistRequestPartial = settings?.JsonBlacklistRequestPartial, 55 | BlacklistResponse = settings?.JsonBlacklistResponse, 56 | BlacklistResponsePartial = settings?.JsonBlacklistResponsePartial, 57 | HeaderBlacklist = settings?.HeaderBlacklist, 58 | HttpContextBlacklist = settings?.HttpContextBlacklist, 59 | QueryStringBlacklist = settings?.QueryStringBlacklist, 60 | RequestKeyProperty = RequestKeyServiceExtension.RequestKeyHeaderName, 61 | AccountIdProperty = AccountIdServiceExtension.AccountIdHeaderName, 62 | TimeElapsedProperty = TimeElapsedServiceExtension.TimeElapsedHeaderName, 63 | IgnoredRoutes = ignoredRoutes 64 | }; 65 | 66 | StaticSimpleLogger.UpdateVersion(Api.ApiSettings.BuildVersion); 67 | StaticSimpleLogger.UpdateEnvironment(EnvironmentUtility.GetCurrentEnvironment()); 68 | 69 | if (settings.SetupSerilog is null) 70 | { 71 | services.SetupSerilog(config); 72 | } 73 | else 74 | { 75 | settings.SetupSerilog.Invoke(services, config); 76 | } 77 | 78 | services.AddScoped(); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Logger/LoggerSettings.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Builder.Models; 2 | using System; 3 | using System.Linq; 4 | using AspNetSerilog; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using System.Collections.Generic; 7 | 8 | namespace AspNetScaffolding.Extensions.Logger 9 | { 10 | public class LoggerSettings 11 | { 12 | public string TitlePrefix { get; set; } 13 | 14 | /// 15 | /// Previously JsonBlacklistRequest 16 | /// 17 | [Obsolete] 18 | public string[] JsonBlacklist { get; set; } 19 | 20 | public string[] GetJsonBlacklistRequest() 21 | { 22 | if (this.JsonBlacklistRequest?.Any() == true) 23 | { 24 | return this.JsonBlacklistRequest; 25 | } 26 | 27 | return this.JsonBlacklist; 28 | } 29 | 30 | public string[] JsonBlacklistRequest { get; set; } 31 | 32 | public Dictionary> JsonBlacklistRequestPartial { get; set; } 33 | 34 | public string[] JsonBlacklistResponse { get; set; } 35 | 36 | public Dictionary> JsonBlacklistResponsePartial { get; set; } 37 | 38 | public string[] HeaderBlacklist { get; set; } 39 | 40 | public string[] HttpContextBlacklist { get; set; } 41 | 42 | public string InformationTitle { get; set; } 43 | 44 | public string ErrorTitle { get; set; } 45 | 46 | public string[] QueryStringBlacklist { get; set; } 47 | 48 | public bool DebugEnabled { get; set; } 49 | 50 | public SeqOptions SeqOptions { get; set; } = new SeqOptions(); 51 | 52 | public SplunkOptions SplunkOptions { get; set; } = new SplunkOptions(); 53 | 54 | public NewRelicOptions NewRelicOptions { get; set; } = new NewRelicOptions(); 55 | 56 | public DataDogOptions DataDogOptions { get; set; } = new DataDogOptions(); 57 | 58 | public LapiOptions LapiOptions { get; set; } = new LapiOptions(); 59 | 60 | public AspNetScaffolding.Extensions.Logger.ScaffoldingConsoleOptions ConsoleOptions { get; set; } = new AspNetScaffolding.Extensions.Logger.ScaffoldingConsoleOptions(); 61 | 62 | public Action SetupSerilog { get; set; } 63 | 64 | public string[] IgnoredRoutes { get; set; } 65 | 66 | public string GetInformationTitle() 67 | { 68 | if (string.IsNullOrWhiteSpace(InformationTitle)) 69 | return CommunicationLogger.DefaultInformationTitle; 70 | 71 | return InformationTitle; 72 | } 73 | 74 | public string GetErrorTitle() 75 | { 76 | if (string.IsNullOrWhiteSpace(ErrorTitle)) 77 | return CommunicationLogger.DefaultErrorTitle; 78 | 79 | return ErrorTitle; 80 | } 81 | } 82 | 83 | public class ScaffoldingConsoleOptions : Serilog.Builder.Models.ConsoleOptions 84 | { 85 | public EConsoleEnricherFormatter FormatterType { get; set; } = EConsoleEnricherFormatter.Default; 86 | } 87 | 88 | public enum EConsoleEnricherFormatter 89 | { 90 | Default, 91 | SnakeCase 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Logger/SimpleLogger.cs: -------------------------------------------------------------------------------- 1 | using PackUtils; 2 | using Serilog; 3 | using Serilog.Context; 4 | using System; 5 | using System.Diagnostics; 6 | using RK = AspNetScaffolding.Extensions.RequestKey; 7 | 8 | namespace AspNetScaffolding.Extensions.Logger 9 | { 10 | public class SimpleLogger : ISimpleLogger 11 | { 12 | public RK.RequestKey RequestKey { get; set; } 13 | 14 | public SimpleLogger(RK.RequestKey requestKey) 15 | { 16 | this.RequestKey = requestKey; 17 | } 18 | 19 | public void Error(string controller, string operation, string message, Exception exception, object additionalData = null) 20 | { 21 | StaticSimpleLogger.Error(controller, operation, message, exception, this.RequestKey.Value, additionalData); 22 | } 23 | 24 | public void Warning(string controller, string operation, string message, Exception exception, object additionalData = null) 25 | { 26 | StaticSimpleLogger.Warning(controller, operation, message, exception, this.RequestKey.Value, additionalData); 27 | } 28 | 29 | public void Fatal(string controller, string operation, string message, Exception exception, object additionalData = null) 30 | { 31 | StaticSimpleLogger.Fatal(controller, operation, message, exception, this.RequestKey.Value, additionalData); 32 | } 33 | 34 | public void Info(string controller, string operation, string message, object additionalData = null) 35 | { 36 | StaticSimpleLogger.Info(controller, operation, message, this.RequestKey.Value, additionalData); 37 | } 38 | 39 | public void Verbose(string controller, string operation, string message, object additionalData = null) 40 | { 41 | StaticSimpleLogger.Verbose(controller, operation, message, this.RequestKey.Value, additionalData); 42 | } 43 | 44 | public void Debug(string controller, string operation, string message, object additionalData = null) 45 | { 46 | StaticSimpleLogger.Debug(controller, operation, message, this.RequestKey.Value, additionalData); 47 | } 48 | 49 | public void Debug(string message, object additionalData = null) 50 | { 51 | StaticSimpleLogger.Debug(message, this.RequestKey.Value, additionalData); 52 | } 53 | 54 | public void Info(string message, object additionalData = null) 55 | { 56 | StaticSimpleLogger.Info(message, this.RequestKey.Value, additionalData); 57 | } 58 | 59 | public void Verbose(string message, object additionalData = null) 60 | { 61 | StaticSimpleLogger.Verbose(message, this.RequestKey.Value, additionalData); 62 | } 63 | 64 | public void Warning(string message, Exception exception = null, object additionalData = null) 65 | { 66 | StaticSimpleLogger.Warning(message, exception, this.RequestKey.Value, additionalData); 67 | } 68 | 69 | public void Error(string message, Exception exception = null, object additionalData = null) 70 | { 71 | StaticSimpleLogger.Error(message, exception, this.RequestKey.Value, additionalData); 72 | } 73 | 74 | public void Fatal(string message, Exception exception = null, object additionalData = null) 75 | { 76 | StaticSimpleLogger.Fatal(message, exception, this.RequestKey.Value, additionalData); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Mapper/MapperExtension.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using System.Collections.Generic; 3 | 4 | namespace AspNetScaffolding.Extensions.Mapper 5 | { 6 | public static class GlobalMapper 7 | { 8 | public static IMapper Mapper { get; set; } 9 | 10 | public static TDestination Map(this object source) 11 | where TDestination : class 12 | { 13 | return GlobalMapper.Mapper.Map(source); 14 | } 15 | 16 | public static TDestination Map(this TDestination destination, TSource source) 17 | where TSource : class 18 | where TDestination : class 19 | { 20 | return GlobalMapper.Mapper.Map(source, destination); 21 | } 22 | 23 | public static IEnumerable MapCollection(this IEnumerable source) 24 | where TDestination : class 25 | { 26 | return GlobalMapper.Mapper.Map>(source); 27 | } 28 | 29 | public static TDestination As(this object source) 30 | where TDestination : class 31 | { 32 | return GlobalMapper.Mapper.Map(source); 33 | } 34 | 35 | public static TDestination As(this TDestination destination, TSource source) 36 | where TSource : class 37 | where TDestination : class 38 | { 39 | return GlobalMapper.Mapper.Map(source, destination); 40 | } 41 | 42 | public static IEnumerable AsCollection(this IEnumerable source) 43 | where TDestination : class 44 | { 45 | return GlobalMapper.Mapper.Map>(source); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Mapper/MapperService.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.DependencyModel; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Reflection; 8 | 9 | namespace AspNetScaffolding.Extensions.Mapper 10 | { 11 | public static class MapperService 12 | { 13 | public static void SetupAutoMapper(this IServiceCollection services) 14 | { 15 | var mapper = MapperService.GetMapper(); 16 | 17 | services.AddSingleton(mapper); 18 | 19 | GlobalMapper.Mapper = mapper; 20 | } 21 | 22 | public static void SetupAutoMapper() 23 | { 24 | var mapper = MapperService.GetMapper(); 25 | 26 | GlobalMapper.Mapper = mapper; 27 | } 28 | 29 | private static Assembly[] GetAssemblies() 30 | { 31 | var assemblies = new List(); 32 | var dependencies = DependencyContext.Default.RuntimeLibraries.Where(p => 33 | p.Type.Equals("Project", StringComparison.CurrentCultureIgnoreCase)); 34 | 35 | foreach (var library in dependencies) 36 | { 37 | var name = new AssemblyName(library.Name); 38 | var assembly = Assembly.Load(name); 39 | assemblies.Add(assembly); 40 | } 41 | 42 | assemblies.AddRange(Api.ApiBasicConfiguration.AutoRegisterAssemblies); 43 | 44 | return assemblies.ToArray(); 45 | } 46 | 47 | private static IMapper GetMapper() 48 | { 49 | var profiles = MapperService.GetAssemblies() 50 | .SelectMany(p => p.GetTypes()) 51 | .Where(p => p.GetTypeInfo().BaseType == typeof(Profile)); 52 | 53 | var configuration = new MapperConfiguration(cfg => 54 | { 55 | cfg.AllowNullCollections = true; 56 | cfg.AllowNullDestinationValues = true; 57 | foreach (var profile in profiles) 58 | { 59 | cfg.AddProfile(Activator.CreateInstance(profile) as Profile); 60 | } 61 | }); 62 | 63 | return configuration.CreateMapper(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Mvc/MvcBuilderExtension.cs: -------------------------------------------------------------------------------- 1 | using FluentValidation.AspNetCore; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | 7 | namespace AspNetScaffolding.Extensions.RequestKey 8 | { 9 | public static class MvcBuilderExtension 10 | { 11 | public static void RegisterAssembliesForControllers(this IMvcBuilder mvc, IEnumerable assemblies) 12 | { 13 | if (assemblies?.Any() == true) 14 | { 15 | assemblies.ToList().ForEach(assembly => mvc.AddApplicationPart(assembly)); 16 | } 17 | } 18 | 19 | public static void RegisterAssembliesForFluentValidation(this IMvcBuilder mvc, IEnumerable assemblies) 20 | { 21 | mvc.AddFluentValidation(fluent => 22 | { 23 | fluent.RegisterValidatorsFromAssemblyContaining(); 24 | fluent.ImplicitlyValidateChildProperties = true; 25 | 26 | if (assemblies?.Any() == true) 27 | { 28 | fluent.RegisterValidatorsFromAssemblies(assemblies); 29 | } 30 | }); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/QueryFormatter/PathFormatterSettings.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.JsonSerializer; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.ModelBinding; 4 | using Microsoft.AspNetCore.Routing; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | namespace AspNetScaffolding.Extensions.QueryFormatter 9 | { 10 | public static class PathFormatterSettings 11 | { 12 | public static void AddPathFormatter(this MvcOptions mvcOptions, JsonSerializerEnum jsonSerializer) 13 | { 14 | PathValueProvider.JsonSerializerMode = jsonSerializer; 15 | mvcOptions.ValueProviderFactories.Add(new PathValueProviderFactory()); 16 | } 17 | } 18 | 19 | public class PathValueProvider : RouteValueProvider, IValueProvider 20 | { 21 | public static JsonSerializerEnum JsonSerializerMode { get; set; } 22 | 23 | public PathValueProvider( 24 | BindingSource bindingSource, 25 | RouteValueDictionary values, 26 | System.Globalization.CultureInfo culture) 27 | : base(bindingSource, values, culture) 28 | { 29 | } 30 | 31 | public override bool ContainsPrefix(string prefix) 32 | { 33 | return base.ContainsPrefix(prefix.GetValueConsideringCurrentCase()); 34 | } 35 | 36 | public override ValueProviderResult GetValue(string key) 37 | { 38 | return base.GetValue(key.GetValueConsideringCurrentCase()); 39 | } 40 | } 41 | 42 | public class PathValueProviderFactory : IValueProviderFactory 43 | { 44 | public Task CreateValueProviderAsync(ValueProviderFactoryContext context) 45 | { 46 | if (context == null) 47 | { 48 | throw new ArgumentNullException(nameof(context)); 49 | } 50 | 51 | var valueProvider = new PathValueProvider( 52 | BindingSource.Query, 53 | context.ActionContext.HttpContext.GetRouteData().Values, 54 | System.Globalization.CultureInfo.CurrentCulture); 55 | 56 | context.ValueProviders.Add(valueProvider); 57 | 58 | return Task.CompletedTask; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/QueryFormatter/QueryFormatterSettings.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.JsonSerializer; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.AspNetCore.Mvc.ModelBinding; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | namespace AspNetScaffolding.Extensions.QueryFormatter 9 | { 10 | public static class QueryFormatterSettings 11 | { 12 | public static void AddQueryFormatter(this MvcOptions mvcOptions, JsonSerializerEnum jsonSerializer) 13 | { 14 | CaseQueryValueProvider.JsonSerializerMode = jsonSerializer; 15 | mvcOptions.ValueProviderFactories.Add(new CaseQueryValueProviderFactory()); 16 | } 17 | } 18 | 19 | public class CaseQueryValueProvider : QueryStringValueProvider, IValueProvider 20 | { 21 | public static JsonSerializerEnum JsonSerializerMode { get; set; } 22 | 23 | public CaseQueryValueProvider( 24 | BindingSource bindingSource, 25 | IQueryCollection values, 26 | System.Globalization.CultureInfo culture) 27 | : base(bindingSource, values, culture) 28 | { 29 | } 30 | 31 | public override bool ContainsPrefix(string prefix) 32 | { 33 | return base.ContainsPrefix(prefix.GetValueConsideringCurrentCase()); 34 | } 35 | 36 | public override ValueProviderResult GetValue(string key) 37 | { 38 | return base.GetValue(key.GetValueConsideringCurrentCase()); 39 | } 40 | 41 | } 42 | 43 | public class CaseQueryValueProviderFactory : IValueProviderFactory 44 | { 45 | public Task CreateValueProviderAsync(ValueProviderFactoryContext context) 46 | { 47 | if (context == null) 48 | { 49 | throw new ArgumentNullException(nameof(context)); 50 | } 51 | 52 | var valueProvider = new CaseQueryValueProvider( 53 | BindingSource.Query, 54 | context.ActionContext.HttpContext.Request.Query, 55 | System.Globalization.CultureInfo.CurrentCulture); 56 | 57 | context.ValueProviders.Add(valueProvider); 58 | 59 | return Task.CompletedTask; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Queue/ChannelFactory.cs: -------------------------------------------------------------------------------- 1 | using RabbitMQ.Client; 2 | using System; 3 | 4 | namespace AspNetScaffolding.Extensions.Queue 5 | { 6 | public interface IChannelFactory : IChannelFactory { } 7 | 8 | public class ChannelFactory : ChannelFactory, IChannelFactory { } 9 | 10 | public interface IChannelFactory : IDisposable 11 | { 12 | IModel Create(ConnectionFactory factory); 13 | } 14 | 15 | public class ChannelFactory : IChannelFactory 16 | { 17 | private readonly object Lock = new object(); 18 | 19 | private IConnection Connection; 20 | 21 | private IModel Model; 22 | 23 | public IModel Create(ConnectionFactory factory) 24 | { 25 | if (this.Connection == null) 26 | { 27 | lock (this.Lock) 28 | { 29 | if (this.Connection == null) 30 | { 31 | this.Connection = factory.CreateConnection(); 32 | } 33 | } 34 | } 35 | 36 | if (this.Model == null) 37 | { 38 | lock (this.Lock) 39 | { 40 | if (this.Model == null) 41 | { 42 | this.Model = this.Connection.CreateModel(); 43 | } 44 | } 45 | } 46 | 47 | return this.Model; 48 | } 49 | 50 | public void Dispose() 51 | { 52 | lock (this.Lock) 53 | { 54 | this.Model?.Close(); 55 | this.Model?.Dispose(); 56 | this.Model = null; 57 | this.Connection?.Close(); 58 | this.Connection?.Dispose(); 59 | this.Connection = null; 60 | } 61 | } 62 | } 63 | 64 | public static class StaticChannelFactory 65 | { 66 | private static readonly object Lock = new object(); 67 | 68 | private static IConnection Connection; 69 | 70 | private static IModel Model; 71 | 72 | public static IModel Create(ConnectionFactory factory) 73 | { 74 | if (Connection == null) 75 | { 76 | lock (Lock) 77 | { 78 | if (Connection == null) 79 | { 80 | Connection = factory.CreateConnection(); 81 | } 82 | } 83 | } 84 | 85 | if (Model == null) 86 | { 87 | lock (Lock) 88 | { 89 | if (Model == null) 90 | { 91 | Model = Connection.CreateModel(); 92 | } 93 | } 94 | } 95 | 96 | return Model; 97 | } 98 | 99 | public static void Dispose() 100 | { 101 | lock (Lock) 102 | { 103 | Model?.Close(); 104 | Model?.Dispose(); 105 | Model = null; 106 | Connection?.Close(); 107 | Connection?.Dispose(); 108 | Connection = null; 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Queue/Interfaces/IQueueClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace AspNetScaffolding.Extensions.Queue.Interfaces 5 | { 6 | public interface IQueueClient 7 | { 8 | Func ReceiveMessage { get; set; } 9 | 10 | void AddRetryMessage(string message, int retryCount, string requestKey); 11 | 12 | void AddDeadMessage(string message, string requestKey); 13 | 14 | void AddMessage(string message, string requestKey); 15 | 16 | void Ack(ulong deliveryTag); 17 | 18 | void NAck(ulong deliveryTag, bool requeued = true); 19 | 20 | void TryConnect(); 21 | 22 | void Dispose(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Queue/Interfaces/IQueueProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace AspNetScaffolding.Extensions.Queue.Interfaces 5 | { 6 | public interface IQueueProcessor : IDisposable 7 | { 8 | bool ExecuteConsumer(Func> func); 9 | 10 | void HandleFailedEvent(string message, int retryCount, ulong deliveryTag, string requestKey); 11 | 12 | void HandleSuccededEvent(ulong deliveryTag); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Queue/QueueHealthcheck.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.Configuration; 2 | using AspNetScaffolding.Extensions.Queue.Interfaces; 3 | using CQRS.Extensions; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Converters; 8 | using Newtonsoft.Json.Serialization; 9 | using PackUtils; 10 | using PackUtils.Converters; 11 | using RabbitMQ.Client; 12 | using System; 13 | using System.Collections.Generic; 14 | using System.Linq; 15 | using System.Net.Security; 16 | 17 | namespace AspNetScaffolding.Extensions.Queue 18 | { 19 | public static class QueueHealthcheck 20 | { 21 | public static void AddRabbitMqAutomatic(this IHealthChecksBuilder builder, IServiceProvider provider) 22 | { 23 | var queueSettings = provider.GetService(); 24 | var sslOptions = new SslOption 25 | { 26 | Enabled = true, 27 | AcceptablePolicyErrors = SslPolicyErrors.RemoteCertificateNotAvailable | SslPolicyErrors.RemoteCertificateChainErrors | SslPolicyErrors.RemoteCertificateNameMismatch 28 | }; 29 | builder.AddRabbitMQ(queueSettings.QueueConnectionString, (queueSettings.UseSsl() ? sslOptions : null), "rabbitmq"); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Queue/QueueService.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.Configuration; 2 | using AspNetScaffolding.Extensions.Queue.Interfaces; 3 | using CQRS.Extensions; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Converters; 8 | using Newtonsoft.Json.Serialization; 9 | using PackUtils; 10 | using PackUtils.Converters; 11 | using System; 12 | using System.Collections.Generic; 13 | using System.Linq; 14 | 15 | namespace AspNetScaffolding.Extensions.Queue 16 | { 17 | public static class QueueService 18 | { 19 | public static void SetupQueue(this IServiceCollection services) 20 | { 21 | if (Api.QueueSettings?.Enabled == true) 22 | { 23 | services.AddSingleton(Api.QueueSettings); 24 | services.AddSingleton(); 25 | services.AddSingleton(provider => 26 | { 27 | var queueSettings = provider.GetService(); 28 | var queueClient = provider.GetService(); 29 | return new QueueProcessor(queueClient, queueSettings); 30 | }); 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Queue/QueueSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace AspNetScaffolding.Extensions.Queue 6 | { 7 | public class QueueSettings 8 | { 9 | public bool Enabled { get; set; } 10 | 11 | public int RetryTTL { get; set; } 12 | 13 | public double RetryTTLFactor { get; set; } 14 | 15 | public int GetCalculedRetryTTL(int retryCount) 16 | { 17 | return (int)(RetryTTL * Math.Pow(RetryTTLFactor, retryCount - 1)); 18 | } 19 | 20 | public int RetryCount { get; set; } 21 | 22 | public string QueueConnectionString { get; set; } 23 | 24 | public string VHostApi { get; set; } 25 | 26 | public string QueueName { get; set; } 27 | 28 | public int MaxThreads { get; set; } 29 | 30 | public bool AutoAckOnSuccess { get; set; } 31 | 32 | public string ExchangeToSubscribe { get; set; } 33 | 34 | public string EventsToSubscribe { get; set; } 35 | 36 | public List EventsToSubscribeAsList => this.EventsToSubscribe?.Split(',').ToList(); 37 | 38 | public bool UseSsl() 39 | { 40 | return this.QueueConnectionString.StartsWith("amqps"); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RequestKey/RequestKey.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding.Extensions.RequestKey 2 | { 3 | public class RequestKey 4 | { 5 | public RequestKey() { } 6 | 7 | public RequestKey(string value) 8 | { 9 | Value = value; 10 | } 11 | 12 | public string Value { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RequestKey/RequestKeyMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Http; 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | namespace AspNetScaffolding.Extensions.RequestKey 7 | { 8 | public class RequestKeyMiddleware : IMiddleware 9 | { 10 | private RequestKey RequestKey { get; set; } 11 | 12 | public RequestKeyMiddleware(RequestKey requestKey) 13 | { 14 | RequestKey = requestKey; 15 | } 16 | 17 | public async Task InvokeAsync(HttpContext context, RequestDelegate next) 18 | { 19 | try 20 | { 21 | context.Request.EnableBuffering(); 22 | } 23 | catch (Exception) { } 24 | 25 | if (context.Request.Headers.ContainsKey(RequestKeyServiceExtension.RequestKeyHeaderName)) 26 | { 27 | RequestKey.Value = context.Request.Headers[RequestKeyServiceExtension.RequestKeyHeaderName]; 28 | } 29 | else 30 | { 31 | RequestKey.Value = Guid.NewGuid().ToString(); 32 | } 33 | 34 | context.Items.Add(RequestKeyServiceExtension.RequestKeyHeaderName, RequestKey.Value); 35 | context.Response.Headers.Add(RequestKeyServiceExtension.RequestKeyHeaderName, RequestKey.Value); 36 | 37 | await next(context); 38 | } 39 | } 40 | 41 | public static class RequestKeyMiddlewareExtension 42 | { 43 | public static void UseRequestKey(this IApplicationBuilder app) 44 | { 45 | app.UseMiddleware(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RequestKey/RequestKeyService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace AspNetScaffolding.Extensions.RequestKey 4 | { 5 | public static class RequestKeyServiceExtension 6 | { 7 | public static string RequestKeyHeaderName = "RequestKey"; 8 | 9 | public static void SetupRequestKey(this IServiceCollection services, string headerName = null) 10 | { 11 | if (string.IsNullOrWhiteSpace(headerName) == false) 12 | { 13 | RequestKeyHeaderName = headerName; 14 | } 15 | 16 | services.AddScoped(); 17 | services.AddScoped(obj => new RequestKey()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RequestLimit/CustomRateLimitConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AspNetCoreRateLimit; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.Extensions.Options; 4 | 5 | namespace AspNetScaffolding3.Extensions.RequestLimit 6 | { 7 | public class CustomRateLimitConfiguration : RateLimitConfiguration 8 | { 9 | public CustomRateLimitConfiguration( 10 | IHttpContextAccessor httpContextAccessor, 11 | IOptions ipOptions, 12 | IOptions clientOptions) : base(httpContextAccessor, ipOptions, clientOptions) 13 | { 14 | } 15 | 16 | protected override void RegisterResolvers() 17 | { 18 | base.RegisterResolvers(); 19 | 20 | ClientResolvers.Add(new UrlResourceRateLimitContributor(HttpContextAccessor)); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RequestLimit/IpRateLimitingAdditional.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding.Extensions.RequestLimit 2 | { 3 | public class IpRateLimitingAdditional 4 | { 5 | public bool Enabled { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RequestLimit/IpRateLimitingService.cs: -------------------------------------------------------------------------------- 1 | using AspNetCoreRateLimit; 2 | using AspNetScaffolding.Extensions.Cache; 3 | using AspNetScaffolding3.Extensions.RequestLimit; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using System; 6 | 7 | namespace AspNetScaffolding.Extensions.RequestLimit 8 | { 9 | public static class IpRateLimitingService 10 | { 11 | public static void SetupIpRateLimiting( 12 | this IServiceCollection services, 13 | RateLimitingAdditional rateLimitingAdditional, 14 | CacheSettings cacheSettings) 15 | { 16 | if (rateLimitingAdditional?.Enabled == true) 17 | { 18 | if (cacheSettings?.Enabled != true) 19 | { 20 | throw new ArgumentException("CacheSettings must be enabled to use IpRateLimit"); 21 | } 22 | 23 | if (rateLimitingAdditional.ByUrlResource) 24 | { 25 | services.Configure(Api.ConfigurationRoot.GetSection("RateLimiting")); 26 | services.Configure(Api.ConfigurationRoot.GetSection("RateLimitPolicies")); 27 | services.AddSingleton(); 28 | UrlResourceRateLimitContributor.UrlResource = rateLimitingAdditional.UrlResource; 29 | } 30 | else if (rateLimitingAdditional.ByClientIdHeader) 31 | { 32 | services.Configure(Api.ConfigurationRoot.GetSection("RateLimiting")); 33 | services.Configure(Api.ConfigurationRoot.GetSection("ClientRateLimitPolicies")); 34 | services.AddSingleton(); 35 | } 36 | else 37 | { 38 | services.Configure(Api.ConfigurationRoot.GetSection("IpRateLimiting")); 39 | services.Configure(Api.ConfigurationRoot.GetSection("IpRateLimitPolicies")); 40 | services.AddSingleton(); 41 | } 42 | 43 | if (cacheSettings.UseRedis) 44 | { 45 | if (rateLimitingAdditional.ByClientIdHeader) 46 | { 47 | services.AddSingleton(); 48 | } 49 | else 50 | { 51 | services.AddSingleton(); 52 | } 53 | 54 | services.AddSingleton(); 55 | } 56 | else 57 | { 58 | if (rateLimitingAdditional.ByClientIdHeader) 59 | { 60 | services.AddSingleton(); 61 | } 62 | else 63 | { 64 | services.AddSingleton(); 65 | } 66 | 67 | services.AddSingleton(); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RequestLimit/RateLimitingAdditional.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding3.Extensions.RequestLimit 2 | { 3 | /// 4 | /// Was created only to keep retrocompatibility with older verions. This could be the same as the IpRateLimitingAdditional class 5 | /// 6 | public class RateLimitingAdditional 7 | { 8 | public bool Enabled { get; set; } 9 | 10 | public bool ByUrlResource { get; set; } 11 | 12 | public bool ByClientIdHeader { get; set; } 13 | 14 | public string UrlResource { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RequestLimit/UrlResourceRateLimitContributor.cs: -------------------------------------------------------------------------------- 1 | using AspNetCoreRateLimit; 2 | using Microsoft.AspNetCore.Http; 3 | 4 | namespace AspNetScaffolding3.Extensions.RequestLimit 5 | { 6 | public class UrlResourceRateLimitContributor : IClientResolveContributor 7 | { 8 | public static string UrlResource; 9 | 10 | private IHttpContextAccessor httpContextAccessor; 11 | 12 | public UrlResourceRateLimitContributor(IHttpContextAccessor httpContextAccessor) 13 | { 14 | this.httpContextAccessor = httpContextAccessor; 15 | } 16 | 17 | public string ResolveClient() 18 | { 19 | string clientId = null; 20 | 21 | string[] urlSections = this.httpContextAccessor.HttpContext.Request.Path.Value?.Split('/'); 22 | 23 | for (int urlSectionPosition = 0; urlSectionPosition < urlSections.Length && clientId == null; urlSectionPosition++) 24 | { 25 | if (urlSections[urlSectionPosition] == UrlResource) 26 | { 27 | clientId = urlSections[urlSectionPosition + 1]; 28 | } 29 | } 30 | 31 | return clientId; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RoutePrefix/IgnoreRoutePrefixAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.Filters; 2 | using System; 3 | 4 | namespace AspNetScaffolding.Extensions.RoutePrefix 5 | { 6 | public class IgnoreRoutePrefixAttribute : Attribute, IActionFilter, IFilterMetadata 7 | { 8 | public bool AllowMultiple => false; 9 | 10 | public void OnActionExecuted(ActionExecutedContext context) 11 | { 12 | } 13 | 14 | public void OnActionExecuting(ActionExecutingContext context) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RoutePrefix/RoutePrefixAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.ApplicationModels; 2 | using Microsoft.AspNetCore.Mvc.Routing; 3 | using System.Linq; 4 | 5 | namespace AspNetScaffolding.Extensions.RoutePrefix 6 | { 7 | public class RoutePrefixConvention : IApplicationModelConvention 8 | { 9 | private readonly AttributeRouteModel CentralPrefix; 10 | 11 | public RoutePrefixConvention(IRouteTemplateProvider routeTemplateProvider) 12 | { 13 | CentralPrefix = new AttributeRouteModel(routeTemplateProvider); 14 | } 15 | 16 | public void Apply(ApplicationModel application) 17 | { 18 | foreach (var controller in application.Controllers) 19 | { 20 | var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList(); 21 | if (matchedSelectors.Any()) 22 | { 23 | foreach (var selectorModel in matchedSelectors) 24 | { 25 | if (selectorModel.EndpointMetadata.Any(r => r.GetType() == typeof(IgnoreRoutePrefixAttribute))) 26 | { 27 | continue; 28 | } 29 | 30 | selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(CentralPrefix, 31 | selectorModel.AttributeRouteModel); 32 | } 33 | } 34 | 35 | var unmatchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel == null).ToList(); 36 | if (unmatchedSelectors.Any()) 37 | { 38 | foreach (var selectorModel in unmatchedSelectors) 39 | { 40 | if (selectorModel.EndpointMetadata.Any(r => r.GetType() == typeof(IgnoreRoutePrefixAttribute))) 41 | { 42 | continue; 43 | } 44 | 45 | selectorModel.AttributeRouteModel = CentralPrefix; 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/RoutePrefix/RoutePrefixExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace AspNetScaffolding.Extensions.RoutePrefix 4 | { 5 | public static class RoutePrefixExtensions 6 | { 7 | public static void UseCentralRoutePrefix(this MvcOptions mvcOptions, string pathPrefix) 8 | { 9 | var routeAttribute = new RouteAttribute(pathPrefix ?? ""); 10 | mvcOptions.Conventions.Insert(0, new RoutePrefixConvention(routeAttribute)); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/StreamExt/StreamExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace AspNetScaffolding.Extensions.StreamExt 6 | { 7 | public static class StreamExtension 8 | { 9 | public static string AsString(this Stream stream) 10 | { 11 | try 12 | { 13 | var result = ""; 14 | stream.Position = 0; 15 | using (var reader = new StreamReader(stream, Encoding.UTF8, true, 1024, true)) 16 | { 17 | result = reader.ReadToEnd(); 18 | } 19 | stream.Position = 0; 20 | 21 | return result; 22 | } 23 | catch (Exception) 24 | { 25 | return ""; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/TimeElapsed/TimeElapsedMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Http; 3 | using System.Diagnostics; 4 | using System.Threading.Tasks; 5 | 6 | namespace AspNetScaffolding.Extensions.TimeElapsed 7 | { 8 | public class TimeElapsedMiddleware 9 | { 10 | private readonly RequestDelegate Next; 11 | 12 | public TimeElapsedMiddleware(RequestDelegate next) 13 | { 14 | Next = next; 15 | } 16 | 17 | public async Task Invoke(HttpContext context) 18 | { 19 | var stopwatch = new Stopwatch(); 20 | string timeIsMs = "-1"; 21 | 22 | context.Response.OnStarting(() => 23 | { 24 | context.Response.Headers[TimeElapsedServiceExtension.TimeElapsedHeaderName] = timeIsMs; 25 | return Task.CompletedTask; 26 | }); 27 | 28 | stopwatch.Start(); 29 | 30 | await Next(context); 31 | 32 | stopwatch.Stop(); 33 | timeIsMs = stopwatch.ElapsedMilliseconds.ToString(); 34 | context.Items[TimeElapsedServiceExtension.TimeElapsedHeaderName] = timeIsMs; 35 | } 36 | } 37 | 38 | public static class TimeElapsedMiddlewareExtension 39 | { 40 | public static void UseTimeElapsed(this IApplicationBuilder app) 41 | { 42 | app.UseMiddleware(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/TimeElapsed/TimeElapsedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace AspNetScaffolding.Extensions.TimeElapsed 4 | { 5 | public static class TimeElapsedServiceExtension 6 | { 7 | public static string TimeElapsedHeaderName = "X-Internal-Time"; 8 | 9 | public static void SetupTimeElapsed(this IServiceCollection services, string headerName = null) 10 | { 11 | if (string.IsNullOrWhiteSpace(headerName) == false) 12 | { 13 | TimeElapsedHeaderName = headerName; 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Worker/BaseWorkerRunner.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.Logger; 2 | using AspNetScaffolding.Extensions.Queue.Interfaces; 3 | using AspNetScaffolding.Extensions.Worker.Interface; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace AspNetScaffolding.Extensions.Worker 11 | { 12 | public abstract class BaseWorkerRunner : IWorkerRunner 13 | { 14 | public BaseWorkerRunner(IQueueProcessor queueProcessor) 15 | { 16 | this.QueueProcessor = queueProcessor; 17 | } 18 | 19 | public IQueueProcessor QueueProcessor { get; set; } 20 | 21 | public Thread CurrentThread { get; set; } 22 | 23 | public abstract Task ExecuteAsync(string message, int retryCount, ulong deliveryTag, string requestKey); 24 | 25 | public void Start() 26 | { 27 | Task.Delay(1000).ContinueWith((state) => 28 | { 29 | this.CurrentThread.Start(); 30 | StaticSimpleLogger.Info("WorkerRunner", nameof(Start), "Worker started!"); 31 | }); 32 | } 33 | 34 | public void Stop() 35 | { 36 | StaticSimpleLogger.Info("WorkerRunner", nameof(Stop), "Worker stopped!"); 37 | Thread.Sleep(2000); 38 | this.CurrentThread.Abort(); 39 | } 40 | 41 | protected void InitFunction(Func> func) 42 | { 43 | this.CurrentThread = new Thread(() => 44 | { 45 | while (!this.QueueProcessor.ExecuteConsumer(func)) { } 46 | }); 47 | } 48 | } 49 | 50 | public class DemoWorkerRunner : BaseWorkerRunner 51 | { 52 | public DemoWorkerRunner(IQueueProcessor queueProcessor) : base(queueProcessor) 53 | { 54 | this.QueueProcessor = queueProcessor; 55 | this.InitFunction(ExecuteAsync); 56 | } 57 | 58 | public override async Task ExecuteAsync(string message, int retryCount, ulong deliveryTag, string requestKey) 59 | { 60 | await Task.Delay(1); 61 | 62 | Console.WriteLine($"Message: {message}"); 63 | 64 | return true; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Worker/Interface/IWorkerRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace AspNetScaffolding.Extensions.Worker.Interface 7 | { 8 | public interface IWorkerRunner 9 | { 10 | void Start(); 11 | 12 | void Stop(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Worker/WorkerService.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.Configuration; 2 | using AspNetScaffolding.Extensions.Queue.Interfaces; 3 | using AspNetScaffolding.Extensions.Worker; 4 | using AspNetScaffolding.Extensions.Worker.Interface; 5 | using CQRS.Extensions; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Newtonsoft.Json; 9 | using Newtonsoft.Json.Converters; 10 | using Newtonsoft.Json.Serialization; 11 | using PackUtils; 12 | using PackUtils.Converters; 13 | using System; 14 | using System.Collections.Generic; 15 | using System.Linq; 16 | 17 | namespace AspNetScaffolding.Extensions.Queue 18 | { 19 | public static class WorkerService 20 | { 21 | public static void SetupWorker(this IServiceCollection services) where T : BaseWorkerRunner 22 | { 23 | if (Api.WorkerSettings?.Enabled == true) 24 | { 25 | services.AddSingleton(); 26 | 27 | var provider = services.BuildServiceProvider(); 28 | 29 | provider.GetService().Start(); 30 | Console.CancelKeyPress += (sender, _event) => 31 | { 32 | provider.GetService().Stop(); 33 | }; 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /AspNetScaffolding3/Extensions/Worker/WorkerSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace AspNetScaffolding.Extensions.Worker 7 | { 8 | public class WorkerSettings 9 | { 10 | public bool Enabled { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Models/ApiBasicConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Reflection; 7 | 8 | namespace AspNetScaffolding.Models 9 | { 10 | public class ApiBasicConfiguration 11 | { 12 | public string ApiName { get; set; } 13 | 14 | public int ApiPort { get; set; } 15 | 16 | public string EnvironmentVariablesPrefix { get; set; } 17 | 18 | public IEnumerable AutoRegisterAssemblies { get; set; } = new List(); 19 | 20 | public Action ConfigureHealthcheck { get; set; } 21 | 22 | public Action ConfigureServices { get; set; } 23 | 24 | public Action ConfigureBefore { get; set; } 25 | 26 | public Action Configure { get; set; } 27 | 28 | public Action ConfigureAfter { get; set; } 29 | 30 | public Action ConfigureControllers { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Models/ApiSettings.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.JsonSerializer; 2 | using System; 3 | using TimeZoneConverter; 4 | 5 | namespace AspNetScaffolding.Models 6 | { 7 | public class ApiSettings 8 | { 9 | public ApiSettings() 10 | { 11 | Domain = "DefaultDomain"; 12 | Application = "DefaultApp"; 13 | TimezoneDefault = "UTC"; 14 | TimezoneHeader = "Timezone"; 15 | TimeElapsedProperty = "X-Internal-Time"; 16 | RequestKeyProperty = "RequestKey"; 17 | } 18 | 19 | public string AppUrl { get; set; } 20 | 21 | public string PathPrefix { get; set; } 22 | 23 | public string GetPathPrefixConsideringVersion() 24 | { 25 | string version = Version ?? null; 26 | 27 | return PathPrefix.Replace("{version}", version, StringComparison.OrdinalIgnoreCase); 28 | } 29 | 30 | public string Domain { get; set; } 31 | 32 | public string Application { get; set; } 33 | 34 | public string Version { get; set; } 35 | 36 | public string BuildVersion { get; set; } 37 | 38 | public JsonSerializerEnum JsonSerializer { get; set; } 39 | 40 | public string JsonSerializerString => Api.ApiSettings.JsonSerializer.ToString().ToLower(); 41 | 42 | public string[] SupportedCultures { get; set; } 43 | 44 | public string RequestKeyProperty { get; set; } 45 | 46 | public string AccountIdProperty { get; set; } 47 | 48 | public bool UseOriginalEnumValue { get; set; } 49 | 50 | public bool UseStaticFiles { get; set; } 51 | 52 | public string StaticFilesPath { get; set; } 53 | 54 | public string GetStaticFilesPath() 55 | { 56 | return $"/{this.GetPathPrefixConsideringVersion().TrimEnd('/')}/{this.StaticFilesPath}".Replace("//","/").TrimEnd('/'); 57 | } 58 | 59 | public string TimezoneHeader { get; set; } 60 | 61 | public string TimezoneDefault { get; set; } 62 | 63 | public TimeZoneInfo TimezoneDefaultInfo => TZConvert.GetTimeZoneInfo(TimezoneDefault); 64 | 65 | public string TimeElapsedProperty { get; set; } 66 | 67 | public string JsonFieldSelectorProperty { get; set; } 68 | 69 | public bool IsJsonFieldSelectorEnabled => !string.IsNullOrWhiteSpace(this.JsonFieldSelectorProperty); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Models/DatabaseSettings.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffolding.Models 2 | { 3 | public class DatabaseSettings 4 | { 5 | public string ConnectionString { get; set; } 6 | 7 | public string Name { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Models/ExceptionContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspNetScaffolding.Models 4 | { 5 | public class ExceptionContainer 6 | { 7 | public Exception Exception { get; set; } 8 | 9 | public ExceptionContainer(Exception exception) 10 | { 11 | Exception = exception; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Program.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Models; 2 | using System.Net; 3 | 4 | namespace AspNetScaffolding 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; 11 | ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 12 | 13 | var config = new ApiBasicConfiguration 14 | { 15 | ApiName = "My AspNet Scaffolding", 16 | ApiPort = 8700, 17 | EnvironmentVariablesPrefix = "Prefix_", 18 | ConfigureHealthcheck = Startup.ConfigureHealthcheck 19 | }; 20 | 21 | Api.Run(config); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Utilities/CQRSExtensions.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.JsonSerializer; 2 | using System.Linq; 3 | 4 | namespace AspNetScaffolding.Utilities 5 | { 6 | public static class CQRSExtensions 7 | { 8 | public static string PropertyNameResolver(string propertyName) 9 | { 10 | if (propertyName == null) 11 | { 12 | return null; 13 | } 14 | 15 | var parts = propertyName.Split(".").ToList(); 16 | return string.Join(".", parts.Select(i => i.GetValueConsideringCurrentCase())); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Utilities/EnvironmentUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspNetScaffolding.Utilities 4 | { 5 | public static class EnvironmentUtility 6 | { 7 | public static string GetCurrentEnvironment() 8 | { 9 | return Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"; 10 | } 11 | 12 | public static bool IsDevelopment() 13 | { 14 | var env = GetCurrentEnvironment(); 15 | 16 | return env.Contains("dev", StringComparison.InvariantCultureIgnoreCase); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Utilities/ObjectMappingExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AspNetScaffolding.Utilities 4 | { 5 | public static class ObjectMappingExtension 6 | { 7 | public static bool IsEligibleWheNotNull(this object srcMember, bool ignoreDefaultEnum = false) 8 | { 9 | if (srcMember == null) 10 | { 11 | return false; 12 | } 13 | 14 | if (ignoreDefaultEnum) 15 | { 16 | Type typeSrcMember = srcMember?.GetType(); 17 | if (typeSrcMember.IsEnum && typeSrcMember.GetEnumValues().GetValue(0).ToString().ToLower() == srcMember.ToString().ToLower()) 18 | { 19 | return false; 20 | } 21 | } 22 | 23 | if (srcMember.ToString() == Guid.Empty.ToString()) 24 | { 25 | return false; 26 | } 27 | 28 | return true; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Utilities/PipelineRExtension.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.JsonSerializer; 2 | using Microsoft.AspNetCore.Mvc; 3 | using PipelineR; 4 | using System.Linq; 5 | using WebApi.Models.Response; 6 | 7 | namespace AspNetScaffolding.Utilities 8 | { 9 | public static class PipelineRExtension 10 | { 11 | public static IActionResult AsActionResult(this RequestHandlerResult requestHandlerResult) 12 | { 13 | var responseObject = requestHandlerResult.Result(); 14 | 15 | if (requestHandlerResult.Errors != null) 16 | { 17 | var errorsResponse = new ErrorsResponse(); 18 | 19 | foreach (var error in requestHandlerResult.Errors) 20 | { 21 | string property = null; 22 | 23 | if (error.Property != null) 24 | { 25 | var parts = error.Property.Split(".").ToList(); 26 | 27 | if (parts.Count > 1) 28 | { 29 | parts.RemoveAt(0); 30 | } 31 | 32 | var finalParts = parts.Select(i => i.GetValueConsideringCurrentCase()); 33 | property = string.Join(".", finalParts); 34 | } 35 | 36 | errorsResponse.AddError(error.Message, property); 37 | } 38 | 39 | responseObject = errorsResponse; 40 | } 41 | 42 | return new ObjectResult(responseObject) 43 | { 44 | StatusCode = requestHandlerResult.StatusCode 45 | }; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AspNetScaffolding3/Utilities/RestsharpEasyExtension.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using RestSharp.Easy.Models; 3 | using WebApi.Models.Response; 4 | 5 | namespace AspNetScaffolding.Utilities 6 | { 7 | public static class RestsharpEasyExtension 8 | { 9 | public static IActionResult AsActionResult(this BaseResponse response) 10 | { 11 | object responseObj = response.Data; 12 | 13 | if (responseObj == null || !response.Is2XX) 14 | { 15 | responseObj = response.Error; 16 | } 17 | 18 | return new ObjectResult(responseObj) 19 | { 20 | StatusCode = (int) response.StatusCode 21 | }; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AspNetScaffolding3/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ApiSettings": { 3 | "AppUrl": "http://localhost:8700", 4 | "JsonSerializer": "Snakecase", 5 | "PathPrefix": "myapp/{version}", 6 | "Domain": "MyDomain", 7 | "UseStaticFiles": true, 8 | "StaticFilesPath": "assets", 9 | "Application": "MyApp", 10 | "Version": "v1", 11 | "UseOriginalEnumValue": true, 12 | "BuildVersion": "1.0.0", 13 | "SupportedCultures": [ "en-US", "pt-BR", "es-ES" ], 14 | "RequestKeyProperty": "RequestKey", 15 | "AccountIdProperty": "AccountId", 16 | "TimezoneHeader": "Timezone", 17 | "TimezoneDefault": "America/Sao_Paulo", 18 | "TimeElapsedProperty": "X-Internal-Time", 19 | "JsonFieldSelectorProperty": "fields" 20 | }, 21 | "WorkerSettings": { 22 | "Enabled": false 23 | }, 24 | "ShutdownSettings": { 25 | "ShutdownTimeoutInSeconds": 10, 26 | "Enabled": true, 27 | "Redirect": false 28 | }, 29 | "HealthcheckSettings": { 30 | "Enabled": true, 31 | "Path": "healthcheck", 32 | "LogEnabled": false 33 | }, 34 | "DbSettings": { 35 | "ConnectionString": "mongodb://user:pass@localhost:27017/DatabaseName", 36 | "Name": "DatabaseName" 37 | }, 38 | "CacheSettings": { 39 | "Enabled": false, 40 | "UseRedis": false, 41 | "UseLocker": false, 42 | "TimeoutInMs": 1000, 43 | "Ssl": false, 44 | "Password": "RedisAuth", 45 | "Host": "localhost", 46 | "Port": 6379, 47 | "LockerPrefix": "app-locker-", 48 | "LockerTtlInSeconds": 100, 49 | "LockerDb": 0, 50 | "CachePrefix": "app-cache-", 51 | "CacheTtlInSeconds": 900, 52 | "CacheDb": 0 53 | }, 54 | "RateLimiting": { 55 | "Enabled": false, 56 | "EnableEndpointRateLimiting": false, 57 | "StackBlockedRequests": false, 58 | "RealIpHeader": "X-Real-IP", 59 | "ClientIdHeader": "X-ClientId", 60 | "HttpStatusCode": 429, 61 | "IpWhitelist": [], 62 | "EndpointWhitelist": [], 63 | "ClientWhitelist": [], 64 | "ByUrlResource": false, 65 | "ByClientIdHeader": false, 66 | "UrlResource": "", 67 | "GeneralRules": [ 68 | { 69 | "Endpoint": "*", 70 | "Period": "1m", 71 | "Limit": 5 72 | }, 73 | { 74 | "Endpoint": "*", 75 | "Period": "1h", 76 | "Limit": 1000 77 | } 78 | ], 79 | "QuotaExceededResponse": { 80 | "Content": "{{ \"message\": \"Quota exceeded. Maximum allowed: {0} per {1}. Please try again in {2} second(s).\" }}", 81 | "ContentType": "application/json", 82 | "StatusCode": 429 83 | } 84 | }, 85 | "LogSettings": { 86 | "DebugEnabled": true, 87 | "TitlePrefix": "[{Application}] ", 88 | "JsonBlacklistRequest": [ "*password", "*card.number", "*creditcardnumber", "*cvv" ], 89 | "JsonBlacklistResponse": [ "*password", "*card.number", "*creditcardnumber", "*cvv" ], 90 | "IgnoredRoutes": [], 91 | "SeqOptions": { 92 | "Enabled": true, 93 | "MinimumLevel": "Verbose", 94 | "Url": "http://localhost:5341", 95 | "ApiKey": "XXXX" 96 | }, 97 | "NewRelicOptions": { 98 | "Enabled": false, 99 | "AppName": "Verbose", 100 | "LicenseKey": "XXXX" 101 | }, 102 | "SplunkOptions": { 103 | "Enabled": false, 104 | "MinimumLevel": "Verbose", 105 | "Url": "http://localhost:8088/services/collector", 106 | "Token": "XXXX", 107 | "Index": "my.index", 108 | "Application": "MyApp :Ds", 109 | "ProcessName": "Domain.App", 110 | "Company": "MyCompany", 111 | "ProductVersion": "1.0.0", 112 | "SourceType": "_json" 113 | }, 114 | "DataDogOptions": { 115 | "Enabled": false, 116 | "MinimumLevel": "Verbose", 117 | "ApiKey": "XXX", 118 | "Service": null, 119 | "Source": null, 120 | "Host": null, 121 | "Tags": [] 122 | }, 123 | "ConsoleOptions": { 124 | "Enabled": false, 125 | "MinimumLevel": "Verbose" 126 | } 127 | }, 128 | "DocsSettings": { 129 | "Enabled": true, 130 | "Title": "MyApp API Reference", 131 | "AuthorName": "Thiago Barradas", 132 | "AuthorEmail": "th.barradas@gmail.com", 133 | "PathToReadme": "DOCS.md", 134 | "IgnoredEnums": [ "none", "undefined" ] 135 | } 136 | } -------------------------------------------------------------------------------- /AspNetScaffolding3Tests/AspNetScaffolding3Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | all 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | all 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AspNetScaffolding3Tests/Extensions/Logger/LoggerSettingsTest.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Extensions.Logger; 2 | 3 | using Xunit; 4 | 5 | namespace AspNetScaffolding3Tests.Extensions.Logger 6 | { 7 | public class LoggerSettingsTest 8 | { 9 | private LoggerSettings _loggerSettings; 10 | 11 | public LoggerSettingsTest() 12 | { 13 | _loggerSettings = new LoggerSettings(); 14 | } 15 | 16 | [Fact] 17 | public void GetInformationTitle_InformingInformationTitle_ReturnsInformedValue() 18 | { 19 | var informationTitle = "Information Title"; 20 | _loggerSettings.InformationTitle = informationTitle; 21 | 22 | var expected = informationTitle; 23 | var actual = _loggerSettings.GetInformationTitle(); 24 | 25 | Assert.Equal(expected, actual); 26 | } 27 | 28 | [Fact] 29 | public void GetInformationTitle_InformationTitleEqualNull_ReturnDefaultValue() 30 | { 31 | var expected = "HTTP {Method} {Path} from {Ip} responded {StatusCode} in {ElapsedMilliseconds} ms"; 32 | var actual = _loggerSettings.GetInformationTitle(); 33 | 34 | Assert.Equal(expected, actual); 35 | } 36 | 37 | [Fact] 38 | public void GetInformationTitle_InformationTitleEqualEmpty_ReturnDefaultValue() 39 | { 40 | var informationTitle = " "; 41 | _loggerSettings.InformationTitle = informationTitle; 42 | 43 | var expected = "HTTP {Method} {Path} from {Ip} responded {StatusCode} in {ElapsedMilliseconds} ms"; 44 | var actual = _loggerSettings.GetInformationTitle(); 45 | 46 | Assert.Equal(expected, actual); 47 | } 48 | 49 | [Fact] 50 | public void GetErrorTitle_ErrorTitleTitle_ReturnsInformedValue() 51 | { 52 | var errorTitle = "Error Title"; 53 | _loggerSettings.ErrorTitle = errorTitle; 54 | 55 | var expected = errorTitle; 56 | var actual = _loggerSettings.GetErrorTitle(); 57 | 58 | Assert.Equal(expected, actual); 59 | } 60 | 61 | [Fact] 62 | public void GetErrorTitle_ErrorTitleEqualNull_ReturnDefaultValue() 63 | { 64 | var expected = "HTTP {Method} {Path} from {Ip} responded {StatusCode} in {ElapsedMilliseconds} ms"; 65 | var actual = _loggerSettings.GetErrorTitle(); 66 | 67 | Assert.Equal(expected, actual); 68 | } 69 | 70 | [Fact] 71 | public void GetErrorTitle_ErrorTitleEqualEmpty_ReturnDefaultValue() 72 | { 73 | var informationTitle = " "; 74 | _loggerSettings.ErrorTitle = informationTitle; 75 | 76 | var expected = "HTTP {Method} {Path} from {Ip} responded {StatusCode} in {ElapsedMilliseconds} ms"; 77 | var actual = _loggerSettings.GetErrorTitle(); 78 | 79 | Assert.Equal(expected, actual); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Thiago Barradas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Api/AspNetScaffoldingTemplate.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Always 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Api/Docs.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vulputate fringilla elementum. Praesent bibendum ipsum sed urna sagittis ultrices. Sed ac ligula ac arcu rutrum scelerisque at at mi. Suspendisse quis eleifend magna. Duis mattis, urna eget iaculis sodales, tortor nisl porttitor mauris, in posuere velit nulla in augue. In vel massa urna. Aenean in ultricies arcu. Nam porttitor libero risus, at sollicitudin lacus fringilla eget. Cras sit amet sapien dapibus, commodo nisi ac, vestibulum justo. Proin faucibus eget ipsum ut sollicitudin. Nulla sit amet quam nunc. Integer ante nulla, finibus eget velit non, sagittis tincidunt libero. -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Models; 2 | using System.Reflection; 3 | 4 | namespace AspNetScaffoldingTemplate.Api 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | var config = new ApiBasicConfiguration 11 | { 12 | ApiName = "My AspNet Scaffolding", 13 | ApiPort = 80, 14 | EnvironmentVariablesPrefix = "Prefix_", 15 | ConfigureHealthcheck = Startup.ConfigureHealthcheck, 16 | ConfigureServices = Startup.ConfigureServices, 17 | Configure = Startup.Configure, 18 | AutoRegisterAssemblies = new Assembly[] 19 | { Assembly.GetExecutingAssembly() } 20 | }; 21 | 22 | AspNetScaffolding.Api.Run(config); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "AspNetScaffoldingTemplate.Api": { 4 | "commandName": "Project", 5 | "environmentVariables": { 6 | "ASPNETCORE_ENVIRONMENT": "Development" 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Api/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using System; 4 | 5 | namespace AspNetScaffoldingTemplate.Api 6 | { 7 | public static class Startup 8 | { 9 | public static void ConfigureHealthcheck(IHealthChecksBuilder builder, IServiceProvider provider) 10 | { 11 | // add health check configuration 12 | builder.AddUrlGroup(new Uri("https://www.google.com"), "google"); 13 | } 14 | 15 | public static void ConfigureServices(IServiceCollection services) 16 | { 17 | // add services 18 | //services.AddSingleton(); 19 | } 20 | 21 | public static void Configure(IApplicationBuilder app) 22 | { 23 | // customize your app 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ApiSettings": { 3 | "AppUrl": "http://localhost:80", 4 | "JsonSerializer": "Snakecase", 5 | "PathPrefix": "myapp/{version}", 6 | "Domain": "MyDomain", 7 | "Application": "MyApp", 8 | "Version": "v1", 9 | "BuildVersion": "1.0.0", 10 | "SupportedCultures": [ "pt-BR", "es-ES", "en-US" ], 11 | "RequestKeyProperty": "RequestKey", 12 | "AccountIdProperty": "AccountId", 13 | "TimezoneHeader": "Timezone", 14 | "TimezoneDefault": "UTC", 15 | "TimeElapsedProperty": "X-Internal-Time" 16 | }, 17 | "HealthcheckSettings": { 18 | "Enabled": true, 19 | "Path": "healthcheck", 20 | "LogEnabled": false 21 | }, 22 | "DbSettings": { 23 | "ConnectionString": "mongodb://user:pass@localhost:27017/DatabaseName", 24 | "Name": "DatabaseName" 25 | }, 26 | "LogSettings": { 27 | "DebugEnabled": true, 28 | "TitlePrefix": "[{Application}] ", 29 | "JsonBlacklist": [ "*password", "*card.number", "*creditcardnumber", "*cvv" ], 30 | "SeqOptions": { 31 | "Enabled": true, 32 | "MinimumLevel": "Verbose", 33 | "Url": "http://localhost:5341", 34 | "ApiKey": "XXXX" 35 | }, 36 | "SplunkOptions": { 37 | "Enabled": false, 38 | "MinimumLevel": "Verbose", 39 | "Url": "http://localhost:8088/services/collector", 40 | "Token": "XXXX", 41 | "Index": "my.index", 42 | "Application": "MyApp :Ds", 43 | "ProcessName": "Domain.App", 44 | "Company": "MyCompany", 45 | "ProductVersion": "1.0.0", 46 | "SourceType": "_json" 47 | } 48 | }, 49 | "DocsSettings": { 50 | "Enabled": true, 51 | "Title": "MyApp API Reference", 52 | "AuthorName": "Thiago Barradas", 53 | "AuthorEmail": "th.barradas@gmail.com", 54 | "PathToReadme": "Docs.md" 55 | } 56 | } -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Core.Tests/AspNetScaffoldingTemplate.Core.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Core.Tests/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace AspNetScaffoldingTemplate.Core.Tests 5 | { 6 | public class UnitTest1 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Core/AspNetScaffoldingTemplate.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Core/Models/Person/Composition/Address.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffoldingTemplate.Core.Models.Person.Composition 2 | { 3 | public class Address 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Core/Models/Person/Composition/PersonType.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffoldingTemplate.Core.Models.Person.Composition 2 | { 3 | public enum PersonType 4 | { 5 | Undefined, 6 | PhysicalPerson, 7 | LegalEntity 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Core/Models/Person/Person.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffoldingTemplate.Core.Models.Person.Composition; 2 | using PackUtils.Converters; 3 | using System; 4 | using System.Text.Json.Serialization; 5 | 6 | namespace AspNetScaffoldingTemplate.Core.Models.Person 7 | { 8 | public class Person 9 | { 10 | public string FirstName { get; set; } 11 | 12 | public string LastName { get; set; } 13 | 14 | [JsonConverter(typeof(DateConverter))] 15 | public DateTime Birthdate { get; set; } 16 | 17 | public DateTime Now { get; set; } = DateTime.UtcNow; 18 | 19 | public string Email { get; set; } 20 | 21 | public Address Address { get; set; } 22 | 23 | public PersonType Type { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Core/Models/Person/Validator/CreatePersonValidator.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffoldingTemplate.Core.Models.Person.Composition; 2 | using FluentValidation; 3 | 4 | namespace AspNetScaffoldingTemplate.Core.Models.Person.Validator 5 | { 6 | public class CreatePersonValidator : AbstractValidator 7 | { 8 | public CreatePersonValidator() 9 | { 10 | RuleFor(p => p.FirstName).NotEmpty().Length(3, 30); 11 | RuleFor(p => p.LastName).NotEmpty().Length(3, 30); 12 | RuleFor(p => p.Email).NotEmpty().EmailAddress(); 13 | RuleFor(p => p.Type).Must(p => p != PersonType.Undefined); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Core/Services/Interfaces/IPersonService.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetScaffoldingTemplate.Core.Services.Interfaces 2 | { 3 | public interface IPersonService 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate.Core/Services/PersonService.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffoldingTemplate.Core.Services.Interfaces; 2 | 3 | namespace AspNetScaffoldingTemplate.Core.Services 4 | { 5 | public class PersonService : IPersonService 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate/ProjectTemplates/AspNetScaffolding3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/AspNetScaffoldingTemplate/ProjectTemplates/AspNetScaffolding3.zip -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AspNetScaffoldingTemplate")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AspNetScaffoldingTemplate")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Build and Revision Numbers 30 | // by using the '*' as shown below: 31 | // [assembly: AssemblyVersion("1.0.*")] 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace AspNetScaffoldingTemplate.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AspNetScaffoldingTemplate.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate/aspnetscaffolding-wizard.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/AspNetScaffoldingTemplate/aspnetscaffolding-wizard.snk -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/AspNetScaffoldingTemplate/icon.png -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/AspNetScaffoldingTemplate/logo.png -------------------------------------------------------------------------------- /Template/src/AspNetScaffoldingTemplate/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AspNetScaffolding3 6 | Creates a new web api based on AspNetScaffolding3 7 | icon.png 8 | icon.png 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | First off, thanks for taking the time to contribute! 4 | 5 | ### How can I contribute? 6 | 7 | * Fork this project; 8 | * Make your changes / new implementatios; 9 | * Use the pattern for git commts; 10 | * Make sure that the acceptance criteria are met (tests, docs, etc); 11 | * Create a pull request; 12 | 13 | ### Pull Requests 14 | 15 | Template [PULLREQUEST-TEMPLATE](PULL_REQUEST_TEMPLATE.md) 16 | 17 | ### Git Commit Messages 18 | 19 | * Use the present tense ("Adds feature" not "Added feature") 20 | * Limit the first line to 72 characters or less 21 | * Reference issues and pull requests liberally 22 | * Consider starting the commit message with an applicable emoji: 23 | * :art: `:art:` when improving the format/structure of the code 24 | * :racehorse: `:racehorse:` when improving performance 25 | * :non-potable_water: `:non-potable_water:` when plugging memory leaks 26 | * :memo: `:memo:` when writing docs 27 | * :penguin: `:penguin:` when fixing something on Linux 28 | * :apple: `:apple:` when fixing something on Mac OS 29 | * :checkered_flag: `:checkered_flag:` when fixing something on Windows 30 | * :bug: `:bug:` when fixing a bug 31 | * :fire: `:fire:` when removing code or files 32 | * :green_heart: `:green_heart:` when fixing the CI build 33 | * :white_check_mark: `:white_check_mark:` when adding tests 34 | * :lock: `:lock:` when dealing with security 35 | * :arrow_up: `:arrow_up:` when upgrading dependencies 36 | * :arrow_down: `:arrow_down:` when downgrading dependencies 37 | * :shirt: `:shirt:` when removing linter warnings 38 | * :bulb: `:bulb:` new idea 39 | * :construction: `:construction:` work in progress 40 | * :heavy_plus_sign: `:heavy_plus_sign:` when adding features 41 | * :heavy_minus_sign: `:heavy_minus_sign:` when removing features 42 | * :speaker: `:mute:` when adding logging 43 | * :mute: `:mute:` when reducing logging 44 | * :facepunch: `:facepunch:` when resolve conflict 45 | * :wrench: `:wrench:` when modify Web.config 46 | 47 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ``` 2 | Please use the following template to submit your issue. 3 | Following this template will allow us to quickly investigate and help you with your issue. 4 | Please be aware that issues which do not conform to this template may be closed. 5 | 6 | DO NOT FORGET TO REMOVE THIS BLOCK 7 | ``` 8 | 9 | ### Status 10 | 11 | BUG REPORT / TASK 12 | 13 | ### Checklist 14 | 15 | Add checklist if this is a task 16 | 17 | - [x] Add slack integration 18 | - [_] Support xyz 19 | 20 | ### Steps 21 | 22 | 1. First step 23 | 2. Second step 24 | 3. Third step 25 | 26 | ### Expected behaviour 27 | 28 | How do you think the program should work? Add screenshots and code blocks if necessary. 29 | 30 | ### Actual behaviour 31 | 32 | How does the program work in its current state? 33 | 34 | ### Environment 35 | 36 | You may write here the specifications like the version of the project, services, operating system, or hardware if applicable. 37 | 38 | ### Logs / Stack trace 39 | 40 | ``` 41 | Insert your log/stack trace here 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ``` 2 | This is a guide to use this Pull Request Template. 3 | 4 | # Title 5 | [Feature] Implements the crazy powerful transaction search 6 | [Bug] Fixes login with e-mail address 7 | 8 | Add a gif that expresses your reaction to the implemented code, make it fun 9 | 10 | DO NOT FORGET TO REMOVE THIS BLOCK 11 | ``` 12 | ![Git Merge](https://media.giphy.com/media/cFkiFMDg3iFoI/giphy.gif) 13 | 14 | ### Status 15 | 16 | READY / IN DEVELOPMENT 17 | 18 | ### Whats? 19 | 20 | Describe in an objective way what has been done. 21 | 22 | ### Why? 23 | 24 | Why do you need this implementation/fix? 25 | 26 | ### How? 27 | 28 | How did you solve the problem? What are the main flows? Any technical information regarding infrastructure or architecture? 29 | 30 | ### Attachments (if appropriate) 31 | 32 | Add additional informations like screenshots, issue link, zendesk ticket link, jira task link, etc 33 | 34 | ### Definition of Done: 35 | - [ ] Increases API documentation 36 | - [ ] Implements integration tests 37 | - [ ] Implements unit tests 38 | - [ ] Is there appropriate logging included? 39 | - [ ] Does this add new dependencies? 40 | - [ ] Does need add new version in changelog? 41 | - [ ] Does need update readme, contributing, etc? 42 | - [ ] Does need change in CI server? 43 | - [ ] Will this feature require a new piece of infrastructure be implemented? 44 | - [ ] Does this PR require a blog post? If so, ensure marketing has signed off on content. 45 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffolding3.vstemplate: -------------------------------------------------------------------------------- 1 | 2 | 3 | AspNetScaffolding3.Api 4 | Creates a new web api based on AspNetScaffolding3 5 | CSharp 6 | MyService 7 | false 8 | false 9 | false 10 | false 11 | __TemplateIcon.png 12 | __PreviewImage.png 13 | 14 | 15 | 16 | 17 | 18 | 19 | AspNetScaffoldingTemplate.Api\AspNetScaffoldingTemplate.Api.vstemplate 20 | 21 | 22 | AspNetScaffoldingTemplate.Core\AspNetScaffoldingTemplate.Core.vstemplate 23 | 24 | 25 | AspNetScaffoldingTemplate.Core.Tests\AspNetScaffoldingTemplate.Core.Tests.vstemplate 26 | 27 | 28 | 29 | 30 | AspNetScaffoldingTemplate, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=88b5b98976609649 31 | AspNetScaffoldingTemplate.Wizard 32 | 33 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffolding3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/AspNetScaffolding3.zip -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/AspNetScaffoldingTemplate.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Always 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/AspNetScaffoldingTemplate.Api.vstemplate: -------------------------------------------------------------------------------- 1 | 2 | 3 | AspNetScaffolding3.Api 4 | Creates a new web api based on AspNetScaffolding3 5 | CSharp 6 | 7 | 8 | 1000 9 | true 10 | AspNetScaffolding3 11 | true 12 | Enabled 13 | true 14 | true 15 | __TemplateIcon.png 16 | __PreviewImage.png 17 | true 18 | 19 | 20 | 21 | 22 | launchSettings.json 23 | 24 | 25 | appsettings.json 26 | Docs.md 27 | Program.cs 28 | Startup.cs 29 | 30 | 31 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/Docs.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vulputate fringilla elementum. Praesent bibendum ipsum sed urna sagittis ultrices. Sed ac ligula ac arcu rutrum scelerisque at at mi. Suspendisse quis eleifend magna. Duis mattis, urna eget iaculis sodales, tortor nisl porttitor mauris, in posuere velit nulla in augue. In vel massa urna. Aenean in ultricies arcu. Nam porttitor libero risus, at sollicitudin lacus fringilla eget. Cras sit amet sapien dapibus, commodo nisi ac, vestibulum justo. Proin faucibus eget ipsum ut sollicitudin. Nulla sit amet quam nunc. Integer ante nulla, finibus eget velit non, sagittis tincidunt libero. -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using AspNetScaffolding.Models; 2 | using System.Reflection; 3 | 4 | namespace $ext_safeprojectname$ 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | var config = new ApiBasicConfiguration 11 | { 12 | ApiName = "My AspNet Scaffolding", 13 | ApiPort = 80, 14 | EnvironmentVariablesPrefix = "Prefix_", 15 | ConfigureHealthcheck = Startup.ConfigureHealthcheck, 16 | ConfigureServices = Startup.ConfigureServices, 17 | Configure = Startup.Configure, 18 | AutoRegisterAssemblies = new Assembly[] 19 | { Assembly.GetExecutingAssembly() } 20 | }; 21 | 22 | AspNetScaffolding.Api.Run(config); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "$ext_safeprojectname$": { 4 | "commandName": "Project", 5 | "environmentVariables": { 6 | "ASPNETCORE_ENVIRONMENT": "Development" 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using System; 4 | 5 | namespace $ext_safeprojectname$ 6 | { 7 | public static class Startup 8 | { 9 | public static void ConfigureHealthcheck(IHealthChecksBuilder builder, IServiceProvider provider) 10 | { 11 | // add health check configuration 12 | builder.AddUrlGroup(new Uri("https://www.google.com"), "google"); 13 | } 14 | 15 | public static void ConfigureServices(IServiceCollection services) 16 | { 17 | // add services 18 | //services.AddSingleton(); 19 | } 20 | 21 | public static void Configure(IApplicationBuilder app) 22 | { 23 | // customize your app 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/__PreviewImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/__PreviewImage.png -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/__TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/__TemplateIcon.png -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ApiSettings": { 3 | "AppUrl": "http://localhost:80", 4 | "JsonSerializer": "Snakecase", 5 | "PathPrefix": "$ext_path$/{version}", 6 | "Domain": "$ext_team$", 7 | "Application": "$ext_safeprojectname$.Api", 8 | "Version": "v$ext_version$", 9 | "BuildVersion": "$ext_version$.0.0", 10 | "SupportedCultures": [ "pt-BR", "es-ES", "en-US" ], 11 | "RequestKeyProperty": "RequestKey", 12 | "AccountIdProperty": "AccountId", 13 | "TimezoneHeader": "Timezone", 14 | "TimezoneDefault": "UTC", 15 | "TimeElapsedProperty": "X-Internal-Time" 16 | }, 17 | "HealthcheckSettings": { 18 | "Enabled": true, 19 | "Path": "healthcheck/$ext_hc_token$", 20 | "LogEnabled": false 21 | }, 22 | "DbSettings": { 23 | "ConnectionString": "mongodb://user:pass@localhost:27017/$ext_team$_$ext_safeprojectname$", 24 | "Name": "$ext_team$_$ext_safeprojectname$" 25 | }, 26 | "LogSettings": { 27 | "DebugEnabled": true, 28 | "TitlePrefix": "[{Application}] ", 29 | "JsonBlacklist": [ "*password", "*card.number", "*creditcardnumber", "*cvv" ], 30 | "SeqOptions": { 31 | "Enabled": true, 32 | "MinimumLevel": "Verbose", 33 | "Url": "http://localhost:5341", 34 | "ApiKey": "" 35 | }, 36 | "SplunkOptions": { 37 | "Enabled": false, 38 | "MinimumLevel": "Verbose", 39 | "Url": "http://localhost:8088/services/collector", 40 | "Token": "", 41 | "Index": "$ext_lower_company$.$ext_lower_team$", 42 | "Application": "$ext_safeprojectname$.Api", 43 | "ProcessName": "$ext_company$.$ext_team$.$ext_safeprojectname$.Api", 44 | "Company": "$ext_company$", 45 | "ProductVersion": "1.0.0", 46 | "SourceType": "_json" 47 | } 48 | }, 49 | "DocsSettings": { 50 | "Enabled": true, 51 | "Title": "$ext_safeprojectname$ API Reference", 52 | "AuthorName": "$ext_author_name$", 53 | "AuthorEmail": "$ext_author_email$", 54 | "PathToReadme": "Docs.md" 55 | } 56 | } -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core.Tests/AspNetScaffoldingTemplate.Core.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core.Tests/AspNetScaffoldingTemplate.Core.Tests.vstemplate: -------------------------------------------------------------------------------- 1 | 2 | 3 | AspNetScaffolding3.Core.Tests 4 | Creates a new unit tests project for web api based on AspNetScaffolding3 5 | CSharp 6 | 7 | 8 | 1000 9 | true 10 | AspNetScaffoldingTemplate.Core.Tests 11 | true 12 | Enabled 13 | true 14 | true 15 | __TemplateIcon.png 16 | __PreviewImage.png 17 | true 18 | 19 | 20 | 21 | 22 | UnitTest1.cs 23 | 24 | 25 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core.Tests/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace $ext_safeprojectname$ 5 | { 6 | public class UnitTest1 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core.Tests/__PreviewImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core.Tests/__PreviewImage.png -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core.Tests/__TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core.Tests/__TemplateIcon.png -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/AspNetScaffoldingTemplate.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/AspNetScaffoldingTemplate.Core.vstemplate: -------------------------------------------------------------------------------- 1 | 2 | 3 | AspNetScaffolding3.Core 4 | Creates a new core for web api based on AspNetScaffolding3 5 | CSharp 6 | 7 | 8 | 1000 9 | true 10 | AspNetScaffoldingTemplate.Core 11 | true 12 | Enabled 13 | true 14 | true 15 | __TemplateIcon.png 16 | __PreviewImage.png 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Address.cs 26 | PersonType.cs 27 | 28 | 29 | 30 | 31 | 32 | CreatePersonValidator.cs 33 | 34 | Person.cs 35 | 36 | 37 | 38 | 39 | IPersonService.cs 40 | 41 | PersonService.cs 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/Models/Person/Composition/Address.cs: -------------------------------------------------------------------------------- 1 | namespace $ext_safeprojectname$.Models.Person.Composition 2 | { 3 | public class Address 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/Models/Person/Composition/PersonType.cs: -------------------------------------------------------------------------------- 1 | namespace $ext_safeprojectname$.Models.Person.Composition 2 | { 3 | public enum PersonType 4 | { 5 | Undefined, 6 | PhysicalPerson, 7 | LegalEntity 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/Models/Person/Person.cs: -------------------------------------------------------------------------------- 1 | using $ext_safeprojectname$.Models.Person.Composition; 2 | using PackUtils.Converters; 3 | using System; 4 | using System.Text.Json.Serialization; 5 | 6 | namespace $ext_safeprojectname$.Models.Person 7 | { 8 | public class Person 9 | { 10 | public string FirstName { get; set; } 11 | 12 | public string LastName { get; set; } 13 | 14 | [JsonConverter(typeof(DateConverter))] 15 | public DateTime Birthdate { get; set; } 16 | 17 | public DateTime Now { get; set; } = DateTime.UtcNow; 18 | 19 | public string Email { get; set; } 20 | 21 | public Address Address { get; set; } 22 | 23 | public PersonType Type { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/Models/Person/Validator/CreatePersonValidator.cs: -------------------------------------------------------------------------------- 1 | using $ext_safeprojectname$.Models.Person.Composition; 2 | using FluentValidation; 3 | 4 | namespace $ext_safeprojectname$.Models.Person.Validator 5 | { 6 | public class CreatePersonValidator : AbstractValidator 7 | { 8 | public CreatePersonValidator() 9 | { 10 | RuleFor(p => p.FirstName).NotEmpty().Length(3, 30); 11 | RuleFor(p => p.LastName).NotEmpty().Length(3, 30); 12 | RuleFor(p => p.Email).NotEmpty().EmailAddress(); 13 | RuleFor(p => p.Type).Must(p => p != PersonType.Undefined); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/Services/Interfaces/IPersonService.cs: -------------------------------------------------------------------------------- 1 | namespace $ext_safeprojectname$.Services.Interfaces 2 | { 3 | public interface IPersonService 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/Services/PersonService.cs: -------------------------------------------------------------------------------- 1 | using $ext_safeprojectname$.Services.Interfaces; 2 | 3 | namespace $ext_safeprojectname$.Services 4 | { 5 | public class PersonService : IPersonService 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/__PreviewImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/__PreviewImage.png -------------------------------------------------------------------------------- /Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/__TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/AspNetScaffoldingTemplate.Core/__TemplateIcon.png -------------------------------------------------------------------------------- /Template/src/TemplateRelease/README.md: -------------------------------------------------------------------------------- 1 | # AspNetScaffoldingTemplate 2 | 3 | :construction: 4 | 5 | # Read more about 6 | 7 | Please, see our wiki for more details about this app. 8 | 9 | # How can I contribute? 10 | Please, refer to [CONTRIBUTING](.github/CONTRIBUTING.md) 11 | 12 | # Found something strange or need a new feature? 13 | Open a new Issue following our [ISSUE TEMPLATE](.github/ISSUE_TEMPLATE.md) -------------------------------------------------------------------------------- /Template/src/TemplateRelease/__PreviewImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/__PreviewImage.png -------------------------------------------------------------------------------- /Template/src/TemplateRelease/__TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/__TemplateIcon.png -------------------------------------------------------------------------------- /Template/src/TemplateRelease/devops/Dockerfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/devops/Dockerfile -------------------------------------------------------------------------------- /Template/src/TemplateRelease/devops/azure-pipelines.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThiagoBarradas/aspnet-scaffolding3/fe7df951fabe7ca8717f06a713f433e044c8f1dd/Template/src/TemplateRelease/devops/azure-pipelines.yml -------------------------------------------------------------------------------- /Template/src/TemplateRelease/devops/docker-compose.yml: -------------------------------------------------------------------------------- 1 | // mongo 2 | // seq 3 | // rabbit --------------------------------------------------------------------------------