From fa1d23d5313438dab0f3b2ab48ce03be82d9d1b8 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Thu, 22 Aug 2019 19:53:26 +0200 Subject: [PATCH] Performance improvements. --- ...quidex.Domain.Apps.Entities.MongoDb.csproj | 2 +- src/Squidex.Domain.Apps.Entities/Context.cs | 28 +++++++++++-------- .../Squidex.Domain.Users.MongoDb.csproj | 2 +- .../Squidex.Infrastructure.MongoDb.csproj | 4 +-- .../Queries/Json/ValueConverter.cs | 1 - .../Security/Permission.Part.cs | 25 +++++++++-------- .../Security/Permission.cs | 21 ++++++++++---- .../Squidex.Infrastructure.csproj | 2 +- src/Squidex.Web/ContextExtensions.cs | 2 +- src/Squidex.Web/ContextProvider.cs | 3 +- src/Squidex.Web/Pipeline/AppResolver.cs | 7 +++-- src/Squidex/Squidex.csproj | 4 +-- .../Apps/AppCommandMiddlewareTests.cs | 3 +- .../Contents/ContentCommandMiddlewareTests.cs | 3 +- .../Squidex.Domain.Apps.Entities.Tests.csproj | 2 +- .../ApiPermissionAttributeTests.cs | 2 +- .../EnrichWithAppIdCommandMiddlewareTests.cs | 3 +- tools/LoadTest/ClientQueryFixture.cs | 12 ++++---- tools/LoadTest/QueryBenchmarks.cs | 7 ++--- tools/Migrate_00/Migrate_00.csproj | 2 +- 20 files changed, 79 insertions(+), 56 deletions(-) diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj b/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj index d46629882..1b63c901a 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Squidex.Domain.Apps.Entities.MongoDb.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/Squidex.Domain.Apps.Entities/Context.cs b/src/Squidex.Domain.Apps.Entities/Context.cs index b0e393aa3..1bdf284da 100644 --- a/src/Squidex.Domain.Apps.Entities/Context.cs +++ b/src/Squidex.Domain.Apps.Entities/Context.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Security.Claims; using Squidex.Domain.Apps.Entities.Apps; +using Squidex.Infrastructure; using Squidex.Infrastructure.Security; using Squidex.Shared; using Squidex.Shared.Identity; @@ -21,27 +22,32 @@ namespace Squidex.Domain.Apps.Entities public IAppEntity App { get; set; } - public ClaimsPrincipal User { get; set; } + public ClaimsPrincipal User { get; } - public PermissionSet Permissions - { - get { return User?.Permissions() ?? PermissionSet.Empty; } - } + public PermissionSet Permissions { get; private set; } = PermissionSet.Empty; + + public bool IsFrontendClient { get; private set; } - public bool IsFrontendClient + public Context(ClaimsPrincipal user) { - get { return User != null && User.IsInClient(DefaultClients.Frontend); } + Guard.NotNull(user, nameof(user)); + + User = user; + + UpdatePermissions(); } - public Context() + public Context(ClaimsPrincipal user, IAppEntity app) + : this(user) { + App = app; } - public Context(ClaimsPrincipal user, IAppEntity app) + public void UpdatePermissions() { - User = user; + Permissions = User.Permissions(); - App = app; + IsFrontendClient = User.IsInClient(DefaultClients.Frontend); } public Context Clone() diff --git a/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj b/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj index 02de039cf..a5c3c9618 100644 --- a/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj +++ b/src/Squidex.Domain.Users.MongoDb/Squidex.Domain.Users.MongoDb.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj b/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj index e9fa41aa7..3ce977368 100644 --- a/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj +++ b/src/Squidex.Infrastructure.MongoDb/Squidex.Infrastructure.MongoDb.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/src/Squidex.Infrastructure/Queries/Json/ValueConverter.cs b/src/Squidex.Infrastructure/Queries/Json/ValueConverter.cs index 96b9b8c47..19f8812f7 100644 --- a/src/Squidex.Infrastructure/Queries/Json/ValueConverter.cs +++ b/src/Squidex.Infrastructure/Queries/Json/ValueConverter.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; -using System.Globalization; using NJsonSchema; using NodaTime; using NodaTime.Text; diff --git a/src/Squidex.Infrastructure/Security/Permission.Part.cs b/src/Squidex.Infrastructure/Security/Permission.Part.cs index 775adc775..a0b712e99 100644 --- a/src/Squidex.Infrastructure/Security/Permission.Part.cs +++ b/src/Squidex.Infrastructure/Security/Permission.Part.cs @@ -6,7 +6,6 @@ // ========================================================================== using System; -using System.Collections.Generic; using System.Linq; namespace Squidex.Infrastructure.Security @@ -18,11 +17,11 @@ namespace Squidex.Infrastructure.Security private static readonly char[] AlternativeSeparators = { '|' }; private static readonly char[] MainSeparators = { '.' }; - public readonly HashSet Alternatives; + public readonly string[] Alternatives; public readonly bool Exclusion; - public Part(HashSet alternatives, bool exclusion) + public Part(string[] alternatives, bool exclusion) { Alternatives = alternatives; @@ -31,10 +30,16 @@ namespace Squidex.Infrastructure.Security public static Part[] ParsePath(string path) { - return path - .Split(MainSeparators, StringSplitOptions.RemoveEmptyEntries) - .Select(Parse) - .ToArray(); + var parts = path.Split(MainSeparators, StringSplitOptions.RemoveEmptyEntries); + + var result = new Part[parts.Length]; + + for (var i = 0; i < result.Length; i++) + { + result[i] = Parse(parts[i]); + } + + return result; } public static Part Parse(string part) @@ -48,13 +53,11 @@ namespace Squidex.Infrastructure.Security part = part.Substring(1); } - HashSet alternatives = null; + string[] alternatives = null; if (part != Any) { - alternatives = - part.Split(AlternativeSeparators, StringSplitOptions.RemoveEmptyEntries) - .ToHashSet(StringComparer.OrdinalIgnoreCase); + alternatives = part.Split(AlternativeSeparators, StringSplitOptions.RemoveEmptyEntries); } return new Part(alternatives, isExclusion); diff --git a/src/Squidex.Infrastructure/Security/Permission.cs b/src/Squidex.Infrastructure/Security/Permission.cs index c81234028..ee644dc9c 100644 --- a/src/Squidex.Infrastructure/Security/Permission.cs +++ b/src/Squidex.Infrastructure/Security/Permission.cs @@ -15,20 +15,31 @@ namespace Squidex.Infrastructure.Security public const string Exclude = "^"; private readonly string id; - private readonly Lazy idParts; + private Part[] path; public string Id { get { return id; } } + private Part[] Path + { + get + { + if (path == null) + { + path = Part.ParsePath(id); + } + + return path; + } + } + public Permission(string id) { Guard.NotNullOrEmpty(id, nameof(id)); this.id = id; - - idParts = new Lazy(() => Part.ParsePath(id)); } public bool Allows(Permission permission) @@ -38,7 +49,7 @@ namespace Squidex.Infrastructure.Security return false; } - return Covers(idParts.Value, permission.idParts.Value); + return Covers(Path, permission.Path); } public bool Includes(Permission permission) @@ -48,7 +59,7 @@ namespace Squidex.Infrastructure.Security return false; } - return PartialCovers(idParts.Value, permission.idParts.Value); + return PartialCovers(Path, permission.Path); } private static bool Covers(Part[] given, Part[] requested) diff --git a/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj b/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj index c5b466af5..e10ded29b 100644 --- a/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj +++ b/src/Squidex.Infrastructure/Squidex.Infrastructure.csproj @@ -8,7 +8,7 @@ True - + diff --git a/src/Squidex.Web/ContextExtensions.cs b/src/Squidex.Web/ContextExtensions.cs index 20c17484a..32b778555 100644 --- a/src/Squidex.Web/ContextExtensions.cs +++ b/src/Squidex.Web/ContextExtensions.cs @@ -19,7 +19,7 @@ namespace Squidex.Web if (context == null) { - context = new Context { User = httpContext.User }; + context = new Context(httpContext.User); foreach (var header in httpContext.Request.Headers) { diff --git a/src/Squidex.Web/ContextProvider.cs b/src/Squidex.Web/ContextProvider.cs index ab6f79dbc..81142610f 100644 --- a/src/Squidex.Web/ContextProvider.cs +++ b/src/Squidex.Web/ContextProvider.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Security.Claims; using System.Threading; using Microsoft.AspNetCore.Http; using Squidex.Domain.Apps.Entities; @@ -25,7 +26,7 @@ namespace Squidex.Web { if (asyncLocal.Value == null) { - asyncLocal.Value = new Context(); + asyncLocal.Value = new Context(new ClaimsPrincipal(new ClaimsIdentity())); } return asyncLocal.Value; diff --git a/src/Squidex.Web/Pipeline/AppResolver.cs b/src/Squidex.Web/Pipeline/AppResolver.cs index 25331c6f7..160793753 100644 --- a/src/Squidex.Web/Pipeline/AppResolver.cs +++ b/src/Squidex.Web/Pipeline/AppResolver.cs @@ -66,11 +66,12 @@ namespace Squidex.Web.Pipeline } } - var permissionSet = user.Permissions(); + var appContext = context.HttpContext.Context(); - context.HttpContext.Context().App = app; + appContext.App = app; + appContext.UpdatePermissions(); - if (!permissionSet.Includes(Permissions.ForApp(Permissions.App, appName)) && !AllowAnonymous(context)) + if (!appContext.Permissions.Includes(Permissions.ForApp(Permissions.App, appName)) && !AllowAnonymous(context)) { context.Result = new NotFoundResult(); return; diff --git a/src/Squidex/Squidex.csproj b/src/Squidex/Squidex.csproj index ae2a21205..1bb0fe5bf 100644 --- a/src/Squidex/Squidex.csproj +++ b/src/Squidex/Squidex.csproj @@ -66,14 +66,14 @@ - + - + diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs index 772a23ccc..aeb4f1854 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppCommandMiddlewareTests.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; using Orleans; @@ -20,7 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { private readonly IContextProvider contextProvider = A.Fake(); private readonly Guid appId = Guid.NewGuid(); - private readonly Context requestContext = new Context(); + private readonly Context requestContext = new Context(new ClaimsPrincipal()); private readonly AppCommandMiddleware sut; public sealed class MyCommand : SquidexCommand diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs index ac4199efd..9d56a5b0b 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; using Orleans; @@ -21,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly IContentEnricher contentEnricher = A.Fake(); private readonly IContextProvider contextProvider = A.Fake(); private readonly Guid contentId = Guid.NewGuid(); - private readonly Context requestContext = new Context(); + private readonly Context requestContext = new Context(new ClaimsPrincipal()); private readonly ContentCommandMiddleware sut; public sealed class MyCommand : SquidexCommand diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj b/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj index d4cf837d7..0c5556db7 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj @@ -21,7 +21,7 @@ - + diff --git a/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs b/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs index a07f0cfb7..9b95902d9 100644 --- a/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs +++ b/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs @@ -38,7 +38,7 @@ namespace Squidex.Web actionExecutingContext = new ActionExecutingContext(actionContext, new List(), new Dictionary(), this); actionExecutingContext.HttpContext = httpContext; - actionExecutingContext.HttpContext.Context().User = new ClaimsPrincipal(user); + actionExecutingContext.HttpContext.User = new ClaimsPrincipal(user); next = () => { diff --git a/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs b/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs index 8ad1aa5de..56ed04125 100644 --- a/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs +++ b/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Entities; @@ -23,7 +24,7 @@ namespace Squidex.Web.CommandMiddlewares private readonly IContextProvider contextProvider = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); private readonly NamedId appId = NamedId.Of(Guid.NewGuid(), "my-app"); - private readonly Context appContext = new Context(); + private readonly Context appContext = new Context(new ClaimsPrincipal()); private readonly EnrichWithAppIdCommandMiddleware sut; public EnrichWithAppIdCommandMiddlewareTests() diff --git a/tools/LoadTest/ClientQueryFixture.cs b/tools/LoadTest/ClientQueryFixture.cs index af696f65b..5283391ec 100644 --- a/tools/LoadTest/ClientQueryFixture.cs +++ b/tools/LoadTest/ClientQueryFixture.cs @@ -36,13 +36,13 @@ namespace LoadTest { Name = TestClient.TestSchemaName, Fields = new List - { - new UpsertSchemaFieldDto { - Name = TestClient.TestSchemaName, - Properties = new NumberFieldPropertiesDto() - } - }, + new UpsertSchemaFieldDto + { + Name = TestClient.TestSchemaField, + Properties = new NumberFieldPropertiesDto() + } + }, IsPublished = true }); } diff --git a/tools/LoadTest/QueryBenchmarks.cs b/tools/LoadTest/QueryBenchmarks.cs index 9140cc608..66c2283ee 100644 --- a/tools/LoadTest/QueryBenchmarks.cs +++ b/tools/LoadTest/QueryBenchmarks.cs @@ -133,14 +133,13 @@ namespace LoadTest var avg = elapsedMs.Average(); + Assert.Equal(0, errors); + Assert.Equal(count, numUsers * numIterationsPerUser); + Assert.InRange(max, 0, expectedAvg * 10); Assert.InRange(min, 0, expectedAvg); Assert.InRange(avg, 0, expectedAvg); - - Assert.Equal(0, errors); - - Assert.Equal(count, numUsers * numIterationsPerUser); } } } diff --git a/tools/Migrate_00/Migrate_00.csproj b/tools/Migrate_00/Migrate_00.csproj index 93522d8d5..de3cd40b1 100644 --- a/tools/Migrate_00/Migrate_00.csproj +++ b/tools/Migrate_00/Migrate_00.csproj @@ -6,7 +6,7 @@ 7.3 - +