Current Path : /www/sites/www.coderblog.in/index/
Url:

NameSizeOptions
App_DataDIRnone
backupDIRnone
cgi-binDIRnone
cssDIRnone
imgDIRnone
metaDIRnone
wp-adminDIRnone
wp-contentDIRnone
wp-includesDIRnone
.htaccess3.35 KBDEL
.htaccess.bk1.84 KBDEL
404.html0.13 KBDEL
ads.txt1.07 KBDEL
favicon.ico2.19 KBDEL
index.php0.40 KBDEL
license.txt19.44 KBDEL
php.ini0.58 KBDEL
readme.html7.25 KBDEL
service.php0.00 KBDEL
web.config2.87 KBDEL
wp-activate.php7.21 KBDEL
wp-blog-header.php1.21 KBDEL
wp-comments-post.php2.27 KBDEL
wp-config-sample.php3.26 KBDEL
wp-config.php2.98 KBDEL
wp-cron.php5.49 KBDEL
wp-links-opml.php2.44 KBDEL
wp-load.php3.84 KBDEL
wp-login.php50.21 KBDEL
wp-mail.php8.52 KBDEL
wp-settings.php29.38 KBDEL
wp-signup.php33.71 KBDEL
wp-trackback.php4.98 KBDEL
xmlrpc.php3.13 KBDEL
.net core – Coder Blog https://www.coderblog.in Join the coding revolution! Learn, share, and grow together! Wed, 30 Aug 2023 04:06:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.1 Create Paging Data from .Net Core Api https://www.coderblog.in/2023/08/create-paging-data-from-net-core-api/ https://www.coderblog.in/2023/08/create-paging-data-from-net-core-api/#comments Fri, 04 Aug 2023 00:41:04 +0000 https://www.coderblog.in/?p=929 This is post 7 of 8 in the series “Create a website with ASP.NET Core and Angular” In

<p>The post Create Paging Data from .Net Core Api first appeared on Coder Blog.</p>

]]>
  1. How to setup VS Code environment for ASP.NET Core Project
  2. Use code first to connect database in .Net Core API
  3. Use the Repository pattern in .Net core
  4. Create .Net Core Api controller for CRUD with repository
  5. Use the Serilog in .Net Core
  6. Create Angular Project and Communicate with .Net Core
  7. Create Paging Data from .Net Core Api
  8. How to do Unit Testing for the Core Api Project with Repository

This article is the second part for Create Angular Project and Communicate with .Net Core

1. Data Result Service

As we need to support filter and paging data from Api, so we also need to create a date result service for handle it. We can create this service in MyDemo.Core Api project:

1.1. Create the properties for filter and paging

//MyDemo.API/MyDemo.Core/Services/DataResultService.cs

public class DataResultService<T>
{
   #region Properties
    /// <summary>
    /// The data result.
    /// </summary>
    public List<T> Data { get; private set; }

    /// <summary>
    /// Zero-based index of current page.
    /// </summary>
    public int PageIndex { get; private set; }

    /// <summary>
    /// Number of items contained in each page.
    /// </summary>
    public int PageSize { get; private set; }

    /// <summary>
    /// Total items count
    /// </summary>
    public int TotalCount { get; private set; }

    /// <summary>
    /// Total pages count
    /// </summary>
    public int TotalPages { get; private set; }

    /// <summary>
    /// TRUE if the current page has a previous page,
    /// FALSE otherwise.
    /// </summary>
    public bool HasPreviousPage
    {
        get
        {
            return (PageIndex > 0);
        }
    }

    /// <summary>
    /// TRUE if the current page has a next page, FALSE otherwise.
    /// </summary>
    public bool HasNextPage
    {
        get
        {
            return ((PageIndex + 1) < TotalPages);
        }
    }

    /// <summary>
    /// Sorting Column name (or null if none set)
    /// </summary>
    public string? SortColumn { get; set; }

    /// <summary>
    /// Sorting Order ("ASC", "DESC" or null if none set)
    /// </summary>
    public string? SortOrder { get; set; }

    /// <summary>
    /// Filter Column name (or null if none set)
    /// </summary>
    public string? FilterColumn { get; set; }
    /// <summary>
    /// Filter Query string
    /// (to be used within the given FilterColumn)
    /// </summary>
    public string? FilterQuery { get; set; }
    #endregion
}

1.2. Create a private constructor

We need to return the data object for client side and include the above properties, so we can use a private constructor for return the data

private DataResultService(
    List<T> data,
    int count,
    int pageIndex,
    int pageSize,
    string? sortColumn,
    string? sortOrder,
    string? filterColumn,
    string? filterQuery)
{
    Data = data;
    PageIndex = pageIndex;
    PageSize = pageSize;
    TotalCount = count;
    TotalPages = (int)Math.Ceiling(count / (double)pageSize);
    SortColumn = sortColumn;
    SortOrder = sortOrder;
    FilterColumn = filterColumn;
    FilterQuery = filterQuery;
}

1.3. Get paging data

Cause I want to support dynamic filter with Linq, so we need to create a method for handle this, and need to install below packages from Nuget for support dynamic filter query

System.Linq.Dynamic.Core
System.Linq.Async

Now we can create the below method

public static async Task<DataResultService<T>> CreateAsync(
            IQueryable<T> source,
            int pageIndex,
            int pageSize,
            string? sortColumn = null,
            string? sortOrder = null,
            string? filterColumn = null,
            string? filterQuery = null)
        {
          //todo...
        }

this method can support many parameters from client side, because these parameters were passed from client by a Get method with a string format, so the first thing we need to do is split the column and query, after that, just create a dynamic SQL query pass to Linq object for get data

if (!string.IsNullOrEmpty(filterColumn)
    && !string.IsNullOrEmpty(filterQuery))
{
    if (filterColumn.Contains(","))
    {
        //handle multiple columns filter
        var index = 0;
        var sql = "";
        var queries = filterQuery.Split(',');
        foreach (var column in filterColumn.Split(','))
        {
            if (!string.IsNullOrEmpty(queries[index]) && queries[index] != "null")
            {
                sql += string.Format("{0}.Contains(@{1}) and ", column, index);
            }
            index++;
        }
        if (sql.Length > 0)
        {
            sql = sql.Substring(0, sql.Length - 4); //remove the end of 'and '
        }
        if (sql != "")
        {
            source = source.Where(sql, queries);
        }
    }
    else
    {
        source = source.Where(
        string.Format("{0}.Contains(@0)",
        filterColumn),
        filterQuery);
    }
}

get the total items and generate the data for paging

var count = await source.CountAsync();

//sort data by column 
if (!string.IsNullOrEmpty(sortColumn))
{
    sortOrder = !string.IsNullOrEmpty(sortOrder)
    && sortOrder.ToUpper() == "ASC" ? "ASC" : "DESC";

    source = source.OrderBy(string.Format("{0} {1}",sortColumn,sortOrder));
}

//get the data by paging query
source = source.Skip(pageIndex * pageSize).Take(pageSize);

//convert to list items
var data = await source.ToAsyncEnumerable().ToListAsync();

//generate the result by private constructor
return new DataResultService<T>(
            data,
            count,
            pageIndex,
            pageSize,
            sortColumn,
            sortOrder,
            filterColumn,
            filterQuery);

2. Update UserController

After created the DataResultService , we can update our UserController.

First, update the GetUsers for support paging parameters, and change the return value to DataResultService<User>

public async Task<ActionResult<DataResultService<User>>> GetUsers(
                        int pageIndex = 0, int pageSize = 10,
                        string? sortColumn = null, string? sortOrder = null,
                        string? filterColumn = null, string? filterQuery = null)

update the apiResult type to DataResultService<User>

var apiResult = new ApiResult<DataResultService<User>>();

in the end, update the get data method

var users = _userRepository.GetAll();

apiResult.Data = await DataResultService<User>.CreateAsync(
            users,
            pageIndex,
            pageSize, sortColumn,
            sortOrder, filterColumn,
            filterQuery);

3. Test the Api

Ok, we have finished the changes with our Api, now we can try it with the angular client.

First, start the Api project in VS Code console with below command (don’t forget goto the Api folder)

dotnet watch run

and create another new console and goto MyDemo.Client folder to run below command

npm run hmr

after that, you should access the user management page as below URL

http://localhost:4810/user-management

and if everything is ok, the result should be like below

Figure 1

after search by user name

Figure 2

Loading

<p>The post Create Paging Data from .Net Core Api first appeared on Coder Blog.</p>

]]>
https://www.coderblog.in/2023/08/create-paging-data-from-net-core-api/feed/ 8
Create Angular Project and Communicate with .Net Core https://www.coderblog.in/2023/08/create-angular-project-and-communicate-with-net-core/ https://www.coderblog.in/2023/08/create-angular-project-and-communicate-with-net-core/#comments Wed, 02 Aug 2023 06:14:23 +0000 https://www.coderblog.in/?p=891 This is post 6 of 8 in the series “Create a website with ASP.NET Core and Angular” In

<p>The post Create Angular Project and Communicate with .Net Core first appeared on Coder Blog.</p>

]]>
  1. How to setup VS Code environment for ASP.NET Core Project
  2. Use code first to connect database in .Net Core API
  3. Use the Repository pattern in .Net core
  4. Create .Net Core Api controller for CRUD with repository
  5. Use the Serilog in .Net Core
  6. Create Angular Project and Communicate with .Net Core
  7. Create Paging Data from .Net Core Api
  8. How to do Unit Testing for the Core Api Project with Repository

We have created the ASP.NET Core Api project, the Api only for backend data handler, now we need to create the client side project to call the Api and present the website layout for end user. Here I will use Angular for client side project.

1. Why Angular

There are some of key advantages of using Angular

Component architecture – Angular promotes building applications using components. This makes the code modular, reusable and maintainable.
Declarative templates – The templates in Angular use HTML to define the UI layout declaratively. This makes it easier to visualize the UI.
Data binding – Angular handles data binding automatically between components, their templates and the application data. This reduces boilerplate code.
TypeScript support – Angular uses TypeScript which brings static typing to JavaScript. This improves code quality and maintainability.
Dependency injection – Angular comes with a built-in dependency injector that makes the code loosely coupled and easy to test.
Testing – Angular was designed with testing in mind. It has great unit and end-to-end testing support.
Cross platform – Angular can be used to build web, mobile and desktop applications from the same codebase.
Community and Google support – Angular is actively developed and maintained by Google. It also has a large community.
A lot of 3rd party extensions – There are a lot of 3rd party extensions support, this can save many of times for help us to create the project.
Features – Angular ships with a lot of built-in features like routing, forms handling, HTTP services, etc. This reduces boilerplate code.
Stable releases – The Angular team focuses on stability and quality with planned major releases every 6 months.

So, Angular simplifies web development by providing a robust framework to build declarative, component-based applications. With its strong features, community support and Google backing, it is a reliable choice for building modern web applications.

2. Create Angular Project

2.1 Install Angular

If you are first time for using Angular, you need to install the CLI, you can execute below command in VS Code terminal as below

npm install -g @angular/cli

Base on our previous Api project, so we goto Demo folder in VS Code terminal and execute below command for creating a new Angular project

ng new MyDemo.Client

After that, the folder structure should be like below

size300

2.2 Running the project

We can try to run the Angular project first, for easy debug, I will suggest using the HMR for running it, the HMR means Hot Module Replacement, which is a development feature that allows you to update the code of your running application without having to reload the entire page. This can greatly speed up the development process by allowing you to see changes in your code immediately, without having to wait for the application to rebuild and reload.

In Angular, you can enable HMR by using the ng serve command with the –hmr flag, like this:

ng serve --hmr

but for convenient to use, we can add the below command to /MyDemo.Client/package.json file under scripts section

"scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "hmr": "ng serve --hmr --disable-host-check --port 4810"
  },

and you can run the command as below for start the project

npm run hmr

after that, you will find there is an Url in console, and the port that’s what you set in the package.json

Figure 1

and you can press Ctrl + C for terminating.

3. Create an user page

3.1. Create user component

For this sample, we just need to create an user page for demonstrate how to do get data from .Net Core Api. Use the below command for create an user-management component

ng generate component user-management

it will generate 4 files in an user-management folder

user-management.component.html : the html layout for displaying
user-management.component.scss : cause we use the scss for handle the style when we create the project, so it will auto generate the scss style sheet file
user-management.component.spect.ts : the unit test file for testing the component
user-management.component.ts : you can think that’s the code-behind file for handle the business logic with typescript

by the way, if you don’t want to generate so many files (actually the unit test file should be use for a few times), you can also use the command for control it, for example the below command will skip the test and style file

ng generate component user-management  --skip-tests --inline-style 

and for easier to use, you also can use below command for the same result

ng g c user-management  --skip-tests --inline-style 

3.2 Update the routing

Update the /src/app/app-routing.module.ts, add the user management route, so that we can access from the url

const routes: Routes = [
  { path: 'user-management', component: UserManagementComponent },
];

Cause we just want a simple page for demo, so update the app.component.html , remove other html and just keep the style and base structure, put the router outlet to the main content, so we can remove all of the html code after <h2>Resources</h2> and the result should be like below

Figure 2

3.3 About the router-outlet:

The router-outlet directive is used to display the components that correspond to the current route. When a route is activated, the component that corresponds to that route is displayed within the router-outlet tag.

It’s typically included in the root component of your application, such as app.component.html. When a user navigates to a route in your application, Angular will dynamically replace the contents of the router-outlet tag with the component that corresponds to that route.

So in our case, it will show the user management component’s content, after that, you will see the below result

Figure 3

4. Create the page layout

4.1.1 Create the models

As we need to show the user data from Api, so we also need to create a same user model in client side map to Api. Create models folder under app folder, and create the user.ts model. We can use interface for the model in angular:

//MyDemo.Client/src/app/models/user.ts

/**
 * ~ User model for mapping to Api
 */
export interface User {
  id?: number;
  isActive?: boolean;
  isDeleted?: boolean;
  name?: string;
  password?: string;
  email?: string;
  createdAt?: Date;
  updatedAt?: Date;
}

and we also need to handle the Api result, so should be there is a same model for mapping

//MyDemo.Client/src/app/models/api-result.ts

/**
 * ~ The common API result model
 */
export interface ApiResult<T> {
  data?: T;
  success: boolean;
  message: string;
}

in the end, we want to show data in a table list layout (grid), so it’s need to support some paging values, we can create a model like below

//MyDemo.Client/src/app/models/data-list-result.ts

/**
 * ~The common data list result model
 */
export interface DataListResult<T> {
  data: T[];
  pageIndex: number;
  pageSize: number;
  totalCount: number;
  totalPages: number;
  sortColumn: string;
  sortOrder: string;
  filterColumn: string;
  filterQuery: string;
}

the data will be a dynamic object, so we use the generic type.

4.2. Use the extensions (or packages)

One of the advantage it there are a lot of great extensions for Angular, so we can use them to easy to create a pretty layout! For this sample, I will use @ng-matero/extensions for create the grid layout, run below command for install it

npm install @ng-matero/extensions --save

For using ng-matero/extensions, we need to add the module to app.module.ts, and because this module base on angular material, so we also need to add some material modules

//MyDemo.Client/src/app/app.module.ts

//import the base form and material modules
import { FormsModule } from '@angular/forms';

import { MatFormFieldModule } from '@angular/material/form-field';
import { MatButtonModule } from '@angular/material/button';
import { MatInputModule} from '@angular/material/input';
import {TextFieldModule} from '@angular/cdk/text-field';

//import the grid module
import { MtxGridModule } from '@ng-matero/extensions/grid';

and set these modules into imports in @NgModule

@NgModule({
  declarations: [
    AppComponent,
    UserManagementComponent
  ],
  imports: [
    FormsModule,
    MatInputModule,
    MatButtonModule,
    TextFieldModule,
    MatFormFieldModule,
    MtxGridModule,
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

4.3. Create the user management page

4.3.1. Frontend layout

if you used the angular CLI to create the user management component, it will auto add the reference in your app.module, but we still need to set the app routing for user management

//MyDemo.Client/src/app/app-routing.module.ts

const routes: Routes = [
  { path: 'user-management', component: UserManagementComponent },
];

after that, we can use the url http://localhost:4801/user-management to access.

Ok, let’s update the user management page layout. We will use the material theme for the layout and ng-matero/extensions grid for showing data, so the frontend html codes should be like below

<!-- user-management.component.html -->

<h1>User Management </h1>

<div class="row">
  <div class="col-sm-12">
      <!-- use the material form field and button -->
      <mat-form-field class="col-sm-3">
        <input matInput [(ngModel)]="query.q" name="q" (keyup.enter)="search()" placeholder="Filter by user name">
      </mat-form-field>
      <button class="m-r-8 bg-green-700 text-light" mat-raised-button  (click)="search()">Search</button>
      <button class="m-r-8 bg-red-700 text-light" mat-raised-button (click)="reset()">Reset</button>
  </div>
</div>
<p></p>

<!-- use the ng-matero grid -->
<mtx-grid [data]="list"
          [columns]="columns"
          [length]="total"
          [loading]="isLoading"
          [hideRowSelectionCheckbox]="false"
          [multiSelectable]="true"
          [rowSelectable]="true"
          [columnResizable]="true"
          [columnSortable] = "true"
          [pageOnFront]="false"
          [toolbarTitle]="'Show Columns'"
          [showToolbar]="true"
          [rowHover]="true"
          [rowStriped]="true"
          [pageIndex]="query.page"
          [pageSize]="query.per_page"
          [pageSizeOptions]="[5,10,20]"
          (page)="getNextPage($event)"
          (sortChange)="sortingChange($event)"
          [sortOnFront] = "false">
</mtx-grid>

you can goto here for the details how to use the grid.

4.3.2. Backend grid

We also need to update the backend ts file

//user-management.component.ts

//import the grid and material paginator, we need to support paging
import { PageEvent } from '@angular/material/paginator';
import { MtxGridColumn } from '@ng-matero/extensions/grid';

define the variable for paging default values

public defaultFilterColumn: string = "name";
public defaultPageIndex: number = 0;
public defaultPageSize: number = 10;
public defaultSortColumn: string = "name";
public defaultSortOrder: "asc" | "desc" = "asc";
public isLoading = true;
public list: any[] = []; //model listing data
public total = 0;   //the total records
public filterQuery?: string; //filter query for search 

define the grid’s column, it will be apply to frontend html value

public columns: MtxGridColumn[] = [ 
  { header: 'Id', field: 'id', hide: true },
  { header: 'Active', field: 'isActive', sortable: true,
      type: 'tag',
      tag: {
        true: { text: 'Yes', color: 'red-100' },
        false: { text: 'No', color: 'green-100' },
      },
  },
  { header: 'User Name', field: 'name', sortable: true, minWidth: 250 },
  { header: 'Email', field: 'email', minWidth: 250 ,sortable: true },
  { header: 'Created Date', field: 'createdAt' , minWidth: 150, sortable: true},
  { header: 'Updated Date', field: 'updatedAt' , minWidth: 160, sortable: true},
];

you can see the column field name should be same with the user model’s field name.

4.3.3. Create service

For support get data from Api, we can create a service for handle it. Create a services folder and user-management.service.ts as below

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { debounceTime, Observable, tap } from 'rxjs';
import { DataListResult } from '../models/data-list-result';
import { ApiResult } from '../models/api-result';
import { User } from '../models/user';

@Injectable({
  providedIn: 'root',
})
export class UserManagementService {

  constructor(public http: HttpClient) { }

  public getData(
    pageIndex: number,
    pageSize: number,
    sortColumn: string,
    sortOrder: string,
    filterColumn: string | null,
    filterQuery: string | null
  ): Observable<ApiResult<DataListResult<User>>> {
    var url = "http://localhost:5293/api/UserManagement/users";

    //pass the params to api for get data
    var params = new HttpParams()
      .set("pageIndex", pageIndex.toString())
      .set("pageSize", pageSize.toString())
      .set("sortColumn", sortColumn)
      .set("sortOrder", sortOrder);
    if (filterColumn && filterQuery) {
      params = params
        .set("filterColumn", filterColumn)
        .set("filterQuery", filterQuery);
    }

    //call the api and return the result map to DataListResult and User model
    return this.http.get<ApiResult<DataListResult<User>>>(url, { params });
  }
}

As you can see, we need to pass many parameters to Api for support paging, and the Api should return the DataListResult<T> object. But for the previous article, our user Api didn’t support these parameters, don’t worry, we will update the Api later, for now , let’s complete the user-management.component.ts first!

4.3.4. Handle get data and filter methods

For using the user service, we need to pass it into constructor, so update the user-management.component.ts as below

constructor(private userManagementService: UserManagementService,
      private dialog: MtxDialog) { }

and also use the MtxDialog for showing error messages.

Next, we need to define a query object for save the filter and paging data

public query = {
  q: '',
  sort: 'name',
  order: 'desc',
  page: 0,
  per_page: this.defaultPageSize,
};

and then, we can create a getData call the service method

public getData() {
  //get sort column
  var sortColumn = (this.query.sort)
    ? this.query.sort
    : this.defaultSortColumn;
  //get the order method
  var order = (this.query.order)
    ? this.query.order
    : this.defaultSortOrder;
  //get the filter query
  var filterQuery = (this.query.q)
    ? this.query.q
    : null;
  //call service to get data from Api
  this.userManagementService.getData(
    this.query.page,
    this.query.per_page,
    sortColumn,
    order,
    this.defaultFilterColumn,
    filterQuery).subscribe(res => {
        //console.log('res', res);
        if(res.success){
          this.list = res.data ? res.data.data : [] ;
          this.total = res.data? res.data.totalCount : 0;
        } else {
          this.dialog.alert(`Failed to get data!`);
        }
      }
    );
}

after that, we can handle the search and paging methods

public search() {
  this.query.page = 0;
  this.getData();
}
public reset() {
  this.query.q = '';
  this.query.page = 0;
  this.getData();
}
//goto next page event
public getNextPage(e: PageEvent) {
  this.query.page = e.pageIndex;
  this.query.per_page = e.pageSize;
  this.getData();
}
//sorting change event
public sortingChange(e: Sort) {
    //console.log('sortingChange', e);
    this.query.sort = e.active;
    this.query.order = e.direction;
    this.getData();
}
//for load data when first time access the page
public loadData(query?: string) {
  var pageEvent = new PageEvent();
  pageEvent.pageIndex = this.defaultPageIndex;
  pageEvent.pageSize = this.defaultPageSize;
  this.filterQuery = query;
  this.getData();
}
//load data when access the page
public ngOnInit() {
  this.loadData();
}

So far, we finished the client side codes, we can just take a look the page

Figure 4

Ok, I know, there is a last important thing we still need to do, otherwise we can’t get any data from our Api. But because there are also many things need to do, so I will describe the details in the next article 🙂

Loading

<p>The post Create Angular Project and Communicate with .Net Core first appeared on Coder Blog.</p>

]]>
https://www.coderblog.in/2023/08/create-angular-project-and-communicate-with-net-core/feed/ 9