diff --git a/docs/en/Samples/Microservice-Demo.md b/docs/en/Samples/Microservice-Demo.md
index 4edebfbe03..bc3c8c0933 100644
--- a/docs/en/Samples/Microservice-Demo.md
+++ b/docs/en/Samples/Microservice-Demo.md
@@ -168,7 +168,7 @@ These are the actual applications those have user interfaces to interact to the
- **AuthServer.Host**: Host the IdentityServer4 to provide an authentication service to other services and applications. It is a single-sign server and contains the login page.
- **BackendAdminApp.Host**: This is a backend admin application that host UI for Identity and Product management modules.
-- **PubicWebSite.Host**: As public web site that contains a simple product list page and blog module UI.
+- **PublicWebSite.Host**: As public web site that contains a simple product list page and blog module UI.
- **ConsoleClientDemo**: A simple console application to demonstrate the usage of services from a C# application.
### Gateways / BFFs (Backend for Frontend)
@@ -1471,4 +1471,4 @@ ABP provides automatic audit logging which saves every request in detail (who is
All of the services and applications are configured to write audit logs. Audit logs are saved to the MsDemo_Identity SQL database. So, you can query all audit logs of all applications from a single point.
-An Audit Log record has a `CorrelationId` property that can be used to track a request. When a service calls another service in a single web request, they both save audit logs with the same `CorrelationId`. See the `AbpAuditLogs` table in the database.
\ No newline at end of file
+An Audit Log record has a `CorrelationId` property that can be used to track a request. When a service calls another service in a single web request, they both save audit logs with the same `CorrelationId`. See the `AbpAuditLogs` table in the database.
diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln
index bed907269c..be77f0ab24 100644
--- a/framework/Volo.Abp.sln
+++ b/framework/Volo.Abp.sln
@@ -234,6 +234,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Specifications.Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Cli.Core.Tests", "test\Volo.Abp.Cli.Core.Tests\Volo.Abp.Cli.Core.Tests.csproj", "{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Widgets", "src\Volo.Abp.AspNetCore.Mvc.UI.Widgets\Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj", "{EE1AAB08-3FBD-487F-B0B4-BEBA4B69528A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Dashboards", "src\Volo.Abp.AspNetCore.Mvc.UI.Dashboards\Volo.Abp.AspNetCore.Mvc.UI.Dashboards.csproj", "{054D766D-5992-460E-A4D8-936D80BE2C1A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -696,6 +700,14 @@ Global
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EE1AAB08-3FBD-487F-B0B4-BEBA4B69528A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EE1AAB08-3FBD-487F-B0B4-BEBA4B69528A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EE1AAB08-3FBD-487F-B0B4-BEBA4B69528A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EE1AAB08-3FBD-487F-B0B4-BEBA4B69528A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {054D766D-5992-460E-A4D8-936D80BE2C1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {054D766D-5992-460E-A4D8-936D80BE2C1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {054D766D-5992-460E-A4D8-936D80BE2C1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {054D766D-5992-460E-A4D8-936D80BE2C1A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -815,6 +827,8 @@ Global
{2C621EED-563C-4F81-A75E-50879E173544} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{D078553A-C70C-4F56-B3E2-9C5BA6384C72} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA} = {447C8A77-E5F0-4538-8687-7383196D04EA}
+ {EE1AAB08-3FBD-487F-B0B4-BEBA4B69528A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
+ {054D766D-5992-460E-A4D8-936D80BE2C1A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/AbpAspNetCoreMvcUiBundlingModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/AbpAspNetCoreMvcUiBundlingModule.cs
index 714a7aa68b..a0f0e65f1e 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/AbpAspNetCoreMvcUiBundlingModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/AbpAspNetCoreMvcUiBundlingModule.cs
@@ -1,5 +1,4 @@
-using Microsoft.Extensions.DependencyInjection;
-using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
+using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Properties/launchSettings.json b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Properties/launchSettings.json
new file mode 100644
index 0000000000..0ce91a367d
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Properties/launchSettings.json
@@ -0,0 +1,27 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:57333/",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "Volo.Abp.AspNetCore.Mvc.UI.Dashboards": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "http://localhost:57343/"
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo.Abp.AspNetCore.Mvc.UI.Dashboards.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo.Abp.AspNetCore.Mvc.UI.Dashboards.csproj
new file mode 100644
index 0000000000..c2e85e8239
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo.Abp.AspNetCore.Mvc.UI.Dashboards.csproj
@@ -0,0 +1,34 @@
+
+
+
+
+
+ netstandard2.0
+ Volo.Abp.AspNetCore.Mvc.UI.Dashboards
+ Volo.Abp.AspNetCore.Mvc.UI.Dashboards
+ $(AssetTargetFallback);portable-net45+win8+wp8+wpa81;
+ false
+ false
+ false
+ true
+ Library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/AbpAspNetCoreMvcUiDashboardsModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/AbpAspNetCoreMvcUiDashboardsModule.cs
new file mode 100644
index 0000000000..6fcb11d28e
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/AbpAspNetCoreMvcUiDashboardsModule.cs
@@ -0,0 +1,20 @@
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+using Volo.Abp.Modularity;
+using Volo.Abp.VirtualFileSystem;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
+{
+ [DependsOn(
+ typeof(AbpAspNetCoreMvcUiWidgetsModule)
+ )]
+ public class AbpAspNetCoreMvcUiDashboardsModule : AbpModule
+ {
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewComponent.cshtml.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewComponent.cshtml.cs
new file mode 100644
index 0000000000..01d14cb7f1
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewComponent.cshtml.cs
@@ -0,0 +1,17 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard
+{
+ public class DashboardViewComponent : AbpViewComponent
+ {
+ public async Task InvokeAsync(string dashboardName, DashboardOptions dashboardOptions, WidgetOptions widgetOptions)
+ {
+ var model = new DashboardViewModel(dashboardName, dashboardOptions, widgetOptions);
+ return View("~/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml", model);
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewModel.cs
new file mode 100644
index 0000000000..4658078a3a
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/DashboardViewModel.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard
+{
+ public class DashboardViewModel
+ {
+ public DashboardDefinition Dashboard { get; set; }
+ public DashboardOptions DashboardOptions { get; set; }
+ public WidgetOptions WidgetOptions { get; set; }
+
+ public DashboardViewModel(string dashboardName, DashboardOptions dashboardOptions, WidgetOptions widgetOptions)
+ {
+ Dashboard = dashboardOptions.Dashboards.Single(d => d.Name.Equals(dashboardName));
+ DashboardOptions = dashboardOptions;
+ WidgetOptions = widgetOptions;
+ }
+
+ public WidgetDefinition GetWidget(string name)
+ {
+ return WidgetOptions.Widgets.Single(d => d.Name.Equals(name));
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml
new file mode 100644
index 0000000000..524bf6d79e
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml
@@ -0,0 +1,21 @@
+@using Microsoft.Extensions.Localization
+@using Volo.Abp.AspNetCore.Mvc.UI.Widgets
+@inject IWidgetRenderer WidgetRenderer
+@inject IStringLocalizerFactory localizer
+@model Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard.DashboardViewModel
+@{
+}
+
+ @foreach (var widgetConfiguration in Model.Dashboard.AvailableWidgets)
+ {
+ var widgetDefinition = Model.GetWidget(widgetConfiguration.WidgetName);
+ widgetDefinition.DefaultDimensions = widgetConfiguration.Dimensions ?? widgetDefinition.DefaultDimensions ?? new WidgetDimensions(5, 5);
+
+
+
+ @await WidgetRenderer.RenderAsync(Component, widgetDefinition.Name)
+
+ }
+
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardDefinition.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardDefinition.cs
new file mode 100644
index 0000000000..20f8da6b75
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardDefinition.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using JetBrains.Annotations;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+using Volo.Abp.Localization;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
+{
+ public class DashboardDefinition
+ {
+ ///
+ /// Unique name of the dashboard.
+ ///
+ [NotNull]
+ public string Name { get; }
+
+ ///
+ /// A list of Widgets available for this dashboard.
+ ///
+ public List AvailableWidgets { get; }
+
+ ///
+ /// Display name of the widget.
+ ///
+ [NotNull]
+ public ILocalizableString DisplayName
+ {
+ get => _displayName;
+ set => _displayName = Check.NotNull(value, nameof(value));
+ }
+ private ILocalizableString _displayName;
+
+ public DashboardDefinition(
+ [NotNull] string name,
+ [CanBeNull] ILocalizableString displayName)
+ {
+ Name = Check.NotNullOrWhiteSpace(name, nameof(name));
+ DisplayName = displayName ?? new FixedLocalizableString(name);
+
+ AvailableWidgets = new List();
+ }
+
+ public DashboardDefinition WithWidget(string widgetName, WidgetLocation location = null, WidgetDimensions dimensions = null)
+ {
+ AvailableWidgets.Add( new DashboardWidgetConfiguration(widgetName, dimensions, location));
+
+ return this;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardOptions.cs
new file mode 100644
index 0000000000..fc3ca09b74
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardOptions.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
+{
+ public class DashboardOptions
+ {
+ public List Dashboards { get; }
+
+ public DashboardOptions()
+ {
+ Dashboards = new List();
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardRenderer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardRenderer.cs
new file mode 100644
index 0000000000..d35c58f0e2
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardRenderer.cs
@@ -0,0 +1,15 @@
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Html;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
+{
+ public class DashboardRenderer : IDashboardRenderer
+ {
+ public async Task RenderAsync(IViewComponentHelper componentHelper, object args = null)
+ {
+ return await componentHelper.InvokeAsync(typeof(DashboardViewComponent), args ?? new object());
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardWidgetConfiguration.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardWidgetConfiguration.cs
new file mode 100644
index 0000000000..74a20bc877
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/DashboardWidgetConfiguration.cs
@@ -0,0 +1,28 @@
+using JetBrains.Annotations;
+using Volo.Abp.AspNetCore.Mvc.UI.Widgets;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
+{
+ public class DashboardWidgetConfiguration
+ {
+ [NotNull]
+ public string WidgetName { get; }
+
+ [CanBeNull]
+ public WidgetDimensions Dimensions { get; set; }
+
+ [CanBeNull]
+ public WidgetLocation Location { get; set; }
+
+ public DashboardWidgetConfiguration(
+ [NotNull] string widgetName,
+ [CanBeNull] WidgetDimensions dimensions = null,
+ [CanBeNull] WidgetLocation location = null
+ )
+ {
+ WidgetName = Check.NotNullOrWhiteSpace(widgetName, nameof(widgetName));
+ Dimensions = dimensions;
+ Location = location;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/IDashboardRenderer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/IDashboardRenderer.cs
new file mode 100644
index 0000000000..64e149696f
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/IDashboardRenderer.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Html;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
+{
+ public interface IDashboardRenderer : ITransientDependency
+ {
+ Task RenderAsync(IViewComponentHelper componentHelper, object args = null);
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/WidgetLocation.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/WidgetLocation.cs
new file mode 100644
index 0000000000..7ce21a342e
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/WidgetLocation.cs
@@ -0,0 +1,15 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
+{
+ public class WidgetLocation
+ {
+ public int X { get; set; }
+
+ public int Y { get; set; }
+
+ public WidgetLocation(int x, int y)
+ {
+ X = x;
+ Y = y;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/_ViewImports.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/_ViewImports.cshtml
new file mode 100644
index 0000000000..225780c2c2
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/_ViewImports.cshtml
@@ -0,0 +1,3 @@
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
+@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
+@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs
index bab248f669..ec82d4b3d6 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages/Volo/Abp/AspNetCore/Mvc/UI/Packages/AbpAspNetCoreMvcUiPackagesModule.cs
@@ -1,5 +1,4 @@
-using Microsoft.Extensions.DependencyInjection;
-using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
+using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj
new file mode 100644
index 0000000000..26634c6270
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo.Abp.AspNetCore.Mvc.UI.Widgets.csproj
@@ -0,0 +1,16 @@
+
+
+
+
+
+ netstandard2.0
+ Volo.Abp.AspNetCore.Mvc.UI.Widgets
+ Volo.Abp.AspNetCore.Mvc.UI.Widgets
+
+
+
+
+
+
+
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs
new file mode 100644
index 0000000000..cdf1db75cd
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/AbpAspNetCoreMvcUiWidgetsModule.cs
@@ -0,0 +1,13 @@
+using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
+using Volo.Abp.Modularity;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets
+{
+ [DependsOn(
+ typeof(AbpAspNetCoreMvcUiBootstrapModule)
+ )]
+ public class AbpAspNetCoreMvcUiWidgetsModule : AbpModule
+ {
+
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/IWidgetRenderer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/IWidgetRenderer.cs
new file mode 100644
index 0000000000..ab3c4ee09f
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/IWidgetRenderer.cs
@@ -0,0 +1,12 @@
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Html;
+using Microsoft.AspNetCore.Mvc;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets
+{
+ public interface IWidgetRenderer : ITransientDependency
+ {
+ Task RenderAsync(IViewComponentHelper componentHelper, string widgetName, object args = null);
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDefinition.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDefinition.cs
new file mode 100644
index 0000000000..2296cfb4e4
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDefinition.cs
@@ -0,0 +1,44 @@
+using System;
+using JetBrains.Annotations;
+using Volo.Abp.Localization;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets
+{
+ public class WidgetDefinition
+ {
+ ///
+ /// Unique name of the widget.
+ ///
+ [NotNull]
+ public string Name { get; }
+
+ ///
+ /// Display name of the widget.
+ ///
+ [NotNull]
+ public ILocalizableString DisplayName
+ {
+ get => _displayName;
+ set => _displayName = Check.NotNull(value, nameof(value));
+ }
+ private ILocalizableString _displayName;
+
+ [NotNull]
+ public Type ViewComponentType { get; }
+
+ [CanBeNull]
+ public WidgetDimensions DefaultDimensions { get; set; }
+
+ public WidgetDefinition(
+ [NotNull] string name,
+ [NotNull] Type viewComponentType,
+ [CanBeNull] ILocalizableString displayName,
+ [CanBeNull] WidgetDimensions defaultDimensions = null)
+ {
+ DefaultDimensions = defaultDimensions;
+ Name = Check.NotNullOrWhiteSpace(name, nameof(name));
+ ViewComponentType = Check.NotNull(viewComponentType, nameof(viewComponentType));
+ DisplayName = displayName ?? new FixedLocalizableString(name);
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDimensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDimensions.cs
new file mode 100644
index 0000000000..eb24d208b4
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetDimensions.cs
@@ -0,0 +1,15 @@
+namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets
+{
+ public class WidgetDimensions
+ {
+ public int Width { get; }
+
+ public int Height { get; }
+
+ public WidgetDimensions(int width, int height)
+ {
+ Width = width;
+ Height = height;
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetOptions.cs
new file mode 100644
index 0000000000..7a4fa3487f
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetOptions.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets
+{
+ public class WidgetOptions
+ {
+ public List Widgets { get; }
+
+ public WidgetOptions()
+ {
+ Widgets = new List();
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetRenderer.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetRenderer.cs
new file mode 100644
index 0000000000..2bb8c58fe9
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets/Volo/Abp/AspNetCore/Mvc/UI/Widgets/WidgetRenderer.cs
@@ -0,0 +1,25 @@
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Html;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+
+namespace Volo.Abp.AspNetCore.Mvc.UI.Widgets
+{
+ public class WidgetRenderer : IWidgetRenderer
+ {
+ private readonly WidgetOptions _widgetOptions;
+
+ public WidgetRenderer(IOptions widgetOptions)
+ {
+ _widgetOptions = widgetOptions.Value;
+ }
+
+ public async Task RenderAsync(IViewComponentHelper componentHelper, string widgetName, object args = null)
+ {
+ var componentType = _widgetOptions.Widgets.Single(w=>w.Name.Equals(widgetName)).ViewComponentType;
+
+ return await componentHelper.InvokeAsync(componentType, args ?? new object());
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/InMemoryBackgroundJobStore.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/InMemoryBackgroundJobStore.cs
index 2e3e8879ec..1dc6d7c700 100644
--- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/InMemoryBackgroundJobStore.cs
+++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/InMemoryBackgroundJobStore.cs
@@ -23,19 +23,19 @@ namespace Volo.Abp.BackgroundJobs
_jobs = new ConcurrentDictionary();
}
- public Task FindAsync(Guid jobId)
+ public virtual Task FindAsync(Guid jobId)
{
return Task.FromResult(_jobs.GetOrDefault(jobId));
}
- public Task InsertAsync(BackgroundJobInfo jobInfo)
+ public virtual Task InsertAsync(BackgroundJobInfo jobInfo)
{
_jobs[jobInfo.Id] = jobInfo;
return Task.FromResult(0);
}
- public Task> GetWaitingJobsAsync(int maxResultCount)
+ public virtual Task> GetWaitingJobsAsync(int maxResultCount)
{
var waitingJobs = _jobs.Values
.Where(t => !t.IsAbandoned && t.NextTryTime <= Clock.Now)
@@ -48,14 +48,14 @@ namespace Volo.Abp.BackgroundJobs
return Task.FromResult(waitingJobs);
}
- public Task DeleteAsync(Guid jobId)
+ public virtual Task DeleteAsync(Guid jobId)
{
_jobs.TryRemove(jobId, out _);
return Task.FromResult(0);
}
- public Task UpdateAsync(BackgroundJobInfo jobInfo)
+ public virtual Task UpdateAsync(BackgroundJobInfo jobInfo)
{
if (jobInfo.IsAbandoned)
{
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs
index 50784a8d90..3c2a88094f 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliService.cs
@@ -1,5 +1,8 @@
using System;
+using System.Diagnostics;
+using System.IO;
using System.Reflection;
+using System.Runtime.InteropServices;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -7,6 +10,7 @@ using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.NuGet;
+using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli
@@ -40,7 +44,9 @@ namespace Volo.Abp.Cli
Logger.LogInformation("https://abp.io");
await CheckForNewVersion();
-
+
+ CheckDependencies();
+
var commandLineArgs = CommandLineArgumentParser.Parse(args);
var commandType = CommandSelector.Select(commandLineArgs);
@@ -63,6 +69,61 @@ namespace Volo.Abp.Cli
}
}
+ private void CheckDependencies()
+ {
+ var installedNpmPackages = GetInstalledNpmPackages();
+
+ if (!installedNpmPackages.Contains(" yarn@"))
+ {
+ InstallYarn();
+ }
+ if (!installedNpmPackages.Contains(" gulp@"))
+ {
+ InstallGulp();
+ }
+ }
+
+ private string GetInstalledNpmPackages()
+ {
+ var output = "";
+
+ using (var process = new Process())
+ {
+ process.StartInfo = new ProcessStartInfo(CmdHelper.GetFileName())
+ {
+ Arguments = CmdHelper.GetArguments("npm list -g --depth 0"),
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true
+ };
+ process.Start();
+
+ using (var stdOut = process.StandardOutput)
+ {
+ using (var stdErr = process.StandardError)
+ {
+ output = stdOut.ReadToEnd();
+ output += stdErr.ReadToEnd();
+ }
+ }
+ }
+
+ return output;
+ }
+
+ private void InstallYarn()
+ {
+ Logger.LogInformation("Installing yarn...");
+ CmdHelper.RunCmd("npm install yarn -g");
+ }
+
+ private void InstallGulp()
+ {
+ Logger.LogInformation("Installing gulp...");
+ CmdHelper.RunCmd("npm install gulp -g");
+ }
+
private async Task CheckForNewVersion()
{
try
@@ -86,7 +147,7 @@ namespace Volo.Abp.Cli
Logger.LogWarning(e.Message);
}
}
-
+
private static string GetCliVersion()
{
var version = typeof(CliService)
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationAdder.cs
index d3178adcb3..d3c324431b 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationAdder.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationAdder.cs
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
+using Volo.Abp.Cli.Utils;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Cli.ProjectModification
@@ -12,8 +13,7 @@ namespace Volo.Abp.Cli.ProjectModification
var moduleName = ParseModuleName(module);
var migrationName = "Added_" + moduleName + "_Module" + GetUniquePostFix();
- var process = Process.Start("CMD.exe", "/C cd \"" + Path.GetDirectoryName(csprojFile) + "\" & dotnet ef migrations add " + migrationName);
- process.WaitForExit();
+ CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(csprojFile) + "\" & dotnet ef migrations add " + migrationName);
if (updateDatabase)
{
@@ -23,8 +23,7 @@ namespace Volo.Abp.Cli.ProjectModification
protected void UpdateDatabase(string csprojFile)
{
- var process = Process.Start("CMD.exe", "/C cd \"" + Path.GetDirectoryName(csprojFile) + "\" & dotnet ef database update");
- process.WaitForExit();
+ CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(csprojFile) + "\" & dotnet ef database update");
}
protected virtual string ParseModuleName(string fullModuleName)
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs
index 01a0f00af0..c9225b62f0 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Utils/CmdHelper.cs
@@ -1,4 +1,5 @@
using System.Diagnostics;
+using System.Runtime.InteropServices;
namespace Volo.Abp.Cli.Utils
{
@@ -12,8 +13,31 @@ namespace Volo.Abp.Cli.Utils
public static void RunCmd(string command)
{
- var procStartInfo = new ProcessStartInfo("cmd.exe", "/C " + command);
+ var procStartInfo = new ProcessStartInfo(GetFileName(), GetArguments(command));
Process.Start(procStartInfo).WaitForExit();
}
+
+ public static string GetArguments(string command)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return "-c \"" + command + "\"";
+ }
+
+ //Windows default.
+ return "/C \"" + command + "\"";
+ }
+
+ public static string GetFileName()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ //TODO: Test this. it should work for both operaion systems.
+ return "/bin/bash";
+ }
+
+ //Windows default.
+ return "cmd.exe";
+ }
}
}
diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AsyncCrudAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AsyncCrudAppService.cs
index 4cc9f48630..151212925a 100644
--- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AsyncCrudAppService.cs
+++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/AsyncCrudAppService.cs
@@ -91,7 +91,7 @@ namespace Volo.Abp.Application.Services
var entity = MapToEntity(input);
- if(entity is IMultiTenant)
+ if(entity is IMultiTenant && !HasTenantIdProperty(entity))
{
TryToSetTenantId(entity);
}
diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs
index 744d472de5..2595bc6edd 100644
--- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs
+++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs
@@ -88,7 +88,7 @@ namespace Volo.Abp.Application.Services
var entity = MapToEntity(input);
- if(entity is IMultiTenant)
+ if(entity is IMultiTenant && !HasTenantIdProperty(entity))
{
TryToSetTenantId(entity);
}
diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppServiceBase.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppServiceBase.cs
index 638375524c..b678362c53 100644
--- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppServiceBase.cs
+++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppServiceBase.cs
@@ -156,7 +156,7 @@ namespace Volo.Abp.Application.Services
{
var tenantId = CurrentTenant.Id;
- if (tenantId == null)
+ if (!tenantId.HasValue)
{
return;
}
@@ -168,5 +168,10 @@ namespace Volo.Abp.Application.Services
propertyInfo.SetValue(entity, tenantId, null);
}
}
+
+ protected virtual bool HasTenantIdProperty(TEntity entity)
+ {
+ return entity.GetType().GetProperty(nameof(IMultiTenant.TenantId)) != null;
+ }
}
}
diff --git a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs
index 5277b5f4f4..fed3718f85 100644
--- a/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs
+++ b/modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain/Volo/Abp/BackgroundJobs/BackgroundJobStore.cs
@@ -19,33 +19,33 @@ namespace Volo.Abp.BackgroundJobs
BackgroundJobRepository = backgroundJobRepository;
}
- public async Task FindAsync(Guid jobId)
+ public virtual async Task FindAsync(Guid jobId)
{
return ObjectMapper.Map(
await BackgroundJobRepository.FindAsync(jobId)
);
}
- public async Task InsertAsync(BackgroundJobInfo jobInfo)
+ public virtual async Task InsertAsync(BackgroundJobInfo jobInfo)
{
await BackgroundJobRepository.InsertAsync(
ObjectMapper.Map(jobInfo)
);
}
- public async Task> GetWaitingJobsAsync(int maxResultCount)
+ public virtual async Task> GetWaitingJobsAsync(int maxResultCount)
{
return ObjectMapper.Map, List>(
await BackgroundJobRepository.GetWaitingListAsync(maxResultCount)
);
}
- public async Task DeleteAsync(Guid jobId)
+ public virtual async Task DeleteAsync(Guid jobId)
{
await BackgroundJobRepository.DeleteAsync(jobId);
}
- public async Task UpdateAsync(BackgroundJobInfo jobInfo)
+ public virtual async Task UpdateAsync(BackgroundJobInfo jobInfo)
{
await BackgroundJobRepository.UpdateAsync(
ObjectMapper.Map(jobInfo)
diff --git a/modules/docs/app/VoloDocs.Migrator/Dockerfile b/modules/docs/app/VoloDocs.Migrator/Dockerfile
new file mode 100644
index 0000000000..13554ea58a
--- /dev/null
+++ b/modules/docs/app/VoloDocs.Migrator/Dockerfile
@@ -0,0 +1,18 @@
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine AS base
+WORKDIR /app
+EXPOSE 80
+
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS build
+WORKDIR /src
+COPY . .
+WORKDIR "/src/modules/docs/app/VoloDocs.Migrator"
+RUN dotnet restore -nowarn:msb3202,nu1503
+RUN dotnet build --no-restore -c Release -o /app
+
+FROM build AS publish
+RUN dotnet publish --no-restore -c Release -o /app
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app .
+ENTRYPOINT ["dotnet", "VoloDocs.Migrator.dll"]
diff --git a/modules/docs/app/VoloDocs.Web/Dockerfile b/modules/docs/app/VoloDocs.Web/Dockerfile
new file mode 100644
index 0000000000..49d1d70f46
--- /dev/null
+++ b/modules/docs/app/VoloDocs.Web/Dockerfile
@@ -0,0 +1,18 @@
+FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine AS base
+WORKDIR /app
+EXPOSE 80
+
+FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS build
+WORKDIR /src
+COPY . .
+WORKDIR "/src/modules/docs/app/VoloDocs.Web"
+RUN dotnet restore -nowarn:msb3202,nu1503
+RUN dotnet build --no-restore -c Release -o /app
+
+FROM build AS publish
+RUN dotnet publish --no-restore -c Release -o /app
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app .
+ENTRYPOINT ["dotnet", "VoloDocs.Web.dll"]
diff --git a/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml b/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml
index 4ac9f376ad..3cc5408311 100644
--- a/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml
+++ b/modules/docs/app/VoloDocs.Web/Pages/Index.cshtml
@@ -12,7 +12,6 @@
@section styles {
-
}
diff --git a/modules/docs/docker-compose.migrate.yml b/modules/docs/docker-compose.migrate.yml
new file mode 100644
index 0000000000..e88580debd
--- /dev/null
+++ b/modules/docs/docker-compose.migrate.yml
@@ -0,0 +1,12 @@
+version: '3.4'
+
+services:
+ volo-docs-migrator:
+ image: 'volosoft/volo-docs-migrator:${TAG:-latest}'
+ build:
+ context: ../../
+ dockerfile: modules/docs/app/VoloDocs.Migrator/Dockerfile
+ environment:
+ - ConnectionString=Server=sqlserver;Database=VoloDocs;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false
+ depends_on:
+ - sqlserver
diff --git a/modules/docs/docker-compose.override.yml b/modules/docs/docker-compose.override.yml
new file mode 100644
index 0000000000..6a8568ce6e
--- /dev/null
+++ b/modules/docs/docker-compose.override.yml
@@ -0,0 +1,17 @@
+version: '3.4'
+
+services:
+ sqlserver:
+ environment:
+ - SA_PASSWORD=yourStrong(!)Password
+ - ACCEPT_EULA=Y
+ ports:
+ - "1433:1433"
+
+ volo-docs:
+ environment:
+ - ConnectionString=Server=sqlserver;Database=VoloDocs;Trusted_Connection=True;MultipleActiveResultSets=true;User=sa;Password=yourStrong(!)Password;Integrated Security=false
+ - Title=VoloDocs
+ - LogoUrl=/assets/images/Logo.png
+ ports:
+ - "80:80"
diff --git a/modules/docs/docker-compose.yml b/modules/docs/docker-compose.yml
new file mode 100644
index 0000000000..38f28c98f7
--- /dev/null
+++ b/modules/docs/docker-compose.yml
@@ -0,0 +1,18 @@
+version: '3.4'
+
+services:
+ sqlserver:
+ image: mcr.microsoft.com/mssql/server
+ volumes:
+ - dbdata:/var/opt/mssql
+
+ volo-docs:
+ image: 'volosoft/volo-docs:${TAG:-latest}'
+ build:
+ context: ../../
+ dockerfile: modules/docs/app/VoloDocs.Web/Dockerfile
+ depends_on:
+ - sqlserver
+
+volumes:
+ dbdata:
\ No newline at end of file
diff --git a/nupkg/common.ps1 b/nupkg/common.ps1
index 59329e6af0..e4ecc832fe 100644
--- a/nupkg/common.ps1
+++ b/nupkg/common.ps1
@@ -37,10 +37,12 @@ $projects = (
"framework/src/Volo.Abp.AspNetCore.Mvc.UI",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling",
+ "framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared",
+ "framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets",
"framework/src/Volo.Abp.AspNetCore.TestBase",
"framework/src/Volo.Abp.Auditing",
"framework/src/Volo.Abp.Authorization",
diff --git a/samples/DashboardDemo/.gitattributes b/samples/DashboardDemo/.gitattributes
new file mode 100644
index 0000000000..c941e52669
--- /dev/null
+++ b/samples/DashboardDemo/.gitattributes
@@ -0,0 +1 @@
+**/wwwroot/libs/** linguist-vendored
diff --git a/samples/DashboardDemo/.gitignore b/samples/DashboardDemo/.gitignore
new file mode 100644
index 0000000000..3c7ee2487b
--- /dev/null
+++ b/samples/DashboardDemo/.gitignore
@@ -0,0 +1,255 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# DashboardDemo
+src/DashboardDemo.Web/Logs/logs.txt
diff --git a/samples/DashboardDemo/DashboardDemo.sln b/samples/DashboardDemo/DashboardDemo.sln
new file mode 100644
index 0000000000..c6b0948d70
--- /dev/null
+++ b/samples/DashboardDemo/DashboardDemo.sln
@@ -0,0 +1,74 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DashboardDemo.Domain", "src\DashboardDemo.Domain\DashboardDemo.Domain.csproj", "{554AD327-6DBA-4F8F-96F8-81CE7A0C863F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DashboardDemo.Application", "src\DashboardDemo.Application\DashboardDemo.Application.csproj", "{1A94A50E-06DC-43C1-80B5-B662820EC3EB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DashboardDemo.EntityFrameworkCore", "src\DashboardDemo.EntityFrameworkCore\DashboardDemo.EntityFrameworkCore.csproj", "{C956DD76-69C8-4A9C-83EA-D17DF83340FD}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DashboardDemo.Web", "src\DashboardDemo.Web\DashboardDemo.Web.csproj", "{068855E8-9240-4F1A-910B-CF825794513B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CA9AC87F-097E-4F15-8393-4BC07735A5B0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{04DBDB01-70F4-4E06-B468-8F87850B22BE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DashboardDemo.Application.Tests", "test\DashboardDemo.Application.Tests\DashboardDemo.Application.Tests.csproj", "{50B2631D-129C-47B3-A587-029CCD6099BC}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DashboardDemo.Web.Tests", "test\DashboardDemo.Web.Tests\DashboardDemo.Web.Tests.csproj", "{5F1B28C6-8D0C-4155-92D0-252F7EA5F674}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DashboardDemo.EntityFrameworkCore.DbMigrations", "src\DashboardDemo.EntityFrameworkCore.DbMigrations\DashboardDemo.EntityFrameworkCore.DbMigrations.csproj", "{0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {554AD327-6DBA-4F8F-96F8-81CE7A0C863F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1A94A50E-06DC-43C1-80B5-B662820EC3EB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C956DD76-69C8-4A9C-83EA-D17DF83340FD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {068855E8-9240-4F1A-910B-CF825794513B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {068855E8-9240-4F1A-910B-CF825794513B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {068855E8-9240-4F1A-910B-CF825794513B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {068855E8-9240-4F1A-910B-CF825794513B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {50B2631D-129C-47B3-A587-029CCD6099BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {50B2631D-129C-47B3-A587-029CCD6099BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {50B2631D-129C-47B3-A587-029CCD6099BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {50B2631D-129C-47B3-A587-029CCD6099BC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5F1B28C6-8D0C-4155-92D0-252F7EA5F674}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {554AD327-6DBA-4F8F-96F8-81CE7A0C863F} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
+ {1A94A50E-06DC-43C1-80B5-B662820EC3EB} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
+ {C956DD76-69C8-4A9C-83EA-D17DF83340FD} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
+ {068855E8-9240-4F1A-910B-CF825794513B} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
+ {50B2631D-129C-47B3-A587-029CCD6099BC} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
+ {5F1B28C6-8D0C-4155-92D0-252F7EA5F674} = {04DBDB01-70F4-4E06-B468-8F87850B22BE}
+ {0372FA84-C517-4EB3-9A9F-B9ACAC0CA5E0} = {CA9AC87F-097E-4F15-8393-4BC07735A5B0}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F}
+ EndGlobalSection
+EndGlobal
diff --git a/samples/DashboardDemo/DashboardDemo.sln.DotSettings b/samples/DashboardDemo/DashboardDemo.sln.DotSettings
new file mode 100644
index 0000000000..b89df7b544
--- /dev/null
+++ b/samples/DashboardDemo/DashboardDemo.sln.DotSettings
@@ -0,0 +1,7 @@
+
+ True
+ D:\github\abp\common.DotSettings
+ ..\..\..\common.DotSettings
+ True
+ 1
+
\ No newline at end of file
diff --git a/samples/DashboardDemo/common.props b/samples/DashboardDemo/common.props
new file mode 100644
index 0000000000..7585f303ba
--- /dev/null
+++ b/samples/DashboardDemo/common.props
@@ -0,0 +1,7 @@
+
+
+ latest
+ 1.0.0
+ $(NoWarn);CS1591
+
+
\ No newline at end of file
diff --git a/samples/DashboardDemo/src/DashboardDemo.Application/DashboardDemo.Application.csproj b/samples/DashboardDemo/src/DashboardDemo.Application/DashboardDemo.Application.csproj
new file mode 100644
index 0000000000..9bbd573401
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Application/DashboardDemo.Application.csproj
@@ -0,0 +1,18 @@
+
+
+
+
+
+ netcoreapp2.2
+ DashboardDemo
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DashboardDemo/src/DashboardDemo.Application/DashboardDemoApplicationAutoMapperProfile.cs b/samples/DashboardDemo/src/DashboardDemo.Application/DashboardDemoApplicationAutoMapperProfile.cs
new file mode 100644
index 0000000000..4fcd9fbab3
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Application/DashboardDemoApplicationAutoMapperProfile.cs
@@ -0,0 +1,12 @@
+using AutoMapper;
+
+namespace DashboardDemo
+{
+ public class DashboardDemoApplicationAutoMapperProfile : Profile
+ {
+ public DashboardDemoApplicationAutoMapperProfile()
+ {
+ //Configure your AutoMapper mapping configuration here...
+ }
+ }
+}
diff --git a/samples/DashboardDemo/src/DashboardDemo.Application/DashboardDemoApplicationModule.cs b/samples/DashboardDemo/src/DashboardDemo.Application/DashboardDemoApplicationModule.cs
new file mode 100644
index 0000000000..afb761cce4
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Application/DashboardDemoApplicationModule.cs
@@ -0,0 +1,27 @@
+using Volo.Abp.AutoMapper;
+using Volo.Abp.FeatureManagement;
+using Volo.Abp.Identity;
+using Volo.Abp.Modularity;
+using Volo.Abp.PermissionManagement;
+using Volo.Abp.TenantManagement;
+
+namespace DashboardDemo
+{
+ [DependsOn(
+ typeof(DashboardDemoDomainModule),
+ typeof(AbpIdentityApplicationModule),
+ typeof(AbpPermissionManagementApplicationModule),
+ typeof(AbpTenantManagementApplicationModule),
+ typeof(AbpFeatureManagementApplicationModule)
+ )]
+ public class DashboardDemoApplicationModule : AbpModule
+ {
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.AddProfile();
+ });
+ }
+ }
+}
diff --git a/samples/DashboardDemo/src/DashboardDemo.Application/Permissions/DashboardDemoPermissionDefinitionProvider.cs b/samples/DashboardDemo/src/DashboardDemo.Application/Permissions/DashboardDemoPermissionDefinitionProvider.cs
new file mode 100644
index 0000000000..07cb79194a
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Application/Permissions/DashboardDemoPermissionDefinitionProvider.cs
@@ -0,0 +1,22 @@
+using DashboardDemo.Localization.DashboardDemo;
+using Volo.Abp.Authorization.Permissions;
+using Volo.Abp.Localization;
+
+namespace DashboardDemo.Permissions
+{
+ public class DashboardDemoPermissionDefinitionProvider : PermissionDefinitionProvider
+ {
+ public override void Define(IPermissionDefinitionContext context)
+ {
+ var myGroup = context.AddGroup(DashboardDemoPermissions.GroupName);
+
+ //Define your own permissions here. Examaple:
+ //myGroup.AddPermission(DashboardDemoPermissions.MyPermission1, L("Permission:MyPermission1"));
+ }
+
+ private static LocalizableString L(string name)
+ {
+ return LocalizableString.Create(name);
+ }
+ }
+}
diff --git a/samples/DashboardDemo/src/DashboardDemo.Application/Permissions/DashboardDemoPermissions.cs b/samples/DashboardDemo/src/DashboardDemo.Application/Permissions/DashboardDemoPermissions.cs
new file mode 100644
index 0000000000..3a09652db2
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Application/Permissions/DashboardDemoPermissions.cs
@@ -0,0 +1,19 @@
+using System;
+using Volo.Abp.Reflection;
+
+namespace DashboardDemo.Permissions
+{
+ public static class DashboardDemoPermissions
+ {
+ public const string GroupName = "DashboardDemo";
+
+ //Add your own permission names. Example:
+ //public const string MyPermission1 = GroupName + ".MyPermission1";
+
+ public static string[] GetAll()
+ {
+ //Return an array of all permissions
+ return ReflectionHelper.GetPublicConstantsRecursively(typeof(DashboardDemoPermissions));
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/DashboardDemo.Domain.csproj b/samples/DashboardDemo/src/DashboardDemo.Domain/DashboardDemo.Domain.csproj
new file mode 100644
index 0000000000..d036f48de2
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/DashboardDemo.Domain.csproj
@@ -0,0 +1,25 @@
+
+
+
+
+
+ netcoreapp2.2
+ DashboardDemo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/DashboardDemoConsts.cs b/samples/DashboardDemo/src/DashboardDemo.Domain/DashboardDemoConsts.cs
new file mode 100644
index 0000000000..25e571159d
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/DashboardDemoConsts.cs
@@ -0,0 +1,11 @@
+namespace DashboardDemo
+{
+ public static class DashboardDemoConsts
+ {
+ public const string DbTablePrefix = "App";
+
+ public const string DbSchema = null;
+
+ public const bool IsMultiTenancyEnabled = true;
+ }
+}
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/DashboardDemoDomainModule.cs b/samples/DashboardDemo/src/DashboardDemo.Domain/DashboardDemoDomainModule.cs
new file mode 100644
index 0000000000..f101211a9a
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/DashboardDemoDomainModule.cs
@@ -0,0 +1,49 @@
+using DashboardDemo.Localization.DashboardDemo;
+using Volo.Abp.Auditing;
+using Volo.Abp.AuditLogging;
+using Volo.Abp.BackgroundJobs;
+using Volo.Abp.FeatureManagement;
+using Volo.Abp.Identity;
+using Volo.Abp.Localization;
+using Volo.Abp.Localization.Resources.AbpValidation;
+using Volo.Abp.Modularity;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.PermissionManagement.Identity;
+using Volo.Abp.TenantManagement;
+using Volo.Abp.VirtualFileSystem;
+
+namespace DashboardDemo
+{
+ [DependsOn(
+ typeof(AbpIdentityDomainModule),
+ typeof(AbpPermissionManagementDomainIdentityModule),
+ typeof(AbpAuditingModule),
+ typeof(BackgroundJobsDomainModule),
+ typeof(AbpAuditLoggingDomainModule),
+ typeof(AbpTenantManagementDomainModule),
+ typeof(AbpFeatureManagementDomainModule)
+ )]
+ public class DashboardDemoDomainModule : AbpModule
+ {
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded("DashboardDemo");
+ });
+
+ Configure(options =>
+ {
+ options.Resources
+ .Add("en")
+ .AddBaseTypes(typeof(AbpValidationResource))
+ .AddVirtualJson("/Localization/DashboardDemo");
+ });
+
+ Configure(options =>
+ {
+ options.IsEnabled = DashboardDemoConsts.IsMultiTenancyEnabled;
+ });
+ }
+ }
+}
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/DashboardDemoResource.cs b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/DashboardDemoResource.cs
new file mode 100644
index 0000000000..52f9f3cc47
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/DashboardDemoResource.cs
@@ -0,0 +1,10 @@
+using Volo.Abp.Localization;
+
+namespace DashboardDemo.Localization.DashboardDemo
+{
+ [LocalizationResourceName("DashboardDemo")]
+ public class DashboardDemoResource
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/en.json b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/en.json
new file mode 100644
index 0000000000..baa9fe753e
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/en.json
@@ -0,0 +1,8 @@
+{
+ "culture": "en",
+ "texts": {
+ "Menu:Home": "Home",
+ "Welcome": "Welcome",
+ "LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io."
+ }
+}
\ No newline at end of file
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/pt-BR.json b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/pt-BR.json
new file mode 100644
index 0000000000..8c818a07af
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/pt-BR.json
@@ -0,0 +1,8 @@
+{
+ "culture": "pt-BR",
+ "texts": {
+ "Menu:Home": "Principal",
+ "Welcome": "Seja bem-vindo!",
+ "LongWelcomeMessage": "Bem-vindo a esta aplicação. Este é um projeto inicial baseado no ABP framework. Para mais informações, visite abp.io."
+ }
+}
\ No newline at end of file
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/tr.json b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/tr.json
new file mode 100644
index 0000000000..5bf83ee7a8
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/tr.json
@@ -0,0 +1,8 @@
+{
+ "culture": "tr",
+ "texts": {
+ "Menu:Home": "Ana sayfa",
+ "Welcome": "Hoşgeldiniz",
+ "LongWelcomeMessage": "Uygulamaya hoşgeldiniz. Bu, ABP framework'ü üzerine bina edilmiş bir başlangıç projesidir. Daha fazla bilgi için abp.io adresini ziyaret edebilirsiniz."
+ }
+}
\ No newline at end of file
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/zh-Hans.json b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/zh-Hans.json
new file mode 100644
index 0000000000..459fc0fefd
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/Localization/DashboardDemo/zh-Hans.json
@@ -0,0 +1,8 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "Menu:Home": "首页",
+ "Welcome": "欢迎",
+ "LongWelcomeMessage": "欢迎来到该应用程序. 这是一个基于ABP框架的启动项目. 有关更多信息, 请访问 cn.abp.io."
+ }
+ }
\ No newline at end of file
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/Settings/DashboardDemoSettingDefinitionProvider.cs b/samples/DashboardDemo/src/DashboardDemo.Domain/Settings/DashboardDemoSettingDefinitionProvider.cs
new file mode 100644
index 0000000000..8ba9abccaa
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/Settings/DashboardDemoSettingDefinitionProvider.cs
@@ -0,0 +1,13 @@
+using Volo.Abp.Settings;
+
+namespace DashboardDemo.Settings
+{
+ public class DashboardDemoSettingDefinitionProvider : SettingDefinitionProvider
+ {
+ public override void Define(ISettingDefinitionContext context)
+ {
+ //Define your own settings here. Example:
+ //context.Add(new SettingDefinition(DashboardDemoSettings.MySetting1));
+ }
+ }
+}
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/Settings/DashboardDemoSettings.cs b/samples/DashboardDemo/src/DashboardDemo.Domain/Settings/DashboardDemoSettings.cs
new file mode 100644
index 0000000000..eaffcc35c6
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/Settings/DashboardDemoSettings.cs
@@ -0,0 +1,10 @@
+namespace DashboardDemo.Settings
+{
+ public static class DashboardDemoSettings
+ {
+ private const string Prefix = "DashboardDemo";
+
+ //Add your own setting names here. Example:
+ //public const string MySetting1 = Prefix + ".MySetting1";
+ }
+}
\ No newline at end of file
diff --git a/samples/DashboardDemo/src/DashboardDemo.Domain/Users/AppUser.cs b/samples/DashboardDemo/src/DashboardDemo.Domain/Users/AppUser.cs
new file mode 100644
index 0000000000..4706cd08e9
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.Domain/Users/AppUser.cs
@@ -0,0 +1,53 @@
+using System;
+using Volo.Abp.Domain.Entities.Auditing;
+using Volo.Abp.Users;
+
+namespace DashboardDemo.Users
+{
+ /* This entity shares the same table/collection ("AbpUsers" by default) with the
+ * IdentityUser entity of the Identity module.
+ *
+ * - You can define your custom properties into this class.
+ * - You never create or delete this entity, becase it is Identity module's job.
+ * - You can query users from database with this entity.
+ * - You can update values of your custom properties.
+ */
+ public class AppUser : FullAuditedAggregateRoot, IUser
+ {
+ #region Base properties
+
+ /* These properties are shared with the IdentityUser entity of the Identity module.
+ * Do not change these properties through this class. Instead, use Identity module
+ * services (like IdentityUserManager) to change them.
+ * So, this properties are designed as read only!
+ */
+
+ public virtual Guid? TenantId { get; private set; }
+
+ public virtual string UserName { get; private set; }
+
+ public virtual string Name { get; private set; }
+
+ public virtual string Surname { get; private set; }
+
+ public virtual string Email { get; private set; }
+
+ public virtual bool EmailConfirmed { get; private set; }
+
+ public virtual string PhoneNumber { get; private set; }
+
+ public virtual bool PhoneNumberConfirmed { get; private set; }
+
+ #endregion
+
+ /* Add your own properties here. Example:
+ *
+ * public virtual string MyProperty { get; set; }
+ */
+
+ private AppUser()
+ {
+
+ }
+ }
+}
diff --git a/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/DashboardDemo.EntityFrameworkCore.DbMigrations.csproj b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/DashboardDemo.EntityFrameworkCore.DbMigrations.csproj
new file mode 100644
index 0000000000..8b1fe3f5ee
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/DashboardDemo.EntityFrameworkCore.DbMigrations.csproj
@@ -0,0 +1,18 @@
+
+
+
+
+
+ netcoreapp2.2
+ DashboardDemo
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/EntityFrameworkCore/DashboardDemoMigrationsDbContext.cs b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/EntityFrameworkCore/DashboardDemoMigrationsDbContext.cs
new file mode 100644
index 0000000000..03ed1a2d3d
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/EntityFrameworkCore/DashboardDemoMigrationsDbContext.cs
@@ -0,0 +1,46 @@
+using Microsoft.EntityFrameworkCore;
+using Volo.Abp.AuditLogging.EntityFrameworkCore;
+using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
+using Volo.Abp.EntityFrameworkCore;
+using Volo.Abp.Identity;
+using Volo.Abp.Identity.EntityFrameworkCore;
+using Volo.Abp.PermissionManagement.EntityFrameworkCore;
+using Volo.Abp.SettingManagement.EntityFrameworkCore;
+using Volo.Abp.TenantManagement.EntityFrameworkCore;
+
+namespace DashboardDemo.EntityFrameworkCore
+{
+ public class DashboardDemoMigrationsDbContext : AbpDbContext
+ {
+ public DashboardDemoMigrationsDbContext(DbContextOptions options)
+ : base(options)
+ {
+
+ }
+
+ protected override void OnModelCreating(ModelBuilder builder)
+ {
+ base.OnModelCreating(builder);
+
+ /* Include modules to your migration db context */
+
+ builder.ConfigurePermissionManagement();
+ builder.ConfigureSettingManagement();
+ builder.ConfigureBackgroundJobs();
+ builder.ConfigureAuditLogging();
+ builder.ConfigureIdentity();
+ builder.ConfigureTenantManagement();
+
+ /* Configure customizations for entities from the modules included */
+
+ builder.Entity(b =>
+ {
+ b.ConfigureCustomUserProperties();
+ });
+
+ /* Configure your own tables/entities inside the ConfigureDashboardDemo method */
+
+ builder.ConfigureDashboardDemo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/EntityFrameworkCore/DashboardDemoMigrationsDbContextFactory.cs b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/EntityFrameworkCore/DashboardDemoMigrationsDbContextFactory.cs
new file mode 100644
index 0000000000..b894e405bc
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/EntityFrameworkCore/DashboardDemoMigrationsDbContextFactory.cs
@@ -0,0 +1,29 @@
+using System.IO;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+using Microsoft.Extensions.Configuration;
+
+namespace DashboardDemo.EntityFrameworkCore
+{
+ public class DashboardDemoMigrationsDbContextFactory : IDesignTimeDbContextFactory
+ {
+ public DashboardDemoMigrationsDbContext CreateDbContext(string[] args)
+ {
+ var configuration = BuildConfiguration();
+
+ var builder = new DbContextOptionsBuilder()
+ .UseSqlServer(configuration.GetConnectionString("Default"));
+
+ return new DashboardDemoMigrationsDbContext(builder.Options);
+ }
+
+ private static IConfigurationRoot BuildConfiguration()
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: false);
+
+ return builder.Build();
+ }
+ }
+}
diff --git a/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/Migrations/20190402131334_Initial.Designer.cs b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/Migrations/20190402131334_Initial.Designer.cs
new file mode 100644
index 0000000000..8c4848b563
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/Migrations/20190402131334_Initial.Designer.cs
@@ -0,0 +1,760 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using DashboardDemo.EntityFrameworkCore;
+
+namespace DashboardDemo.Migrations
+{
+ [DbContext(typeof(DashboardDemoMigrationsDbContext))]
+ [Migration("20190402131334_Initial")]
+ partial class Initial
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.2.0-rtm-35687")
+ .HasAnnotation("Relational:MaxIdentifierLength", 128)
+ .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+
+ modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApplicationName")
+ .HasColumnName("ApplicationName")
+ .HasMaxLength(96);
+
+ b.Property("BrowserInfo")
+ .HasColumnName("BrowserInfo")
+ .HasMaxLength(512);
+
+ b.Property("ClientId")
+ .HasColumnName("ClientId")
+ .HasMaxLength(64);
+
+ b.Property("ClientIpAddress")
+ .HasColumnName("ClientIpAddress")
+ .HasMaxLength(64);
+
+ b.Property("ClientName")
+ .HasColumnName("ClientName")
+ .HasMaxLength(128);
+
+ b.Property("Comments")
+ .HasColumnName("Comments")
+ .HasMaxLength(256);
+
+ b.Property("ConcurrencyStamp");
+
+ b.Property("CorrelationId")
+ .HasColumnName("CorrelationId")
+ .HasMaxLength(64);
+
+ b.Property("Exceptions")
+ .HasColumnName("Exceptions")
+ .HasMaxLength(4000);
+
+ b.Property("ExecutionDuration")
+ .HasColumnName("ExecutionDuration");
+
+ b.Property("ExecutionTime");
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("HttpMethod")
+ .HasColumnName("HttpMethod")
+ .HasMaxLength(16);
+
+ b.Property("HttpStatusCode")
+ .HasColumnName("HttpStatusCode");
+
+ b.Property("ImpersonatorTenantId")
+ .HasColumnName("ImpersonatorTenantId");
+
+ b.Property("ImpersonatorUserId")
+ .HasColumnName("ImpersonatorUserId");
+
+ b.Property("TenantId")
+ .HasColumnName("TenantId");
+
+ b.Property("TenantName");
+
+ b.Property("Url")
+ .HasColumnName("Url")
+ .HasMaxLength(256);
+
+ b.Property("UserId")
+ .HasColumnName("UserId");
+
+ b.Property("UserName")
+ .HasColumnName("UserName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.HasIndex("TenantId", "ExecutionTime");
+
+ b.HasIndex("TenantId", "UserId", "ExecutionTime");
+
+ b.ToTable("AbpAuditLogs");
+ });
+
+ modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AuditLogId")
+ .HasColumnName("AuditLogId");
+
+ b.Property("ExecutionDuration")
+ .HasColumnName("ExecutionDuration");
+
+ b.Property("ExecutionTime")
+ .HasColumnName("ExecutionTime");
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("MethodName")
+ .HasColumnName("MethodName")
+ .HasMaxLength(128);
+
+ b.Property("Parameters")
+ .HasColumnName("Parameters")
+ .HasMaxLength(2000);
+
+ b.Property("ServiceName")
+ .HasColumnName("ServiceName")
+ .HasMaxLength(256);
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuditLogId");
+
+ b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime");
+
+ b.ToTable("AbpAuditLogActions");
+ });
+
+ modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AuditLogId")
+ .HasColumnName("AuditLogId");
+
+ b.Property("ChangeTime")
+ .HasColumnName("ChangeTime");
+
+ b.Property("ChangeType")
+ .HasColumnName("ChangeType");
+
+ b.Property("EntityId")
+ .IsRequired()
+ .HasColumnName("EntityId")
+ .HasMaxLength(128);
+
+ b.Property("EntityTenantId");
+
+ b.Property("EntityTypeFullName")
+ .IsRequired()
+ .HasColumnName("EntityTypeFullName")
+ .HasMaxLength(128);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("TenantId")
+ .HasColumnName("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuditLogId");
+
+ b.HasIndex("TenantId", "EntityTypeFullName", "EntityId");
+
+ b.ToTable("AbpEntityChanges");
+ });
+
+ modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("EntityChangeId");
+
+ b.Property("NewValue")
+ .HasColumnName("NewValue")
+ .HasMaxLength(512);
+
+ b.Property("OriginalValue")
+ .HasColumnName("OriginalValue")
+ .HasMaxLength(512);
+
+ b.Property("PropertyName")
+ .IsRequired()
+ .HasColumnName("PropertyName")
+ .HasMaxLength(128);
+
+ b.Property("PropertyTypeFullName")
+ .IsRequired()
+ .HasColumnName("PropertyTypeFullName")
+ .HasMaxLength(64);
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EntityChangeId");
+
+ b.ToTable("AbpEntityPropertyChanges");
+ });
+
+ modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsAbandoned")
+ .ValueGeneratedOnAdd()
+ .HasDefaultValue(false);
+
+ b.Property("JobArgs")
+ .IsRequired()
+ .HasMaxLength(1048576);
+
+ b.Property("JobName")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("LastTryTime");
+
+ b.Property("NextTryTime");
+
+ b.Property("Priority")
+ .ValueGeneratedOnAdd()
+ .HasDefaultValue((byte)15);
+
+ b.Property("TryCount")
+ .ValueGeneratedOnAdd()
+ .HasDefaultValue((short)0);
+
+ b.HasKey("Id");
+
+ b.HasIndex("IsAbandoned", "NextTryTime");
+
+ b.ToTable("AbpBackgroundJobs");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasColumnName("ConcurrencyStamp")
+ .HasMaxLength(256);
+
+ b.Property("Description")
+ .HasMaxLength(256);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsStatic");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("Regex")
+ .HasMaxLength(512);
+
+ b.Property("RegexDescription")
+ .HasMaxLength(128);
+
+ b.Property("Required");
+
+ b.Property("ValueType");
+
+ b.HasKey("Id");
+
+ b.ToTable("AbpClaimTypes");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasColumnName("ConcurrencyStamp")
+ .HasMaxLength(256);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDefault")
+ .HasColumnName("IsDefault");
+
+ b.Property("IsPublic")
+ .HasColumnName("IsPublic");
+
+ b.Property("IsStatic")
+ .HasColumnName("IsStatic");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("NormalizedName")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName");
+
+ b.ToTable("AbpRoles");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("ClaimValue")
+ .HasMaxLength(1024);
+
+ b.Property("RoleId");
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AbpRoleClaims");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AccessFailedCount")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("AccessFailedCount")
+ .HasDefaultValue(0);
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Email")
+ .HasColumnName("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("EmailConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("LockoutEnabled")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("LockoutEnabled")
+ .HasDefaultValue(false);
+
+ b.Property("LockoutEnd");
+
+ b.Property("Name")
+ .HasColumnName("Name")
+ .HasMaxLength(64);
+
+ b.Property("NormalizedEmail")
+ .HasColumnName("NormalizedEmail")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedUserName")
+ .IsRequired()
+ .HasColumnName("NormalizedUserName")
+ .HasMaxLength(256);
+
+ b.Property("PasswordHash")
+ .HasColumnName("PasswordHash")
+ .HasMaxLength(256);
+
+ b.Property("PhoneNumber")
+ .HasColumnName("PhoneNumber")
+ .HasMaxLength(16);
+
+ b.Property("PhoneNumberConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("PhoneNumberConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("SecurityStamp")
+ .IsRequired()
+ .HasColumnName("SecurityStamp")
+ .HasMaxLength(256);
+
+ b.Property("Surname")
+ .HasColumnName("Surname")
+ .HasMaxLength(64);
+
+ b.Property("TenantId")
+ .HasColumnName("TenantId");
+
+ b.Property("TwoFactorEnabled")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("TwoFactorEnabled")
+ .HasDefaultValue(false);
+
+ b.Property("UserName")
+ .IsRequired()
+ .HasColumnName("UserName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.HasIndex("Email");
+
+ b.HasIndex("NormalizedEmail");
+
+ b.HasIndex("NormalizedUserName");
+
+ b.HasIndex("UserName");
+
+ b.ToTable("AbpUsers");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("ClaimValue")
+ .HasMaxLength(1024);
+
+ b.Property("TenantId");
+
+ b.Property("UserId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AbpUserClaims");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider")
+ .HasMaxLength(64);
+
+ b.Property("ProviderDisplayName")
+ .HasMaxLength(128);
+
+ b.Property("ProviderKey")
+ .IsRequired()
+ .HasMaxLength(196);
+
+ b.Property("TenantId");
+
+ b.HasKey("UserId", "LoginProvider");
+
+ b.HasIndex("LoginProvider", "ProviderKey");
+
+ b.ToTable("AbpUserLogins");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("RoleId");
+
+ b.Property("TenantId");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId", "UserId");
+
+ b.ToTable("AbpUserRoles");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider")
+ .HasMaxLength(64);
+
+ b.Property("Name")
+ .HasMaxLength(128);
+
+ b.Property("TenantId");
+
+ b.Property("Value");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AbpUserTokens");
+ });
+
+ modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("ProviderKey")
+ .IsRequired()
+ .HasMaxLength(64);
+
+ b.Property("ProviderName")
+ .IsRequired()
+ .HasMaxLength(64);
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name", "ProviderName", "ProviderKey");
+
+ b.ToTable("AbpPermissionGrants");
+ });
+
+ modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("ProviderKey")
+ .HasMaxLength(64);
+
+ b.Property("ProviderName")
+ .HasMaxLength(64);
+
+ b.Property("Value")
+ .IsRequired()
+ .HasMaxLength(2048);
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name", "ProviderName", "ProviderKey");
+
+ b.ToTable("AbpSettings");
+ });
+
+ modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(64);
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.ToTable("AbpTenants");
+ });
+
+ modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b =>
+ {
+ b.Property("TenantId");
+
+ b.Property("Name")
+ .HasMaxLength(64);
+
+ b.Property("Value")
+ .IsRequired()
+ .HasMaxLength(1024);
+
+ b.HasKey("TenantId", "Name");
+
+ b.ToTable("AbpTenantConnectionStrings");
+ });
+
+ modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b =>
+ {
+ b.HasOne("Volo.Abp.AuditLogging.AuditLog")
+ .WithMany("Actions")
+ .HasForeignKey("AuditLogId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b =>
+ {
+ b.HasOne("Volo.Abp.AuditLogging.AuditLog")
+ .WithMany("EntityChanges")
+ .HasForeignKey("AuditLogId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b =>
+ {
+ b.HasOne("Volo.Abp.AuditLogging.EntityChange")
+ .WithMany("PropertyChanges")
+ .HasForeignKey("EntityChangeId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b =>
+ {
+ b.HasOne("Volo.Abp.Identity.IdentityRole")
+ .WithMany("Claims")
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b =>
+ {
+ b.HasOne("Volo.Abp.Identity.IdentityUser")
+ .WithMany("Claims")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("Volo.Abp.Identity.IdentityUser")
+ .WithMany("Logins")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b =>
+ {
+ b.HasOne("Volo.Abp.Identity.IdentityRole")
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("Volo.Abp.Identity.IdentityUser")
+ .WithMany("Roles")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b =>
+ {
+ b.HasOne("Volo.Abp.Identity.IdentityUser")
+ .WithMany("Tokens")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Volo.Abp.TenantManagement.TenantConnectionString", b =>
+ {
+ b.HasOne("Volo.Abp.TenantManagement.Tenant")
+ .WithMany("ConnectionStrings")
+ .HasForeignKey("TenantId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/Migrations/20190402131334_Initial.cs b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/Migrations/20190402131334_Initial.cs
new file mode 100644
index 0000000000..f6b5519820
--- /dev/null
+++ b/samples/DashboardDemo/src/DashboardDemo.EntityFrameworkCore.DbMigrations/Migrations/20190402131334_Initial.cs
@@ -0,0 +1,546 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace DashboardDemo.Migrations
+{
+ public partial class Initial : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "AbpAuditLogs",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ ExtraProperties = table.Column(nullable: true),
+ ConcurrencyStamp = table.Column(nullable: true),
+ ApplicationName = table.Column(maxLength: 96, nullable: true),
+ UserId = table.Column(nullable: true),
+ UserName = table.Column(maxLength: 256, nullable: true),
+ TenantId = table.Column(nullable: true),
+ TenantName = table.Column(nullable: true),
+ ImpersonatorUserId = table.Column(nullable: true),
+ ImpersonatorTenantId = table.Column(nullable: true),
+ ExecutionTime = table.Column(nullable: false),
+ ExecutionDuration = table.Column(nullable: false),
+ ClientIpAddress = table.Column(maxLength: 64, nullable: true),
+ ClientName = table.Column(maxLength: 128, nullable: true),
+ ClientId = table.Column(maxLength: 64, nullable: true),
+ CorrelationId = table.Column(maxLength: 64, nullable: true),
+ BrowserInfo = table.Column(maxLength: 512, nullable: true),
+ HttpMethod = table.Column(maxLength: 16, nullable: true),
+ Url = table.Column(maxLength: 256, nullable: true),
+ Exceptions = table.Column(maxLength: 4000, nullable: true),
+ Comments = table.Column(maxLength: 256, nullable: true),
+ HttpStatusCode = table.Column(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AbpAuditLogs", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AbpBackgroundJobs",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ ExtraProperties = table.Column(nullable: true),
+ ConcurrencyStamp = table.Column(nullable: true),
+ JobName = table.Column(maxLength: 128, nullable: false),
+ JobArgs = table.Column(maxLength: 1048576, nullable: false),
+ TryCount = table.Column(nullable: false, defaultValue: (short)0),
+ CreationTime = table.Column(nullable: false),
+ NextTryTime = table.Column(nullable: false),
+ LastTryTime = table.Column(nullable: true),
+ IsAbandoned = table.Column(nullable: false, defaultValue: false),
+ Priority = table.Column(nullable: false, defaultValue: (byte)15)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AbpClaimTypes",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ ExtraProperties = table.Column(nullable: true),
+ ConcurrencyStamp = table.Column(maxLength: 256, nullable: false),
+ Name = table.Column(maxLength: 256, nullable: false),
+ Required = table.Column(nullable: false),
+ IsStatic = table.Column(nullable: false),
+ Regex = table.Column(maxLength: 512, nullable: true),
+ RegexDescription = table.Column(maxLength: 128, nullable: true),
+ Description = table.Column(maxLength: 256, nullable: true),
+ ValueType = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AbpClaimTypes", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AbpPermissionGrants",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ TenantId = table.Column(nullable: true),
+ Name = table.Column(maxLength: 128, nullable: false),
+ ProviderName = table.Column(maxLength: 64, nullable: false),
+ ProviderKey = table.Column(maxLength: 64, nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AbpRoles",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ ExtraProperties = table.Column(nullable: true),
+ ConcurrencyStamp = table.Column(maxLength: 256, nullable: false),
+ TenantId = table.Column(nullable: true),
+ Name = table.Column(maxLength: 256, nullable: false),
+ NormalizedName = table.Column(maxLength: 256, nullable: false),
+ IsDefault = table.Column(nullable: false),
+ IsStatic = table.Column(nullable: false),
+ IsPublic = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AbpRoles", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AbpSettings",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ Name = table.Column(maxLength: 128, nullable: false),
+ Value = table.Column(maxLength: 2048, nullable: false),
+ ProviderName = table.Column(maxLength: 64, nullable: true),
+ ProviderKey = table.Column(maxLength: 64, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AbpSettings", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "AbpTenants",
+ columns: table => new
+ {
+ Id = table.Column