Skip to content

Instantly share code, notes, and snippets.

@thiagomajesk
Created February 11, 2017 22:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thiagomajesk/bb493719674c57c6eec6975ca3fe7835 to your computer and use it in GitHub Desktop.
Save thiagomajesk/bb493719674c57c6eec6975ca3fe7835 to your computer and use it in GitHub Desktop.
View Model Factories in ASP.NET Core with Mediator + IoC Extension
public class FooController : Controller
{
private readonly IViewFactory viewFactory;
public FooController(IViewFactory viewFactory) { this.viewFactory = viewFactory; }
public IActionResult Index()
{
var viewModel = viewFactory.Create<CreateFooViewModel>();
return View(viewModel);
}
}
public interface IViewFactory
{
TView Create<TView>();
TView Create<TInput, TView>(TInput input);
}
public class DefaultViewFactory : IViewFactory
{
private readonly IServiceProvider provider;
public DefaultViewFactory(IServiceProvider provider) { this.provider = provider; }
public TView Create<TView>()
{
var builder = provider.GetService(typeof(IViewBuilder<TView>)) as IViewBuilder<TView>;
return (builder != null ? builder.Build() : Activator.CreateInstance<TView>());
}
public TView Create<TInput, TView>(TInput input)
{
var builder = provider.GetService(typeof(IViewBuilder<TView, TInput>)) as IViewBuilder<TView, TInput>;
return (builder != null ? builder.Build(input) : (TView)Activator.CreateInstance(typeof(TView), input));
}
}
public static class ContainerExtensions
{
public static IServiceCollection ConnectImplementations<TService>(this IServiceCollection services, Assembly assembly) where TService : class
{
return services.ConnectImplementations(typeof(TService), assembly);
}
public static IServiceCollection ConnectImplementations(this IServiceCollection services, Type serviceType, Assembly assembly)
{
if (!serviceType.IsInterface) throw new ArgumentException("Type must be an interface");
var concreteTypes = assembly.ExportedTypes.Select(t => t.GetTypeInfo()).Where(ti => ti.IsClass && !ti.IsAbstract);
foreach (var type in concreteTypes)
{
var interfaces = type.ImplementedInterfaces.Select(i => i.GetTypeInfo()).ToArray();
foreach (var @interface in interfaces.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == serviceType))
{
services.AddTransient(@interface.AsType(), type.AsType());
}
foreach (var @interface in interfaces.Where(i => !i.IsGenericType && i.IsAssignableFrom(serviceType)))
{
services.AddTransient(@interface.AsType(), type.AsType());
}
}
return services;
}
}
public interface IFoo
{
string GetDescription();
}
public class Foo : IFoo
{
public int Id { get; set; }
public string Name { get; set; }
public string GetDescription() => $"Id: {Id} | Name: {Name}";
}
public interface IViewBuilder<TView>
{
TView Build();
}
public interface IViewBuilder<TView, TInput>
{
TView Build(TInput input);
}
public class CreateFooViewBuilder : IViewBuilder<CreateFooViewModel>
{
private readonly DatabaseContext context;
public CreateFooViewBuilder(DatabaseContext context) { this.context = context; }
public CreateFooViewModel Build()
{
return new CreateFooViewModel { Id = 1, Name = "Foo" };
}
}
public class EditFooViewBuilder : IViewBuilder<CreateFooViewModel, string>
{
private readonly DatabaseContext context;
public EditFooViewBuilder(DatabaseContext context) { this.context = context; }
public CreateFooViewModel Build(string input)
{
return new CreateFooViewModel { Id = 1, Name = input };
}
}
public class CreateFooViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class EditFooViewModel
{
public string Name { get; set; }
}
public void ConfigureServices(IServiceCollection services)
{
// [...]
services.AddScoped(typeof(IViewFactory), typeof(DefaultViewFactory));
services.ConnectImplementations(typeof(IFoo), Assembly.GetExecutingAssembly());
services.ConnectImplementations(typeof(IViewBuilder<>), Assembly.GetExecutingAssembly());
services.ConnectImplementations(typeof(IViewBuilder<,>), Assembly.GetExecutingAssembly());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment