Ah, right, I would need to have this file located at aspnet-zero-core\aspnet-core\src\MyCompanyName.AbpZeroTemplate.Web.Host\wwwroot\Common\Images
!
But it is not there, not even in the github project. But there are the .svg
files - so, it seems there is the wrong file linked somewhere?
Hi @ismcagdas
No, I don't use the public website and it is not running anywhere. Still, the log message appears very often.
Hi @m.aliozkaya
It doesn't require authentication on my project (tried using browser's private mode, also tried on phone where I never ever logged in to swagger ui for sure)... I need to figure out why. Any ideas?
UPDATE
~~It does require authentication in development environment - but it does NOT require authentication in production environment...~~
What I mean is that I can open https://mydomain/swagger/index.html without any authentication / authorization. I want Swagger UI to be available only when authorized.
This seems to do what i want to achieve: Swagger UI with login form and role-based api visibility
UPDATE [A minimalist ASPNETZERO Angular client #11164](https://support.aspnetzero.com/QA/Questions/11164/A-minimalist-ASPNETZERO-Angular-client)
That's it for now ; )
This documentation shows how to make use of ASPNETZERO's SignalR capabilities (public/non-authorized endpoint only).
Add package:
npm install --save --legacy-peer-deps @microsoft/signalr
Add assets and scripts to ./angular.json
:
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "abp.signalr-client.js",
"input": "node_modules/abp-web-resources/Abp/Framework/scripts/libs",
"output": "/assets/abp"
}
],
"scripts": [
"src/assets/abp-web-resources/abp.js",
"node_modules/@microsoft/signalr/dist/browser/signalr.min.js"
]
Adapt ./src/typings.d.ts
as follows:
///<reference path="../node_modules/abp-web-resources/Abp/Framework/scripts/abp.d.ts"/>
///<reference path="../node_modules/abp-web-resources/Abp/Framework/scripts/libs/abp.signalr.d.ts"/>
Copy ./src/shared/helpers/signalr-helper.ts
from original ASPNETZERO Angular client (original name is SignalRHelper.ts
).
Adapt the file as follows:
import { AppConsts } from '@shared/app-consts';
export class SignalRHelper {
static initSignalR(callback: () => void): void {
abp.signalr = {
autoConnect: false,
connect: undefined,
hubs: undefined,
qs: undefined,
remoteServiceBaseUrl: AppConsts.remoteServiceBaseUrl,
startConnection: undefined,
url: '/signalr-public',
};
let script = document.createElement('script');
script.src = `${AppConsts.appBaseUrl}/assets/abp/abp.signalr-client.js`;
script.onload = () => {
callback();
};
document.head.appendChild(script);
}
}
That's it! Now we can make use of ASPNETZERO's SignalR capabilities in our minimalist ASPNETZERO Angular client!
This documentation shows how to make use of ASPNETZERO's localization capabilities.
Add packages:
npm install --save --legacy-peer-deps lodash-es
npm install --save-dev --legacy-peer-deps @types/lodash-es
Edit ./tsconfig.json
to contain the following compilerOptions
:
"strict": false,
"paths": {
"@shared/*": ["./src/shared/*"]
}
Copy ./src/shared/services/locale-mappings.services.ts
from original ASPNETZERO Angular client (original location is ./src/shared/
).
Copy ./src/shared/pipes/localize.pipe.ts
from original ASPNETZERO Angular client (original location is ./src/shared/common/pipes/
).
Add ./src/shared/pipes/pipes.module.ts
with the following content:
import { NgModule } from '@angular/core';
import { LocalizePipe } from "./localize.pipe";
@NgModule({
declarations: [
LocalizePipe,
],
exports: [
LocalizePipe,
]
})
export class PipesModule {}
Add the following functions to ./src/app/app.module.ts
:
export function convertAbpLocaleToAngularLocale(locale: string): string {
return new LocaleMappingService().map('angular', locale);
}
export function getCurrentLanguage(): string {
return convertAbpLocaleToAngularLocale(abp.localization.currentLanguage.name);
}
function registerLocales(
resolve: (value?: boolean | Promise<boolean>) => void,
reject: any,
spinnerService: NgxSpinnerService
) {
if (abp.localization.currentLanguage.name && abp.localization.currentLanguage.name !== 'en-US') {
let angularLocale = convertAbpLocaleToAngularLocale(abp.localization.currentLanguage.name);
import(`/node_modules/@angular/common/locales/${angularLocale}.mjs`).then((module) => {
registerLocaleData(module.default);
spinnerService.hide();
resolve(true);
}, reject);
}
else {
spinnerService.hide();
resolve(true);
}
}
Adapt appInitializerFactory()
in ./src/app/app.module.ts
as follows:
export function appInitializerFactory(injector: Injector, platformLocation: PlatformLocation) {
return () => {
const spinnerService = injector.get(NgxSpinnerService);
spinnerService.show();
return new Promise<boolean>((resolve, reject) => {
AppConsts.appBaseHref = getBaseHref(platformLocation);
let appBaseUrl = `${getDocumentOrigin()}${AppConsts.appBaseHref}`;
AppPreBootstrap.run(
appBaseUrl,
() => {
registerLocales(resolve, reject, spinnerService);
resolve(true);
},
resolve,
reject
);
});
};
}
Adapt @NgModule
decorator in ./src/app/app.module.ts
as follows:
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
ServiceProxyModule,
HttpClientModule,
NgxSpinnerModule,
PipesModule,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
{ provide: API_BASE_URL, useFactory: getRemoteServiceBaseUrl },
{
provide: APP_INITIALIZER,
useFactory: appInitializerFactory,
deps: [Injector, PlatformLocation],
multi: true
},
{
provide: LOCALE_ID,
useFactory: getCurrentLanguage
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
Adapt ./src/app-pre-bootstrap.ts
as follows:
import { environment } from './environments/environment';
import { AppConsts } from './shared/app-consts';
import { XmlHttpRequestHelper } from './shared/helpers/xml-http-request-helper';
import { merge as _merge } from 'lodash-es';
import { LocaleMappingService } from '@shared/services/locale-mapping.service';
import { DateTime, Settings } from 'luxon';
export class AppPreBootstrap {
static run(appRootUrl: string, callback: () => void, resolve: any, reject: any): void {
AppPreBootstrap.getApplicationConfig(appRootUrl, () => {
AppPreBootstrap.getUserConfiguration(callback);
});
}
private static getApplicationConfig(appRootUrl: string, callback: () => void) {
let type = 'GET';
let url = appRootUrl + 'assets/' + environment.appConfig;
let customHeaders = [{
name: 'Abp.TenantId',
value: abp.multiTenancy.getTenantIdCookie() + ''
}];
XmlHttpRequestHelper.ajax(type, url, customHeaders, null, (result: any) => {
AppConsts.localeMappings = result.localeMappings;
AppConsts.appBaseUrlFormat = result.appBaseUrl;
AppConsts.remoteServiceBaseUrlFormat = result.remoteServiceBaseUrl;
AppConsts.appBaseUrl = result.appBaseUrl.replace(AppConsts.tenancyNamePlaceHolderInUrl + '.', '');
AppConsts.remoteServiceBaseUrl = result.remoteServiceBaseUrl.replace(AppConsts.tenancyNamePlaceHolderInUrl + '.', '');
callback();
});
}
private static getCurrentClockProvider(currentProviderName: string): abp.timing.IClockProvider {
if (currentProviderName === 'unspecifiedClockProvider') {
return abp.timing.unspecifiedClockProvider;
}
if (currentProviderName === 'utcClockProvider') {
return abp.timing.utcClockProvider;
}
return abp.timing.localClockProvider;
}
private static getRequestHeadersWithDefaultValues() {
const cookieLangValue = abp.utils.getCookieValue('Abp.Localization.CultureName');
let requestHeaders = {
'.AspNetCore.Culture': 'c=' + cookieLangValue + '|uic=' + cookieLangValue,
[abp.multiTenancy.tenantIdCookieName]: abp.multiTenancy.getTenantIdCookie(),
};
if (!cookieLangValue) {
delete requestHeaders['.AspNetCore.Culture'];
}
return requestHeaders;
}
private static getUserConfiguration(callback: () => void): any {
const token = abp.auth.getToken();
let requestHeaders = AppPreBootstrap.getRequestHeadersWithDefaultValues();
if (token) {
requestHeaders['Authorization'] = 'Bearer ' + token;
}
return XmlHttpRequestHelper.ajax(
'GET',
AppConsts.remoteServiceBaseUrl + '/AbpUserConfiguration/GetAll',
requestHeaders,
null,
(response) => {
let result = response.result;
_merge(abp, result);
abp.clock.provider = this.getCurrentClockProvider(result.clock.provider);
AppPreBootstrap.configureLuxon();
abp.event.trigger('abp.dynamicScriptsInitialized');
AppConsts.recaptchaSiteKey = abp.setting.get('Recaptcha.SiteKey');
AppConsts.subscriptionExpireNootifyDayCount = parseInt(
abp.setting.get('App.TenantManagement.SubscriptionExpireNotifyDayCount')
);
callback();
}
);
}
private static configureLuxon() {
let luxonLocale = new LocaleMappingService().map('luxon', abp.localization.currentLanguage.name);
DateTime.local().setLocale(luxonLocale);
DateTime.utc().setLocale(luxonLocale);
Settings.defaultLocale = luxonLocale;
if (abp.clock.provider.supportsMultipleTimezone) {
Settings.defaultZone = abp.timing.timeZoneInfo.iana.timeZoneId;
}
Date.prototype.toISOString = function () {
return DateTime.fromJSDate(this)
.setLocale('en')
.setZone(abp.timing.timeZoneInfo.iana.timeZoneId)
.toString();
};
Date.prototype.toString = function () {
return DateTime.fromJSDate(this)
.setLocale('en')
.setZone(abp.timing.timeZoneInfo.iana.timeZoneId)
.toString();
};
DateTime.prototype.toString = function () {
let date = this.setLocale('en').setZone(abp.timing.timeZoneInfo.iana.timeZoneId) as DateTime;
return date.toISO();
};
}
}
That's it! Now we can make use of ASPNETZERO's localization capabilities in our minimalist ASPNETZERO Angular client!
This documentation shows how to make use of package ngx-spinner.
Add package:
npm install --save --legacy-peer-deps ngx-spinner
Adapt @NgModule
decorator in ./src/app/app.module.ts
as follows:
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
ServiceProxyModule,
HttpClientModule,
NgxSpinnerModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
{ provide: API_BASE_URL, useFactory: getRemoteServiceBaseUrl },
{
provide: APP_INITIALIZER,
useFactory: appInitializerFactory,
deps: [Injector, PlatformLocation],
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
Adapt appInitializerFactory()
in ./src/app/app.module.ts
as follows:
export function appInitializerFactory(injector: Injector, platformLocation: PlatformLocation) {
return () => {
const spinnerService = injector.get(NgxSpinnerService);
spinnerService.show();
return new Promise<boolean>((resolve, reject) => {
AppConsts.appBaseHref = getBaseHref(platformLocation);
let appBaseUrl = `${getDocumentOrigin()}${AppConsts.appBaseHref}`;
AppPreBootstrap.run(
appBaseUrl,
() => {
spinnerService.hide();
resolve(true);
},
resolve,
reject
);
});
};
}
Add stylings to ./angular.json
:
Note: Which css file to import depends on the type of animation you want to use.
"styles": [
"node_modules/ngx-spinner/animations/ball-clip-rotate.css"
],
That's it! Now we can make use of NgxSpinner in our minimalist ASPNETZERO Angular client!
This project was generated with Angular CLI version 14.0.4.
This project is a minimalist ASPNETZERO Angular client. It implements the very minimal requirements to make use of the ASPNETZERO Core Services (ASPNETZERO 11.2.1).
This documentation shows how to create a minimalist ASPNETZERO Angular client that can consume ASPNETZERO Core Services (public/non-authorized API only).
Add package:
npm install --save-dev nswag
Copy ./nswag/*
from original ASPNETZERO Angular client.
In ./nswag/service.config.nswag
update typeScriptVersion
and rxJsVersion
according to ./project.json
.
Go to ./nswag
and run ./resfresh.bat
(ASPNETZERO Core Services must be up and running).
This creates ./src/shared/service-proxies/service-proxies.ts
.
Copy ./src/shared/service-proxies/service-proxy.module.ts
from original ASPNETZERO Angular client.
Remove everything irrelevant:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { AbpHttpInterceptor } from 'abp-ng2-module';
import * as ApiServiceProxies from './service-proxies';
@NgModule({
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AbpHttpInterceptor, multi: true },
ApiServiceProxies.MyServiceProxy,
],
})
export class ServiceProxyModule {}
As we can see ServiceProxyModule
requires package abp-ng2-module
.
Add packages:
npm install --save luxon
npm install --save-dev @types/luxon
npm install --save --legacy-peer-deps abp-web-resources
npm install --save --legacy-peer-deps abp-ng2-module
Adding @types
to ./tsconfig.*.json
:
see: angular.io / guide / typescript-configuration / installable-typings-files
In ./tsconfig.app.json
add "luxon"
to compilerOptions.types
:
"compilerOptions": {
// ...,
"types": [
"luxon"
]
}
In ./tsconfig.spec.json
add "luxon"
to compilerOptions.types
:
"compilerOptions": {
// ...,
"types": [
// ...,
"luxon"
]
}
Adding "skipLibCheck": true
to ./tsconfig.compilerOptions
:
This is necessary to prevent build errors caused by abp-ng2-module
not being able to find references to abp-web-resources
.
{
"compilerOptions": {
// ...,
"skipLibCheck": true
}
}
Add ./src/typings.d.ts
with the following content:
see: typescriptlang.org / docs / handbook / declaration-files / publishing / red-flags
///<reference path="../node_modules/abp-web-resources/Abp/Framework/scripts/abp.d.ts"/>
Adding abp-web-resources
to ./src/assets/
:
Copy ./src/assets/abp-web-resources/abp.js
from original ASPNETZERO Angular client.
Adding "src/assets/abp-web-resources/abp.js"
to ./angular.json
to build.options
and test.options
:
"scripts": [
"src/assets/abp-web-resources/abp.js"
]
Copy the following files from original ASPNETZERO Angular client:
./src/app-pre-bootstrap.ts
./src/assets/appconfig.json
./src/assets/appconfig.production.json
./src/shared/app-consts.ts
(original name: AppConsts.ts
)./src/shared/helpers/xml-http-request-helper.ts
(original name: XmlHttpRequestHelper.ts
)The content of ./src/app-pre-bootstrap.ts
is the following:
import { environment } from './environments/environment';
import { AppConsts } from './shared/app-consts';
import { XmlHttpRequestHelper } from './shared/helpers/xml-http-request-helper';
export class AppPreBootstrap {
static run(appRootUrl: string, callback: () => void, resolve: any, reject: any): void {
AppPreBootstrap.getApplicationConfig(appRootUrl, () => {
callback();
});
}
private static getApplicationConfig(appRootUrl: string, callback: () => void) {
let type = 'GET';
let url = appRootUrl + 'assets/' + environment.appConfig;
let customHeaders = [{
name: 'Abp.TenantId',
value: abp.multiTenancy.getTenantIdCookie() + ''
}];
XmlHttpRequestHelper.ajax(type, url, customHeaders, null, (result: any) => {
AppConsts.localeMappings = result.localeMappings;
AppConsts.appBaseUrlFormat = result.appBaseUrl;
AppConsts.remoteServiceBaseUrlFormat = result.remoteServiceBaseUrl;
AppConsts.appBaseUrl = result.appBaseUrl.replace(AppConsts.tenancyNamePlaceHolderInUrl + '.', '');
AppConsts.remoteServiceBaseUrl = result.remoteServiceBaseUrl.replace(AppConsts.tenancyNamePlaceHolderInUrl + '.', '');
callback();
});
}
}
Modify the following files:
./src/environments/environment.prod.ts
export const environment = {
production: true,
appConfig: 'appconfig.production.json'
};
./src/environments/environment.ts
export const environment = {
production: false,
appConfig: 'appconfig.json'
};
Modify ./src/app/app.module.ts
:
import { PlatformLocation } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppPreBootstrap } from 'src/app-pre-bootstrap';
import { AppConsts } from 'src/shared/app-consts';
import { API_BASE_URL } from 'src/shared/service-proxies/service-proxies';
import { ServiceProxyModule } from 'src/shared/service-proxies/service-proxy.module';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
export function appInitializerFactory(platformLocation: PlatformLocation) {
return () => {
return new Promise<boolean>((resolve, reject) => {
AppConsts.appBaseHref = getBaseHref(platformLocation);
let appBaseUrl = `${getDocumentOrigin()}${AppConsts.appBaseHref}`;
AppPreBootstrap.run(
appBaseUrl,
() => { resolve(true); },
resolve,
reject
);
});
};
}
function getDocumentOrigin() {
const docloc = document.location;
return docloc.origin ?? `${docloc.protocol}//${docloc.hostname}${docloc.port ? ':' + docloc.port : ''}`
}
export function getRemoteServiceBaseUrl(): string {
return AppConsts.remoteServiceBaseUrl;
}
export function getBaseHref(platformLocation: PlatformLocation) {
return platformLocation.getBaseHrefFromDOM() ?? '/';
}
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
ServiceProxyModule,
HttpClientModule,
],
providers: [
{ provide: API_BASE_URL, useFactory: getRemoteServiceBaseUrl },
{
provide: APP_INITIALIZER,
useFactory: appInitializerFactory,
deps: [PlatformLocation],
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
Alright, for whatever reason I thought I could use Metronic's ressources... My bad.
Still, the result is not working very well:
Anyway, I'm not going to try and get it right with noUiSlider. PrimeNG's Slider component works as expected and is all I need, so I switched to that one.
Thank you for your help!