using System; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor; #if !NETCORE2_1 using Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation; #endif using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Prise.DependencyInjection; using Prise.Activation; using Prise.AssemblyLoading; using Prise.AssemblyScanning; using Prise.Proxy; using Prise.Caching; namespace Prise.Mvc { public static class PriseMvcExtensions { internal static PluginLoadContext AddMvcTypes(this PluginLoadContext loadContext) { return loadContext.AddHostTypes(new[] { typeof(ControllerBase) }); } internal static PluginLoadContext AddMvcRazorTypes(this PluginLoadContext loadContext) { return loadContext.AddHostTypes(new[] { typeof(ControllerBase), typeof(ITempDataDictionaryFactory) }); } public static IServiceCollection AddCorePriseServices(this IServiceCollection services) { return services .AddFactory(DefaultFactories.DefaultAssemblyScanner, ServiceLifetime.Scoped) .AddFactory(DefaultFactories.DefaultPluginTypeSelector, ServiceLifetime.Scoped) .AddFactory(DefaultFactories.DefaultParameterConverter, ServiceLifetime.Scoped) .AddFactory(DefaultFactories.DefaultResultConverter, ServiceLifetime.Scoped) .AddFactory(DefaultFactories.DefaultPluginActivationContextProvider, ServiceLifetime.Scoped) .AddFactory(DefaultFactories.DefaultRemotePluginActivator, ServiceLifetime.Scoped) .AddFactory(DefaultFactories.DefaultPluginProxyCreator, ServiceLifetime.Scoped) .AddFactory(DefaultFactories.DefaultAssemblyLoader, ServiceLifetime.Singleton); } /// /// Does all of the plumbing to load API Controllers as Prise Plugins. /// Limitiations: /// - No DispatchProxy can be used, backwards compatability is compromised (DispatchProxy requires an interface as base class, not ControllerBase) /// - Plugin Cache is set to Singleton because we cannot unload assemblies, this would disable the controller routing (and result in 404) /// - Assembly unloading is disabled, memory leaks can occur /// /// A fully configured Prise setup that allows you to load plugins via the IMvcPluginLoader public static IServiceCollection AddPriseMvc(this IServiceCollection services) { return services .AddCorePriseServices() .AddSingleton() .AddScoped() .ConfigureMvcServices() ; } /// /// Does all of the plumbing to load API Controllers and RAZOR Controllers as Prise Plugins. /// Limitiations: /// - No DispatchProxy can be used, backwards compatability is compromised (DispatchProxy requires an interface as base class, not ControllerBase) /// - Plugin Cache is set to Singleton because we cannot unload assemblies, this would disable the controller routing (and result in 404) /// - Assembly unloading is disabled, memory leaks can occur /// /// /// /// By default, this should be the IWebHostEnvironment.WebRootPaht or IHostingEnvironment.WebRootPath /// public static IServiceCollection AddPriseRazorPlugins(this IServiceCollection services, string webRootPath, string pathToPlugins) { return services .AddCorePriseServices() .AddSingleton() .AddScoped() .ConfigureMvcServices() .ConfigureRazorServices(webRootPath, pathToPlugins) ; } private static IServiceCollection ConfigureMvcServices(this IServiceCollection services) { var actionDescriptorChangeProvider = new DefaultPriseMvcActionDescriptorChangeProvider(); // Registers the change provider return services .AddSingleton(actionDescriptorChangeProvider) .AddSingleton(actionDescriptorChangeProvider) // Registers the activator for controllers from plugin assemblies .Replace(ServiceDescriptor.Transient()); } private static IServiceCollection ConfigureRazorServices(this IServiceCollection services, string webRootPath, string pathToPlugins) { return services #if NETCORE2_1 .Configure(options => { options.FileProviders.Add(new DefaultPrisePluginViewsAssemblyFileProvider(webRootPath, pathToPlugins)); }) #else .Configure(options => { options.FileProviders.Add(new DefaultPrisePluginViewsAssemblyFileProvider(webRootPath, pathToPlugins)); }) #endif // Registers the static Plugin Cache Accessor .AddSingleton(); } } }