Skip to content

Commit

Permalink
- Ported the default Dependency Injection into Blazyload to make mod…
Browse files Browse the repository at this point in the history
…ifications to how open generics are loaded
  • Loading branch information
RonSijm committed Sep 24, 2023
1 parent 61ec1f7 commit 9ebf3ce
Show file tree
Hide file tree
Showing 36 changed files with 2,534 additions and 37 deletions.
9 changes: 8 additions & 1 deletion src/RonSijm.Blazyload.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Blazy/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Blazyload/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sijm/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bootstapper/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bootstapping/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dlls/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Initializers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sijm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Trimmability/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unattempted/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Wasm/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
namespace RonSijm.Blazyload.Features.Bootstapping;

// ReSharper disable once UnusedType.Global - Justification: Used by library consumers
public static class BlazyloadBootstapper
{
// ReSharper disable once UnusedMember.Global - Justification: Used by library consumers
public static void UseBlazyload(this WebAssemblyHostBuilder builder, Action<BlazyOptions> optionsConfig = null)
{
var options = new BlazyOptions();
Expand Down
36 changes: 15 additions & 21 deletions src/RonSijm.Blazyload/Features/DIComponents/BlazyAssemblyLoader.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
using System.Net.Http.Json;
// ReSharper disable global EventNeverSubscribedTo.Global - Justification: Used by library consumers
// ReSharper disable global UnusedMember.Global - Justification: Used by library consumers

using System.Net.Http.Json;
using RonSijm.Blazyload.Features.DIComponents.Models;

namespace RonSijm.Blazyload.Features.DIComponents;

public class BlazyAssemblyLoader
public class BlazyAssemblyLoader(BlazyServiceProvider blazyServiceProvider, NavigationManager navigationManager)
{
private HashSet<string> _loadedAssemblies = new();

private readonly BlazyServiceProvider _blazyServiceProvider;
private readonly NavigationManager _navigationManager;

private HashSet<string> _preloadedDlls;

public BlazyAssemblyLoader(BlazyServiceProvider blazyServiceProvider, NavigationManager navigationManager)
{
_navigationManager = navigationManager;
_blazyServiceProvider = blazyServiceProvider;
}

public event Action<List<Assembly>> OnAssembliesLoaded;

public async Task<List<Assembly>> LoadAssemblyAsync(string assemblyToLoad)
Expand Down Expand Up @@ -50,7 +44,7 @@ private async Task<List<Assembly>> LoadAssembliesAsync(IEnumerable<string> assem
var assemblyWithOptions = new List<(string assemblyToLoad, BlazyAssemblyOptions options)>();
foreach (var assemblyToLoad in unattemptedAssemblies)
{
BlazyAssemblyOptions options = _blazyServiceProvider.Options.GetOptions(assemblyToLoad);
var options = blazyServiceProvider.Options.GetOptions(assemblyToLoad);
assemblyWithOptions.Add((assemblyToLoad, options));
}

Expand All @@ -63,12 +57,12 @@ private async Task<List<Assembly>> LoadAssembliesAsync(IEnumerable<string> assem

loadedAssemblies.AddRange(assemblies);

await _blazyServiceProvider.Register(assemblies);
await blazyServiceProvider.Register(assemblies);

foreach (var assembly in assemblies)
{
var assemblyName = $"{assembly.GetName().Name}";
var assemblyOptions = _blazyServiceProvider.Options?.GetOptions(assemblyName);
var assemblyOptions = blazyServiceProvider.Options?.GetOptions(assemblyName);

if (BlazyOptions.DisableCascadeLoadingGlobally && assemblyOptions is { DisableCascadeLoading: true })
{
Expand Down Expand Up @@ -99,7 +93,7 @@ private async Task<List<Assembly>> LoadAssembliesAsync(IEnumerable<string> assem
}

// Only at the end of the recursive loop we rebuild the service provider, and call consumers
_blazyServiceProvider.CreateServiceProvider();
blazyServiceProvider.CreateServiceProvider();
OnAssembliesLoaded?.Invoke(loadedAssemblies);

return loadedAssemblies;
Expand All @@ -112,7 +106,7 @@ private async Task<HashSet<string>> GetPreloadedAssemblies()
try
{
using var client = new HttpClient();
var result = await client.GetFromJsonAsync<BlazorBootModel>($"{_navigationManager.BaseUri}/_framework/blazor.boot.json");
var result = await client.GetFromJsonAsync<BlazorBootModel>($"{navigationManager.BaseUri}/_framework/blazor.boot.json");

foreach (var assembly in result.Resources.Assembly)
{
Expand All @@ -123,7 +117,7 @@ private async Task<HashSet<string>> GetPreloadedAssemblies()
}
catch (Exception e)
{
Console.WriteLine("Error while attempting discover preloaded dlls.");
Console.WriteLine(@"Error while attempting discover preloaded dlls.");
Console.WriteLine(e);
}

Expand Down Expand Up @@ -171,11 +165,11 @@ private string GetDllLocationFromOptions((string assemblyToLoad, BlazyAssemblyOp
{
var options = assemblyToLoad.options;

var dllLocation = options == null ? // If options is null,
$"{_navigationManager.BaseUri}/_framework/" : // use default path
var dllLocation = options == null ? // If options is null,
$"{navigationManager.BaseUri}/_framework/" : // use default path
options.AbsolutePath ?? // If AbsolutePath isn't null, use that.
(options.RelativePath != null ? $"{_navigationManager.BaseUri}{assemblyToLoad.options.RelativePath}" : // If RelativePath isn't null, use base path + RelativePath
$"{_navigationManager.BaseUri}/_framework/"); // Else just use default path
(options.RelativePath != null ? $"{navigationManager.BaseUri}{assemblyToLoad.options.RelativePath}" : // If RelativePath isn't null, use base path + RelativePath
$"{navigationManager.BaseUri}/_framework/"); // Else just use default path

return dllLocation;
}
Expand Down
48 changes: 38 additions & 10 deletions src/RonSijm.Blazyload/Features/DIComponents/BlazyServiceProvider.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
namespace RonSijm.Blazyload.Features.DIComponents;
using ServiceProviderOptions = RonSijm.Blazyload.MicrosoftServiceProvider.ServiceProviderOptions;

public class BlazyServiceProvider : IServiceProvider
namespace RonSijm.Blazyload.Features.DIComponents;

public interface IBlazyInternalServiceProvider
{
bool TryGetServiceFromOverride(Type serviceType, out object value);
}

public class BlazyServiceProvider : IServiceProvider, IBlazyInternalServiceProvider
{
private readonly ServiceCollection _services = new();
private readonly Dictionary<Type, Func<IServiceProvider, object>> _typeOverwrites = new();
private readonly List<(Func<Type, bool> Criteria, Func<Type, IServiceProvider, object> Factory)> _typeFunctionOverrides = new();

private IServiceProvider _serviceProvider;
private readonly DefaultServiceProviderFactory _serviceProviderFactory = new();


public BlazyOptions Options { get; }

public BlazyServiceProvider(IEnumerable<ServiceDescriptor> services, BlazyOptions options)
Expand All @@ -28,16 +34,34 @@ public BlazyServiceProvider(IEnumerable<ServiceDescriptor> services, BlazyOption
_typeFunctionOverrides.RegisterOptional();
}

_serviceProvider = _serviceProviderFactory.CreateServiceProvider(_services);
foreach (var factory in options.AdditionalFactories)
{
_typeFunctionOverrides.Add(factory);
}

_serviceProvider = new MicrosoftServiceProvider.MicrosoftServiceProvider(_services, ServiceProviderOptions.Default, this);
}

public object GetService(Type serviceType)
{
if (TryGetServiceFromOverride(serviceType, out var value))
{
return value;
}

return _serviceProvider.GetService(serviceType);
}

public bool TryGetServiceFromOverride(Type serviceType, out object value)
{
var hasOverWrite = _typeOverwrites.TryGetValue(serviceType, out var objectFactory);

if (hasOverWrite)
{
return objectFactory(this);
{
value = objectFactory(this);
return true;
}
}

// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator - Justification: Generates shitty linq
Expand All @@ -49,10 +73,14 @@ public object GetService(Type serviceType)
}

var result = typeFunctionOverride.Factory(serviceType, this);
return result;
{
value = result;
return true;
}
}

return _serviceProvider.GetService(serviceType);
value = null;
return false;
}

public async Task Register(params Assembly[] assemblies)
Expand Down Expand Up @@ -83,7 +111,7 @@ public async Task Register(params Assembly[] assemblies)
{
// If there is a class but no method, that's an error, so we log out it.
// Don't think there's a need to throw anything.
Console.Write("Error: BlazyBootstrap Class found but no GetServices");
Console.Write(@"Error: BlazyBootstrap Class found but no GetServices");
continue;
}

Expand Down Expand Up @@ -125,6 +153,6 @@ private static async Task<IEnumerable<ServiceDescriptor>> TryLoadServices(object

public void CreateServiceProvider()
{
_serviceProvider = _serviceProviderFactory.CreateServiceProvider(_services);
_serviceProvider = new MicrosoftServiceProvider.MicrosoftServiceProvider(_services, ServiceProviderOptions.Default, this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public BlazyServiceProviderFactory(BlazyOptions options, IServiceCollection serv
_options = options;
serviceCollection.AddSingleton<BlazyAssemblyLoader>();
}

public BlazyBuilder CreateBuilder(IServiceCollection services)
{
var container = new BlazyBuilder(services);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Text.Json.Serialization;


using System.Text.Json.Serialization;

namespace RonSijm.Blazyload.Features.DIComponents.Models;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Text.Json.Serialization;
// ReSharper disable global UnusedMember.Global

using System.Text.Json.Serialization;

namespace RonSijm.Blazyload.Features.DIComponents.Models;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ public class BlazyOptions

private List<(Func<string, bool> Criteria, BlazyAssemblyOptions Options)> _assemblyMapping;

public List<(Func<Type, bool> Criteria, Func<Type, IServiceProvider, object> Factory)> AdditionalFactories { get; } = new();

public BlazyAssemblyOptions GetOptions(string assemblyName)
{
if (_assemblyMapping == null)
{
return null;
}

if (assemblyName.EndsWith(".dll"))
if (assemblyName.EndsWith(".dll", StringComparison.Ordinal))
{
assemblyName = assemblyName.Replace(".dll", string.Empty);
}
Expand Down

0 comments on commit 9ebf3ce

Please sign in to comment.