Skip to content

Commit

Permalink
Merge pull request #86 from dncsvr/feature/request-cache
Browse files Browse the repository at this point in the history
Feature / Request Cache
  • Loading branch information
dncsvr authored Dec 11, 2023
2 parents c3b8f61 + db869f6 commit d177ee9
Show file tree
Hide file tree
Showing 18 changed files with 183 additions and 23 deletions.
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
<PackageVersion Include="FluentNHibernate" Version="3.3.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.13" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
Expand Down
23 changes: 12 additions & 11 deletions docs/blueprints/service.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ Layers in this blueprint are;

Features with default options are;

| Features | Run | Test | Required |
| ------------------ | ----------- | --------------- | -------- |
| Business | | | Yes |
| Core | Dotnet | Mock | |
| Database | Sqlite | InMemory | Yes |
| Documentation | Default | | |
| Exception Handling | Default | | |
| Greeting | Hello World | | |
| Logging | Request | | |
| Mocking Overrider | | First Interface | |
| Orm | Default | Default | |
| Features | Run | Test | Required |
| ------------------ | ----------- | --------------- | -------- |
| Business | | | Yes |
| Caching | Scoped Memory | Scoped Memory | |
| Core | Dotnet | Mock | |
| Database | Sqlite | InMemory | Yes |
| Documentation | Default | | |
| Exception Handling | Default | | |
| Greeting | Hello World | | |
| Logging | Request | | |
| Mocking Overrider | | First Interface | |
| Orm | Default | Default | |
19 changes: 19 additions & 0 deletions docs/features/caching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Caching

Implementations of this feature provides predefined caching behaviour.

Add this feature using `AddCaching()` extension;

```csharp
app.Features.AddCaching(...);
```

## Scoped Memory

This feature implementation registers `Func<IMemoryCache>` factory with scoped
`MemoryCache` implementation to provide request in-memory caching.

```csharp
c => c.ScopedMemory()
```

Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,25 @@ public static class BusinessExtensions
{
public static void AddBusiness(this List<IFeature> source, Func<BusinessConfigurator, IFeature<BusinessConfigurator>> configure) => source.Add(configure(new()));

public static void AddTransientWithFactory<T>(this IServiceCollection source) where T : class
public static void AddTransientWithFactory<TService>(this IServiceCollection source) where TService : class =>
source.AddTransientWithFactory<TService, TService>();

public static void AddTransientWithFactory<TService, TImplementation>(this IServiceCollection source)
where TService : class
where TImplementation : class, TService
{
source.AddSingleton<Func<T>>(sp => () => sp.GetRequiredServiceUsingRequestServices<T>());
source.AddTransient<T>();
source.AddSingleton<Func<TService>>(sp => () => sp.GetRequiredServiceUsingRequestServices<TService>());
source.AddTransient<TService, TImplementation>();
}

public static void AddScopedWithFactory<T>(this IServiceCollection source) where T : class
public static void AddScopedWithFactory<TService>(this IServiceCollection source) where TService : class =>
source.AddScopedWithFactory<TService, TService>();

public static void AddScopedWithFactory<TService, TImplementation>(this IServiceCollection source)
where TService : class
where TImplementation : class, TService
{
source.AddSingleton<Func<T>>(sp => () => sp.GetRequiredServiceUsingRequestServices<T>());
source.AddScoped<T>();
source.AddSingleton<Func<TService>>(sp => () => sp.GetRequiredServiceUsingRequestServices<TService>());
source.AddScoped<TService, TImplementation>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Do.Caching;

public class CachingConfigurator { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Do.Architecture;
using Do.Caching;

namespace Do;

public static class CachingExtensions
{
public static void AddCaching(this List<IFeature> source, Func<CachingConfigurator, IFeature<CachingConfigurator>> configure) => source.Add(configure(new()));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Do.Caching;
using Do.Caching.ScopedMemory;

namespace Do;

public static class ScopedMemoryCachingExtensions
{
public static ScopedMemoryCachingFeature ScopedMemory(this CachingConfigurator _) => new();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Do.Architecture;
using Microsoft.Extensions.Caching.Memory;

namespace Do.Caching.ScopedMemory;

public class ScopedMemoryCachingFeature : IFeature<CachingConfigurator>
{
public void Configure(LayerConfigurator configurator)
{
configurator.ConfigureServiceCollection(services =>
{
services.AddScopedWithFactory<IMemoryCache, MemoryCache>();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using NHibernate.Dialect;
using System.Data;

namespace Do.Database.MySql;

public class CustomMySQL57Dialect : MySQL57Dialect
{
public CustomMySQL57Dialect()
{
RegisterColumnType(DbType.String, 1023, "VARCHAR($l)");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void Configure(LayerConfigurator configurator)
{
var mysql = MySQLConfiguration.Standard
.ConnectionString(_connectionString)
.Dialect<MySQL57Dialect>();
.Dialect<CustomMySQL57Dialect>();

// this should be in logging
if (_showSql) { mysql.ShowSql(); }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Do.Architecture;
using Do.Business;
using Do.Caching;
using Do.Core;
using Do.Database;
using Do.Documentation;
Expand All @@ -14,6 +15,7 @@ public static class ForgeExtensions
{
public static Application Service(this Forge source,
Func<BusinessConfigurator, IFeature<BusinessConfigurator>> business,
Func<CachingConfigurator, IFeature<CachingConfigurator>>? caching = default,
Func<CoreConfigurator, IFeature<CoreConfigurator>>? core = default,
Func<DatabaseConfigurator, IFeature<DatabaseConfigurator>>? database = default,
Func<DocumentationConfigurator, IFeature<DocumentationConfigurator>>? documentation = default,
Expand All @@ -24,6 +26,7 @@ public static Application Service(this Forge source,
Action<ApplicationDescriptor>? configure = default
)
{
caching ??= c => c.ScopedMemory();
core ??= c => c.Dotnet();
database ??= c => c.Sqlite();
documentation ??= c => c.Default();
Expand All @@ -43,6 +46,7 @@ public static Application Service(this Forge source,
app.Layers.AddRestApi();

app.Features.AddBusiness(business);
app.Features.AddCaching(caching);
app.Features.AddCore(core);
app.Features.AddDatabase(database);
app.Features.AddDocumentation(documentation);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Do.Architecture;
using Do.Business;
using Do.Caching;
using Do.Core;
using Do.Database;
using Do.ExceptionHandling;
Expand All @@ -22,6 +23,7 @@ public abstract class ServiceSpec : Spec

protected static ApplicationContext Init(
Func<BusinessConfigurator, IFeature<BusinessConfigurator>> business,
Func<CachingConfigurator, IFeature<CachingConfigurator>>? caching = default,
Func<CoreConfigurator, IFeature<CoreConfigurator>>? core = default,
Func<DatabaseConfigurator, IFeature<DatabaseConfigurator>>? database = default,
Func<ExceptionHandlingConfigurator, IFeature<ExceptionHandlingConfigurator>>? exceptionHandling = default,
Expand All @@ -30,6 +32,7 @@ protected static ApplicationContext Init(
Action<ApplicationDescriptor>? configure = default
)
{
caching ??= c => c.ScopedMemory();
core ??= c => c.Mock();
database ??= c => c.InMemory();
exceptionHandling ??= c => c.Default();
Expand All @@ -46,6 +49,7 @@ protected static ApplicationContext Init(
app.Layers.AddTesting();

app.Features.AddBusiness(business);
app.Features.AddCaching(caching);
app.Features.AddCore(core);
app.Features.AddDatabase(database);
app.Features.AddExceptionHandling(exceptionHandling);
Expand Down Expand Up @@ -84,6 +88,7 @@ public override void TearDown()
Session.Clear();

GiveMe.The<IMockOverrider>().Reset();
GiveMe.AMemoryCache(clear: true);
}

protected virtual string? GetDefaultSettingsValue(string key) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Do.Core;
using Do.MockOverrider;
using Do.Testing;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Moq;
Expand Down Expand Up @@ -52,6 +53,34 @@ public static Guid AGuid(this Stubber _,

#endregion

#region Integer

public static int AnInteger(this Stubber _) => 42;

#endregion

#region MemoryCache

public static IMemoryCache AMemoryCache(this Stubber giveMe,
bool clear = false
)
{
var getMemoryCache = giveMe.The<Func<IMemoryCache>>();
var memoryCache = getMemoryCache();

if (clear)
{
(memoryCache as MemoryCache)?.Clear();
}

return memoryCache;
}

public static void ShouldHaveCount(this IMemoryCache memoryCache, int count) =>
((MemoryCache)memoryCache).Count.ShouldBe(count);

#endregion

#region MockOverrider

public static T The<T>(this Stubber _, params object?[] mockOverrides) where T : notnull =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public void Configure(LayerConfigurator configurator)
{
configurator.ConfigureAutoPersistenceModel(model =>
{
model.Override<Entity>(x => x.Map(e => e.String).Length(200));
model.Override<Entity>(x => x.Map(e => e.String).Length(500));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ public EntityController(IServiceProvider serviceProvider) =>
_serviceProvider = serviceProvider;

public record ByRequest(
Guid guid = default,
Guid? guid = default,
string @string = default,
string stringData = default,
int int32 = default,
int? int32 = default,
Uri uri = default,
Status status = default,
DateTime dateTime = default
Status? status = default,
DateTime? dateTime = default
);

[HttpGet]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Microsoft.Extensions.Caching.Memory;

namespace Do.Test.Caching;

public class UsingScopedMemory : TestServiceSpec
{
public override void TearDown()
{
base.TearDown();

GiveMe.AMemoryCache().ShouldHaveCount(0);
}

[Test]
public void Objects_can_be_cached_in__scoped_memory()
{
var cache = GiveMe.AMemoryCache();
var expected = cache.GetOrCreate<object>("key", _ => new());

var actual = cache.GetOrCreate<object>("key", _ => new());

actual.ShouldBeSameAs(expected);
cache.ShouldHaveCount(1);
}
}
17 changes: 17 additions & 0 deletions unreleased.md
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
# Unreleased

## Features

- Beta features are available in do-blueprints-service package;
- `Caching` feature is now added with `ScopedMemory` implementation

## Improvements

- Added `CustomMySQL57Dialect` for enabling `varchar` column type with _1023_
max capacity
- Added `TransientWithFactory<TService, TImplementation>` and
`ScopedWithFactory<TService, TImplementation>` extensions for registering
services with implementations
- Added new ServiceSpec extensions:
- `AnInteger` extension for `Stubber`
- `AMemoryCache` extension for `Stubber`
- `ShouldHaveCount` extension for `IMemoryCache`

0 comments on commit d177ee9

Please sign in to comment.