Skip to content

Commit

Permalink
feat: Added depencency reflector factory
Browse files Browse the repository at this point in the history
* feat: Partial reflector factory

* feat: Added depencency reflector factory
  • Loading branch information
nikcio authored Jan 27, 2022
1 parent dfb43a3 commit db8236b
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.Extensions.DependencyInjection;
using Nikcio.UHeadless.Factories.Properties;
using Nikcio.UHeadless.Factories.Properties.PropertyValues;
using Nikcio.UHeadless.Factories.Reflection;
using Nikcio.UHeadless.Mappers.Properties;
using Nikcio.UHeadless.Models.Dtos.Content;
using Nikcio.UHeadless.Models.Dtos.ContentTypes;
Expand All @@ -25,7 +26,8 @@ public static IUmbracoBuilder AddUHeadless(this IUmbracoBuilder builder, List<As
.AddScoped<ContentRepository>()
.AddScoped<IPropertyFactory, PropertyFactory>()
.AddScoped<IPropertyValueFactory, PropertyValueFactory>()
.AddSingleton<IPropertyMap, PropertyMap>();
.AddSingleton<IPropertyMap, PropertyMap>()
.AddScoped<IDependencyReflectorFactory, DependencyReflectorFactory>();

builder.Services
.AddGraphQLServer()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
using Nikcio.UHeadless.Commands.Properties;
using Nikcio.UHeadless.Factories.Reflection;
using Nikcio.UHeadless.Mappers.Properties;
using Nikcio.UHeadless.Models.Dtos.Propreties.PropertyValues;
using Nikcio.UHeadless.Models.Properties.BlockList;
using Nikcio.UHeadless.Models.Properties.NestedContent;
using System;
using System.Linq;
using Umbraco.Cms.Core;

namespace Nikcio.UHeadless.Factories.Properties.PropertyValues
{
public class PropertyValueFactory : IPropertyValueFactory
{
private readonly IPropertyMap propertyMap;
private readonly IServiceProvider serviceProvider;
private readonly IDependencyReflectorFactory dependencyReflectorFactory;

public PropertyValueFactory(IPropertyMap propertyMapper, IServiceProvider serviceProvider)
public PropertyValueFactory(IPropertyMap propertyMapper, IDependencyReflectorFactory dependencyReflectorFactory)
{
propertyMap = propertyMapper;
this.dependencyReflectorFactory = dependencyReflectorFactory;
AddPropertyMapDefaults();
this.serviceProvider = serviceProvider;
}
private void AddPropertyMapDefaults()
{
Expand Down Expand Up @@ -53,10 +53,7 @@ public PropertyValueBaseGraphType GetPropertyValue(CreatePropertyValue createPro
propertyTypeAssemblyQualifiedName = propertyMap.GetEditorValue(UHeadlessConstants.Constants.PropertyConstants.DefaultKey);
}
var type = Type.GetType(propertyTypeAssemblyQualifiedName);
var constructors = type.GetConstructors();
var parameters = constructors.FirstOrDefault(constructor => constructor.GetParameters().FirstOrDefault().ParameterType == typeof(CreatePropertyValue)).GetParameters();
var injectedParamerters = new object[] { createPropertyValue }.Concat(parameters.Skip(1).Select(parameter => serviceProvider.GetService(parameter.ParameterType))).ToArray();
return (PropertyValueBaseGraphType)Activator.CreateInstance(Type.GetType(propertyTypeAssemblyQualifiedName), injectedParamerters);
return dependencyReflectorFactory.GetReflectedType<PropertyValueBaseGraphType>(type, new object[1] { createPropertyValue });
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Reflection;

namespace Nikcio.UHeadless.Factories.Reflection
{
public class DependencyReflectorFactory : IDependencyReflectorFactory
{
private readonly IServiceProvider serviceProvider;
private readonly ILogger<DependencyReflectorFactory> logger;

public DependencyReflectorFactory(IServiceProvider serviceProvider, ILogger<DependencyReflectorFactory> logger)
{
this.serviceProvider = serviceProvider;
this.logger = logger;
}

public T GetReflectedType<T>(Type typeToReflect, object[] constructorRequiredParamerters)
where T : class
{
var propertyTypeAssemblyQualifiedName = typeToReflect.AssemblyQualifiedName;
var constructors = typeToReflect.GetConstructors();
if (constructors.Length == 0)
{
LogConstructorError(typeToReflect, constructorRequiredParamerters);
return null;
}
var parameters = GetConstructor(constructors, constructorRequiredParamerters).GetParameters();
object[] injectedParamerters = null;
if (constructorRequiredParamerters == null)
{
injectedParamerters = parameters.Select(parameter => serviceProvider.GetService(parameter.ParameterType)).ToArray();
}
else
{
injectedParamerters = constructorRequiredParamerters
.Concat(parameters.Skip(constructorRequiredParamerters.Length).Select(parameter => serviceProvider.GetService(parameter.ParameterType)))
.ToArray();
}
return (T)Activator.CreateInstance(Type.GetType(propertyTypeAssemblyQualifiedName), injectedParamerters);
}

private void LogConstructorError(Type typeToReflect, object[] constructorRequiredParamerters)
{
string constructorNames = string.Join(", ", constructorRequiredParamerters?.Select(item => item.GetType().Name));
string message = $"Unable to create instance of {typeToReflect.Name}. " +
$"Could not find a constructor with {constructorNames} as first argument(s)";
logger.LogError(message);
}

private ParameterInfo[] TakeConstructorRequiredParamters(ConstructorInfo constructor, int constructorRequiredParamertersLength)
{
var parameters = constructor.GetParameters();
if (parameters.Length < constructorRequiredParamertersLength)
{
return parameters;
}
return parameters?.Take(constructorRequiredParamertersLength).ToArray();
}

private bool ValidateConstructorRequiredParameters(ConstructorInfo constructor, object[] constructorRequiredParameters)
{
if (constructorRequiredParameters == null)
{
return true;
}
var parameters = TakeConstructorRequiredParamters(constructor, constructorRequiredParameters.Length);
for (int i = 0; i < parameters.Length; i++)
{
var requiredParameter = constructorRequiredParameters[i].GetType();
if (parameters[i].ParameterType != requiredParameter)
{
return false;
}
}
return true;
}

private ConstructorInfo GetConstructor(ConstructorInfo[] constructors, object[] constructorRequiredParameters)
{
return constructors?.FirstOrDefault(constructor =>
ValidateConstructorRequiredParameters(constructor, constructorRequiredParameters));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace Nikcio.UHeadless.Factories.Reflection
{
public interface IDependencyReflectorFactory
{
T GetReflectedType<T>(Type typeToReflect, object[] constructorRequiredParamerters) where T : class;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using AutoMapper;
using Nikcio.UHeadless.Commands.Properties;
using Nikcio.UHeadless.Factories.Properties;
using Nikcio.UHeadless.Factories.Reflection;
using Nikcio.UHeadless.Models.Dtos.Propreties.PropertyValues;
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Cms.Core.Models.Blocks;
Expand All @@ -19,4 +21,22 @@ public BlockListModelGraphType(CreatePropertyValue createPropertyValue, IMapper
?.Select(blockListItem => new BlockListItemGraphType(blockListItem, mapper, propertyFactory, createPropertyValue.Content, createPropertyValue.Culture)).ToList();
}
}

public class BlockListModelGraphType<T> : PropertyValueBaseGraphType
where T : PropertyValueBaseGraphType
{
public List<T> Blocks { get; set; }

public BlockListModelGraphType(CreatePropertyValue createPropertyValue, IDependencyReflectorFactory dependencyReflectorFactory) : base(createPropertyValue)
{
var value = (BlockListModel)createPropertyValue.Property.GetValue();
Blocks = value.ToList()
?.Select(blockListItem =>
{
var propertyTypeAssemblyQualifiedName = blockListItem.GetType().AssemblyQualifiedName;
var type = Type.GetType(propertyTypeAssemblyQualifiedName);
return dependencyReflectorFactory.GetReflectedType<T>(type, new object[1] { createPropertyValue });
}).ToList();
}
}
}
3 changes: 0 additions & 3 deletions src/TestProject/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,12 @@ public Startup(IWebHostEnvironment webHostEnvironment, IConfiguration config)
/// </remarks>
public void ConfigureServices(IServiceCollection services)
{
#pragma warning disable IDE0022 // Use expression body for methods
services.AddUmbraco(_env, _config)
.AddBackOffice()
.AddWebsite()
.AddComposers()
.AddUHeadless()
.Build();
#pragma warning restore IDE0022 // Use expression body for methods

}

/// <summary>
Expand Down

0 comments on commit db8236b

Please sign in to comment.