Przeglądaj źródła

Adding Platform Fortune (#3747)

* Adding Platform Fortune

* Moving Startup code in Program
Sébastien Ros 7 lat temu
rodzic
commit
a2257bd458
22 zmienionych plików z 535 dodań i 5 usunięć
  1. 37 2
      frameworks/CSharp/aspnetcore/.gitignore
  2. 11 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.HttpConnection.cs
  3. 72 3
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.cs
  4. 12 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Configuration/AppSettings.cs
  5. 13 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Configuration/DatabaseServer.cs
  6. 24 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/BatchUpdateString.cs
  7. 25 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/Fortune.cs
  8. 19 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/IDb.cs
  9. 10 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/IRandom.cs
  10. 20 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/Random.cs
  11. 171 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/RawDb.cs
  12. 17 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/World.cs
  13. 6 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/PlatformBenchmarks.csproj
  14. 20 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Program.cs
  15. 11 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Utilities/BufferExtensions.cs
  16. 1 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Utilities/BufferWriter.cs
  17. 0 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Utilities/DateHeader.cs
  18. 3 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/appsettings.json
  19. 13 0
      frameworks/CSharp/aspnetcore/aspcore-ado-my.dockerfile
  20. 13 0
      frameworks/CSharp/aspnetcore/aspcore-ado-pg.dockerfile
  21. 1 0
      frameworks/CSharp/aspnetcore/aspcore.dockerfile
  22. 36 0
      frameworks/CSharp/aspnetcore/benchmark_config.json

+ 37 - 2
frameworks/CSharp/aspnetcore/.gitignore

@@ -1,2 +1,37 @@
-*/bin
-*/obj
+[Oo]bj/
+[Bb]in/
+TestResults/
+.nuget/
+*.sln.ide/
+_ReSharper.*/
+.idea/
+packages/
+artifacts/
+PublishProfiles/
+.vs/
+*.user
+*.suo
+*.cache
+*.docstates
+_ReSharper.*
+nuget.exe
+*net45.csproj
+*net451.csproj
+*k10.csproj
+*.psess
+*.vsp
+*.pidb
+*.userprefs
+*DS_Store
+*.ncrunchsolution
+*.*sdf
+*.ipch
+*.swp
+*~
+.build/
+.testPublish/
+launchSettings.json
+BenchmarkDotNet.Artifacts/
+BDN.Generated/
+binaries/
+global.json

+ 11 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.HttpConnection.cs

@@ -5,6 +5,8 @@ using System;
 using System.Buffers;
 using System.IO.Pipelines;
 using System.Runtime.CompilerServices;
+using System.Text.Encodings.Web;
+using System.Text.Unicode;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 
@@ -17,6 +19,8 @@ namespace PlatformBenchmarks
         public PipeReader Reader { get; set; }
         public PipeWriter Writer { get; set; }
 
+        protected HtmlEncoder HtmlEncoder { get; } = CreateHtmlEncoder();
+
         private HttpParser<ParsingAdapter> Parser { get; } = new HttpParser<ParsingAdapter>();
 
         public async Task ExecuteAsync()
@@ -130,6 +134,13 @@ namespace PlatformBenchmarks
             await Writer.FlushAsync();
         }
 
+        private static HtmlEncoder CreateHtmlEncoder()
+        {
+            var settings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Katakana, UnicodeRanges.Hiragana);
+            settings.AllowCharacter('\u2014');  // allow EM DASH through
+            return HtmlEncoder.Create(settings);
+        }
+
         private static void ThrowUnexpectedEndOfData()
         {
             throw new InvalidOperationException("Unexpected end of data!");

+ 72 - 3
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.cs

@@ -2,7 +2,9 @@
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
 using System;
+using System.Collections.Generic;
 using System.IO.Pipelines;
+using System.Text.Encodings.Web;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 using Utf8Json;
@@ -22,13 +24,24 @@ namespace PlatformBenchmarks
         private readonly static AsciiString _headerContentLengthZero = "Content-Length: 0\r\n";
         private readonly static AsciiString _headerContentTypeText = "Content-Type: text/plain\r\n";
         private readonly static AsciiString _headerContentTypeJson = "Content-Type: application/json\r\n";
+        private readonly static AsciiString _headerContentTypeHtml = "Content-Type: text/html; charset=UTF-8\r\n";
 
         private readonly static AsciiString _plainTextBody = "Hello, World!";
 
+        private readonly static AsciiString _fortunesTableStart = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
+        private readonly static AsciiString _fortunesRowStart = "<tr><td>";
+        private readonly static AsciiString _fortunesColumn = "</td><td>";
+        private readonly static AsciiString _fortunesRowEnd = "</td></tr>";
+        private readonly static AsciiString _fortunesTableEnd = "</table></body></html>";
+        private readonly static AsciiString _contentLengthGap = new string(' ', 4);
+
+        public static IDb Db { get; set; }
+
         public static class Paths
         {
             public readonly static AsciiString Plaintext = "/plaintext";
             public readonly static AsciiString Json = "/json";
+            public readonly static AsciiString Fortunes = "/fortunes";
         }
 
         private RequestType _requestType;
@@ -46,12 +59,16 @@ namespace PlatformBenchmarks
                 {
                     requestType = RequestType.Json;
                 }
+                else if (Paths.Fortunes.Length <= path.Length && path.StartsWith(Paths.Fortunes))
+                {
+                    requestType = RequestType.Fortunes;
+                }
             }
 
             _requestType = requestType;
         }
 
-        public ValueTask ProcessRequestAsync()
+        public Task ProcessRequestAsync()
         {
             if (_requestType == RequestType.PlainText)
             {
@@ -61,12 +78,16 @@ namespace PlatformBenchmarks
             {
                 Json(Writer);
             }
+            else if (_requestType == RequestType.Fortunes)
+            {
+                return Fortunes(Writer);
+            }
             else
             {
                 Default(Writer);
             }
 
-            return default;
+            return Task.CompletedTask;
         }
 
         private static void PlainText(PipeWriter pipeWriter)
@@ -126,6 +147,53 @@ namespace PlatformBenchmarks
             writer.Commit();
         }
 
+        private async Task Fortunes(PipeWriter pipeWriter)
+        {
+            OutputFortunes(pipeWriter, await Db.LoadFortunesRows());
+        }
+
+        private void OutputFortunes(PipeWriter pipeWriter, List<Fortune> model)
+        {
+            var writer = GetWriter(pipeWriter);
+
+            // HTTP 1.1 OK
+            writer.Write(_http11OK);
+
+            // Server headers
+            writer.Write(_headerServer);
+
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
+
+            // Content-Type header
+            writer.Write(_headerContentTypeHtml);
+
+            // Content-Length header
+            writer.Write(_headerContentLength);
+
+            var lengthWriter = writer;
+            writer.Write(_contentLengthGap);
+
+            // End of headers
+            writer.Write(_eoh);
+
+            var bodyStart = writer.Buffered;
+            // Body
+            writer.Write(_fortunesTableStart);
+            foreach (var item in model)
+            {
+                writer.Write(_fortunesRowStart);
+                writer.WriteNumeric((uint)item.Id);
+                writer.Write(_fortunesColumn);
+                writer.WriteUtf8String(HtmlEncoder.Encode(item.Message));
+                writer.Write(_fortunesRowEnd);
+            }
+            writer.Write(_fortunesTableEnd);
+            lengthWriter.WriteNumeric((uint)(writer.Buffered - bodyStart));
+
+            writer.Commit();
+        }
+
         private static void Default(PipeWriter pipeWriter)
         {
             var writer = GetWriter(pipeWriter);
@@ -151,7 +219,8 @@ namespace PlatformBenchmarks
         {
             NotRecognized,
             PlainText,
-            Json
+            Json,
+            Fortunes
         }
     }
 }

+ 12 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Configuration/AppSettings.cs

@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace PlatformBenchmarks
+{
+    public class AppSettings
+    {
+        public string ConnectionString { get; set; }
+
+        public DatabaseServer Database { get; set; } = DatabaseServer.None;
+    }
+}

+ 13 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Configuration/DatabaseServer.cs

@@ -0,0 +1,13 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+namespace PlatformBenchmarks
+{
+    public enum DatabaseServer
+    {
+        None,
+        SqlServer,
+        PostgreSql,
+        MySql
+    }
+}

+ 24 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/BatchUpdateString.cs

@@ -0,0 +1,24 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace PlatformBenchmarks
+{
+    internal class BatchUpdateString
+    {
+        public static IList<BatchUpdateString> Strings { get;} = 
+            Enumerable.Range(0, 500)
+                      .Select(i => new BatchUpdateString
+                      {
+                          Id = $"Id_{i}",
+                          Random = $"Random_{i}",
+                          UpdateQuery = $"UPDATE world SET randomnumber = @Random_{i} WHERE id = @Id_{i};"
+                      }).ToArray();
+                        
+        public string Id { get; set; }
+        public string Random { get; set; }
+        public string UpdateQuery { get; set; }
+    }
+}

+ 25 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/Fortune.cs

@@ -0,0 +1,25 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+
+namespace PlatformBenchmarks
+{
+    public class Fortune : IComparable<Fortune>, IComparable
+    {
+        public int Id { get; set; }
+
+        public string Message { get; set; }
+        
+        public int CompareTo(object obj)
+        {
+            return CompareTo((Fortune)obj);
+        }
+
+        public int CompareTo(Fortune other)
+        {
+            // Performance critical, using culture insensitive comparison
+            return String.CompareOrdinal(Message, other.Message);
+        }
+    }
+}

+ 19 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/IDb.cs

@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace PlatformBenchmarks
+{
+    public interface IDb
+    {
+        Task<World> LoadSingleQueryRow();
+
+        Task<World[]> LoadMultipleQueriesRows(int count);
+
+        Task<World[]> LoadMultipleUpdatesRows(int count);
+
+        Task<List<Fortune>> LoadFortunesRows();
+    }
+}

+ 10 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/IRandom.cs

@@ -0,0 +1,10 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+namespace PlatformBenchmarks
+{
+    public interface IRandom
+    {
+        int Next(int minValue, int maxValue);
+    }
+}

+ 20 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/Random.cs

@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved. 
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
+
+using System;
+using System.Threading;
+
+namespace PlatformBenchmarks
+{
+    public class DefaultRandom : IRandom
+    {
+        private static int nextSeed = 0;
+        // Random isn't thread safe
+        private static readonly ThreadLocal<Random> _random = new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref nextSeed)));
+
+        public int Next(int minValue, int maxValue)
+        {
+            return _random.Value.Next(minValue, maxValue);
+        }
+    }
+}

+ 171 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/RawDb.cs

@@ -0,0 +1,171 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Options;
+
+namespace PlatformBenchmarks
+{
+    public class RawDb : IDb
+    {
+        private readonly IRandom _random;
+        private readonly DbProviderFactory _dbProviderFactory;
+        private readonly string _connectionString;
+
+        public RawDb(IRandom random, DbProviderFactory dbProviderFactory, AppSettings appSettings)
+        {
+            _random = random;
+            _dbProviderFactory = dbProviderFactory;
+            _connectionString = appSettings.ConnectionString;
+        }
+
+        public async Task<World> LoadSingleQueryRow()
+        {
+            using (var db = _dbProviderFactory.CreateConnection())
+            {
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+
+                using (var cmd = CreateReadCommand(db))
+                {
+                    return await ReadSingleRow(db, cmd);
+                }
+            }
+        }
+
+        async Task<World> ReadSingleRow(DbConnection connection, DbCommand cmd)
+        {
+            using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.SingleRow))
+            {
+                await rdr.ReadAsync();
+
+                return new World
+                {
+                    Id = rdr.GetInt32(0),
+                    RandomNumber = rdr.GetInt32(1)
+                };
+            }
+        }
+
+        DbCommand CreateReadCommand(DbConnection connection)
+        {
+            var cmd = connection.CreateCommand();
+            cmd.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id";
+            var id = cmd.CreateParameter();
+            id.ParameterName = "@Id";
+            id.DbType = DbType.Int32;
+            id.Value = _random.Next(1, 10001);
+            cmd.Parameters.Add(id);
+
+            return cmd;
+        }
+
+        public async Task<World[]> LoadMultipleQueriesRows(int count)
+        {
+            var result = new World[count];
+
+            using (var db = _dbProviderFactory.CreateConnection())
+            {
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+                using (var cmd = CreateReadCommand(db))
+                {
+                    for (int i = 0; i < count; i++)
+                    {
+                        result[i] = await ReadSingleRow(db, cmd);
+                        cmd.Parameters["@Id"].Value = _random.Next(1, 10001);
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        public async Task<World[]> LoadMultipleUpdatesRows(int count)
+        {
+            var results = new World[count];
+
+            var updateCommand = new StringBuilder(count);
+
+            using (var db = _dbProviderFactory.CreateConnection())
+            {
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+
+                using (var updateCmd = db.CreateCommand())
+                using (var queryCmd = CreateReadCommand(db))
+                {
+                    for (int i = 0; i < count; i++)
+                    {
+                        results[i] = await ReadSingleRow(db, queryCmd);
+                        queryCmd.Parameters["@Id"].Value = _random.Next(1, 10001);
+                    }
+
+                    // Postgres has problems with deadlocks when these aren't sorted
+                    Array.Sort<World>(results, (a, b) => a.Id.CompareTo(b.Id));
+
+                    for(int i = 0; i < count; i++)
+                    {
+                        var id = updateCmd.CreateParameter();
+                        id.ParameterName = BatchUpdateString.Strings[i].Id;
+                        id.DbType = DbType.Int32;
+                        updateCmd.Parameters.Add(id);
+
+                        var random = updateCmd.CreateParameter();
+                        random.ParameterName = BatchUpdateString.Strings[i].Random;
+                        random.DbType = DbType.Int32;
+                        updateCmd.Parameters.Add(random);
+
+                        var randomNumber = _random.Next(1, 10001);
+                        id.Value = results[i].Id;
+                        random.Value = randomNumber;
+                        results[i].RandomNumber = randomNumber;
+
+                        updateCommand.Append(BatchUpdateString.Strings[i].UpdateQuery);
+                    }
+
+                    updateCmd.CommandText = updateCommand.ToString();
+                    await updateCmd.ExecuteNonQueryAsync();
+                }
+            }
+
+            return results;
+        }
+
+        public async Task<List<Fortune>> LoadFortunesRows()
+        {
+            var result = new List<Fortune>();
+
+            using (var db = _dbProviderFactory.CreateConnection())
+            using (var cmd = db.CreateCommand())
+            {
+                cmd.CommandText = "SELECT id, message FROM fortune";
+
+                db.ConnectionString = _connectionString;
+                await db.OpenAsync();
+
+                using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection))
+                {
+                    while (await rdr.ReadAsync())
+                    {
+                        result.Add(new Fortune
+                        {
+                            Id = rdr.GetInt32(0),
+                            Message = rdr.GetString(1)
+                        });
+                    }
+                }
+            }
+
+            result.Add(new Fortune { Message = "Additional fortune added at request time." });
+            result.Sort();
+
+            return result;
+        }
+    }
+}

+ 17 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/World.cs

@@ -0,0 +1,17 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace PlatformBenchmarks
+{
+    [Table("world")]
+    public class World
+    {
+        [Column("id")]
+        public int Id { get; set; }
+
+        [Column("randomnumber")]
+        public int RandomNumber { get; set; }
+    }
+}

+ 6 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/PlatformBenchmarks.csproj

@@ -7,8 +7,14 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   
+  <ItemGroup>
+      <None Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
+  </ItemGroup>
+
   <ItemGroup>
     <PackageReference Include="Utf8Json" Version="1.3.7" />
+    <PackageReference Include="Npgsql" Version="4.0.0-rc1" />
+    <PackageReference Include="MySqlConnector" Version="0.40.3" />
     <PackageReference Include="Microsoft.AspNetCore.All" />
   </ItemGroup>
 </Project>

+ 20 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Program.cs

@@ -6,16 +6,23 @@ using System.Net;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 using Microsoft.Extensions.Configuration;
+using Npgsql;
+using MySql.Data.MySqlClient;
 
 namespace PlatformBenchmarks
 {
     public class Program
     {
+        public static string[] Args;
+
         public static void Main(string[] args)
         {
+            Args = args;
+
             Console.WriteLine(BenchmarkApplication.ApplicationName);
             Console.WriteLine(BenchmarkApplication.Paths.Plaintext);
             Console.WriteLine(BenchmarkApplication.Paths.Json);
+            Console.WriteLine(BenchmarkApplication.Paths.Fortunes);
             DateHeader.SyncDateTimer();
 
             BuildWebHost(args).Run();
@@ -24,10 +31,23 @@ namespace PlatformBenchmarks
         public static IWebHost BuildWebHost(string[] args)
         {
             var config = new ConfigurationBuilder()
+                .AddJsonFile("appsettings.json")
                 .AddEnvironmentVariables(prefix: "ASPNETCORE_")
                 .AddCommandLine(args)
                 .Build();
 
+            var appSettings = config.Get<AppSettings>();
+            Console.WriteLine($"Database: {appSettings.Database}");
+
+            if (appSettings.Database == DatabaseServer.PostgreSql)
+            {
+                BenchmarkApplication.Db = new RawDb(new DefaultRandom(), NpgsqlFactory.Instance, appSettings);
+            }
+            else if (appSettings.Database == DatabaseServer.MySql)
+            {
+                BenchmarkApplication.Db = new RawDb(new DefaultRandom(), MySqlClientFactory.Instance, appSettings);
+            }
+
             var host = new WebHostBuilder()
                 .UseBenchmarksConfiguration(config)
                 .UseKestrel((context, options) =>

+ 11 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BufferExtensions.cs → frameworks/CSharp/aspnetcore/PlatformBenchmarks/Utilities/BufferExtensions.cs

@@ -3,8 +3,10 @@
 
 using System;
 using System.Buffers;
+using System.Buffers.Text;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
+using System.Text;
 
 namespace PlatformBenchmarks
 {
@@ -20,6 +22,15 @@ namespace PlatformBenchmarks
         [ThreadStatic]
         private static byte[] _numericBytesScratch;
 
+        internal static void WriteUtf8String<T>(ref this BufferWriter<T> buffer, string text)
+             where T : struct, IBufferWriter<byte>
+        {
+            var byteCount = Encoding.UTF8.GetByteCount(text);
+            buffer.Ensure(byteCount);
+            byteCount = Encoding.UTF8.GetBytes(text.AsSpan(), buffer.Span);
+            buffer.Advance(byteCount);
+        }
+
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal static unsafe void WriteNumeric<T>(ref this BufferWriter<T> buffer, uint number)
              where T : struct, IBufferWriter<byte>

+ 1 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BufferWriter.cs → frameworks/CSharp/aspnetcore/PlatformBenchmarks/Utilities/BufferWriter.cs

@@ -21,6 +21,7 @@ namespace PlatformBenchmarks
         }
 
         public Span<byte> Span => _span;
+        public int Buffered => _buffered;
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void Commit()

+ 0 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/DateHeader.cs → frameworks/CSharp/aspnetcore/PlatformBenchmarks/Utilities/DateHeader.cs


+ 3 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/appsettings.json

@@ -0,0 +1,3 @@
+{
+  "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnetcore-Benchmarks;Trusted_Connection=True;MultipleActiveResultSets=true"
+}

+ 13 - 0
frameworks/CSharp/aspnetcore/aspcore-ado-my.dockerfile

@@ -0,0 +1,13 @@
+FROM microsoft/dotnet:2.1-sdk-stretch AS build
+WORKDIR /app
+COPY PlatformBenchmarks .
+RUN dotnet publish -c Release -o out
+COPY Benchmarks/appsettings.mysql.json ./out/appsettings.json
+
+FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime
+ENV ASPNETCORE_URLS http://+:8080
+ENV COMPlus_ReadyToRun 0
+WORKDIR /app
+COPY --from=build /app/out ./
+
+ENTRYPOINT ["dotnet", "PlatformBenchmarks.dll"]

+ 13 - 0
frameworks/CSharp/aspnetcore/aspcore-ado-pg.dockerfile

@@ -0,0 +1,13 @@
+FROM microsoft/dotnet:2.1-sdk-stretch AS build
+WORKDIR /app
+COPY PlatformBenchmarks .
+RUN dotnet publish -c Release -o out
+COPY Benchmarks/appsettings.postgresql.json ./out/appsettings.json
+
+FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime
+ENV ASPNETCORE_URLS http://+:8080
+ENV COMPlus_ReadyToRun 0
+WORKDIR /app
+COPY --from=build /app/out ./
+
+ENTRYPOINT ["dotnet", "PlatformBenchmarks.dll"]

+ 1 - 0
frameworks/CSharp/aspnetcore/aspcore.dockerfile

@@ -2,6 +2,7 @@ FROM microsoft/dotnet:2.1-sdk-stretch AS build
 WORKDIR /app
 COPY PlatformBenchmarks .
 RUN dotnet publish -c Release -o out
+COPY Benchmarks/appsettings.json ./out/appsettings.json
 
 FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime
 ENV ASPNETCORE_URLS http://+:8080

+ 36 - 0
frameworks/CSharp/aspnetcore/benchmark_config.json

@@ -20,6 +20,42 @@
       "notes": "",
       "versus": ""
     },
+    "ado-pg": {
+      "fortune_url": "/fortunes",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "Postgres",
+      "framework": "ASP.NET Core",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": ".NET",
+      "flavor": "CoreCLR",
+      "webserver": "Kestrel",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspcore",
+      "notes": "",
+      "versus": ""
+    },
+    "ado-my": {
+      "fortune_url": "/fortunes",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "ASP.NET Core",
+      "language": "C#",
+      "orm": "Raw",
+      "platform": ".NET",
+      "flavor": "CoreCLR",
+      "webserver": "Kestrel",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aspcore",
+      "notes": "",
+      "versus": ""
+    },
     "mw": {
       "plaintext_url": "/plaintext",
       "json_url": "/json",