Skip to content

Commit 4c0a6b0

Browse files
committed
example for #567 and #563 which takes into account SetsRequiredMembers constructor
1 parent 6c7e8bf commit 4c0a6b0

File tree

3 files changed

+57
-12
lines changed

3 files changed

+57
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace BlazorServerSide.Data;
2+
3+
using System.Diagnostics.CodeAnalysis;
4+
5+
public interface IRandomProvider
6+
{
7+
public Random Random { get; }
8+
}
9+
10+
/// <summary>
11+
/// Just and example service for the use of `SetsRequiredMembers` and `required properties` together with DryIoc.
12+
/// </summary>
13+
public class SharedRandomProvider : IRandomProvider
14+
{
15+
public required Random Random { get; init; }
16+
17+
[SetsRequiredMembers]
18+
public SharedRandomProvider()
19+
{
20+
Random = Random.Shared;
21+
}
22+
}

samples/BlazorServerSide/Data/WeatherForecastService.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,21 @@ public class WeatherForecastService
77
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
88
};
99

10-
public required Func<WeatherForecast> WeatherForecastFactory { protected get; init; }
10+
// injected by the DI container
11+
public required Func<WeatherForecast> WeatherForecastFactory { get; init; }
12+
13+
public readonly IRandomProvider RandomProvider;
14+
public WeatherForecastService(IRandomProvider randomProvider) => RandomProvider = randomProvider;
1115

1216
public Task<WeatherForecast[]> GetForecastAsync(DateOnly startDate)
1317
{
18+
var random = RandomProvider.Random;
1419
return Task.FromResult(Enumerable.Range(1, 5).Select(index =>
1520
{
1621
var f = WeatherForecastFactory();
1722
f.Date = startDate.AddDays(index);
18-
f.TemperatureC = Random.Shared.Next(-20, 55);
19-
f.Summary = Summaries[Random.Shared.Next(Summaries.Length)];
23+
f.TemperatureC = random.Next(-20, 55);
24+
f.Summary = Summaries[random.Next(Summaries.Length)];
2025
return f;
2126
}).ToArray());
2227
}

samples/BlazorServerSide/Program.cs

+27-9
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,46 @@
22
using Microsoft.AspNetCore.Components.Web;
33
using BlazorServerSide.Data;
44

5-
// to get the required properties
5+
// support for injection of required properties
66
using System.Reflection;
77
using System.Runtime.CompilerServices;
8+
using System.Diagnostics.CodeAnalysis;
89

910
using Serilog;
1011
using DryIoc;
1112
using DryIoc.Microsoft.DependencyInjection;
1213

1314
var builder = WebApplication.CreateBuilder(args);
1415

15-
// todo: @wip take into account constructor with SetsRequiredMembers attribute
16-
var requiredProperties = PropertiesAndFields.All(withFields: false,
17-
serviceInfo: (p, _) => p.GetCustomAttribute<RequiredMemberAttribute>() == null ? null
18-
: PropertyOrFieldServiceInfo.Of(p).WithDetails(ServiceDetails.Of(IfUnresolved.Throw)));
16+
static PropertyOrFieldServiceInfo? TryInjectRequiredProperties(MemberInfo memberInfo, Request request)
17+
{
18+
if (memberInfo is not PropertyInfo p)
19+
return null;
20+
21+
// avoid injection of properties if the selected constructor already supposed to set them
22+
var ctor = request.SelectedConstructor;
23+
if (ctor != null && ctor.GetCustomAttribute<SetsRequiredMembersAttribute>() != null)
24+
{
25+
#if DEBUG
26+
var logger = request.Container.GetService<ILogger<DryIoc.IContainer>>();
27+
logger?.LogDebug("Skipping injection of required property `{PropertyName}` because the selected constructor `{Constructor}` already supposed to set it for service `{ServiceType}`.", p.Name, ctor, request.ServiceType);
28+
#endif
29+
return null;
30+
}
31+
32+
return p.GetCustomAttribute<RequiredMemberAttribute>() == null
33+
? null
34+
: PropertyOrFieldServiceInfo.Of(p).WithDetails(ServiceDetails.Of(IfUnresolved.Throw));
35+
}
1936

20-
var container = new Container(Rules.MicrosoftDependencyInjectionRules.With(propertiesAndFields: requiredProperties));
37+
var tryInjectRequiredProperties = PropertiesAndFields.All(withFields: false, serviceInfo: TryInjectRequiredProperties);
2138

39+
var container = new Container(Rules.MicrosoftDependencyInjectionRules.With(propertiesAndFields: tryInjectRequiredProperties));
2240

2341
// Here it goes the integration with the existing DryIoc container
2442
var diFactory = new DryIocServiceProviderFactory(container, RegistrySharing.Share);
2543
builder.Host.UseServiceProviderFactory(diFactory);
2644

27-
2845
// Add services to the container.
2946
builder.Services.AddRazorPages();
3047
builder.Services.AddServerSideBlazor(options =>
@@ -37,13 +54,14 @@
3754
.MinimumLevel.Verbose()
3855
.ReadFrom.Configuration(builder.Configuration)
3956
.Enrich.FromLogContext()
40-
.WriteTo.File("Errors/Log_.log", rollingInterval: RollingInterval.Day)
57+
.WriteTo.File("Logs/Log_.log", rollingInterval: RollingInterval.Day)
4158
.CreateLogger();
4259
builder.Host.UseSerilog(logger);
4360

4461

45-
builder.Services.AddSingleton<WeatherForecast>(); // will be injected as required property
62+
builder.Services.AddTransient<WeatherForecast>();
4663
builder.Services.AddSingleton<WeatherForecastService>();
64+
builder.Services.AddSingleton<IRandomProvider, SharedRandomProvider>();
4765

4866
var app = builder.Build();
4967

0 commit comments

Comments
 (0)