به نام خدا. در این آموزش قصد دارم نحوه ی پیاده سازی سمت سرور قابلیت های Pagination و Sort و Search در جداول را خدمتتان ارائه کنم. این آموزش دو بخش دارد، در این بخش به پیاده سازی قابلیت های مذکور در سمت سرور با ASP.net Core و Entity Framework Core خواهیم پرداخت.
در آموزش ارائه شده در لینک زیر که بخش دوم این آموزش است به پیاده سازی قسمت Front End این قابلیت ها با Angular 8 و Bootstrap 4 و اتصال آن به سرور ASP.net Core پرداخته ایم که می توانید با مراجعه به لینک زیر آن را مطالعه بفرمایید:
کدهای این آموزش (هم کدهای سمت سرور با ASP.net Core و هم کدهای سمت کاربر با Angular 8 و Bootstrap 4) را می توانید از لینک زیر به صورت رایگان دانلود و استفاده کنید.
کدهای این آموزش در آدرس زیر قابل مشاهده و دانلود است
https://github.com/MohammadMoeinFazeli/ASP.NetCore-Angular8-PaginationSortingFiltering
برای ایجاد قابلیت های Pagination و Sort و Search در سمت سرور ابتدا یک پروژه ASP.net Core جدید ایجاد کنید. اگر نیاز به راهنمایی دارید از آموزش های زیر استفاده کنید:
– آموزش ویدئویی ASP.net Core WebAPI
– ایجاد اولین پروژه Web API در ASP.net Core با Visual Studio 2019
برای برگرداندن خروجی درخواست های pagination به صورت استاندارد و با فیلدهای موردنیاز کلاس پایه ی PagedResultBase را با استفاده از کدهای زیر ایجاد می کنیم:
public abstract class PagedResultBase
{
public int CurrentPage { get; set; }
public int PageCount { get; set; }
public int PageSize { get; set; }
public int RowCount { get; set; }
public int FirstRowOnPage => (CurrentPage - 1) * PageSize + 1;
public int LastRowOnPage => Math.Min(CurrentPage * PageSize, RowCount);
}
اکنون مدل عمومی پاسخ خود را که از کلاس PagedResultBase ارثبری می کند و به صورت Generic پیاده سازی شده است تا هرنوع داده ای را پشتیبانی کند به صورت زیر پیاده سازی می کنیم:
public class PagedResult<T> : PagedResultBase where T : class
{
public IList<T> Results { get; set; }
public PagedResult()
{
Results = new List<T>();
}
}
از آنجایی که مدل های ایجاد شده توسط Entity Framework Core از نوع IQueryable هستند و بدین واسطه امکان اجرای توابع System.Linq روی آن ها وجود دارد، یک افزونه (تابع جدید) به نوع داده ای IQueryable با استفاده از کد زیر اضافه می کنیم و نام آن را GetPaged قرار می دهیم. این تابع مجددا Generic است و هرنوع مدلی را پشتیبانی می کند. تابع GetPaged فیلد page(یا همان شماره صفحه فعلی در pagination) و فیلد pageSize(یا همان تعداد آیتم ها در هرصفحه) را دریافت کرده و پس از اعمال یکسری توابع Linq مورد نیاز برای جابه جایی بین داده ها و یافتن داده ی مورد نظر و متناسب با فیلدهای page و pageSize و سپس استخراج داده های مناسب از پایگاه داده، خروجی را که از نوع PagedResult است برمی گرداند:
public static class QueryableExtention
{
public static PagedResult<T> GetPaged<T>(this IQueryable<T> query,
int page, int pageSize) where T : class
{
var result = new PagedResult<T>
{
CurrentPage = page, PageSize = pageSize, RowCount = query.Count()
};
var pageCount = (double) result.RowCount / pageSize;
result.PageCount = (int) Math.Ceiling(pageCount);
var skip = (page - 1) * pageSize;
result.Results = query.Skip(skip).Take(pageSize).ToList();
return result;
}
}
اکنون تمام اموری که مربوط به بحث Pagination در سمت سرور بود تمام شد. برای پیاده سازی قابلیت های Sort و Filter و همچنین تست کدهای پیاده سازی شده، یک مدل جدید با نام Student با استفاده از کدهای زیر ایجاد کنید:
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
public string Family { get; set; }
}
اکنون یک کلاس جدید که از DbContext ارثبری میکند و برای استفاده از Entity Framework Core که به صورت مختصر EF خوانده می شود و ایجاد پایگاه داده و جداول و اتصال به دیتابیس استفاده می شود همانند کدهای زیر ایجاد کنید و نام آن را AppDbContext قرار دهید:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
}
حال برای اینکه در ابتدا جدول Students خالی نباشد و دارای داده باشد، از قابلیت Seed فریمورک EF استفاده می کنیم. بدین منظور کدهای مربوط به کلاس AppDbContext را به صورت زیر تکمیل کنید:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>().HasData(new Student[]
{
new Student {StudentId = 1, Name = "moein", Family = "Fazeli"},
new Student {StudentId = 2, Name = "omid", Family = "gholami"},
new Student {StudentId = 3, Name = "sara", Family = "saravi"},
new Student {StudentId = 4, Name = "fateme", Family = "mosavi"},
new Student {StudentId = 5, Name = "jodi", Family = "abot"},
new Student {StudentId = 6, Name = "sobasa", Family = "karaeer"},
new Student {StudentId = 7, Name = "ahmad", Family = "hoseeini"},
new Student {StudentId = 8, Name = "mohammad", Family = "bahrami"},
new Student {StudentId = 9, Name = "saeed", Family = "sadeghi"},
new Student {StudentId = 10, Name = "sajad", Family = "saheri"},
new Student {StudentId = 11, Name = "sami", Family = "sarvari"},
new Student {StudentId = 12, Name = "bano", Family = "mahmodi"},
new Student {StudentId = 13, Name = "mahdie", Family = "maghsoodi"},
new Student {StudentId = 14, Name = "shahriar", Family = "asadi"}
});
}
}
خوب حال وقت اتصال به پایگاه داده است. بدین منظور نیاز به connection string اتصال به پایگاه داده دارید. connection string مدنظر خود را در فایل تنظیمات یعنی فایل appsettings.json همانند کدهای زیر قرار دهید:
{
"AppSettings": {
"DbConnection": "Server=(localdb)\\MSSQLLocalDB;Database=Student;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
در کدهای بالا به جای Student می توانید از هر نام پایگاه داده ای دیگری که مدنظرتان است استفاده کنید. برای اینکه به صورت مناسب و ساختارمند بتوانیم از این تنظیمات استفاده کنیم با استفاده از کدهای زیر کلاسی با نام AppSettings برای آن ایجاد کنید:
public class AppSettings
{
public string Secret { get; set; }
public string DbConnection { get; set; }
}
حال باید به سراغ تنظیم سرویس های مربوط به اتصال به پایگاه داده و ارتباط با آن از طریق EF برویم. ما از پایگاه داده ی SQL Server برای این منظور استفاده کردیم.
همچنین باید امکان ارتباط و ارسال درخواست از منابع بیرونی به سرور خود را فعال کنیم. به صورت پیش فرض، فقط امکان ارسال درخواست ها از کامپیتوری که کدهای سرور روی آن درحال اجراست وجود دارد. برای اینکه این محدودیت را برداریم از میان افزاری به نام Cors استفاده می کنیم.
بدین منظور کدهای زیر را به کلاس Startup درون فایل Startup.cs اضافه کنید:
public class Startup
{
private readonly IConfiguration _configuration;
public Startup(IConfiguration configuration)
{
_configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
// configure strongly typed settings objects
var appSettingsSection = _configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
var appSettings = appSettingsSection.Get<AppSettings>();
// configure Dbcontext service
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(appSettings.DbConnection)
);
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(options =>
{
options.AllowAnyHeader();
options.AllowAnyMethod();
options.AllowAnyOrigin();
});
app.UseMvc();
}
}
اکنون با اجرای دستورات زیر در خط فرمان، جداول و پایگاه داده ی مدنظرتان توسط Entity Framework Core ایجاد می شود:
dotnet ef migrations add Init
dotnet ef database update
تا اینجای کار بسیار عالی است. اکنون برای اینکه APIهایی برای ارتباط با دنیای بیرون فراهم کنیم نیاز به ایجاد یک Controller داریم. قبل از ایجاد Controller بهتر است منطق برنامه ی خود یعنی اصل کدهای خود را به صورت یک سرویس جداگانه که قرار است در آینده Controller مدنظر از آن استفاده کند ارائه کنید. برای نمونه سازی از کلاس سرویس با استفاده از قابلیت Dependency Injection ابتدا interface زیر را ایجاد کنید:
public interface IStudentService
{
void FilterAll(string term);
void Sort(string filed, string sortDirection);
PagedResult<Student> GetStudents(int page, int pageSize);
}
حال سرویس StudentService را که را همانند کدهای زیر پیاده سازی کنید:
public class StudentService : IStudentService
{
private IQueryable<Student> _students;
public StudentService(AppDbContext dbContext)
{
_students = dbContext.Students;
}
public void FilterAll(string term)
{
_students = _students.Where(std => std.Name.Contains(term) || std.Family.Contains(term));
}
public void Sort(string filed, string sortDirection)
{
switch (filed)
{
case "name" when sortDirection == "desc":
_students = _students.OrderByDescending(x => x.Name);
break;
case "name" when sortDirection == "asc":
_students = _students.OrderBy(x => x.Name);
break;
case "family" when sortDirection == "desc":
_students = _students.OrderByDescending(x => x.Family);
break;
case "family" when sortDirection == "asc":
_students = _students.OrderBy(x => x.Family);
break;
}
}
public PagedResult<Student> GetStudents(int page, int pageSize)
{
return _students.GetPaged(page, pageSize);
}
}
این سرویس که IStudentService را پیاده سازی می کند سه تابع اصلی دارد. تابع FilterAll با گرفتن عبارت جستجو و با استفاده از قابلیت های Linq، آن عبارت را در تک تک ستون های مدنظر ما در جدول student جستجو می کند و نتیجه را در که از نوع IQueryable است در متغییر students_ قرار می دهد. تابع Sort نیز با گرفتن نام ستون مورد نظر(filed) و همچنین جهت مرتب سازی(صعودی یا نزولی) اقدام مورد نظر را روی students_ انجام می دهد. توجه کنید که تا اینجای کار هیچ درخواستی به پایگاه داده ی واقعی ارسال نشده است و عملا در حال ایجاد درخواست SQL مناسب هستیم. همانطور که اطلاع دارید، درخواست های EF پس از اجرای توابعی نظیر ToList به صورت واقعی اجرا می شوند. تابع بعدی GetStudents است که با اعمال قابلیت paging، داده های واقعی را از دیتابیس واکشی کرده و برمی گرداند.
اکنون کافی است با افزودن کد زیر به تابع ConfigureServices از کلاس Startup امکان نمونه سازی از IStudentService با StudentService با استفاده از قابلیت Dependency Injection را فراهم کنید:
services.AddScoped<IStudentService, StudentService>();
خوب حالا به سراغ پیاده سازی Controller مناسب می رویم. برای این کار از کدهای بسیار ساده ی زیر استفاده کنید. در این Controller عملا فقط با بهره گیری از سرویس StudentService امور درخواستی به سادگی انجام می شود.
[Route("api/[Controller]")]
[ApiController]
public class StudentController : Controller
{
private readonly IStudentService _studentService;
public StudentController(IStudentService studentService)
{
_studentService = studentService;
}
[HttpGet]
public PagedResult<Student> Index(string filed, string term,
int page = 1, int pageSize = 4, string sortDirection = "")
{
if (term != null)
{
_studentService.FilterAll(term);
}
if (filed != null)
{
_studentService.Sort(filed, sortDirection);
}
return _studentService.GetStudents(page, pageSize);
}
}
بسیار عالی… کار تمام است. برای تست این APIها و قابلیت های آن می توانید با کمک آموزش زیر ابزار Swaager را به پروژه ی خود اضافه کنید:
– چگونه Swagger را به پروژه ASP.net Core خود اضافه کنیم؟
خوب حالا باید به پیاده سازی سمت Front End کار با استفاده از Angular 8 و Bootstrap 4 بپردازیم. برای اینکار همانطور که در ابتدای این مقاله ذکر شد به بخش دوم این آموزش از طریق این لینک مراجعه کنید.
امیدوارم این آموزش برای شما مفید باشد. مجددا یادآوری می کنم کدهای این آموزش از طریق این لینک قابل دانلود و استفاده است.
موفق باشید. التماس دعا
salam mamnon az etelate khobeton man taze barname nevici ro shoo kardam ,miche lotfan begid in clas ha bayad dakhel model akhte bashe ya b iron az model