Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue / Refine Layers #182

Merged
merged 30 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f56e996
init issue/refine-layers
dncsvr Oct 7, 2024
08cff6f
add `Runtime` layer and extensions
dncsvr Oct 7, 2024
14d3131
rename `DependencyInjection` to `Runtime` in documentation
dncsvr Oct 7, 2024
18f3ad8
merge `Monitoring` layer and extensions into `Runtime`
dncsvr Oct 7, 2024
3fcccd4
merge `Configuration` layer and extensions into `Runtime`
dncsvr Oct 7, 2024
4d843c8
add configuring four phase layer test case to architecture providing …
dncsvr Oct 7, 2024
21572f9
expose fluent configuration to features
dncsvr Oct 8, 2024
929c438
move registering data access services to ondispose action
dncsvr Oct 8, 2024
9ed6281
fix export schema scoped session issue
dncsvr Oct 10, 2024
ec2eefd
add `GetServiceScope` helper
dncsvr Oct 10, 2024
cd545b3
update samples project
dncsvr Oct 10, 2024
4f827ba
update unreleased.md
dncsvr Oct 10, 2024
b8c57ea
review changes
dncsvr Oct 10, 2024
0732287
update layer document generic arguments count to four
dncsvr Oct 10, 2024
1b31b04
add update schema helper
dncsvr Oct 10, 2024
34f53c9
minor format edit
dncsvr Oct 10, 2024
e2565fe
move configuration extensions to `Runtime` folder
dncsvr Oct 14, 2024
b006e30
remove show sql from logging feature
dncsvr Oct 14, 2024
8f8aef2
review changes
dncsvr Oct 14, 2024
8cec6e2
remove show sql helper
dncsvr Oct 14, 2024
471e6eb
fix multiline formatting
dncsvr Oct 15, 2024
87bce91
edit `AddFromAssembly` order in `RuntimeExtensions`
dncsvr Oct 15, 2024
4e45db6
refactor accessing scoped services with service provider accessors
dncsvr Oct 15, 2024
8603db1
fix unused parameters error
dncsvr Oct 15, 2024
b7f5be6
use semicolon instead of empty curly braces in collection classes
dncsvr Oct 15, 2024
0fd7d26
rename `RequestServicesAccessor` to `RequestServicesServiceProviderAc…
dncsvr Oct 15, 2024
8e80baf
update docs and unreleased notes
dncsvr Oct 15, 2024
c3eae6b
fix not clearing logger providers issue
dncsvr Oct 15, 2024
f54a39a
revert logging builder collection configuration target
dncsvr Oct 16, 2024
4c348ea
minor edits
dncsvr Oct 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/architecture/layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ For a consistent developer experience, follow below conventions when
implementing a new layer;

1. Place all layer related classes under the same folder named after layer,
e.g., `DependencyInjection/`
e.g., `Runtime/`
1. Use `Layer` suffix in layer class name, e.g.,
`DependencyInjection/DependencyInjectionLayer.cs`
`Runtime/RuntimeLayer.cs`
1. Provide extension methods in `Baked` namespace, e.g.,
`DependencyInjection/DependencyInjectionExtensions.cs`;
1. `Add` extension to `List<ILayer>`, e.g., `AddDependencyInjection()`
`Runtime/RuntimeExtensions.cs`;
1. `Add` extension to `List<ILayer>`, e.g., `AddRuntime()`
1. `Get` extensions to `ApplicationContext`, e.g.,
`GetWebApplicationBuilder()`, `GetWebApplication()`
1. `Configure` extensions to `LayerConfigurator` per configuration
Expand Down
32 changes: 0 additions & 32 deletions docs/layers/configuration.md

This file was deleted.

29 changes: 27 additions & 2 deletions docs/layers/data-access.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ app.Layers.AddDataAccess();
## Configuration Targets

This layer provides `PersistenceConfiguration`, `AutomappingConfiguration`
`AutoPersistenceModel`, `InterceptorConfiguration` for configuring
_NHibernate_ behavior.
`AutoPersistenceModel`, `InterceptorConfiguration`, `FluentConfiguration`
for configuring _NHibernate_ behavior and `IDatabaseInitializationCollection`
for configuring database initialization actions.

### `PersistenceConfiguration`

Expand Down Expand Up @@ -60,3 +61,27 @@ configurator.ConfigureAutoPersistenceModel(autoPersistenceModel =>
...
});
```

### `FluentConfiguration`

This target is provided in `AddServices` phase. To configure it in a
feature;

```csharp
configurator.ConfigureFluentConfiguration(fluentConfiguration =>
{
...
});
```

### `IDatabaseInitializationCollection`

This target is provided in `PostBuild` phase. To configure it in a
feature;

```csharp
configurator.ConfigureDatabaseInitializationCollection(initializations =>
{
...
});
```
43 changes: 0 additions & 43 deletions docs/layers/dependency-injection.md

This file was deleted.

22 changes: 0 additions & 22 deletions docs/layers/monitoring.md

This file was deleted.

71 changes: 71 additions & 0 deletions docs/layers/runtime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Runtime

This layer serves as foundation and provides common libraries for an
application. Baked uses .NET's standard libraries for providing an environment
based configuration mechanism, dependency injection container for inversion of
control and logging mechanism for monitoring and diagnostic purposes.

```csharp
app.Layers.AddRuntime();
```

## Configuration Targets

`Runtime` layer provides `IConfigurationBuilder`, `ILoggingBuilder`,
`IServiceCollection` and `IServiceProvider` as configuration targets.

### `IConfigurationBuilder`

This target is provided in `BuildConfiguration` phase. To configure it in a
feature;

```csharp
configurator.ConfigureConfigurationBuilder(configuration =>
{
...
});
```

### `ILoggingBuilder`

This target is provided in `AddServices` phase. To configure it in a feature;

```csharp
configurator.ConfigureLoggingBuilder(logging =>
{
...
});
```

### `IServiceCollection`

This target is provided in `AddServices` phase. To configure it in a feature;

```csharp
configurator.ConfigureServiceCollection(services =>
{
...
});
```

### `IServiceProvider`

This target is provided in `PostBuild` phase. To configure it in a feature;

```csharp
configurator.ConfigureServiceProvider(sp =>
{
...
});
```

## Phases

This layer introduces following phases to the application it is added;

- `BuildConfiguration`: This phase runs in the earliest stage to allow the usage
of `Settings` API from features
- `AddServices`: This phase creates a `IServiceCollection` instance and places
it in the application context
- `PostBuild`: This phase depends on a `IServiceProvider` instance to be added
to application context so that it can be provided from this layer
6 changes: 3 additions & 3 deletions docs/layers/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ This layer introduces following phases to the application it is added;

- `CreateConfigurationManager`: This phase runs as the earliest stage of a test
run to add an empty `ConfigurationManager` to the application context
- `Run`: This phase is added to the application internally as the latest phase
to add `IServiceProvider` to application context so that it can be used during
the test run
- `Build`: This phase is added to the application internally to build an
`IServiceProvider`from registered services and add to the application context
so that it can be used during the test run and trigger later phases
4 changes: 1 addition & 3 deletions docs/recipes/service.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@ Bake.New
| Name | Run | Test |
| -------------------- | ------------------ | ------------------ |
| Code Generation | :white_check_mark: | :white_check_mark: |
| Configuration | :white_check_mark: | :white_check_mark: |
| Data Access | :white_check_mark: | :white_check_mark: |
| Dependency Injection | :white_check_mark: | :white_check_mark: |
| Domain | :white_check_mark: | :white_check_mark: |
| HTTP Client | :white_check_mark: | :no_entry: |
| HTTP Server | :white_check_mark: | :no_entry: |
| Monitoring | :white_check_mark: | :white_check_mark: |
| Rest API | :white_check_mark: | :no_entry: |
| Runtime | :white_check_mark: | :white_check_mark: |
| Testing | :no_entry: | :white_check_mark: |

## Features
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Baked.Architecture;
using Mouseless.EventScheduler.Application.ConfigurationOverrider;

namespace Baked;

public static class ConfigurationOverriderExtensions
{
public static void AddConfigurationOverrider(this List<IFeature> features) =>
features.Add(new ConfigurationOverriderFeature());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Baked.Architecture;

namespace Mouseless.EventScheduler.Application.ConfigurationOverrider;

public class ConfigurationOverriderFeature : IFeature
{
public void Configure(LayerConfigurator configurator)
{
configurator.ConfigureApiModelConventions(api =>
{
api.OverrideAction<DeleteMeetingContact>(routeParts: ["meeting", "contact"]);
});
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Bake.New
.Service(
business: c => c.DomainAssemblies([typeof(Contact).Assembly]),
database: c => c.Sqlite("Mouseless.EventScheduler.Application.db")
database: c => c.Sqlite("Mouseless.EventScheduler.Application.db"),
configure: app => app.Features.AddConfigurationOverrider()
)
.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Baked.Business;

namespace Mouseless.EventScheduler;

public class DeleteMeetingContact(MeetingContacts _meetingContacts)
{
Meeting _meeting = default!;

internal DeleteMeetingContact With(Meeting meeting)
{
_meeting = meeting;

return this;
}

public void Execute(Contact contact)
{
var result = _meetingContacts.SingleBy(_meeting, contact);

result?.Delete();
}

public static implicit operator DeleteMeetingContact(Meeting meeting) =>
meeting.Cast().To<DeleteMeetingContact>();
}

public class DeleteMeetingContacts(Func<DeleteMeetingContact> _newDeleteMeetingContact)
: ICasts<Meeting, DeleteMeetingContact>
{
DeleteMeetingContact ICasts<Meeting, DeleteMeetingContact>.To(Meeting from) =>
_newDeleteMeetingContact().With(from);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,7 @@ public class MeetingContacts(IQueryContext<MeetingContact> _context)
{
internal List<MeetingContact> ByMeeting(Meeting meeting) =>
_context.By(mc => mc.Meeting == meeting);

internal MeetingContact? SingleBy(Meeting meeting, Contact contact) =>
_context.SingleBy(mc => mc.Meeting == meeting && mc.Contact == contact);
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,12 @@ public static Application Service(this Bake bake,
return bake.Application(app =>
{
app.Layers.AddCodeGeneration();
app.Layers.AddConfiguration();
app.Layers.AddDataAccess();
app.Layers.AddDependencyInjection();
app.Layers.AddDomain();
app.Layers.AddHttpClient();
app.Layers.AddHttpServer();
app.Layers.AddMonitoring();
app.Layers.AddRestApi();
app.Layers.AddRuntime();

app.Features.AddAuthentications(authentications);
app.Features.AddAuthorization(authorization);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static IServiceCollection AddTransientWithFactory<TService, TImplementati
where TService : class
where TImplementation : class, TService
=> services
.AddSingleton<Func<TService>>(sp => () => sp.GetRequiredServiceUsingRequestServices<TService>())
.AddSingleton<Func<TService>>(sp => () => sp.UsingCurrentScope().GetRequiredService<TService>())
.AddTransient<TService, TImplementation>();

public static IServiceCollection AddScopedWithFactory(this IServiceCollection services, Type service) =>
Expand All @@ -51,7 +51,7 @@ public static IServiceCollection AddScopedWithFactory<TService, TImplementation>
where TService : class
where TImplementation : class, TService
=> services
.AddSingleton<Func<TService>>(sp => () => sp.GetRequiredServiceUsingRequestServices<TService>())
.AddSingleton<Func<TService>>(sp => () => sp.UsingCurrentScope().GetRequiredService<TService>())
.AddScoped<TService, TImplementation>();

public static IServiceCollection AddSingleton<TService, TImplementation>(this IServiceCollection services, bool forward)
Expand All @@ -63,7 +63,7 @@ public static IServiceCollection AddSingleton(this IServiceCollection services,
{
if (!forward) { return services.AddSingleton(service, implementation); }

return services.AddSingleton(service, sp => sp.GetRequiredServiceUsingRequestServices(implementation));
return services.AddSingleton(service, sp => sp.UsingCurrentScope().GetRequiredService(implementation));
}

public static bool TryGetMappedMethod(this ApiDescription apiDescription, [NotNullWhen(true)] out MappedMethodAttribute? result)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ c.Method.DefaultOverload.BaseDefinition.DeclaringType is not null &&
{
type.Apply(t => @interface.Apply(i =>
{
Caster.Add(i.GenericTypeArguments[0], i.GenericTypeArguments[1], sp => sp.GetRequiredServiceUsingRequestServices(t));
Caster.Add(i.GenericTypeArguments[0], i.GenericTypeArguments[1], sp => sp.UsingCurrentScope().GetRequiredService(t));
}));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace Baked.CodeGeneration;

public class GeneratedAssemblyCollection : List<GeneratedAssemblyDescriptor>, IGeneratedAssemblyCollection { }
public class GeneratedAssemblyCollection : List<GeneratedAssemblyDescriptor>, IGeneratedAssemblyCollection;
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace Baked.CodeGeneration;

public interface IGeneratedAssemblyCollection : IList<GeneratedAssemblyDescriptor> { }
public interface IGeneratedAssemblyCollection : IList<GeneratedAssemblyDescriptor>;
Loading