إنشاء المشروع الأول في Web APIs in ASP.NET Core
-
الاول في Web APIs in ASP.NET Core
لنبدأ بانشاء مشروع جديد في Visual Studio 2022 ، (رابط التحميل )
قم بشتغيل Visual Studio 2022 ثم اختر create new project

واستخدم قالب ASP.Net core Web API لإنشاء مشروع ثم اضغط فوق Next

في الشاشة التالية سنعمل على تسمية المشروع MyFirstAPIProject. تذكر تحديد إطار العمل كـ .NET Core والإصدار كـ ASP.NET Core 6.0. لقد أظهرت هذا في الصورة أدناه.


ثم انقر فوق Create وانتظر لبضع ثواني حتى بتم انشاء المشروع
شكل المشروع :

تركيب المشروع:
كما تلاحظ ان المشروع الذي أنشأناه يحتوي على مجلد باسم Controllers، ويحتوي على API باسم WeatherForecast API. يمكن إزالة هذا.
إضافة NuGet packages الضرورية للعمل
سنحتاج في هذا المشروع الى مجموعه من المكتبات الضرورية للعمل وهي:
اسم packages | الوصف |
Microsoft.VisualStudio.Web.CodeGeneration.Design Version(6.0.2) | تساعد في انشاء controllers و Views |
Microsoft.EntityFrameworkCore.Tools –Version(6.0.2) | تساعد هذه الحزمة في إنشاء database contextو model classes من قاعدة البيانات. |
Microsoft.EntityFrameworkCore.SqlServer –Version(6.0.2) | يستخدم Entity Framework Core للعمل مع SQL Server. |
System.IdentityModel.Tokens.Jwt –Version(6.16.0) | يستخدم لإنشاء رمز JWT والتحقق منه وذلك بهدف حماية API . سنتحدث بالتفصيل حول ذلك في الدروس اللاحقة |
Microsoft.AspNetCore.Authentication.JwtBearer–Version(6.0.2) | هذا هو البرنامج الوسيط middleware الذي يمكّن تطبيق ASP.NET Core من تلقي bearer token في request pipeline. |
بعد الإضافة سيكون شكل المشروع كالتالي :

قاعدة البيانات
في دروس ASP.Net Core قمنا بإنشاء قاعدة بيانات خاصة بالطلاب والمواد سنستخدم نفس قاعدة البيانات لتحميل Script الخاص بقاعدة البيانات من هنا
العمل مع connection string
كما تعلمنا في ASP.Net Core تحتوي مشاريع ASP.Net Core على ملف باسم appsettings.json و appsettings.Development.json يستخدم هذا الملف لإضافة connection string

الفرق بين الملفات:
في appsettings.json تستخدم عند عمل release للمشروع ونشره بشكل رسمي
appsettings.Development.json تستخدم اثناء التطوير والاختبار.(يستخدم عادتا مع قاعدة البيانات الخاصة بالاختبار)
للمزيد حول ذلك شاهد الدرس ASP.Net connection string
إضافة connection string الخاصة بنا في هذه الملفات
قم بتعديل الكود الموجود في هذا الملف الى
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings":
"STDCS": "Server=yourservername;Database=yourdatabase;User Id=userId; Password=Password;"
}
لاحظ ان اسم ConnectionStrings هو STDCS وتحتوي على اسم Server و اسم قاعدة البيانات ، اسم المستخدم ، كلمة المرو
تأكد من تغير هذه الخصائص بناء على قاعدة البيانات الخاصة بك
إضافة DbContext (entity classes) الى المشروع
يجب إضافة class ليتم تعريف واعداد الاتصال بقاعدة البيانات من خلاله لذا اضف class باسم STDDbContext ثم اضف الكود التالي الى هذا class:
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System.Data;
namespace MyFirstAPIProject
{
public class STDDbContext : DbContext
{
private readonly IConfiguration _configuration;
private IDbConnection DbConnection { get; }
public STDDbContext(DbContextOptions<STDDbContext> options, IConfiguration configuration)
: base(options)
{
this._configuration = configuration;
DbConnection = new SqlConnection(this._configuration.GetConnectionString("STDCS"));
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(DbConnection.ToString());
}
}
}
}

تسجيل connecting string في ملف Program.cs
في Net 6. طريقة الإضافة مختلفة عن Net 5. حيث تم الاستغناء عن StartUp في Net 6.
لعمل ذلك أضف الكود التالي داخل ملف Program.cs
string connString = builder.Configuration.GetConnectionString("STDCS");
builder.Services.AddDbContext<STDDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
بهذا نكون قد اتممنا اعداد المشروع وتجهيز قاعدة البيانات و entity classes
الان سننتقل الى إضافة API
إضافة CoursesModel
سنعمل الان على إضافة class يحتوي على مكونات(الحقول) الخاصة بالمواد الدراسية
لذا سنبدأ بإنشاء مجلد باسم Models ومن ثم اضف class باسم CoursesModel ثم اضف الكود التالي الى هذا class
using System.ComponentModel.DataAnnotations;
namespace MyFirstAPIProject.Models
{
public class CoursesModel
{
[Key]
public int CoursesId { get; set; }
public string CourseNumber { get; set; }
public string CourseName { get; set; }
public string CourseDescription { get; set; }
public decimal Price { get; set; }
public int Capacity { get; set; }
}
}
لاحظ اننا اضفنا الكود [Key] قبل CoursesId وذلك بهدف تحديد هذا الحقل ك primary key

إضافة Controller
انتقل الى المجلد Controller ثم اختر Add New Controller

ثم اختر الخيار كما في الصورة (سنستخدم DbContext التي أنشأناها سابقا). ثم اختر Add

من الشاشة التالية سنحدد CoursesModel في Model Class ثم اختر STDDbContext كما في الصورة، ثم تأكد من اسم Controller ليكون CourseController ثم انقر فوق Add

- انتظر لبضع ثواني وسيتم بشكل تلقائي انشاء API باستخدام تقنية ASP.NET CORE scaffolding مع الكود الخاص بهذا APIتم انشاء مجموعة من API هي:
- GetCoursesModel() يستخدم HTTP Get لعرض جميع المواد
- GetCoursesModel(int id) يستخدم HTTP Get لعرض كورس بناء على رقم محدد
- PutCoursesModel(int id, CoursesModel coursesModel) يستخدم طريقة HTTP Put
- PostCoursesModel(CoursesModel coursesModel) يستخدم HTTP Post لإنشاء كورس
- DeleteCoursesModel(int id) يستخدم HTTP Delete لحذف كورس يستخدم
وفقًا REST best practice، يتم تعيين كل endpoint ب HTTP methods بناءً على طريقة عملها.الكود التالي هو الكود الخاص ب controller :nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MyFirstAPIProject;
using MyFirstAPIProject.Models;
namespace MyFirstAPIProject.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CourseController : ControllerBase
{
private readonly STDDbContext _context;
public CourseController(STDDbContext context)
{
_context = context;
}
// GET: api/Course
[HttpGet]
public async Task<ActionResult<IEnumerable<CoursesModel>>> GetCoursesModel()
{
return await _context.CoursesModel.ToListAsync();
}
// GET: api/Course/5
[HttpGet("{id}")]
public async Task<ActionResult<CoursesModel>> GetCoursesModel(int id)
{
var coursesModel = await _context.CoursesModel.FindAsync(id);
if (coursesModel == null)
{
return NotFound();
}
return coursesModel;
}
// PUT: api/Course/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
public async Task<IActionResult> PutCoursesModel(int id, CoursesModel coursesModel)
{
if (id != coursesModel.CoursesId)
{
return BadRequest();
}
_context.Entry(coursesModel).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CoursesModelExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Course
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost]
public async Task<ActionResult<CoursesModel>> PostCoursesModel(CoursesModel coursesModel)
{
_context.CoursesModel.Add(coursesModel);
await _context.SaveChangesAsync();
return CreatedAtAction("GetCoursesModel", new { id = coursesModel.CoursesId }, coursesModel);
}
// DELETE: api/Course/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteCoursesModel(int id)
{
var coursesModel = await _context.CoursesModel.FindAsync(id);
if (coursesModel == null)
{
return NotFound();
}
_context.CoursesModel.Remove(coursesModel);
await _context.SaveChangesAsync();
return NoContent();
}
private bool CoursesModelExists(int id)
{
return _context.CoursesModel.Any(e => e.CoursesId == id);
}
}
}
لنقم بتشغيل التطبيق سيكون الشكل كما في الصورة:
لاحظ ان اسم API هو نفس اسم Controller حيث يتم انشاء ذلك بشكل تلقائي. يمكن تغيير الاسم عن طريق تغيير Route .
لتغير API الأول أضف الكود التالي فوق Function
[HttpGet]
[Route("GetAllCourses")]
public async Task<ActionResult<IEnumerable<CoursesModel>>> GetCoursesModel()
{
return await _context.CoursesModel.ToListAsync();
}
لنقم بإعادة تنفيذ المشروع ستكون النتيجة :

سنقوم الان بإجراء بعض التعديلات على API بهدف عرض جميع المواد الموجودة في قاعدة البيانات(سنتعامل مع قواعد البيانات باستخدام ADO.Net ) لذا سنقوم بكتابة بعض الكود لغرض جلب البيانات.
اضف الكود التالي الى API :
#nullable disable
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using MyFirstAPIProject;
using MyFirstAPIProject.Models;
namespace MyFirstAPIProject.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CourseController : ControllerBase
{
private readonly STDDbContext _context;
private readonly IHttpContextAccessor httpContextAccessor;
private readonly IConfiguration configuration;
CoursesModel CusModel = new CoursesModel();
DataTable Dt = new DataTable();
DbConnection connection;
public CourseController(IConfiguration config, IHttpContextAccessor _httpContextAccessor)
{
configuration = config;
httpContextAccessor = _httpContextAccessor;
}
// GET: api/Course
[HttpGet]
[Route("GetAllCourses")]
public async Task<ActionResult<IEnumerable<CoursesModel>>> GetCoursesModel()
{
connection = new SqlConnection(configuration.GetConnectionString("STDCS"));
List<CoursesModel> CoursesModelList = new List<CoursesModel>();
try
{
string sqlQuery ="select CoursesId, CourseNumber, CourseName, CourseDescription, Price, Capacity, CreatedDate from courses";
DbProviderFactory dbFactory = DbProviderFactories.GetFactory(connection);
using (var cmd = dbFactory.CreateCommand())
{
cmd.Connection = connection;
cmd.CommandType = CommandType.Text;
cmd.CommandText = sqlQuery;
using (DbDataAdapter adapter = dbFactory.CreateDataAdapter())
{
adapter.SelectCommand = cmd;
await Task.Run(() => adapter.Fill(Dt));
}
}
foreach (DataRow BDM in Dt.Rows)
{
CoursesModelList.Add(new CoursesModel
{
CoursesId = Convert.ToInt16(BDM["CoursesId"]),
CourseNumber = BDM["CourseNumber"].ToString(),
CourseName = BDM["CourseName"].ToString(),
CourseDescription = Convert.ToString(BDM["CourseDescription"]),
Price = Convert.ToDecimal(BDM["Price"]),
Capacity = Convert.ToInt32(BDM["Capacity"]),
});
}
}
catch (Exception ex)
{
}
finally
{
}
return (CoursesModelList);
//return await _context.CoursesModel.ToListAsync();
}
// GET: api/Course/5
[HttpGet("{id}")]
public async Task<ActionResult<CoursesModel>> GetCoursesModel(int id)
{
var coursesModel = await _context.CoursesModel.FindAsync(id);
if (coursesModel == null)
{
return NotFound();
}
return coursesModel;
}
// PUT: api/Course/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
public async Task<IActionResult> PutCoursesModel(int id, CoursesModel coursesModel)
{
if (id != coursesModel.CoursesId)
{
return BadRequest();
}
_context.Entry(coursesModel).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CoursesModelExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Course
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost]
public async Task<ActionResult<CoursesModel>> PostCoursesModel(CoursesModel coursesModel)
{
_context.CoursesModel.Add(coursesModel);
await _context.SaveChangesAsync();
return CreatedAtAction("GetCoursesModel", new { id = coursesModel.CoursesId }, coursesModel);
}
// DELETE: api/Course/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteCoursesModel(int id)
{
var coursesModel = await _context.CoursesModel.FindAsync(id);
if (coursesModel == null)
{
return NotFound();
}
_context.CoursesModel.Remove(coursesModel);
await _context.SaveChangesAsync();
return NoContent();
}
private bool CoursesModelExists(int id)
{
return _context.CoursesModel.Any(e => e.CoursesId == id);
}
}
}
لنقم بتنفيذ المشروع بالنقر فوق F5 ثم انقر قوق
api/Course/GetAllCourses
ثم اختر Try it Out كما في الصورة

ثم انقر فوق Execute كما في الصورة:

ستكون نتيجة التنفيذ أسفل الشاشة كما في الصورة:

يمكن تنفيذ الAPI عن طريق الرابط :
https://localhost:7081/api/Course/GetAllCourses
ستكون نتيجة التنفيذ :

سنقوم بإنشاء API يعمل على ارجاع البيانات الموجودة في جدول courses في قاعدة البيانات StudentsAcademy
شرح الكود السابق :
فيما يلي شرح بالتفصيل للاكواد التي تم اضافتها سابق
سنبدأ بالكود constructor
private readonly STDDbContext _context;
private readonly IConfiguration configuration;
CoursesModel CusModel = new CoursesModel();
DataTable Dt = new DataTable();
DbConnection connection;
public CourseController(IConfiguration config)
{
configuration = config;
}
قمنا بتعريف constructor خاص بهذا controller حيث تم تمرير parameter التالي:
⦁ IConfiguration config : بهدف الوصول الى concoction string الموجودة في ملف appsettings.json
وقمنا بإضافة متغير من نوع IConfiguration لاستخدامه مع هذه constructor
الكود الخاص ب GetAllCourses
// GET: api/Course
[HttpGet]
[Route("GetAllCourses")]
public async Task<ActionResult<IEnumerable<CoursesModel>>> GetCoursesModel()
{
connection = new SqlConnection(configuration.GetConnectionString("STDCS"));
List<CoursesModel> CoursesModelList = new List<CoursesModel>();
try
{
string sqlQuery ="select CoursesId, CourseNumber, CourseName, CourseDescription, Price, Capacity, CreatedDate from courses";
DbProviderFactory dbFactory = DbProviderFactories.GetFactory(connection);
using (var cmd = dbFactory.CreateCommand())
{
cmd.Connection = connection;
cmd.CommandType = CommandType.Text;
cmd.CommandText = sqlQuery;
using (DbDataAdapter adapter = dbFactory.CreateDataAdapter())
{
adapter.SelectCommand = cmd;
await Task.Run(() => adapter.Fill(Dt));
}
}
foreach (DataRow BDM in Dt.Rows)
{
CoursesModelList.Add(new CoursesModel
{
CoursesId = Convert.ToInt16(BDM["CoursesId"]),
CourseNumber = BDM["CourseNumber"].ToString(),
CourseName = BDM["CourseName"].ToString(),
CourseDescription = Convert.ToString(BDM["CourseDescription"]),
Price = Convert.ToDecimal(BDM["Price"]),
Capacity = Convert.ToInt32(BDM["Capacity"]),
});
}
}
catch (Exception ex)
{
}
finally
{
}
return (CoursesModelList);
//return await _context.CoursesModel.ToListAsync();
}
هنا قمنا بإضافة كود باستخدام ADO.Net لإرجاع البيانات الموجودة في جدول courses وتم تخزين النتيجة في DataTable باسم Dt وتم بعد ذلك ارجاع البيانات في List من نوع CoursesModel وذلك لان نوع API هو :IEnumerable<CoursesModel>
لننتقل الان الى GetAllCourses باستخدام Parameter
أولا سنعمل على تغيير اسم هذا API الى [Route("GetCoursesById")]حيث يعمل هذا API على ارجاع قيمة محددة بناء على رقمها ، سنرسل رقم الكورس لهاذ API وستكون النتيجة بناء على هذا ID
التغيير الوحيد هنا هو إضافة Parameter بقيمة ID الى string sqlQuery لذا اضف الكود التالي داخل هذا API (التغيير الوحيد هنا تم تميزيه باللون الأصفر)
// GET: api/Course/5
[HttpGet]
[Route("GetCoursesById")]
public async Task<ActionResult<IEnumerable<CoursesModel>>> GetCoursesModel(int id)
{
connection = new SqlConnection(configuration.GetConnectionString("STDCS"));
List<CoursesModel> CoursesModelList = new List<CoursesModel>();
try
{
string sqlQuery = "select CoursesId, CourseNumber, CourseName, CourseDescription, Price, Capacity, CreatedDate from courses where CoursesId="+id;
DbProviderFactory dbFactory = DbProviderFactories.GetFactory(connection);
using (var cmd = dbFactory.CreateCommand())
{
cmd.Connection = connection;
cmd.CommandType = CommandType.Text;
cmd.CommandText = sqlQuery;
using (DbDataAdapter adapter = dbFactory.CreateDataAdapter())
{
adapter.SelectCommand = cmd;
await Task.Run(() => adapter.Fill(Dt));
}
}
foreach (DataRow BDM in Dt.Rows)
{
CoursesModelList.Add(new CoursesModel
{
CoursesId = Convert.ToInt16(BDM["CoursesId"]),
CourseNumber = BDM["CourseNumber"].ToString(),
CourseName = BDM["CourseName"].ToString(),
CourseDescription = Convert.ToString(BDM["CourseDescription"]),
Price = Convert.ToDecimal(BDM["Price"]),
Capacity = Convert.ToInt32(BDM["Capacity"]),
});
}
}
catch (Exception ex)
{
}
finally
{
}
return (CoursesModelList);
}
لنقم بتشغيل التطبيق بنفس الطريقة السابقة
لاحظ انه عند التنفيذ تم إضافة textbox لإرسال رقم CourseId كما في الصورة :

او من خلال الرابط
https://localhost:7081/api/Course/GetCoursesById?id=1
ستكون نتيجة التنفيذ

فيما يتعلق ب Delete و Update سنطلب منك محاولة تطبيق ذلك بشكل شخصي حتي نتأكد من فهم الموضوع بشكل جيد
اذا لم تتمكن من ذلك راسلنا وسنقوم بالتواصل معك لشرح الطريقة.
اترك تعليقك