diff --git a/zero.Backoffice.UI/app/core/plugins.js b/zero.Backoffice.UI/app/core/plugins.js
index 6033adb0..c3b2f775 100644
--- a/zero.Backoffice.UI/app/core/plugins.js
+++ b/zero.Backoffice.UI/app/core/plugins.js
@@ -1,5 +1 @@
-import zeroPlugin0 from '@zeroplugin0/plugin.js';
-import zeroPlugin1 from '@zeroplugin1/plugin.js';
-import zeroPlugin2 from '@zeroplugin2/plugin.js';
-import zeroPlugin3 from '@zeroplugin3/plugin.js';
-export default [ zeroPlugin0, zeroPlugin1, zeroPlugin2, zeroPlugin3 ];
\ No newline at end of file
+export default [ ];
\ No newline at end of file
diff --git a/zero.Backoffice.UI/vite.config.js b/zero.Backoffice.UI/vite.config.js
index e6bb9b36..dbb17055 100644
--- a/zero.Backoffice.UI/vite.config.js
+++ b/zero.Backoffice.UI/vite.config.js
@@ -7,7 +7,8 @@ let loadedPlugins = JSON.parse(process.env.ZERO_PLUGINS || "[]");
if (!process.env.ZERO_PLUGINS)
{
- loadedPlugins = ["../zero.Commerce/Plugin", "../zero.Stories/Plugin", "../zero.Forms/Plugin", "../../Laola/Laola.Backoffice/Plugin"];
+ //loadedPlugins = ["../zero.Commerce/Plugin", "../zero.Stories/Plugin", "../zero.Forms/Plugin", "../../Laola/Laola.Backoffice/Plugin"];
+ loadedPlugins = [];
}
let zeroPlugins = [];
diff --git a/zero.Backoffice/Configuration/BackofficeMaps.cs b/zero.Backoffice/Configuration/BackofficeMaps.cs
new file mode 100644
index 00000000..a9279bca
--- /dev/null
+++ b/zero.Backoffice/Configuration/BackofficeMaps.cs
@@ -0,0 +1,28 @@
+using AutoMapper;
+
+namespace zero.Backoffice.Configuration;
+
+///
+///
+///
+public class BackofficeMaps
+{
+ public MapperConfiguration MapperConfiguration { get; internal set; }
+
+ internal List> Expressions { get; }
+
+
+ public void Configure(Action expression)
+ {
+ Expressions.Add(expression);
+ }
+
+
+ internal void Run(IMapperConfigurationExpression mapperConfig)
+ {
+ foreach (var expression in Expressions)
+ {
+ expression(mapperConfig);
+ }
+ }
+}
\ No newline at end of file
diff --git a/zero.Backoffice/Configuration/BackofficeOptions.cs b/zero.Backoffice/Configuration/BackofficeOptions.cs
index 80b3d59b..68c7b096 100644
--- a/zero.Backoffice/Configuration/BackofficeOptions.cs
+++ b/zero.Backoffice/Configuration/BackofficeOptions.cs
@@ -1,4 +1,6 @@
-using zero.Backoffice.Modules.Search;
+using AutoMapper;
+using System.Linq.Expressions;
+using zero.Backoffice.Modules.Search;
namespace zero.Backoffice.Configuration;
@@ -38,4 +40,9 @@ public class BackofficeOptions
/// Language ISO codes which are supported by the zero backoffice
///
public string[] SupportedLanguages { get; internal set; }
+
+ ///
+ /// Configuration for AutoMapper
+ ///
+ public BackofficeMaps Mapper { get; private set; } = new();
}
\ No newline at end of file
diff --git a/zero.Backoffice/Controllers/ZeroIndexController.cs b/zero.Backoffice/Controllers/ZeroIndexController.cs
index 8ac275b8..56d8095d 100644
--- a/zero.Backoffice/Controllers/ZeroIndexController.cs
+++ b/zero.Backoffice/Controllers/ZeroIndexController.cs
@@ -4,7 +4,7 @@ namespace zero.Backoffice.Controllers;
[ZeroAuthorize(false)]
[DisableBrowserCache]
-public abstract class ZeroIndexController : Controller
+public class ZeroIndexController : Controller
{
IZeroVue ZeroVue { get; set; }
IZeroOptions Options { get; set; }
diff --git a/zero.Backoffice/Modules/Countries/CountriesController.cs b/zero.Backoffice/Modules/Countries/CountriesController.cs
index 1993ac64..266a853b 100644
--- a/zero.Backoffice/Modules/Countries/CountriesController.cs
+++ b/zero.Backoffice/Modules/Countries/CountriesController.cs
@@ -63,7 +63,7 @@ public class CountriesController : ZeroBackofficeApiController
}
- [HttpGet]
+ [HttpGet("")]
[ZeroAuthorize(CountryPermissions.Read)]
public virtual async Task> Get(ListQuery query)
{
@@ -73,7 +73,7 @@ public class CountriesController : ZeroBackofficeApiController
}
- [HttpPost]
+ [HttpPost("")]
[ZeroAuthorize(CountryPermissions.Create)]
public virtual async Task> Create(CountrySave saveModel)
{
diff --git a/zero.Backoffice/Modules/Countries/CountryPermissions.cs b/zero.Backoffice/Modules/Countries/CountryPermissions.cs
index b7c5e72b..be6598bb 100644
--- a/zero.Backoffice/Modules/Countries/CountryPermissions.cs
+++ b/zero.Backoffice/Modules/Countries/CountryPermissions.cs
@@ -2,25 +2,28 @@
public class CountryPermissions : PermissionProvider
{
- public CountryPermissions() : base("@settings.application.countries.name") { }
-
-
- ///
- public override IEnumerable Requires() => new[] { SectionPermissions.Settings, "zero.settings.country" };
-
-
public const string Create = "zero.settings.country.create";
- public const string Read = "zero.settings.country.read";
+ public const string Read = "zero.settings.country.read";
public const string Update = "zero.settings.country.update";
public const string Delete = "zero.settings.country.delete";
- ///
- public override IEnumerable GetPermissions() => new Permission[]
- {
- new(Create, "@permission.states.create"),
- new(Read, "@permission.states.read"),
- new(Update, "@permission.states.update"),
- new(Delete, "@permission.states.delete")
- };
+ public override Task Configure(IPermissionContext context)
+ {
+ if (!context.TryGetGroup(Constants.Permissions.Groups.Settings, out PermissionGroup group))
+ {
+ group.Permissions.Add(new Permission("zero.settings.country", "@settings.application.countries.name")
+ {
+ Children = new()
+ {
+ new(Create, "@permission.states.create"),
+ new(Read, "@permission.states.read"),
+ new(Update, "@permission.states.update"),
+ new(Delete, "@permission.states.delete")
+ }
+ });
+ }
+
+ return Task.CompletedTask;
+ }
}
\ No newline at end of file
diff --git a/zero.Backoffice/Modules/ServiceCollectionExtensions.cs b/zero.Backoffice/Modules/ServiceCollectionExtensions.cs
index acfb8dab..0cf4512b 100644
--- a/zero.Backoffice/Modules/ServiceCollectionExtensions.cs
+++ b/zero.Backoffice/Modules/ServiceCollectionExtensions.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.Configuration;
+using AutoMapper;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using zero.Backoffice.Modules.Countries;
using zero.Backoffice.Modules.Pages;
@@ -22,6 +23,14 @@ public static class ServiceCollectionExtensions
opts.Indexes.Add();
});
+ services.Configure(opts =>
+ {
+ opts.Mapper.Configure(maps =>
+ {
+ maps.AddProfile();
+ });
+ });
+
return services;
}
}
\ No newline at end of file
diff --git a/zero.Backoffice/Plugin.cs b/zero.Backoffice/Plugin.cs
index 3adec97f..e12445ed 100644
--- a/zero.Backoffice/Plugin.cs
+++ b/zero.Backoffice/Plugin.cs
@@ -1,10 +1,12 @@
-using Microsoft.AspNetCore.Hosting;
+using AutoMapper;
+using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using System.IO;
+using zero.Backoffice.Modules;
namespace zero.Backoffice;
@@ -34,12 +36,14 @@ public class ZeroBackofficePlugin : ZeroPlugin
//});
services.AddZeroBackofficeUIComposition();
+ services.AddZeroBackofficeModules(configuration);
//services.AddTransient();
//services.AddTransient();
//services.AddScoped();
+
PostConfigureServices?.Invoke(services, configuration);
}
diff --git a/zero.Backoffice/ServiceCollectionExtensions.cs b/zero.Backoffice/ServiceCollectionExtensions.cs
index fd1a617f..ec0089f5 100644
--- a/zero.Backoffice/ServiceCollectionExtensions.cs
+++ b/zero.Backoffice/ServiceCollectionExtensions.cs
@@ -6,7 +6,7 @@ public static class ServiceCollectionExtensions
{
public static ZeroBuilder AddBackoffice(this ZeroBuilder builder) where T : ZeroBackofficePlugin, IZeroPlugin, new()
{
- return builder.AddBackoffice();
+ return builder.AddBackoffice(_ => { });
}
public static ZeroBuilder AddBackoffice(this ZeroBuilder builder)
@@ -27,9 +27,4 @@ public static class ServiceCollectionExtensions
return plugin;
});
}
-
- public static ZeroBuilder AddStories(this ZeroBuilder builder, Action options)
- {
- return builder.AddBackoffice(options);
- }
}
\ No newline at end of file
diff --git a/zero.Backoffice/UIComposition/Sections/SectionPermissions.cs b/zero.Backoffice/UIComposition/Sections/SectionPermissions.cs
index 9a8d496d..869dc88c 100644
--- a/zero.Backoffice/UIComposition/Sections/SectionPermissions.cs
+++ b/zero.Backoffice/UIComposition/Sections/SectionPermissions.cs
@@ -2,22 +2,32 @@
public class SectionPermissions : PermissionProvider
{
- public SectionPermissions() : base("@permissions.collections.sections") { }
-
- public const string Dashboard = "zero.sections.dashboard";
- public const string Pages = "zero.sections.pages";
- public const string Spaces = "zero.sections.spaces";
- public const string Media = "zero.sections.media";
- public const string Settings = "zero.sections.settings";
+ protected IEnumerable Sections { get; private set; }
- ///
- public override IEnumerable GetPermissions() => new Permission[]
- {
- new(Dashboard, "@sections.item.dashboard"),
- new(Pages, "@sections.item.pages"),
- new(Spaces, "@sections.item.spaces"),
- new(Media, "@sections.item.media"),
- new(Settings, "@sections.item.settings")
- };
+ public SectionPermissions(IEnumerable sections)
+ {
+ Sections = sections;
+ }
+
+
+ public override Task Configure(IPermissionContext context)
+ {
+ PermissionGroup group = new("zero.sections", "@permissions.collections.sections");
+
+ foreach (IBackofficeSection section in Sections)
+ {
+ Permission permission = new("zero.sections." + section.Alias, section.Name);
+
+ foreach (IChildBackofficeSection child in section.Children)
+ {
+ Permission childPermission = new(permission.Key + "." + child.Alias, child.Name);
+ permission.Children.Add(childPermission);
+ }
+
+ group.Add(permission);
+ }
+
+ return Task.CompletedTask;
+ }
}
\ No newline at end of file
diff --git a/zero.Backoffice/UIComposition/Settings/SettingsPermissions.cs b/zero.Backoffice/UIComposition/Settings/SettingsPermissions.cs
index 3507659d..57b0a1a6 100644
--- a/zero.Backoffice/UIComposition/Settings/SettingsPermissions.cs
+++ b/zero.Backoffice/UIComposition/Settings/SettingsPermissions.cs
@@ -2,24 +2,24 @@
public class SettingsPermissions : PermissionProvider
{
- public SettingsPermissions() : base("@permissions.collections.settings") { }
+ //public SettingsPermissions() : base("@permissions.collections.settings") { }
- public const string Dashboard = "zero.sections.dashboard";
- public const string Pages = "zero.sections.pages";
- public const string Spaces = "zero.sections.spaces";
- public const string Media = "zero.sections.media";
- public const string Settings = "zero.sections.settings";
+ //public const string Dashboard = "zero.sections.dashboard";
+ //public const string Pages = "zero.sections.pages";
+ //public const string Spaces = "zero.sections.spaces";
+ //public const string Media = "zero.sections.media";
+ //public const string Settings = "zero.sections.settings";
- ///
- public override IEnumerable GetPermissions() => new Permission[]
- {
- new(Dashboard, "@sections.item.dashboard"),
- new(Pages, "@sections.item.pages"),
- new(Spaces, "@sections.item.spaces"),
- new(Media, "@sections.item.media"),
- new(Settings, "@sections.item.settings")
- };
+ /////
+ //public override IEnumerable GetPermissions() => new Permission[]
+ //{
+ // new(Dashboard, "@sections.item.dashboard"),
+ // new(Pages, "@sections.item.pages"),
+ // new(Spaces, "@sections.item.spaces"),
+ // new(Media, "@sections.item.media"),
+ // new(Settings, "@sections.item.settings")
+ //};
}
//namespace zero.Backoffice.UIComposition;
diff --git a/zero.Core/Configuration/Constants.cs b/zero.Core/Configuration/Constants.cs
index d99d12f9..00e8bf1c 100644
--- a/zero.Core/Configuration/Constants.cs
+++ b/zero.Core/Configuration/Constants.cs
@@ -13,7 +13,7 @@ public static class Constants
{
public const string SystemUser = "system";
public const string DefaultScheme = "zeroScheme";
- public const string BackofficeDisplayName = "Zero Bacckoffice";
+ public const string BackofficeDisplayName = "Zero Backoffice";
public const string BackofficeScheme = "zeroBackoffice";
public const string BackofficeCookieName = "zero.be.session";
public const string DefaultCookieName = "zero.session";
@@ -34,10 +34,23 @@ public static class Constants
}
}
+
+ public static class Permissions
+ {
+ public static class Groups
+ {
+ public const string Sections = "zero.permissions.groups.sections";
+ public const string Spaces = "zero.permissions.groups.spaces";
+ public const string Settings = "zero.permissions.groups.settings";
+ public const string Pages = "zero.permissions.groups.pages";
+ public const string Modules = "zero.permissions.groups.modules";
+ }
+ }
+
+
public static class Database
{
public const string ReservationPrefix = "zero.";
- public const string CoreIdPrefix = "core.";
public const string Expires = Raven.Client.Constants.Documents.Metadata.Expires;
}
diff --git a/zero.Core/Configuration/ServiceCollectionExtensions.cs b/zero.Core/Configuration/ServiceCollectionExtensions.cs
index 8fe4f28a..bc1f6341 100644
--- a/zero.Core/Configuration/ServiceCollectionExtensions.cs
+++ b/zero.Core/Configuration/ServiceCollectionExtensions.cs
@@ -8,13 +8,14 @@ internal static class ServiceCollectionExtensions
{
public static IServiceCollection AddZeroConfiguration(this IServiceCollection services, IConfiguration config)
{
- services.AddOptions().Bind(config.GetSection("Zero")).Configure(opts =>
+ services.AddOptions().Configure((opts, svc) =>
{
+ opts.ServiceProvider = svc;
opts.Version = "0.0.1-alpha.1";
opts.ZeroPath = "/zero";
- opts.TokenExpiration = TimeSpan.FromHours(3);
- });
- services.AddTransient(factory => factory.GetService>().CurrentValue);
+ opts.TokenExpiration = TimeSpan.FromHours(3);
+ }).Bind(config.GetSection("Zero"));
+ services.AddTransient(factory => factory.GetService>().Value);
services.AddOptions().Bind(config.GetSection("Zero:Features"));
diff --git a/zero.Core/Configuration/ZeroOptions.cs b/zero.Core/Configuration/ZeroOptions.cs
index 1960ecf8..52ff5455 100644
--- a/zero.Core/Configuration/ZeroOptions.cs
+++ b/zero.Core/Configuration/ZeroOptions.cs
@@ -19,17 +19,11 @@ public class ZeroOptions : IZeroOptions
public TimeSpan TokenExpiration { get; set; }
- protected IServiceProvider ServiceProvider { get; set; }
+ internal IServiceProvider ServiceProvider { get; set; }
protected ConcurrentDictionary OptionsCache { get; private set; } = new();
- public ZeroOptions(IServiceProvider serviceProvider)
- {
- ServiceProvider = serviceProvider;
- }
-
-
///
public TOptions For() where TOptions : class
{
diff --git a/zero.Core/Identity/Permissions/Permission.cs b/zero.Core/Identity/Permissions/Permission.cs
index 554d13a8..d6e6e18a 100644
--- a/zero.Core/Identity/Permissions/Permission.cs
+++ b/zero.Core/Identity/Permissions/Permission.cs
@@ -14,11 +14,23 @@ public struct Permission
///
public string Label { get; set; }
+ ///
+ /// When a permission is disabled it can not be updated anymore
+ ///
+ public bool IsDisabled { get; set; }
+
+ ///
+ /// Child permissions
+ ///
+ public HashSet Children { get; set; }
+
public Permission(string key, string label)
{
Key = key;
Label = label;
+ IsDisabled = false;
+ Children = new();
}
/////
diff --git a/zero.Core/Identity/Permissions/PermissionContext.cs b/zero.Core/Identity/Permissions/PermissionContext.cs
new file mode 100644
index 00000000..f5815f91
--- /dev/null
+++ b/zero.Core/Identity/Permissions/PermissionContext.cs
@@ -0,0 +1,80 @@
+namespace zero.Identity;
+
+public class PermissionContext : IPermissionContext
+{
+ ///
+ public HashSet Groups { get; protected set; }
+
+ ///
+ public IZeroOptions Options { get; protected set; }
+
+
+ public PermissionContext(IZeroOptions options)
+ {
+ Groups = new();
+ Options = options;
+ }
+
+
+ ///
+ public PermissionGroup? GetGroup(string key)
+ {
+ return Groups.FirstOrDefault(x => x.Key == key);
+ }
+
+
+ ///
+ public bool TryGetGroup(string key, out PermissionGroup group)
+ {
+ group = Groups.FirstOrDefault(x => x.Key == key);
+ return Groups.Contains(group);
+ }
+
+
+ ///
+ public void AddGroup(PermissionGroup group)
+ {
+ Groups.Add(group);
+ }
+
+
+ ///
+ public void RemoveGroup(PermissionGroup group)
+ {
+ Groups.Remove(group);
+ }
+}
+
+
+public interface IPermissionContext
+{
+ ///
+ /// All registered permission groups
+ ///
+ HashSet Groups { get; }
+
+ ///
+ /// Zero options
+ ///
+ IZeroOptions Options { get; }
+
+ ///
+ /// Try to get a permission group by key
+ ///
+ PermissionGroup? GetGroup(string key);
+
+ ///
+ /// Get permission group by key
+ ///
+ bool TryGetGroup(string key, out PermissionGroup group);
+
+ ///
+ /// Add a new permission group to the context
+ ///
+ void AddGroup(PermissionGroup group);
+
+ ///
+ /// Remove a permission group from the context
+ ///
+ void RemoveGroup(PermissionGroup group);
+}
\ No newline at end of file
diff --git a/zero.Core/Identity/Permissions/PermissionGroup.cs b/zero.Core/Identity/Permissions/PermissionGroup.cs
new file mode 100644
index 00000000..50375634
--- /dev/null
+++ b/zero.Core/Identity/Permissions/PermissionGroup.cs
@@ -0,0 +1,63 @@
+namespace zero.Identity;
+
+public struct PermissionGroup
+{
+ ///
+ /// Full key of the group
+ ///
+ public string Key { get; set; }
+
+ ///
+ /// Title of this permission group for output
+ ///
+ public string Label { get; set; }
+
+ ///
+ /// Permissions for this group
+ ///
+ public HashSet Permissions { get; set; }
+
+
+ public PermissionGroup(string key, string label)
+ {
+ Key = key;
+ Label = label;
+ Permissions = new();
+ }
+
+
+ ///
+ /// Add a new permission to this group
+ ///
+ public void Add(Permission permission)
+ {
+ Permissions.Add(permission);
+ }
+
+
+ ///
+ /// Remove a permission
+ ///
+ public void Remove(Permission permission)
+ {
+ Permissions.Remove(permission);
+ }
+
+
+ ///
+ /// Get permission by key
+ ///
+ public Permission? Get(string key)
+ {
+ return Permissions.FirstOrDefault(x => x.Key == key);
+ }
+
+
+ ///
+ /// Get permission by key
+ ///
+ public object this[string key]
+ {
+ get => Permissions.FirstOrDefault(x => x.Key == key);
+ }
+}
\ No newline at end of file
diff --git a/zero.Core/Identity/Permissions/PermissionProvider.cs b/zero.Core/Identity/Permissions/PermissionProvider.cs
index 2769a58f..b5b9449f 100644
--- a/zero.Core/Identity/Permissions/PermissionProvider.cs
+++ b/zero.Core/Identity/Permissions/PermissionProvider.cs
@@ -3,47 +3,19 @@
public abstract class PermissionProvider : IPermissionProvider
{
///
- public string Name { get; private set; }
-
-
- public PermissionProvider(string name)
- {
- Name = name;
- }
-
- ///
- public virtual IEnumerable Requires() => Array.Empty();
-
- ///
- public virtual IEnumerable GetPermissions() => Array.Empty();
-
-
- ///
- public virtual Task> GetPermissionsAsync() => Task.FromResult(GetPermissions());
+ public virtual Task Configure(IPermissionContext context) => Task.CompletedTask;
}
public interface IPermissionProvider
{
///
- /// Name (can be a localization) which is displayed in the permission group
+ /// Manage permissions (add/remove/update permission groups and containing permissions)
///
- string Name { get; }
+ Task Configure(IPermissionContext context);
///
/// In order for this permissions to work, the specified provider requires the following permission
///
- IEnumerable Requires() => Array.Empty();
-
- ///
- /// Get all permissions for this provider.
- /// These permissions can be granted to roles or individual users.
- ///
- IEnumerable GetPermissions();
-
- ///
- /// Get all permissions for this provider.
- /// These permissions can be granted to roles or individual users.
- ///
- Task> GetPermissionsAsync();
+ //IEnumerable Requires() => Array.Empty();
}
\ No newline at end of file
diff --git a/zero.Core/Identity/ServiceCollectionExtensions.cs b/zero.Core/Identity/ServiceCollectionExtensions.cs
index 76ff8c85..f0019b4a 100644
--- a/zero.Core/Identity/ServiceCollectionExtensions.cs
+++ b/zero.Core/Identity/ServiceCollectionExtensions.cs
@@ -22,8 +22,8 @@ internal static class ServiceCollectionExtensions
services.AddScoped();
services.AddScoped();
- services.AddAuthentication(Constants.Auth.BackofficeScheme);
- //.AddZeroBackofficeCookie(); // TODO
+ services.AddAuthentication(Constants.Auth.BackofficeScheme)
+ .AddZeroBackofficeCookie();
services.AddAuthorization();
return services;
diff --git a/zero.Core/Identity/ZeroIdentityExtensions.cs b/zero.Core/Identity/ZeroIdentityExtensions.cs
index 8c2c29be..c3733419 100644
--- a/zero.Core/Identity/ZeroIdentityExtensions.cs
+++ b/zero.Core/Identity/ZeroIdentityExtensions.cs
@@ -12,7 +12,7 @@ public static class ZeroIdentityExtensions
{
services.AddZeroIdentityCore();
- IdentityBuilder builder = new IdentityBuilder(typeof(TUser), typeof(TRole), services);
+ IdentityBuilder builder = new(typeof(TUser), typeof(TRole), services);
builder.AddDefaultTokenProviders();
@@ -33,7 +33,7 @@ public static class ZeroIdentityExtensions
{
services.AddZeroIdentityCore();
- IdentityBuilder builder = new IdentityBuilder(typeof(TUser), services);
+ IdentityBuilder builder = new(typeof(TUser), services);
builder.AddDefaultTokenProviders();
builder.AddUserStore>();
diff --git a/zero.Core/ZeroBuilder.cs b/zero.Core/ZeroBuilder.cs
index bb32b1d6..7e71990f 100644
--- a/zero.Core/ZeroBuilder.cs
+++ b/zero.Core/ZeroBuilder.cs
@@ -28,6 +28,8 @@ public class ZeroBuilder
StartupOptions.AssemblyDiscoveryRules.Add(new ZeroAssemblyDiscoveryRule());
setupAction?.Invoke(StartupOptions);
+ services.AddControllers();
+
// adds and discovers additional and built-in assemblies
new AssemblyDiscovery(Mvc).Execute(StartupOptions.AssemblyDiscoveryRules);