Browse Source

Merge branch 'dev' into cms-kit/blog-post-cover-image

pull/7963/head
Ilkay Ilknur 6 years ago
parent
commit
e4b3b02a8e
  1. 101
      docs/en/UI/Angular/HTTP-Requests.md
  2. 2
      docs/en/UI/Angular/Router-Events.md
  3. BIN
      docs/en/UI/Angular/images/custom-error-handler-404-component.jpg
  4. BIN
      docs/en/UI/Angular/images/custom-error-handler-toaster-message.jpg
  5. 78
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/MicroserviceServiceRandomPortStep.cs
  6. 54
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromTyeStep.cs
  7. 6
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceTemplateBase.cs
  8. 10
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs
  9. 13
      framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionLoggingExtensions.cs
  10. 27
      framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs
  11. 6
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs
  12. 20
      framework/src/Volo.Abp.Core/Volo/Abp/Logging/AbpInitLogEntry.cs
  13. 38
      framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLogger.cs
  14. 15
      framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLoggerFactory.cs
  15. 10
      framework/src/Volo.Abp.Core/Volo/Abp/Logging/IInitLogger.cs
  16. 7
      framework/src/Volo.Abp.Core/Volo/Abp/Logging/IInitLoggerFactory.cs
  17. 15
      framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleHelper.cs
  18. 10
      framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs
  19. 12
      framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs
  20. 8
      framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceExtensions.cs
  21. 7
      framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceList.cs
  22. 10
      framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs
  23. 4
      modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo.CmsKit.HttpApi.csproj
  24. 4
      modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo/CmsKit/CmsKitHttpApiModule.cs
  25. 229
      npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts
  26. 9
      npm/ng-packs/packages/theme-shared/src/lib/models/common.ts
  27. 6
      npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts

101
docs/en/UI/Angular/HTTP-Requests.md

@ -27,13 +27,13 @@ An `HttpInterceptor` is able to catch `HttpErrorResponse`  and can be used for
## RestService ## RestService
ABP core module has a utility service for HTTP requests: `RestService`. Unless explicitly configured otherwise, it catches HTTP errors and dispatches a `RestOccurError` action. This action is then captured by the `ErrorHandler` introduced by the `ThemeSharedModule`. Since you should already import this module in your app, when the `RestService` is used, all HTTP errors get automatically handled by deafult. ABP core module has a utility service for HTTP requests: `RestService`. Unless explicitly configured otherwise, it catches HTTP errors and dispatches a `RestOccurError` action. This action is then captured by the `ErrorHandler` introduced by the `ThemeSharedModule`. Since you should already import this module in your app, when the `RestService` is used, all HTTP errors get automatically handled by default.
### Getting Started with RestService ### Getting Started with RestService
In order to use the `RestService`, you must inject it in your class as a dependency. In order to use the `RestService`, you must inject it in your class as a dependency.
```js ```js
import { RestService } from '@abp/ng.core'; import { RestService } from '@abp/ng.core';
@ -200,6 +200,101 @@ getSomeCustomHeaderValue() {
} }
``` ```
You may find `Rest.Observe` enum [here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L10).
You may find `Rest.Observe` enum [here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L10). ## HTTP Error Handling
When the `RestService` is used, all HTTP errors are automatically handled by `ErrorHandler` which is a service that exposed by the `@abp/ng.theme.shared` package.
### Custom HTTP Error Handler
A custom HTTP error handler can be registered to an injection token named `HTTP_ERROR_HANDLER`. If a custom handler function is registered, the `ErrorHandler` executes that function.
See an example:
```js
// http-error-handler.ts
import { ContentProjectionService, PROJECTION_STRATEGY } from '@abp/ng.core';
import { ToasterService } from '@abp/ng.theme.shared';
import { HttpErrorResponse } from '@angular/common/http';
import { Injector } from '@angular/core';
import { throwError } from 'rxjs';
import { Error404Component } from './error404/error404.component';
export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
if (httpError.status === 400) {
const toaster = injector.get(ToasterService);
toaster.error(httpError.error?.error?.message || 'Bad request!', '400');
return;
}
if (httpError.status === 404) {
const contentProjection = injector.get(ContentProjectionService);
contentProjection.projectContent(PROJECTION_STRATEGY.AppendComponentToBody(Error404Component));
return;
}
return throwError(httpError);
}
// app.module.ts
import { Error404Component } from './error404/error404.component';
import { handleHttpErrors } from './http-error-handling';
import { HTTP_ERROR_HANDLER, ... } from '@abp/ng.theme.shared';
@NgModule({
// ...
providers: [
// ...
{ provide: HTTP_ERROR_HANDLER, useValue: handleHttpErrors }
],
declarations: [
//...
Error404Component],
})
export class AppModule {}
```
In the example above:
- Created a function named `handleHttpErrors` and defined as value of the `HTTP_ERROR_HANDLER` provider in app.module. After this, the function executes when an HTTP error occurs.
- 400 bad request errors is handled. When a 400 error occurs, backend error message will be displayed as shown below:
![custom-error-handler-toaster-message](images/custom-error-handler-toaster-message.jpg)
- 404 not found errors is handled. When a 404 error occurs, `Error404Component` will be appended to the `<body>` as shown below:
![custom-error-handler-404-component](images/custom-error-handler-404-component.jpg)
- Since `throwError(httpError)` is returned at bottom of the `handleHttpErrors`, the `ErrorHandler` will handle the HTTP errors except 400 and 404 errors.
**Note 1:** If you put `return` to next line of handling an error, default error handling will not work for that error.
```js
export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
if (httpError.status === 403) {
// handle 403 errors here
return; // put return to skip default error handling
}
}
```
**Note 2:** If you put `return throwError(httpError)`, default error handling will work.
- `throwError` is a function. It can be imported from `rxjs`.
- `httpError` is the second parameter of the error handler function which is registered to the `HTTP_ERROR_HANDLER` provider. Type of the `httpError` is `HttpErrorResponse`.
```js
import { throwError } from 'rxjs';
export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) {
if (httpError.status === 500) {
// handle 500 errors here
return;
}
// you can return the throwError(httpError) at bottom of the function to run the default handler of ABP for HTTP errors that you didn't handle above.
return throwError(httpError)
}
```

2
docs/en/UI/Angular/Router-Events.md

@ -1,6 +1,6 @@
# Router Events Simplified # Router Events Simplified
`RouterEvents` is a utility service to provide an easy implementation for one of the most frequent needs in Angular templates: `TrackByFunction`. Please see [this page in Angular docs](https://angular.io/guide/template-syntax#ngfor-with-trackby) for its purpose. `RouterEvents` is a utility service for filtering specific router events and reacting to them. Please see [this page in Angular docs](https://angular.io/api/router/Event) for available router events.

BIN
docs/en/UI/Angular/images/custom-error-handler-404-component.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
docs/en/UI/Angular/images/custom-error-handler-toaster-message.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

78
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/MicroserviceServiceRandomPortStep.cs

@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Linq;
using Volo.Abp.Cli.Commands;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
public class MicroserviceServiceRandomPortStep : ProjectBuildPipelineStep
{
private readonly string _defaultPort = string.Empty;
private string _tyeFileContent = null;
public MicroserviceServiceRandomPortStep(string defaultPort)
{
_defaultPort = defaultPort;
}
public override void Execute(ProjectBuildContext context)
{
var newPort = GetNewRandomPort(context);
var targetFiles = context.Files.Where(f=> f.Name.EndsWith("launchSettings.json") || f.Name.EndsWith("appsettings.json")).ToList();
foreach (var file in targetFiles)
{
file.SetContent(file.Content.Replace(_defaultPort, newPort));
}
}
private string GetNewRandomPort(ProjectBuildContext context)
{
string newPort;
var rnd = new Random();
var tryCount = 0;
do
{
newPort = rnd.Next(44350, 45350).ToString();
if (tryCount++ > 2000)
{
break;
}
} while (PortExistsForAnotherService(context, newPort));
return newPort;
}
private bool PortExistsForAnotherService(ProjectBuildContext context, string newPort)
{
return ReadTyeFileContent(context).SplitToLines().Any(l => l.Contains("port") && l.Contains(newPort));
}
private string ReadTyeFileContent(ProjectBuildContext context)
{
if (_tyeFileContent != null)
{
return _tyeFileContent;
}
var solutionFolderPath = context.BuildArgs.ExtraProperties[NewCommand.Options.OutputFolder.Short] ??
context.BuildArgs.ExtraProperties[NewCommand.Options.OutputFolder.Long] ??
Directory.GetCurrentDirectory();
var tyeFilePath = Path.Combine(solutionFolderPath, "tye.yaml");
if (!File.Exists(tyeFilePath))
{
return String.Empty;
}
_tyeFileContent = File.ReadAllText(tyeFilePath);
return _tyeFileContent;
}
}
}

54
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveProjectFromTyeStep.cs

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
public class RemoveProjectFromTyeStep : ProjectBuildPipelineStep
{
private readonly string _name;
public RemoveProjectFromTyeStep(string name)
{
_name = name;
}
public override void Execute(ProjectBuildContext context)
{
var tyeFile = context.Files.FirstOrDefault(f => f.Name == "/tye.yaml");
if (tyeFile == null)
{
return;
}
var lines = tyeFile.GetLines();
var newLines = new List<string>();
var nameLine = $"- name:";
var isOneOfTargetLines = false;
foreach (var line in lines)
{
if (line.Equals($"{nameLine} {_name}"))
{
isOneOfTargetLines = true;
continue;
}
if (line.StartsWith(nameLine))
{
isOneOfTargetLines = false;
}
if (!isOneOfTargetLines)
{
newLines.Add(line);
}
}
tyeFile.SetContent(String.Join(Environment.NewLine, newLines));
}
}
}

6
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceServiceTemplateBase.cs

@ -31,6 +31,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice
var steps = new List<ProjectBuildPipelineStep>(); var steps = new List<ProjectBuildPipelineStep>();
DeleteUnrelatedUiProject(context, steps); DeleteUnrelatedUiProject(context, steps);
SetRandomPortForHostProject(context, steps);
RandomizeStringEncryption(context, steps); RandomizeStringEncryption(context, steps);
return steps; return steps;
@ -54,6 +55,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice
} }
} }
private static void SetRandomPortForHostProject(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
steps.Add(new MicroserviceServiceRandomPortStep("44371"));
}
private static void RandomizeStringEncryption(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps) private static void RandomizeStringEncryption(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{ {
steps.Add(new RandomizeStringEncryptionStep()); steps.Add(new RandomizeStringEncryptionStep());

10
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/Microservice/MicroserviceTemplateBase.cs

@ -36,9 +36,13 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web",null, steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web",null,
"/applications/web/src/MyCompanyName.MyProjectName.Web")); "/applications/web/src/MyCompanyName.MyProjectName.Web"));
steps.Add(new RemoveFolderStep("/applications/web")); steps.Add(new RemoveFolderStep("/applications/web"));
steps.Add(new RemoveProjectFromTyeStep("web"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null,
"/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor"));
steps.Add(new RemoveFolderStep("/applications/blazor")); steps.Add(new RemoveFolderStep("/applications/blazor"));
steps.Add(new RemoveProjectFromTyeStep("blazor"));
steps.Add(new RemoveFolderStep("/angular")); steps.Add(new RemoveFolderStep("/angular"));
break; break;
@ -46,9 +50,12 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web",null, steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web",null,
"/applications/web/src/MyCompanyName.MyProjectName.Web")); "/applications/web/src/MyCompanyName.MyProjectName.Web"));
steps.Add(new RemoveFolderStep("/applications/web")); steps.Add(new RemoveFolderStep("/applications/web"));
steps.Add(new RemoveProjectFromTyeStep("web"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null,
"/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor"));
steps.Add(new RemoveFolderStep("/applications/blazor")); steps.Add(new RemoveFolderStep("/applications/blazor"));
steps.Add(new RemoveProjectFromTyeStep("blazor"));
break; break;
case UiFramework.Blazor: case UiFramework.Blazor:
@ -56,6 +63,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice
"/applications/web/src/MyCompanyName.MyProjectName.Web")); "/applications/web/src/MyCompanyName.MyProjectName.Web"));
steps.Add(new RemoveFolderStep("/applications/web")); steps.Add(new RemoveFolderStep("/applications/web"));
steps.Add(new RemoveFolderStep("/angular")); steps.Add(new RemoveFolderStep("/angular"));
steps.Add(new RemoveProjectFromTyeStep("web"));
break; break;
case UiFramework.Mvc: case UiFramework.Mvc:
@ -63,6 +71,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.Microservice
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null, steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor",null,
"/applications/blazor/src/MyCompanyName.MyProjectName.Blazor")); "/applications/blazor/src/MyCompanyName.MyProjectName.Blazor"));
steps.Add(new RemoveFolderStep("/applications/blazor")); steps.Add(new RemoveFolderStep("/applications/blazor"));
steps.Add(new RemoveProjectFromTyeStep("blazor"));
steps.Add(new RemoveFolderStep("/angular")); steps.Add(new RemoveFolderStep("/angular"));
break; break;
} }

13
framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionLoggingExtensions.cs

@ -0,0 +1,13 @@
using Microsoft.Extensions.Logging;
using Volo.Abp.Logging;
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionLoggingExtensions
{
public static ILogger<T> GetInitLogger<T>(this IServiceCollection services)
{
return services.GetSingletonInstance<IInitLoggerFactory>().Create<T>();
}
}
}

27
framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs

@ -3,8 +3,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Internal; using Volo.Abp.Internal;
using Volo.Abp.Logging;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp namespace Volo.Abp
@ -60,7 +62,7 @@ namespace Volo.Abp
{ {
//TODO: Shutdown if not done before? //TODO: Shutdown if not done before?
} }
protected virtual void SetServiceProvider(IServiceProvider serviceProvider) protected virtual void SetServiceProvider(IServiceProvider serviceProvider)
{ {
ServiceProvider = serviceProvider; ServiceProvider = serviceProvider;
@ -71,12 +73,31 @@ namespace Volo.Abp
{ {
using (var scope = ServiceProvider.CreateScope()) using (var scope = ServiceProvider.CreateScope())
{ {
WriteInitLogs(scope.ServiceProvider);
scope.ServiceProvider scope.ServiceProvider
.GetRequiredService<IModuleManager>() .GetRequiredService<IModuleManager>()
.InitializeModules(new ApplicationInitializationContext(scope.ServiceProvider)); .InitializeModules(new ApplicationInitializationContext(scope.ServiceProvider));
} }
} }
protected virtual void WriteInitLogs(IServiceProvider serviceProvider)
{
var logger = serviceProvider.GetService<ILogger<AbpApplicationBase>>();
if (logger == null)
{
return;
}
var initLogger = serviceProvider.GetRequiredService<IInitLoggerFactory>().Create<AbpApplicationBase>();
foreach (var entry in initLogger.Entries)
{
logger.Log(entry.LogLevel, entry.EventId, entry.State, entry.Exception, entry.Formatter);
}
initLogger.Entries.Clear();
}
protected virtual IReadOnlyList<IAbpModuleDescriptor> LoadModules(IServiceCollection services, AbpApplicationCreationOptions options) protected virtual IReadOnlyList<IAbpModuleDescriptor> LoadModules(IServiceCollection services, AbpApplicationCreationOptions options)
{ {
return services return services
@ -87,7 +108,7 @@ namespace Volo.Abp
options.PlugInSources options.PlugInSources
); );
} }
//TODO: We can extract a new class for this //TODO: We can extract a new class for this
protected virtual void ConfigureServices() protected virtual void ConfigureServices()
{ {
@ -158,4 +179,4 @@ namespace Volo.Abp
} }
} }
} }
} }

6
framework/src/Volo.Abp.Core/Volo/Abp/Internal/InternalServiceCollectionExtensions.cs

@ -1,6 +1,7 @@
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Logging;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Reflection; using Volo.Abp.Reflection;
@ -16,7 +17,7 @@ namespace Volo.Abp.Internal
} }
internal static void AddCoreAbpServices(this IServiceCollection services, internal static void AddCoreAbpServices(this IServiceCollection services,
IAbpApplication abpApplication, IAbpApplication abpApplication,
AbpApplicationCreationOptions applicationCreationOptions) AbpApplicationCreationOptions applicationCreationOptions)
{ {
var moduleLoader = new ModuleLoader(); var moduleLoader = new ModuleLoader();
@ -35,6 +36,7 @@ namespace Volo.Abp.Internal
services.TryAddSingleton<IModuleLoader>(moduleLoader); services.TryAddSingleton<IModuleLoader>(moduleLoader);
services.TryAddSingleton<IAssemblyFinder>(assemblyFinder); services.TryAddSingleton<IAssemblyFinder>(assemblyFinder);
services.TryAddSingleton<ITypeFinder>(typeFinder); services.TryAddSingleton<ITypeFinder>(typeFinder);
services.TryAddSingleton<IInitLoggerFactory>(new DefaultInitLoggerFactory());
services.AddAssemblyOf<IAbpApplication>(); services.AddAssemblyOf<IAbpApplication>();
@ -47,4 +49,4 @@ namespace Volo.Abp.Internal
}); });
} }
} }
} }

20
framework/src/Volo.Abp.Core/Volo/Abp/Logging/AbpInitLogEntry.cs

@ -0,0 +1,20 @@
using System;
using Microsoft.Extensions.Logging;
namespace Volo.Abp.Logging
{
public class AbpInitLogEntry
{
public LogLevel LogLevel { get; set; }
public EventId EventId { get; set; }
public object State { get; set; }
public Exception Exception { get; set; }
public Func<object, Exception, string> Formatter { get; set; }
public string Message => Formatter(State, Exception);
}
}

38
framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLogger.cs

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
namespace Volo.Abp.Logging
{
public class DefaultInitLogger<T> : IInitLogger<T>
{
public List<AbpInitLogEntry> Entries { get; }
public DefaultInitLogger()
{
Entries = new List<AbpInitLogEntry>();
}
public virtual void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
Entries.Add(new AbpInitLogEntry
{
LogLevel = logLevel,
EventId = eventId,
State = state,
Exception = exception,
Formatter = (s, e) => formatter((TState)s, e),
});
}
public virtual bool IsEnabled(LogLevel logLevel)
{
return logLevel != LogLevel.None;
}
public virtual IDisposable BeginScope<TState>(TState state)
{
return NullDisposable.Instance;
}
}
}

15
framework/src/Volo.Abp.Core/Volo/Abp/Logging/DefaultInitLoggerFactory.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Logging
{
public class DefaultInitLoggerFactory : IInitLoggerFactory
{
private readonly Dictionary<Type, object> _cache = new Dictionary<Type, object>();
public virtual IInitLogger<T> Create<T>()
{
return (IInitLogger<T>)_cache.GetOrAdd(typeof(T), () => new DefaultInitLogger<T>());;
}
}
}

10
framework/src/Volo.Abp.Core/Volo/Abp/Logging/IInitLogger.cs

@ -0,0 +1,10 @@
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
namespace Volo.Abp.Logging
{
public interface IInitLogger<out T> : ILogger<T>
{
public List<AbpInitLogEntry> Entries { get; }
}
}

7
framework/src/Volo.Abp.Core/Volo/Abp/Logging/IInitLoggerFactory.cs

@ -0,0 +1,7 @@
namespace Volo.Abp.Logging
{
public interface IInitLoggerFactory
{
IInitLogger<T> Create<T>();
}
}

15
framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleHelper.cs

@ -2,15 +2,17 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Microsoft.Extensions.Logging;
namespace Volo.Abp.Modularity namespace Volo.Abp.Modularity
{ {
internal static class AbpModuleHelper internal static class AbpModuleHelper
{ {
public static List<Type> FindAllModuleTypes(Type startupModuleType) public static List<Type> FindAllModuleTypes(Type startupModuleType, ILogger logger)
{ {
var moduleTypes = new List<Type>(); var moduleTypes = new List<Type>();
AddModuleAndDependenciesResursively(moduleTypes, startupModuleType); logger.Log(LogLevel.Information, "Loaded ABP modules:");
AddModuleAndDependenciesResursively(moduleTypes, startupModuleType, logger);
return moduleTypes; return moduleTypes;
} }
@ -35,7 +37,11 @@ namespace Volo.Abp.Modularity
return dependencies; return dependencies;
} }
private static void AddModuleAndDependenciesResursively(List<Type> moduleTypes, Type moduleType) private static void AddModuleAndDependenciesResursively(
List<Type> moduleTypes,
Type moduleType,
ILogger logger,
int depth = 0)
{ {
AbpModule.CheckAbpModuleType(moduleType); AbpModule.CheckAbpModuleType(moduleType);
@ -45,10 +51,11 @@ namespace Volo.Abp.Modularity
} }
moduleTypes.Add(moduleType); moduleTypes.Add(moduleType);
logger.Log(LogLevel.Information, $"{new string(' ', depth * 2)}- {moduleType.FullName}");
foreach (var dependedModuleType in FindDependedModuleTypes(moduleType)) foreach (var dependedModuleType in FindDependedModuleTypes(moduleType))
{ {
AddModuleAndDependenciesResursively(moduleTypes, dependedModuleType); AddModuleAndDependenciesResursively(moduleTypes, dependedModuleType, logger, depth + 1);
} }
} }
} }

10
framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleLoader.cs

@ -25,7 +25,7 @@ namespace Volo.Abp.Modularity
} }
private List<IAbpModuleDescriptor> GetDescriptors( private List<IAbpModuleDescriptor> GetDescriptors(
IServiceCollection services, IServiceCollection services,
Type startupModuleType, Type startupModuleType,
PlugInSourceList plugInSources) PlugInSourceList plugInSources)
{ {
@ -43,14 +43,16 @@ namespace Volo.Abp.Modularity
Type startupModuleType, Type startupModuleType,
PlugInSourceList plugInSources) PlugInSourceList plugInSources)
{ {
var logger = services.GetInitLogger<AbpApplicationBase>();
//All modules starting from the startup module //All modules starting from the startup module
foreach (var moduleType in AbpModuleHelper.FindAllModuleTypes(startupModuleType)) foreach (var moduleType in AbpModuleHelper.FindAllModuleTypes(startupModuleType, logger))
{ {
modules.Add(CreateModuleDescriptor(services, moduleType)); modules.Add(CreateModuleDescriptor(services, moduleType));
} }
//Plugin modules //Plugin modules
foreach (var moduleType in plugInSources.GetAllModules()) foreach (var moduleType in plugInSources.GetAllModules(logger))
{ {
if (modules.Any(m => m.Type == moduleType)) if (modules.Any(m => m.Type == moduleType))
{ {
@ -102,4 +104,4 @@ namespace Volo.Abp.Modularity
} }
} }
} }
} }

12
framework/src/Volo.Abp.Core/Volo/Abp/Modularity/ModuleManager.cs

@ -32,8 +32,6 @@ namespace Volo.Abp.Modularity
public void InitializeModules(ApplicationInitializationContext context) public void InitializeModules(ApplicationInitializationContext context)
{ {
LogListOfModules();
foreach (var contributor in _lifecycleContributors) foreach (var contributor in _lifecycleContributors)
{ {
foreach (var module in _moduleContainer.Modules) foreach (var module in _moduleContainer.Modules)
@ -52,16 +50,6 @@ namespace Volo.Abp.Modularity
_logger.LogInformation("Initialized all ABP modules."); _logger.LogInformation("Initialized all ABP modules.");
} }
private void LogListOfModules()
{
_logger.LogInformation("Loaded ABP modules:");
foreach (var module in _moduleContainer.Modules)
{
_logger.LogInformation("- " + module.Type.FullName);
}
}
public void ShutdownModules(ApplicationShutdownContext context) public void ShutdownModules(ApplicationShutdownContext context)
{ {
var modules = _moduleContainer.Modules.Reverse().ToList(); var modules = _moduleContainer.Modules.Reverse().ToList();

8
framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceExtensions.cs

@ -1,21 +1,23 @@
using System; using System;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Volo.Abp.Logging;
namespace Volo.Abp.Modularity.PlugIns namespace Volo.Abp.Modularity.PlugIns
{ {
public static class PlugInSourceExtensions public static class PlugInSourceExtensions
{ {
[NotNull] [NotNull]
public static Type[] GetModulesWithAllDependencies([NotNull] this IPlugInSource plugInSource) public static Type[] GetModulesWithAllDependencies([NotNull] this IPlugInSource plugInSource, ILogger logger)
{ {
Check.NotNull(plugInSource, nameof(plugInSource)); Check.NotNull(plugInSource, nameof(plugInSource));
return plugInSource return plugInSource
.GetModules() .GetModules()
.SelectMany(AbpModuleHelper.FindAllModuleTypes) .SelectMany(type => AbpModuleHelper.FindAllModuleTypes(type, logger))
.Distinct() .Distinct()
.ToArray(); .ToArray();
} }
} }
} }

7
framework/src/Volo.Abp.Core/Volo/Abp/Modularity/PlugIns/PlugInSourceList.cs

@ -2,18 +2,19 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
namespace Volo.Abp.Modularity.PlugIns namespace Volo.Abp.Modularity.PlugIns
{ {
public class PlugInSourceList : List<IPlugInSource> public class PlugInSourceList : List<IPlugInSource>
{ {
[NotNull] [NotNull]
internal Type[] GetAllModules() internal Type[] GetAllModules(ILogger logger)
{ {
return this return this
.SelectMany(pluginSource => pluginSource.GetModulesWithAllDependencies()) .SelectMany(pluginSource => pluginSource.GetModulesWithAllDependencies(logger))
.Distinct() .Distinct()
.ToArray(); .ToArray();
} }
} }
} }

10
framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs

@ -1,5 +1,6 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Shouldly; using Shouldly;
using Volo.Abp.Logging;
using Volo.Abp.Modularity.PlugIns; using Volo.Abp.Modularity.PlugIns;
using Xunit; using Xunit;
@ -11,7 +12,12 @@ namespace Volo.Abp.Modularity
public void Should_Load_Modules_By_Dependency_Order() public void Should_Load_Modules_By_Dependency_Order()
{ {
var moduleLoader = new ModuleLoader(); var moduleLoader = new ModuleLoader();
var modules = moduleLoader.LoadModules(new ServiceCollection(), typeof(MyStartupModule), new PlugInSourceList()); var modules = moduleLoader.LoadModules(
new ServiceCollection()
.AddSingleton<IInitLoggerFactory>(new DefaultInitLoggerFactory()),
typeof(MyStartupModule),
new PlugInSourceList()
);
modules.Length.ShouldBe(2); modules.Length.ShouldBe(2);
modules[0].Type.ShouldBe(typeof(IndependentEmptyModule)); modules[0].Type.ShouldBe(typeof(IndependentEmptyModule));
modules[1].Type.ShouldBe(typeof(MyStartupModule)); modules[1].Type.ShouldBe(typeof(MyStartupModule));
@ -22,7 +28,7 @@ namespace Volo.Abp.Modularity
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
} }
} }
} }

4
modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo.CmsKit.HttpApi.csproj

@ -9,9 +9,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Volo.CmsKit.Admin.Application\Volo.CmsKit.Admin.Application.csproj" /> <ProjectReference Include="..\Volo.CmsKit.Admin.HttpApi\Volo.CmsKit.Admin.HttpApi.csproj" />
<ProjectReference Include="..\Volo.CmsKit.Application.Contracts\Volo.CmsKit.Application.Contracts.csproj" /> <ProjectReference Include="..\Volo.CmsKit.Application.Contracts\Volo.CmsKit.Application.Contracts.csproj" />
<ProjectReference Include="..\Volo.CmsKit.Public.Application\Volo.CmsKit.Public.Application.csproj" /> <ProjectReference Include="..\Volo.CmsKit.Public.HttpApi\Volo.CmsKit.Public.HttpApi.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

4
modules/cms-kit/src/Volo.CmsKit.HttpApi/Volo/CmsKit/CmsKitHttpApiModule.cs

@ -5,8 +5,8 @@ using Volo.CmsKit.Public;
namespace Volo.CmsKit namespace Volo.CmsKit
{ {
[DependsOn( [DependsOn(
typeof(CmsKitAdminApplicationModule), typeof(CmsKitAdminHttpApiModule),
typeof(CmsKitPublicApplicationModule), typeof(CmsKitPublicHttpApiModule),
typeof(CmsKitApplicationContractsModule) typeof(CmsKitApplicationContractsModule)
)] )]
public class CmsKitHttpApiModule : AbpModule public class CmsKitHttpApiModule : AbpModule

229
npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts

@ -12,13 +12,14 @@ import {
} from '@angular/core'; } from '@angular/core';
import { NavigationError, ResolveEnd } from '@angular/router'; import { NavigationError, ResolveEnd } from '@angular/router';
import { Actions, ofActionSuccessful } from '@ngxs/store'; import { Actions, ofActionSuccessful } from '@ngxs/store';
import { Observable, Subject } from 'rxjs'; import { Observable, of, Subject, throwError } from 'rxjs';
import { filter, map } from 'rxjs/operators'; import { catchError, filter, map, switchMap } from 'rxjs/operators';
import snq from 'snq'; import snq from 'snq';
import { HttpErrorWrapperComponent } from '../components/http-error-wrapper/http-error-wrapper.component'; import { HttpErrorWrapperComponent } from '../components/http-error-wrapper/http-error-wrapper.component';
import { ErrorScreenErrorCodes, HttpErrorConfig } from '../models/common'; import { ErrorScreenErrorCodes, HttpErrorConfig } from '../models/common';
import { Confirmation } from '../models/confirmation'; import { Confirmation } from '../models/confirmation';
import { ConfirmationService } from '../services/confirmation.service'; import { ConfirmationService } from '../services/confirmation.service';
import { HTTP_ERROR_HANDLER } from '../tokens/http-error.token';
export const DEFAULT_ERROR_MESSAGES = { export const DEFAULT_ERROR_MESSAGES = {
defaultError: { defaultError: {
@ -70,28 +71,32 @@ export const DEFAULT_ERROR_LOCALIZATIONS = {
export class ErrorHandler { export class ErrorHandler {
componentRef: ComponentRef<HttpErrorWrapperComponent>; componentRef: ComponentRef<HttpErrorWrapperComponent>;
protected httpErrorHandler = this.injector.get(HTTP_ERROR_HANDLER, (_, err: HttpErrorResponse) =>
throwError(err),
);
constructor( constructor(
private actions: Actions, protected actions: Actions,
private routerEvents: RouterEvents, protected routerEvents: RouterEvents,
private confirmationService: ConfirmationService, protected confirmationService: ConfirmationService,
private cfRes: ComponentFactoryResolver, protected cfRes: ComponentFactoryResolver,
private rendererFactory: RendererFactory2, protected rendererFactory: RendererFactory2,
private injector: Injector, protected injector: Injector,
@Inject('HTTP_ERROR_CONFIG') private httpErrorConfig: HttpErrorConfig, @Inject('HTTP_ERROR_CONFIG') protected httpErrorConfig: HttpErrorConfig,
) { ) {
this.listenToRestError(); this.listenToRestError();
this.listenToRouterError(); this.listenToRouterError();
this.listenToRouterDataResolved(); this.listenToRouterDataResolved();
} }
private listenToRouterError() { protected listenToRouterError() {
this.routerEvents this.routerEvents
.getNavigationEvents('Error') .getNavigationEvents('Error')
.pipe(filter(this.filterRouteErrors)) .pipe(filter(this.filterRouteErrors))
.subscribe(() => this.show404Page()); .subscribe(() => this.show404Page());
} }
private listenToRouterDataResolved() { protected listenToRouterDataResolved() {
this.routerEvents this.routerEvents
.getEvents(ResolveEnd) .getEvents(ResolveEnd)
.pipe(filter(() => !!this.componentRef)) .pipe(filter(() => !!this.componentRef))
@ -101,113 +106,127 @@ export class ErrorHandler {
}); });
} }
private listenToRestError() { protected listenToRestError() {
this.actions this.actions
.pipe( .pipe(
ofActionSuccessful(RestOccurError), ofActionSuccessful(RestOccurError),
map(action => action.payload), map(action => action.payload),
filter(this.filterRestErrors), filter(this.filterRestErrors),
switchMap(this.executeErrorHandler),
) )
.subscribe(err => { .subscribe();
const body = snq(() => err.error.error, { }
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
});
if (err instanceof HttpErrorResponse && err.headers.get('_AbpErrorFormat')) { private executeErrorHandler = error => {
const confirmation$ = this.showError(null, null, body); const returnValue = this.httpErrorHandler(this.injector, error);
if (err.status === 401) { return (returnValue instanceof Observable ? returnValue : of(null)).pipe(
confirmation$.subscribe(() => { catchError(err => {
this.navigateToLogin(); this.handleError(err);
}); return of(null);
} }),
} else { );
switch (err.status) { };
case 401:
this.canCreateCustomError(401) private handleError(err: any) {
? this.show401Page() const body = snq(() => err.error.error, {
: this.showError( key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
{ defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.title, });
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.title,
}, if (err instanceof HttpErrorResponse && err.headers.get('_AbpErrorFormat')) {
{ const confirmation$ = this.showError(null, null, body);
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.details, if (err.status === 401) {
}, confirmation$.subscribe(() => {
).subscribe(() => this.navigateToLogin()); this.navigateToLogin();
break; });
case 403: }
this.createErrorComponent({ } else {
title: { switch (err.status) {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.title, case 401:
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.title, this.canCreateCustomError(401)
}, ? this.show401Page()
details: { : this.showError(
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.details, {
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.details, key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.title,
}, defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.title,
status: 403,
});
break;
case 404:
this.canCreateCustomError(404)
? this.show404Page()
: this.showError(
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.details,
},
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.title,
},
);
break;
case 500:
this.createErrorComponent({
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.title,
}, },
details: { {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.details, key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.details, defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.details,
}, },
status: 500, ).subscribe(() => this.navigateToLogin());
}); break;
break; case 403:
case 0: this.createErrorComponent({
if (err.statusText === 'Unknown Error') { title: {
this.createErrorComponent({ key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.title,
title: { defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.title,
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title, },
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, details: {
}, key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.details,
details: err.message, defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.details,
isHomeShow: false, },
}); status: 403,
} });
break; break;
default: case 404:
this.showError( this.canCreateCustomError(404)
? this.show404Page()
: this.showError(
{ {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.details, key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.details, defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.details,
}, },
{ {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title, key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.title,
}, },
); );
break; break;
case 500:
this.createErrorComponent({
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.title,
},
details: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.details,
},
status: 500,
});
break;
case 0:
if (err.statusText === 'Unknown Error') {
this.createErrorComponent({
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
},
details: err.message,
isHomeShow: false,
});
} }
} break;
}); default:
this.showError(
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.details,
},
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
},
);
break;
}
}
} }
private show401Page() { protected show401Page() {
this.createErrorComponent({ this.createErrorComponent({
title: { title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.title, key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.title,
@ -217,7 +236,7 @@ export class ErrorHandler {
}); });
} }
private show404Page() { protected show404Page() {
this.createErrorComponent({ this.createErrorComponent({
title: { title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title, key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title,
@ -227,7 +246,7 @@ export class ErrorHandler {
}); });
} }
private showError( protected showError(
message?: LocalizationParam, message?: LocalizationParam,
title?: LocalizationParam, title?: LocalizationParam,
body?: any, body?: any,
@ -256,7 +275,7 @@ export class ErrorHandler {
}); });
} }
private navigateToLogin() { protected navigateToLogin() {
this.injector.get(AuthService).initLogin(); this.injector.get(AuthService).initLogin();
} }
@ -304,13 +323,13 @@ export class ErrorHandler {
); );
} }
private filterRestErrors = ({ status }: HttpErrorResponse): boolean => { protected filterRestErrors = ({ status }: HttpErrorResponse): boolean => {
if (typeof status !== 'number') return false; if (typeof status !== 'number') return false;
return this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === status) < 0; return this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === status) < 0;
}; };
private filterRouteErrors = (navigationError: NavigationError): boolean => { protected filterRouteErrors = (navigationError: NavigationError): boolean => {
return ( return (
snq(() => navigationError.error.message.indexOf('Cannot match') > -1) && snq(() => navigationError.error.message.indexOf('Cannot match') > -1) &&
this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === 404) < 0 this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === 404) < 0

9
npm/ng-packs/packages/theme-shared/src/lib/models/common.ts

@ -1,5 +1,7 @@
import { Type } from '@angular/core'; import { HttpErrorResponse } from '@angular/common/http';
import { Injector, Type } from '@angular/core';
import { Validation } from '@ngx-validate/core'; import { Validation } from '@ngx-validate/core';
import { Observable } from 'rxjs';
export interface RootParams { export interface RootParams {
httpErrorConfig: HttpErrorConfig; httpErrorConfig: HttpErrorConfig;
@ -17,4 +19,9 @@ export interface HttpErrorConfig {
}; };
} }
export type HttpErrorHandler = (
injector: Injector,
httpError: HttpErrorResponse,
) => Observable<any>;
export type LocaleDirection = 'ltr' | 'rtl'; export type LocaleDirection = 'ltr' | 'rtl';

6
npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts

@ -1,5 +1,5 @@
import { InjectionToken } from '@angular/core'; import { InjectionToken } from '@angular/core';
import { HttpErrorConfig } from '../models/common'; import { HttpErrorConfig, HttpErrorHandler } from '../models/common';
export function httpErrorConfigFactory(config = {} as HttpErrorConfig) { export function httpErrorConfigFactory(config = {} as HttpErrorConfig) {
if (config.errorScreen && config.errorScreen.component && !config.errorScreen.forWhichErrors) { if (config.errorScreen && config.errorScreen.component && !config.errorScreen.forWhichErrors) {
@ -13,4 +13,6 @@ export function httpErrorConfigFactory(config = {} as HttpErrorConfig) {
} as HttpErrorConfig; } as HttpErrorConfig;
} }
export const HTTP_ERROR_CONFIG = new InjectionToken('HTTP_ERROR_CONFIG'); export const HTTP_ERROR_CONFIG = new InjectionToken<HttpErrorConfig>('HTTP_ERROR_CONFIG');
export const HTTP_ERROR_HANDLER = new InjectionToken<HttpErrorHandler>('HTTP_ERROR_HANDLER');

Loading…
Cancel
Save