diff --git a/SuccessfulCodeTools.Tests/StringExtensionsTests.cs b/SuccessfulCodeTools.Tests/StringExtensionsTests.cs new file mode 100644 index 0000000..6623c23 --- /dev/null +++ b/SuccessfulCodeTools.Tests/StringExtensionsTests.cs @@ -0,0 +1,19 @@ +using System; +using Xunit; + +namespace SuccessfulCodeTools.Tests +{ + public class StringExtensionsTests + { + [Theory] + [InlineData("CaMel_cAse", "CamelCase")] + public void CheckSnakeCaseToCamelCase(string input, string expectedOutput) + { + //Arrange + //Act + var result = input.FromSnakeToCamel(); + //Assert + Assert.Equal(expectedOutput, result); + } + } +} diff --git a/SuccessfulCodeTools.Tests/SuccessfulCodeTools.Tests.csproj b/SuccessfulCodeTools.Tests/SuccessfulCodeTools.Tests.csproj new file mode 100644 index 0000000..2bad026 --- /dev/null +++ b/SuccessfulCodeTools.Tests/SuccessfulCodeTools.Tests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + diff --git a/SuccessfulCodeTools.sln b/SuccessfulCodeTools.sln index 79fa6aa..1251242 100644 --- a/SuccessfulCodeTools.sln +++ b/SuccessfulCodeTools.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29424.173 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuccessfulCodeTools", "SuccessfulCodeTools\SuccessfulCodeTools.csproj", "{0CF60384-D7C3-491D-B3FD-73BDA7EE8B89}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SuccessfulCodeTools", "SuccessfulCodeTools\SuccessfulCodeTools.csproj", "{0CF60384-D7C3-491D-B3FD-73BDA7EE8B89}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuccessfulCodeTools.Tests", "SuccessfulCodeTools.Tests\SuccessfulCodeTools.Tests.csproj", "{43979EEF-19B8-46B1-A32B-CC99879F5168}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {0CF60384-D7C3-491D-B3FD-73BDA7EE8B89}.Debug|Any CPU.Build.0 = Debug|Any CPU {0CF60384-D7C3-491D-B3FD-73BDA7EE8B89}.Release|Any CPU.ActiveCfg = Release|Any CPU {0CF60384-D7C3-491D-B3FD-73BDA7EE8B89}.Release|Any CPU.Build.0 = Release|Any CPU + {43979EEF-19B8-46B1-A32B-CC99879F5168}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43979EEF-19B8-46B1-A32B-CC99879F5168}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43979EEF-19B8-46B1-A32B-CC99879F5168}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43979EEF-19B8-46B1-A32B-CC99879F5168}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SuccessfulCodeTools/Extensions/DecimalExtensions.cs b/SuccessfulCodeTools/Extensions/DecimalExtensions.cs new file mode 100644 index 0000000..7618bfc --- /dev/null +++ b/SuccessfulCodeTools/Extensions/DecimalExtensions.cs @@ -0,0 +1,10 @@ +namespace SuccessfulCodeTools.Extensions +{ + public static class DecimalExtensions + { + public static decimal PercentOf(this decimal value, decimal total) + { + return (value / 100) * total; + } + } +} diff --git a/SuccessfulCodeTools/Extensions/StringExtensions.cs b/SuccessfulCodeTools/Extensions/StringExtensions.cs index 60d45d6..44ec805 100644 --- a/SuccessfulCodeTools/Extensions/StringExtensions.cs +++ b/SuccessfulCodeTools/Extensions/StringExtensions.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System; +using System.Text.RegularExpressions; namespace SuccessfulCodeTools { @@ -19,5 +20,13 @@ namespace SuccessfulCodeTools { return Int32.Parse(value); } + + public static string FromSnakeToCamel(this string str) + { + var lowerCasedValue = str.ToLowerInvariant(); + return Regex.Replace(lowerCasedValue, "(^[a-zA-Z]|_([a-zA-Z]))", m => { + return m.Value.TrimStart('_').ToUpper(); + }, RegexOptions.Compiled); + } } } diff --git a/SuccessfulCodeTools/LowLevelHttpClient/CustomHttpClient.cs b/SuccessfulCodeTools/LowLevelHttpClient/CustomHttpClient.cs index af339bd..bbf0265 100644 --- a/SuccessfulCodeTools/LowLevelHttpClient/CustomHttpClient.cs +++ b/SuccessfulCodeTools/LowLevelHttpClient/CustomHttpClient.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.IO.Compression; @@ -7,6 +8,7 @@ using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Text; +using System.Threading; using System.Threading.Tasks; namespace SuccessfulCodeTools.LowLevelHttpClient @@ -15,6 +17,7 @@ namespace SuccessfulCodeTools.LowLevelHttpClient { public int? OutgoingPort { get; set; } public KeyValueCollection DefaultHeaders = new KeyValueCollection(); + private static ConcurrentDictionary _dictionary = new ConcurrentDictionary(); public CustomHttpClient(int? outgoingPort = null) { OutgoingPort = outgoingPort; @@ -22,11 +25,13 @@ namespace SuccessfulCodeTools.LowLevelHttpClient public async Task SendAsync(CustomHttpRequestMessage message, int? outgoingPort = null) { + var defaultHeaders = DefaultHeaders.Where(e => !message.Headers.Contains(e)).ToArray(); message.Headers.AddRange(defaultHeaders); var outBoundPort = outgoingPort ?? OutgoingPort ?? 0; - string result = string.Empty; + var semphoreLock = (SemaphoreSlim)_dictionary.GetOrAdd(outBoundPort, e => new SemaphoreSlim(1)); + semphoreLock.Wait(); var ipLocalEndPoint = new IPEndPoint(IPAddress.Any, outBoundPort); using (var tcp = new TcpClient(ipLocalEndPoint)) { @@ -52,10 +57,11 @@ namespace SuccessfulCodeTools.LowLevelHttpClient { await stream.CopyToAsync(memory); tcp.Client.Disconnect(true); + semphoreLock.Release(); return new CustomHttpResponseMessage(memory); } } - } + } } }