Skip to content

Instantly share code, notes, and snippets.

@bmcdavid
Created March 20, 2018 15:15
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 bmcdavid/484038f6f73e9e1edfa959746d6c2d0d to your computer and use it in GitHub Desktop.
Save bmcdavid/484038f6f73e9e1edfa959746d6c2d0d to your computer and use it in GitHub Desktop.
Demonstrates DotNetStarter using net core and DotNetStarter.RegistrationAbstractions only.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using DotNetStarter.Abstractions;
using Microsoft.DotNet.PlatformAbstractions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
// todo: Set namespace
namespace Replace.With.Namespace
{
/// <summary>
/// Sorts registrations, null attributes first
/// </summary>
public class DependentRegistrationComparer : IComparer<DependentRegistration>
{
public int Compare(DependentRegistration x, DependentRegistration y)
{
if (x == null || y == null) return 0;
var xDep = x.Registration?.Dependencies.Length ?? -1;
var yDep = y.Registration?.Dependencies.Length ?? -1;
var num = xDep - yDep;
return num == 0 ?
string.Compare(x.Implementation.FullName, y.Implementation.FullName, StringComparison.Ordinal) :
num;
}
}
public class DependentRegistration
{
public DependentRegistration(Type impl, RegistrationAttribute reg)
{
Implementation = impl;
Registration = reg;
}
public Type Implementation { get; }
public RegistrationAttribute Registration { get; }
}
/// <summary>
/// Usage in Startup class
/// Add using namespace.of.this
/// Insert line Startup.ConfigureServices: services.AddDotNetStarterRegistrations();
/// </summary>
public static class RegistrationExtensions
{
/// <summary>
/// Adds classes that contain RegistrationAttribute in given assemblies or assemblies with DiscoverableAssemblyAttribute assembly attribute
/// </summary>
/// <param name="services"></param>
/// <param name="assembliesToCheck">Assemblies to look for types with RegistrationAttribute</param>
/// <returns></returns>
public static IServiceCollection AddDotNetStarterRegistrations(this IServiceCollection services, IEnumerable<Assembly> assembliesToCheck = null)
{
var assemblies = assembliesToCheck ??
AssemblyLoader()
.Where(a => a.GetCustomAttribute<DiscoverableAssemblyAttribute>() != null)
.ToList();
var collection = assemblies.SelectMany(AssemblyTypes)
.Select(type => new DependentRegistration(type, type.GetCustomAttribute<RegistrationAttribute>()))
.ToList();
var sortedCollection = collection.OrderBy(x => x, new DependentRegistrationComparer())
.SkipWhile(x => x.Registration == null)
.ToList();
foreach (var t in sortedCollection)
{
services.Add(new ServiceDescriptor(t.Registration.ServiceType, t.Implementation, Convert(t.Registration.Lifecycle)));
}
return services;
}
private static IEnumerable<Type> AssemblyTypes(Assembly assembly)
{
var exportsType = ExportsType.All;
var exportAttribute = assembly.GetCustomAttribute<ExportsAttribute>();
if (exportAttribute != null)
{
exportsType = exportAttribute.ExportsType;
}
switch (exportsType)
{
case ExportsType.All:
return assembly.GetTypes();
case ExportsType.ExportsOnly:
return assembly.ExportedTypes;
case ExportsType.Specfic:
return exportAttribute?.Exports ?? Enumerable.Empty<Type>();
default:
throw new NotSupportedException("Unknown ExportsType of " + exportsType);
}
}
private static IEnumerable<Assembly> AssemblyLoader()
{
var runtimeId = RuntimeEnvironment.GetRuntimeIdentifier();
var libraries = DependencyContext.Default.GetRuntimeAssemblyNames(runtimeId);
return libraries.Select(x => Assembly.Load(new AssemblyName(x.Name)));
}
private static ServiceLifetime Convert(Lifecycle l)
{
switch (l)
{
case Lifecycle.Singleton: return ServiceLifetime.Singleton;
case Lifecycle.Scoped: return ServiceLifetime.Scoped;
case Lifecycle.Transient: return ServiceLifetime.Transient;
default: throw new Exception($"Unable to convert {l} to {typeof(ServiceLifetime).FullName}!");
}
}
}
}
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Replace.With.Namespace;
namespace _ThrowAwayCoreWeb
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services
.AddDotNetStarterRegistrations()
.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment