@ -20,19 +20,20 @@ First things first! Let's setup your development environment before creating the
The following tools should be installed on your development machine:
The following tools should be installed on your development machine:
* [Visual Studio 2019 (v16.4+)](https://visualstudio.microsoft.com/vs/) for Windows / [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).*
* [Visual Studio 2019 (v16.4+)](https://visualstudio.microsoft.com/vs/) for Windows / [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).<supid="a-editor">[1](#f-editor)</sup>
* [Yarn v1.20+ (not v2)](https://classic.yarnpkg.com/en/docs/install)<supid="a-yarn">[2](#f-yarn)</sup> or npm v6+ (installed with Node)
{{ if Tiered == "Yes" }}
{{ if Tiered == "Yes" }}
* [Redis](https://redis.io/) (the startup solution uses the Redis as the [distributed cache](Caching.md)).
* [Redis](https://redis.io/) (the startup solution uses the Redis as the [distributed cache](Caching.md)).
{{ end }}
{{ end }}
<supid="f-editor"><b>1</b></sup>_You can use another editor instead of Visual Studio as long as it supports .NET Core and ASP.NET Core._<sup>[↩](#a-editor)</sup>
> *You can use another editor instead of Visual Studio as long as it supports .NET Core and ASP.NET Core.
<supid="f-yarn"><b>2</b></sup>_Yarn v2 works differently and is not supported._<sup>[↩](#a-yarn)</sup>
### Install the ABP CLI
### Install the ABP CLI
@ -348,4 +349,4 @@ See the "[Getting Started with the React Native](Getting-Started-React-Native.md
## Next
## Next
* [Web Application Development Tutorial](Tutorials/Part-1.md)
* [Web Application Development Tutorial](Tutorials/Part-1.md)
@ -115,7 +115,7 @@ public class MessagingHub : Hub
}
}
````
````
The hub route will be `/signalr-hubs/messasing` for the `MessasingHub`:
The hub route will be `/signalr-hubs/messaging` for the `MessagingHub`:
* Adding a standard `/signalr-hubs/` prefix
* Adding a standard `/signalr-hubs/` prefix
* Continue with the **camel case** hub name, without the `Hub` suffix.
* Continue with the **camel case** hub name, without the `Hub` suffix.
@ -123,7 +123,7 @@ The hub route will be `/signalr-hubs/messasing` for the `MessasingHub`:
If you want to specify the route, you can use the `HubRoute` attribute:
If you want to specify the route, you can use the `HubRoute` attribute:
````csharp
````csharp
[HubRoute("/my-messasing-hub")]
[HubRoute("/my-messaging-hub")]
public class MessagingHub : Hub
public class MessagingHub : Hub
{
{
//...
//...
@ -132,7 +132,7 @@ public class MessagingHub : Hub
### AbpHub Base Classes
### AbpHub Base Classes
Instead of the standard `Hub` and `Hub<T>` classes, you can inherit from the `AbpHub` or `AbpHub<T>` which hve useful base properties like `CurrentUser`.
Instead of the standard `Hub` and `Hub<T>` classes, you can inherit from the `AbpHub` or `AbpHub<T>` which have useful base properties like `CurrentUser`.
import { AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent action
import { eIdentityComponents } from '@abp/ng.identity'; // imported eIdentityComponents enum
import { eIdentityComponents } from '@abp/ng.identity'; // imported eIdentityComponents enum
import { Store } from '@ngxs/store'; // imported Store
import { Store } from '@ngxs/store'; // imported Store
//...
//...
@Component(/* component metadata */)
@Component(/* component metadata */)
export class AppComponent implements OnInit {
export class AppComponent {
constructor(..., private store: Store) {} // injected Store
constructor(
private store: Store // injected Store
ngOnInit() {
)
// added dispatch
{
// dispatched the AddReplaceableComponent action
this.store.dispatch(
this.store.dispatch(
new AddReplaceableComponent({
new AddReplaceableComponent({
component: YourNewRoleComponent,
component: YourNewRoleComponent,
key: eIdentityComponents.Roles,
key: eIdentityComponents.Roles,
}),
}),
);
);
//...
}
}
}
}
```
```
@ -48,9 +47,7 @@ The example below describes how to replace the `ApplicationLayoutComponent`:
Run the following command to generate a layout in `angular` folder:
Run the following command to generate a layout in `angular` folder:
```bash
```bash
yarn ng generate component shared/my-application-layout --export --entryComponent
yarn ng generate component my-application-layout
# You don't need the --entryComponent option in Angular 9
```
```
Add the following code in your layout template (`my-layout.component.html`) where you want the page to be loaded.
Add the following code in your layout template (`my-layout.component.html`) where you want the page to be loaded.
@ -62,30 +59,29 @@ Add the following code in your layout template (`my-layout.component.html`) wher
Open `app.component.ts` in `src/app` folder and modify it as shown below:
Open `app.component.ts` in `src/app` folder and modify it as shown below:
```js
```js
import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent
import { AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent
import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents enum for component keys
import { eThemeBasicComponents } from '@abp/ng.theme.basic'; // imported eThemeBasicComponents enum for component keys
import { MyApplicationLayoutComponent } from './shared/my-application-layout/my-application-layout.component'; // imported MyApplicationLayoutComponent
import { Store } from '@ngxs/store'; // imported Store
import { Store } from '@ngxs/store'; // imported Store
//...
import { MyApplicationLayoutComponent } from './my-application-layout/my-application-layout.component'; // imported MyApplicationLayoutComponent
@Component(/* component metadata */)
@Component(/* component metadata */)
export class AppComponent implements OnInit {
export class AppComponent {
constructor(..., private store: Store) {} // injected Store
constructor(
private store: Store, // injected Store
ngOnInit() {
) {
// added dispatch
// dispatched the AddReplaceableComponent action
this.store.dispatch(
this.store.dispatch(
new AddReplaceableComponent({
new AddReplaceableComponent({
component: MyApplicationLayoutComponent,
component: MyApplicationLayoutComponent,
key: eThemeBasicComponents.ApplicationLayout,
key: eThemeBasicComponents.ApplicationLayout,
}),
}),
);
);
//...
}
}
}
}
```
```
> If you like to replace a layout component at runtime (e.g: changing the layout by pressing a button), pass the second parameter of the AddReplaceableComponent action as true. DynamicLayoutComponent loads content using a router-outlet. When the second parameter of AddReplaceableComponent is true, the route will be refreshed, so use it with caution. Your component state will be gone and any initiation logic (including HTTP requests) will be repeated.
@ -18,7 +18,7 @@ This will make the following modifications:
- Update your package.json and install new packages
- Update your package.json and install new packages
- Revise tsconfig.json files to create a "Solution Style" configuration
- Revise tsconfig.json files to create a "Solution Style" configuration
- Rename `browserlist` as `.browserlistrc`
- Rename `browserslist` as `.browserslistrc`
On the other hand, it would be better if you check which packages to update first with `yarn ng update` command alone. Angular will give you a list of packages to update.
On the other hand, it would be better if you check which packages to update first with `yarn ng update` command alone. Angular will give you a list of packages to update.
"MaxResultCountExceededExceptionMessage":"{0} kann nicht mehr als {1} sein! Erhöhen Sie {2}.{3} auf der Serverseite, um mehr Ergebnisse zu ermöglichen."
"MaxResultCountExceededExceptionMessage":"{0} kann nicht mehr als {1} sein! Erhöhen Sie {2}.{3} auf der Serverseite, um mehr Ergebnisse zu ermöglichen."
"'{0}' and '{1}' do not match.":"'{0}' und '{1}' stimmen nicht überein.",
"'{0}' and '{1}' do not match.":"'{0}' und '{1}' stimmen nicht überein.",
"The {0} field is not a valid credit card number.":"Das Feld {0} ist keine gültige Kreditkartennummer.",
"The {0} field is not a valid credit card number.":"Das Feld {0} ist keine gültige Kreditkartennummer.",
"{0} is not valid.":"{0} ist nicht gültig.",
"{0} is not valid.":"{0} ist nicht gültig.",
"The {0} field is not a valid e-mail address.":"Das Feld {0} ist keine gültige E-Mail-Adresse.",
"The {0} field is not a valid e-mail address.":"Das Feld {0} ist keine gültige E-Mail-Adresse.",
"The {0} field only accepts files with the following extensions: {1}":"Das Feld {0} akzeptiert nur Dateien mit den folgenden Erweiterungen: {1}",
"The {0} field only accepts files with the following extensions: {1}":"Das Feld {0} akzeptiert nur Dateien mit den folgenden Erweiterungen: {1}",
"The field {0} must be a string or array type with a maximum length of '{1}'.":"Das Feld {0} muss eine Zeichenfolge oder Auflistung mit einer maximalen Länge von '{1}' sein.",
"The field {0} must be a string or array type with a maximum length of '{1}'.":"Das Feld {0} muss eine Zeichenfolge oder Auflistung mit einer maximalen Länge von '{1}' sein.",
"The field {0} must be a string or array type with a minimum length of '{1}'.":"Das Feld {0} muss eine Zeichenfolge oder Auflistung mit einer Mindestlänge von '{1}' sein.",
"The field {0} must be a string or array type with a minimum length of '{1}'.":"Das Feld {0} muss eine Zeichenfolge oder Auflistung mit einer Mindestlänge von '{1}' sein.",
"The {0} field is not a valid phone number.":"Das Feld {0} ist keine gültige Telefonnummer.",
"The {0} field is not a valid phone number.":"Das Feld {0} ist keine gültige Telefonnummer.",
"The field {0} must be between {1} and {2}.":"Das Feld {0} muss zwischen {1} und {2} liegen.",
"The field {0} must be between {1} and {2}.":"Das Feld {0} muss zwischen {1} und {2} liegen.",
"The field {0} must match the regular expression '{1}'.":"Das Feld {0} muss dem regulären Ausdruck '{1}' entsprechen.",
"The field {0} must match the regular expression '{1}'.":"Das Feld {0} muss dem regulären Ausdruck '{1}' entsprechen.",
"The {0} field is required.":"Das Feld {0} ist erforderlich.",
"The {0} field is required.":"Das Feld {0} ist erforderlich.",
"The field {0} must be a string with a maximum length of {1}.":"Das Feld {0} muss eine Zeichenfolge mit einer maximalen Länge von {1} sein.",
"The field {0} must be a string with a maximum length of {1}.":"Das Feld {0} muss eine Zeichenfolge mit einer maximalen Länge von {1} sein.",
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.":"Das Feld {0} muss eine Zeichenfolge mit einer minimalen Länge von {2} und einer maximalen Länge von {1} sein.",
"The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.":"Das Feld {0} muss eine Zeichenfolge mit einer minimalen Länge von {2} und einer maximalen Länge von {1} sein.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.":"Das {0}-Feld ist keine gültige vollqualifizierte http-, https- oder ftp-URL.",
"The {0} field is not a valid fully-qualified http, https, or ftp URL.":"Das {0}-Feld ist keine gültige vollqualifizierte http-, https- oder ftp-URL.",
"The field {0} is invalid.":"Das Feld {0} ist ungültig.",
"The field {0} is invalid.":"Das Feld {0} ist ungültig.",
"ThisFieldIsNotAValidCreditCardNumber.":"Dieses Feld ist keine gültige Kreditkartennummer.",
"ThisFieldIsNotAValidCreditCardNumber.":"Dieses Feld ist keine gültige Kreditkartennummer.",
"ThisFieldIsNotValid.":"Dieses Feld ist nicht gültig.",
"ThisFieldIsNotValid.":"Dieses Feld ist nicht gültig.",
"ThisFieldIsNotAValidEmailAddress.":"Dieses Feld ist keine gültige E-Mail-Adresse.",
"ThisFieldIsNotAValidEmailAddress.":"Dieses Feld ist keine gültige E-Mail-Adresse.",
"ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}":"Dieses Feld akzeptiert nur Dateien mit den folgenden Erweiterungen: {0}",
"ThisFieldOnlyAcceptsFilesWithTheFollowingExtensions:{0}":"Dieses Feld akzeptiert nur Dateien mit den folgenden Erweiterungen: {0}",
"ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}":"Dieses Feld muss eine Zeichenfolge oder Auflistung mit einer maximalen Länge von '{0}' sein.",
"ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthOf{0}":"Dieses Feld muss eine Zeichenfolge oder Auflistung mit einer maximalen Länge von '{0}' sein.",
"ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}":"Dieses Feld muss eine Zeichenfolge oder Auflistung mit einer Mindestlänge von '{0}' sein.",
"ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}":"Dieses Feld muss eine Zeichenfolge oder Auflistung mit einer Mindestlänge von '{0}' sein.",
"ThisFieldIsNotAValidPhoneNumber.":"Dieses Feld ist keine gültige Telefonnummer.",
"ThisFieldIsNotAValidPhoneNumber.":"Dieses Feld ist keine gültige Telefonnummer.",
"ThisFieldMustBeBetween{0}And{1}":"Dieses Feld muss zwischen {0} und {1} liegen.",
"ThisFieldMustBeBetween{0}And{1}":"Dieses Feld muss zwischen {0} und {1} liegen.",
"ThisFieldMustMatchTheRegularExpression{0}":"Dieses Feld muss dem regulären Ausdruck '{0}' entsprechen.",
"ThisFieldMustMatchTheRegularExpression{0}":"Dieses Feld muss dem regulären Ausdruck '{0}' entsprechen.",
"ThisFieldIsRequired.":"Dieses Feld ist erforderlich.",
"ThisFieldIsRequired.":"Dieses Feld ist erforderlich.",
"ThisFieldMustBeAStringWithAMaximumLengthOf{0}":"Dieses Feld muss eine Zeichenfolge mit einer maximalen Länge von {0} sein.",
"ThisFieldMustBeAStringWithAMaximumLengthOf{0}":"Dieses Feld muss eine Zeichenfolge mit einer maximalen Länge von {0} sein.",
"ThisFieldMustBeAStringWithAMinimumLengthOf{1}AndAMaximumLengthOf{0}":"Dieses Feld muss eine Zeichenfolge mit einer Mindestlänge von '{0}' sein.",
"ThisFieldMustBeAStringWithAMinimumLengthOf{1}AndAMaximumLengthOf{0}":"Dieses Feld muss eine Zeichenfolge mit einer Mindestlänge von '{0}' sein.",
"ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl":"Dieses Feld ist keine gültige vollqualifizierte http-, https- oder ftp-URL.",
"ThisFieldIsNotAValidFullyQualifiedHttpHttpsOrFtpUrl":"Dieses Feld ist keine gültige vollqualifizierte http-, https- oder ftp-URL.",
"UseAnotherServiceToLogin":"Einen anderen Dienst zum Anmelden verwenden",
"UseAnotherServiceToLogin":"Einen anderen Dienst zum Anmelden verwenden",
"UserLockedOutMessage":"Das Benutzerkonto wurde aufgrund fehlgeschlagener Anmeldeversuche gesperrt. Bitte warten Sie eine Weile und versuchen Sie es erneut.",
"UserLockedOutMessage":"Das Benutzerkonto wurde aufgrund fehlgeschlagener Anmeldeversuche gesperrt. Bitte warten Sie eine Weile und versuchen Sie es erneut.",
"InvalidUserNameOrPassword":"Ungültiger Benutzername oder Passwort!",
"InvalidUserNameOrPassword":"Ungültiger Benutzername oder Passwort!",
"LoginIsNotAllowed":"Sie dürfen sich nicht anmelden! Sie müssen Ihre E-Mail/Telefonnummer bestätigen.",
"LoginIsNotAllowed":"Sie dürfen sich nicht anmelden! Sie müssen Ihre E-Mail/Telefonnummer bestätigen.",
"SelfRegistrationDisabledMessage":"Die Selbstregistrierung ist für diese Anwendung deaktiviert. Bitte wenden Sie sich an den Anwendungsadministrator, um einen neuen Benutzer zu registrieren.",
"SelfRegistrationDisabledMessage":"Die Selbstregistrierung ist für diese Anwendung deaktiviert. Bitte wenden Sie sich an den Anwendungsadministrator, um einen neuen Benutzer zu registrieren.",
"LocalLoginDisabledMessage":"Die lokale Anmeldung ist für diese Anwendung deaktiviert.",
"LocalLoginDisabledMessage":"Die lokale Anmeldung ist für diese Anwendung deaktiviert.",
"Login":"Anmelden",
"Login":"Anmelden",
"Cancel":"Abbrechen",
"Cancel":"Abbrechen",
"Register":"Registrieren",
"Register":"Registrieren",
"AreYouANewUser":"Neuer Benutzer?",
"AreYouANewUser":"Neuer Benutzer?",
"AlreadyRegistered":"Bereits registriert?",
"AlreadyRegistered":"Bereits registriert?",
"InvalidLoginRequest":"Ungültige Login-Anfrage",
"InvalidLoginRequest":"Ungültige Login-Anfrage",
"ThereAreNoLoginSchemesConfiguredForThisClient":"Es sind keine Anmeldeschemata für diesen Client konfiguriert.",
"ThereAreNoLoginSchemesConfiguredForThisClient":"Es sind keine Anmeldeschemata für diesen Client konfiguriert.",
"LogInUsingYourProviderAccount":"Melden Sie sich mit Ihrem {0}-Konto an",
"LogInUsingYourProviderAccount":"Melden Sie sich mit Ihrem {0}-Konto an",
"DisplayName:Abp.Identity.User.IsUserNameUpdateEnabled":"Ist die Aktualisierung des Benutzernamens aktiviert?",
"DisplayName:Abp.Identity.User.IsUserNameUpdateEnabled":"Ist die Aktualisierung des Benutzernamens aktiviert?",
"DisplayName:Abp.Identity.User.IsEmailUpdateEnabled":"Ist die E-Mail-Aktualisierung aktiviert?",
"DisplayName:Abp.Identity.User.IsEmailUpdateEnabled":"Ist die E-Mail-Aktualisierung aktiviert?",
"Description:Abp.Identity.Password.RequiredLength":"Die Mindestlänge, die ein Passwort haben muss.",
"Description:Abp.Identity.Password.RequiredLength":"Die Mindestlänge, die ein Passwort haben muss.",
"Description:Abp.Identity.Password.RequiredUniqueChars":"Die Mindestanzahl eindeutiger Zeichen, die ein Passwort enthalten muss.",
"Description:Abp.Identity.Password.RequiredUniqueChars":"Die Mindestanzahl eindeutiger Zeichen, die ein Passwort enthalten muss.",
"Description:Abp.Identity.Password.RequireNonAlphanumeric":"Ob Passwörter ein nicht-alphanumerisches Zeichen enthalten müssen.",
"Description:Abp.Identity.Password.RequireNonAlphanumeric":"Ob Passwörter ein nicht-alphanumerisches Zeichen enthalten müssen.",
"Description:Abp.Identity.Password.RequireLowercase":"Ob Passwörter ein kleingeschriebenes ASCII-Zeichen enthalten müssen.",
"Description:Abp.Identity.Password.RequireLowercase":"Ob Passwörter ein kleingeschriebenes ASCII-Zeichen enthalten müssen.",
"Description:Abp.Identity.Password.RequireUppercase":"Ob Passwörter ein ASCII-Zeichen in Großbuchstaben enthalten müssen.",
"Description:Abp.Identity.Password.RequireUppercase":"Ob Passwörter ein ASCII-Zeichen in Großbuchstaben enthalten müssen.",
"Description:Abp.Identity.Password.RequireDigit":"Ob Passwörter eine Ziffer enthalten müssen.",
"Description:Abp.Identity.Password.RequireDigit":"Ob Passwörter eine Ziffer enthalten müssen.",
"Description:Abp.Identity.Lockout.AllowedForNewUsers":"Ob ein neuer Benutzer ausgesperrt werden kann.",
"Description:Abp.Identity.Lockout.AllowedForNewUsers":"Ob ein neuer Benutzer ausgesperrt werden kann.",
"Description:Abp.Identity.Lockout.LockoutDuration":"Die Dauer, für die ein Benutzer ausgesperrt ist, wenn eine Sperre auftritt.",
"Description:Abp.Identity.Lockout.LockoutDuration":"Die Dauer, für die ein Benutzer ausgesperrt ist, wenn eine Sperre auftritt.",
"Description:Abp.Identity.Lockout.MaxFailedAccessAttempts":"Die Anzahl der fehlgeschlagenen Zugriffsversuche, die erlaubt sind, bevor ein Benutzer gesperrt wird, vorausgesetzt, die Sperre ist aktiviert.",
"Description:Abp.Identity.Lockout.MaxFailedAccessAttempts":"Die Anzahl der fehlgeschlagenen Zugriffsversuche, die erlaubt sind, bevor ein Benutzer gesperrt wird, vorausgesetzt, die Sperre ist aktiviert.",
"Description:Abp.Identity.SignIn.RequireConfirmedEmail":"Whether a confirmed email address is required to sign in.",
"Description:Abp.Identity.SignIn.RequireConfirmedEmail":"Whether a confirmed email address is required to sign in.",
"Description:Abp.Identity.SignIn.EnablePhoneNumberConfirmation":"Ob für die Anmeldung eine bestätigte E-Mail-Adresse erforderlich ist.",
"Description:Abp.Identity.SignIn.EnablePhoneNumberConfirmation":"Ob für die Anmeldung eine bestätigte E-Mail-Adresse erforderlich ist.",
"Description:Abp.Identity.SignIn.RequireConfirmedPhoneNumber":"Ob für die Anmeldung eine bestätigte Telefonnummer erforderlich ist.",
"Description:Abp.Identity.SignIn.RequireConfirmedPhoneNumber":"Ob für die Anmeldung eine bestätigte Telefonnummer erforderlich ist.",
"Description:Abp.Identity.User.IsUserNameUpdateEnabled":"Ob der Benutzername vom Benutzer aktualisiert werden kann.",
"Description:Abp.Identity.User.IsUserNameUpdateEnabled":"Ob der Benutzername vom Benutzer aktualisiert werden kann.",
"Description:Abp.Identity.User.IsEmailUpdateEnabled":"Ob die E-Mail durch den Benutzer aktualisiert werden kann."
"Description:Abp.Identity.User.IsEmailUpdateEnabled":"Ob die E-Mail durch den Benutzer aktualisiert werden kann."