diff --git a/Directory.Build.props b/Directory.Build.props index 1cde62c..f30b483 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,23 +2,61 @@ Shayne van Asperen + true + latest + embedded + true + true + $(MSBuildProjectName.EndsWith('Tests')) + $(MSBuildProjectName.StartsWith('Sample')) + false + true + false + true + $(IsPackable) + $(IsPackable) + true + $(MSBuildThisFileDirectory)Magneto.snk MIT https://github.com/shaynevanasperen/Magneto + Magneto.png https://raw.githubusercontent.com/shaynevanasperen/Magneto/master/Magneto.png https://github.com/shaynevanasperen/Magneto.git Git - $(MSBuildThisFileDirectory)Magneto.snk - true - latest 0 $(MSBuildProjectName). + $(NoWarn);CA1034;CA1051;CA1307;CA1822;CA2007;IDE0051 - - - - + + + + + + + + + + + + + + + + + + + + + + + + 0 + $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(BUILD_NUMBER) + + + diff --git a/Magneto.sln b/Magneto.sln index c1e0499..a48fa68 100644 --- a/Magneto.sln +++ b/Magneto.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26430.15 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30611.23 MinimumVisualStudioVersion = 15.0.26124.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C529A908-6353-4998-AA30-4DB69B717BCD}" EndProject @@ -15,8 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{8ACE EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples", "samples\Samples\Samples.csproj", "{8570D686-AD15-4B2A-9EF5-E825A43662AB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Magneto.Microsoft", "src\Magneto.Microsoft\Magneto.Microsoft.csproj", "{EF67ACA9-144B-4E8E-AB97-8D958A6BB480}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Samples.Tests", "samples\Samples.Tests\Samples.Tests.csproj", "{ED0DE9A0-5C24-4C7E-A6E0-81A26FF024EC}" EndProject Global @@ -65,18 +63,6 @@ Global {8570D686-AD15-4B2A-9EF5-E825A43662AB}.Release|x64.Build.0 = Release|Any CPU {8570D686-AD15-4B2A-9EF5-E825A43662AB}.Release|x86.ActiveCfg = Release|Any CPU {8570D686-AD15-4B2A-9EF5-E825A43662AB}.Release|x86.Build.0 = Release|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Debug|x64.ActiveCfg = Debug|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Debug|x64.Build.0 = Debug|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Debug|x86.ActiveCfg = Debug|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Debug|x86.Build.0 = Debug|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Release|Any CPU.Build.0 = Release|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Release|x64.ActiveCfg = Release|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Release|x64.Build.0 = Release|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Release|x86.ActiveCfg = Release|Any CPU - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480}.Release|x86.Build.0 = Release|Any CPU {ED0DE9A0-5C24-4C7E-A6E0-81A26FF024EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ED0DE9A0-5C24-4C7E-A6E0-81A26FF024EC}.Debug|Any CPU.Build.0 = Debug|Any CPU {ED0DE9A0-5C24-4C7E-A6E0-81A26FF024EC}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -97,7 +83,9 @@ Global {BD3F8F6D-A51C-4249-ADD7-6C099C8B9E43} = {C529A908-6353-4998-AA30-4DB69B717BCD} {58423EFB-4531-4989-9336-1FA9F4C95D7F} = {3F1747A6-02DB-43F9-987E-18C26A3B8D46} {8570D686-AD15-4B2A-9EF5-E825A43662AB} = {8ACE88B4-2C33-4DFB-8364-64DAEE706077} - {EF67ACA9-144B-4E8E-AB97-8D958A6BB480} = {C529A908-6353-4998-AA30-4DB69B717BCD} {ED0DE9A0-5C24-4C7E-A6E0-81A26FF024EC} = {8ACE88B4-2C33-4DFB-8364-64DAEE706077} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FAEBD1F1-D24F-4137-8F90-F30E337457CC} + EndGlobalSection EndGlobal diff --git a/ScenarioFor.cs b/ScenarioFor.cs index 44085cf..5f27585 100644 --- a/ScenarioFor.cs +++ b/ScenarioFor.cs @@ -1,4 +1,5 @@ -using Specify; +using System; +using Specify; using Specify.Stories; using TestStack.BDDfy.Configuration; using TestStack.BDDfy.Xunit; @@ -34,9 +35,11 @@ public static class ScenarioExtensions { public static string GetTitle(this Specify.ScenarioFor scenario) where TSut : class where TStory : Story, new() { - var type = scenario.GetType(); + if (scenario == null) throw new ArgumentNullException(nameof(scenario)); + + var type = scenario.GetType(); var title = Configurator.Scanners - .Humanize(type.FullName.Replace(type.Namespace + ".", string.Empty)) + .Humanize(type.FullName?.Replace(type.Namespace + ".", string.Empty)) .ToTitleCase(); if (scenario.Number != 0) { diff --git a/samples/Samples.Tests/Properties/launchSettings.json b/samples/Samples.Tests/Properties/launchSettings.json deleted file mode 100644 index 474baaa..0000000 --- a/samples/Samples.Tests/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:63735/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Samples.Tests": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:63738/" - } - } -} diff --git a/samples/Samples.Tests/Samples.Tests.csproj b/samples/Samples.Tests/Samples.Tests.csproj index aeca572..4a39eef 100644 --- a/samples/Samples.Tests/Samples.Tests.csproj +++ b/samples/Samples.Tests/Samples.Tests.csproj @@ -1,25 +1,13 @@ - + netcoreapp3.1 - $(NoWarn);CA2007;CA1307 - - - - - - - - - - - diff --git a/samples/Samples/Controllers/PostsController.cs b/samples/Samples/Controllers/PostsController.cs index 6011fae..f3869c9 100644 --- a/samples/Samples/Controllers/PostsController.cs +++ b/samples/Samples/Controllers/PostsController.cs @@ -50,7 +50,7 @@ public async Task Post(int id, string body) public class AllPosts : AsyncQuery { - protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken = default) => + protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken) => context.GetAsync("/posts", cancellationToken); } @@ -61,7 +61,7 @@ public class PostById : AsyncCachedQuery new DistributedCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(30)); - protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken = default) => + protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken) => context.GetAsync($"/posts/{Id}", cancellationToken); public int Id { get; set; } @@ -74,7 +74,7 @@ public class CommentsByPostId : AsyncCachedQuery new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(30)); - protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken = default) => + protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken) => context.GetAsync($"/posts/{PostId}/comments", cancellationToken); public int PostId { get; set; } @@ -82,7 +82,7 @@ protected override Task Query(JsonPlaceHolderHttpClient context, Canc public class SavePost : AsyncCommand { - public override Task Execute(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken = default) => + public override Task Execute(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken) => context.PostAsync($"/posts/{Post.Id}", Post, cancellationToken); public Post Post { get; set; } diff --git a/samples/Samples/Controllers/UsersController.cs b/samples/Samples/Controllers/UsersController.cs index 24cc4d9..428caea 100644 --- a/samples/Samples/Controllers/UsersController.cs +++ b/samples/Samples/Controllers/UsersController.cs @@ -1,5 +1,6 @@ using System.IO; using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Magneto; @@ -8,7 +9,6 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Samples.Domain; using Samples.Models; @@ -51,7 +51,7 @@ public class AllUsers : AsyncCachedQuery User.AllUsersCacheEntryOptions(); - protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken = default) => + protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken) => User.AllUsersAsync(context, cancellationToken); } @@ -62,10 +62,10 @@ public class UserById : AsyncTransformedCachedQuery User.AllUsersCacheEntryOptions(); - protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken = default) => + protected override Task Query(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken) => User.AllUsersAsync(context, cancellationToken); - protected override Task TransformCachedResult(User[] cachedResult, CancellationToken cancellationToken = default) => + protected override Task TransformCachedResult(User[] cachedResult, CancellationToken cancellationToken) => Task.FromResult(cachedResult.SingleOrDefault(x => x.Id == Id)); public int Id { get; set; } @@ -85,11 +85,9 @@ protected override MemoryCacheEntryOptions CacheEntryOptions((IFileProvider, ILo protected override Album[] Query((IFileProvider, ILogger) context) { var (fileProvider, _) = context; - using (var streamReader = new StreamReader(fileProvider.GetFileInfo(Album.AllAlbumsFilename).CreateReadStream())) - { - var json = streamReader.ReadToEnd(); - return JsonConvert.DeserializeObject(json); - } + using var streamReader = new StreamReader(fileProvider.GetFileInfo(Album.AllAlbumsFilename).CreateReadStream()); + var json = streamReader.ReadToEnd(); + return JsonSerializer.Deserialize(json); } protected override Album[] TransformCachedResult(Album[] cachedResult) => cachedResult.Where(x => x.UserId == UserId).ToArray(); @@ -97,11 +95,11 @@ protected override Album[] Query((IFileProvider, ILogger) contex public int UserId { get; set; } } - public class SaveAlbum : SyncCommand<(IFileProvider, JsonSerializerSettings)> + public class SaveAlbum : SyncCommand<(IFileProvider, JsonSerializerOptions)> { - public override void Execute((IFileProvider, JsonSerializerSettings) context) + public override void Execute((IFileProvider, JsonSerializerOptions) context) { - var (fileProvider, jsonSerializerSettings) = context; + var (fileProvider, jsonSerializerOptions) = context; lock (fileProvider) { var fileInfo = fileProvider.GetFileInfo(Album.AllAlbumsFilename); @@ -110,9 +108,9 @@ public override void Execute((IFileProvider, JsonSerializerSettings) context) using (var streamReader = new StreamReader(fileInfo.CreateReadStream())) json = streamReader.ReadToEnd(); - var existingAlbums = JsonConvert.DeserializeObject(json); + var existingAlbums = JsonSerializer.Deserialize(json); Album.Id = existingAlbums.Max(x => x.Id) + 1; - json = JsonConvert.SerializeObject(existingAlbums.Concat(new[] { Album }), jsonSerializerSettings); + json = JsonSerializer.Serialize(existingAlbums.Concat(new[] { Album }), jsonSerializerOptions); File.WriteAllText(fileInfo.PhysicalPath, json); } diff --git a/samples/Samples/Domain/Entities.cs b/samples/Samples/Domain/Entities.cs index 7df8a39..c50c485 100644 --- a/samples/Samples/Domain/Entities.cs +++ b/samples/Samples/Domain/Entities.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; @@ -69,7 +69,7 @@ public class User public static DistributedCacheEntryOptions AllUsersCacheEntryOptions() => new DistributedCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(30)); - public static Task AllUsersAsync(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken = default) => + public static Task AllUsersAsync(JsonPlaceHolderHttpClient context, CancellationToken cancellationToken) => context.GetAsync("/users", cancellationToken); } } diff --git a/samples/Samples/Domain/JsonPlaceHolderHttpClient.cs b/samples/Samples/Domain/JsonPlaceHolderHttpClient.cs index e4fada6..1878364 100644 --- a/samples/Samples/Domain/JsonPlaceHolderHttpClient.cs +++ b/samples/Samples/Domain/JsonPlaceHolderHttpClient.cs @@ -24,7 +24,13 @@ public async Task GetAsync(string requestUri, CancellationToken cancellati return JsonConvert.DeserializeObject(content); } +#pragma warning disable CA1822 // Mark members as static +#pragma warning disable CA1801 // Review unused parameters +#pragma warning disable IDE0060 // Remove unused parameter public Task PostAsync(string requestUri, T data, CancellationToken cancellationToken = default) => +#pragma warning restore IDE0060 // Remove unused parameter +#pragma warning restore CA1801 // Review unused parameters +#pragma warning restore CA1822 // Mark members as static Task.FromResult(new HttpResponseMessage(HttpStatusCode.NoContent)); } } diff --git a/samples/Samples/Infrastructure/ApplicationInsightsDecorator.cs b/samples/Samples/Infrastructure/ApplicationInsightsDecorator.cs index 262a1f7..9d96127 100644 --- a/samples/Samples/Infrastructure/ApplicationInsightsDecorator.cs +++ b/samples/Samples/Infrastructure/ApplicationInsightsDecorator.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Threading.Tasks; using Magneto.Configuration; @@ -6,7 +6,9 @@ namespace Samples.Infrastructure { - public class ApplicationInsightsDecorator : IDecorator +#pragma warning disable CA1812 // Avoid uninstantiated internal classes + internal class ApplicationInsightsDecorator : IDecorator +#pragma warning restore CA1812 // Avoid uninstantiated internal classes { readonly TelemetryClient _telemetryClient; diff --git a/samples/Samples/Samples.csproj b/samples/Samples/Samples.csproj index 187a72c..37cd058 100644 --- a/samples/Samples/Samples.csproj +++ b/samples/Samples/Samples.csproj @@ -2,7 +2,7 @@ netcoreapp3.1 - $(NoWarn);CA2007;CA1819;CA1054;CA2234 + $(NoWarn);CA1054;CA1062;CA1819;CA2007;CA2234 @@ -10,13 +10,12 @@ - - - + + + - diff --git a/samples/Samples/Startup.cs b/samples/Samples/Startup.cs index 9970214..d8b42b0 100644 --- a/samples/Samples/Startup.cs +++ b/samples/Samples/Startup.cs @@ -1,8 +1,8 @@ using System; using System.IO; +using System.Text.Json; using Magneto; using Magneto.Configuration; -using Magneto.Microsoft; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; @@ -11,8 +11,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; using Polly; using Samples.Domain; using Samples.Infrastructure; @@ -40,29 +38,21 @@ void InitializeAlbums() public void ConfigureServices(IServiceCollection services) { + // Here we add ApplicationInsights, which is a dependency of our Magneto decorator. services.AddApplicationInsightsTelemetry(Configuration); - // Here we add the Microsoft memory cache and our associated cache store. + // Here we add the Microsoft memory cache, used by some of our Magneto cached queries. services.AddMemoryCache(); - services.AddSingleton, MemoryCacheStore>(); - // Here we add the Microsoft distributed cache and our associated cache store with it's associated serializer. Normally - // we'd only have one type of cache in an application, but this is a sample application so we've got both here as examples. + // Here we add the Microsoft distributed cache, used by some of our Magneto cached queries. + // Normally we'd only have one type of cache in an application, but this is a + // sample application so we've got both here as examples. services.AddDistributedMemoryCache(); - services.AddSingleton(); - services.AddSingleton, DistributedCacheStore>(); - - // Here we add a decorator object which performs exception logging and timing telemetry for all our Magneto operations. - services.AddSingleton(); // Here we add the three context objects with which our queries and commands are executed. The first two are actually // used together in a ValueTuple and are resolved as such by a special wrapper around IServiceProvider. services.AddSingleton(Environment.WebRootFileProvider); - services.AddSingleton(new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver(), - Formatting = Formatting.Indented - }); + services.AddSingleton(new JsonSerializerOptions(JsonSerializerDefaults.Web) { WriteIndented = true }); services.AddHttpClient() .AddHttpMessageHandler(() => new EnsureSuccessHandler()) .AddTransientHttpErrorPolicy(x => x.WaitAndRetryAsync(new[] @@ -71,18 +61,44 @@ public void ConfigureServices(IServiceCollection services) TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) })); - - // Here we add Magneto.IMagneto as the main entry point for consumers, because it can do everything. We could also add any of - // the interfaces which Magneto.IMagneto is comprised of, to enable exposing limited functionality to some consumers. - // Internally, Magneto.Magneto relies on Magneto.IMediary to do it's work, so we could also add that or any of the interfaces + + // Here we configure Magneto fluently. + services.AddMagneto() + .WithDecorator() + .WithCacheKeyCreator((prefix, varyBy) => $"{prefix}.{JsonSerializer.Serialize(varyBy)}") + .WithMemoryCacheStore() + .WithDistributedCacheStore(); + + // Or we could configure it manually. + //ConfigureMagnetoManually(services); + + services.AddControllersWithViews().SetCompatibilityVersion(CompatibilityVersion.Latest); + } + +#pragma warning disable IDE0051 // Remove unused private members + static void ConfigureMagnetoManually(IServiceCollection services) +#pragma warning restore IDE0051 // Remove unused private members + { + // Here we add IMagneto as the main entry point for consumers, because it can do everything. We could also add any of + // the interfaces which IMagneto is comprised of, to enable exposing limited functionality to some consumers. + // Internally, Conductor relies on IMediary to do its work, so we could also add that or any of the interfaces // it's comprised of in order to take control of passing the context when executing queries or commands. - services.AddTransient(); + services.AddTransient(); + + // Here we add a decorator object which performs exception logging and timing telemetry for all our Magneto operations. + services.AddSingleton(); + + // Here we add the our cache store associated with the Microsoft memory cache. + services.AddSingleton, MemoryCacheStore>(); + + // Here we add our cache store and serializer associated with the Microsoft distributed cache. Normally we'd only + // have one type of cache in an application, but this is a sample application so we've got both here as examples. + services.AddSingleton(); + services.AddSingleton, DistributedCacheStore>(); // Here we specify how cache keys are created. This is optional as there is already a default built-in method, // but consumers may want to use their own method instead. - CachedQuery.UseKeyCreator((prefix, varyBy) => $"{prefix}.{JsonConvert.SerializeObject(varyBy)}"); - - services.AddControllersWithViews().SetCompatibilityVersion(CompatibilityVersion.Latest); + CachedQuery.UseKeyCreator((prefix, varyBy) => $"{prefix}.{JsonSerializer.Serialize(varyBy)}"); } public void Configure(IApplicationBuilder app) diff --git a/samples/Samples/Views/Users/Index.cshtml b/samples/Samples/Views/Users/Index.cshtml index cd5db9a..4b58f76 100644 --- a/samples/Samples/Views/Users/Index.cshtml +++ b/samples/Samples/Views/Users/Index.cshtml @@ -26,8 +26,8 @@ @user.Name @user.Email @user.Phone - @user.Address - @user.Company + @user.Address.Suite @user.Address.Street @user.Address.City @user.Address.Zipcode @user.Address.Geo + @user.Company.Name @user.Company.Bs @user.Company.CatchPhrase @user.Website } diff --git a/samples/Samples/Views/Users/User.cshtml b/samples/Samples/Views/Users/User.cshtml index 34810c9..55ff3c8 100644 --- a/samples/Samples/Views/Users/User.cshtml +++ b/samples/Samples/Views/Users/User.cshtml @@ -1,4 +1,4 @@ -@model UserViewModel +@model UserViewModel @{ ViewData["Title"] = $"User {Model.User.Id}"; @@ -27,13 +27,13 @@
Address
-
@Model.User.Address
+
@Model.User.Address.Suite @Model.User.Address.Street @Model.User.Address.City @Model.User.Address.Zipcode @Model.User.Address.Geo
Company
-
@Model.User.Company
+
@Model.User.Company.Name @Model.User.Company.Bs @Model.User.Company.CatchPhrase
@@ -51,4 +51,4 @@
-
\ No newline at end of file + diff --git a/src/Magneto.Microsoft/JsonConvertStringSerializer.cs b/src/Magneto.Microsoft/JsonConvertStringSerializer.cs deleted file mode 100644 index 3fdb453..0000000 --- a/src/Magneto.Microsoft/JsonConvertStringSerializer.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Newtonsoft.Json; - -namespace Magneto.Microsoft -{ - /// - /// An implementation of backed by . - /// - public class JsonConvertStringSerializer : IStringSerializer - { - readonly JsonSerializerSettings _settings; - - /// - /// Creates a new instance of . - /// - /// Optional settings to use when serializing/deserializing objects. - public JsonConvertStringSerializer(JsonSerializerSettings settings = null) => _settings = settings; - - /// - public string Serialize(object value) => JsonConvert.SerializeObject(value, _settings); - - /// - public T Deserialize(string value) => JsonConvert.DeserializeObject(value, _settings); - } -} diff --git a/src/Magneto.Microsoft/Magneto.Microsoft.csproj b/src/Magneto.Microsoft/Magneto.Microsoft.csproj deleted file mode 100644 index 83f55e3..0000000 --- a/src/Magneto.Microsoft/Magneto.Microsoft.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - netstandard2.0 - A library extending Magneto with implementations of ICacheStore backed by implementations from Microsoft.Extensions.Caching. - query command object queryobject commandobject mediator cqs cqrs operation read write cache caching async mock mocking - true - $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(APPVEYOR_BUILD_NUMBER) - embedded - true - true - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Magneto/CachedQuery.cs b/src/Magneto/CachedQuery.cs index 4527d64..8fbabc7 100644 --- a/src/Magneto/CachedQuery.cs +++ b/src/Magneto/CachedQuery.cs @@ -68,7 +68,7 @@ public abstract class AsyncCachedQuery : Core.AsyncCachedQuery, IAsyncCachedQuery { /// - public virtual Task Execute(TContext context, IAsyncCacheStore cacheStore, CacheOption cacheOption, CancellationToken cancellationToken = default) => + public virtual Task Execute(TContext context, IAsyncCacheStore cacheStore, CacheOption cacheOption, CancellationToken cancellationToken) => GetCachedResult(context, cacheStore, cacheOption, cancellationToken); } @@ -91,12 +91,12 @@ public abstract class AsyncTransformedCachedQuery /// The intermediate result to be transformed. - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// The result of transforming the intermediate result. - protected abstract Task TransformCachedResult(TCachedResult cachedResult, CancellationToken cancellationToken = default); + protected abstract Task TransformCachedResult(TCachedResult cachedResult, CancellationToken cancellationToken); /// - public virtual async Task Execute(TContext context, IAsyncCacheStore cacheStore, CacheOption cacheOption, CancellationToken cancellationToken = default) + public virtual async Task Execute(TContext context, IAsyncCacheStore cacheStore, CacheOption cacheOption, CancellationToken cancellationToken) { var cachedResult = await GetCachedResult(context, cacheStore, cacheOption, cancellationToken).ConfigureAwait(false); return await TransformCachedResult(cachedResult, cancellationToken).ConfigureAwait(false); diff --git a/src/Magneto/Command.cs b/src/Magneto/Command.cs index e624491..1cdc6d5 100644 --- a/src/Magneto/Command.cs +++ b/src/Magneto/Command.cs @@ -1,4 +1,4 @@ -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Magneto.Core; @@ -35,7 +35,7 @@ public abstract class SyncCommand : Operation, ISyncCommand : Operation, IAsyncCommand { /// - public abstract Task Execute(TContext context, CancellationToken cancellationToken = default); + public abstract Task Execute(TContext context, CancellationToken cancellationToken); } /// @@ -47,6 +47,6 @@ public abstract class AsyncCommand : Operation, IAsyncCommand : Operation, IAsyncCommand { /// - public abstract Task Execute(TContext context, CancellationToken cancellationToken = default); + public abstract Task Execute(TContext context, CancellationToken cancellationToken); } } diff --git a/src/Magneto/Magneto.cs b/src/Magneto/Conductor.cs similarity index 95% rename from src/Magneto/Magneto.cs rename to src/Magneto/Conductor.cs index 9dca0b1..7128b6c 100644 --- a/src/Magneto/Magneto.cs +++ b/src/Magneto/Conductor.cs @@ -20,17 +20,17 @@ namespace Magneto /// class MyQuery : ISyncQuery<(DbContext, IFileProvider), string> { ... } /// /// - public class Magneto : IMagneto + public class Conductor : IMagneto { /// - /// Creates a new instance of . The contained is initialized from either the instance of + /// Creates a new instance of . The contained is initialized from either the instance of /// obtained from the given , or a new instance of if the given /// couldn't provide it. The contained wraps , /// adding the capability to resolve instances of . /// /// Used for obtaining instances of the context objects with which queries and commands are invoked. /// Thrown if the is null. - public Magneto(IServiceProvider serviceProvider) + public Conductor(IServiceProvider serviceProvider) { if (serviceProvider == null) throw new ArgumentNullException(nameof(serviceProvider)); diff --git a/src/Magneto/Configuration/CachedQuery.cs b/src/Magneto/Configuration/CachedQuery.cs index 855f944..1298e48 100644 --- a/src/Magneto/Configuration/CachedQuery.cs +++ b/src/Magneto/Configuration/CachedQuery.cs @@ -14,19 +14,15 @@ public static class CachedQuery /// /// The method to use for creating cache keys. /// Thrown if is null. - public static void UseKeyCreator(Func createKey) - { - if (createKey == null) throw new ArgumentNullException(nameof(createKey)); - - KeyConfig.CreateKey = createKey; - } + public static void UseKeyCreator(Func createKey) => + KeyConfig.CreateKey = createKey ?? throw new ArgumentNullException(nameof(createKey)); /// /// The default method of creating cache keys. Uses reflection to serialize the argument. /// /// The prefix to be used for the resultant key. /// The object to serialize into a string that will be appended to . - /// + /// The generated cache key. public static string DefaultKeyCreator(string prefix, object varyBy) => varyBy == null ? prefix : $"{prefix}_{string.Join("_", varyBy.Flatten())}"; diff --git a/src/Magneto.Microsoft/DistributedCacheStore.cs b/src/Magneto/Configuration/DistributedCacheStore.cs similarity index 70% rename from src/Magneto.Microsoft/DistributedCacheStore.cs rename to src/Magneto/Configuration/DistributedCacheStore.cs index a097629..f4f9cd3 100644 --- a/src/Magneto.Microsoft/DistributedCacheStore.cs +++ b/src/Magneto/Configuration/DistributedCacheStore.cs @@ -1,11 +1,10 @@ using System; using System.Threading; using System.Threading.Tasks; -using Magneto.Configuration; using Magneto.Core; using Microsoft.Extensions.Caching.Distributed; -namespace Magneto.Microsoft +namespace Magneto.Configuration { /// /// An implementation of backed by . @@ -26,8 +25,8 @@ public DistributedCacheStore(IDistributedCache distributedCache, IStringSerializ _stringSerializer = stringSerializer ?? throw new ArgumentNullException(nameof(stringSerializer)); } - /// - public CacheEntry Get(string key) + /// + public CacheEntry GetEntry(string key) { if (key == null) throw new ArgumentNullException(nameof(key)); @@ -46,8 +45,8 @@ public CacheEntry Get(string key) } } - /// - public async Task> GetAsync(string key, CancellationToken cancellationToken = default) + /// + public async Task> GetEntryAsync(string key, CancellationToken cancellationToken) { if (key == null) throw new ArgumentNullException(nameof(key)); @@ -66,8 +65,8 @@ public async Task> GetAsync(string key, CancellationToken cance } } - /// - public void Set(string key, CacheEntry item, DistributedCacheEntryOptions cacheEntryOptions) + /// + public void SetEntry(string key, CacheEntry item, DistributedCacheEntryOptions cacheEntryOptions) { if (key == null) throw new ArgumentNullException(nameof(key)); if (item == null) throw new ArgumentNullException(nameof(item)); @@ -77,8 +76,8 @@ public void Set(string key, CacheEntry item, DistributedCacheEntryOptions _distributedCache.SetString(key, value, cacheEntryOptions); } - /// - public Task SetAsync(string key, CacheEntry item, DistributedCacheEntryOptions cacheEntryOptions, CancellationToken cancellationToken = default) + /// + public Task SetEntryAsync(string key, CacheEntry item, DistributedCacheEntryOptions cacheEntryOptions, CancellationToken cancellationToken) { if (key == null) throw new ArgumentNullException(nameof(key)); if (item == null) throw new ArgumentNullException(nameof(item)); @@ -88,16 +87,16 @@ public Task SetAsync(string key, CacheEntry item, DistributedCacheEntryOpt return _distributedCache.SetStringAsync(key, value, cacheEntryOptions, cancellationToken); } - /// - public void Remove(string key) + /// + public void RemoveEntry(string key) { if (key == null) throw new ArgumentNullException(nameof(key)); _distributedCache.Remove(key); } - /// - public Task RemoveAsync(string key, CancellationToken cancellationToken = default) + /// + public Task RemoveEntryAsync(string key, CancellationToken cancellationToken) { if (key == null) throw new ArgumentNullException(nameof(key)); diff --git a/src/Magneto/Configuration/ICacheStore.cs b/src/Magneto/Configuration/ICacheStore.cs index ab318d9..e00fc93 100644 --- a/src/Magneto/Configuration/ICacheStore.cs +++ b/src/Magneto/Configuration/ICacheStore.cs @@ -24,7 +24,7 @@ public interface ISyncCacheStore /// The type of the cached item. /// The key for the cached item. /// A if it exits in the cache, otherwise null. - CacheEntry Get(string key); + CacheEntry GetEntry(string key); /// /// Adds or updates an entry in the cache with the specified and . @@ -33,13 +33,13 @@ public interface ISyncCacheStore /// The key for the cached item. /// The value to be added/updated. /// Options pertaining to the cache entry (such as expiration policy). - void Set(string key, CacheEntry item, TCacheEntryOptions cacheEntryOptions); + void SetEntry(string key, CacheEntry item, TCacheEntryOptions cacheEntryOptions); /// /// Removes an entry with the specified from the cache. /// /// The key for the cached item. - void Remove(string key); + void RemoveEntry(string key); } /// @@ -54,9 +54,9 @@ public interface IAsyncCacheStore /// /// The type of the cached item. /// The key for the cached item. - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// A if it exits in the cache, otherwise null. - Task> GetAsync(string key, CancellationToken cancellationToken = default); + Task> GetEntryAsync(string key, CancellationToken cancellationToken); /// /// Adds or updates an entry in the cache with the specified and . @@ -65,16 +65,16 @@ public interface IAsyncCacheStore /// The key for the cached item. /// The value to be added/updated. /// Options pertaining to the cache entry (such as expiration policy). - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// A task representing the add/update operation. - Task SetAsync(string key, CacheEntry item, TCacheEntryOptions cacheEntryOptions, CancellationToken cancellationToken = default); + Task SetEntryAsync(string key, CacheEntry item, TCacheEntryOptions cacheEntryOptions, CancellationToken cancellationToken); /// /// Removes an entry with the specified from the cache. /// /// The key for the cached item. - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// A task representing the remove operation. - Task RemoveAsync(string key, CancellationToken cancellationToken = default); + Task RemoveEntryAsync(string key, CancellationToken cancellationToken); } } diff --git a/src/Magneto.Microsoft/IStringSerializer.cs b/src/Magneto/Configuration/IStringSerializer.cs similarity index 93% rename from src/Magneto.Microsoft/IStringSerializer.cs rename to src/Magneto/Configuration/IStringSerializer.cs index f6e69d3..a7de956 100644 --- a/src/Magneto.Microsoft/IStringSerializer.cs +++ b/src/Magneto/Configuration/IStringSerializer.cs @@ -1,4 +1,4 @@ -namespace Magneto.Microsoft +namespace Magneto.Configuration { /// /// An abstraction for serializing and deserializing objects to and from strings. diff --git a/src/Magneto/Configuration/MagnetoBuilder.cs b/src/Magneto/Configuration/MagnetoBuilder.cs new file mode 100644 index 0000000..6368283 --- /dev/null +++ b/src/Magneto/Configuration/MagnetoBuilder.cs @@ -0,0 +1,158 @@ +using System; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; + +namespace Magneto.Configuration +{ + /// + /// A class for fluently configuring Magneto decorator, cache key creator, and cache stores. + /// + public class MagnetoBuilder + { + readonly IServiceCollection _services; + + /// + /// Creates a new instance, wrapping the given . + /// + /// The to add services to. + public MagnetoBuilder(IServiceCollection services) => _services = services ?? throw new ArgumentNullException(nameof(services)); + + /// + /// Adds a singleton of the specified type. + /// + /// The type of decorator to add. + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithDecorator() where T : class, IDecorator + { + _services.AddSingleton(); + + return this; + } + + /// + /// Configures the delegate Magneto uses for creating cache keys. + /// + /// The method for creating cache keys. + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithCacheKeyCreator(Func createKey) + { + CachedQuery.UseKeyCreator(createKey); + + return this; + } + + /// + /// Adds a singleton of type . + /// + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithMemoryCacheStore() + { + return WithCacheStore(); + } + + + /// + /// Adds a singleton of type + /// . Also adds a singleton + /// of type , for use by the cache store. + /// + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithDistributedCacheStore() + { + return WithDistributedCacheStore(); + } + + /// + /// Adds a singleton of type + /// . Also adds a singleton + /// of the specified type, for use by the cache store. + /// + /// The type of string serializer to add. + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithDistributedCacheStore() where T : class, IStringSerializer + { + _services.AddSingleton(); + return WithCacheStore(); + } + + /// + /// Adds a singleton of type + /// . Also adds the given + /// as a singleton , for use by the cache store. + /// + /// The string serializer to use. + /// The type of . + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithDistributedCacheStore(T stringSerializer) where T : class, IStringSerializer + { + if (stringSerializer == null) throw new ArgumentNullException(nameof(stringSerializer)); + + _services.AddSingleton(stringSerializer); + return WithCacheStore(); + } + + /// + /// Adds a singleton of type + /// . Also adds a singleton + /// created by , for use by the cache store. + /// + /// The factory for creating the string serializer. + /// The type of string serializer created by . + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithDistributedCacheStore(Func stringSerializerFactory) where T : class, IStringSerializer + { + if (stringSerializerFactory == null) throw new ArgumentNullException(nameof(stringSerializerFactory)); + + _services.AddSingleton(stringSerializerFactory); + return WithCacheStore(); + } + + /// + /// Adds a singleton of type . + /// + /// The type of cache entry options. + /// The type of the cache store. + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithCacheStore() where TImplementation : class, ICacheStore + { + _services.AddSingleton, TImplementation>(); + + return this; + } + + /// + /// Adds the given as a singleton . + /// + /// The cache store to use. + /// The type of cache entry options. + /// The type of the cache store. + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithCacheStore(TImplementation cacheStore) + where TImplementation : class, ICacheStore + { + if (cacheStore == null) throw new ArgumentNullException(nameof(cacheStore)); + + _services.AddSingleton>(cacheStore); + + return this; + } + + /// + /// Adds a singleton created by . + /// + /// The factory for creating the cache store. + /// The type of cache entry options. + /// The type of the cache store created by . + /// A reference to this instance after the operation has completed. + public MagnetoBuilder WithCacheStore(Func cacheStoreFactory) + where TImplementation : class, ICacheStore + { + if (cacheStoreFactory == null) throw new ArgumentNullException(nameof(cacheStoreFactory)); + + _services.AddSingleton>(cacheStoreFactory); + + return this; + } + } +} diff --git a/src/Magneto.Microsoft/MemoryCacheStore.cs b/src/Magneto/Configuration/MemoryCacheStore.cs similarity index 62% rename from src/Magneto.Microsoft/MemoryCacheStore.cs rename to src/Magneto/Configuration/MemoryCacheStore.cs index 0a7a9a7..d5bf167 100644 --- a/src/Magneto.Microsoft/MemoryCacheStore.cs +++ b/src/Magneto/Configuration/MemoryCacheStore.cs @@ -1,11 +1,10 @@ using System; using System.Threading; using System.Threading.Tasks; -using Magneto.Configuration; using Magneto.Core; using Microsoft.Extensions.Caching.Memory; -namespace Magneto.Microsoft +namespace Magneto.Configuration { /// /// An implementation of backed by . @@ -20,24 +19,24 @@ public class MemoryCacheStore : ICacheStore /// The underlying cache implementation. public MemoryCacheStore(IMemoryCache memoryCache) => _memoryCache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache)); - /// - public CacheEntry Get(string key) + /// + public CacheEntry GetEntry(string key) { if (key == null) throw new ArgumentNullException(nameof(key)); return _memoryCache.Get>(key); } - /// - public Task> GetAsync(string key, CancellationToken cancellationToken = default) + /// + public Task> GetEntryAsync(string key, CancellationToken cancellationToken) { if (key == null) throw new ArgumentNullException(nameof(key)); return Task.FromResult(_memoryCache.Get>(key)); } - /// - public void Set(string key, CacheEntry item, MemoryCacheEntryOptions cacheEntryOptions) + /// + public void SetEntry(string key, CacheEntry item, MemoryCacheEntryOptions cacheEntryOptions) { if (key == null) throw new ArgumentNullException(nameof(key)); if (item == null) throw new ArgumentNullException(nameof(item)); @@ -46,8 +45,8 @@ public void Set(string key, CacheEntry item, MemoryCacheEntryOptions cache _memoryCache.Set(key, item, cacheEntryOptions); } - /// - public Task SetAsync(string key, CacheEntry item, MemoryCacheEntryOptions cacheEntryOptions, CancellationToken cancellationToken = default) + /// + public Task SetEntryAsync(string key, CacheEntry item, MemoryCacheEntryOptions cacheEntryOptions, CancellationToken cancellationToken) { if (key == null) throw new ArgumentNullException(nameof(key)); if (item == null) throw new ArgumentNullException(nameof(item)); @@ -57,16 +56,16 @@ public Task SetAsync(string key, CacheEntry item, MemoryCacheEntryOptions return Task.CompletedTask; } - /// - public void Remove(string key) + /// + public void RemoveEntry(string key) { if (key == null) throw new ArgumentNullException(nameof(key)); _memoryCache.Remove(key); } - /// - public Task RemoveAsync(string key, CancellationToken cancellationToken = default) + /// + public Task RemoveEntryAsync(string key, CancellationToken cancellationToken) { if (key == null) throw new ArgumentNullException(nameof(key)); diff --git a/src/Magneto/Configuration/ServiceCollectionExtensions.cs b/src/Magneto/Configuration/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..d418852 --- /dev/null +++ b/src/Magneto/Configuration/ServiceCollectionExtensions.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel; +using Magneto; +using Magneto.Configuration; + +// ReSharper disable once CheckNamespace +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// A extension class for configuring Magneto. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class ServiceCollectionExtensions + { + + /// + /// Adds Magneto. Returns a for use in + /// specifying a decorator, cache key creator, and cache stores. + /// + /// The to add services to. + /// An instance of for use in + /// specifying a decorator, cache key creator, and cache stores. + public static MagnetoBuilder AddMagneto(this IServiceCollection services) + { + if (services == null) throw new ArgumentNullException(nameof(services)); + + services.AddTransient(); + + return new MagnetoBuilder(services); + } + } +} diff --git a/src/Magneto/Configuration/SystemTextStringSerializer.cs b/src/Magneto/Configuration/SystemTextStringSerializer.cs new file mode 100644 index 0000000..f168d57 --- /dev/null +++ b/src/Magneto/Configuration/SystemTextStringSerializer.cs @@ -0,0 +1,25 @@ +using System.Text.Json; + +namespace Magneto.Configuration +{ + /// + /// An implementation of backed by . + /// + public class SystemTextStringSerializer : IStringSerializer + { + JsonSerializerOptions JsonSerializerOptions { get; } + + /// + /// Creates a new instance of . + /// + /// Optional settings to use when serializing/deserializing objects. + public SystemTextStringSerializer(JsonSerializerOptions options = null) => + JsonSerializerOptions = options ?? new JsonSerializerOptions(); + + /// + public string Serialize(object value) => JsonSerializer.Serialize(value, JsonSerializerOptions); + + /// + public T Deserialize(string value) => JsonSerializer.Deserialize(value, JsonSerializerOptions); + } +} diff --git a/src/Magneto/Core/CacheEntry.cs b/src/Magneto/Core/CacheEntry.cs index 4a7bd0d..852f6eb 100644 --- a/src/Magneto/Core/CacheEntry.cs +++ b/src/Magneto/Core/CacheEntry.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Text.Json.Serialization; namespace Magneto.Core { @@ -14,6 +15,7 @@ public sealed class CacheEntry : IEquatable> /// Creates a new wrapping the given . /// /// The value to wrap. + [JsonConstructor] public CacheEntry(T value) => Value = value; /// @@ -34,10 +36,7 @@ public override bool Equals(object obj) } /// - public override int GetHashCode() - { - return EqualityComparer.Default.GetHashCode(Value); - } + public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Value); /// public bool Equals(CacheEntry other) diff --git a/src/Magneto/Core/CachedQuery.cs b/src/Magneto/Core/CachedQuery.cs index cf33042..00c05ba 100644 --- a/src/Magneto/Core/CachedQuery.cs +++ b/src/Magneto/Core/CachedQuery.cs @@ -21,13 +21,13 @@ protected virtual TCachedResult GetCachedResult(TContext context, ISyncCacheStor if (cacheOption == CacheOption.Default) { - var cacheEntry = cacheStore.Get(State.CacheKey); + var cacheEntry = cacheStore.GetEntry(State.CacheKey); if (cacheEntry != null) return State.SetCachedResult(cacheEntry.Value); } var result = Query(context); - cacheStore.Set(State.CacheKey, result.ToCacheEntry(), State.CacheEntryOptions); + cacheStore.SetEntry(State.CacheKey, result.ToCacheEntry(), State.CacheEntryOptions); return State.SetCachedResult(result); } @@ -36,7 +36,7 @@ public virtual void EvictCachedResult(ISyncCacheStore cacheS { if (cacheStore == null) throw new ArgumentNullException(nameof(cacheStore)); - cacheStore.Remove(State.CacheKey); + cacheStore.RemoveEntry(State.CacheKey); } /// @@ -44,7 +44,7 @@ public virtual void UpdateCachedResult(ISyncCacheStore cache { if (cacheStore == null) throw new ArgumentNullException(nameof(cacheStore)); - cacheStore.Set(State.CacheKey, State.CachedResult.ToCacheEntry(), State.CacheEntryOptions); + cacheStore.SetEntry(State.CacheKey, State.CachedResult.ToCacheEntry(), State.CacheEntryOptions); } } @@ -52,10 +52,10 @@ public virtual void UpdateCachedResult(ISyncCacheStore cache public abstract class AsyncCachedQuery : CachedQuery, IAsyncCachedQuery { /// - protected abstract Task Query(TContext context, CancellationToken cancellationToken = default); + protected abstract Task Query(TContext context, CancellationToken cancellationToken); /// - protected virtual async Task GetCachedResult(TContext context, IAsyncCacheStore cacheStore, CacheOption cacheOption, CancellationToken cancellationToken = default) + protected virtual async Task GetCachedResult(TContext context, IAsyncCacheStore cacheStore, CacheOption cacheOption, CancellationToken cancellationToken) { if (context == null) throw new ArgumentNullException(nameof(context)); if (cacheStore == null) throw new ArgumentNullException(nameof(cacheStore)); @@ -64,30 +64,30 @@ protected virtual async Task GetCachedResult(TContext context, IA if (cacheOption == CacheOption.Default) { - var cacheEntry = await cacheStore.GetAsync(State.CacheKey, cancellationToken).ConfigureAwait(false); + var cacheEntry = await cacheStore.GetEntryAsync(State.CacheKey, cancellationToken).ConfigureAwait(false); if (cacheEntry != null) return State.SetCachedResult(cacheEntry.Value); } var result = await Query(context, cancellationToken).ConfigureAwait(false); - await cacheStore.SetAsync(State.CacheKey, result.ToCacheEntry(), State.CacheEntryOptions, cancellationToken).ConfigureAwait(false); + await cacheStore.SetEntryAsync(State.CacheKey, result.ToCacheEntry(), State.CacheEntryOptions, cancellationToken).ConfigureAwait(false); return State.SetCachedResult(result); } /// - public virtual Task EvictCachedResult(IAsyncCacheStore cacheStore, CancellationToken cancellationToken = default) + public virtual Task EvictCachedResult(IAsyncCacheStore cacheStore, CancellationToken cancellationToken) { if (cacheStore == null) throw new ArgumentNullException(nameof(cacheStore)); - return cacheStore.RemoveAsync(State.CacheKey, cancellationToken); + return cacheStore.RemoveEntryAsync(State.CacheKey, cancellationToken); } /// - public virtual Task UpdateCachedResult(IAsyncCacheStore cacheStore, CancellationToken cancellationToken = default) + public virtual Task UpdateCachedResult(IAsyncCacheStore cacheStore, CancellationToken cancellationToken) { if (cacheStore == null) throw new ArgumentNullException(nameof(cacheStore)); - return cacheStore.SetAsync(State.CacheKey, State.CachedResult.ToCacheEntry(), State.CacheEntryOptions, cancellationToken); + return cacheStore.SetEntryAsync(State.CacheKey, State.CachedResult.ToCacheEntry(), State.CacheEntryOptions, cancellationToken); } } diff --git a/src/Magneto/Core/ConcurrentDictionaryExtensions.cs b/src/Magneto/Core/ConcurrentDictionaryExtensions.cs index 8a22fee..dbceb5e 100644 --- a/src/Magneto/Core/ConcurrentDictionaryExtensions.cs +++ b/src/Magneto/Core/ConcurrentDictionaryExtensions.cs @@ -1,8 +1,10 @@ -using System; +using System; using System.Collections.Concurrent; +using System.ComponentModel; namespace Magneto.Core { + [EditorBrowsable(EditorBrowsableState.Never)] static class ConcurrentDictionaryExtensions { internal static T GetOrAdd(this ConcurrentDictionary concurrentDictionary, Func valueFactory) => diff --git a/src/Magneto/Core/KeyConfig.cs b/src/Magneto/Core/KeyConfig.cs index 8f6ca59..a59b960 100644 --- a/src/Magneto/Core/KeyConfig.cs +++ b/src/Magneto/Core/KeyConfig.cs @@ -25,6 +25,7 @@ public class KeyConfig : IKeyConfig /// This same instance, after being configured by . public KeyConfig Configure(Action configure) { + if (configure == null) throw new ArgumentNullException(nameof(configure)); configure(this); return this; } @@ -32,7 +33,7 @@ public KeyConfig Configure(Action configure) /// /// The key that is generated from a combination of the and . /// - public string Key => _key ?? (_key = CreateKey(Prefix, VaryBy)); + public string Key => _key ??= CreateKey(Prefix, VaryBy); /// public string Prefix diff --git a/src/Magneto/Core/NullCacheStore.cs b/src/Magneto/Core/NullCacheStore.cs index 06b923d..6d162b9 100644 --- a/src/Magneto/Core/NullCacheStore.cs +++ b/src/Magneto/Core/NullCacheStore.cs @@ -1,4 +1,4 @@ -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Magneto.Configuration; @@ -6,16 +6,16 @@ namespace Magneto.Core { class NullCacheStore : ICacheStore { - public CacheEntry Get(string key) => null; + public CacheEntry GetEntry(string key) => null; - public Task> GetAsync(string key, CancellationToken cancellationToken = default) => Task.FromResult>(null); + public Task> GetEntryAsync(string key, CancellationToken cancellationToken) => Task.FromResult>(null); - public void Set(string key, CacheEntry item, TCacheEntryOptions cacheEntryOptions) { } + public void SetEntry(string key, CacheEntry item, TCacheEntryOptions cacheEntryOptions) { } - public Task SetAsync(string key, CacheEntry item, TCacheEntryOptions cacheEntryOptions, CancellationToken cancellationToken = default) => Task.CompletedTask; + public Task SetEntryAsync(string key, CacheEntry item, TCacheEntryOptions cacheEntryOptions, CancellationToken cancellationToken) => Task.CompletedTask; - public void Remove(string key) { } + public void RemoveEntry(string key) { } - public Task RemoveAsync(string key, CancellationToken cancellationToken = default) => Task.CompletedTask; + public Task RemoveEntryAsync(string key, CancellationToken cancellationToken) => Task.CompletedTask; } } diff --git a/src/Magneto/Core/ServiceProviderExtensions.cs b/src/Magneto/Core/ServiceProviderExtensions.cs index 1b2f180..994fa4d 100644 --- a/src/Magneto/Core/ServiceProviderExtensions.cs +++ b/src/Magneto/Core/ServiceProviderExtensions.cs @@ -1,7 +1,9 @@ using System; +using System.ComponentModel; namespace Magneto.Core { + [EditorBrowsable(EditorBrowsableState.Never)] static class ServiceProviderExtensions { internal static T GetService(this IServiceProvider serviceProvider) => (T)serviceProvider.GetService(typeof(T)); diff --git a/src/Magneto/ICachedQuery.cs b/src/Magneto/ICachedQuery.cs index e0625f6..b1455ba 100644 --- a/src/Magneto/ICachedQuery.cs +++ b/src/Magneto/ICachedQuery.cs @@ -40,9 +40,9 @@ public interface IAsyncCachedQuery /// An object used for storing and retrieving cached values. /// An option designating whether or not the cache should be checked when executing the query. /// Use to skip reading from the cache and ensure a fresh result. - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// The result of query execution in the case of a cache miss or if is , otherwise the cached result. - Task Execute(TContext context, IAsyncCacheStore cacheStore, CacheOption cacheOption, CancellationToken cancellationToken = default); + Task Execute(TContext context, IAsyncCacheStore cacheStore, CacheOption cacheOption, CancellationToken cancellationToken); } /// @@ -74,16 +74,16 @@ public interface IAsyncCachedQuery /// Evicts any prior cached result from previous execution of the query. /// /// An object used for storing and retrieving cached values. - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// A task representing the eviction of the cached result. - Task EvictCachedResult(IAsyncCacheStore cacheStore, CancellationToken cancellationToken = default); + Task EvictCachedResult(IAsyncCacheStore cacheStore, CancellationToken cancellationToken); /// /// Updates the prior cached result from previous execution of the query. Useful when the underlying cache store is not in memory. /// /// An object used for storing and retrieving cached values. - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// A task representing the update of the cached result. - Task UpdateCachedResult(IAsyncCacheStore cacheStore, CancellationToken cancellationToken = default); + Task UpdateCachedResult(IAsyncCacheStore cacheStore, CancellationToken cancellationToken); } } diff --git a/src/Magneto/ICommand.cs b/src/Magneto/ICommand.cs index bada553..2b96e74 100644 --- a/src/Magneto/ICommand.cs +++ b/src/Magneto/ICommand.cs @@ -1,4 +1,4 @@ -using System.Threading; +using System.Threading; using System.Threading.Tasks; namespace Magneto @@ -41,9 +41,9 @@ public interface IAsyncCommand /// Executes the command. /// /// The context with which the command is executed. - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// A task representing the execution of the command. - Task Execute(TContext context, CancellationToken cancellationToken = default); + Task Execute(TContext context, CancellationToken cancellationToken); } /// @@ -57,8 +57,8 @@ public interface IAsyncCommand /// Executes the command and returns the result. /// /// The context with which the command is executed. - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// The result of command execution. - Task Execute(TContext context, CancellationToken cancellationToken = default); + Task Execute(TContext context, CancellationToken cancellationToken); } } diff --git a/src/Magneto/IKeyConfig.cs b/src/Magneto/IKeyConfig.cs index e7becac..879651d 100644 --- a/src/Magneto/IKeyConfig.cs +++ b/src/Magneto/IKeyConfig.cs @@ -1,3 +1,5 @@ +using System; + namespace Magneto { /// @@ -39,6 +41,7 @@ public static class KeyConfigExtensions /// public static IKeyConfig UsePrefix(this IKeyConfig keyConfig, string value) { + if (keyConfig == null) throw new ArgumentNullException(nameof(keyConfig)); keyConfig.Prefix = value; return keyConfig; } @@ -58,6 +61,7 @@ public static IKeyConfig UsePrefix(this IKeyConfig keyConfig, string value) /// public static IKeyConfig VaryBy(this IKeyConfig keyConfig, params object[] value) { + if (keyConfig == null) throw new ArgumentNullException(nameof(keyConfig)); keyConfig.VaryBy = value; return keyConfig; } diff --git a/src/Magneto/IQuery.cs b/src/Magneto/IQuery.cs index 2431be1..c57bc89 100644 --- a/src/Magneto/IQuery.cs +++ b/src/Magneto/IQuery.cs @@ -1,4 +1,4 @@ -using System.Threading; +using System.Threading; using System.Threading.Tasks; namespace Magneto @@ -29,8 +29,8 @@ public interface IAsyncQuery /// Executes the query and returns the result. /// /// The context with which the query is executed. - /// Optional. A to cancel the operation. + /// A to cancel the operation. /// The result of query execution. - Task Execute(TContext context, CancellationToken cancellationToken = default); + Task Execute(TContext context, CancellationToken cancellationToken); } } diff --git a/src/Magneto/Magneto.csproj b/src/Magneto/Magneto.csproj index 7286427..8433eb3 100644 --- a/src/Magneto/Magneto.csproj +++ b/src/Magneto/Magneto.csproj @@ -1,24 +1,19 @@ - + netstandard2.0;net461 A library for implementing the Command Pattern, providing of a set of base classes and an invoker class. Useful for abstracting data access and API calls as either queries (for read operations) or commands (for write operations). query command object queryobject commandobject mediator cqs cqrs operation read write cache caching async mock mocking - true - $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(APPVEYOR_BUILD_NUMBER) - embedded - true - true - $(NoWarn);CA1716;CA1724 - - - + + + + \ No newline at end of file diff --git a/src/Magneto/Mediary.cs b/src/Magneto/Mediary.cs index b6166bc..86dc3a0 100644 --- a/src/Magneto/Mediary.cs +++ b/src/Magneto/Mediary.cs @@ -71,7 +71,12 @@ protected virtual ICacheStore GetCacheStoreThe object from which to retrieve the full type name. /// The name of a method on the given object. /// A string made up of the full type name and the given method name, joined by a dot. - protected virtual string GetOperationName(object instance, string methodName) => $"{instance.GetType().FullName}.{methodName}"; + protected virtual string GetOperationName(object instance, string methodName) + { + if (instance == null) throw new ArgumentNullException(nameof(instance)); + + return $"{instance.GetType().FullName}.{methodName}"; + } /// public virtual TResult Query(ISyncQuery query, TContext context) diff --git a/src/Magneto/Query.cs b/src/Magneto/Query.cs index 00739c4..8b14de8 100644 --- a/src/Magneto/Query.cs +++ b/src/Magneto/Query.cs @@ -1,4 +1,4 @@ -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Magneto.Core; @@ -28,10 +28,10 @@ public abstract class SyncQuery : Operation, ISyncQuery : Operation, IAsyncQuery { /// - public Task Execute(TContext context, CancellationToken cancellationToken = default) => + public Task Execute(TContext context, CancellationToken cancellationToken) => Query(context, cancellationToken); /// - protected abstract Task Query(TContext context, CancellationToken cancellationToken = default); + protected abstract Task Query(TContext context, CancellationToken cancellationToken); } } diff --git a/test/Magneto.Tests/MagnetoTests/MagnetoTests.cs b/test/Magneto.Tests/ConductorTests/ConductorTests.cs similarity index 85% rename from test/Magneto.Tests/MagnetoTests/MagnetoTests.cs rename to test/Magneto.Tests/ConductorTests/ConductorTests.cs index 34a8ee1..887a21f 100644 --- a/test/Magneto.Tests/MagnetoTests/MagnetoTests.cs +++ b/test/Magneto.Tests/ConductorTests/ConductorTests.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using FluentAssertions; -namespace Magneto.Tests.MagnetoTests +namespace Magneto.Tests.ConductorTests { - public abstract class GettingContext : ScenarioFor + public abstract class GettingContext : ScenarioFor { readonly ServiceProvider _serviceProvider = new ServiceProvider(); @@ -17,7 +17,7 @@ public override void Setup() _serviceProvider.Register(new Foo()); _serviceProvider.Register(new Bar()); _serviceProvider.Register(new Baz()); - SUT = new MagnetoTest(_serviceProvider); + SUT = new ConductorTest(_serviceProvider); } public class ForUnavailableType : GettingContext @@ -72,7 +72,7 @@ protected void AssertContextIsResolvedCorrectly() } } - public class ServiceProvider : IServiceProvider + class ServiceProvider : IServiceProvider { private readonly Dictionary _services = new Dictionary(); @@ -83,9 +83,9 @@ public class ServiceProvider : IServiceProvider public object GetService(Type serviceType) => _services.GetValueOrDefault(serviceType); } - public class MagnetoTest : Magneto + public class ConductorTest : Conductor { - public MagnetoTest(IServiceProvider serviceProvider) : base(serviceProvider) { } + public ConductorTest(IServiceProvider serviceProvider) : base(serviceProvider) { } public TContext ResolveContext() => GetContext(); } diff --git a/test/Magneto.Tests/Core/AsyncCachedQueryTests/AsyncCachedQueryTests.cs b/test/Magneto.Tests/Core/AsyncCachedQueryTests/AsyncCachedQueryTests.cs index c3c5ed2..ad3cdbc 100644 --- a/test/Magneto.Tests/Core/AsyncCachedQueryTests/AsyncCachedQueryTests.cs +++ b/test/Magneto.Tests/Core/AsyncCachedQueryTests/AsyncCachedQueryTests.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using FluentAssertions; +using JetBrains.Annotations; using Magneto.Configuration; using Magneto.Core; using NSubstitute; @@ -32,20 +33,20 @@ public override void Setup() protected void ThenTheCacheKeyIsRequestedOnlyOnce() => The().Received(1).CacheKey(Arg.Any()); protected void AndThenTheCacheKeyContainsTheFullClassName() => SUT.PeekCacheKey().Should().Contain(SUT.GetType().FullName); protected void AndThenTheCacheKeyContainsTheVaryByValue() => SUT.PeekCacheKey().Should().Contain(nameof(IKeyConfig.VaryBy)); - protected void AndThenNothingIsRemovedFromTheCacheStore() => The>().DidNotReceive().Remove(Arg.Any()); + protected void AndThenNothingIsRemovedFromTheCacheStore() => The>().DidNotReceive().RemoveEntry(Arg.Any()); protected void AndThenTheCachedResultIsSet() => SUT.PeekCachedResult().Should().BeSameAs(Result); public abstract class CacheOptionIsDefault : Executing { protected void GivenTheCacheOptionIsDefault() => CacheOption = CacheOption.Default; - protected void AndThenTheCacheStoreIsQueried() => The>().Received().GetAsync(ExpectedCacheKey, CancellationToken); + protected void AndThenTheCacheStoreIsQueried() => The>().Received().GetEntryAsync(ExpectedCacheKey, CancellationToken); public class CacheMiss : CacheOptionIsDefault { void GivenTheQueryResultIsNotCached() { } void AndThenTheQueryIsExecuted() => The().Received(1).Query(QueryContext, CancellationToken); void AndThenTheCacheEntryOptionsIsRequested() => The().Received(1).CacheEntryOptions(QueryContext); - void AndThenTheResultIsSetInTheCacheStore() => The>().Received(1).SetAsync(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions, CancellationToken); + void AndThenTheResultIsSetInTheCacheStore() => The>().Received(1).SetEntryAsync(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions, CancellationToken); void AndThenTheResultIsTheQueryResult() => Result.Should().BeSameAs(QueryResult); } @@ -53,10 +54,10 @@ public class CacheHit : CacheOptionIsDefault { readonly QueryResult _cachedResult = new QueryResult(); - void GivenTheQueryResultIsCached() => The>().GetAsync($"{SUT.GetType().FullName}_{nameof(IKeyConfig.VaryBy)}", CancellationToken).Returns(x => _cachedResult.ToCacheEntry()); - void AndThenTheQueryIsNotExecuted() => The().DidNotReceive().Query(QueryContext); + void GivenTheQueryResultIsCached() => The>().GetEntryAsync($"{SUT.GetType().FullName}_{nameof(IKeyConfig.VaryBy)}", CancellationToken).Returns(x => _cachedResult.ToCacheEntry()); + void AndThenTheQueryIsNotExecuted() => The().DidNotReceive().Query(QueryContext, Arg.Any()); void AndThenTheCacheEntryOptionsIsNotRequested() => The().DidNotReceive().CacheEntryOptions(Arg.Any()); - void AndThenTheResultIsNotSetInTheCacheStore() => The>().DidNotReceive().SetAsync(Arg.Any(), Arg.Any>(), Arg.Any(), Arg.Any()); + void AndThenTheResultIsNotSetInTheCacheStore() => The>().DidNotReceive().SetEntryAsync(Arg.Any(), Arg.Any>(), Arg.Any(), Arg.Any()); void AndThenTheResultIsTheCachedResult() => Result.Should().BeSameAs(_cachedResult); } } @@ -64,10 +65,10 @@ public class CacheHit : CacheOptionIsDefault public class CacheOptionIsRefresh : Executing { void GivenTheCacheOptionIsRefresh() => CacheOption = CacheOption.Refresh; - void AndThenTheCacheStoreIsNotQueried() => The>().DidNotReceive().GetAsync(Arg.Any(), Arg.Any()); + void AndThenTheCacheStoreIsNotQueried() => The>().DidNotReceive().GetEntryAsync(Arg.Any(), Arg.Any()); void AndThenTheQueryIsExecuted() => The().Received(1).Query(QueryContext, CancellationToken); void AndThenTheCacheEntryOptionsIsRequested() => The().Received(1).CacheEntryOptions(QueryContext); - void AndThenTheResultIsSetInTheCacheStore() => The>().Received(1).SetAsync(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions, CancellationToken); + void AndThenTheResultIsSetInTheCacheStore() => The>().Received(1).SetEntryAsync(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions, CancellationToken); void AndThenTheResultIsTheQueryResult() => Result.Should().BeSameAs(QueryResult); } } @@ -90,7 +91,7 @@ public override void Setup() SUT = new ConcreteAsyncCachedQuery(The()); The().When(x => x.CacheKey(Arg.Any())).Do(x => x.ArgAt(0).VaryBy = Guid.NewGuid().ToString()); The().CacheEntryOptions(_queryContext).Returns(x => new CacheEntryOptions()); - The().Query(_queryContext).Returns(x => new QueryResult()); + The().Query(_queryContext, CancellationToken.None).Returns(x => new QueryResult()); } async Task WhenExecutingTheQuery() @@ -109,11 +110,11 @@ async Task AndWhenExecutingTheQueryAgain() _cachedResult2 = SUT.PeekCachedResult(); } - void ThenTheQueryIsExecutedTwice() => The().Received(2).Query(_queryContext); - void AndThenTwoResultsAreDifferent() => _result1.Should().NotBeSameAs(_result2); - void AndThenTwoStateCacheKeysAreDifferent() => _cacheKey1.Should().NotBeSameAs(_cacheKey2); - void AndThenTwoStateCacheEntryOptionsAreDifferent() => _cacheEntryOptions1.Should().NotBeSameAs(_cacheEntryOptions2); - void AndThenTwoStateCachedResultsAreDifferent() => _cachedResult1.Should().NotBeSameAs(_cachedResult2); + void ThenTheQueryIsExecutedTwice() => The().Received(2).Query(_queryContext, CancellationToken.None); + void AndThenTheTwoResultsAreDifferent() => _result1.Should().NotBeSameAs(_result2); + void AndThenTheTwoStateCacheKeysAreDifferent() => _cacheKey1.Should().NotBeSameAs(_cacheKey2); + void AndThenTheTwoStateCacheEntryOptionsAreDifferent() => _cacheEntryOptions1.Should().NotBeSameAs(_cacheEntryOptions2); + void AndThenTheTwoStateCachedResultsAreDifferent() => _cachedResult1.Should().NotBeSameAs(_cachedResult2); } public class EvictingCachedResult : ScenarioFor> @@ -123,7 +124,7 @@ public class EvictingCachedResult : ScenarioFor SUT = new ConcreteAsyncCachedQuery(The()); void WhenEvictingCachedResult() => SUT.EvictCachedResult(The>(), _cancellationToken); - void ThenItDelegatesToTheCacheStore() => The>().Received(1).RemoveAsync(SUT.PeekCacheKey(), _cancellationToken); + void ThenItDelegatesToTheCacheStore() => The>().Received(1).RemoveEntryAsync(SUT.PeekCacheKey(), _cancellationToken); void AndThenTheCacheKeyIsRequestedOnlyOnce() => The().Received(1).CacheKey(Arg.Any()); } @@ -164,7 +165,7 @@ public abstract class QueryWasExecuted : UpdatingCachedResult protected void WhenUpdatingCachedResult() => SUT.UpdateCachedResult(The>(), CancellationToken); protected void ThenTheCacheKeyIsRequestedOnlyOnce() => The().Received(1).CacheKey(Arg.Any()); protected void AndThenTheCacheEntryOptionsIsNotRequestedAgain() => The().Received(1).CacheEntryOptions(QueryContext); - protected void AndThenItDelegatesToTheCacheStore() => The>().Received(ExpectedCacheStoreSetCount).SetAsync(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions, CancellationToken); + protected void AndThenItDelegatesToTheCacheStore() => The>().Received(ExpectedCacheStoreSetCount).SetEntryAsync(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions, CancellationToken); public class CacheMiss : QueryWasExecuted { @@ -179,7 +180,7 @@ public class CacheHit : QueryWasExecuted { void GivenTheQueryResultIsCached() { - The>().GetAsync(ExpectedCacheKey, CancellationToken).Returns(QueryResult.ToCacheEntry()); + The>().GetEntryAsync(ExpectedCacheKey, CancellationToken).Returns(QueryResult.ToCacheEntry()); ExpectedCacheStoreSetCount = 1; } } @@ -190,7 +191,7 @@ public interface IAsyncCachedQueryStub { void CacheKey(IKeyConfig keyConfig); CacheEntryOptions CacheEntryOptions(QueryContext context); - Task Query(QueryContext context, CancellationToken cancellationToken = default); + Task Query(QueryContext context, CancellationToken cancellationToken); } public class ConcreteAsyncCachedQuery : AsyncCachedQuery @@ -203,6 +204,6 @@ public class ConcreteAsyncCachedQuery : AsyncCachedQuery _asyncCachedQueryStub.CacheEntryOptions(context); - protected override Task Query(QueryContext context, CancellationToken cancellationToken = default) => _asyncCachedQueryStub.Query(context, cancellationToken); + protected override Task Query(QueryContext context, CancellationToken cancellationToken) => _asyncCachedQueryStub.Query(context, cancellationToken); } } diff --git a/test/Magneto.Tests/Core/CacheEntryTests/CacheEntryTests.cs b/test/Magneto.Tests/Core/CacheEntryTests/CacheEntryTests.cs index 5e27a22..8674bda 100644 --- a/test/Magneto.Tests/Core/CacheEntryTests/CacheEntryTests.cs +++ b/test/Magneto.Tests/Core/CacheEntryTests/CacheEntryTests.cs @@ -5,7 +5,9 @@ namespace Magneto.Tests.Core.CacheEntryTests { public abstract class CheckingEquality : ScenarioFor> { +#pragma warning disable CA1720 // Identifier contains type name protected object Object; +#pragma warning restore CA1720 // Identifier contains type name bool _objectsAreEqual; bool _cacheEntriesAreEqual; diff --git a/test/Magneto.Tests/Core/CachedQueryInspectionExtensions.cs b/test/Magneto.Tests/Core/CachedQueryInspectionExtensions.cs index 8d546ef..8061952 100644 --- a/test/Magneto.Tests/Core/CachedQueryInspectionExtensions.cs +++ b/test/Magneto.Tests/Core/CachedQueryInspectionExtensions.cs @@ -1,31 +1,37 @@ +using System.ComponentModel; +using System.Diagnostics; using System.Reflection; using Magneto.Core; namespace Magneto.Tests.Core { - public static class CachedQueryInspectionExtensions + [EditorBrowsable(EditorBrowsableState.Never)] + static class CachedQueryInspectionExtensions { public static string PeekCacheKey(this CachedQuery cachedQuery) { - return cachedQuery.getStateProperty("CacheKey"); + return cachedQuery.GetStateProperty("CacheKey"); } public static TCacheEntryOptions PeekCacheEntryOptions(this CachedQuery cachedQuery) { - return cachedQuery.getStateProperty("CacheEntryOptions"); + return cachedQuery.GetStateProperty("CacheEntryOptions"); } public static TCachedResult PeekCachedResult(this CachedQuery cachedQuery) { - return cachedQuery.getStateProperty("CachedResult"); + return cachedQuery.GetStateProperty("CachedResult"); } - static T getStateProperty(this object cachedQuery, string name) + static T GetStateProperty(this object cachedQuery, string name) { var stateProperty = cachedQuery.GetType().GetField("State", BindingFlags.Instance | BindingFlags.NonPublic); + Debug.Assert(stateProperty != null, nameof(stateProperty) + " != null"); var state = stateProperty.GetValue(cachedQuery); + Debug.Assert(state != null, nameof(state) + " != null"); var type = state.GetType(); var property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.NonPublic); + Debug.Assert(property != null, nameof(property) + " != null"); return (T)property.GetValue(state); } } diff --git a/test/Magneto.Tests/Core/OperationTests/OperationTests.cs b/test/Magneto.Tests/Core/OperationTests/OperationTests.cs index ce1560c..a2940bd 100644 --- a/test/Magneto.Tests/Core/OperationTests/OperationTests.cs +++ b/test/Magneto.Tests/Core/OperationTests/OperationTests.cs @@ -9,7 +9,9 @@ namespace Magneto.Tests.Core.OperationTests { public abstract class CheckingEquality : ScenarioFor { +#pragma warning disable CA1720 // Identifier contains type name protected object Object; +#pragma warning restore CA1720 // Identifier contains type name bool _objectsAreEqual; bool _operationsAreEqual; @@ -299,7 +301,7 @@ public class SyncQueryWithoutProperties : SyncQuery public class AsyncQueryWithoutProperties : AsyncQuery { - protected override Task Query(object context, CancellationToken cancellationToken = default) => throw new NotImplementedException(); + protected override Task Query(object context, CancellationToken cancellationToken) => throw new NotImplementedException(); } public class SyncCachedQueryWithoutProperties : SyncCachedQuery @@ -311,7 +313,7 @@ public class SyncCachedQueryWithoutProperties : SyncCachedQuery { protected override object CacheEntryOptions(object context) => throw new NotImplementedException(); - protected override Task Query(object context, CancellationToken cancellationToken = default) => throw new NotImplementedException(); + protected override Task Query(object context, CancellationToken cancellationToken) => throw new NotImplementedException(); } public class SyncTransformedCachedQueryWithoutProperties : SyncTransformedCachedQuery @@ -324,8 +326,8 @@ public class SyncTransformedCachedQueryWithoutProperties : SyncTransformedCached public class AsyncTransformedCachedQueryWithoutProperties : AsyncTransformedCachedQuery { protected override object CacheEntryOptions(object context) => throw new NotImplementedException(); - protected override Task Query(object context, CancellationToken cancellationToken = default) => throw new NotImplementedException(); - protected override Task TransformCachedResult(object cachedResult, CancellationToken cancellationToken = default) => throw new NotImplementedException(); + protected override Task Query(object context, CancellationToken cancellationToken) => throw new NotImplementedException(); + protected override Task TransformCachedResult(object cachedResult, CancellationToken cancellationToken) => throw new NotImplementedException(); } public class SyncCommandWithoutProperties : SyncCommand @@ -338,7 +340,7 @@ public override void Execute(object context) public class AsyncCommandWithoutProperties : AsyncCommand { - public override Task Execute(object context, CancellationToken cancellationToken = default) => throw new NotImplementedException(); + public override Task Execute(object context, CancellationToken cancellationToken) => throw new NotImplementedException(); } public class SyncReturningCommandWithoutProperties : SyncCommand @@ -348,26 +350,30 @@ public class SyncReturningCommandWithoutProperties : SyncCommand public class AsyncReturningCommandWithoutProperties : AsyncCommand { - public override Task Execute(object context, CancellationToken cancellationToken = default) => throw new NotImplementedException(); + public override Task Execute(object context, CancellationToken cancellationToken) => throw new NotImplementedException(); } public class OperationWithProperties1 : Operation { +#pragma warning disable CA1720 // Identifier contains type name public int Integer { get; set; } public bool Boolean { get; set; } public string String { get; set; } public UriKind Enum { get; set; } public object Object { get; set; } +#pragma warning restore CA1720 // Identifier contains type name public IEnumerable Collection { get; set; } } public class OperationWithProperties2 : Operation { +#pragma warning disable CA1720 // Identifier contains type name public int Integer { get; set; } public bool Boolean { get; set; } public string String { get; set; } public UriKind Enum { get; set; } public object Object { get; set; } +#pragma warning restore CA1720 // Identifier contains type name public IEnumerable Collection { get; set; } } } diff --git a/test/Magneto.Tests/Core/SyncCachedQueryTests/SyncCachedQueryTests.cs b/test/Magneto.Tests/Core/SyncCachedQueryTests/SyncCachedQueryTests.cs index 107b9ac..fcd1ff7 100644 --- a/test/Magneto.Tests/Core/SyncCachedQueryTests/SyncCachedQueryTests.cs +++ b/test/Magneto.Tests/Core/SyncCachedQueryTests/SyncCachedQueryTests.cs @@ -29,20 +29,20 @@ public override void Setup() protected void ThenTheCacheKeyIsRequestedOnlyOnce() => The().Received(1).CacheKey(Arg.Any()); protected void AndThenTheCacheKeyContainsTheFullClassName() => SUT.PeekCacheKey().Should().Contain(SUT.GetType().FullName); protected void AndThenTheCacheKeyContainsTheVaryByValue() => SUT.PeekCacheKey().Should().Contain(nameof(IKeyConfig.VaryBy)); - protected void AndThenNothingIsRemovedFromTheCacheStore() => The>().DidNotReceive().Remove(Arg.Any()); + protected void AndThenNothingIsRemovedFromTheCacheStore() => The>().DidNotReceive().RemoveEntry(Arg.Any()); protected void AndThenTheCachedResultIsSet() => SUT.PeekCachedResult().Should().BeSameAs(Result); public abstract class CacheOptionIsDefault : Executing { protected void GivenTheCacheOptionIsDefault() => CacheOption = CacheOption.Default; - protected void AndThenTheCacheStoreIsQueried() => The>().Received().Get(ExpectedCacheKey); + protected void AndThenTheCacheStoreIsQueried() => The>().Received().GetEntry(ExpectedCacheKey); public class CacheMiss : CacheOptionIsDefault { void GivenTheQueryResultIsNotCached() { } void AndThenTheQueryIsExecuted() => The().Received(1).Query(QueryContext); void AndThenTheCacheEntryOptionsIsRequested() => The().Received(1).CacheEntryOptions(QueryContext); - void AndThenTheResultIsSetInTheCacheStore() => The>().Received(1).Set(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions); + void AndThenTheResultIsSetInTheCacheStore() => The>().Received(1).SetEntry(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions); void AndThenTheResultIsTheQueryResult() => Result.Should().BeSameAs(QueryResult); } @@ -50,7 +50,7 @@ public class CacheHit : CacheOptionIsDefault { readonly QueryResult _cachedResult = new QueryResult(); - void GivenTheQueryResultIsCached() => The>().Get(ExpectedCacheKey).Returns(_cachedResult.ToCacheEntry()); + void GivenTheQueryResultIsCached() => The>().GetEntry(ExpectedCacheKey).Returns(_cachedResult.ToCacheEntry()); void AndThenTheQueryIsNotExecuted() => The().DidNotReceive().Query(QueryContext); void AndThenTheCacheEntryOptionsIsNotRequested() => The().DidNotReceive().CacheEntryOptions(Arg.Any()); void AndThenTheResultIsTheCachedResult() => Result.Should().BeSameAs(_cachedResult); @@ -60,10 +60,10 @@ public class CacheHit : CacheOptionIsDefault public class CacheOptionIsRefresh : Executing { void GivenTheCacheOptionIsRefresh() => CacheOption = CacheOption.Refresh; - void AndThenTheCacheStoreIsNotQueried() => The>().DidNotReceive().Get(Arg.Any()); + void AndThenTheCacheStoreIsNotQueried() => The>().DidNotReceive().GetEntry(Arg.Any()); void AndThenTheQueryIsExecuted() => The().Received(1).Query(QueryContext); void AndThenTheCacheEntryOptionsIsRequested() => The().Received(1).CacheEntryOptions(QueryContext); - void AndThenTheResultIsSetInTheCacheStore() => The>().Received(1).Set(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions); + void AndThenTheResultIsSetInTheCacheStore() => The>().Received(1).SetEntry(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions); void AndThenTheResultIsTheQueryResult() => Result.Should().BeSameAs(QueryResult); } } @@ -106,10 +106,10 @@ void AndWhenExecutingTheQueryAgain() } void ThenTheQueryIsExecutedTwice() => The().Received(2).Query(_queryContext); - void AndThenTwoResultsAreDifferent() => _result1.Should().NotBeSameAs(_result2); - void AndThenTwoStateCacheKeysAreDifferent() => _cacheKey1.Should().NotBeSameAs(_cacheKey2); - void AndThenTwoStateCacheEntryOptionsAreDifferent() => _cacheEntryOptions1.Should().NotBeSameAs(_cacheEntryOptions2); - void AndThenTwoStateCachedResultsAreDifferent() => _cachedResult1.Should().NotBeSameAs(_cachedResult2); + void AndThenTheTwoResultsAreDifferent() => _result1.Should().NotBeSameAs(_result2); + void AndThenTheTwoStateCacheKeysAreDifferent() => _cacheKey1.Should().NotBeSameAs(_cacheKey2); + void AndThenTheTwoStateCacheEntryOptionsAreDifferent() => _cacheEntryOptions1.Should().NotBeSameAs(_cacheEntryOptions2); + void AndThenTheTwoStateCachedResultsAreDifferent() => _cachedResult1.Should().NotBeSameAs(_cachedResult2); } public class EvictingCachedResult : ScenarioFor> @@ -117,7 +117,7 @@ public class EvictingCachedResult : ScenarioFor SUT = new ConcreteSyncCachedQuery(The()); void WhenEvictingCachedResult() => SUT.EvictCachedResult(The>()); - void ThenItDelegatesToTheCacheStore() => The>().Received(1).Remove(SUT.PeekCacheKey()); + void ThenItDelegatesToTheCacheStore() => The>().Received(1).RemoveEntry(SUT.PeekCacheKey()); void AndThenTheCacheKeyIsRequestedOnlyOnce() => The().Received(1).CacheKey(Arg.Any()); } @@ -157,7 +157,7 @@ public abstract class QueryWasExecuted : UpdatingCachedResult protected void WhenUpdatingCachedResult() => SUT.UpdateCachedResult(The>()); protected void ThenTheCacheKeyIsRequestedOnlyOnce() => The().Received(1).CacheKey(Arg.Any()); protected void AndThenTheCacheEntryOptionsIsNotRequestedAgain() => The().Received(1).CacheEntryOptions(QueryContext); - protected void AndThenItDelegatesToTheCacheStore() => The>().Received(ExpectedCacheStoreSetCount).Set(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions); + protected void AndThenItDelegatesToTheCacheStore() => The>().Received(ExpectedCacheStoreSetCount).SetEntry(ExpectedCacheKey, QueryResult.ToCacheEntry(), CacheEntryOptions); public class CacheMiss : QueryWasExecuted { @@ -172,7 +172,7 @@ public class CacheHit : QueryWasExecuted { void GivenTheQueryResultIsCached() { - The>().Get(ExpectedCacheKey).Returns(QueryResult.ToCacheEntry()); + The>().GetEntry(ExpectedCacheKey).Returns(QueryResult.ToCacheEntry()); ExpectedCacheStoreSetCount = 1; } } diff --git a/test/Magneto.Tests/Magneto.Tests.csproj b/test/Magneto.Tests/Magneto.Tests.csproj index 1b13835..820d37b 100644 --- a/test/Magneto.Tests/Magneto.Tests.csproj +++ b/test/Magneto.Tests/Magneto.Tests.csproj @@ -2,7 +2,6 @@ netcoreapp3.1 - $(NoWarn);CA1051;CA1034;CA2007;CA1720;CA1307 @@ -13,18 +12,4 @@ - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers - - -