├── Gaev.Blog.Examples.GoogleAlert ├── publish.cmd ├── appsettings.json ├── deploy.cmd ├── Gaev.Blog.Examples.GoogleAlert.csproj ├── CodeFragments.cs └── Program.cs ├── Gaev.Blog.Examples.HelloSshDeploy ├── make.sh ├── uninstall.sh ├── Gaev.Blog.Examples.HelloSshDeploy.csproj ├── Program.cs └── deploy.sh ├── Gaev.Blog.Examples.KeybaseSignIn ├── make.sh ├── appsettings.json ├── uninstall.sh ├── Program.cs ├── Startup.cs ├── Gaev.Blog.Examples.KeybaseSignIn.csproj └── deploy.sh ├── Gaev.Blog.Examples.WarmUpAspNetMvc ├── Views │ ├── _ViewStart.cshtml │ ├── Home │ │ ├── About.cshtml │ │ ├── Contact.cshtml │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ └── Web.config ├── Global.asax ├── Controllers │ ├── InitialSlowdown.cs │ ├── HomeController.cs │ └── WarmUpController.cs ├── Global.asax.cs ├── packages.config ├── Properties │ └── AssemblyInfo.cs └── Web.config ├── ArchitectureTestProjects ├── Gaev.Alfa.Api │ ├── IAlfaApi.cs │ └── Gaev.Alfa.Api.csproj ├── Gaev.Bravo.Api │ ├── IBravoApi.cs │ ├── Playground.cs │ └── Gaev.Bravo.Api.csproj ├── Gaev.Charlie.Api │ ├── ICharlieApi.cs │ └── Gaev.Charlie.Api.csproj ├── Gaev.Alfa │ ├── Domain.cs │ ├── Bootstrap.cs │ └── Gaev.Alfa.csproj ├── Gaev.Bravo │ ├── Domain.cs │ ├── Bootstrap.cs │ └── Gaev.Bravo.csproj ├── Gaev.Charlie │ ├── Bootstrap.cs │ ├── Domain.cs │ └── Gaev.Charlie.csproj └── Gaev.Shell │ ├── Bootstrap.cs │ └── Gaev.Shell.csproj ├── Gaev.Blog.SecuredAppSettingsJson ├── run.cmd ├── global.json ├── appsettings.json ├── Program.cs ├── Gaev.Blog.SecuredAppSettingsJson.csproj ├── ConfigurationRootExtensions.cs ├── Aes256Cipher.cs └── UtilityTests.cs ├── Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6 ├── run.cmd ├── Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6.csproj ├── appsettings.json ├── Properties │ └── launchSettings.json ├── Program.cs └── ProgramOption2.cs ├── Gaev.Blog.Examples.ScriptInString ├── Global.asax ├── Views │ ├── Home │ │ ├── Problem2.cshtml │ │ ├── Problem1.cshtml │ │ ├── Fix2.cshtml │ │ └── Fix1.cshtml │ └── Web.config ├── Controllers │ └── HomeController.cs ├── Global.asax.cs ├── packages.config └── Web.config ├── .gitignore ├── Gaev.Blog.Examples.SqlQueue ├── packages.config └── Gaev.Blog.Examples.SqlQueue.csproj ├── Gaev.Blog.Examples.FunnyTestCases ├── packages.config └── Gaev.Blog.Examples.FunnyTestCases.csproj ├── Gaev.Blog.Examples.TransactionScopeFailure ├── packages.config └── Gaev.Blog.Examples.TransactionScopeFailure.csproj ├── Gaev.Blog.Examples.Mocking ├── ICustomerService.cs ├── CustomerService.cs ├── Customer.cs ├── CustomerServiceViaVirtualMethod.cs ├── CustomerServiceViaDelegate.cs ├── Gaev.Blog.Examples.Mocking.csproj └── CustomerServiceViaInterface.cs ├── Gaev.Blog.Examples.AsyncTaskThrottling ├── DriveService.cs ├── ThrottlerExt.cs ├── Gaev.Blog.Examples.AsyncTaskThrottling.csproj └── ThrottlingExamples.cs ├── Gaev.Blog.Examples.PiiTypes ├── IPiiEncoder.cs ├── User.cs ├── PiiAsPlainText.cs ├── EfCore │ ├── PiiStringConverter.cs │ └── PiiStringTests.cs ├── PiiAsSha256.cs ├── SystemTextJson │ ├── PiiStringConverter.cs │ └── PiiStringTests.cs ├── NewtonsoftJson │ ├── PiiStringConverter.cs │ └── PiiStringTests.cs ├── Serilog │ └── PiiStringTests.cs ├── Gaev.Blog.Examples.PiiTypes.csproj ├── PiiStringTests.cs ├── PiiString.cs ├── PiiAsAes128.cs └── NLog │ └── PiiStringTests.cs ├── Gaev.Blog.Examples.SqlQueryLogger ├── TimeSpanExt.cs ├── ProfilerGetter.cs ├── TestLogger.cs ├── packages.config ├── LongRunningQueryProfiler.cs └── AlertLongRunningEfQueriesTests.cs ├── Gaev.Blog.ParallelizableTests ├── OtherTests.cs ├── OtherParallelizableTests.cs ├── DefaultTests.cs ├── NonParallelizableTests.cs ├── Gaev.Blog.ParallelizableTests.csproj ├── ParallelizableTests.cs ├── ParallelizableAllTests.cs └── ParallelizableAllTestsPitfalls.cs ├── Gaev.Blog.EnumAsStringTrap ├── Model.cs ├── Gaev.Blog.EnumAsStringTrap.csproj ├── NewtonsoftJson │ ├── UnknownEnumConverter.cs │ └── DeserializationTests.cs └── SystemTextJson │ ├── UnknownEnumConverter.cs │ └── DeserializationTests.cs ├── Gaev.Blog.Examples.MiniProfiler3Bug ├── packages.config ├── Microsoft.Threading │ └── AsyncPump.cs ├── MiniProfilerReproductionTests.cs └── Gaev.Blog.Examples.MiniProfiler3Bug.csproj ├── Gaev.Blog.Examples.AzureServiceBus ├── UnitTest1.cs ├── Gaev.Blog.Examples.AzureServiceBus.csproj └── AzureServiceBus.cs ├── Gaev.Blog.Examples.FileReceiver ├── Gaev.Blog.Examples.FileReceiver.csproj └── Program.cs ├── Gaev.Blog.Examples.ExceptionCustomData ├── packages.config └── Gaev.Blog.Examples.ExceptionCustomData.csproj ├── Gaev.Blog.Examples.StateViaEF ├── packages.config ├── LegacyUser.cs └── User.cs ├── Gaev.Blog.Examples.SerializationTests ├── packages.config ├── Properties │ └── AssemblyInfo.cs └── SerializationTests.cs ├── Gaev.Blog.AzureServiceBusTaskScheduler ├── Gaev.Blog.AzureServiceBusTaskScheduler.csproj ├── Program.cs └── ServiceBusJobScheduler.cs ├── Gaev.Blog.ExceptionRethrow ├── Gaev.Blog.ExceptionRethrow.csproj └── ExceptionRethrowTests.cs ├── Gaev.Blog.Examples.OrderOfEnumValues ├── Gaev.Blog.Examples.OrderOfEnumValues.csproj └── OrderOfEnumValuesMatters.cs ├── Gaev.Blog.Examples.EnumParsePitfall ├── Gaev.Blog.Examples.EnumParsePitfall.csproj └── ParsingEnumTests.cs ├── Gaev.Blog.EnumFlags ├── Gaev.Blog.EnumFlags.csproj ├── EnumFlagsPerformance.cs ├── EnumFlagExtensions.cs └── Program.cs ├── Gaev.Blog.CSharp12AndNetFramework ├── Gaev.Blog.CSharp12AndNetFramework.csproj └── Program.cs ├── Gaev.Blog.Sha256ForStream ├── Gaev.Blog.Sha256ForStream.csproj └── CryptoUtilsTests.cs ├── Gaev.Blog.Examples.ArchitectureTests ├── Gaev.Blog.Examples.ArchitectureTests.csproj ├── DotNetAssemblyExt.cs ├── DotNetAssembly.cs └── ArchitectureTests.cs ├── Gaev.Blog.Examples.WebhookTests └── packages.config ├── Gaev.Blog.Examples.SelfDocumentedApp └── packages.config └── Gaev.Blog.Examples.SelfDocumentedFSM └── packages.config /Gaev.Blog.Examples.GoogleAlert/publish.cmd: -------------------------------------------------------------------------------- 1 | dotnet publish --runtime ubuntu.16.04-x64 --configuration Release -------------------------------------------------------------------------------- /Gaev.Blog.Examples.GoogleAlert/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "TelegramApiKey": "...", 3 | "TelegramChatId": "..." 4 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.HelloSshDeploy/make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | dotnet publish --runtime ubuntu.16.04-x64 --configuration Release -------------------------------------------------------------------------------- /Gaev.Blog.Examples.KeybaseSignIn/make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | dotnet publish --runtime ubuntu.16.04-x64 --configuration Release -------------------------------------------------------------------------------- /Gaev.Blog.Examples.WarmUpAspNetMvc/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Alfa.Api/IAlfaApi.cs: -------------------------------------------------------------------------------- 1 | namespace Gaev.Alfa.Api; 2 | 3 | public interface IAlfaApi 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Bravo.Api/IBravoApi.cs: -------------------------------------------------------------------------------- 1 | namespace Gaev.Bravo.Api; 2 | 3 | public interface IBravoApi 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /Gaev.Blog.SecuredAppSettingsJson/run.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set CipherKey=l8cpD27QcWDXjAg8ut+qH0IkWv/p38DrAst4Ee83jMg= 3 | dotnet run 4 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Charlie.Api/ICharlieApi.cs: -------------------------------------------------------------------------------- 1 | namespace Gaev.Charlie.Api; 2 | 3 | public interface ICharlieApi 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /Gaev.Blog.SecuredAppSettingsJson/global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "3.1.100", 4 | "rollForward": "latestPatch" 5 | } 6 | } -------------------------------------------------------------------------------- /Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6/run.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set CipherKey=l8cpD27QcWDXjAg8ut+qH0IkWv/p38DrAst4Ee83jMg= 3 | dotnet run 4 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Alfa/Domain.cs: -------------------------------------------------------------------------------- 1 | using Gaev.Alfa.Api; 2 | 3 | namespace Gaev.Alfa; 4 | 5 | public class Domain : IAlfaApi 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.GoogleAlert/deploy.cmd: -------------------------------------------------------------------------------- 1 | scp -r bin/Release/netcoreapp2.2/ubuntu.16.04-x64/publish/ root@165.227.244.117:/apps/Gaev.Blog.Examples.GoogleAlert/ -------------------------------------------------------------------------------- /Gaev.Blog.Examples.ScriptInString/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Gaev.Blog.Examples.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.WarmUpAspNetMvc/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Gaev.Blog.Examples.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/* 2 | **/bin/ 3 | **/obj/ 4 | *.sln.DotSettings.user 5 | **/packages/ 6 | /Gaev.Blog.Examples.GoogleAlert/Alerts.sqlite3 7 | 8 | *.csproj.user 9 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.SqlQueue/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.FunnyTestCases/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.TransactionScopeFailure/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.Mocking/ICustomerService.cs: -------------------------------------------------------------------------------- 1 | namespace Gaev.Blog.Examples 2 | { 3 | public interface ICustomerService 4 | { 5 | Customer RegisterCustomer(string name); 6 | } 7 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.AsyncTaskThrottling/DriveService.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | 4 | public interface DriveService 5 | { 6 | Task UploadFile(string name, Stream content); 7 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.PiiTypes/IPiiEncoder.cs: -------------------------------------------------------------------------------- 1 | namespace Gaev.Blog.Examples; 2 | 3 | public interface IPiiEncoder 4 | { 5 | string ToSystemString(PiiString piiString); 6 | PiiString ToPiiString(string str); 7 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.KeybaseSignIn/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "AllowedHosts": "*", 3 | "Kestrel": { 4 | "EndPoints": { 5 | "Http": { 6 | "Url": "http://*:5002" 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.SqlQueryLogger/TimeSpanExt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Gaev.Blog.Examples 4 | { 5 | public static class TimeSpanExt 6 | { 7 | public static TimeSpan Milliseconds(this int val) => TimeSpan.FromMilliseconds(val); 8 | } 9 | } -------------------------------------------------------------------------------- /Gaev.Blog.ParallelizableTests/OtherTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Gaev.Blog; 4 | 5 | [Category("Other")] 6 | public class OtherTests 7 | { 8 | [Test] 9 | public Task OtherTest() 10 | => Task.Delay(2_000); 11 | } 12 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Bravo.Api/Playground.cs: -------------------------------------------------------------------------------- 1 | namespace Gaev.Bravo.Api; 2 | 3 | public class Playground 4 | { 5 | // public Gaev.Alfa.Api.IAlfaApi AlfaApi; 6 | // public Microsoft.Extensions.DependencyInjection.IServiceCollection Container; 7 | } 8 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Alfa.Api/Gaev.Alfa.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 10 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.WarmUpAspNetMvc/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "About"; 3 | InitialSlowdown.For("About.View"); 4 | } 5 |

@ViewBag.Title.

6 |

@ViewBag.Message

7 | 8 |

Use this area to provide additional information.

9 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Bravo.Api/Gaev.Bravo.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 10 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.WarmUpAspNetMvc/Views/Home/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Contact"; 3 | InitialSlowdown.For("Contact.View"); 4 | } 5 |

@ViewBag.Title.

6 |

@ViewBag.Message

7 | 8 |
9 | My Company Address 10 |
-------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Charlie.Api/Gaev.Charlie.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 10 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Gaev.Blog.EnumAsStringTrap/Model.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | 3 | namespace Gaev.Blog.EnumAsStringTrap; 4 | 5 | public record Money(Currency Currency, decimal Amount); 6 | 7 | public enum Currency 8 | { 9 | Undefined = 0, 10 | EUR = 1, 11 | USD = 2 12 | } 13 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.PiiTypes/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Gaev.Blog.Examples; 4 | 5 | public class User 6 | { 7 | public Guid Id { get; set; } 8 | public PiiString Name { get; set; } 9 | public PiiString Email { get; set; } 10 | public PiiString Location { get; set; } 11 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.HelloSshDeploy/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ssh root@192.168.2.4 'bash -s' <<'ENDSSH' 3 | systemctl stop HelloSshDeploy 4 | systemctl disable HelloSshDeploy 5 | rm /etc/systemd/system/HelloSshDeploy.service 6 | systemctl daemon-reload 7 | systemctl reset-failed 8 | rm -rf /apps/HelloSshDeploy 9 | ENDSSH -------------------------------------------------------------------------------- /Gaev.Blog.ParallelizableTests/OtherParallelizableTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Gaev.Blog; 4 | 5 | [Parallelizable, Category("OtherParallelizable")] 6 | public class OtherParallelizableTests 7 | { 8 | [Test] 9 | public Task OtherTest() 10 | => Task.Delay(2_000); 11 | } 12 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.KeybaseSignIn/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ssh root@app.gaevoy.com 'bash -s' <<'ENDSSH' 3 | systemctl stop GaevKeybaseSignIn 4 | systemctl disable GaevKeybaseSignIn 5 | rm /etc/systemd/system/GaevKeybaseSignIn.service 6 | systemctl daemon-reload 7 | systemctl reset-failed 8 | rm -rf /apps/GaevKeybaseSignIn 9 | ENDSSH -------------------------------------------------------------------------------- /Gaev.Blog.Examples.PiiTypes/PiiAsPlainText.cs: -------------------------------------------------------------------------------- 1 | namespace Gaev.Blog.Examples; 2 | 3 | public class PiiAsPlainText : IPiiEncoder 4 | { 5 | public string ToSystemString(PiiString piiString) 6 | => piiString.ToString(); 7 | 8 | public PiiString ToPiiString(string str) 9 | => new PiiString(str); 10 | } -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Bravo/Domain.cs: -------------------------------------------------------------------------------- 1 | using Gaev.Alfa.Api; 2 | using Gaev.Bravo.Api; 3 | 4 | namespace Gaev.Bravo; 5 | 6 | public class Domain : IBravoApi 7 | { 8 | private readonly IAlfaApi _alfaApi; 9 | 10 | public Domain(IAlfaApi alfaApi) 11 | { 12 | _alfaApi = alfaApi; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Alfa/Bootstrap.cs: -------------------------------------------------------------------------------- 1 | using Gaev.Alfa.Api; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Gaev.Alfa; 5 | 6 | public class Bootstrap 7 | { 8 | public static void Boot(IServiceCollection container) 9 | { 10 | container.AddScoped(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Bravo/Bootstrap.cs: -------------------------------------------------------------------------------- 1 | using Gaev.Bravo.Api; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Gaev.Bravo; 5 | 6 | public class Bootstrap 7 | { 8 | public static void Boot(IServiceCollection container) 9 | { 10 | container.AddScoped(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Charlie/Bootstrap.cs: -------------------------------------------------------------------------------- 1 | using Gaev.Charlie.Api; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Gaev.Charlie; 5 | 6 | public class Bootstrap 7 | { 8 | public static void Boot(IServiceCollection container) 9 | { 10 | container.AddScoped(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.MiniProfiler3Bug/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.AzureServiceBus/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Tests 4 | { 5 | public class Tests 6 | { 7 | [SetUp] 8 | public void Setup() 9 | { 10 | } 11 | 12 | [Test] 13 | public void Test1() 14 | { 15 | Assert.Pass(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.FileReceiver/Gaev.Blog.Examples.FileReceiver.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.WarmUpAspNetMvc/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Error 6 | 7 | 8 |
9 |

Error.

10 |

An error occurred while processing your request.

11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Shell/Bootstrap.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Gaev.Shell; 4 | 5 | public class Bootstrap 6 | { 7 | public static void Boot(IServiceCollection container) 8 | { 9 | Alfa.Bootstrap.Boot(container); 10 | Bravo.Bootstrap.Boot(container); 11 | Charlie.Bootstrap.Boot(container); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.ExceptionCustomData/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.PiiTypes/EfCore/PiiStringConverter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 2 | 3 | namespace Gaev.Blog.Examples.EfCore; 4 | 5 | public class PiiStringConverter : ValueConverter 6 | { 7 | public PiiStringConverter(IPiiEncoder encoder) : base( 8 | v => encoder.ToSystemString(v), 9 | v => encoder.ToPiiString(v)) 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.Mocking/CustomerService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Gaev.Blog.Examples 4 | { 5 | public class CustomerService : ICustomerService 6 | { 7 | public Customer RegisterCustomer(string name) 8 | { 9 | return new Customer(NewId(), GetUtcNow(), name); 10 | } 11 | 12 | private Guid NewId() => Guid.NewGuid(); 13 | private DateTime GetUtcNow() => DateTime.UtcNow; 14 | } 15 | } -------------------------------------------------------------------------------- /ArchitectureTestProjects/Gaev.Charlie/Domain.cs: -------------------------------------------------------------------------------- 1 | using Gaev.Alfa.Api; 2 | using Gaev.Bravo.Api; 3 | using Gaev.Charlie.Api; 4 | 5 | namespace Gaev.Charlie; 6 | 7 | public class Domain : ICharlieApi 8 | { 9 | private readonly IAlfaApi _alfaApi; 10 | private readonly IBravoApi _bravoApi; 11 | 12 | public Domain(IAlfaApi alfaApi, IBravoApi bravoApi) 13 | { 14 | _alfaApi = alfaApi; 15 | _bravoApi = bravoApi; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.ScriptInString/Views/Home/Problem2.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

 5 | "},
 8 |     {"Name":""}
 9 | ];
10 | var content = document.getElementById("content");
11 | content.innerText = clientModel.map(e => e.Name).join("\n");
12 | 
13 | 
14 | 
15 | 
16 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.StateViaEF/packages.config:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |   
4 |   
5 |   
6 |   
7 |   
8 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.Mocking/Customer.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace Gaev.Blog.Examples
 4 | {
 5 |     public class Customer
 6 |     {
 7 |         public Customer(Guid id, DateTime createdAt, string name)
 8 |         {
 9 |             Id = id;
10 |             CreatedAt = createdAt;
11 |             Name = name;
12 |         }
13 | 
14 |         public Guid Id { get; }
15 |         public DateTime CreatedAt { get; }
16 |         public string Name { get; }
17 |     }
18 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.SerializationTests/packages.config:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |   
4 |   
5 |   
6 |   
7 |   
8 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.ScriptInString/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
 1 | using System.Web.Mvc;
 2 | 
 3 | namespace Gaev.Blog.Examples.Controllers
 4 | {
 5 |     public class HomeController : Controller
 6 |     {
 7 |         public ActionResult Index() => View("Problem1");
 8 |         public ActionResult Problem1() => View();
 9 |         public ActionResult Problem2() => View();
10 |         public ActionResult Fix1() => View();
11 |         public ActionResult Fix2() => View();
12 |     }
13 | }


--------------------------------------------------------------------------------
/Gaev.Blog.AzureServiceBusTaskScheduler/Gaev.Blog.AzureServiceBusTaskScheduler.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         Exe
 5 |         netcoreapp3.0
 6 |     
 7 | 
 8 |     
 9 |       
10 |       
11 |     
12 | 
13 | 
14 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.Mocking/CustomerServiceViaVirtualMethod.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace Gaev.Blog.Examples
 4 | {
 5 |     public class CustomerServiceViaVirtualMethod : ICustomerService
 6 |     {
 7 |         public Customer RegisterCustomer(string name)
 8 |         {
 9 |             return new Customer(NewId(), GetUtcNow(), name);
10 |         }
11 | 
12 |         public virtual Guid NewId() => Guid.NewGuid();
13 |         public virtual DateTime GetUtcNow() => DateTime.UtcNow;
14 |     }
15 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.KeybaseSignIn/Program.cs:
--------------------------------------------------------------------------------
 1 | using Microsoft.AspNetCore;
 2 | using Microsoft.AspNetCore.Hosting;
 3 | 
 4 | namespace Gaev.Blog.Examples
 5 | {
 6 |     public class Program
 7 |     {
 8 |         public static void Main(string[] args)
 9 |         {
10 |             CreateWebHostBuilder(args).Build().Run();
11 |         }
12 | 
13 |         public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
14 |             WebHost.CreateDefaultBuilder(args)
15 |                 .UseStartup();
16 |     }
17 | }


--------------------------------------------------------------------------------
/ArchitectureTestProjects/Gaev.Shell/Gaev.Shell.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         netstandard2.0
 5 |         10
 6 |     
 7 | 
 8 |     
 9 |       
10 |       
11 |       
12 |     
13 | 
14 | 
15 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.WarmUpAspNetMvc/Controllers/InitialSlowdown.cs:
--------------------------------------------------------------------------------
 1 | using System.Collections.Concurrent;
 2 | using System.Threading;
 3 | 
 4 | public class InitialSlowdown
 5 | {
 6 |     private static readonly ConcurrentDictionary IsInitialized =
 7 |         new ConcurrentDictionary();
 8 | 
 9 |     public static void For(string section)
10 |     {
11 |         IsInitialized.GetOrAdd(section, _ =>
12 |         {
13 |             Thread.Sleep(2000);
14 |             return true;
15 |         });
16 |     }
17 | }


--------------------------------------------------------------------------------
/Gaev.Blog.ExceptionRethrow/Gaev.Blog.ExceptionRethrow.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         10
 5 |         net8.0;net48
 6 |     
 7 | 
 8 |     
 9 |         
10 |         
11 |         
12 |     
13 | 
14 | 
15 | 


--------------------------------------------------------------------------------
/ArchitectureTestProjects/Gaev.Alfa/Gaev.Alfa.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         netstandard2.0
 5 |         10
 6 |     
 7 | 
 8 |     
 9 |       
10 |     
11 | 
12 |     
13 |       
14 |     
15 | 
16 | 
17 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.ScriptInString/Global.asax.cs:
--------------------------------------------------------------------------------
 1 | using System.Web;
 2 | using System.Web.Mvc;
 3 | using System.Web.Routing;
 4 | 
 5 | namespace Gaev.Blog.Examples
 6 | {
 7 |     public class MvcApplication : HttpApplication
 8 |     {
 9 |         protected void Application_Start()
10 |         {
11 |             RouteTable.Routes.MapRoute(
12 |                 name: "Default",
13 |                 url: "{action}/{id}",
14 |                 defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional}
15 |             );
16 |         }
17 |     }
18 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.HelloSshDeploy/Gaev.Blog.Examples.HelloSshDeploy.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         Exe
 5 |         netcoreapp2.2
 6 |         7.1
 7 |         Gaev.Blog.Examples
 8 |     
 9 | 
10 |     
11 |       
12 |       
13 |     
14 | 
15 | 
16 | 


--------------------------------------------------------------------------------
/ArchitectureTestProjects/Gaev.Bravo/Gaev.Bravo.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         netstandard2.0
 5 |         10
 6 |     
 7 | 
 8 |     
 9 |       
10 |       
11 |     
12 | 
13 |     
14 |       
15 |     
16 | 
17 | 
18 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.AsyncTaskThrottling/ThrottlerExt.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Threading;
 3 | using System.Threading.Tasks;
 4 | 
 5 | public static class ThrottlerExt
 6 | {
 7 |     public static async Task Throttle(this SemaphoreSlim throttler)
 8 |     {
 9 |         await throttler.WaitAsync();
10 |         return new Throttler(throttler);
11 |     }
12 | 
13 |     private class Throttler : IDisposable
14 |     {
15 |         private readonly SemaphoreSlim _throttler;
16 | 
17 |         public Throttler(SemaphoreSlim throttler) => _throttler = throttler;
18 | 
19 |         public void Dispose() => _throttler.Release();
20 |     }
21 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.PiiTypes/PiiAsSha256.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Security.Cryptography;
 3 | using System.Text;
 4 | 
 5 | namespace Gaev.Blog.Examples;
 6 | 
 7 | public class PiiAsSha256 : IPiiEncoder
 8 | {
 9 |     public string ToSystemString(PiiString piiString)
10 |     {
11 |         var dataToHash = Encoding.UTF8.GetBytes(piiString.ToString());
12 |         using var sha = SHA256.Create();
13 |         var hashedBuffer = sha.ComputeHash(dataToHash);
14 |         return Convert.ToBase64String(hashedBuffer);
15 |     }
16 | 
17 |     public PiiString ToPiiString(string str)
18 |         => throw new NotSupportedException();
19 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.OrderOfEnumValues/Gaev.Blog.Examples.OrderOfEnumValues.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         netcoreapp2.2
 5 | 
 6 |         false
 7 | 
 8 |         Gaev.Blog.Examples
 9 |     
10 | 
11 |     
12 |         
13 |         
14 |         
15 |     
16 | 
17 | 
18 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.ScriptInString/Views/Home/Problem1.cshtml:
--------------------------------------------------------------------------------
 1 | @using Newtonsoft.Json
 2 | @{
 3 |     var serverModel = new[]
 4 |     {
 5 |         new {Name = ""},
 6 |         new {Name = ""}
 7 |     };
 8 |     var json = JsonConvert.SerializeObject(serverModel);
 9 | }
10 | 
11 | 
12 | 
13 | 

14 | 
19 | 
20 | 
21 | 
22 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.ScriptInString/packages.config:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |   
4 |   
5 |   
6 |   
7 |   
8 |   
9 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.AzureServiceBus/Gaev.Blog.Examples.AzureServiceBus.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         netcoreapp2.2
 5 | 
 6 |         false
 7 |     
 8 | 
 9 |     
10 |         
11 |         
12 |         
13 |         
14 |     
15 | 
16 | 
17 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.EnumParsePitfall/Gaev.Blog.Examples.EnumParsePitfall.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         net6.0
 5 |         false
 6 |         Gaev.Blog.Examples
 7 |         9
 8 |     
 9 | 
10 |     
11 |         
12 |         
13 |         
14 |     
15 | 
16 | 
17 | 


--------------------------------------------------------------------------------
/Gaev.Blog.EnumAsStringTrap/Gaev.Blog.EnumAsStringTrap.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         net7.0
 5 |         disable
 6 |         Library
 7 |     
 8 | 
 9 |     
10 |         
11 |         
12 |         
13 |         
14 |     
15 | 
16 | 
17 | 
18 | 
19 | 
20 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.ScriptInString/Views/Home/Fix2.cshtml:
--------------------------------------------------------------------------------
 1 | @using Newtonsoft.Json
 2 | @{
 3 |     var serverModel = new[]
 4 |     {
 5 |         new {Name = ""},
 6 |         new {Name = ""}
 7 |     };
 8 |     var json = JsonConvert.SerializeObject(serverModel);
 9 | }
10 | 
11 | 
12 | 
13 | 

14 | 
19 | 
20 | 
21 | 
22 | 


--------------------------------------------------------------------------------
/Gaev.Blog.SecuredAppSettingsJson/appsettings.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "AppName": "SecuredAppSettingsJson",
 3 |   "DbConnectionString": "CipherText:09lXf8qen+mQJeAgl7lBcTIdCvpvDOQs7NL3oyiwOJpfqn26PWxkpEkS2+SAGf0BjCHT/uHfXzYZPQeyYyb+0A==",
 4 |   "CertificatePassphrase": "CipherText:liYy2ad2f5b4djk8FGpQ3y6+O1+of/ZFgJ1NEtxpRc+drUxKevKjm7RODxgSIvNE",
 5 |   "SendGrid": {
 6 |     "ApiKey": "CipherText:vZUMf1j23bLV3zY8+OmklWimYgf84TScmXD3lA2eEm2bqhvcjPQyHuiYQ7rqk6oZd3wrpfjASHWnEJ/892asuQ=="
 7 |   },
 8 |   "Partner": {
 9 |     "SftpUrl": "CipherText:6eyuaz4e1TbYP8Y2qQZpVSEuc7TYWR2sLQ2qrJGZDtMGpxJNvH7ietcp/nD/N3w6dEeShc2A9K3SboOY0W1txZ3/xHOzwSuax3bmKnidoQPh+V1OzT7nWnuGX+fQ4hmcE6v5wF6K4DJSbKYkau3ceA=="
10 |   }
11 | }
12 | 


--------------------------------------------------------------------------------
/Gaev.Blog.ParallelizableTests/DefaultTests.cs:
--------------------------------------------------------------------------------
 1 | using NUnit.Framework;
 2 | 
 3 | namespace Gaev.Blog;
 4 | 
 5 | // dotnet test --filter:"Category=Default"
 6 | // dotnet test --filter:"Category=Default|Category=Other"
 7 | 
 8 | [Category("Default")]
 9 | public class DefaultTests
10 | {
11 |     [Test]
12 |     public Task Test1()
13 |         => Task.Delay(1_000);
14 | 
15 |     [Test]
16 |     public Task Test2()
17 |         => Task.Delay(1_000);
18 | 
19 |     [Test]
20 |     public Task Test3()
21 |         => Task.Delay(1_000);
22 | 
23 |     [Test]
24 |     public Task Test4()
25 |         => Task.Delay(1_000);
26 | 
27 |     [Test]
28 |     public Task Test5()
29 |         => Task.Delay(1_000);
30 | }
31 | 


--------------------------------------------------------------------------------
/ArchitectureTestProjects/Gaev.Charlie/Gaev.Charlie.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         netstandard2.0
 5 |         10
 6 |     
 7 | 
 8 |     
 9 |       
10 |       
11 |       
12 |     
13 | 
14 |     
15 |       
16 |     
17 | 
18 | 
19 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.Mocking/CustomerServiceViaDelegate.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace Gaev.Blog.Examples
 4 | {
 5 |     public class CustomerServiceViaDelegate : ICustomerService
 6 |     {
 7 |         public Func NewId = () => Guid.NewGuid();
 8 |         public Func GetUtcNow = () => DateTime.UtcNow;
 9 | 
10 |         public CustomerServiceViaDelegate(Func newId = null, Func getUtcNow = null)
11 |         {
12 |             NewId = newId ?? NewId;
13 |             GetUtcNow = getUtcNow ?? GetUtcNow;
14 |         }
15 | 
16 |         public Customer RegisterCustomer(string name)
17 |         {
18 |             return new Customer(NewId(), GetUtcNow(), name);
19 |         }
20 |     }
21 | }


--------------------------------------------------------------------------------
/Gaev.Blog.EnumFlags/Gaev.Blog.EnumFlags.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         enable
 5 |         disable
 6 |         10
 7 |         false
 8 |         net7.0;net48
 9 |     
10 | 
11 |     
12 |       
13 |       
14 |       
15 |       
16 |     
17 | 
18 | 
19 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.Mocking/Gaev.Blog.Examples.Mocking.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         netcoreapp2.2
 5 | 
 6 |         false
 7 | 
 8 |         Gaev.Blog.Examples
 9 |     
10 | 
11 |     
12 |         
13 |         
14 |         
15 |         
16 |         
17 |     
18 | 
19 | 
20 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.ScriptInString/Views/Home/Fix1.cshtml:
--------------------------------------------------------------------------------
 1 | @using Newtonsoft.Json
 2 | @{
 3 |     var serverModel = new[]
 4 |     {
 5 |         new {Name = ""},
 6 |         new {Name = ""}
 7 |     };
 8 |     var json = JsonConvert.SerializeObject(serverModel, new JsonSerializerSettings
 9 |     {
10 |         StringEscapeHandling = StringEscapeHandling.EscapeHtml
11 |     });
12 | }
13 | 
14 | 
15 | 
16 | 

17 | 
22 | 
23 | 
24 | 
25 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.PiiTypes/SystemTextJson/PiiStringConverter.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Text.Json;
 3 | using System.Text.Json.Serialization;
 4 | 
 5 | namespace Gaev.Blog.Examples.SystemTextJson;
 6 | 
 7 | public class PiiStringConverter : JsonConverter
 8 | {
 9 |     private readonly IPiiEncoder _encoder;
10 | 
11 |     public PiiStringConverter(IPiiEncoder encoder)
12 |         => _encoder = encoder;
13 | 
14 |     public override PiiString Read(ref Utf8JsonReader reader, Type _, JsonSerializerOptions __)
15 |         => _encoder.ToPiiString(reader.GetString());
16 | 
17 |     public override void Write(Utf8JsonWriter writer, PiiString value, JsonSerializerOptions _)
18 |         => writer.WriteStringValue(_encoder.ToSystemString(value));
19 | }


--------------------------------------------------------------------------------
/Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6/Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         net6.0
 5 |         disable
 6 |         enable
 7 |     
 8 | 
 9 |     
10 |         
11 |     
12 | 
13 |     
14 |       
15 |     
16 | 
17 |     
18 |       
19 |     
20 | 
21 | 
22 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.WarmUpAspNetMvc/Global.asax.cs:
--------------------------------------------------------------------------------
 1 | using System.Web.Mvc;
 2 | using System.Web.Routing;
 3 | 
 4 | namespace Gaev.Blog.Examples
 5 | {
 6 |     public class MvcApplication : System.Web.HttpApplication
 7 |     {
 8 |         protected void Application_Start()
 9 |         {
10 |             AreaRegistration.RegisterAllAreas();
11 |             GlobalFilters.Filters.Add(new HandleErrorAttribute());
12 |             RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
13 | 
14 |             RouteTable.Routes.MapRoute(
15 |                 name: "Default",
16 |                 url: "{controller}/{action}/{id}",
17 |                 defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional}
18 |             );
19 |         }
20 |     }
21 | }


--------------------------------------------------------------------------------
/Gaev.Blog.ParallelizableTests/NonParallelizableTests.cs:
--------------------------------------------------------------------------------
 1 | using NUnit.Framework;
 2 | 
 3 | namespace Gaev.Blog;
 4 | 
 5 | // dotnet test --filter:"Category=NonParallelizable"
 6 | // dotnet test --filter:"Category=NonParallelizable|Category=Other"
 7 | 
 8 | [NonParallelizable, Category("NonParallelizable")]
 9 | public class NonParallelizableTests
10 | {
11 |     [Test]
12 |     public Task Test1()
13 |         => Task.Delay(1_000);
14 | 
15 |     [Test]
16 |     public Task Test2()
17 |         => Task.Delay(1_000);
18 | 
19 |     [Test]
20 |     public Task Test3()
21 |         => Task.Delay(1_000);
22 | 
23 |     [Test]
24 |     public Task Test4()
25 |         => Task.Delay(1_000);
26 | 
27 |     [Test]
28 |     public Task Test5()
29 |         => Task.Delay(1_000);
30 | }
31 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.PiiTypes/NewtonsoftJson/PiiStringConverter.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using Newtonsoft.Json;
 3 | 
 4 | namespace Gaev.Blog.Examples.NewtonsoftJson;
 5 | 
 6 | public class PiiStringConverter : JsonConverter
 7 | {
 8 |     private readonly IPiiEncoder _encoder;
 9 | 
10 |     public PiiStringConverter(IPiiEncoder encoder)
11 |         => _encoder = encoder;
12 | 
13 |     public override PiiString ReadJson(JsonReader reader, Type _, PiiString __, bool ___, JsonSerializer ____)
14 |         => reader.Value is string valueAsString
15 |             ? _encoder.ToPiiString(valueAsString)
16 |             : null;
17 | 
18 |     public override void WriteJson(JsonWriter writer, PiiString value, JsonSerializer _)
19 |         => writer.WriteValue(_encoder.ToSystemString(value));
20 | }


--------------------------------------------------------------------------------
/Gaev.Blog.ParallelizableTests/Gaev.Blog.ParallelizableTests.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         net7.0
 5 |         enable
 6 |         disable
 7 | 
 8 |         false
 9 |         true
10 |         Library
11 |         Gaev.Blog
12 |     
13 | 
14 |     
15 |         
16 |         
17 |         
18 |     
19 | 
20 | 
21 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.SqlQueryLogger/ProfilerGetter.cs:
--------------------------------------------------------------------------------
 1 | using System.Threading.Tasks;
 2 | using StackExchange.Profiling;
 3 | using StackExchange.Profiling.Internal;
 4 | 
 5 | namespace Gaev.Blog.Examples
 6 | {
 7 |     public class ProfilerGetter : IAsyncProfilerProvider
 8 |     {
 9 |         public ProfilerGetter(MiniProfiler profiler)
10 |         {
11 |             CurrentProfiler = profiler;
12 |         }
13 | 
14 |         public MiniProfiler Start(string profilerName, MiniProfilerBaseOptions options) => CurrentProfiler;
15 | 
16 |         public void Stopped(MiniProfiler profiler, bool discardResults)
17 |         {
18 |         }
19 | 
20 |         public Task StoppedAsync(MiniProfiler profiler, bool discardResults) => Task.CompletedTask;
21 | 
22 |         public MiniProfiler CurrentProfiler { get; }
23 |     }
24 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.WarmUpAspNetMvc/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
 1 | using System.Web.Mvc;
 2 | 
 3 | namespace Gaev.Blog.Examples.Controllers
 4 | {
 5 |     public class HomeController : Controller
 6 |     {
 7 |         public ActionResult Index()
 8 |         {
 9 |             InitialSlowdown.For("Index");
10 |             return View();
11 |         }
12 | 
13 |         public ActionResult About()
14 |         {
15 |             InitialSlowdown.For("About");
16 |             ViewBag.Message = "Your application description page.";
17 |             return View();
18 |         }
19 | 
20 |         public ActionResult Contact()
21 |         {
22 |             InitialSlowdown.For("Contact");
23 |             ViewBag.Message = "Your contact page.";
24 |             return View();
25 |         }
26 |     }
27 | }


--------------------------------------------------------------------------------
/Gaev.Blog.CSharp12AndNetFramework/Gaev.Blog.CSharp12AndNetFramework.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 |     
 3 |         Exe
 4 |         net48
 5 |         12
 6 |     
 7 |     
 8 |         
 9 | 
10 |         
11 |         
12 |             all
13 |             runtime; build; native; contentfiles; analyzers; buildtransitive
14 |         
15 | 
16 |     
17 | 
18 | 


--------------------------------------------------------------------------------
/Gaev.Blog.CSharp12AndNetFramework/Program.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace Gaev.Blog.CSharp12AndNetFramework;
 4 | 
 5 | public static class Program
 6 | {
 7 |     public static void Main(string[] args)
 8 |     {
 9 |         Console.WriteLine("Hello, World!");
10 | 
11 |         ReadOnlySpan numbers = [1, 2, 3, 4, 5, 6];
12 |         // Index
13 |         int secondToLast = numbers[^2];
14 |         // Range
15 |         var firstFour = numbers[..4];
16 |         // List pattern
17 |         if (numbers is [_, 2, var third, .. var rest])
18 |         {
19 |         }
20 |     }
21 | 
22 |     // Records
23 |     public record Person(string FirstName, string LastName);
24 | 
25 |     // Required member, init
26 |     public class Config
27 |     {
28 |         public required string ConnectionString { get; init; }
29 |     }
30 | }
31 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.SqlQueryLogger/TestLogger.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Collections.Generic;
 3 | using Newtonsoft.Json;
 4 | using NLog;
 5 | 
 6 | namespace Gaev.Blog.Examples
 7 | {
 8 |     public class TestLogger : Logger, ILogger
 9 |     {
10 |         public readonly List Warnings = new List();
11 | 
12 |         void ILogger.Warn(string message, TArgument argument)
13 |         {
14 |             lock (Warnings)
15 |                 Warnings.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(argument)));
16 |         }
17 | 
18 |         void ILogger.Warn(Exception _, string message, params object[] args)
19 |         {
20 |             lock (Warnings)
21 |                 Warnings.Add(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(args[0])));
22 |         }
23 |     }
24 | }


--------------------------------------------------------------------------------
/Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6/appsettings.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "Logging": {
 3 |     "LogLevel": {
 4 |       "Default": "Information",
 5 |       "Microsoft.AspNetCore": "Warning"
 6 |     }
 7 |   },
 8 |   "AllowedHosts": "*",
 9 |   "DbConnectionString": "CipherText:09lXf8qen+mQJeAgl7lBcTIdCvpvDOQs7NL3oyiwOJpfqn26PWxkpEkS2+SAGf0BjCHT/uHfXzYZPQeyYyb+0A==",
10 |   "CertificatePassphrase": "CipherText:liYy2ad2f5b4djk8FGpQ3y6+O1+of/ZFgJ1NEtxpRc+drUxKevKjm7RODxgSIvNE",
11 |   "SendGrid": {
12 |     "ApiKey": "CipherText:vZUMf1j23bLV3zY8+OmklWimYgf84TScmXD3lA2eEm2bqhvcjPQyHuiYQ7rqk6oZd3wrpfjASHWnEJ/892asuQ=="
13 |   },
14 |   "Partner": {
15 |     "SftpUrl": "CipherText:6eyuaz4e1TbYP8Y2qQZpVSEuc7TYWR2sLQ2qrJGZDtMGpxJNvH7ietcp/nD/N3w6dEeShc2A9K3SboOY0W1txZ3/xHOzwSuax3bmKnidoQPh+V1OzT7nWnuGX+fQ4hmcE6v5wF6K4DJSbKYkau3ceA=="
16 |   }
17 | }
18 | 


--------------------------------------------------------------------------------
/Gaev.Blog.ParallelizableTests/ParallelizableTests.cs:
--------------------------------------------------------------------------------
 1 | using NUnit.Framework;
 2 | 
 3 | namespace Gaev.Blog;
 4 | 
 5 | // dotnet test --filter:"Category=Parallelizable"
 6 | // dotnet test --filter:"Category=Parallelizable|Category=Other"
 7 | // dotnet test --filter:"Category=Parallelizable|Category=OtherParallelizable"
 8 | 
 9 | [Parallelizable, Category("Parallelizable")]
10 | public class ParallelizableTests
11 | {
12 |     [Test]
13 |     public Task Test1()
14 |         => Task.Delay(1_000);
15 | 
16 |     [Test]
17 |     public Task Test2()
18 |         => Task.Delay(1_000);
19 | 
20 |     [Test]
21 |     public Task Test3()
22 |         => Task.Delay(1_000);
23 | 
24 |     [Test]
25 |     public Task Test4()
26 |         => Task.Delay(1_000);
27 | 
28 |     [Test]
29 |     public Task Test5()
30 |         => Task.Delay(1_000);
31 | }
32 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.SqlQueryLogger/packages.config:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |   
 5 |   
 6 |   
 7 |   
 8 |   
 9 |   
10 |   
11 |   
12 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.KeybaseSignIn/Startup.cs:
--------------------------------------------------------------------------------
 1 | using Microsoft.AspNetCore.Authentication.Cookies;
 2 | using Microsoft.AspNetCore.Builder;
 3 | using Microsoft.AspNetCore.Hosting;
 4 | using Microsoft.Extensions.DependencyInjection;
 5 | 
 6 | namespace Gaev.Blog.Examples
 7 | {
 8 |     public class Startup
 9 |     {
10 |         public void ConfigureServices(IServiceCollection services)
11 |         {
12 |             services.AddMvc();
13 |             services
14 |                 .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
15 |                 .AddCookie();
16 |         }
17 | 
18 |         public void Configure(IApplicationBuilder app, IHostingEnvironment env) =>
19 |             app
20 |                 .UseAuthentication()
21 |                 .UseMvc()
22 |                 .UseDefaultFiles()
23 |                 .UseStaticFiles();
24 |     }
25 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.PiiTypes/Serilog/PiiStringTests.cs:
--------------------------------------------------------------------------------
 1 | using NUnit.Framework;
 2 | using Serilog;
 3 | 
 4 | namespace Gaev.Blog.Examples.Serilog;
 5 | 
 6 | public class PiiStringTests
 7 | {
 8 |     [Test]
 9 |     public void Serilog_should_work()
10 |     {
11 |         var sha256 = new PiiAsSha256();
12 |         var logger = new LoggerConfiguration()
13 |             .WriteTo.Console()
14 |             .Destructure.ByTransforming(e => sha256.ToSystemString(e))
15 |             .CreateLogger();
16 | 
17 |         var user = new User
18 |         {
19 |             Name = "John Doe",
20 |             Email = "john.doe@test.com"
21 |         };
22 |         logger.Information("The user is {@Data}", user);
23 |         logger.Information("The email is {@Data}", user.Email);
24 |         logger.Information("The email is {@Data}", new {user.Email});
25 |     }
26 | }


--------------------------------------------------------------------------------
/Gaev.Blog.SecuredAppSettingsJson/Program.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using Microsoft.Extensions.Configuration;
 3 | 
 4 | namespace Gaev.Blog.SecuredAppSettingsJson
 5 | {
 6 |     class Program
 7 |     {
 8 |         static void Main(string[] args)
 9 |         {
10 |             var config = new ConfigurationBuilder()
11 |                 .AddJsonFile("appsettings.json")
12 |                 .AddEnvironmentVariables()
13 |                 .Build()
14 |                 .Decrypt(keyPath: "CipherKey", cipherPrefix: "CipherText:");
15 |             Console.WriteLine($@"
16 | AppName:               {config["AppName"]}
17 | DbConnectionString:    {config["DbConnectionString"]}
18 | CertificatePassphrase: {config["CertificatePassphrase"]}
19 | SendGrid.ApiKey:       {config["SendGrid:ApiKey"]}
20 | Partner.SftpUrl:       {config["Partner:SftpUrl"]}
21 | ");
22 |         }
23 |     }
24 | }


--------------------------------------------------------------------------------
/Gaev.Blog.ParallelizableTests/ParallelizableAllTests.cs:
--------------------------------------------------------------------------------
 1 | using NUnit.Framework;
 2 | 
 3 | namespace Gaev.Blog;
 4 | 
 5 | // dotnet test --filter:"Category=ParallelizableAll"
 6 | // dotnet test --filter:"Category=ParallelizableAll|Category=Other"
 7 | // dotnet test --filter:"Category=ParallelizableAll|Category=OtherParallelizable"
 8 | 
 9 | [Parallelizable(ParallelScope.All), Category("ParallelizableAll")]
10 | public class ParallelizableAllTests
11 | {
12 |     [Test]
13 |     public Task Test1()
14 |         => Task.Delay(1_000);
15 | 
16 |     [Test]
17 |     public Task Test2()
18 |         => Task.Delay(1_000);
19 | 
20 |     [Test]
21 |     public Task Test3()
22 |         => Task.Delay(1_000);
23 | 
24 |     [Test]
25 |     public Task Test4()
26 |         => Task.Delay(1_000);
27 | 
28 |     [Test]
29 |     public Task Test5()
30 |         => Task.Delay(1_000);
31 | }
32 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Sha256ForStream/Gaev.Blog.Sha256ForStream.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         net7.0
 5 |         enable
 6 |         enable
 7 | 
 8 |         false
 9 |         true
10 |         Gaev.Blog
11 |     
12 | 
13 |     
14 |         
15 |         
16 |         
17 |         
18 |         
19 |     
20 | 
21 | 
22 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.PiiTypes/SystemTextJson/PiiStringTests.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Text.Json;
 3 | using FluentAssertions;
 4 | using NUnit.Framework;
 5 | 
 6 | namespace Gaev.Blog.Examples.SystemTextJson;
 7 | 
 8 | public class PiiStringTests
 9 | {
10 |     [Test]
11 |     public void SystemTextJson_should_work()
12 |     {
13 |         // Given
14 |         var user = new User
15 |         {
16 |             Name = "John Doe",
17 |             Email = "john.doe@test.com"
18 |         };
19 |         var settings = new JsonSerializerOptions { Converters = { new PiiStringConverter(new PiiAsPlainText()) } };
20 | 
21 |         // When
22 |         var json = JsonSerializer.Serialize(user, settings);
23 |         var actual = JsonSerializer.Deserialize(json, settings);
24 | 
25 |         // Then
26 |         Console.WriteLine(json);
27 |         actual.Should().BeEquivalentTo(user);
28 |     }
29 | }


--------------------------------------------------------------------------------
/Gaev.Blog.EnumAsStringTrap/NewtonsoftJson/UnknownEnumConverter.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using Newtonsoft.Json;
 3 | using Newtonsoft.Json.Converters;
 4 | 
 5 | namespace Gaev.Blog.EnumAsStringTrap.NewtonsoftJson;
 6 | 
 7 | public class UnknownEnumConverter : StringEnumConverter
 8 | {
 9 |     // https://stackoverflow.com/a/51847437
10 |     public override object ReadJson(JsonReader reader, Type enumType, object existingValue, JsonSerializer serializer)
11 |     {
12 |         try
13 |         {
14 |             return base.ReadJson(reader, enumType, existingValue, serializer);
15 |         }
16 |         catch (JsonSerializationException) when (enumType.IsEnum)
17 |         {
18 |             // TODO: Modify logic here to return custom faulty value
19 |             // This returns default value https://stackoverflow.com/a/353073
20 |             return Activator.CreateInstance(enumType);
21 |         }
22 |     }
23 | }
24 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.GoogleAlert/Gaev.Blog.Examples.GoogleAlert.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         Exe
 5 |         netcoreapp2.2
 6 |         Gaev.Blog.Examples
 7 |         7.2
 8 |     
 9 | 
10 |     
11 |       
12 |       
13 |       
14 |       
15 |     
16 | 
17 |     
18 |       
19 |         PreserveNewest
20 |       
21 |     
22 | 
23 | 
24 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.KeybaseSignIn/Gaev.Blog.Examples.KeybaseSignIn.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         netcoreapp2.2
 5 |         Gaev.Blog.Examples
 6 |     
 7 | 
 8 |     
 9 |         
10 |         
11 |         
12 |         
13 |         
14 |         
15 |         
16 |     
17 | 
18 | 
19 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.ArchitectureTests/Gaev.Blog.Examples.ArchitectureTests.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         net6.0
 5 |         disable
 6 |         Gaev.Blog.Examples
 7 |     
 8 | 
 9 |     
10 |       
11 |       
12 |       
13 |       
14 |       
15 |       
16 |     
17 | 
18 |     
19 |       
20 |     
21 | 
22 | 
23 | 


--------------------------------------------------------------------------------
/Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6/Properties/launchSettings.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "$schema": "https://json.schemastore.org/launchsettings.json",
 3 |   "iisSettings": {
 4 |     "windowsAuthentication": false,
 5 |     "anonymousAuthentication": true,
 6 |     "iisExpress": {
 7 |       "applicationUrl": "http://localhost:36567",
 8 |       "sslPort": 44354
 9 |     }
10 |   },
11 |   "profiles": {
12 |     "Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi": {
13 |       "commandName": "Project",
14 |       "dotnetRunMessages": true,
15 |       "launchBrowser": true,
16 |       "launchUrl": "swagger",
17 |       "applicationUrl": "http://localhost:5165",
18 |       "environmentVariables": {
19 |         "ASPNETCORE_ENVIRONMENT": "Development"
20 |       }
21 |     },
22 |     "IIS Express": {
23 |       "commandName": "IISExpress",
24 |       "launchBrowser": true,
25 |       "launchUrl": "swagger",
26 |       "environmentVariables": {
27 |         "ASPNETCORE_ENVIRONMENT": "Development"
28 |       }
29 |     }
30 |   }
31 | }
32 | 


--------------------------------------------------------------------------------
/Gaev.Blog.SecuredAppSettingsJson/Gaev.Blog.SecuredAppSettingsJson.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         Exe
 5 |         netcoreapp3.1
 6 |         8
 7 |         false
 8 |     
 9 | 
10 |     
11 |       
12 |       
13 |       
14 |       
15 |       
16 |     
17 | 
18 |     
19 |       
20 |         PreserveNewest
21 |       
22 |     
23 | 
24 | 
25 | 


--------------------------------------------------------------------------------
/Gaev.Blog.SecuredAppSettingsJson/ConfigurationRootExtensions.cs:
--------------------------------------------------------------------------------
 1 | using Microsoft.Extensions.Configuration;
 2 | 
 3 | namespace Gaev.Blog.SecuredAppSettingsJson
 4 | {
 5 |     public static class ConfigurationRootExtensions
 6 |     {
 7 |         public static IConfigurationRoot Decrypt(this IConfigurationRoot root, string keyPath, string cipherPrefix)
 8 |         {
 9 |             var secret = root[keyPath];
10 |             var cipher = new Aes256Cipher(secret);
11 |             DecryptInChildren(root);
12 |             return root;
13 | 
14 |             void DecryptInChildren(IConfiguration parent)
15 |             {
16 |                 foreach (var child in parent.GetChildren())
17 |                 {
18 |                     if (child.Value?.StartsWith(cipherPrefix) == true)
19 |                     {
20 |                         var cipherText = child.Value.Substring(cipherPrefix.Length);
21 |                         parent[child.Key] = cipher.Decrypt(cipherText);
22 |                     }
23 | 
24 |                     DecryptInChildren(child);
25 |                 }
26 |             }
27 |         }
28 |     }
29 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.HelloSshDeploy/Program.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Threading;
 3 | using System.Threading.Tasks;
 4 | using Serilog;
 5 | using Serilog.Core;
 6 | 
 7 | namespace Gaev.Blog.Examples
 8 | {
 9 |     class Program
10 |     {
11 |         static async Task Main(string[] args)
12 |         {
13 |             var cancellation = new CancellationTokenSource();
14 |             Console.CancelKeyPress += (_, e) => { e.Cancel = true; cancellation.Cancel(); };
15 |             using (var logger = new LoggerConfiguration()
16 |                 .WriteTo.Console()
17 |                 .WriteTo.File("HelloSshDeploy.log")
18 |                 .CreateLogger())
19 |                 await RunApplication(logger, cancellation.Token);
20 |         }
21 | 
22 |         static async Task RunApplication(Logger logger, CancellationToken cancellation)
23 |         {
24 |             logger.Information("Hello World!");
25 |             try
26 |             {
27 |                 await Task.Delay(Timeout.Infinite, cancellation);
28 |             }
29 |             catch (TaskCanceledException) { }
30 |             logger.Information("Goodbye World!");
31 |         }
32 |     }
33 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.Mocking/CustomerServiceViaInterface.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace Gaev.Blog.Examples
 4 | {
 5 |     public class CustomerServiceViaInterface: ICustomerService
 6 |     {
 7 |         private readonly IIdGenerator _idGenerator;
 8 |         private readonly ISystemTime _systemTime;
 9 | 
10 |         public CustomerServiceViaInterface(IIdGenerator idGenerator, ISystemTime systemTime)
11 |         {
12 |             _idGenerator = idGenerator;
13 |             _systemTime = systemTime;
14 |         }
15 | 
16 |         public Customer RegisterCustomer(string name)
17 |         {
18 |             return new Customer(_idGenerator.NewId(), _systemTime.GetUtcNow(), name);
19 |         }
20 |     }
21 | 
22 |     public interface IIdGenerator
23 |     {
24 |         Guid NewId();
25 |     }
26 | 
27 |     public class IdGenerator : IIdGenerator
28 |     {
29 |         public Guid NewId() => Guid.NewGuid();
30 |     }
31 | 
32 |     public interface ISystemTime
33 |     {
34 |         DateTime GetUtcNow();
35 |     }
36 | 
37 |     public class SystemTime : ISystemTime
38 |     {
39 |         public DateTime GetUtcNow() => DateTime.UtcNow;
40 |     }
41 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.PiiTypes/Gaev.Blog.Examples.PiiTypes.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         net6.0
 5 |         disable
 6 | 
 7 |         false
 8 | 
 9 |         Gaev.Blog.Examples
10 |     
11 | 
12 |     
13 |         
14 |         
15 |         
16 |         
17 |         
18 |         
19 |         
20 |         
21 |         
22 |         
23 |     
24 | 
25 | 
26 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.HelloSshDeploy/deploy.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | ssh root@192.168.2.4 'bash -s' <<'ENDSSH'
 3 | printf "Stopping service...\n"
 4 | systemctl stop HelloSshDeploy
 5 | printf "Service is "
 6 | systemctl is-active HelloSshDeploy
 7 | mkdir -p /apps/HelloSshDeploy
 8 | ENDSSH
 9 | 
10 | printf "Uploading new version of service...\n"
11 | rsync -v -a ./bin/Release/netcoreapp2.2/ubuntu.16.04-x64/publish/ root@192.168.2.4:/apps/HelloSshDeploy/
12 | 
13 | ssh root@192.168.2.4 'bash -s' <<'ENDSSH'
14 | chmod 777 /apps/HelloSshDeploy/Gaev.Blog.Examples.HelloSshDeploy
15 | if [[ ! -e /etc/systemd/system/HelloSshDeploy.service ]]; then
16 |     printf "Installing service...\n"
17 |     cat > /etc/systemd/system/HelloSshDeploy.service <<'EOF'
18 |     [Unit]
19 |     Description=HelloSshDeploy
20 |     After=network.target
21 |     
22 |     [Service]
23 |     WorkingDirectory=/apps/HelloSshDeploy
24 |     ExecStart=/apps/HelloSshDeploy/Gaev.Blog.Examples.HelloSshDeploy
25 |     Restart=always
26 |     KillSignal=SIGINT
27 |     
28 |     [Install]
29 |     WantedBy=multi-user.target
30 | EOF
31 |     systemctl daemon-reload
32 |     systemctl enable HelloSshDeploy
33 | fi
34 | printf "Starting service...\n"
35 | systemctl start HelloSshDeploy
36 | printf "Service is "
37 | systemctl is-active HelloSshDeploy
38 | ENDSSH


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.WebhookTests/packages.config:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |   
 5 |   
 6 |   
 7 |   
 8 |   
 9 |   
10 |   
11 |   
12 |   
13 |   
14 |   
15 |   
16 |   
17 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.WarmUpAspNetMvc/packages.config:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |   
 5 |   
 6 |   
 7 |   
 8 |   
 9 |   
10 |   
11 |   
12 |   
13 |   
14 |   
15 |   
16 |   
17 | 


--------------------------------------------------------------------------------
/Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6/Program.cs:
--------------------------------------------------------------------------------
 1 | using Gaev.Blog.SecuredAppSettingsJson;
 2 | using Microsoft.AspNetCore.Mvc;
 3 | 
 4 | var builder = WebApplication.CreateBuilder(args);
 5 | 
 6 | // This will decrypt the configuration
 7 | builder.Configuration.Decrypt(keyPath: "CipherKey", cipherPrefix: "CipherText:");
 8 | 
 9 | // Add services to the container.
10 | builder.Services.AddControllers();
11 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
12 | builder.Services.AddEndpointsApiExplorer();
13 | builder.Services.AddSwaggerGen();
14 | 
15 | var app = builder.Build();
16 | 
17 | // Configure the HTTP request pipeline.
18 | if (app.Environment.IsDevelopment())
19 | {
20 |     app.UseSwagger();
21 |     app.UseSwaggerUI();
22 | }
23 | 
24 | // app.UseHttpsRedirection();
25 | 
26 | app.UseAuthorization();
27 | 
28 | app.MapControllers();
29 | 
30 | app.Run();
31 | 
32 | [ApiController]
33 | [Route("[controller]")]
34 | public class TestController : ControllerBase
35 | {
36 |     private readonly IConfiguration _config;
37 | 
38 |     public TestController(IConfiguration config)
39 |         => _config = config;
40 | 
41 |     [HttpGet]
42 |     public string TestConfig()
43 |         => _config["DbConnectionString"];
44 | }
45 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.SelfDocumentedApp/packages.config:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |   
 5 |   
 6 |   
 7 |   
 8 |   
 9 |   
10 |   
11 |   
12 |   
13 |   
14 |   
15 |   
16 |   
17 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.KeybaseSignIn/deploy.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/bash
 2 | ssh root@app.gaevoy.com 'bash -s' <<'ENDSSH'
 3 | printf "Stopping service...\n"
 4 | systemctl stop GaevKeybaseSignIn
 5 | printf "Service is "
 6 | systemctl is-active GaevKeybaseSignIn
 7 | mkdir -p /apps/GaevKeybaseSignIn
 8 | ENDSSH
 9 | 
10 | printf "Uploading new version of service...\n"
11 | rsync -v -a ./bin/Release/netcoreapp2.2/ubuntu.16.04-x64/publish/ root@app.gaevoy.com:/apps/GaevKeybaseSignIn/
12 | 
13 | ssh root@app.gaevoy.com 'bash -s' <<'ENDSSH'
14 | chmod 777 /apps/GaevKeybaseSignIn/Gaev.Blog.Examples.KeybaseSignIn
15 | if [[ ! -e /etc/systemd/system/GaevKeybaseSignIn.service ]]; then
16 |     printf "Installing service...\n"
17 |     cat > /etc/systemd/system/GaevKeybaseSignIn.service <<'EOF'
18 |     [Unit]
19 |     Description=GaevKeybaseSignIn
20 |     After=network.target
21 |     
22 |     [Service]
23 |     WorkingDirectory=/apps/GaevKeybaseSignIn
24 |     ExecStart=/apps/GaevKeybaseSignIn/Gaev.Blog.Examples.KeybaseSignIn
25 |     Restart=always
26 |     KillSignal=SIGINT
27 |     
28 |     [Install]
29 |     WantedBy=multi-user.target
30 | EOF
31 |     systemctl daemon-reload
32 |     systemctl enable GaevKeybaseSignIn
33 | fi
34 | printf "Starting service...\n"
35 | systemctl start GaevKeybaseSignIn
36 | printf "Service is "
37 | systemctl is-active GaevKeybaseSignIn
38 | ENDSSH


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.FileReceiver/Program.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.IO;
 3 | using Microsoft.AspNetCore;
 4 | using Microsoft.AspNetCore.Builder;
 5 | using Microsoft.AspNetCore.Hosting;
 6 | using Microsoft.AspNetCore.Http;
 7 | 
 8 | namespace Gaev.Blog.Examples.FileReceiver
 9 | {
10 |     public class Program
11 |     {
12 |         public static void Main(string[] args) =>
13 |             WebHost.CreateDefaultBuilder(args)
14 |                 .UseStartup()
15 |                 .UseKestrel(opt => { opt.Limits.MaxRequestBodySize = null; })
16 |                 .Build()
17 |                 .Run();
18 |     }
19 | 
20 |     public class Startup
21 |     {
22 |         // tar zcf - /var/www | curl --data-binary @- http://f81512d0.ngrok.io/www.tar.gz
23 |         // zip -rq - /var/www | curl --data-binary @- http://f81512d0.ngrok.io/www.zip
24 |         public void Configure(IApplicationBuilder app, IHostingEnvironment env)
25 |         {
26 |             app.Run(async ctx =>
27 |             {
28 |                 using (var file = File.OpenWrite(Path.GetFileName(ctx.Request.Path)))
29 |                 {
30 |                     await ctx.Request.Body.CopyToAsync(file);
31 |                     await ctx.Response.WriteAsync($"Received in `{file.Name}`\n");
32 |                 }
33 |             });
34 |         }
35 |     }
36 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.SelfDocumentedFSM/packages.config:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |   
 5 |   
 6 |   
 7 |   
 8 |   
 9 |   
10 |   
11 |   
12 |   
13 |   
14 |   
15 |   
16 |   
17 |   
18 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.PiiTypes/PiiStringTests.cs:
--------------------------------------------------------------------------------
 1 | using FluentAssertions;
 2 | using NUnit.Framework;
 3 | 
 4 | namespace Gaev.Blog.Examples;
 5 | 
 6 | public class PiiStringTests
 7 | {
 8 |     [TestCase("a", "a", true)]
 9 |     [TestCase("", "", true)]
10 |     [TestCase(null, null, true)]
11 |     [TestCase("a", "b", false)]
12 |     [TestCase("a", null, false)]
13 |     [TestCase(null, "b", false)]
14 |     public void EqOperator(string a, string b, bool expected)
15 |     {
16 |         var actual = (PiiString)a == (PiiString)b;
17 |         actual.Should().Be(expected);
18 |     }
19 | 
20 |     [TestCase("a", "a", false)]
21 |     [TestCase("", "", false)]
22 |     [TestCase(null, null, false)]
23 |     [TestCase("a", "b", true)]
24 |     [TestCase("a", null, true)]
25 |     [TestCase(null, "b", true)]
26 |     public void NotEqOperator(string a, string b, bool expected)
27 |     {
28 |         var actual = (PiiString)a != (PiiString)b;
29 |         actual.Should().Be(expected);
30 |     }
31 | 
32 |     [TestCase("a", "a", true)]
33 |     [TestCase("", "", true)]
34 |     [TestCase("a", "b", false)]
35 |     [TestCase("a", null, false)]
36 |     public void Equals(string a, string b, bool expected)
37 |     {
38 |         var aAsPiiString = (PiiString)a;
39 |         aAsPiiString.Equals((PiiString)b).Should().Be(expected);
40 |         aAsPiiString.Equals((object)b).Should().Be(expected);
41 |     }
42 | }


--------------------------------------------------------------------------------
/Gaev.Blog.EnumFlags/EnumFlagsPerformance.cs:
--------------------------------------------------------------------------------
 1 | using BenchmarkDotNet.Attributes;
 2 | using BenchmarkDotNet.Jobs;
 3 | 
 4 | namespace Gaev.Blog.EnumFlags;
 5 | 
 6 | [SimpleJob(RuntimeMoniker.Net48)]
 7 | [SimpleJob(RuntimeMoniker.Net70)]
 8 | [MemoryDiagnoser]
 9 | public class EnumFlagsPerformance
10 | {
11 |     private Pet _value = Pet.Cat | Pet.Dog;
12 | 
13 |     [Benchmark]
14 |     public void RaiseFlag_Native() => _value = _value | Pet.Bird;
15 | 
16 |     [Benchmark]
17 |     public void RaiseFlag_NonBoxing() => _value = _value.SetFlag(Pet.Bird, true);
18 | 
19 |     [Benchmark]
20 |     public void RaiseFlag_Boxing() => _value = SetFlagWithBoxing(_value, Pet.Bird, true);
21 | 
22 |     [Benchmark]
23 |     public void LowerFlag_Native() => _value = _value & ~Pet.Dog;
24 | 
25 |     [Benchmark]
26 |     public void LowerFlag_NonBoxing() => _value = _value.SetFlag(Pet.Dog, false);
27 | 
28 |     [Benchmark]
29 |     public void LowerFlag_Boxing() => _value = SetFlagWithBoxing(_value, Pet.Dog, false);
30 | 
31 |     private static TEnum SetFlagWithBoxing(TEnum value, TEnum flag, bool state) where TEnum : Enum
32 |     {
33 |         // conversion with boxing
34 |         var left = Convert.ToUInt64(value);
35 |         var right = Convert.ToUInt64(flag);
36 |         var result = state
37 |             ? left | right
38 |             : left & ~right;
39 |         return (TEnum)Convert.ChangeType(result, Enum.GetUnderlyingType(typeof(TEnum)));
40 |     }
41 | }
42 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.ArchitectureTests/DotNetAssemblyExt.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Linq;
 3 | using System.Runtime.Versioning;
 4 | using System.Text;
 5 | 
 6 | namespace Gaev.Blog.Examples;
 7 | 
 8 | public static class DotNetAssemblyExt
 9 | {
10 |     public static string GetTargetFramework(this DotNetAssembly assembly)
11 |         => assembly.MonoCecilAssembly.CustomAttributes
12 |             .Where(e => e.AttributeType.FullName == typeof(TargetFrameworkAttribute).FullName)
13 |             .SelectMany(e => e.ConstructorArguments)
14 |             .Select(e => e.Value as string)
15 |             .FirstOrDefault() ?? "";
16 | 
17 |     public static bool IsDotNetStandard(this DotNetAssembly assembly)
18 |         => assembly.Name == "netstandard" || assembly.GetTargetFramework().StartsWith(".NETStandard");
19 | 
20 |     public static string RenderPlantUmlDiagram(this DotNetAssembly project, Func condition)
21 |     {
22 |         var plantUmlCode = new StringBuilder();
23 | 
24 |         void Render(DotNetAssembly parent)
25 |         {
26 |             plantUmlCode.AppendLine($"[{parent}]");
27 |             foreach (var dependency in parent.Dependencies.Where(condition))
28 |             {
29 |                 plantUmlCode.AppendLine($"[{parent}] -up-> [{dependency}]");
30 |                 Render(dependency);
31 |             }
32 |         }
33 | 
34 |         Render(project);
35 |         return $"@startuml\n\n{plantUmlCode}\n@enduml";
36 |     }
37 | }
38 | 


--------------------------------------------------------------------------------
/Gaev.Blog.EnumFlags/EnumFlagExtensions.cs:
--------------------------------------------------------------------------------
 1 | using System.Linq.Expressions;
 2 | 
 3 | namespace Gaev.Blog.EnumFlags;
 4 | 
 5 | public static class EnumFlagExtensions
 6 | {
 7 |     public static TEnum SetFlag(this TEnum value, TEnum flag, bool state) where TEnum : Enum
 8 |     {
 9 |         // non-boxing conversion
10 |         var left = Caster.Cast(value);
11 |         var right = Caster.Cast(flag);
12 |         var result = state
13 |             ? left | right
14 |             : left & ~right;
15 |         return Caster.Cast(result);
16 |     }
17 | 
18 |     public static TEnum RaiseFlag(this TEnum value, TEnum flag) where TEnum : Enum
19 |         => value.SetFlag(flag, true);
20 | 
21 |     public static TEnum LowerFlag(this TEnum value, TEnum flag) where TEnum : Enum
22 |         => value.SetFlag(flag, false);
23 | 
24 |     /// 
25 |     /// C# non-boxing conversion of enum to numeric and back. Based on https://stackoverflow.com/a/23391746
26 |     /// 
27 |     private static class Caster
28 |     {
29 |         public static readonly Func Cast = CreateConvertMethod();
30 | 
31 |         private static Func CreateConvertMethod()
32 |         {
33 |             var p = Expression.Parameter(typeof(TSource));
34 |             var c = Expression.ConvertChecked(p, typeof(TTarget));
35 |             return Expression.Lambda>(c, p).Compile();
36 |         }
37 |     }
38 | }
39 | 


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.PiiTypes/PiiString.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace Gaev.Blog.Examples;
 4 | 
 5 | public class PiiString
 6 | {
 7 |     private readonly string _string;
 8 | 
 9 |     public PiiString(string underlyingString)
10 |         => _string = underlyingString ?? throw new ArgumentNullException(nameof(underlyingString));
11 | 
12 |     public override string ToString()
13 |         => _string;
14 | 
15 |     public override int GetHashCode()
16 |         => _string.GetHashCode();
17 | 
18 |     public override bool Equals(object obj)
19 |         => obj switch
20 |         {
21 |             PiiString other => AreEqual(this, other),
22 |             string other => AreEqual(this, new PiiString(other)),
23 |             _ => false
24 |         };
25 | 
26 |     public static bool operator ==(PiiString a, PiiString b)
27 |         => AreEqual(a, b);
28 | 
29 |     public static bool operator !=(PiiString a, PiiString b)
30 |         => !AreEqual(a, b);
31 | 
32 |     public static implicit operator string(PiiString piiString)
33 |         => piiString?._string;
34 | 
35 |     public static implicit operator PiiString(string underlyingString)
36 |         => underlyingString == null ? null : new PiiString(underlyingString);
37 | 
38 |     private static bool AreEqual(PiiString a, PiiString b) =>
39 |         (a, b) switch
40 |         {
41 |             (null, null) => true,
42 |             (null, _) => false,
43 |             (_, null) => false,
44 |             (_, _) => a._string.Equals(b._string)
45 |         };
46 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.OrderOfEnumValues/OrderOfEnumValuesMatters.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using NUnit.Framework;
 3 | 
 4 | namespace Gaev.Blog.Examples
 5 | {
 6 |     public class OrderOfEnumValuesMatters
 7 |     {
 8 |         [Test]
 9 |         public void It_should_treat_a_black_as_is()
10 |         {
11 |             Assert.AreEqual("Black", ((Colors_v1) 4).ToString());
12 |             Assert.AreEqual("Black", Enum.Parse("Black").ToString());
13 |         }
14 | 
15 |         [Test]
16 |         public void It_should_use_a_white_instead_of_a_black_FAULTY()
17 |         {
18 |             Assert.AreEqual("White", ((Colors_v2) 4).ToString());
19 |             Assert.AreEqual("White", Enum.Parse("Black").ToString());
20 |         }
21 | 
22 |         [Test]
23 |         public void It_should_use_a_white_instead_of_a_black_FIXED()
24 |         {
25 |             Assert.AreEqual("White", ((Colors_v3) 4).ToString());
26 |             Assert.AreEqual("White", Enum.Parse("Black").ToString());
27 |         }
28 |     }
29 | 
30 |     public enum Colors_v1
31 |     {
32 |         Red = 1,
33 |         Green = 2,
34 |         Blue = 3,
35 |         Black = 4
36 |     }
37 | 
38 |     public enum Colors_v2
39 |     {
40 |         Red = 1,
41 |         Green = 2,
42 |         Blue = 3,
43 |         [Obsolete] Black = White,
44 |         White = 4
45 |     }
46 | 
47 |     public enum Colors_v3
48 |     {
49 |         Red = 1,
50 |         Green = 2,
51 |         Blue = 3,
52 |         White = 4,
53 |         [Obsolete] Black = White
54 |     }
55 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.PiiTypes/PiiAsAes128.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Linq;
 3 | using System.Security.Cryptography;
 4 | using System.Text;
 5 | 
 6 | namespace Gaev.Blog.Examples;
 7 | 
 8 | public class PiiAsAes128 : IPiiEncoder
 9 | {
10 |     private readonly string _key;
11 | 
12 |     public PiiAsAes128(string key)
13 |     {
14 |         _key = key;
15 |     }
16 | 
17 |     public string ToSystemString(PiiString piiString)
18 |     {
19 |         var stringToEncrypt = piiString.ToString();
20 |         using var aes = Aes.Create();
21 |         aes.Key = Convert.FromBase64String(_key);
22 |         aes.GenerateIV();
23 |         using var encryptor = aes.CreateEncryptor();
24 |         var buffer = Encoding.UTF8.GetBytes(stringToEncrypt);
25 |         var encryptedBuffer = encryptor.TransformFinalBlock(buffer, 0, buffer.Length);
26 |         return Convert.ToBase64String(aes.IV.Concat(encryptedBuffer).ToArray());
27 |     }
28 | 
29 |     public PiiString ToPiiString(string str)
30 |     {
31 |         var dataToDecrypt = Convert.FromBase64String(str);
32 |         using var aes = Aes.Create();
33 |         aes.Key = Convert.FromBase64String(_key);
34 |         var ivSize = aes.BlockSize / 8;
35 |         aes.IV = dataToDecrypt.Take(ivSize).ToArray();
36 |         using var decryptor = aes.CreateDecryptor();
37 |         var encryptedBuffer = dataToDecrypt.Skip(ivSize).ToArray();
38 |         var decryptedBuffer = decryptor.TransformFinalBlock(encryptedBuffer, 0, encryptedBuffer.Length);
39 |         return new PiiString(Encoding.UTF8.GetString(decryptedBuffer));
40 |     }
41 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.WarmUpAspNetMvc/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("Gaev.Blog.Examples.WarmUpAspNetMvc")]
 9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Gaev.Blog.Examples.WarmUpAspNetMvc")]
13 | [assembly: AssemblyCopyright("Copyright ©  2019")]
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 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("4719104E-93C8-47B9-B78C-E8E040E945E1")]
24 | 
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | //      Major Version
28 | //      Minor Version
29 | //      Build Number
30 | //      Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.SerializationTests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
 1 | using System.Reflection;
 2 | using System.Runtime.InteropServices;
 3 | 
 4 | // General Information about an assembly is controlled through the following 
 5 | // set of attributes. Change these attribute values to modify the information
 6 | // associated with an assembly.
 7 | [assembly: AssemblyTitle("Gaev.Blog.Examples.SerializationTests")]
 8 | [assembly: AssemblyDescription("")]
 9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("Gaev.Blog.Examples.SerializationTests")]
12 | [assembly: AssemblyCopyright("Copyright ©  2019")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 | 
16 | // Setting ComVisible to false makes the types in this assembly not visible 
17 | // to COM components.  If you need to access a type in this assembly from 
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 | 
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("CED62EC3-C199-4124-9A68-83D5349F5FDA")]
23 | 
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | //      Major Version
27 | //      Minor Version 
28 | //      Build Number
29 | //      Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers 
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.GoogleAlert/CodeFragments.cs:
--------------------------------------------------------------------------------
 1 | using System.ComponentModel.DataAnnotations;
 2 | using System.Threading.Tasks;
 3 | using Gaev.Blog.Examples;
 4 | using Microsoft.EntityFrameworkCore;
 5 | using Serilog;
 6 | using Serilog.Sinks.Telegram;
 7 | 
 8 | public class CodeFragments
 9 | {
10 |     void Serilog_and_Telegram_example()
11 |     {
12 |         var config = new Config();
13 | 
14 |         var logger = new LoggerConfiguration()
15 |             .WriteTo.Telegram(config.TelegramApiKey, config.TelegramChatId)
16 |             .CreateLogger();
17 |         logger.Information("Offer #1 - https://the.internet/offer-1.html");
18 |     }
19 | 
20 |     public class AlertsDatabase : DbContext
21 |     {
22 |         public DbSet Pages { get; set; }
23 | 
24 |         protected override void OnConfiguring(DbContextOptionsBuilder opt) =>
25 |             opt.UseSqlite("Data Source=Alerts.sqlite3");
26 |     }
27 | 
28 |     public class Page
29 |     {
30 |         [Key] public string Link { get; set; }
31 |         public string Title { get; set; }
32 |         public override bool Equals(object compared) => string.Equals(Link, ((Page) compared).Link);
33 |         public override int GetHashCode() => Link.GetHashCode();
34 |     }
35 | 
36 |     async Task EntityFramework_and_Sqlite_example()
37 |     {
38 |         using (var db = new AlertsDatabase())
39 |         {
40 |             await db.Database.EnsureCreatedAsync();
41 |             db.Pages.Add(new Page
42 |             {
43 |                 Link = "https://the.internet/offer-1.html",
44 |                 Title = "Offer #1"
45 |             });
46 |             await db.SaveChangesAsync();
47 |         }
48 |     }
49 | }


--------------------------------------------------------------------------------
/Gaev.Blog.Examples.WarmUpAspNetMvc/Views/Home/Index.cshtml:
--------------------------------------------------------------------------------
 1 | @{
 2 |     ViewBag.Title = "Home Page";
 3 |     InitialSlowdown.For("Index.View");
 4 | }
 5 | 
 6 | 
7 |

ASP.NET

8 |

ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.

9 |

Learn more »

10 |
11 | 12 |
13 |
14 |

Getting started

15 |

16 | ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that 17 | enables a clean separation of concerns and gives you full control over markup 18 | for enjoyable, agile development. 19 |

20 |

Learn more »

21 |
22 |
23 |

Get more libraries

24 |

NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.

25 |

Learn more »

26 |
27 |
28 |

Web Hosting

29 |

You can easily find a web hosting company that offers the right mix of features and price for your applications.

30 |

Learn more »

31 |
32 |
-------------------------------------------------------------------------------- /Gaev.Blog.ParallelizableTests/ParallelizableAllTestsPitfalls.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace Gaev.Blog; 4 | 5 | // dotnet test --filter:"Category=ParallelizableAllPitfalls" 6 | 7 | [FixtureLifeCycle(LifeCycle.InstancePerTestCase)] 8 | [Parallelizable(ParallelScope.All), Category("ParallelizableAllPitfalls")] 9 | public class ParallelizableAllTestsPitfalls 10 | { 11 | private int _state = 0; 12 | 13 | [SetUp] 14 | public void Setup() 15 | => WriteLine($"Setup State: {_state} Instance: {GetHashCode()}"); 16 | 17 | [TearDown] 18 | public void TearDown() 19 | => WriteLine($"TearDown State: {_state} Instance: {GetHashCode()}"); 20 | 21 | [Test] 22 | public Task Test1() 23 | => KindOfTest("Test1"); 24 | 25 | [Test] 26 | public Task Test2() 27 | => KindOfTest("Test2"); 28 | 29 | [Test] 30 | public Task Test3() 31 | => KindOfTest("Test3"); 32 | 33 | [Test] 34 | public Task Test4() 35 | => KindOfTest("Test4"); 36 | 37 | [Test] 38 | public Task Test5() 39 | => KindOfTest("Test5"); 40 | 41 | private async Task KindOfTest(string testName) 42 | { 43 | var initial = _state; 44 | _state++; 45 | var changed = _state; 46 | await Task.Delay(1_000); 47 | WriteLine($"{testName} State: {initial}->{changed}->{_state} Instance: {GetHashCode()}"); 48 | } 49 | 50 | private void WriteLine(string message) 51 | { 52 | var position = Interlocked.Add(ref _currentOrder, 1); 53 | Console.WriteLine($"{position:00}. {message}"); 54 | } 55 | 56 | private static int _currentOrder = 0; 57 | } 58 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.WarmUpAspNetMvc/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewBag.Title - My ASP.NET Application 7 | 8 | 9 | 10 | 11 | 30 |
31 | @RenderBody() 32 |
33 |
34 |

© @DateTime.Now.2019 - My ASP.NET Application

35 |
36 |
37 | 38 | @RenderSection("scripts", required: false) 39 | 40 | 41 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.StateViaEF/LegacyUser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using static Gaev.Blog.Examples.LegacyUser.UserState; 3 | 4 | namespace Gaev.Blog.Examples 5 | { 6 | public class LegacyUser 7 | { 8 | public int NumberOfAttempts { get; set; } 9 | public string Captcha { get; set; } 10 | public DateTimeOffset? BlockedUntil { get; set; } 11 | public UserState State { get; set; } 12 | 13 | public void Login(string password) 14 | { 15 | if (State != AttemptsToLogin) throw new InvalidOperationException(); 16 | if (password == "test") 17 | State = IsAuthorized; 18 | else 19 | { 20 | NumberOfAttempts++; 21 | if (NumberOfAttempts > 2) 22 | { 23 | Captcha = Guid.NewGuid().ToString(); 24 | State = InputsCaptcha; 25 | } 26 | } 27 | } 28 | 29 | public void InputCaptcha(string captcha) 30 | { 31 | if (State != InputsCaptcha) throw new InvalidOperationException(); 32 | if (captcha == Captcha) 33 | { 34 | NumberOfAttempts = 0; 35 | State = AttemptsToLogin; 36 | } 37 | else 38 | { 39 | BlockedUntil = DateTimeOffset.UtcNow.AddHours(1); 40 | State = IsBlocked; 41 | } 42 | } 43 | 44 | public void Logout() 45 | { 46 | if (State != IsAuthorized) throw new InvalidOperationException(); 47 | NumberOfAttempts = 0; 48 | State = AttemptsToLogin; 49 | } 50 | 51 | public enum UserState 52 | { 53 | AttemptsToLogin, 54 | IsAuthorized, 55 | InputsCaptcha, 56 | IsBlocked 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6/ProgramOption2.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace Gaev.Blog.SecuredAppSettingsJson.AspNetCoreWebApi6; 5 | 6 | public static class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | WebHost 11 | .CreateDefaultBuilder(args) 12 | .ConfigureAppConfiguration(appConfig => 13 | { 14 | appConfig.AddEnvironmentVariables(prefix: "APPPREFIX_"); 15 | }) 16 | .UseStartup() 17 | .Build() 18 | .Run(); 19 | } 20 | 21 | public class Startup 22 | { 23 | public Startup(IConfiguration cfg) 24 | { 25 | // This will decrypt the configuration 26 | ((IConfigurationRoot) cfg).Decrypt(keyPath: "CipherKey", cipherPrefix: "CipherText:"); 27 | } 28 | 29 | public void ConfigureServices(IServiceCollection services) 30 | { 31 | services.AddControllers(); 32 | services.AddEndpointsApiExplorer(); 33 | services.AddSwaggerGen(); 34 | } 35 | 36 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 37 | { 38 | app.UseSwagger(); 39 | app.UseSwaggerUI(); 40 | app.UseRouting(); 41 | app.UseAuthorization(); 42 | app.UseEndpoints(c => c.MapControllers()); 43 | } 44 | } 45 | } 46 | 47 | [ApiController] 48 | [Route("[controller]")] 49 | public class TestController : ControllerBase 50 | { 51 | private readonly IConfiguration _config; 52 | 53 | public TestController(IConfiguration config) 54 | => _config = config; 55 | 56 | [HttpGet] 57 | public string TestConfig() 58 | => _config["DbConnectionString"]; 59 | } 60 | -------------------------------------------------------------------------------- /Gaev.Blog.ExceptionRethrow/ExceptionRethrowTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.ExceptionServices; 4 | using NUnit.Framework; 5 | using static System.Runtime.CompilerServices.MethodImplOptions; 6 | 7 | // ReSharper disable RedundantCatchClause 8 | 9 | namespace Gaev.Blog.ExceptionRethrow; 10 | 11 | public class ExceptionRethrowTests 12 | { 13 | [Test] 14 | public void Stacktrace_should_point_to_exception_line() 15 | { 16 | try 17 | { 18 | throw new Exception(); 19 | } 20 | catch (Exception) 21 | { 22 | throw; 23 | } 24 | } 25 | 26 | [Test] 27 | public void Stacktrace_should_point_to_exception_line_of_validate_method() 28 | { 29 | [MethodImpl(NoInlining)] 30 | void Validate() 31 | { 32 | throw new Exception(); 33 | } 34 | 35 | try 36 | { 37 | Validate(); 38 | } 39 | catch (Exception) 40 | { 41 | throw; 42 | } 43 | } 44 | 45 | [Test] 46 | public void Stacktrace_should_point_to_exception_line_of_inlined_validate_method() 47 | { 48 | [MethodImpl(AggressiveInlining)] 49 | void Validate() 50 | { 51 | throw new Exception(); 52 | } 53 | 54 | try 55 | { 56 | Validate(); 57 | } 58 | catch (Exception) 59 | { 60 | throw; 61 | } 62 | } 63 | 64 | [Test] 65 | public void Stacktrace_should_point_to_exception_line_with_net_framework_fix() 66 | { 67 | try 68 | { 69 | throw new Exception(); 70 | } 71 | catch (Exception ex) 72 | { 73 | ExceptionDispatchInfo.Capture(ex).Throw(); 74 | throw; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Gaev.Blog.AzureServiceBusTaskScheduler/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Cronos; 5 | using Microsoft.Azure.ServiceBus; 6 | 7 | // ReSharper disable PossibleInvalidOperationException 8 | 9 | namespace Gaev.Blog.AzureServiceBusTaskScheduler 10 | { 11 | class Program 12 | { 13 | const string ConnectionString = "..."; 14 | 15 | static async Task Main(string[] _) 16 | { 17 | var cancellation = new CancellationTokenSource(); 18 | Console.CancelKeyPress += (__, e) => 19 | { 20 | e.Cancel = true; 21 | cancellation.Cancel(); 22 | }; 23 | var scheduler = new ServiceBusJobScheduler(ConnectionString); 24 | await scheduler.Run( 25 | queueName: "TakeABreak", 26 | init: () => new Message 27 | { 28 | ScheduledEnqueueTimeUtc = DateTime.UtcNow 29 | }, 30 | job: async (message) => 31 | { 32 | // Watch out for exceptions! By default, ServiceBus retries 10 times then move the message into dead-letter queue. 33 | // Watch out for long-running jobs! By default, ServiceBus waits 5 minutes then returns the message back to the queue. 34 | var scheduledFor = message.ScheduledEnqueueTimeUtc.ToLocalTime(); 35 | Console.WriteLine($"Take a break! It is {scheduledFor:T}."); 36 | await Task.Delay(100); 37 | return new Message 38 | { 39 | ScheduledEnqueueTimeUtc = CronExpression 40 | .Parse("*/30 8-18 * * MON-FRI") 41 | .GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Local) 42 | .Value 43 | }; 44 | }, 45 | cancellation.Token 46 | ); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.WarmUpAspNetMvc/Views/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Gaev.Blog.SecuredAppSettingsJson/Aes256Cipher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Security.Cryptography; 4 | using System.Text; 5 | 6 | namespace Gaev.Blog.SecuredAppSettingsJson 7 | { 8 | /// 9 | /// A tiny wrapper around built-in AES-256 algorithm. 10 | /// For better security it prefixes randomly generated IV to a cipher text. 11 | /// Yes, it is secure enough https://security.stackexchange.com/a/85778/207381 12 | /// 13 | public class Aes256Cipher 14 | { 15 | private readonly byte[] _key; 16 | 17 | public Aes256Cipher(string key) 18 | { 19 | if (string.IsNullOrWhiteSpace(key)) throw new NullReferenceException("The key is empty"); 20 | _key = Convert.FromBase64String(key); 21 | } 22 | 23 | public string Decrypt(string value) 24 | { 25 | var ivAndCipherText = Convert.FromBase64String(value); 26 | using var aes = Aes.Create(); 27 | var ivLength = aes.BlockSize / 8; 28 | aes.IV = ivAndCipherText.Take(ivLength).ToArray(); 29 | aes.Key = _key; 30 | using var cipher = aes.CreateDecryptor(); 31 | var cipherText = ivAndCipherText.Skip(ivLength).ToArray(); 32 | var text = cipher.TransformFinalBlock(cipherText, 0, cipherText.Length); 33 | return Encoding.UTF8.GetString(text); 34 | } 35 | 36 | public string Encrypt(string value) 37 | { 38 | using var aes = Aes.Create(); 39 | aes.Key = _key; 40 | aes.GenerateIV(); 41 | using var cipher = aes.CreateEncryptor(); 42 | var text = Encoding.UTF8.GetBytes(value); 43 | var cipherText = cipher.TransformFinalBlock(text, 0, text.Length); 44 | return Convert.ToBase64String(aes.IV.Concat(cipherText).ToArray()); 45 | } 46 | 47 | public static string GenerateNewKey() 48 | { 49 | using var aes = Aes.Create(); 50 | aes.GenerateKey(); 51 | return Convert.ToBase64String(aes.Key); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.ScriptInString/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.AzureServiceBus/AzureServiceBus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Microsoft.ServiceBus; 6 | using Microsoft.ServiceBus.Messaging; 7 | 8 | namespace Tests 9 | { 10 | 11 | // Topics are needed to show forwarding logic without session and with it 12 | public class AzureServiceBus : IDisposable 13 | { 14 | private readonly MessagingFactory _factory; 15 | private readonly Dictionary _queueClient; 16 | 17 | public AzureServiceBus(string connectionString) 18 | { 19 | _factory = MessagingFactory.CreateFromConnectionString(connectionString); 20 | _queueClient = new Dictionary 21 | { 22 | {"test1", _factory.CreateQueueClient("test1")} 23 | }; 24 | } 25 | 26 | public Task SendToQueue(string queueName, BrokeredMessage message) 27 | { 28 | return _queueClient[queueName].SendAsync(message); 29 | } 30 | 31 | public async Task SubscribeToQueue(string queueName, Func onMessage, 32 | CancellationToken cancellation) 33 | { 34 | var receiver = await _factory.CreateMessageReceiverAsync(queueName, ReceiveMode.PeekLock); 35 | while (!cancellation.IsCancellationRequested) 36 | try 37 | { 38 | var message = await receiver.ReceiveAsync(); 39 | if (message != null) 40 | { 41 | await onMessage(message); 42 | // await message.CompleteAsync(); 43 | // await message.DeadLetterAsync("ProcessingError", "Don't know what to do with this message"); 44 | } 45 | } 46 | catch (MessagingException e) 47 | { 48 | if (!e.IsTransient) 49 | throw; 50 | } 51 | 52 | await receiver.CloseAsync(); 53 | } 54 | 55 | public void Dispose() 56 | { 57 | foreach (var client in _queueClient.Values) 58 | client.Close(); 59 | _factory.Close(); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.PiiTypes/NewtonsoftJson/PiiStringTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentAssertions; 3 | using Newtonsoft.Json; 4 | using NUnit.Framework; 5 | 6 | namespace Gaev.Blog.Examples.NewtonsoftJson; 7 | 8 | public class PiiStringTests 9 | { 10 | [Test] 11 | public void NewtonsoftJson_should_work() 12 | { 13 | // Given 14 | var user = new User 15 | { 16 | Name = "John Doe", 17 | Email = "john.doe@test.com" 18 | }; 19 | var settings = new JsonSerializerSettings {Converters = {new PiiStringConverter(new PiiAsPlainText())}}; 20 | 21 | // When 22 | var json = JsonConvert.SerializeObject(user, settings); 23 | var actual = JsonConvert.DeserializeObject(json, settings); 24 | 25 | // Then 26 | Console.WriteLine(json); 27 | actual.Should().BeEquivalentTo(user); 28 | } 29 | 30 | [Test] 31 | public void NewtonsoftJson_should_encrypt() 32 | { 33 | // Given 34 | var user = new User 35 | { 36 | Name = "John Doe", 37 | Email = "john.doe@test.com" 38 | }; 39 | var key = "hb50qBZSF0fcLSl9814PIqmO4gEZcJGB/Kd4fpTTBcU="; 40 | var settings = new JsonSerializerSettings {Converters = {new PiiStringConverter(new PiiAsAes128(key))}}; 41 | 42 | // When 43 | var json = JsonConvert.SerializeObject(user, settings); 44 | var actual = JsonConvert.DeserializeObject(json, settings); 45 | 46 | // Then 47 | Console.WriteLine(json); 48 | actual.Should().BeEquivalentTo(user); 49 | } 50 | 51 | [Test] 52 | public void NewtonsoftJson_should_hash() 53 | { 54 | // Given 55 | var user = new User 56 | { 57 | Name = "John Doe", 58 | Email = "john.doe@test.com" 59 | }; 60 | var settings = new JsonSerializerSettings {Converters = {new PiiStringConverter(new PiiAsSha256())}}; 61 | 62 | // When 63 | var json = JsonConvert.SerializeObject(user, settings); 64 | var json2 = JsonConvert.SerializeObject(user, settings); 65 | var json3 = JsonConvert.SerializeObject(user, settings); 66 | 67 | // Then 68 | Console.WriteLine(json); 69 | Console.WriteLine(json2); 70 | Console.WriteLine(json3); 71 | } 72 | } -------------------------------------------------------------------------------- /Gaev.Blog.EnumFlags/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | namespace Gaev.Blog.EnumFlags; 4 | 5 | public static class Program 6 | { 7 | public static void Main(string[] _) 8 | => BenchmarkRunner.Run(typeof(Program).Assembly); 9 | } 10 | 11 | /* 12 | // * Summary * 13 | 14 | BenchmarkDotNet v0.13.10, Windows 10 (10.0.19045.3570/22H2/2022Update) 15 | 11th Gen Intel Core i7-11800H 2.30GHz, 1 CPU, 16 logical and 8 physical cores 16 | .NET SDK 7.0.401 17 | [Host] : .NET 7.0.11 (7.0.1123.42427), X64 RyuJIT AVX2 18 | .NET 7.0 : .NET 7.0.11 (7.0.1123.42427), X64 RyuJIT AVX2 19 | .NET Framework 4.8 : .NET Framework 4.8.1 (4.8.9181.0), X64 RyuJIT VectorSize=256 20 | 21 | | Method | Job | Runtime | Mean | Error | StdDev | Gen0 | Allocated | 22 | |-------------------- |------------------- |------------------- |------------:|----------:|----------:|-------:|----------:| 23 | | RaiseFlag_Native | .NET 7.0 | .NET 7.0 | 0.3910 ns | 0.0194 ns | 0.0181 ns | - | - | 24 | | RaiseFlag_NonBoxing | .NET 7.0 | .NET 7.0 | 2.7012 ns | 0.0119 ns | 0.0111 ns | - | - | 25 | | RaiseFlag_Boxing | .NET 7.0 | .NET 7.0 | 52.0814 ns | 0.6821 ns | 0.6380 ns | 0.0114 | 144 B | 26 | | LowerFlag_Native | .NET 7.0 | .NET 7.0 | 0.4116 ns | 0.0109 ns | 0.0102 ns | - | - | 27 | | LowerFlag_NonBoxing | .NET 7.0 | .NET 7.0 | 2.6383 ns | 0.0146 ns | 0.0137 ns | - | - | 28 | | LowerFlag_Boxing | .NET 7.0 | .NET 7.0 | 51.5234 ns | 0.3467 ns | 0.2895 ns | 0.0114 | 144 B | 29 | | RaiseFlag_Native | .NET Framework 4.8 | .NET Framework 4.8 | 0.3665 ns | 0.0234 ns | 0.0269 ns | - | - | 30 | | RaiseFlag_NonBoxing | .NET Framework 4.8 | .NET Framework 4.8 | 3.5727 ns | 0.0178 ns | 0.0167 ns | - | - | 31 | | RaiseFlag_Boxing | .NET Framework 4.8 | .NET Framework 4.8 | 100.7910 ns | 0.2107 ns | 0.1759 ns | 0.0229 | 144 B | 32 | | LowerFlag_Native | .NET Framework 4.8 | .NET Framework 4.8 | 0.3292 ns | 0.0305 ns | 0.0327 ns | - | - | 33 | | LowerFlag_NonBoxing | .NET Framework 4.8 | .NET Framework 4.8 | 3.8718 ns | 0.0203 ns | 0.0170 ns | - | - | 34 | | LowerFlag_Boxing | .NET Framework 4.8 | .NET Framework 4.8 | 103.2550 ns | 2.0824 ns | 2.3981 ns | 0.0229 | 144 B | 35 | */ 36 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.AsyncTaskThrottling/Gaev.Blog.Examples.AsyncTaskThrottling.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6632D1AC-CA63-484E-BDA0-05F143EEB242} 8 | Library 9 | Properties 10 | Gaev.Blog.Examples 11 | Gaev.Blog.Examples.AsyncTaskThrottling 12 | v4.7.1 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 50 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.SqlQueryLogger/LongRunningQueryProfiler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Data; 4 | using System.Data.Common; 5 | using System.Diagnostics; 6 | using NLog; 7 | using StackExchange.Profiling; 8 | using StackExchange.Profiling.Data; 9 | using StackExchange.Profiling.Helpers; 10 | using DbCommandKey = System.Tuple; 11 | 12 | namespace Gaev.Blog.Examples 13 | { 14 | public class LongRunningQueryProfiler : MiniProfiler, IDbProfiler 15 | { 16 | private readonly TimeSpan _threshold; 17 | private readonly ILogger _logger; 18 | 19 | private readonly ConcurrentDictionary _inProgress = 20 | new ConcurrentDictionary(); 21 | 22 | public LongRunningQueryProfiler(ILogger logger, TimeSpan threshold) : base(null, DefaultOptions) 23 | { 24 | _threshold = threshold; 25 | _logger = logger; 26 | } 27 | 28 | public void ExecuteStart(IDbCommand command, SqlExecuteType type) 29 | { 30 | DbCommandKey id = Tuple.Create((object) command, type); 31 | _inProgress[id] = Stopwatch.StartNew(); 32 | } 33 | 34 | public void ExecuteFinish(IDbCommand command, SqlExecuteType type, DbDataReader reader) 35 | { 36 | DbCommandKey id = Tuple.Create((object) command, type); 37 | if (_inProgress.TryRemove(id, out Stopwatch stopwatch) && stopwatch.Elapsed > _threshold) 38 | _logger.Warn("{LongRunningQuery}", new 39 | { 40 | stackTrace = StackTraceSnippet.Get(Options), 41 | sql = command.CommandText, 42 | elapsed = (long) stopwatch.Elapsed.TotalMilliseconds 43 | }); 44 | } 45 | 46 | public void ReaderFinish(IDataReader reader) 47 | { 48 | } 49 | 50 | public void OnError(IDbCommand command, SqlExecuteType type, Exception exception) 51 | { 52 | DbCommandKey id = Tuple.Create((object) command, type); 53 | if (_inProgress.TryRemove(id, out Stopwatch stopwatch) && stopwatch.Elapsed > _threshold) 54 | _logger.Warn(exception, "{LongRunningQuery}", new 55 | { 56 | sql = command.CommandText, 57 | elapsed = (long) stopwatch.Elapsed.TotalMilliseconds 58 | }); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.SqlQueryLogger/AlertLongRunningEfQueriesTests.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Entity; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using NUnit.Framework; 5 | using StackExchange.Profiling; 6 | using StackExchange.Profiling.EntityFramework6; 7 | 8 | namespace Gaev.Blog.Examples 9 | { 10 | [NonParallelizable] 11 | public class AlertLongRunningEfQueriesTests 12 | { 13 | private const string ConnectionString = "server=localhost;database=tempdb;UID=sa;PWD=sa123"; 14 | private TestLogger _logger; 15 | 16 | [OneTimeSetUp] 17 | public void InitializeEf6Profiler() 18 | { 19 | _logger = new TestLogger(); 20 | var profiler = new LongRunningQueryProfiler(_logger, threshold: 200.Milliseconds()); 21 | MiniProfiler.DefaultOptions.ProfilerProvider = new ProfilerGetter(profiler); 22 | MiniProfilerEF6.Initialize(); 23 | } 24 | 25 | [Test] 26 | public async Task It_should_alert_EntityFramework_SQL_queries() 27 | { 28 | // Given 29 | _logger.Warnings.Clear(); 30 | 31 | // When 32 | var sql = "WAITFOR DELAY '00:00:00.200'; SELECT 123 as 'Id'"; 33 | using (var ctx = new MyDbContext(ConnectionString)) 34 | { 35 | var _ = await ctx.Cars.SqlQuery(sql).ToListAsync(); 36 | } 37 | 38 | // Then 39 | Assert.That(_logger.Warnings.Any(e => e.sql == sql), Is.True); 40 | } 41 | 42 | [Test] 43 | public async Task It_should_not_alert_EntityFramework_SQL_queries() 44 | { 45 | // Given 46 | _logger.Warnings.Clear(); 47 | 48 | // When 49 | var sql = "SELECT 123 as 'Id'"; 50 | using (var ctx = new MyDbContext(ConnectionString)) 51 | { 52 | var _ = await ctx.Cars.SqlQuery(sql).ToListAsync(); 53 | } 54 | 55 | // Then 56 | Assert.That(_logger.Warnings, Is.Empty); 57 | } 58 | 59 | public class MyDbContext : DbContext 60 | { 61 | public DbSet Cars { get; set; } 62 | 63 | static MyDbContext() 64 | { 65 | Database.SetInitializer(null); 66 | } 67 | 68 | public MyDbContext(string connectionString) : base(connectionString) 69 | { 70 | } 71 | } 72 | 73 | public class Car 74 | { 75 | public int Id { get; set; } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /Gaev.Blog.Sha256ForStream/CryptoUtilsTests.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | using System.Text; 3 | using NUnit.Framework; 4 | 5 | namespace Gaev.Blog; 6 | 7 | public class CryptoUtilsTests 8 | { 9 | public string ComputeSha256(MemoryStream stream) 10 | { 11 | using var sha = SHA256.Create(); 12 | return string.Join("", sha.ComputeHash(stream).Select(b => b.ToString("x2"))); 13 | } 14 | 15 | public string ComputeSha256Fixed(MemoryStream stream) 16 | { 17 | stream.Seek(0, SeekOrigin.Begin); 18 | using var sha = SHA256.Create(); 19 | return string.Join("", sha.ComputeHash(stream).Select(b => b.ToString("x2"))); 20 | } 21 | 22 | [TestCase("John Doe", "6cea57c2fb6cbc2a40411135005760f241fffc3e5e67ab99882726431037f908")] 23 | [TestCase("C# developer", "c9298659b4622ec5881c09fc510f23fcfbe75159d13f64b388b74c4d060d65d7")] 24 | public void It_should_compute_SHA256_for_stream(string payload, string expected) 25 | { 26 | // Given 27 | var binary = Encoding.UTF8.GetBytes(payload); 28 | var stream = new MemoryStream(binary); 29 | 30 | // When 31 | var actual = ComputeSha256(stream); 32 | 33 | // Then 34 | Assert.That(actual, Is.EqualTo(expected)); 35 | } 36 | 37 | [TestCase("John Doe", "6cea57c2fb6cbc2a40411135005760f241fffc3e5e67ab99882726431037f908")] 38 | [TestCase("C# developer", "c9298659b4622ec5881c09fc510f23fcfbe75159d13f64b388b74c4d060d65d7")] 39 | public void It_should_compute_SHA256_for_stream_broken(string payload, string expected) 40 | { 41 | // Given 42 | var binary = Encoding.UTF8.GetBytes(payload); 43 | var stream = new MemoryStream(); 44 | stream.Write(binary); 45 | 46 | // When 47 | var actual = ComputeSha256(stream); 48 | 49 | // Then 50 | Assert.That(actual, Is.EqualTo(expected)); 51 | } 52 | 53 | [TestCase("John Doe", "6cea57c2fb6cbc2a40411135005760f241fffc3e5e67ab99882726431037f908")] 54 | [TestCase("C# developer", "c9298659b4622ec5881c09fc510f23fcfbe75159d13f64b388b74c4d060d65d7")] 55 | public void It_should_compute_SHA256_for_stream_fixed(string payload, string expected) 56 | { 57 | // Given 58 | var binary = Encoding.UTF8.GetBytes(payload); 59 | var stream = new MemoryStream(); 60 | stream.Write(binary); 61 | 62 | // When 63 | var actual = ComputeSha256Fixed(stream); 64 | 65 | // Then 66 | Assert.That(actual, Is.EqualTo(expected)); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Gaev.Blog.AzureServiceBusTaskScheduler/ServiceBusJobScheduler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.Azure.ServiceBus; 5 | using Microsoft.Azure.ServiceBus.Management; 6 | 7 | namespace Gaev.Blog.AzureServiceBusTaskScheduler 8 | { 9 | public class ServiceBusJobScheduler 10 | { 11 | private readonly string _connectionString; 12 | 13 | public ServiceBusJobScheduler(string connectionString) 14 | { 15 | _connectionString = connectionString; 16 | } 17 | 18 | public async Task Run( 19 | string queueName, 20 | Func init, 21 | Func> job, 22 | CancellationToken cancellation 23 | ) 24 | { 25 | var queueClient = new QueueClient(_connectionString, queueName); 26 | var created = await EnsureQueueCreated(queueName); 27 | if (created) 28 | await queueClient.SendAsync(init()); 29 | queueClient.RegisterMessageHandler( 30 | handler: async (message, _) => 31 | { 32 | var nextMessage = await job(message); 33 | if (nextMessage != null) 34 | await queueClient.SendAsync(nextMessage); 35 | }, 36 | exceptionReceivedHandler: _ => Task.CompletedTask 37 | ); 38 | await Wait(cancellation); 39 | await queueClient.CloseAsync(); 40 | } 41 | 42 | private async Task EnsureQueueCreated(string queueName) 43 | { 44 | var client = new ManagementClient(_connectionString); 45 | for (int probe = 1;; probe++) 46 | try 47 | { 48 | if (!await client.QueueExistsAsync(queueName)) 49 | { 50 | await client.CreateQueueAsync(queueName); 51 | return true; 52 | } 53 | 54 | return false; 55 | } 56 | catch (ServiceBusException) when (probe < 3) 57 | { 58 | await Task.Delay(100); 59 | } 60 | } 61 | 62 | private static async Task Wait(CancellationToken cancellation) 63 | { 64 | try 65 | { 66 | await Task.Delay(Timeout.Infinite, cancellation); 67 | } 68 | catch (TaskCanceledException) 69 | { 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /Gaev.Blog.EnumAsStringTrap/SystemTextJson/UnknownEnumConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | 5 | // ReSharper disable MemberCanBePrivate.Global 6 | 7 | namespace Gaev.Blog.EnumAsStringTrap.SystemTextJson; 8 | 9 | public class UnknownEnumConverter : JsonConverterFactory 10 | { 11 | private readonly JsonStringEnumConverter _underlying; 12 | 13 | public UnknownEnumConverter() : this(namingPolicy: null, allowIntegerValues: true) 14 | { 15 | } 16 | 17 | public UnknownEnumConverter(JsonNamingPolicy namingPolicy = null, bool allowIntegerValues = true) 18 | => _underlying = new JsonStringEnumConverter(namingPolicy, allowIntegerValues); 19 | 20 | public sealed override JsonConverter CreateConverter(Type enumType, JsonSerializerOptions options) 21 | { 22 | var underlyingConverter = _underlying.CreateConverter(enumType, options); 23 | var converterType = typeof(UnknownEnumConverter<>).MakeGenericType(enumType); 24 | return (JsonConverter)Activator.CreateInstance(converterType, underlyingConverter); 25 | } 26 | 27 | public sealed override bool CanConvert(Type enumType) 28 | => _underlying.CanConvert(enumType); 29 | } 30 | 31 | public class UnknownEnumConverter : JsonConverter where T : struct, Enum 32 | { 33 | private readonly JsonConverter _underlying; 34 | 35 | public UnknownEnumConverter(JsonConverter underlying) 36 | => _underlying = underlying; 37 | 38 | public override T Read(ref Utf8JsonReader reader, Type enumType, JsonSerializerOptions options) 39 | { 40 | try 41 | { 42 | return _underlying.Read(ref reader, enumType, options); 43 | } 44 | catch (JsonException) when (enumType.IsEnum) 45 | { 46 | // TODO: Modify logic here to return custom faulty value 47 | return default; 48 | } 49 | } 50 | 51 | public override bool CanConvert(Type typeToConvert) 52 | => _underlying.CanConvert(typeToConvert); 53 | 54 | public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) 55 | => _underlying.Write(writer, value, options); 56 | 57 | public override T ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 58 | => _underlying.ReadAsPropertyName(ref reader, typeToConvert, options); 59 | 60 | public override void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options) 61 | => _underlying.WriteAsPropertyName(writer, value, options); 62 | } 63 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.AsyncTaskThrottling/ThrottlingExamples.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | // ReSharper disable CheckNamespace 6 | #pragma warning disable 649 7 | 8 | public class Uploader 9 | { 10 | private readonly DriveService _googleApi; 11 | 12 | public async Task UploadFolder(string path) 13 | { 14 | await Task.WhenAll(new DirectoryInfo(path) 15 | .EnumerateFiles() 16 | .Select(file => UploadFile(file.FullName)) 17 | ); 18 | } 19 | 20 | public async Task UploadFile(string path) 21 | { 22 | using (var content = File.OpenRead(path)) 23 | await _googleApi.UploadFile(path, content); 24 | } 25 | } 26 | 27 | public class ThrottledSomething 28 | { 29 | private readonly SemaphoreSlim _throttler = new SemaphoreSlim( /*degreeOfParallelism:*/ 2); 30 | 31 | public async Task Throttle() 32 | { 33 | await _throttler.WaitAsync(); 34 | try 35 | { 36 | // calling a method to throttle 37 | } 38 | finally 39 | { 40 | _throttler.Release(); 41 | } 42 | } 43 | } 44 | 45 | public class ThrottledUploader 46 | { 47 | private readonly DriveService _googleApi; 48 | private readonly SemaphoreSlim _throttler = new SemaphoreSlim( /*degreeOfParallelism:*/ 2); 49 | 50 | public async Task UploadFolder(string path) 51 | { 52 | await Task.WhenAll(new DirectoryInfo(path) 53 | .EnumerateFiles() 54 | .Select(file => UploadFile(file.FullName)) 55 | ); 56 | } 57 | 58 | public async Task UploadFile(string path) 59 | { 60 | await _throttler.WaitAsync(); 61 | try 62 | { 63 | using (var content = File.OpenRead(path)) 64 | await _googleApi.UploadFile(path, content); 65 | } 66 | finally 67 | { 68 | _throttler.Release(); 69 | } 70 | } 71 | } 72 | 73 | public class ThrottledUploaderRefactored 74 | { 75 | private readonly DriveService _googleApi; 76 | private readonly SemaphoreSlim _throttler = new SemaphoreSlim( /*degreeOfParallelism:*/ 2); 77 | 78 | public async Task UploadFolder(string path) 79 | { 80 | await Task.WhenAll(new DirectoryInfo(path) 81 | .EnumerateFiles() 82 | .Select(file => UploadFile(file.FullName)) 83 | ); 84 | } 85 | 86 | public async Task UploadFile(string path) 87 | { 88 | using (_throttler.Throttle()) 89 | using (var content = File.OpenRead(path)) 90 | await _googleApi.UploadFile(path, content); 91 | } 92 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.ArchitectureTests/DotNetAssembly.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Mono.Cecil; 4 | 5 | namespace Gaev.Blog.Examples; 6 | 7 | public class DotNetAssembly 8 | { 9 | private DotNetAssembly(AssemblyDefinition assembly) 10 | => MonoCecilAssembly = assembly; 11 | 12 | public AssemblyDefinition MonoCecilAssembly { get; } 13 | public HashSet Dependencies { get; } = new(); 14 | public HashSet BackwardsDependencies { get; } = new(); 15 | 16 | public string FullName 17 | => MonoCecilAssembly.Name?.FullName ?? ""; 18 | 19 | public string Name 20 | => MonoCecilAssembly.Name?.Name ?? ""; 21 | 22 | public override int GetHashCode() 23 | => FullName.GetHashCode(); 24 | 25 | public override string ToString() 26 | => Name; 27 | 28 | public override bool Equals(object obj) 29 | => obj is DotNetAssembly other && other.FullName.Equals(FullName); 30 | 31 | public static List LoadAll() 32 | { 33 | var entryPointLocation = System.Reflection.Assembly.GetExecutingAssembly().Location; 34 | var entryPoint = new DotNetAssembly(AssemblyDefinition.ReadAssembly(entryPointLocation)); 35 | var allProjects = new Dictionary(); 36 | LoadDependencies(entryPoint, allProjects); 37 | return allProjects.Values.ToList(); 38 | } 39 | 40 | private static void LoadDependencies(DotNetAssembly parent, Dictionary allProjects) 41 | { 42 | allProjects[parent.FullName] = parent; 43 | if (parent.Dependencies.Any()) return; 44 | var dependencies = parent.MonoCecilAssembly.Modules.SelectMany(module => module 45 | .AssemblyReferences 46 | .Select(reference => allProjects.TryGetValue(reference.FullName, out var dependency) 47 | ? dependency 48 | : ResolveReference(module, reference)) 49 | .Where(dependency => dependency != null) 50 | ); 51 | foreach (var dependency in dependencies) 52 | { 53 | parent.Dependencies.Add(dependency); 54 | dependency.BackwardsDependencies.Add(parent); 55 | LoadDependencies(dependency, allProjects); 56 | } 57 | } 58 | 59 | private static DotNetAssembly ResolveReference(ModuleDefinition module, AssemblyNameReference assembly) 60 | { 61 | try 62 | { 63 | return new DotNetAssembly(module.AssemblyResolver.Resolve(assembly)); 64 | } 65 | catch (AssemblyResolutionException) 66 | { 67 | return null; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.ScriptInString/Views/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.WarmUpAspNetMvc/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 54 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Gaev.Blog.SecuredAppSettingsJson/UtilityTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text.RegularExpressions; 4 | using NUnit.Framework; 5 | 6 | namespace Gaev.Blog.SecuredAppSettingsJson 7 | { 8 | public class UtilityTests 9 | { 10 | private static string CipherKey => "l8cpD27QcWDXjAg8ut+qH0IkWv/p38DrAst4Ee83jMg="; 11 | 12 | [TestCase("This is kind of connection string ;)")] 13 | public void Encrypt_value_and_print(string value) 14 | { 15 | var cipher = new Aes256Cipher(CipherKey); 16 | Console.WriteLine(cipher.Encrypt(value)); 17 | } 18 | 19 | [TestCase("09lXf8qen+mQJeAgl7lBcTIdCvpvDOQs7NL3oyiwOJpfqn26PWxkpEkS2+SAGf0BjCHT/uHfXzYZPQeyYyb+0A==")] 20 | public void Decrypt_value_and_print(string value) 21 | { 22 | var cipher = new Aes256Cipher(CipherKey); 23 | Console.WriteLine(cipher.Decrypt(value)); 24 | } 25 | 26 | [Test] 27 | public void Generate_new_key_and_print() 28 | { 29 | Console.WriteLine("Key: " + Aes256Cipher.GenerateNewKey()); 30 | } 31 | 32 | [TestCase("../../../appsettings.json")] 33 | public void Encrypt_secured_fields_in_json(string filename) 34 | { 35 | var cipher = new Aes256Cipher(CipherKey); 36 | var jsonFile = new FileInfo(filename); 37 | var json = File.ReadAllText(jsonFile.FullName); 38 | json = Regex.Replace( 39 | json, 40 | @"""CipherText:(?[^""]+)""", 41 | m => 42 | { 43 | var text = m.Groups["Text"].Value; 44 | try 45 | { 46 | var cipherText = cipher.Encrypt(text); 47 | return $@"""CipherText:{cipherText}"""; 48 | } 49 | catch (Exception) 50 | { 51 | Console.WriteLine($@"Failed encrypting ""{text}"""); 52 | return m.Value; 53 | } 54 | }); 55 | File.WriteAllText(jsonFile.FullName, json); 56 | } 57 | 58 | [TestCase("../../../appsettings.json")] 59 | public void Decrypt_secured_fields_in_json(string filename) 60 | { 61 | var cipher = new Aes256Cipher(CipherKey); 62 | var jsonFile = new FileInfo(filename); 63 | var json = File.ReadAllText(jsonFile.FullName); 64 | json = Regex.Replace( 65 | json, 66 | @"""CipherText:(?[^""]+)""", 67 | m => 68 | { 69 | var cipherText = m.Groups["CipherText"].Value; 70 | try 71 | { 72 | var text = cipher.Decrypt(cipherText); 73 | return $@"""CipherText:{text}"""; 74 | } 75 | catch (Exception) 76 | { 77 | Console.WriteLine($@"Failed decrypting ""{cipherText}"""); 78 | return m.Value; 79 | } 80 | }); 81 | File.WriteAllText(jsonFile.FullName, json); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.WarmUpAspNetMvc/Controllers/WarmUpController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Security.Principal; 4 | using System.Threading.Tasks; 5 | using System.Web; 6 | using System.Web.Mvc; 7 | using System.Web.Mvc.Html; 8 | using System.Web.Routing; 9 | 10 | namespace Gaev.Blog.Examples.Controllers 11 | { 12 | [AllowAnonymous] 13 | public class WarmUpController : Controller 14 | { 15 | private static bool _isWarm; 16 | 17 | public async Task Index() 18 | { 19 | if (_isWarm) 20 | return; 21 | await Task.WhenAll( 22 | WarmUp(html => html.RenderAction("Index", "Home")), 23 | WarmUp(html => html.RenderAction("About", "Home")), 24 | WarmUp(html => html.RenderAction("Contact", "Home")) 25 | ); 26 | _isWarm = true; 27 | } 28 | 29 | private Task WarmUp(Action act) 30 | { 31 | return Task.Factory.StartNew(() => 32 | { 33 | var requestUrl = Request.Url.AbsoluteUri; 34 | var httpContext = NewHttpContext(requestUrl, new WarmUpUser()); 35 | System.Web.HttpContext.Current = httpContext; 36 | var htmlHelper = CreateHtmlHelper(httpContext); 37 | act(htmlHelper); 38 | }, TaskCreationOptions.LongRunning); 39 | } 40 | 41 | private class WarmUpUser : IPrincipal, IIdentity 42 | { 43 | public bool IsInRole(string role) => true; 44 | public IIdentity Identity => this; 45 | public string Name { get; } = "Warm-up user"; 46 | public string AuthenticationType { get; } = ""; 47 | public bool IsAuthenticated { get; } = true; 48 | } 49 | 50 | private static HttpContext NewHttpContext(string requestUrl, IPrincipal currentUser) 51 | { 52 | var request = new HttpRequest("", requestUrl, ""); 53 | var response = new HttpResponse(TextWriter.Null); 54 | return new HttpContext(request, response) {User = currentUser}; 55 | } 56 | 57 | private static HtmlHelper CreateHtmlHelper(HttpContext httpContext) 58 | { 59 | var controller = new NullController(); 60 | var requestContext = new RequestContext( 61 | new HttpContextWrapper(httpContext), 62 | new RouteData()); 63 | var controllerContext = new ControllerContext(requestContext, controller); 64 | controller.ControllerContext = controllerContext; 65 | var viewContext = new ViewContext( 66 | controllerContext, 67 | new NullView(), 68 | new ViewDataDictionary(), 69 | new TempDataDictionary(), 70 | TextWriter.Null); 71 | return new HtmlHelper(viewContext, new ViewPage()); 72 | } 73 | 74 | private class NullController : ControllerBase 75 | { 76 | protected override void ExecuteCore() => throw new NotImplementedException(); 77 | } 78 | 79 | private class NullView : IView 80 | { 81 | public void Render(ViewContext _, TextWriter __) => throw new NotImplementedException(); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.FunnyTestCases/Gaev.Blog.Examples.FunnyTestCases.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {6368C84E-9009-47F9-964E-F9B3B12F64C5} 9 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10 | Library 11 | Properties 12 | Gaev.Blog.Examples 13 | Gaev.Blog.Examples.FunnyTestCases 14 | v4.7.1 15 | 512 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll 39 | True 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. 54 | 55 | 56 | 57 | 64 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.SerializationTests/SerializationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using AutoFixture; 5 | using AutoFixture.Kernel; 6 | using FluentAssertions; 7 | using Gaev.Blog.Examples.Messages; 8 | using Newtonsoft.Json; 9 | using NUnit.Framework; 10 | 11 | namespace Gaev.Blog.Examples 12 | { 13 | public class SerializationTests 14 | { 15 | [Test] 16 | public void It_should_serialize_then_deserialize_UserRegistered() 17 | { 18 | // Given 19 | var random = TestContext.CurrentContext.Random; 20 | var givenMessage = new UserRegistered( 21 | id: random.NextGuid(), 22 | email: random.GetString(), 23 | name: random.GetString()); 24 | 25 | // When 26 | var json = JsonConvert.SerializeObject(givenMessage); 27 | var deserializedMessage = JsonConvert.DeserializeObject(json); 28 | 29 | // Then 30 | Assert.That(deserializedMessage.Id, Is.EqualTo(givenMessage.Id)); 31 | Assert.That(deserializedMessage.Email, Is.EqualTo(givenMessage.Email)); 32 | Assert.That(deserializedMessage.Name, Is.EqualTo(givenMessage.Name)); 33 | } 34 | 35 | [Test] 36 | public void It_should_serialize_then_deserialize_UserRegistered_entirely() 37 | { 38 | // Given 39 | var givenMessage = new Fixture().Create(); 40 | 41 | // When 42 | var json = JsonConvert.SerializeObject(givenMessage); 43 | var deserializedMessage = JsonConvert.DeserializeObject(json); 44 | 45 | // Then 46 | deserializedMessage.Should().BeEquivalentTo(givenMessage); 47 | } 48 | 49 | [TestCaseSource(nameof(AllMessageTypes))] 50 | public void It_should_serialize_then_deserialize(Type messageType) 51 | { 52 | // Given 53 | var givenMessage = new SpecimenContext(new Fixture()).Resolve(messageType); // https://github.com/AutoFixture/AutoFixture/issues/97#issuecomment-17064685 54 | 55 | // When 56 | var json = JsonConvert.SerializeObject(givenMessage); 57 | var deserializedMessage = JsonConvert.DeserializeObject(json, messageType); 58 | 59 | // Then 60 | deserializedMessage.Should().BeEquivalentTo(givenMessage); 61 | } 62 | 63 | private static IEnumerable AllMessageTypes => 64 | AppDomain.CurrentDomain.GetAssemblies() 65 | .SelectMany(a => a.GetTypes()) 66 | .Where(t => t.IsClass && t.Namespace == "Gaev.Blog.Examples.Messages"); 67 | } 68 | } 69 | 70 | namespace Gaev.Blog.Examples.Messages 71 | { 72 | public class UserRegistered 73 | { 74 | public UserRegistered(Guid id, string email, string name) 75 | { 76 | Id = id; 77 | Email = email; 78 | Name = name; 79 | } 80 | 81 | public Guid Id { get; } 82 | public string Email { get; } 83 | public string Name { get; } 84 | } 85 | 86 | public class UserRegistered_V2 87 | { 88 | public UserRegistered_V2(Guid id, string email, string name) 89 | { 90 | Id = id; 91 | Login = email; 92 | Name = name; 93 | } 94 | 95 | public Guid Id { get; } 96 | public string Login { get; } 97 | public string Name { get; } 98 | } 99 | } -------------------------------------------------------------------------------- /Gaev.Blog.EnumAsStringTrap/SystemTextJson/DeserializationTests.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Text.Json.Serialization; 3 | using FluentAssertions; 4 | using NUnit.Framework; 5 | 6 | namespace Gaev.Blog.EnumAsStringTrap.SystemTextJson; 7 | 8 | public class DeserializationTests 9 | { 10 | [Test] 11 | public void It_should_deserialize_all_known_enum_values() 12 | { 13 | // Given 14 | var json = """ 15 | [ 16 | {"Currency": "EUR", "Amount": 1}, 17 | {"Currency": "USD", "Amount": 2} 18 | ] 19 | """; 20 | 21 | // When 22 | var actual = Deserialize(json); 23 | 24 | //Then 25 | actual.Should().BeEquivalentTo(new[] 26 | { 27 | new Money(Currency.EUR, 1), 28 | new Money(Currency.USD, 2) 29 | }); 30 | } 31 | 32 | [Test] 33 | public void It_should_deserialize_unknown_enum_value() 34 | { 35 | // Given 36 | var json = """ 37 | [ 38 | {"Currency": "EUR", "Amount": 1}, 39 | {"Currency": "USD", "Amount": 2}, 40 | {"Currency": "Bitcoin", "Amount": 3} 41 | ] 42 | """; 43 | 44 | // When 45 | var actual = Deserialize(json); 46 | 47 | //Then 48 | actual.Should().BeEquivalentTo(new[] 49 | { 50 | new Money(Currency.EUR, 1), 51 | new Money(Currency.USD, 2) 52 | }); 53 | } 54 | 55 | [Test] 56 | public void It_should_deserialize_unknown_enum_value_server_fix() 57 | { 58 | // Given 59 | var json = """ 60 | [ 61 | {"Currency": 1, "Amount": 1}, 62 | {"Currency": 2, "Amount": 2}, 63 | {"Currency": 3, "Amount": 3} 64 | ] 65 | """; 66 | 67 | // When 68 | var actual = Deserialize(json); 69 | 70 | //Then 71 | actual.Should().BeEquivalentTo(new[] 72 | { 73 | new Money(Currency.EUR, 1), 74 | new Money(Currency.USD, 2), 75 | new Money((Currency)3, 3), 76 | }); 77 | } 78 | 79 | [Test] 80 | public void It_should_deserialize_unknown_enum_value_client_fix() 81 | { 82 | // Given 83 | var json = """ 84 | [ 85 | {"Currency": "EUR", "Amount": 1}, 86 | {"Currency": "USD", "Amount": 2}, 87 | {"Currency": "Bitcoin", "Amount": 3} 88 | ] 89 | """; 90 | 91 | // When 92 | var actual = JsonSerializer.Deserialize(json, new JsonSerializerOptions 93 | { 94 | Converters = { new UnknownEnumConverter() } 95 | }); 96 | 97 | //Then 98 | actual.Should().BeEquivalentTo(new[] 99 | { 100 | new Money(Currency.EUR, 1), 101 | new Money(Currency.USD, 2), 102 | new Money(default, 3), 103 | }); 104 | } 105 | 106 | private static Money[] Deserialize(string json) 107 | { 108 | return JsonSerializer.Deserialize(json, new JsonSerializerOptions 109 | { 110 | Converters = { new JsonStringEnumConverter() } 111 | }); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.EnumParsePitfall/ParsingEnumTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text.Json; 5 | using System.Text.Json.Serialization; 6 | using NUnit.Framework; 7 | 8 | // ReSharper disable InconsistentNaming 9 | 10 | namespace Gaev.Blog.Examples 11 | { 12 | public enum CountryCode 13 | { 14 | Undefined = default, 15 | DK = 10, 16 | PL = 20 17 | } 18 | 19 | public class ParsingEnumTests 20 | { 21 | [TestCase("DK:1034567", CountryCode.DK)] 22 | [TestCase("PL:1034567", CountryCode.PL)] 23 | [TestCase("1034567", CountryCode.Undefined)] 24 | public void It_should_parse(string vatNumber, CountryCode expected) 25 | { 26 | // Given 27 | string twoLetterCode = vatNumber[..2]; 28 | 29 | // When 30 | CountryCode actual = Parse(twoLetterCode); 31 | 32 | // Then 33 | Assert.That(actual, Is.EqualTo(expected)); 34 | } 35 | 36 | [Test, Repeat(100)] 37 | public void It_should_parse_as_undefined() 38 | { 39 | // Given 40 | var randomizer = TestContext.CurrentContext.Random; 41 | string randomVatNumber = randomizer.Next(1000000, 9999999).ToString(); 42 | string twoLetterCode = randomVatNumber[..2]; 43 | 44 | // When 45 | CountryCode countryCode = Parse(twoLetterCode); 46 | 47 | // Then 48 | Assert.That(countryCode, Is.EqualTo(CountryCode.Undefined)); 49 | } 50 | 51 | public static CountryCode ParseBroken1(string twoLetterCode) 52 | { 53 | if (Enum.TryParse(twoLetterCode, out CountryCode countryCode)) 54 | return countryCode; 55 | 56 | return CountryCode.Undefined; 57 | } 58 | 59 | public static CountryCode ParseBroken2(string twoLetterCode) 60 | { 61 | if (Enum.TryParse(twoLetterCode, out CountryCode countryCode)) 62 | if (Enum.IsDefined(countryCode)) 63 | return countryCode; 64 | 65 | return CountryCode.Undefined; 66 | } 67 | 68 | public static CountryCode ParseBrokenViaJson(string twoLetterCode) 69 | { 70 | var options = new JsonSerializerOptions 71 | { 72 | Converters = { new JsonStringEnumConverter() } 73 | }; 74 | var json = JsonSerializer.Serialize(twoLetterCode); 75 | return JsonSerializer.Deserialize(json, options); 76 | } 77 | 78 | public static CountryCode Parse(string twoLetterCode) 79 | { 80 | return Enum 81 | .GetValues() 82 | .FirstOrDefault(val => Enum.GetName(val) == twoLetterCode); 83 | } 84 | 85 | public static CountryCode ParseFixedMemoryFriendly(string twoLetterCode) 86 | { 87 | var valueByName = EnumCache.ValueByName; 88 | if (valueByName.TryGetValue(twoLetterCode, out var countryCode)) 89 | return countryCode; 90 | 91 | return CountryCode.Undefined; 92 | } 93 | } 94 | 95 | public class EnumCache where TEnum : struct, Enum 96 | { 97 | public static readonly Dictionary ValueByName 98 | = Enum.GetValues().ToDictionary(Enum.GetName); 99 | } 100 | } -------------------------------------------------------------------------------- /Gaev.Blog.EnumAsStringTrap/NewtonsoftJson/DeserializationTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using FluentAssertions; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Converters; 5 | using NUnit.Framework; 6 | 7 | namespace Gaev.Blog.EnumAsStringTrap.NewtonsoftJson; 8 | 9 | public class DeserializationTests 10 | { 11 | [Test] 12 | public void It_should_deserialize_known_enum_values() 13 | { 14 | // Given 15 | var json = """ 16 | [ 17 | {"Currency": "EUR", "Amount": 1}, 18 | {"Currency": "USD", "Amount": 2} 19 | ] 20 | """; 21 | 22 | // When 23 | var actual = Deserialize(json); 24 | 25 | //Then 26 | actual.Should().BeEquivalentTo(new[] 27 | { 28 | new Money(Currency.EUR, 1), 29 | new Money(Currency.USD, 2) 30 | }); 31 | } 32 | 33 | [Test] 34 | public void It_should_deserialize_unknown_enum_value() 35 | { 36 | // Given 37 | var json = """ 38 | [ 39 | {"Currency": "EUR", "Amount": 1}, 40 | {"Currency": "USD", "Amount": 2}, 41 | {"Currency": "Bitcoin", "Amount": 3} 42 | ] 43 | """; 44 | 45 | // When 46 | var actual = Deserialize(json); 47 | 48 | //Then 49 | actual.Should().BeEquivalentTo(new[] 50 | { 51 | new Money(Currency.EUR, 1), 52 | new Money(Currency.USD, 2) 53 | }); 54 | } 55 | 56 | [Test] 57 | public void It_should_deserialize_unknown_enum_value_server_fix() 58 | { 59 | // Given 60 | var json = """ 61 | [ 62 | {"Currency": 1, "Amount": 1}, 63 | {"Currency": 2, "Amount": 2}, 64 | {"Currency": 3, "Amount": 3} 65 | ] 66 | """; 67 | 68 | // When 69 | var actual = Deserialize(json); 70 | 71 | //Then 72 | actual.Should().BeEquivalentTo(new[] 73 | { 74 | new Money(Currency.EUR, 1), 75 | new Money(Currency.USD, 2), 76 | new Money((Currency)3, 3), 77 | }); 78 | } 79 | 80 | [Test] 81 | public void It_should_deserialize_unknown_enum_value_client_fix() 82 | { 83 | // Given 84 | var json = """ 85 | [ 86 | {"Currency": "EUR", "Amount": 1}, 87 | {"Currency": "USD", "Amount": 2}, 88 | {"Currency": "Bitcoin", "Amount": 3} 89 | ] 90 | """; 91 | 92 | // When 93 | var actual = JsonConvert.DeserializeObject(json, new JsonSerializerSettings 94 | { 95 | Converters = new List { new UnknownEnumConverter() } 96 | }); 97 | 98 | //Then 99 | actual.Should().BeEquivalentTo(new[] 100 | { 101 | new Money(Currency.EUR, 1), 102 | new Money(Currency.USD, 2), 103 | new Money(default, 3), 104 | }); 105 | } 106 | 107 | private static Money[] Deserialize(string json) 108 | { 109 | return JsonConvert.DeserializeObject(json, new JsonSerializerSettings 110 | { 111 | Converters = new List { new StringEnumConverter() } 112 | }); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.MiniProfiler3Bug/Microsoft.Threading/AsyncPump.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft.Threading 8 | { 9 | /// Provides a pump that supports running asynchronous methods on the current thread. 10 | public static class AsyncPump 11 | { 12 | /// Runs the specified asynchronous function. 13 | /// The asynchronous function to execute. 14 | public static void Run(Func func) 15 | { 16 | if (func == null) throw new ArgumentNullException("func"); 17 | 18 | var prevCtx = SynchronizationContext.Current; 19 | try 20 | { 21 | // Establish the new context 22 | var syncCtx = new SingleThreadSynchronizationContext(); 23 | SynchronizationContext.SetSynchronizationContext(syncCtx); 24 | 25 | // Invoke the function and alert the context to when it completes 26 | var t = func(); 27 | if (t == null) throw new InvalidOperationException("No task provided."); 28 | t.ContinueWith(delegate { syncCtx.Complete(); }, TaskScheduler.Default); 29 | 30 | // Pump continuations and propagate any exceptions 31 | syncCtx.RunOnCurrentThread(); 32 | t.GetAwaiter().GetResult(); 33 | } 34 | finally { SynchronizationContext.SetSynchronizationContext(prevCtx); } 35 | } 36 | 37 | /// Provides a SynchronizationContext that's single-threaded. 38 | private sealed class SingleThreadSynchronizationContext : SynchronizationContext 39 | { 40 | /// The queue of work items. 41 | private readonly BlockingCollection> m_queue = 42 | new BlockingCollection>(); 43 | /// The processing thread. 44 | private readonly Thread m_thread = Thread.CurrentThread; 45 | 46 | /// Dispatches an asynchronous message to the synchronization context. 47 | /// The System.Threading.SendOrPostCallback delegate to call. 48 | /// The object passed to the delegate. 49 | public override void Post(SendOrPostCallback d, object state) 50 | { 51 | if (d == null) throw new ArgumentNullException("d"); 52 | m_queue.Add(new KeyValuePair(d, state)); 53 | } 54 | 55 | /// Not supported. 56 | public override void Send(SendOrPostCallback d, object state) 57 | { 58 | throw new NotSupportedException("Synchronously sending is not supported."); 59 | } 60 | 61 | /// Runs an loop to process all queued work items. 62 | public void RunOnCurrentThread() 63 | { 64 | foreach (var workItem in m_queue.GetConsumingEnumerable()) 65 | workItem.Key(workItem.Value); 66 | } 67 | 68 | /// Notifies the context that no more work will arrive. 69 | public void Complete() { m_queue.CompleteAdding(); } 70 | } 71 | } 72 | } 73 | // Downloaded from https://devblogs.microsoft.com/pfxteam/await-synchronizationcontext-and-console-apps/ -------------------------------------------------------------------------------- /Gaev.Blog.Examples.TransactionScopeFailure/Gaev.Blog.Examples.TransactionScopeFailure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {DC29DA90-8A6E-48E1-BFD3-0527788B5498} 9 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10 | Library 11 | Properties 12 | Gaev.Blog.Examples 13 | Gaev.Blog.Examples.TransactionScopeFailure 14 | v4.7.1 15 | 512 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | ..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll 40 | True 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. 57 | 58 | 59 | 60 | 67 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.StateViaEF/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace Gaev.Blog.Examples 5 | { 6 | public class User 7 | { 8 | private UserState _userState; 9 | 10 | [NotMapped] 11 | public UserState State 12 | { 13 | get => _userState ?? (_userState = UserState.New(StateType, this)); 14 | set => _userState = value; 15 | } 16 | 17 | public int Id { get; set; } 18 | public string StateType { get; set; } 19 | public int NumberOfAttempts { get; set; } 20 | public string Captcha { get; set; } 21 | public DateTimeOffset? BlockedUntil { get; set; } 22 | 23 | public virtual void OnStateChanged(UserState prev, UserState next) 24 | { 25 | } 26 | } 27 | 28 | public class UserAttemptsToLogin : UserState 29 | { 30 | protected override void OnStart() 31 | { 32 | User.NumberOfAttempts = 0; 33 | User.Captcha = null; 34 | } 35 | 36 | public override void Login(string password) 37 | { 38 | if (password == "test") 39 | Become(new UserIsAuthorized()); 40 | else 41 | { 42 | User.NumberOfAttempts++; 43 | if (User.NumberOfAttempts > 2) 44 | Become(new UserInputsCaptcha()); 45 | } 46 | } 47 | } 48 | 49 | public class UserIsAuthorized : UserState 50 | { 51 | public override bool HasAccess => true; 52 | 53 | public override void Logout() 54 | { 55 | Become(new UserAttemptsToLogin()); 56 | } 57 | } 58 | 59 | public class UserInputsCaptcha : UserState 60 | { 61 | protected override void OnStart() 62 | { 63 | User.Captcha = Guid.NewGuid().ToString(); 64 | } 65 | 66 | public override void InputCaptcha(string captcha) 67 | { 68 | if (captcha == User.Captcha) 69 | Become(new UserAttemptsToLogin()); 70 | else 71 | Become(new UserIsBlocked()); 72 | } 73 | } 74 | 75 | public class UserIsBlocked : UserState 76 | { 77 | protected override void OnStart() 78 | { 79 | User.BlockedUntil = DateTimeOffset.UtcNow.AddHours(1); 80 | } 81 | } 82 | 83 | public abstract class UserState 84 | { 85 | protected User User { get; private set; } 86 | public virtual void Login(string password) => throw new InvalidOperationException(); 87 | public virtual void InputCaptcha(string captcha) => throw new InvalidOperationException(); 88 | public virtual void Logout() => throw new InvalidOperationException(); 89 | public virtual bool HasAccess => false; 90 | 91 | protected virtual void OnStart() 92 | { 93 | } 94 | 95 | protected void Become(UserState next) 96 | { 97 | next.User = User; 98 | next.OnStart(); 99 | User.StateType = next.GetType().Name; 100 | User.State = next; 101 | User.OnStateChanged(this, next); 102 | } 103 | 104 | public static UserState New(string type, User user) 105 | { 106 | switch (type) 107 | { 108 | case nameof(UserIsAuthorized): return new UserIsAuthorized {User = user}; 109 | case nameof(UserInputsCaptcha): return new UserInputsCaptcha {User = user}; 110 | case nameof(UserIsBlocked): return new UserIsBlocked {User = user}; 111 | default: return new UserAttemptsToLogin {User = user}; 112 | } 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.SqlQueue/Gaev.Blog.Examples.SqlQueue.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {ADAFF4C9-05D6-4E29-BD59-A134BCD68DBD} 9 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10 | Library 11 | Properties 12 | Gaev.Blog.Examples 13 | Gaev.Blog.Examples.SqlQueue 14 | v4.7.2 15 | 512 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll 39 | True 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. 57 | 58 | 59 | 60 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.PiiTypes/NLog/PiiStringTests.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Newtonsoft.Json; 3 | using NLog; 4 | using NLog.Config; 5 | using NLog.Layouts; 6 | using NLog.Targets; 7 | using NUnit.Framework; 8 | 9 | namespace Gaev.Blog.Examples.NLog; 10 | 11 | public class PiiStringTests 12 | { 13 | [Test] 14 | public void NLog_should_work() 15 | { 16 | LogManager.Setup().SetupSerialization(s => 17 | { 18 | var jsonConverter = new NewtonsoftJson.PiiStringConverter(new PiiAsSha256()); 19 | var settings = new JsonSerializerSettings {Converters = {jsonConverter}}; 20 | s.RegisterJsonConverter(new NewtonsoftJsonConverter(settings)); 21 | }); 22 | 23 | var logger = new LogFactory(WriteToConsoleConfig()).GetCurrentClassLogger(); 24 | var user = new User 25 | { 26 | Name = "John Doe", 27 | Email = "john.doe@test.com" 28 | }; 29 | logger.Info("The user is {@Data}", user); 30 | logger.Info("The email is {@Data}", user.Email); 31 | logger.Info("The email is {@Data}", new {user.Email}); 32 | } 33 | 34 | [Test] 35 | public void NLog_should_work_for_JsonLayout() 36 | { 37 | LogManager.Setup().SetupSerialization(s => 38 | { 39 | var jsonConverter = new NewtonsoftJson.PiiStringConverter(new PiiAsSha256()); 40 | var settings = new JsonSerializerSettings {Converters = {jsonConverter}}; 41 | s.RegisterJsonConverter(new NewtonsoftJsonConverter(settings)); 42 | }); 43 | 44 | var logger = new LogFactory(WriteJsonToConsoleConfig()).GetCurrentClassLogger(); 45 | var user = new User 46 | { 47 | Name = "John Doe", 48 | Email = "john.doe@test.com" 49 | }; 50 | logger.Info("The user is {@Data}", user); 51 | logger.Info("The email is {@Data}", user.Email); 52 | logger.Info("The email is {@Data}", new {user.Email}); 53 | } 54 | 55 | private static LoggingConfiguration WriteToConsoleConfig() 56 | { 57 | var config = new LoggingConfiguration(); 58 | var target = new ColoredConsoleTarget("console") 59 | { 60 | Layout = @"[${date:format=HH\:mm\:ss} ${level}] ${message}${newline}${exception:format=ToString}" 61 | }; 62 | config.AddTarget(target); 63 | config.AddRuleForAllLevels(target); 64 | return config; 65 | } 66 | 67 | private static LoggingConfiguration WriteJsonToConsoleConfig() 68 | { 69 | var config = new LoggingConfiguration(); 70 | var target = new ColoredConsoleTarget("console") 71 | { 72 | Layout = new JsonLayout 73 | { 74 | IncludeAllProperties = true, 75 | Attributes = 76 | { 77 | new JsonAttribute("Message", "${message:raw=true}"), 78 | new JsonAttribute("Date", "${date:universalTime=True:format=O}"), 79 | new JsonAttribute("Logger", "${logger}"), 80 | new JsonAttribute("Level", "${level:upperCase=true}"), 81 | new JsonAttribute("Exception", "${exception:format=toString}"), 82 | } 83 | } 84 | }; 85 | config.AddTarget(target); 86 | config.AddRuleForAllLevels(target); 87 | return config; 88 | } 89 | } 90 | 91 | public class NewtonsoftJsonConverter : IJsonConverter 92 | { 93 | private readonly JsonSerializerSettings _settings; 94 | 95 | public NewtonsoftJsonConverter(JsonSerializerSettings settings) 96 | { 97 | _settings = settings; 98 | } 99 | 100 | public bool SerializeObject(object value, StringBuilder builder) 101 | { 102 | builder.Append(JsonConvert.SerializeObject(value, _settings)); 103 | return true; 104 | } 105 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.MiniProfiler3Bug/MiniProfilerReproductionTests.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | using System.Data.SqlClient; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using System.Transactions; 6 | using Microsoft.Threading; 7 | using NUnit.Framework; 8 | using StackExchange.Profiling.Data; 9 | 10 | namespace Gaev.Blog.Examples 11 | { 12 | [TestFixture(false, "it uses SqlConnection")] 13 | [TestFixture(true, "it uses ProfiledDbConnection")] 14 | public class MiniProfilerReproductionTests 15 | { 16 | private readonly bool _useMiniProfiler; 17 | 18 | public MiniProfilerReproductionTests(bool useMiniProfiler, string _) 19 | { 20 | _useMiniProfiler = useMiniProfiler; 21 | } 22 | 23 | [Test] 24 | public void Sync_transaction_should_not_flow() 25 | { 26 | // Given 27 | Transaction transactionBeforeDbCall = null; 28 | Transaction transactionAfterDbCall = null; 29 | using (var tran = new TransactionScope()) 30 | { 31 | transactionBeforeDbCall = Transaction.Current; 32 | AsyncPump.Run(async () => 33 | { 34 | // When 35 | await MakeDatabaseCall().ConfigureAwait(false); 36 | transactionAfterDbCall = Transaction.Current; 37 | }); 38 | tran.Complete(); 39 | } 40 | 41 | // Then 42 | Assert.That(transactionBeforeDbCall, Is.Not.Null); 43 | Assert.That(transactionAfterDbCall, Is.Null); 44 | } 45 | 46 | [Test] 47 | public void Async_transaction_should_flow() 48 | { 49 | // Given 50 | Transaction transactionBeforeDbCall = null; 51 | Transaction transactionAfterDbCall = null; 52 | using (var tran = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) 53 | { 54 | transactionBeforeDbCall = Transaction.Current; 55 | AsyncPump.Run(async () => 56 | { 57 | // When 58 | await MakeDatabaseCall().ConfigureAwait(false); 59 | transactionAfterDbCall = Transaction.Current; 60 | }); 61 | tran.Complete(); 62 | } 63 | 64 | // Then 65 | Assert.That(transactionBeforeDbCall, Is.Not.Null); 66 | Assert.That(transactionAfterDbCall, Is.Not.Null); 67 | } 68 | 69 | [Test] 70 | public void ConfigureAwait_should_be_respected() 71 | { 72 | AsyncPump.Run(async () => 73 | { 74 | // Given 75 | var contextBeforeDbCall = SynchronizationContext.Current; 76 | 77 | // When 78 | await MakeDatabaseCall().ConfigureAwait(false); 79 | var contextAfterDbCall = SynchronizationContext.Current; 80 | 81 | // Then 82 | Assert.That(contextBeforeDbCall, Is.Not.Null); 83 | Assert.That(contextAfterDbCall, Is.Null); 84 | }); 85 | } 86 | 87 | private async Task MakeDatabaseCall() 88 | { 89 | using (var con = CreateDbConnection()) 90 | { 91 | await con.OpenAsync(); 92 | var cmd = con.CreateCommand(); 93 | cmd.CommandText = "select 1;"; 94 | await cmd.ExecuteScalarAsync(); 95 | } 96 | } 97 | 98 | private DbConnection CreateDbConnection() 99 | { 100 | var connection = new SqlConnection("server=localhost;database=tempdb;UID=sa;PWD=sa123"); 101 | if (_useMiniProfiler) 102 | return new ProfiledDbConnection(connection, null); 103 | return connection; 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.PiiTypes/EfCore/PiiStringTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using FluentAssertions; 5 | using Microsoft.EntityFrameworkCore; 6 | using NUnit.Framework; 7 | 8 | namespace Gaev.Blog.Examples.EfCore; 9 | 10 | public class PiiStringTests 11 | { 12 | [Test] 13 | public async Task EfCore_should_work() 14 | { 15 | // Given 16 | await using var db = new TestDbContext(new PiiAsPlainText()); 17 | await db.Database.EnsureCreatedAsync(); 18 | var givenUser = new User 19 | { 20 | Id = Guid.NewGuid(), 21 | Name = "John Doe", 22 | Email = "john.doe@test.com" 23 | }; 24 | 25 | // When 26 | db.Users.Add(givenUser); 27 | await db.SaveChangesAsync(); 28 | db.DetachAll(); 29 | var savedUser = await db.Users.FindAsync(givenUser.Id); 30 | 31 | // Then 32 | savedUser.Should().BeEquivalentTo(givenUser); 33 | } 34 | 35 | [Test] 36 | public async Task EfCore_queries_should_work() 37 | { 38 | // Given 39 | await using var db = new TestDbContext(new PiiAsPlainText()); 40 | await db.Database.EnsureCreatedAsync(); 41 | var givenUser = new User 42 | { 43 | Id = Guid.NewGuid(), 44 | Name = "John Doe", 45 | Email = "john.doe@test.com" 46 | }; 47 | 48 | // When 49 | db.Users.Add(givenUser); 50 | await db.SaveChangesAsync(); 51 | db.DetachAll(); 52 | var savedUser = await db.Users 53 | .Where(e => ((string) e.Email).Contains("john.doe@test.com") || e.Name == "bla") 54 | .ToListAsync(); 55 | } 56 | 57 | [Test] 58 | public async Task EfCore_should_encrypt() 59 | { 60 | // Given 61 | var key = "hb50qBZSF0fcLSl9814PIqmO4gEZcJGB/Kd4fpTTBcU="; 62 | await using var db = new TestDbContext(new PiiAsAes128(key)); 63 | await db.Database.EnsureCreatedAsync(); 64 | var givenUser = new User 65 | { 66 | Id = Guid.NewGuid(), 67 | Name = "John Doe", 68 | Email = "john.doe@test.com" 69 | }; 70 | 71 | // When 72 | db.Users.Add(givenUser); 73 | await db.SaveChangesAsync(); 74 | db.DetachAll(); 75 | var savedUser = await db.Users.FindAsync(givenUser.Id); 76 | 77 | // Then 78 | savedUser.Should().BeEquivalentTo(givenUser); 79 | } 80 | } 81 | 82 | public class TestDbContext : DbContext 83 | { 84 | private readonly IPiiEncoder _piiEncoder; 85 | 86 | public TestDbContext(IPiiEncoder piiEncoder) : this( 87 | "Server=localhost;Port=5432;Database=playground;User ID=postgres;Password=sa123;") 88 | { 89 | _piiEncoder = piiEncoder; 90 | } 91 | 92 | public TestDbContext(string connectionString) 93 | : base(new DbContextOptionsBuilder().UseNpgsql(connectionString).Options) 94 | { 95 | } 96 | 97 | protected override void OnModelCreating(ModelBuilder modelBuilder) 98 | { 99 | var piiConverter = new PiiStringConverter(_piiEncoder); 100 | 101 | modelBuilder.Entity(opt => 102 | { 103 | opt.ToTable("User"); 104 | opt.Property(e => e.Name).HasConversion(piiConverter); 105 | opt.Property(e => e.Email).HasConversion(piiConverter); 106 | opt.Property(e => e.Location).HasConversion(piiConverter); 107 | }); 108 | } 109 | 110 | public DbSet Users { get; set; } 111 | } 112 | 113 | public static class DbContextEfCoreExt 114 | { 115 | public static void DetachAll(this DbContext db) 116 | { 117 | foreach (var dbEntityEntry in db.ChangeTracker.Entries().ToList()) 118 | { 119 | if (dbEntityEntry.Entity != null) 120 | { 121 | dbEntityEntry.State = EntityState.Detached; 122 | } 123 | } 124 | } 125 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.MiniProfiler3Bug/Gaev.Blog.Examples.MiniProfiler3Bug.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {ACD0EFA6-8E0A-47E2-82DF-362AB75B2672} 9 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10 | Library 11 | Properties 12 | Gaev.Blog.Examples 13 | Gaev.Blog.Examples.MiniProfiler3Bug 14 | v4.7.2 15 | 512 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\MiniProfiler.3.2.0.157\lib\net40\MiniProfiler.dll 39 | True 40 | 41 | 42 | ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll 43 | True 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. 62 | 63 | 64 | 65 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.ExceptionCustomData/Gaev.Blog.Examples.ExceptionCustomData.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {1AC06AD0-0262-4458-B02A-DA9024F2B3E2} 9 | {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 10 | Library 11 | Properties 12 | Gaev.Blog.Examples 13 | Gaev.Blog.Examples.ExceptionCustomData 14 | v4.7.1 15 | 512 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | ..\packages\NLog.4.5.11\lib\net45\NLog.dll 40 | True 41 | 42 | 43 | ..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll 44 | True 45 | 46 | 47 | ..\packages\Serilog.2.8.0\lib\net46\Serilog.dll 48 | True 49 | 50 | 51 | ..\packages\Serilog.Sinks.Console.3.1.1\lib\net45\Serilog.Sinks.Console.dll 52 | True 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. 66 | 67 | 68 | 69 | 76 | -------------------------------------------------------------------------------- /Gaev.Blog.Examples.GoogleAlert/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using HtmlAgilityPack; 7 | using Microsoft.EntityFrameworkCore; 8 | using Microsoft.Extensions.Configuration; 9 | using Serilog; 10 | using Serilog.Core; 11 | using Serilog.Sinks.Telegram; 12 | 13 | namespace Gaev.Blog.Examples 14 | { 15 | public class Program 16 | { 17 | private const string SpecificOtoDomSearchUrl = 18 | "https://www.otodom.pl/sprzedaz/mieszkanie/krakow/pradnik-czerwony/?search%5Bfilter_float_price%3Afrom%5D=300000&search%5Bfilter_float_price%3Ato%5D=600000&search%5Bfilter_enum_rooms_num%5D%5B0%5D=3&search%5Bfilter_enum_rooms_num%5D%5B1%5D=4&search%5Bfilter_enum_market%5D%5B0%5D=secondary&search%5Bdescription%5D=1&search%5Bdist%5D=0&search%5Bdistrict_id%5D=66&search%5Bsubregion_id%5D=410&search%5Bcity_id%5D=38&nrAdsPerPage=72"; 19 | 20 | public static async Task Main(string[] args) 21 | { 22 | var config = new ConfigurationBuilder() 23 | .AddJsonFile("appsettings.json") 24 | .Build() 25 | .Get(); 26 | using (var logger = new LoggerConfiguration() 27 | .WriteTo.Telegram(config.TelegramApiKey, config.TelegramChatId) 28 | .CreateLogger()) 29 | try 30 | { 31 | using (var db = new AlertsDatabase()) 32 | await Sync(logger, db); 33 | } 34 | catch (Exception ex) 35 | { 36 | logger.Error(ex, "Oops :("); 37 | } 38 | } 39 | 40 | private static async Task Sync(Logger logger, AlertsDatabase db) 41 | { 42 | await db.Database.EnsureCreatedAsync(); 43 | var foundPages = await OtoDomCrawler.Search(SpecificOtoDomSearchUrl); 44 | var knownPages = await db.Pages.ToListAsync(); 45 | var newPages = foundPages.Except(knownPages).ToList(); 46 | db.Pages.AddRange(newPages); 47 | await db.SaveChangesAsync(); 48 | foreach (var page in newPages) 49 | logger.Information($"[{page.Title}]({page.Link})"); 50 | } 51 | } 52 | 53 | public class Config 54 | { 55 | public string TelegramApiKey { get; set; } 56 | public string TelegramChatId { get; set; } 57 | } 58 | 59 | public class AlertsDatabase : DbContext 60 | { 61 | public DbSet Pages { get; set; } 62 | 63 | protected override void OnConfiguring(DbContextOptionsBuilder opt) => 64 | opt.UseSqlite("Data Source=Alerts.sqlite3"); 65 | } 66 | 67 | public class Page 68 | { 69 | [Key] public string Link { get; set; } 70 | public string Title { get; set; } 71 | public override bool Equals(object compared) => string.Equals(Link, ((Page) compared).Link); 72 | public override int GetHashCode() => Link.GetHashCode(); 73 | } 74 | 75 | public static class OtoDomCrawler 76 | { 77 | public static async Task> Search(string url) 78 | { 79 | var offers = new List(); 80 | while (url != null) 81 | { 82 | var html = (await new HtmlWeb().LoadFromWebAsync(url)).DocumentNode; 83 | offers.AddRange(GetOffers(html)); 84 | url = html.SelectSingleNode("//a[@data-dir='next']")?.GetAttributeValue("href", null); 85 | } 86 | 87 | return offers; 88 | } 89 | 90 | private static IEnumerable GetOffers(HtmlNode html) 91 | { 92 | foreach (var offer in html.SelectNodes("//*[@class='offer-item-details']")) 93 | { 94 | var title = offer.SelectSingleNode(".//*[@class='offer-item-title']"); 95 | var link = title?.AncestorsAndSelf("a").FirstOrDefault(); 96 | yield return new Page 97 | { 98 | Link = link?.GetAttributeValue("href", null)?.Split("#")?.FirstOrDefault(), 99 | Title = title?.InnerText 100 | }; 101 | } 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /Gaev.Blog.Examples.ArchitectureTests/ArchitectureTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using FluentAssertions; 5 | using NUnit.Framework; 6 | using PlantUml.Net; 7 | using static Gaev.Blog.Examples.Conventions; 8 | 9 | namespace Gaev.Blog.Examples; 10 | 11 | public class ArchitectureTests 12 | { 13 | static readonly List AllAssemblies 14 | = DotNetAssembly.LoadAll(); 15 | 16 | public static IEnumerable AppProjects 17 | => AllAssemblies.Where(IsMyApp).Where(IsNotTest); 18 | 19 | [TestCaseSource(nameof(AppProjects))] 20 | public void App_project_should_be_NetStandard(DotNetAssembly it) 21 | => it.IsDotNetStandard() 22 | .Should().BeTrue(); 23 | 24 | [TestCaseSource(nameof(AppProjects))] 25 | public void App_project_should_have_NetStandard_dependencies_only(DotNetAssembly my) 26 | => my.Dependencies 27 | .Should().OnlyContain(e => e.IsDotNetStandard()); 28 | 29 | public static IEnumerable Contracts 30 | => AppProjects.Where(IsContract); 31 | 32 | [TestCaseSource(nameof(Contracts))] 33 | public void Contract_should_not_reference_contract(DotNetAssembly contract) 34 | => contract.Dependencies 35 | .Should().NotContain(e => IsContract(e)); 36 | 37 | [TestCaseSource(nameof(Contracts))] 38 | public void Contract_should_not_have_any_dependencies(DotNetAssembly contract) 39 | => contract.Dependencies 40 | .Should().OnlyContain(e => IsSystem(e)); 41 | 42 | [TestCaseSource(nameof(Contracts))] 43 | public void Contract_should_not_reference_implementation(DotNetAssembly contract) 44 | => contract.Dependencies 45 | .Should().NotContain(e => IsImplementation(e)); 46 | 47 | public static IEnumerable Implementations 48 | => AppProjects.Where(IsImplementation); 49 | 50 | [TestCaseSource(nameof(Implementations))] 51 | public void Implementation_should_not_reference_implementation(DotNetAssembly implementation) 52 | => implementation.Dependencies 53 | .Should().NotContain(e => IsImplementation(e)); 54 | 55 | [TestCaseSource(nameof(Implementations))] 56 | public void Implementation_should_reference_DI(DotNetAssembly implementation) 57 | => implementation.Dependencies 58 | .Should().Contain(e => e.Name.StartsWith("Microsoft.Extensions.DependencyInjection")); 59 | 60 | [TestCaseSource(nameof(AppProjects))] 61 | public void It_should_render_PlantUml_diagram(DotNetAssembly project) 62 | { 63 | var plantUmlCode = project.RenderPlantUmlDiagram(IsMyApp); 64 | var svgDiagramUrl = new RendererFactory() 65 | .CreateRenderer() 66 | .RenderAsUri(plantUmlCode, OutputFormat.Svg); 67 | Console.WriteLine($"{svgDiagramUrl}\n{plantUmlCode}"); 68 | } 69 | 70 | private void CompilerHint() 71 | { 72 | // This should make compiler to include the following dependencies 73 | _ = typeof(Shell.Bootstrap).Assembly; 74 | } 75 | } 76 | 77 | public static class Conventions 78 | { 79 | public static bool IsMyApp(DotNetAssembly project) 80 | => project.Name.StartsWith("Gaev"); 81 | 82 | public static bool IsNotMyApp(DotNetAssembly project) 83 | => !IsMyApp(project); 84 | 85 | public static bool IsTest(DotNetAssembly project) 86 | => IsMyApp(project) && project.Name.EndsWith("Tests"); 87 | 88 | public static bool IsNotTest(DotNetAssembly project) 89 | => !IsTest(project); 90 | 91 | public static bool IsShell(DotNetAssembly project) 92 | => IsMyApp(project) && project.Name.EndsWith(".Shell"); 93 | 94 | public static bool IsContract(DotNetAssembly project) 95 | => IsMyApp(project) && project.Name.EndsWith(".Api"); 96 | 97 | public static bool IsImplementation(DotNetAssembly project) 98 | => IsMyApp(project) && !IsShell(project) && !IsContract(project) && !IsTest(project); 99 | 100 | public static bool IsSystem(DotNetAssembly assembly) 101 | => assembly.Name == "netstandard"; 102 | 103 | public static bool IsNotSystem(DotNetAssembly assembly) 104 | => !IsSystem(assembly); 105 | } 106 | --------------------------------------------------------------------------------