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.snkMIThttps://github.com/shaynevanasperen/Magneto
+ Magneto.pnghttps://raw.githubusercontent.com/shaynevanasperen/Magneto/master/Magneto.pnghttps://github.com/shaynevanasperen/Magneto.gitGit
- $(MSBuildThisFileDirectory)Magneto.snk
- true
- latest0$(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 @@