Browse Source

Merge remote-tracking branch 'abpframework/dev' into Translate

pull/1926/head
梁士伟 7 years ago
parent
commit
1bebc7ae72
  1. 3
      docs/en/AspNetCore/Client-Side-Package-Management.md
  2. 6
      docs/en/Caching.md
  3. 115
      docs/en/Getting-Started-AspNetCore-Application.md
  4. BIN
      docs/en/images/create-aspnet-core-application.png
  5. BIN
      docs/en/images/create-new-aspnet-core-application-v2.png
  6. BIN
      docs/en/images/select-empty-web-application-v2.png
  7. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs
  8. 23
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentCultureDto.cs
  9. 19
      framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/DateTimeFormatDto.cs
  10. 36
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs
  11. 19
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs
  12. 5
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderOptions.cs
  13. 13
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs
  14. 3
      npm/ng-packs/package.json
  15. 10
      npm/ng-packs/packages/core/src/lib/directives/for.directive.ts
  16. 12
      npm/ng-packs/packages/core/src/lib/directives/visibility.directive.ts
  17. 8
      npm/ng-packs/packages/core/src/lib/states/config.state.ts
  18. 2
      npm/ng-packs/packages/core/src/lib/states/session.state.ts
  19. 90
      npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts
  20. 191
      npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts
  21. 74
      npm/ng-packs/packages/core/src/lib/tests/profile.state.spec.ts
  22. 70
      npm/ng-packs/packages/core/src/lib/tests/session.state.spec.ts
  23. 128
      npm/ng-packs/packages/core/src/lib/tests/visibility.directive.spec.ts
  24. 8
      npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts
  25. 8
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.html
  26. 48
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  27. 9
      npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts
  28. 16
      npm/ng-packs/packages/identity/src/lib/resolvers/roles.resolver.ts
  29. 16
      npm/ng-packs/packages/identity/src/lib/resolvers/users.resolver.ts
  30. 8
      npm/ng-packs/packages/identity/src/lib/states/identity.state.ts
  31. 1
      npm/ng-packs/packages/identity/src/public-api.ts
  32. 14
      npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts
  33. 1
      npm/ng-packs/packages/tenant-management/src/lib/resolvers/index.ts
  34. 16
      npm/ng-packs/packages/tenant-management/src/lib/resolvers/tenants.resolver.ts
  35. 4
      npm/ng-packs/packages/tenant-management/src/lib/tenant-management-routing.module.ts
  36. 1
      npm/ng-packs/packages/tenant-management/src/public-api.ts
  37. 41
      npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts
  38. 39
      npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts
  39. 2
      npm/ng-packs/scripts/build.js
  40. 16
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication.sln
  41. 22
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/AppModule.cs
  42. 10
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/BasicAspNetCoreApplication.csproj
  43. 13
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Controllers/HomeController.cs
  44. 26
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Error.cshtml
  45. 31
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Error.cshtml.cs
  46. 10
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Index.cshtml
  47. 25
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Index.cshtml.cs
  48. 8
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Privacy.cshtml
  49. 24
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Privacy.cshtml.cs
  50. 50
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Shared/_Layout.cshtml
  51. 2
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Shared/_ValidationScriptsPartial.cshtml
  52. 3
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/_ViewImports.cshtml
  53. 3
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/_ViewStart.cshtml
  54. 15
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Program.cs
  55. 14
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Properties/launchSettings.json
  56. 11
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Startup.cs
  57. 9
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/appsettings.Development.json
  58. 10
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/appsettings.json
  59. 71
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/css/site.css
  60. BIN
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/favicon.ico
  61. 4
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/js/site.js
  62. 22
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/LICENSE
  63. 3719
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css
  64. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map
  65. 7
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css
  66. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map
  67. 331
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css
  68. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map
  69. 8
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css
  70. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map
  71. 10038
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap.css
  72. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map
  73. 7
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css
  74. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map
  75. 7013
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js
  76. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map
  77. 7
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js
  78. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map
  79. 4435
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.js
  80. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map
  81. 7
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js
  82. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map
  83. 12
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt
  84. 432
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js
  85. 5
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js
  86. 22
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/LICENSE.md
  87. 1158
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/dist/additional-methods.js
  88. 4
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/dist/additional-methods.min.js
  89. 1601
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/dist/jquery.validate.js
  90. 4
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js
  91. 36
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery/LICENSE.txt
  92. 10364
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery/dist/jquery.js
  93. 2
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery/dist/jquery.min.js
  94. 1
      samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery/dist/jquery.min.map
  95. 30
      templates/app/angular/package.json
  96. 8
      templates/app/angular/src/app/app.module.ts
  97. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/Controllers/HomeController.cs

3
docs/en/AspNetCore/Client-Side-Package-Management.md

@ -93,7 +93,8 @@ An example mapping configuration is shown below:
````js
mappings: {
"@node_modules/bootstrap/dist/css/bootstrap.css": "@libs/bootstrap/css/",
"@node_modules/bootstrap/dist/js/bootstrap.bundle.js": "@libs/bootstrap/js/"
"@node_modules/bootstrap/dist/js/bootstrap.bundle.js": "@libs/bootstrap/js/",
"@node_modules/bootstrap-datepicker/dist/locales/*.*": "@libs/bootstrap-datepicker/locales/"
}
````

6
docs/en/Caching.md

@ -2,7 +2,7 @@
ABP framework extends ASP.NET Core's distributed caching system.
## IDistributedCache Interface
## `IDistributedCache` Interface
ASP.NET Core defines the `IDistributedCache` interface to get/set cache values. But it has some difficulties:
@ -17,7 +17,7 @@ ASP.NET Core defines the `IDistributedCache` interface to get/set cache values.
See [ASP.NET Core's distributed caching document](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed) for more information.
## IDistributedCache<TCacheItem> Interface
## `IDistributedCache<TCacheItem>` Interface
ABP framework defines the generic `IDistributedCache<TCacheItem>` interface in the [Volo.Abp.Caching](https://www.nuget.org/packages/Volo.Abp.Caching/) package. `TCacheItem` is the type of the object stored in the cache.
@ -82,4 +82,4 @@ Other methods of the `IDistributedCache<BookCacheItem>` are same as ASP.NET Core
### DistributedCacheOptions
TODO
TODO

115
docs/en/Getting-Started-AspNetCore-Application.md

@ -4,15 +4,17 @@ This tutorial explains how to start ABP from scratch with minimal dependencies.
## Create A New Project
1. Create a new empty AspNet Core Web Application from Visual Studio:
1. Create a new AspNet Core Web Application from Visual Studio 2019 (16.3.0+):
![](images/create-new-aspnet-core-application.png)
![](images/create-new-aspnet-core-application-v2.png)
2. Select Empty Template
2. Configure your new project:
![](images/select-empty-web-application.png)
![](images/select-empty-web-application-v2.png)
You could select another template, but I want to show it from a clear project.
3. Press to the create button:
![create-aspnet-core-application](D:\Github\abp\docs\en\images\create-aspnet-core-application.png)
## Install Volo.Abp.AspNetCore.Mvc Package
@ -28,10 +30,8 @@ ABP is a modular framework and it requires a **startup (root) module** class der
````C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Volo.Abp;
using Volo.Abp.AspNetCore.Modularity;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
@ -40,7 +40,8 @@ namespace BasicAspNetCoreApplication
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
public class AppModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
public override void OnApplicationInitialization(
ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
@ -49,8 +50,14 @@ namespace BasicAspNetCoreApplication
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseMvcWithDefaultRoute();
app.UseStaticFiles();
app.UseRouting();
app.UseMvcWithDefaultRouteAndArea();
}
}
}
@ -58,16 +65,15 @@ namespace BasicAspNetCoreApplication
``AppModule`` is a good name for the startup module for an application.
ABP packages define module classes and a module can depend on another module. In the code above, our ``AppModule`` depends on ``AbpAspNetCoreMvcModule`` (defined by Volo.Abp.AspNetCore.Mvc package). It's common to add a ``DependsOn`` attribute after installing a new ABP nuget package.
ABP packages define module classes and a module can depend on another. In the code above, the ``AppModule`` depends on the ``AbpAspNetCoreMvcModule`` (defined by [Volo.Abp.AspNetCore.Mvc](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc) package). It's common to add a ``DependsOn`` attribute after installing a new ABP nuget package.
Instead of Startup class, we are configuring ASP.NET Core pipeline in this module class.
Instead of the Startup class, we are configuring ASP.NET Core pipeline in this module class.
## The Startup Class
Next step is to modify Startup class to integrate to ABP module system:
````C#
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
@ -75,11 +81,9 @@ namespace BasicAspNetCoreApplication
{
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<AppModule>();
return services.BuildServiceProviderFromFactory();
}
public void Configure(IApplicationBuilder app)
@ -88,41 +92,19 @@ namespace BasicAspNetCoreApplication
}
}
}
````
Changed ``ConfigureServices`` method to return ``IServiceProvider`` instead of ``void``. This change allows us to replace AspNet Core's Dependency Injection with another framework (see Autofac integration section below). ``services.AddApplication<AppModule>()`` adds all services defined in all modules beginning from the ``AppModule``.
``services.AddApplication<AppModule>()`` adds all services defined in all modules starting from the ``AppModule``.
``app.InitializeApplication()`` call in ``Configure`` method initializes and starts the application.
``app.InitializeApplication()`` in ``Configure`` method initializes and starts the application.
## Hello World!
## Run the Application!
The application above does nothing. Let's create an MVC controller does something:
````C#
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace BasicAspNetCoreApplication.Controllers
{
public class HomeController : AbpController
{
public IActionResult Index()
{
return Content("Hello World!");
}
}
}
````
If you run the application, you will see a "Hello World!" message on the page.
Derived ``HomeController`` from ``AbpController`` instead of standard ``Controller`` class. This is not required, but ``AbpController`` class has useful base properties and methods to make your development easier.
That's all! Run the application, it will just work as expected.
## Using Autofac as the Dependency Injection Framework
While AspNet Core's Dependency Injection (DI) system is fine for basic requirements, Autofac provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features.
While AspNet Core's Dependency Injection (DI) system is fine for basic requirements, [Autofac](https://autofac.org/) provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features.
Replacing AspNet Core's DI system by Autofac and integrating to ABP is pretty easy.
@ -143,40 +125,29 @@ public class AppModule : AbpModule
}
````
3. Change ``services.AddApplication<AppModule>();`` line in the ``Startup`` class as shown below:
````C#
services.AddApplication<AppModule>(options =>
{
options.UseAutofac(); //Integrate to Autofac
});
````
4. Update `Program.cs` to not use the `WebHost.CreateDefaultBuilder()` method since it uses the default DI container:
3. Update `Program.cs` to use AutoMapper:
````csharp
public class Program
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace BasicAspNetCoreApplication
{
public static void Main(string[] args)
public class Program
{
/*
https://github.com/aspnet/AspNetCore/issues/4206#issuecomment-445612167
CurrentDirectoryHelpers exists in: \framework\src\Volo.Abp.AspNetCore.Mvc\Microsoft\AspNetCore\InProcess\CurrentDirectoryHelpers.cs
Will remove CurrentDirectoryHelpers.cs when upgrade to ASP.NET Core 3.0.
*/
CurrentDirectoryHelpers.SetCurrentDirectory();
BuildWebHostInternal(args).Run();
}
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IWebHost BuildWebHostInternal(string[] args) =>
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIIS()
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseAutofac(); //Add this line
}
}
````

BIN
docs/en/images/create-aspnet-core-application.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
docs/en/images/create-new-aspnet-core-application-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

BIN
docs/en/images/select-empty-web-application-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

2
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationLocalizationConfigurationDto.cs

@ -12,6 +12,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
public List<LanguageInfo> Languages { get; set; }
public CurrentCultureDto CurrentCulture { get; set; }
public ApplicationLocalizationConfigurationDto()
{
Values = new Dictionary<string, Dictionary<string, string>>();

23
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/CurrentCultureDto.cs

@ -0,0 +1,23 @@
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{
public class CurrentCultureDto
{
public string DisplayName { get; set; }
public string EnglishName { get; set; }
public string ThreeLetterIsoLanguageName { get; set; }
public string TwoLetterIsoLanguageName { get; set; }
public bool IsRightToLeft { get; set; }
public string CultureName { get; set; }
public string Name { get; set; }
public string NativeName { get; set; }
public DateTimeFormatDto DateTimeFormat { get; set; }
}
}

19
framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/DateTimeFormatDto.cs

@ -0,0 +1,19 @@
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
{
public class DateTimeFormatDto
{
public string CalendarAlgorithmType { get; set; }
public string DateTimeFormatLong { get; set; }
public string ShortDatePattern { get; set; }
public string FullDateTimePattern { get; set; }
public string DateSeparator { get; set; }
public string ShortTimePattern { get; set; }
public string LongTimePattern { get; set; }
}
}

36
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs

@ -4,6 +4,7 @@ using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Authorization;
@ -31,10 +32,10 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
IServiceProvider serviceProvider,
IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider,
IAuthorizationService authorizationService,
ICurrentUser currentUser,
ISettingProvider settingProvider,
SettingDefinitionManager settingDefinitionManager,
IFeatureDefinitionManager featureDefinitionManager,
ICurrentUser currentUser,
ISettingProvider settingProvider,
SettingDefinitionManager settingDefinitionManager,
IFeatureDefinitionManager featureDefinitionManager,
ILanguageProvider languageProvider)
{
_serviceProvider = serviceProvider;
@ -112,9 +113,36 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
localizationConfig.Values[resource.ResourceName] = dictionary;
}
localizationConfig.CurrentCulture = GetCurrentCultureInfo();
return localizationConfig;
}
private static CurrentCultureDto GetCurrentCultureInfo()
{
return new CurrentCultureDto
{
Name = CultureInfo.CurrentUICulture.Name,
DisplayName = CultureInfo.CurrentUICulture.DisplayName,
EnglishName = CultureInfo.CurrentUICulture.EnglishName,
NativeName = CultureInfo.CurrentUICulture.NativeName,
IsRightToLeft = CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft,
CultureName = CultureInfo.CurrentUICulture.TextInfo.CultureName,
TwoLetterIsoLanguageName = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
ThreeLetterIsoLanguageName = CultureInfo.CurrentUICulture.ThreeLetterISOLanguageName,
DateTimeFormat = new DateTimeFormatDto
{
CalendarAlgorithmType = CultureInfo.CurrentUICulture.DateTimeFormat.Calendar.AlgorithmType.ToString(),
DateTimeFormatLong = CultureInfo.CurrentUICulture.DateTimeFormat.LongDatePattern,
ShortDatePattern = CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern,
FullDateTimePattern = CultureInfo.CurrentUICulture.DateTimeFormat.FullDateTimePattern,
DateSeparator = CultureInfo.CurrentUICulture.DateTimeFormat.DateSeparator,
ShortTimePattern = CultureInfo.CurrentUICulture.DateTimeFormat.ShortTimePattern,
LongTimePattern = CultureInfo.CurrentUICulture.DateTimeFormat.LongTimePattern,
}
};
}
private async Task<ApplicationSettingConfigurationDto> GetSettingConfigAsync()
{
var result = new ApplicationSettingConfigurationDto

19
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs

@ -128,9 +128,22 @@ namespace Volo.Abp.Cli.ProjectModification
protected virtual List<JProperty> GetAbpPackagesFromPackageJson(JObject fileObject)
{
var dependencies = (JObject)fileObject["dependencies"];
var properties = dependencies.Properties().ToList();
var abpPackages = properties.Where(p => p.Name.StartsWith("@abp/") || p.Name.StartsWith("@volo/")).ToList();
var dependencyList = new [] { "dependencies", "devDependencies", "peerDependencies" };
var abpPackages = new List<JProperty>();
foreach (var dependencyListName in dependencyList)
{
var dependencies = (JObject)fileObject[dependencyListName];
if (dependencies == null)
{
continue;
}
var properties = dependencies.Properties().ToList();
abpPackages.AddRange(properties.Where(p => p.Name.StartsWith("@abp/") || p.Name.StartsWith("@volo/")).ToList());
}
return abpPackages;
}

5
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderOptions.cs

@ -22,5 +22,10 @@ namespace Volo.Abp.IdentityServer
/// Default: true.
/// </summary>
public bool IntegrateToAspNetIdentity { get; set; } = true;
/// <summary>
/// Set false to suppress AddDeveloperSigningCredential() call on the IIdentityServerBuilder.
/// </summary>
public bool AddDeveloperSigningCredential { get; set; } = true;
}
}

13
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs

@ -1,4 +1,5 @@
using IdentityServer4.Services;
using System.Security.Cryptography.X509Certificates;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
@ -24,6 +25,7 @@ namespace Volo.Abp.IdentityServer
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<AbpIdentityServerDomainModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<ClientAutoMapperProfile>(validate: true);
@ -45,9 +47,12 @@ namespace Volo.Abp.IdentityServer
options.Events.RaiseSuccessEvents = true;
});
identityServerBuilder
.AddDeveloperSigningCredential() //TODO: Should be able to change this!
.AddAbpIdentityServer(builderOptions);
if (builderOptions.AddDeveloperSigningCredential)
{
identityServerBuilder = identityServerBuilder.AddDeveloperSigningCredential();
}
identityServerBuilder.AddAbpIdentityServer(builderOptions);
services.ExecutePreConfiguredActions(identityServerBuilder);

3
npm/ng-packs/package.json

@ -92,6 +92,7 @@
"prettier --write",
"tslint --fix",
"git add"
]
],
"dist/*": []
}
}

10
npm/ng-packs/packages/core/src/lib/directives/for.directive.ts

@ -9,7 +9,7 @@ import {
OnChanges,
TemplateRef,
TrackByFunction,
ViewContainerRef
ViewContainerRef,
} from '@angular/core';
import compare from 'just-compare';
import clone from 'just-clone';
@ -25,7 +25,7 @@ class RecordView {
}
@Directive({
selector: '[abpFor]'
selector: '[abpFor]',
})
export class ForDirective implements OnChanges {
@Input('abpForOf')
@ -67,7 +67,7 @@ export class ForDirective implements OnChanges {
constructor(
private tempRef: TemplateRef<AbpForContext>,
private vcRef: ViewContainerRef,
private differs: IterableDiffers
private differs: IterableDiffers,
) {}
private iterateOverAppliedOperations(changes: IterableChanges<any>) {
@ -78,7 +78,7 @@ export class ForDirective implements OnChanges {
const view = this.vcRef.createEmbeddedView(
this.tempRef,
new AbpForContext(null, -1, -1, this.items),
currentIndex
currentIndex,
);
rw.push(new RecordView(record, view));
@ -155,7 +155,7 @@ export class ForDirective implements OnChanges {
const compareFn = this.compareFn;
if (typeof this.filterBy !== 'undefined') {
if (typeof this.filterBy !== 'undefined' && this.filterVal) {
items = items.filter(item => compareFn(item[this.filterBy], this.filterVal));
}

12
npm/ng-packs/packages/core/src/lib/directives/visibility.directive.ts

@ -3,7 +3,7 @@ import { Subject } from 'rxjs';
import snq from 'snq';
@Directive({
selector: '[abpVisibility]'
selector: '[abpVisibility]',
})
export class VisibilityDirective implements AfterViewInit {
@Input('abpVisibility')
@ -17,6 +17,10 @@ export class VisibilityDirective implements AfterViewInit {
constructor(@Optional() private elRef: ElementRef, private renderer: Renderer2) {}
ngAfterViewInit() {
if (!this.focusedElement && this.elRef) {
this.focusedElement = this.elRef.nativeElement;
}
let observer: MutationObserver;
if (this.mutationObserverEnabled) {
observer = new MutationObserver(mutations => {
@ -25,7 +29,7 @@ export class VisibilityDirective implements AfterViewInit {
const htmlNodes = snq(
() => Array.from(mutation.target.childNodes).filter(node => node instanceof HTMLElement),
[]
[],
);
if (!htmlNodes.length) {
@ -40,13 +44,13 @@ export class VisibilityDirective implements AfterViewInit {
});
observer.observe(this.focusedElement, {
childList: true
childList: true,
});
} else {
setTimeout(() => {
const htmlNodes = snq(
() => Array.from(this.focusedElement.childNodes).filter(node => node instanceof HTMLElement),
[]
[],
);
if (!htmlNodes.length) this.removeFromDOM();

8
npm/ng-packs/packages/core/src/lib/states/config.state.ts

@ -278,18 +278,16 @@ function patchRouteDeep(
routes: ABP.FullRoute[],
name: string,
newValue: Partial<ABP.FullRoute>,
parentUrl: string = null,
parentUrl: string = '',
): ABP.FullRoute[] {
routes = routes.map(route => {
if (route.name === name) {
if (newValue.path) {
newValue.url = `${parentUrl}/${newValue.path}`;
}
newValue.url = `${parentUrl}/${(!newValue.path && newValue.path === '' ? route.path : newValue.path) || ''}`;
if (newValue.children && newValue.children.length) {
newValue.children = newValue.children.map(child => ({
...child,
url: `${parentUrl}/${route.path}/${child.path}`,
url: `${newValue.url}/${child.path}`.replace('//', '/'),
}));
}

2
npm/ng-packs/packages/core/src/lib/states/session.state.ts

@ -35,7 +35,7 @@ export class SessionState {
}
@Action(SetTenant)
setTenantId({ patchState }: StateContext<Session.State>, { payload }: SetTenant) {
setTenant({ patchState }: StateContext<Session.State>, { payload }: SetTenant) {
patchState({
tenant: payload,
});

90
npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts

@ -1,11 +1,10 @@
import { Router } from '@angular/router';
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest';
import { Store, NgxsModule } from '@ngxs/store';
import { Observable, of } from 'rxjs';
import { ConfigService, ApplicationConfigurationService, RestService } from '../services';
import { ConfigState } from '../states';
import { HttpClient } from '@angular/common/http';
import { Store } from '@ngxs/store';
import { ReplaySubject, timer, Subject, of } from 'rxjs';
import { Config } from '../models/config';
import { ApplicationConfigurationService, ConfigService } from '../services';
import { ConfigState } from '../states';
import { SetLanguage, PatchRouteByName } from '../actions';
export const CONFIG_STATE_DATA = {
environment: {
@ -110,11 +109,12 @@ export const CONFIG_STATE_DATA = {
},
} as Config.State;
describe('ConfigService', () => {
describe('ConfigState', () => {
let spectator: SpectatorService<ConfigService>;
let store: SpyObject<Store>;
let service: ConfigService;
let state: ConfigState;
let appConfigService: SpyObject<ApplicationConfigurationService>;
const createService = createServiceFactory({
service: ConfigService,
@ -125,6 +125,7 @@ describe('ConfigService', () => {
spectator = createService();
store = spectator.get(Store);
service = spectator.service;
appConfigService = spectator.get(ApplicationConfigurationService);
state = new ConfigState(spectator.get(ApplicationConfigurationService), store);
});
@ -223,8 +224,79 @@ describe('ConfigService', () => {
});
describe('#GetAppConfiguration', () => {
it('should call the getConfiguration of ApplicationConfigurationService and patch the state', () => {
// state.addData()
it('should call the getConfiguration of ApplicationConfigurationService and patch the state', done => {
let patchStateArg;
let dispatchArg;
const configuration = {
setting: { values: { 'Abp.Localization.DefaultLanguage': 'tr;TR' } },
};
const res$ = new ReplaySubject(1);
res$.next(configuration);
const patchState = jest.fn(s => (patchStateArg = s));
const dispatch = jest.fn(a => {
dispatchArg = a;
return of(a);
});
appConfigService.getConfiguration.andReturn(res$);
state.addData({ patchState, dispatch } as any).subscribe();
timer(0).subscribe(() => {
expect(patchStateArg).toEqual(configuration);
expect(dispatchArg instanceof SetLanguage).toBeTruthy();
expect(dispatchArg).toEqual({ payload: 'tr' });
done();
});
});
});
describe('#PatchRouteByName', () => {
it('should should patch the route', () => {
let patchStateArg;
const patchState = jest.fn(s => (patchStateArg = s));
const getState = jest.fn(() => CONFIG_STATE_DATA);
state.patchRoute(
{ patchState, getState } as any,
new PatchRouteByName('::Menu:Home', {
name: 'Home',
path: 'home',
children: [{ path: 'dashboard', name: 'Dashboard' }],
}),
);
expect(patchStateArg.routes[0]).toEqual({
name: 'Home',
path: 'home',
url: '/home',
children: [{ path: 'dashboard', name: 'Dashboard', url: '/home/dashboard' }],
});
});
it('should should patch the route without path', () => {
let patchStateArg;
const patchState = jest.fn(s => (patchStateArg = s));
const getState = jest.fn(() => CONFIG_STATE_DATA);
state.patchRoute(
{ patchState, getState } as any,
new PatchRouteByName('::Menu:Home', {
name: 'Main',
children: [{ path: 'dashboard', name: 'Dashboard' }],
}),
);
expect(patchStateArg.routes[0]).toEqual({
name: 'Main',
path: '',
url: '/',
children: [{ path: 'dashboard', name: 'Dashboard', url: '/dashboard' }],
});
});
});
});

191
npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts

@ -0,0 +1,191 @@
import { SpectatorDirective, createDirectiveFactory } from '@ngneat/spectator/jest';
import { ForDirective } from '../directives/for.directive';
import { uuid } from '../utils';
describe('ForDirective', () => {
let spectator: SpectatorDirective<ForDirective>;
let directive: ForDirective;
const items = [0, 1, 2, 3, 4, 5];
const createDirective = createDirectiveFactory({
directive: ForDirective,
});
describe('basic', () => {
beforeEach(() => {
spectator = createDirective('<ul><li *abpFor="let item of items">{{ item }}</li></ul>', {
hostProps: { items },
});
directive = spectator.directive;
});
test('should be created', () => {
expect(directive).toBeTruthy();
});
test('should be iterated', () => {
const elements = spectator.queryAll('li');
expect(elements[3]).toHaveText('3');
expect(elements).toHaveLength(6);
});
test('should sync the DOM when change items', () => {
(spectator.hostComponent as any).items = [10, 11, 12];
spectator.detectChanges();
const elements = spectator.queryAll('li');
expect(elements[1]).toHaveText('11');
expect(elements).toHaveLength(3);
});
test('should sync the DOM when add an item', () => {
(spectator.hostComponent as any).items = [...items, 6];
spectator.detectChanges();
const elements = spectator.queryAll('li');
expect(elements[6]).toHaveText('6');
expect(elements).toHaveLength(7);
});
});
describe('trackBy', () => {
const trackByFn = (_, item) => item;
beforeEach(() => {
spectator = createDirective('<ul><li *abpFor="let item of items; trackBy: trackByFn">{{ item }}</li></ul>', {
hostProps: { items, trackByFn },
});
directive = spectator.directive;
});
test('should be setted the trackBy', () => {
expect(directive.trackBy).toEqual(trackByFn);
});
});
describe('with basic order', () => {
beforeEach(() => {
spectator = createDirective(
`<ul>
<li
*abpFor="let item of [3,6,2];
orderDir: 'ASC'">
{{ item }}
</li>
</ul>`,
);
directive = spectator.directive;
});
test('should order by asc', () => {
const elements = spectator.queryAll('li');
expect(elements.map(el => el.textContent.trim())).toEqual(['2', '3', '6']);
});
});
describe('with order', () => {
beforeEach(() => {
spectator = createDirective(
`<ul>
<li
*abpFor="let item of [{value: 3}, {value: 6}, {value: 2}];
orderBy: 'value';
orderDir: orderDir">
{{ item.value }}
</li>
</ul>`,
{
hostProps: { orderDir: 'ASC' },
},
);
directive = spectator.directive;
});
test('should order by asc', () => {
const elements = spectator.queryAll('li');
expect(elements.map(el => el.textContent.trim())).toEqual(['2', '3', '6']);
});
test('should order by desc', () => {
(spectator.hostComponent as any).orderDir = 'DESC';
spectator.detectChanges();
const elements = spectator.queryAll('li');
expect(elements.map(el => el.textContent.trim())).toEqual(['6', '3', '2']);
});
});
describe('with filter', () => {
beforeEach(() => {
spectator = createDirective(
`<ul>
<li
*abpFor="let item of [{value: 'test'}, {value: 'abp'}, {value: 'volo'}];
filterBy: 'value';
filterVal: filterVal">
{{ item.value }}
</li>
</ul>`,
{
hostProps: { filterVal: '' },
},
);
directive = spectator.directive;
});
test('should not filter when filterVal is empty,', () => {
const elements = spectator.queryAll('li');
expect(elements.map(el => el.textContent.trim())).toEqual(['test', 'abp', 'volo']);
});
test('should be filtered', () => {
(spectator.hostComponent as any).filterVal = 'volo';
spectator.detectChanges();
expect(spectator.query('li')).toHaveText('volo');
});
test('should not show an element when filter value not match to any text', () => {
(spectator.hostComponent as any).filterVal = 'volos';
spectator.detectChanges();
const elements = spectator.queryAll('li');
expect(elements).toHaveLength(0);
});
});
describe('with empty ref', () => {
beforeEach(() => {
spectator = createDirective(
`<ul>
<li
*abpFor="let item of items;
emptyRef: empty">
{{ item.value }}
</li>
<ng-template #empty>No records found</ng-template>
</ul>`,
{
hostProps: { items: [] },
},
);
directive = spectator.directive;
});
test('should display the empty ref', () => {
expect(spectator.query('ul')).toHaveText('No records found');
expect(spectator.queryAll('li')).toHaveLength(0);
});
test('should not display the empty ref', () => {
expect(spectator.query('ul')).toHaveText('No records found');
expect(spectator.queryAll('li')).toHaveLength(0);
(spectator.hostComponent as any).items = [0];
spectator.detectChanges();
expect(spectator.query('ul')).not.toHaveText('No records found');
expect(spectator.queryAll('li')).toHaveLength(1);
});
});
});

74
npm/ng-packs/packages/core/src/lib/tests/profile.state.spec.ts

@ -0,0 +1,74 @@
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest';
import { Session } from '../models/session';
import { ProfileService } from '../services';
import { ProfileState } from '../states';
import { GetAppConfiguration } from '../actions/config.actions';
import { of } from 'rxjs';
import { Profile } from '../models/profile';
export class DummyClass {}
export const PROFILE_STATE_DATA = {
profile: { userName: 'admin', email: 'info@abp.io', name: 'Admin' },
} as Profile.State;
describe('ProfileState', () => {
let spectator: SpectatorService<DummyClass>;
let state: ProfileState;
let profileService: SpyObject<ProfileService>;
let patchedData;
const patchState = jest.fn(data => (patchedData = data));
const createService = createServiceFactory({
service: DummyClass,
mocks: [ProfileService],
});
beforeEach(() => {
spectator = createService();
profileService = spectator.get(ProfileService);
state = new ProfileState(profileService);
});
describe('#getProfile', () => {
it('should return the current language', () => {
expect(ProfileState.getProfile(PROFILE_STATE_DATA)).toEqual(PROFILE_STATE_DATA.profile);
});
});
describe('#GetProfile', () => {
it('should call the profile service get method and update the state', () => {
const mockData = { userName: 'test', email: 'test@abp.io' };
const spy = jest.spyOn(profileService, 'get');
spy.mockReturnValue(of(mockData as any));
state.profileGet({ patchState } as any).subscribe();
expect(patchedData).toEqual({ profile: mockData });
});
});
describe('#UpdateProfile', () => {
it('should call the profile service update method and update the state', () => {
const mockData = { userName: 'test2', email: 'test@abp.io' };
const spy = jest.spyOn(profileService, 'update');
spy.mockReturnValue(of(mockData as any));
state.profileUpdate({ patchState } as any, { payload: mockData as any }).subscribe();
expect(patchedData).toEqual({ profile: mockData });
});
});
describe('#ChangePassword', () => {
it('should call the profile service changePassword method', () => {
const mockData = { currentPassword: 'test123', newPassword: 'test123' };
const spy = jest.spyOn(profileService, 'changePassword');
spy.mockReturnValue(of(null));
state.changePassword(null, { payload: mockData }).subscribe();
expect(spy).toHaveBeenCalledWith(mockData, true);
});
});
});

70
npm/ng-packs/packages/core/src/lib/tests/session.state.spec.ts

@ -0,0 +1,70 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { Session } from '../models/session';
import { LocalizationService } from '../services';
import { SessionState } from '../states';
import { GetAppConfiguration } from '../actions/config.actions';
import { of } from 'rxjs';
export class DummyClass {}
export const SESSION_STATE_DATA = {
language: 'tr',
tenant: { id: 'd5692aef-2ac6-49cd-9f3e-394c0bd4f8b3', name: 'Test' },
} as Session.State;
describe('SessionState', () => {
let spectator: SpectatorService<DummyClass>;
let state: SessionState;
const createService = createServiceFactory({
service: DummyClass,
mocks: [LocalizationService],
});
beforeEach(() => {
spectator = createService();
state = new SessionState(spectator.get(LocalizationService));
});
describe('#getLanguage', () => {
it('should return the current language', () => {
expect(SessionState.getLanguage(SESSION_STATE_DATA)).toEqual(SESSION_STATE_DATA.language);
});
});
describe('#getTenant', () => {
it('should return the tenant object', () => {
expect(SessionState.getTenant(SESSION_STATE_DATA)).toEqual(SESSION_STATE_DATA.tenant);
});
});
describe('#SetLanguage', () => {
it('should set the language and dispatch the GetAppConfiguration action', () => {
let patchedData;
let dispatchedData;
const patchState = jest.fn(data => (patchedData = data));
const dispatch = jest.fn(action => {
dispatchedData = action;
return of({});
});
const spy = jest.spyOn(spectator.get(LocalizationService), 'registerLocale');
state.setLanguage({ patchState, dispatch } as any, { payload: 'en' }).subscribe();
expect(patchedData).toEqual({ language: 'en' });
expect(dispatchedData instanceof GetAppConfiguration).toBeTruthy();
expect(spy).toHaveBeenCalledWith('en');
});
});
describe('#setTenantId', () => {
it('should set the tenant', () => {
let patchedData;
const patchState = jest.fn(data => (patchedData = data));
const testTenant = { id: '54ae02ba-9289-4c1b-8521-0ea437756288', name: 'Test Tenant' };
state.setTenant({ patchState } as any, { payload: testTenant });
expect(patchedData).toEqual({ tenant: testTenant });
});
});
});

128
npm/ng-packs/packages/core/src/lib/tests/visibility.directive.spec.ts

@ -0,0 +1,128 @@
import { SpectatorDirective, createDirectiveFactory } from '@ngneat/spectator/jest';
import { VisibilityDirective } from '../directives/visibility.directive';
describe('VisibilityDirective', () => {
let spectator: SpectatorDirective<VisibilityDirective>;
let directive: VisibilityDirective;
const createDirective = createDirectiveFactory({
directive: VisibilityDirective,
});
describe('without mutation observer and without content', () => {
beforeEach(() => {
spectator = createDirective('<div [abpVisibility] [mutationObserverEnabled]="false"></div>');
directive = spectator.directive;
});
it('should be created', () => {
expect(directive).toBeTruthy();
});
it('should be removed', done => {
setTimeout(() => {
expect(spectator.query('div')).toBeFalsy();
done();
}, 0);
});
});
describe('without mutation observer and with content', () => {
beforeEach(() => {
spectator = createDirective(
'<div [abpVisibility] [mutationObserverEnabled]="false"><p id="content">Content</p></div>',
);
directive = spectator.directive;
});
it('should not removed', done => {
setTimeout(() => {
expect(spectator.query('div')).toBeTruthy();
done();
}, 0);
});
});
describe('without mutation observer and with focused element', () => {
beforeEach(() => {
spectator = createDirective(
'<div id="main" [abpVisibility]="container" [mutationObserverEnabled]="false"></div><div #container><p id="content">Content</p></div>',
);
directive = spectator.directive;
});
it('should not removed', done => {
setTimeout(() => {
expect(spectator.query('#main')).toBeTruthy();
done();
}, 0);
});
});
describe('without content and with focused element', () => {
beforeEach(() => {
spectator = createDirective(
'<div id="main" [abpVisibility]="container" [mutationObserverEnabled]="false"></div><div #container></div>',
);
directive = spectator.directive;
});
it('should be removed', done => {
setTimeout(() => {
expect(spectator.query('#main')).toBeFalsy();
done();
}, 0);
});
});
describe('with mutation observer and with content', () => {
beforeEach(() => {
spectator = createDirective('<div [abpVisibility]><div id="content">Content</div></div>');
directive = spectator.directive;
});
it('should remove the main div element when content removed', done => {
spectator.query('#content').remove();
setTimeout(() => {
expect(spectator.query('div')).toBeFalsy();
done();
}, 0);
});
it('should not remove the main div element', done => {
spectator.query('div').appendChild(document.createElement('div'));
setTimeout(() => {
expect(spectator.query('div')).toBeTruthy();
done();
}, 100);
});
});
describe('with mutation observer and with focused element', () => {
beforeEach(() => {
spectator = createDirective(
'<div id="main" [abpVisibility]="container"></div><div #container><p id="content">Content</p></div>',
);
directive = spectator.directive;
});
it('should remove the main div element when content removed', done => {
spectator.query('#content').remove();
setTimeout(() => {
expect(spectator.query('#main')).toBeFalsy();
done();
}, 0);
});
it('should not remove the main div element', done => {
spectator.query('#content').appendChild(document.createElement('div'));
setTimeout(() => {
expect(spectator.query('#main')).toBeTruthy();
done();
}, 100);
});
});
});

8
npm/ng-packs/packages/identity/src/lib/components/roles/roles.component.ts

@ -1,6 +1,6 @@
import { ABP } from '@abp/ng.core';
import { ConfirmationService, Toaster } from '@abp/ng.theme.shared';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { Component, TemplateRef, ViewChild, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
@ -13,7 +13,7 @@ import { IdentityState } from '../../states/identity.state';
selector: 'abp-roles',
templateUrl: './roles.component.html',
})
export class RolesComponent {
export class RolesComponent implements OnInit {
@Select(IdentityState.getRoles)
data$: Observable<Identity.RoleItem[]>;
@ -45,6 +45,10 @@ export class RolesComponent {
constructor(private confirmationService: ConfirmationService, private fb: FormBuilder, private store: Store) {}
ngOnInit() {
this.get();
}
onSearch(value) {
this.pageQuery.filter = value;
this.get();

8
npm/ng-packs/packages/identity/src/lib/components/users/users.component.html

@ -112,7 +112,11 @@
</ng-template>
<ng-template #abpBody>
<form [formGroup]="form" (ngSubmit)="save()">
<ng-template #loaderRef
><div class="text-center"><i class="fa fa-pulse fa-spinner"></i></div
></ng-template>
<form *ngIf="form; else loaderRef" [formGroup]="form" (ngSubmit)="save()">
<ngb-tabset>
<ngb-tab [title]="'AbpIdentity::UserInformations' | abpLocalization">
<ng-template ngbTabContent>
@ -210,7 +214,7 @@
<button type="button" class="btn btn-secondary" #abpClose>
{{ 'AbpIdentity::Cancel' | abpLocalization }}
</button>
<abp-button iconClass="fa fa-check" (click)="save()" [disabled]="form.invalid">{{
<abp-button iconClass="fa fa-check" (click)="save()" [disabled]="form?.invalid">{{
'AbpIdentity::Save' | abpLocalization
}}</abp-button>
</ng-template>

48
npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts

@ -1,6 +1,6 @@
import { ABP } from '@abp/ng.core';
import { ConfirmationService, Toaster } from '@abp/ng.theme.shared';
import { Component, TemplateRef, TrackByFunction, ViewChild } from '@angular/core';
import { Component, TemplateRef, TrackByFunction, ViewChild, OnInit } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
@ -13,6 +13,7 @@ import {
GetUserRoles,
GetUsers,
UpdateUser,
GetRoles,
} from '../../actions/identity.actions';
import { Identity } from '../../models/identity';
import { IdentityState } from '../../states/identity.state';
@ -20,7 +21,7 @@ import { IdentityState } from '../../states/identity.state';
selector: 'abp-users',
templateUrl: './users.component.html',
})
export class UsersComponent {
export class UsersComponent implements OnInit {
@Select(IdentityState.getUsers)
data$: Observable<Identity.UserItem[]>;
@ -62,32 +63,39 @@ export class UsersComponent {
constructor(private confirmationService: ConfirmationService, private fb: FormBuilder, private store: Store) {}
ngOnInit() {
this.get();
}
onSearch(value) {
this.pageQuery.filter = value;
this.get();
}
buildForm() {
this.roles = this.store.selectSnapshot(IdentityState.getRoles);
this.form = this.fb.group({
userName: [this.selected.userName || '', [Validators.required, Validators.maxLength(256)]],
email: [this.selected.email || '', [Validators.required, Validators.email, Validators.maxLength(256)]],
name: [this.selected.name || '', [Validators.maxLength(64)]],
surname: [this.selected.surname || '', [Validators.maxLength(64)]],
phoneNumber: [this.selected.phoneNumber || '', [Validators.maxLength(16)]],
lockoutEnabled: [this.selected.twoFactorEnabled || (this.selected.id ? false : true)],
twoFactorEnabled: [this.selected.twoFactorEnabled || (this.selected.id ? false : true)],
roleNames: this.fb.array(
this.roles.map(role =>
this.fb.group({
[role.name]: [!!snq(() => this.selectedUserRoles.find(userRole => userRole.id === role.id))],
}),
this.store.dispatch(new GetRoles()).subscribe(() => {
this.roles = this.store.selectSnapshot(IdentityState.getRoles);
this.form = this.fb.group({
userName: [this.selected.userName || '', [Validators.required, Validators.maxLength(256)]],
email: [this.selected.email || '', [Validators.required, Validators.email, Validators.maxLength(256)]],
name: [this.selected.name || '', [Validators.maxLength(64)]],
surname: [this.selected.surname || '', [Validators.maxLength(64)]],
phoneNumber: [this.selected.phoneNumber || '', [Validators.maxLength(16)]],
lockoutEnabled: [this.selected.twoFactorEnabled || (this.selected.id ? false : true)],
twoFactorEnabled: [this.selected.twoFactorEnabled || (this.selected.id ? false : true)],
roleNames: this.fb.array(
this.roles.map(role =>
this.fb.group({
[role.name]: [!!snq(() => this.selectedUserRoles.find(userRole => userRole.id === role.id))],
}),
),
),
),
});
if (!this.selected.userName) {
this.form.addControl('password', new FormControl('', [Validators.required, Validators.maxLength(32)]));
}
});
if (!this.selected.userName) {
this.form.addControl('password', new FormControl('', [Validators.required, Validators.maxLength(32)]));
}
}
openModal() {

9
npm/ng-packs/packages/identity/src/lib/identity-routing.module.ts

@ -1,10 +1,8 @@
import { AuthGuard, DynamicLayoutComponent, PermissionGuard } from '@abp/ng.core';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { RouterModule, Routes } from '@angular/router';
import { RolesComponent } from './components/roles/roles.component';
import { RoleResolver } from './resolvers/roles.resolver';
import { DynamicLayoutComponent, AuthGuard, PermissionGuard } from '@abp/ng.core';
import { UsersComponent } from './components/users/users.component';
import { UserResolver } from './resolvers/users.resolver';
const routes: Routes = [
{ path: '', redirectTo: 'roles', pathMatch: 'full' },
@ -16,14 +14,12 @@ const routes: Routes = [
{
path: 'roles',
component: RolesComponent,
resolve: [RoleResolver],
data: { requiredPolicy: 'AbpIdentity.Roles' },
},
{
path: 'users',
component: UsersComponent,
data: { requiredPolicy: 'AbpIdentity.Users' },
resolve: [RoleResolver, UserResolver],
},
],
},
@ -32,6 +28,5 @@ const routes: Routes = [
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: [RoleResolver, UserResolver],
})
export class IdentityRoutingModule {}

16
npm/ng-packs/packages/identity/src/lib/resolvers/roles.resolver.ts

@ -1,16 +0,0 @@
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Store } from '@ngxs/store';
import { GetRoles } from '../actions/identity.actions';
import { Identity } from '../models/identity';
import { IdentityState } from '../states/identity.state';
@Injectable()
export class RoleResolver implements Resolve<Identity.State> {
constructor(private store: Store) {}
resolve() {
const roles = this.store.selectSnapshot(IdentityState.getRoles);
return roles && roles.length ? null : this.store.dispatch(new GetRoles());
}
}

16
npm/ng-packs/packages/identity/src/lib/resolvers/users.resolver.ts

@ -1,16 +0,0 @@
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Store } from '@ngxs/store';
import { GetUsers } from '../actions/identity.actions';
import { Identity } from '../models/identity';
import { IdentityState } from '../states/identity.state';
@Injectable()
export class UserResolver implements Resolve<Identity.State> {
constructor(private store: Store) {}
resolve() {
const users = this.store.selectSnapshot(IdentityState.getUsers);
return users && users.length ? null : this.store.dispatch(new GetUsers());
}
}

8
npm/ng-packs/packages/identity/src/lib/states/identity.state.ts

@ -23,22 +23,22 @@ import { IdentityService } from '../services/identity.service';
export class IdentityState {
@Selector()
static getRoles({ roles }: Identity.State): Identity.RoleItem[] {
return roles.items;
return roles.items || [];
}
@Selector()
static getRolesTotalCount({ roles }: Identity.State): number {
return roles.totalCount;
return roles.totalCount || 0;
}
@Selector()
static getUsers({ users }: Identity.State): Identity.UserItem[] {
return users.items;
return users.items || [];
}
@Selector()
static getUsersTotalCount({ users }: Identity.State): number {
return users.totalCount;
return users.totalCount || 0;
}
constructor(private identityService: IdentityService) {}

1
npm/ng-packs/packages/identity/src/public-api.ts

@ -7,6 +7,5 @@ export * from './lib/actions/identity.actions';
export * from './lib/components/roles/roles.component';
export * from './lib/constants/routes';
export * from './lib/models/identity';
export * from './lib/resolvers/roles.resolver';
export * from './lib/services/identity.service';
export * from './lib/states/identity.state';

14
npm/ng-packs/packages/tenant-management/src/lib/components/tenants/tenants.component.ts

@ -1,15 +1,15 @@
import { ABP } from '@abp/ng.core';
import { ConfirmationService, Toaster } from '@abp/ng.theme.shared';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Select, Store } from '@ngxs/store';
import { Observable, Subject } from 'rxjs';
import { debounceTime, finalize, pluck, switchMap, take } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { finalize, pluck, switchMap, take } from 'rxjs/operators';
import {
CreateTenant,
DeleteTenant,
GetTenants,
GetTenantById,
GetTenants,
UpdateTenant,
} from '../../actions/tenant-management.actions';
import { TenantManagementService } from '../../services/tenant-management.service';
@ -25,7 +25,7 @@ interface SelectedModalContent {
selector: 'abp-tenants',
templateUrl: './tenants.component.html',
})
export class TenantsComponent {
export class TenantsComponent implements OnInit {
@Select(TenantManagementState.get)
data$: Observable<ABP.BasicItem[]>;
@ -81,6 +81,10 @@ export class TenantsComponent {
private store: Store,
) {}
ngOnInit() {
this.get();
}
onSearch(value) {
this.pageQuery.filter = value;
this.get();

1
npm/ng-packs/packages/tenant-management/src/lib/resolvers/index.ts

@ -1 +0,0 @@
export * from './tenants.resolver';

16
npm/ng-packs/packages/tenant-management/src/lib/resolvers/tenants.resolver.ts

@ -1,16 +0,0 @@
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Store } from '@ngxs/store';
import { GetTenants } from '../actions/tenant-management.actions';
import { TenantManagement } from '../models/tenant-management';
import { TenantManagementState } from '../states/tenant-management.state';
@Injectable()
export class TenantsResolver implements Resolve<TenantManagement.State> {
constructor(private store: Store) {}
resolve() {
const data = this.store.selectSnapshot(TenantManagementState.get);
return data && data.length ? null : this.store.dispatch(new GetTenants());
}
}

4
npm/ng-packs/packages/tenant-management/src/lib/tenant-management-routing.module.ts

@ -1,7 +1,6 @@
import { AuthGuard, DynamicLayoutComponent, PermissionGuard } from '@abp/ng.core';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TenantsResolver } from './resolvers/tenants.resolver';
import { TenantsComponent } from './components/tenants/tenants.component';
const routes: Routes = [
@ -11,13 +10,12 @@ const routes: Routes = [
component: DynamicLayoutComponent,
canActivate: [AuthGuard, PermissionGuard],
data: { requiredPolicy: 'AbpTenantManagement.Tenants' },
children: [{ path: '', component: TenantsComponent, resolve: [TenantsResolver] }],
children: [{ path: '', component: TenantsComponent }],
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: [TenantsResolver],
})
export class TenantManagementRoutingModule {}

1
npm/ng-packs/packages/tenant-management/src/public-api.ts

@ -3,6 +3,5 @@ export * from './lib/actions';
export * from './lib/components';
export * from './lib/constants';
export * from './lib/models';
export * from './lib/resolvers';
export * from './lib/services';
export * from './lib/states';

41
npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts

@ -1,14 +1,24 @@
import { Component, Input } from '@angular/core';
import { Component, EventEmitter, Input, Output, ViewChild, ElementRef, Renderer2, OnInit } from '@angular/core';
import { ABP } from '@abp/ng.core';
@Component({
selector: 'abp-button',
// tslint:disable-next-line: component-max-inline-declarations
template: `
<button [attr.type]="type" [ngClass]="buttonClass" [disabled]="loading || disabled">
<button
#button
[attr.type]="type"
[ngClass]="buttonClass"
[disabled]="loading || disabled"
(click)="click.emit($event)"
(focus)="focus.emit($event)"
(blur)="blur.emit($event)"
>
<i [ngClass]="icon" class="mr-1"></i><ng-content></ng-content>
</button>
`,
})
export class ButtonComponent {
export class ButtonComponent implements OnInit {
@Input()
buttonClass = 'btn btn-primary';
@ -24,6 +34,21 @@ export class ButtonComponent {
@Input()
disabled = false;
@Input()
attributes: ABP.Dictionary<string>;
// tslint:disable-next-line: no-output-native
@Output() readonly click = new EventEmitter<MouseEvent>();
// tslint:disable-next-line: no-output-native
@Output() readonly focus = new EventEmitter<FocusEvent>();
// tslint:disable-next-line: no-output-native
@Output() readonly blur = new EventEmitter<FocusEvent>();
@ViewChild('button', { static: true })
buttonRef: ElementRef<HTMLButtonElement>;
/**
* @deprecated Use buttonType instead. To be deleted in v1
*/
@ -32,4 +57,14 @@ export class ButtonComponent {
get icon(): string {
return `${this.loading ? 'fa fa-pulse fa-spinner' : this.iconClass || 'd-none'}`;
}
constructor(private renderer: Renderer2) {}
ngOnInit() {
if (this.attributes) {
Object.keys(this.attributes).forEach(key => {
this.renderer.setAttribute(this.buttonRef.nativeElement, key, this.attributes[key]);
});
}
}
}

39
npm/ng-packs/packages/theme-shared/src/lib/tests/button.component.spec.ts

@ -2,46 +2,55 @@ import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest';
import { ButtonComponent } from '../components';
describe('ButtonComponent', () => {
let host: SpectatorHost<ButtonComponent>;
let spectator: SpectatorHost<ButtonComponent>;
const createHost = createHostFactory(ButtonComponent);
beforeEach(() => (host = createHost('<abp-button iconClass="fa fa-check">Button</abp-button>')));
beforeEach(
() =>
(spectator = createHost('<abp-button iconClass="fa fa-check" [attributes]="attributes">Button</abp-button>', {
hostProps: { attributes: { autofocus: '', name: 'abp-button' } },
})),
);
it('should display the button', () => {
expect(host.query('button')).toBeTruthy();
expect(spectator.query('button')).toBeTruthy();
});
it('should equal the default classes to btn btn-primary', () => {
expect(host.query('button')).toHaveClass('btn btn-primary');
expect(spectator.query('button')).toHaveClass('btn btn-primary');
});
it('should equal the default type to button', () => {
expect(host.query('button')).toHaveAttribute('type', 'button');
expect(spectator.query('button')).toHaveAttribute('type', 'button');
});
it('should enabled', () => {
expect(host.query('[disabled]')).toBeFalsy();
expect(spectator.query('[disabled]')).toBeFalsy();
});
it('should have the text content', () => {
expect(host.query('button')).toHaveText('Button');
expect(spectator.query('button')).toHaveText('Button');
});
it('should display the icon', () => {
expect(host.query('i.d-none')).toBeFalsy();
expect(host.query('i')).toHaveClass('fa');
expect(spectator.query('i.d-none')).toBeFalsy();
expect(spectator.query('i')).toHaveClass('fa');
});
it('should display the spinner icon', () => {
host.component.loading = true;
host.detectComponentChanges();
expect(host.query('i')).toHaveClass('fa-spinner');
spectator.component.loading = true;
spectator.detectComponentChanges();
expect(spectator.query('i')).toHaveClass('fa-spinner');
});
it('should disabled when the loading input is true', () => {
host.component.loading = true;
host.detectComponentChanges();
expect(host.query('[disabled]')).toBeDefined();
spectator.component.loading = true;
spectator.detectComponentChanges();
expect(spectator.query('[disabled]')).toBeTruthy();
});
it('should disabled when the loading input is true', () => {
expect(spectator.query('[autofocus][name="abp-button"]')).toBeTruthy();
});
});

2
npm/ng-packs/scripts/build.js

@ -37,7 +37,7 @@ import fse from 'fs-extra';
});
await execa('git', ['add', '../dist/*', '../package.json'], { stdout: 'inherit' });
await execa('git', ['commit', '-m', 'Build ng packages'], { stdout: 'inherit' });
await execa('git', ['commit', '--no-verify', '-m', 'Build ng packages'], { stdout: 'inherit' });
process.exit(0);
})();

16
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication.sln

@ -1,9 +1,9 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2002
# Visual Studio Version 16
VisualStudioVersion = 16.0.29326.143
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicAspNetCoreApplication", "BasicAspNetCoreApplication\BasicAspNetCoreApplication.csproj", "{FDE52C9E-87E7-485F-B6E1-97C09E8254D7}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicAspNetCoreApplication", "BasicAspNetCoreApplication\BasicAspNetCoreApplication.csproj", "{069D79DF-2340-4101-9B6E-32FEEC6893A8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -11,15 +11,15 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FDE52C9E-87E7-485F-B6E1-97C09E8254D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FDE52C9E-87E7-485F-B6E1-97C09E8254D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FDE52C9E-87E7-485F-B6E1-97C09E8254D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FDE52C9E-87E7-485F-B6E1-97C09E8254D7}.Release|Any CPU.Build.0 = Release|Any CPU
{069D79DF-2340-4101-9B6E-32FEEC6893A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{069D79DF-2340-4101-9B6E-32FEEC6893A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{069D79DF-2340-4101-9B6E-32FEEC6893A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{069D79DF-2340-4101-9B6E-32FEEC6893A8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BA01D8A1-8D4F-46A4-9BDB-30F327AE4605}
SolutionGuid = {9AC9422D-35CC-4A8E-9F5B-D695565E9B45}
EndGlobalSection
EndGlobal

22
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/AppModule.cs

@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc;
@ -8,19 +7,10 @@ using Volo.Abp.Modularity;
namespace BasicAspNetCoreApplication
{
[DependsOn(
typeof(AbpAspNetCoreMvcModule),
typeof(AbpAutofacModule)
)]
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
[DependsOn(typeof(AbpAutofacModule))] //Add dependency to ABP Autofac module
public class AppModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddMvc();
context.Services.AddAssemblyOf<AppModule>();
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
@ -30,10 +20,14 @@ namespace BasicAspNetCoreApplication
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseMvcWithDefaultRouteAndArea();
}
}
}
}

10
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/BasicAspNetCoreApplication.csproj

@ -1,12 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="0.20.0" />
<PackageReference Include="Volo.Abp.Autofac" Version="0.20.0" />
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="0.22.0" />
<PackageReference Include="Volo.Abp.Autofac" Version="0.22.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\" />
</ItemGroup>
</Project>

13
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Controllers/HomeController.cs

@ -1,13 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace BasicAspNetCoreApplication.Controllers
{
public class HomeController : AbpController
{
public IActionResult Index()
{
return Content("Hello World!");
}
}
}

26
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Error.cshtml

@ -0,0 +1,26 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

31
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Error.cshtml.cs

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace BasicAspNetCoreApplication.Pages
{
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
private readonly ILogger<ErrorModel> _logger;
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
}

10
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Index.cshtml

@ -0,0 +1,10 @@
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

25
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Index.cshtml.cs

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace BasicAspNetCoreApplication.Pages
{
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}

8
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Privacy.cshtml

@ -0,0 +1,8 @@
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

24
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Privacy.cshtml.cs

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace BasicAspNetCoreApplication.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}

50
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Shared/_Layout.cshtml

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - BasicAspNetCoreApplication</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">BasicAspNetCoreApplication</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2019 - BasicAspNetCoreApplication - <a asp-area="" asp-page="/Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>

2
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/Shared/_ValidationScriptsPartial.cshtml

@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

3
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/_ViewImports.cshtml

@ -0,0 +1,3 @@
@using BasicAspNetCoreApplication
@namespace BasicAspNetCoreApplication.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

3
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Pages/_ViewStart.cshtml

@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

15
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Program.cs

@ -1,5 +1,5 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace BasicAspNetCoreApplication
{
@ -7,12 +7,15 @@ namespace BasicAspNetCoreApplication
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
CreateHostBuilder(args).Build().Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseAutofac();
}
}

14
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Properties/launchSettings.json

@ -1,10 +1,10 @@
{
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:63233/",
"sslPort": 0
"applicationUrl": "http://localhost:54720",
"sslPort": 44389
}
},
"profiles": {
@ -18,10 +18,10 @@
"BasicAspNetCoreApplication": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:63234/"
}
}
}
}

11
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/Startup.cs

@ -1,20 +1,13 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
namespace BasicAspNetCoreApplication
{
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
public void ConfigureServices(IServiceCollection services)
{
services.AddApplication<AppModule>(options =>
{
options.UseAutofac();
});
return services.BuildServiceProviderFromFactory();
services.AddApplication<AppModule>();
}
public void Configure(IApplicationBuilder app)

9
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/appsettings.Development.json

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

10
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/appsettings.json

@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

71
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/css/site.css

@ -0,0 +1,71 @@
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}
/* Provide sufficient contrast against white background */
a {
color: #0366d6;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
/* Sticky footer styles
-------------------------------------------------- */
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px; /* Vertically center the text there */
}

BIN
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

4
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/js/site.js

@ -0,0 +1,4 @@
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your Javascript code.

22
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/LICENSE

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2011-2018 Twitter, Inc.
Copyright (c) 2011-2018 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

3719
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css

File diff suppressed because it is too large

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map

File diff suppressed because one or more lines are too long

7
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css

File diff suppressed because one or more lines are too long

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map

File diff suppressed because one or more lines are too long

331
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css

@ -0,0 +1,331 @@
/*!
* Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
* Copyright 2011-2019 The Bootstrap Authors
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
text-align: left;
background-color: #fff;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg {
overflow: hidden;
vertical-align: middle;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: 0.5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
select {
word-wrap: normal;
}
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button:not(:disabled),
[type="button"]:not(:disabled),
[type="reset"]:not(:disabled),
[type="submit"]:not(:disabled) {
cursor: pointer;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
cursor: pointer;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map

File diff suppressed because one or more lines are too long

8
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css

@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
* Copyright 2011-2019 The Bootstrap Authors
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map

File diff suppressed because one or more lines are too long

10038
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap.css

File diff suppressed because it is too large

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map

File diff suppressed because one or more lines are too long

7
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css

File diff suppressed because one or more lines are too long

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map

File diff suppressed because one or more lines are too long

7013
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js

File diff suppressed because it is too large

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map

File diff suppressed because one or more lines are too long

7
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js

File diff suppressed because one or more lines are too long

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map

File diff suppressed because one or more lines are too long

4435
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.js

File diff suppressed because it is too large

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map

File diff suppressed because one or more lines are too long

7
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js

File diff suppressed because one or more lines are too long

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map

File diff suppressed because one or more lines are too long

12
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt

@ -0,0 +1,12 @@
Copyright (c) .NET Foundation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
these files except in compliance with the License. You may obtain a copy of the
License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

432
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js

@ -0,0 +1,432 @@
// Unobtrusive validation support library for jQuery and jQuery Validate
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// @version v3.2.11
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global document: false, jQuery: false */
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define("jquery.validate.unobtrusive", ['jquery-validation'], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS-like environments that support module.exports
module.exports = factory(require('jquery-validation'));
} else {
// Browser global
jQuery.validator.unobtrusive = factory(jQuery);
}
}(function ($) {
var $jQval = $.validator,
adapters,
data_validation = "unobtrusiveValidation";
function setValidationValues(options, ruleName, value) {
options.rules[ruleName] = value;
if (options.message) {
options.messages[ruleName] = options.message;
}
}
function splitAndTrim(value) {
return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
}
function escapeAttributeValue(value) {
// As mentioned on http://api.jquery.com/category/selectors/
return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
}
function getModelPrefix(fieldName) {
return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}
function appendModelPrefix(value, prefix) {
if (value.indexOf("*.") === 0) {
value = value.replace("*.", prefix);
}
return value;
}
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
function onErrors(event, validator) { // 'this' is the form element
var container = $(this).find("[data-valmsg-summary=true]"),
list = container.find("ul");
if (list && list.length && validator.errorList.length) {
list.empty();
container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
$.each(validator.errorList, function () {
$("<li />").html(this.message).appendTo(list);
});
}
}
function onSuccess(error) { // 'this' is the form element
var container = error.data("unobtrusiveContainer");
if (container) {
var replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
container.addClass("field-validation-valid").removeClass("field-validation-error");
error.removeData("unobtrusiveContainer");
if (replace) {
container.empty();
}
}
}
function onReset(event) { // 'this' is the form element
var $form = $(this),
key = '__jquery_unobtrusive_validation_form_reset';
if ($form.data(key)) {
return;
}
// Set a flag that indicates we're currently resetting the form.
$form.data(key, true);
try {
$form.data("validator").resetForm();
} finally {
$form.removeData(key);
}
$form.find(".validation-summary-errors")
.addClass("validation-summary-valid")
.removeClass("validation-summary-errors");
$form.find(".field-validation-error")
.addClass("field-validation-valid")
.removeClass("field-validation-error")
.removeData("unobtrusiveContainer")
.find(">*") // If we were using valmsg-replace, get the underlying error
.removeData("unobtrusiveContainer");
}
function validationInfo(form) {
var $form = $(form),
result = $form.data(data_validation),
onResetProxy = $.proxy(onReset, form),
defaultOptions = $jQval.unobtrusive.options || {},
execInContext = function (name, args) {
var func = defaultOptions[name];
func && $.isFunction(func) && func.apply(form, args);
};
if (!result) {
result = {
options: { // options structure passed to jQuery Validate's validate() method
errorClass: defaultOptions.errorClass || "input-validation-error",
errorElement: defaultOptions.errorElement || "span",
errorPlacement: function () {
onError.apply(form, arguments);
execInContext("errorPlacement", arguments);
},
invalidHandler: function () {
onErrors.apply(form, arguments);
execInContext("invalidHandler", arguments);
},
messages: {},
rules: {},
success: function () {
onSuccess.apply(form, arguments);
execInContext("success", arguments);
}
},
attachValidation: function () {
$form
.off("reset." + data_validation, onResetProxy)
.on("reset." + data_validation, onResetProxy)
.validate(this.options);
},
validate: function () { // a validation function that is called by unobtrusive Ajax
$form.validate();
return $form.valid();
}
};
$form.data(data_validation, result);
}
return result;
}
$jQval.unobtrusive = {
adapters: [],
parseElement: function (element, skipAttach) {
/// <summary>
/// Parses a single HTML element for unobtrusive validation attributes.
/// </summary>
/// <param name="element" domElement="true">The HTML element to be parsed.</param>
/// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
/// validation to the form. If parsing just this single element, you should specify true.
/// If parsing several elements, you should specify false, and manually attach the validation
/// to the form when you are finished. The default is false.</param>
var $element = $(element),
form = $element.parents("form")[0],
valInfo, rules, messages;
if (!form) { // Cannot do client-side validation without a form
return;
}
valInfo = validationInfo(form);
valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};
$.each(this.adapters, function () {
var prefix = "data-val-" + this.name,
message = $element.attr(prefix),
paramValues = {};
if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
prefix += "-";
$.each(this.params, function () {
paramValues[this] = $element.attr(prefix + this);
});
this.adapt({
element: element,
form: form,
message: message,
params: paramValues,
rules: rules,
messages: messages
});
}
});
$.extend(rules, { "__dummy__": true });
if (!skipAttach) {
valInfo.attachValidation();
}
},
parse: function (selector) {
/// <summary>
/// Parses all the HTML elements in the specified selector. It looks for input elements decorated
/// with the [data-val=true] attribute value and enables validation according to the data-val-*
/// attribute values.
/// </summary>
/// <param name="selector" type="String">Any valid jQuery selector.</param>
// $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
// element with data-val=true
var $selector = $(selector),
$forms = $selector.parents()
.addBack()
.filter("form")
.add($selector.find("form"))
.has("[data-val=true]");
$selector.find("[data-val=true]").each(function () {
$jQval.unobtrusive.parseElement(this, true);
});
$forms.each(function () {
var info = validationInfo(this);
if (info) {
info.attachValidation();
}
});
}
};
adapters = $jQval.unobtrusive.adapters;
adapters.add = function (adapterName, params, fn) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
/// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
/// mmmm is the parameter name).</param>
/// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
/// attributes into jQuery Validate rules and/or messages.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
if (!fn) { // Called with no params, just a function
fn = params;
params = [];
}
this.push({ name: adapterName, params: params, adapt: fn });
return this;
};
adapters.addBool = function (adapterName, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has no parameter values.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, function (options) {
setValidationValues(options, ruleName || adapterName, true);
});
};
adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
/// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
/// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a minimum value.</param>
/// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
/// have a maximum value.</param>
/// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
/// have both a minimum and maximum value.</param>
/// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the minimum value. The default is "min".</param>
/// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
/// contains the maximum value. The default is "max".</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
var min = options.params.min,
max = options.params.max;
if (min && max) {
setValidationValues(options, minMaxRuleName, [min, max]);
}
else if (min) {
setValidationValues(options, minRuleName, min);
}
else if (max) {
setValidationValues(options, maxRuleName, max);
}
});
};
adapters.addSingleVal = function (adapterName, attribute, ruleName) {
/// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
/// the jQuery Validate validation rule has a single value.</summary>
/// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
/// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
/// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
/// The default is "val".</param>
/// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
/// of adapterName will be used instead.</param>
/// <returns type="jQuery.validator.unobtrusive.adapters" />
return this.add(adapterName, [attribute || "val"], function (options) {
setValidationValues(options, ruleName || adapterName, options.params[attribute]);
});
};
$jQval.addMethod("__dummy__", function (value, element, params) {
return true;
});
$jQval.addMethod("regex", function (value, element, params) {
var match;
if (this.optional(element)) {
return true;
}
match = new RegExp(params).exec(value);
return (match && (match.index === 0) && (match[0].length === value.length));
});
$jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
var match;
if (nonalphamin) {
match = value.match(/\W/g);
match = match && match.length >= nonalphamin;
}
return match;
});
if ($jQval.methods.extension) {
adapters.addSingleVal("accept", "mimtype");
adapters.addSingleVal("extension", "extension");
} else {
// for backward compatibility, when the 'extension' validation method does not exist, such as with versions
// of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
// validating the extension, and ignore mime-type validations as they are not supported.
adapters.addSingleVal("extension", "extension", "accept");
}
adapters.addSingleVal("regex", "pattern");
adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
adapters.add("equalto", ["other"], function (options) {
var prefix = getModelPrefix(options.element.name),
other = options.params.other,
fullOtherName = appendModelPrefix(other, prefix),
element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
setValidationValues(options, "equalTo", element);
});
adapters.add("required", function (options) {
// jQuery Validate equates "required" with "mandatory" for checkbox elements
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
setValidationValues(options, "required", true);
}
});
adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
var value = {
url: options.params.url,
type: options.params.type || "GET",
data: {}
},
prefix = getModelPrefix(options.element.name);
$.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
var paramName = appendModelPrefix(fieldName, prefix);
value.data[paramName] = function () {
var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
// For checkboxes and radio buttons, only pick up values from checked fields.
if (field.is(":checkbox")) {
return field.filter(":checked").val() || field.filter(":hidden").val() || '';
}
else if (field.is(":radio")) {
return field.filter(":checked").val() || '';
}
return field.val();
};
});
setValidationValues(options, "remote", value);
});
adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
if (options.params.min) {
setValidationValues(options, "minlength", options.params.min);
}
if (options.params.nonalphamin) {
setValidationValues(options, "nonalphamin", options.params.nonalphamin);
}
if (options.params.regex) {
setValidationValues(options, "regex", options.params.regex);
}
});
adapters.add("fileextensions", ["extensions"], function (options) {
setValidationValues(options, "extension", options.params.extensions);
});
$(function () {
$jQval.unobtrusive.parse(document);
});
return $jQval.unobtrusive;
}));

5
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js

File diff suppressed because one or more lines are too long

22
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/LICENSE.md

@ -0,0 +1,22 @@
The MIT License (MIT)
=====================
Copyright Jörn Zaefferer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

1158
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/dist/additional-methods.js

File diff suppressed because it is too large

4
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/dist/additional-methods.min.js

File diff suppressed because one or more lines are too long

1601
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/dist/jquery.validate.js

File diff suppressed because it is too large

4
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js

File diff suppressed because one or more lines are too long

36
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery/LICENSE.txt

@ -0,0 +1,36 @@
Copyright JS Foundation and other contributors, https://js.foundation/
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/jquery/jquery
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
All files located in the node_modules and external directories are
externally maintained libraries used by this software which have their
own licenses; we recommend you read them, as their terms may differ from
the terms above.

10364
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery/dist/jquery.js

File diff suppressed because it is too large

2
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery/dist/jquery.min.js

File diff suppressed because one or more lines are too long

1
samples/BasicAspNetCoreApplication/BasicAspNetCoreApplication/wwwroot/lib/jquery/dist/jquery.min.map

File diff suppressed because one or more lines are too long

30
templates/app/angular/package.json

@ -18,17 +18,14 @@
"@abp/ng.setting-management": "^0.9.1",
"@abp/ng.tenant-management": "^0.9.1",
"@abp/ng.theme.basic": "^0.9.1",
"@angular/animations": "~8.2.10",
"@angular/common": "~8.2.10",
"@angular/compiler": "~8.2.10",
"@angular/core": "~8.2.10",
"@angular/forms": "~8.2.10",
"@angular/platform-browser": "~8.2.10",
"@angular/platform-browser-dynamic": "~8.2.10",
"@angular/router": "~8.2.10",
"@angularclass/hmr": "^2.1.3",
"@ngxs/devtools-plugin": "^3.5.0",
"@ngxs/hmr-plugin": "^3.5.0",
"@angular/animations": "~8.2.11",
"@angular/common": "~8.2.11",
"@angular/compiler": "~8.2.11",
"@angular/core": "~8.2.11",
"@angular/forms": "~8.2.11",
"@angular/platform-browser": "~8.2.11",
"@angular/platform-browser-dynamic": "~8.2.11",
"@angular/router": "~8.2.11",
"rxjs": "~6.4.0",
"tslib": "^1.10.0",
"zone.js": "~0.9.1"
@ -36,19 +33,22 @@
"devDependencies": {
"@angular-devkit/build-angular": "~0.803.9",
"@angular/cli": "~8.3.9",
"@angular/compiler-cli": "~8.2.10",
"@angular/language-service": "~8.2.10",
"@angular/compiler-cli": "~8.2.11",
"@angular/language-service": "~8.2.11",
"@angularclass/hmr": "^2.1.3",
"@ngxs/hmr-plugin": "^3.5.0",
"@ngxs/logger-plugin": "^3.5.1",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"karma-jasmine": "~2.0.1",
"karma": "~4.1.0",
"ngxs-schematic": "^1.1.9",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",

8
templates/app/angular/src/app/app.module.ts

@ -3,7 +3,7 @@ import { LAYOUTS } from '@abp/ng.theme.basic';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin';
import { NgxsModule } from '@ngxs/store';
import { OAuthModule } from 'angular-oauth2-oidc';
import { environment } from '../environments/environment';
@ -16,16 +16,18 @@ import { IdentityConfigModule } from '@abp/ng.identity.config';
import { TenantManagementConfigModule } from '@abp/ng.tenant-management.config';
import { SettingManagementConfigModule } from '@abp/ng.setting-management.config';
const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })];
@NgModule({
declarations: [AppComponent],
imports: [
ThemeSharedModule.forRoot(),
CoreModule.forRoot({
environment,
requirements: {
layouts: LAYOUTS,
},
}),
ThemeSharedModule.forRoot(),
OAuthModule.forRoot(),
NgxsModule.forRoot([]),
AccountConfigModule.forRoot({ redirectUrl: '/' }),
@ -37,7 +39,7 @@ import { SettingManagementConfigModule } from '@abp/ng.setting-management.config
AppRoutingModule,
SharedModule,
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production }),
...(environment.production ? [] : LOGGERS),
],
bootstrap: [AppComponent],
})

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/Controllers/HomeController.cs

@ -9,7 +9,7 @@ namespace MyCompanyName.MyProjectName.Controllers
{
//TODO: Enabled once Swagger supports ASP.NET Core 3.x
//return Redirect("/swagger");
return Content("OK: MyCompanyName.MyProjectName.HttpApi.HostWithIds is running...");
return Content("OK: MyCompanyName.MyProjectName.HttpApi.Host is running...");
}
}
}

Loading…
Cancel
Save