Skip to content

Commit f8523b4

Browse files
committed
Merge branch 'master' into dev
2 parents 3098116 + ab3c59c commit f8523b4

File tree

206 files changed

+8846
-8466
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

206 files changed

+8846
-8466
lines changed

docs/en/Deployment-Angular-Docker.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Publishing to Docker Containers
2+
3+
ASP.NET Zero solution has a **build folder** which contains a PowerShell script to **build & publish** your solution to the **output** folder.
4+
5+
It also contains **Docker** files to run your application inside Docker containers. You can customize the default run configuration according to your requirements.
6+
7+
In your `aspnet-core\docker\ng\` folder, you will see;
8+
9+
* `up.ps1` which starts the Docker container with the configuration defined in `docker-compose.yml`
10+
* `down.ps1` which shuts down the Docker container with the configuration defined in `docker-compose.yml`
11+
12+
![docker-folder-angular](images\docker-folder-angular.jpg)

docs/en/Deployment-Angular.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Deployment
2+
3+
## About Deployment
4+
5+
If you have merged Angular UI project into ASP.NET Core project then you only need to publish your .Host project. After publish .Host project, you should copy files that are in .Host/wwwroot/dist folder to publish_folder/wwwroot.
6+
7+
For example: Move files in `.Host/wwwroot/dist` to `C:\inetpub\wwwroot\my-website\wwwroot`
8+
9+
We are using [angular-cli](https://cli.angular.io/) for development & deployment. Angular CLI has it's own build command that can be used to build your application:
10+
11+
```
12+
ng build --prod
13+
```
14+
15+
This command uses **dist** folder as output. Just remember to change **assets/appconfig.json** file with your own configuration.
16+
17+
## AOT
18+
19+
Angular CLI uses **[AOT](https://angular.io/docs/ts/latest/cookbook/aot-compiler.html) (Ahead of Time)** compilation by default. You can add --no-aot parameter
20+
to the `ng build` command to disable it. But we recommend AOT feature since it has significant performance gain.
21+
22+
*Be aware that, if you don't configure email settings, some functions like new tenant registration may not work.*
23+
24+
# Next
25+
26+
* [Publishing to Azure](Deployment-Angular-Publish-Azure)
27+
* [Publishing to IIS](Deployment-Angular-Publish-IIS)
28+
* [Publishing to Docker](Deployment-Angular-Docker)
29+
30+
31+

docs/en/Deployment-Mvc-Core-Docker.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Publishing to Docker Containers
2+
3+
ASP.NET Zero solution has a **build folder** which contains a PowerShell script to **build & publish** your solution to the **output** folder.
4+
5+
It also contains **Docker** files to run your application inside Docker containers. You can customize the default run configuration according to your requirements.
6+
7+
In your `aspnet-core\docker\mvc\` folder, you will see;
8+
9+
* `up.ps1` which starts the Docker container with the configuration defined in `docker-compose.yml`
10+
* `down.ps1` which shuts down the Docker container with the configuration defined in `docker-compose.yml`
11+
12+
![docker-folder-angular](images\docker-folder-core-mvc.jpg)

docs/en/Step-by-step-core-publish-to-iis.md renamed to docs/en/Deployment-Mvc-Core-IIS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Step By Step Publish To IIS
1+
# Publishing to IIS
22

33
Publishing ASP.NET Zero Core MVC project is no different to any other ASP.NET Core Applications.
44

@@ -23,4 +23,5 @@ Publishing ASP.NET Zero Core MVC project is no different to any other ASP.NET Co
2323

2424
<img src="images/iis-core-publish-configure-app-pool.png">
2525

26-
Check [Host ASP.NET Core on Windows with IIS](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index?view=aspnetcore-2.1) document for more detail.
26+
For more information see [Host ASP.NET Core on Windows with IIS](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/index?view=aspnetcore-2.1) document
27+

docs/en/Deployment-Mvc-Core.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Deployment & Publish
2+
3+
Publishing ASP.NET Zero is not different than any other solution. You can use Visual Studio as you normally do.
4+
5+
Notice that, if you don't configure email settings, some functions (like new tenant registration) may not work as expected.
6+
7+
## Next
8+
9+
* [Publishing to Azure](Deployment-Mvc-Core-Azure)
10+
* [Publishing to IIS](Deployment-Mvc-Core-IIS)
11+
* [Publishing to Docker Containers](Deployment-Mvc-Core-Docker)
12+
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Adding AddPhone and DeletePhone Methods
2+
3+
We are adding two more methods to IPersonAppService interface as shown
4+
below:
5+
6+
```csharp
7+
Task DeletePhone(EntityDto<long> input);
8+
Task<PhoneInPersonListDto> AddPhone(AddPhoneInput input);
9+
```
10+
11+
We could create a new, separated IPhoneAppService. It's your choice.
12+
But, we can consider Person as an aggregate and add phone related
13+
methods here. AddPhoneInput DTO is shown below:
14+
15+
```csharp
16+
public class AddPhoneInput
17+
{
18+
[Range(1, int.MaxValue)]
19+
public int PersonId { get; set; }
20+
21+
[Required]
22+
public PhoneType Type { get; set; }
23+
24+
[Required]
25+
[MaxLength(PhoneConsts.MaxNumberLength)]
26+
public string Number { get; set; }
27+
}
28+
```
29+
30+
We used PhoneConsts.MaxNumberLength for Number field. You should create
31+
this consts in **.Core.Shared**.
32+
33+
```csharp
34+
public class PhoneConsts
35+
{
36+
public const int MaxNumberLength = 16;
37+
}
38+
```
39+
40+
Now, we can implement these methods:
41+
42+
```csharp
43+
[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook_EditPerson)]
44+
public async Task DeletePhone(EntityDto<long> input)
45+
{
46+
await _phoneRepository.DeleteAsync(input.Id);
47+
}
48+
49+
[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook_EditPerson)]
50+
public async Task<PhoneInPersonListDto> AddPhone(AddPhoneInput input)
51+
{
52+
var person = _personRepository.Get(input.PersonId);
53+
await _personRepository.EnsureCollectionLoadedAsync(person, p => p.Phones);
54+
55+
var phone = ObjectMapper.Map<Phone>(input);
56+
person.Phones.Add(phone);
57+
58+
//Get auto increment Id of the new Phone by saving to database
59+
await CurrentUnitOfWork.SaveChangesAsync();
60+
61+
return ObjectMapper.Map<PhoneInPersonListDto>(phone);
62+
}
63+
```
64+
65+
Then we add configuration for AutoMapper into CustomDtoMapper.cs like below:
66+
67+
```csharp
68+
configuration.CreateMap<AddPhoneInput, Phone>();
69+
```
70+
71+
(Note: We injected **IRepository&lt;Phone, long&gt;** in the constructor
72+
and set to \_phoneRepository field, as similar to \_personRepository)
73+
74+
**DeletePhone** method is simple. It only deletes phone with given id.
75+
76+
**AddPhone** method **gets** the person from database and add new phone
77+
to person.Phones collection. Then is **save changes**. Saving changes
78+
causes inserting new added phone to database and get its **Id**.
79+
Because, we are returning a DTO that contains newly created phone
80+
informations including Id. So, it should be assigned before mapping in
81+
the last line. (Notice that; normally it's not needed to call
82+
CurrentUnitOfWork.SaveChangesAsync. It's automatically called at the end
83+
of the method. We called it in the method since we need to save entity
84+
and get its Id immediately. See [UOW
85+
document](https://aspnetboilerplate.com/Pages/Documents/Unit-Of-Work#DocAutoSaveChanges)
86+
for more.)
87+
88+
There may be different approaches for AddPhone method. You can directly
89+
work with a **phone repository** to insert new phone. They all have
90+
different pros and cons. It's your choice.
91+
92+
## Next
93+
94+
- [Edit Mode for Phone Numbers](Developing-Step-By-Step-Angular-Edit-Mode-Phone-Numbers)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Adding a New Menu Item
2+
3+
Let's begin from UI and create a new page named "**Phone book**".
4+
5+
## Defining a Menu Item
6+
7+
Open **src\\app\\shared\\layout\\nav\\app-navigation.service.ts** in the client side (**Acme.PhoneBookDemo.AngularUI**) which defines menu items in the application. Create new menu item as shown below (You can add it right after the dashboard menu item).
8+
9+
```csharp
10+
new AppMenuItem("PhoneBook", null, "flaticon-book", "/app/main/phonebook")
11+
```
12+
13+
**PhoneBook** is the menu name (will localize below), **null** is for permission name (will set it later), **flaticon-book** is just an arbitrary icon class (from [this set](http://keenthemes.com/metronic/preview/?page=components/icons/flaticon&demo=default)) and **/phonebook** is the Angular route.
14+
15+
If you run the application, you can see a new menu item on the left menu, but it won't work (it redirects to default route) if you click to the menu item, since we haven't defined the Angular route yet.
16+
17+
## Localize Menu Item Display Name
18+
19+
Localization strings are defined in **XML** files in **.Core** project in server side as shown below:
20+
21+
<img src="D:/Github/documents/docs/en/images/localization-files-4.png" alt="Localization files" class="img-thumbnail" />
22+
23+
Open PhoneBookDemo.xml (the **default**, **English** localization dictionary) and add the following line:
24+
25+
```xml
26+
<text name="PhoneBook">Phone Book</text>
27+
```
28+
29+
If we don't define "PhoneBook"s value for other localization dictionaries, default value is shown in all languages. For example, we can define it also for Turkish in `PhoneBookDmo-tr.xml` file:
30+
31+
```xml
32+
<text name="PhoneBook">Telefon Rehberi</text>
33+
```
34+
35+
Note: Any change in server side (including change localization texts) requires recycle of the server application. We suggest to use Ctrl+F5 if you don't need to debugging for a faster startup. In that case, it's
36+
enough to make a re-build to recycle the application.
37+
38+
## Angular Route
39+
40+
Angular has a powerful URL routing system. ASP.NET Zero has defined routes in a few places (for modularity, see [main menu & layout](Features-Angular-Main-Menu-Layout.md)). We want to add phone book page to the main module. So, open **src\\app\\main\\main-routing.module.ts** in the client side and add a new route just below to the dashboard:
41+
42+
```json
43+
{ path: 'phonebook', component: PhoneBookComponent }
44+
```
45+
46+
We get an error since we haven't defined PhoneBookComponent yet. Also, we ignored permission for now (will implement later).
47+
48+
## Next
49+
50+
- [Creating the PhoneBook Component](Developing-Step-By-Step-Angular-Creating-PhoneBook-Component)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Adding Phone Numbers
2+
3+
Until now, we did not even mention about phone numbers. It's time to
4+
extend our domain to support **multiple phone numbers** for a person.
5+
6+
## Next
7+
8+
- [Creating Phone Entity](Developing-Step-By-Step-Angular-Creating-Phone-Entity)
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Authorization For Phone Book
2+
3+
At this point, anyone can enter phone book page since no authorization
4+
defined. We will define two permission:
5+
6+
- A permission to **enter phone book page**.
7+
- A permission to **create new person** (which is a child permission
8+
of first one, as naturally).
9+
10+
## Permission for Entering Phone Book Page
11+
12+
### Define the permission
13+
14+
Go to **AppAuthorizationProvider** class in the server side and add a new permission as shown below (you can add just below the dashboard permission):
15+
16+
```csharp
17+
pages.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook, L("PhoneBook" | localize), multiTenancySides: MultiTenancySides.Tenant);
18+
```
19+
20+
A permission should have a unique name. We define permission names as constant strings in **AppPermissions** class. It's a simple constant string:
21+
22+
```csharp
23+
public const string Pages_Tenant_PhoneBook = "Pages.Tenant.PhoneBook";
24+
```
25+
26+
Unique name of this permission is "**Pages.Tenant.PhoneBook**". While you can set any string (as long as it's unique), it's suggested to use that convention. A permission can have a localizable display name: "**PhoneBook**" here. (See "Adding a New Page" section for more about localization, since it's very similar). Lastly, we set this as a **tenant** level permission.
27+
28+
### Add AbpAuthorize attribute
29+
30+
**AbpAuthorize** attribute can be used as **class level** or **method level** to protect an application service or service method from unauthorized users. Since all server side code is located in `PersonAppService` class, we can declare a class level attribute as shown below:
31+
32+
```csharp
33+
[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook)]
34+
public class PersonAppService : PhoneBookAppServiceBase, IPersonAppService
35+
{
36+
//...
37+
}
38+
```
39+
40+
Admin role has every static permission by default but those permissions can be reversible on user interface for this role. Go to Roles page, edit role named "admin", go to Permissions tab and revoke "Phone Book" permission and save.
41+
42+
Now, let's try to enter Phone Book page by clicking the menu item without required permission:
43+
44+
<img src="D:/Github/documents/docs/en/images/phonebook-permission-error.png" alt="Permission error" class="img-thumbnail" width="505" height="412" />
45+
46+
We get an error message. This exception is thrown when any method of `PersonAppService` is called without required permission.
47+
48+
### Guard Angular Route
49+
50+
We got an exception about permission. Server did not send the data but we can still enter the page. To prevent it, open **main-routing.module.ts** and change the route definition like that:
51+
52+
```json
53+
{ path: 'phonebook', component: PhoneBookComponent, data: { permission: 'Pages.Tenant.PhoneBook' } }
54+
```
55+
56+
**AuthRouteGuard** class automatically checks route permission data and prevents entering to the view if specified permission is not granted. Try to click Phone Book menu!
57+
58+
### Hide Unauthorized Menu Item
59+
60+
While user can not enter to the page, the menu item still there! We should also **hide** the Phone book **menu item**. It's easy, open **app-navigation-service.ts** and add change PhoneBook menu definition as shown below:
61+
62+
```typescript
63+
new AppMenuItem("PhoneBook", 'Pages.Tenant.PhoneBook', "flaticon-book", "/app/main/phonebook")
64+
```
65+
66+
### Grant permission
67+
68+
So, how we can enter the page now? Simple, go to **Role Management** page and edit **admin** role:
69+
70+
<img src="D:/Github/documents/docs/en/images/role-permissions-with-phonebook1.png" alt="Role permissions" class="img-thumbnail" />
71+
72+
We see that a **new permission** named "**Phone book**" added to **permissions** tab. So, we can check it and save the role. After saving, we need to **refresh** the whole page to refresh permissions for the current user. We could also grant this permission to a specific user. Now, we can enter the Phone book page again.
73+
74+
## Permission for Create New Person
75+
76+
While a permission for a page is useful and probably always needed, we may want to define additional permissions to perform some **specific actions** on a page, like creating a new person.
77+
78+
### Define the Permission
79+
80+
Defining a permission is similar (in the `AppAuthorizationProvider` class):
81+
82+
```csharp
83+
var phoneBook = pages.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook, L("PhoneBook" | localize), multiTenancySides: MultiTenancySides.Tenant);
84+
phoneBook.CreateChildPermission(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson, L("CreateNewPerson" | localize), multiTenancySides: MultiTenancySides.Tenant);
85+
```
86+
87+
First permission was defined before. In the second line, we are creating a child permission of first one. Remember to create a constant in `AppPermissions` class:
88+
89+
```csharp
90+
public const string Pages_Tenant_PhoneBook_CreatePerson = "Pages.Tenant.PhoneBook.CreatePerson";
91+
```
92+
93+
### Add AbpAuthorize Attribute
94+
95+
This time, we're declaring **AbpAuthorize** attribute just for **CreatePerson** method:
96+
97+
```csharp
98+
[AbpAuthorize(AppPermissions.Pages_Tenant_PhoneBook_CreatePerson)]
99+
public async Task CreatePerson(CreatePersonInput input)
100+
{
101+
//...
102+
}
103+
```
104+
105+
### Hide Unauthorized Button
106+
107+
If we run the application and try to create a person, we get an authorization error after clicking the save button. But, it's good to **completely hide Create New Person button** if we don't have the permission. It's very simple:
108+
109+
Open the **phonebook.component.html** view and add the permission **Pages.Tenant.PhoneBook.CreatePerson** condition as shown below:
110+
111+
```html
112+
<button *ngIf="'Pages.Tenant.PhoneBook.CreatePerson' | permission" class="btn btn-primary" (click)="createPersonModal.show()"><i class="fa fa-plus"></i> {{l("CreateNewPerson" | localize)}}</button>
113+
```
114+
115+
In this way, the "Create New Person" button does not rendered in server and user can not see this button.
116+
117+
### Grant permission
118+
119+
To see the button again, we can go to role or user manager and grant related permission as shown below:
120+
121+
<img src="D:/Github/documents/docs/en/images/user-permissions-phonebook1.png" alt="User specific permissions" class="img-thumbnail" />
122+
123+
As shown above, **Create new person** permission is a child permission of the **Phone book**. Remember to refresh page to get permissions updated.
124+
125+
## Next
126+
127+
- [Deleting a Person](Developing-Step-By-Step-Angular-Deleting-Person)

0 commit comments

Comments
 (0)