07 ASP - NET Core MVC Notes
07 ASP - NET Core MVC Notes
ASP.Net MVC
وهي اختصار ل Model View Controllerوهي عبارة عن
architectural pattern separates an application into three main components
يعنى من خاللها بتحدد المعمارية بتاعت البروجكت بيقوم بتقسم البروجكت بتاعى الي 3كومبوننت وهما الـ
هو الكالس اللى بيمثل الجدول الموجودة عندى ف الداتا بيز Model
هو صفحة ال اتش تي ام ال او الصفحات اللى بيتعرض فيها االبلكيشن بتاعى View
هو المتحكم في البروجكت كله وبيعمل بروسيسنج Controller
Client , Server
الـ Clientهو الجهاز ال Installedعليه ال prowserزي . google chromeوانا اللى قاعد على الجهاز دا اسمي End User
الـ Serverهو جهاز برضو بيكون امكانياته اكبر شوية وهو الجهاز الـ Deploydeعليه الـ web Applicationف انا لما بخلص عمل
االبلكيشن بتاعى بروح اعمله deployeعلي السيرفر والسيرفر دا يكون له ipيكون متشاف سرو االنترنت .
HTTP , HTTPS
يعنى The Hypertext Transfer Protocol is an application protocol for distributed, collaborative, and
hypermedia information systems.
يعنى القواعد المتابعة للترنسفير بتاع ال htmlيعنى بكل بساطة القواعد المتابعة لنقل صفحات ال htmlمن السيرفر لل clientف انا لما ببعت
requestبيرد عليا السيرفر ب . responseهل دا البروتكول الوحيد الموجود ال فى واحد تانى FTPالبروتكول المتبع لنقل الفايل من ال
clientللسيرفر .عندى واحد تانى اسمه CTPبستخدمه عشان اعمل real time appllicationزي مثال عايز اعمل نوتيفكيشن شاتينج زي
الواتساب ...عندى فيرجن تانيه من ال httpاسمها httpsطب اي الفرق ما بينهم
صفحة ال htmlمش بتيجي لوحدها ف ال responseاللى جاي من السيرفر بيجي معاها ملفات css, jsالحاجات دي اسمها resources
URL
هو اختصار ل Uniform Resource Locatorودا اللى بيحدد اللوكيشن بتاع الـ Resourceيعنى مثال لو عايز اجيب الفيلم اللى اسمه
blackAdamف بروح اكتب www.netfelx.com:80/Movies/GetMovie?id=5&name=BlackAdamوهكذا
---عشان اعمل deployeمعنديش غير 3حلول وهما -1ياما استضافة بدفعلها فلوس -2ياما بشتري سيرفر -3ياما بأجر من داتا سنتر
ومعنديش داتا سنتر ف مصر انما فى فى اوروبا والسعودية واالمارات ..وفي العادى بيكون عندى الماشيين بتاعتنا بتكون خاصة بينا الن بروجكت
ال .netبتكون كبيرة جدا ف بنروح نشتريلها سيرفر .طب ليه ف االمارات بيرفعو على الفيرشوال ماشين (داتا سنتر) عشان مايكرسوفت بتوفر
فيتشر مش موجودة فى انك لو اشتريت ماشين خاصة بيك .اي ماشين بيكون ليها ipوعشان استخدم حاجة مرفوعة ع الماشين دي او السيرفر دا
هكتب ال Ipبس دا مش افضل حاجة النى مش هحفظ ال ipف كان الحل ان يكون لكل بروجكت portمعين ف الريكوست اللى بيروح للسيرفر
Port بيروح سرو البورت دا
ف البورت هو نقطة الكالم بتاعتنا مع االبلكيشن الفالنى .واقدر استخدم اي بورت فوق ال 1221يعنى معايا 1221وهكذا وكمان معايا 02فقط .
ف احنا عشان ننادي على بروجكت معين كنت بكتب ال ipواكتب رقم ال portبس دا قولنا مش افضل حاجة ف الحل اننا نسمي الويب سايت .
Host
دا اللى بنسمي الـ host nameودا تعويضا عن ال ipوال portودا بيكون . uniqeف انا بروح اشتري هوست نيم واشهر االماكن Godaddy
الفرق ما بين .comو .info
بتحدد الكاتيجري بتاعت الويب سايت ف .comخاصة بالحاجات التجارية ام ا .infoخاصة بالمواقع االخبارية
---ف انا ممكن اكتب ال ipبتاع الجهاز الموجود عليه الويب سايت بتاعى في السيرش وهيجبهولي وممكن اكتب الهوست نيم مثال Ip
googleهفتح ال cmdواكتب ping google.comهيجبلي ال ipهاخده كوبي وارمي ف السيرش هيجبلي جوجل وممكن اكتب
google.comهيجبلي جوجل برضو .
ملحوظة URL vs URN
Web Application
والـ Kestrelبيتكون من شوية مراحل (مواسير) فالريكوست بتاعنا بيمر بكذا مرحلة وهما عبارة عن 0مراحل وممكن انا ازود مرحلة ومن
خالله بنحدد المراحل او المرحلة اللى هيمر بيها الريكوست وبعد كدا يكلم االبلكيشن بتاعنا .انما ايام زمان كان الـ IISهو اللى بيهندل الريكوست
ASP.NET MVC
Kestrel
وبيكون عندى ملف اسمه appSettingsودا بيكون عندي منه 1فيرجن واحد لل developmentاللى هو انا والتاني للتيست والتالت
للدبلوي والرابع لل برودكشن وبيكون عندى انا بتاع ال devودا بيكون في ال seetingsاو ال confegrationبتاعت االبلكيشن ومن
ضمنها ال connection stringاللى هي االتصال بالداتا بيز يعنى .
وهنالقي عندنا كالس اسمه programوهو دا ال kestrelهو بروجكت ال consoleوبيكون بداخله فانكشن ال main
;)(app.UseRouting
بتأخد اللينك وتشوفه بيماتش انهى راوت او طريق من الطرق الموجودة عندى في ال endpoint.MapGetودى بتكون داخل
middleWareتانيه اسمها app.UseEndpointsوبكتب فيها الروتنج اللى محتاجه
;)(app.UseRouting
>= app.UseEndpoints(endpoints
{
فهو هنا كدا بقولو لو انا مش كاتب حاجة خالص نفذ الفانكشن دي هيطبع هالوورلدendpoints.MapGet("/", async context => //
{
;)"!await context.Response.WriteAsync("Hello World
;)}
;)}
ولو قولتله كدا يبقا الزم اكتب فوق ف اللينك اسالش حمادهendpoints.MapGet("/hamada", async context => //
>= app.UseEndpoints(endpoints
{
>= endpoints.MapGet("/hamada", async context
{
;)"!await context.Response.WriteAsync("Hello World
;)}
>= endpoints.MapGet("/index", async context
{
;)"!await context.Response.WriteAsync("Hello From Index
;)}
;)}
وكمان عندى فانكشن اسمها mapControllerRouteودى من خاللها بقدر اضيف كنترول وميزود و اي دي مثال لو انا عملت كنترول اسمه
moviesوبداخله methodاسمها getMovieبواسطة ال idف انا بكتب الروت بتاعها كدا بالشكل اللى تحت دا ودى بكتبها داخل ال
>= app.UseEndpoints(endpointsبنفس طريقة ال mapGet
(endpoints.MapControllerRoute
name: "default",
كدا انا بقوله ممكن تبعتلي اي دي او ممكن ال وكذلك ممكن مع االكشن}?pattern: "{controller}/{action}/{id}" //{id
;)
بس هو هنا هيجبلي ايرور عشان خاطر البروجكت دا emptyمحددتش في هل هو mvc,razorPage,WebAPIفبالتالى محتاج اروح اقوله
فوق فى ConfigureServicesانى هستخدم انهى نوعه ودا بيكون حقن انجيكشن بالشكل دا
)public void ConfigureServices(IServiceCollection services
يعني لو مكتبش ف اللينك اسم كنترول يروح على كنترول كديفولت وبعملهcontroller او للـaction للـdefault value وكمان اقدر اديله
بالشكل دا ودا القديم
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}", //"{controller}/{action=Index}/{id?}"
defaults : new { action = "Index" }
);اما الشكل الجديد باجي جنب كلمة اكشن اللى فى الباترن واديله الديفولت بالشكل دا كدا وبمسح ديفولتس دي
endpoints.MapControllerRoute(
name: "default",
pattern: "hamada/{controller=Home}/{action=Index}/{id?}",
);
والكونسترينت موجودة ف اللينك داid دا اقدر احددله النوع بتاعه وعندى شكلين او طريقتين له وافضل طريقة اني اكتب جنب كلمةid وكمان ال
endpoints.MapControllerRoute(
name: "default",
pattern: "hamada/{controller=Home}/{action=Index}/{id:int?}" //id: alpha? [ يعنيstring]//id: bool?
// constraints:new {id = new IntRouteConstraint()}
// defaults : new { action = "Index" }
); https://www.c-sharpcorner.com/blogs/asp-net-core-route-constraints
ومن خاللها اقدر اقوله لما تكتبلي اللينك دا يروح على لينك تاني انا بحددهله بالشكل داRedirectResult وكمان ممكن اخلي يرجعلي
public class MoviesController : Controller
{
public RedirectResult index()
{
RedirectResult Result = new RedirectResult("https://localhost:44302/index");
return Result;
}
}
ف انا كدا بجبره انه يرجع لينك معين بالنسبة للدايركت ريسلت وفى الكونتنت ريسلت بجبره يرجعلي حاجة معينة ودا مش هيكون افضل حاجة ف انا هقوله
IactionResult بتاعه هوpernat والParent او اي حاجة بتورث من الperant بتاعه فهو كدا هيقدر يرجعلي الperant رجع من ال
وكل ActionResultعندي له HelperMethodبتسهل عليا بدل اكريت اوبجكت واكتب كذا خطوة وبيكون بالشكل دا وعندنا اكشن ريسلت كتير
public class MoviesController : Controller
{
)(public IActionResult index
{
;)"return Content("index
}
وعندي فانكشن اسمها redirectToRouteدى من خاللها بقوله لما تكتب ف اللينك كذا روح علي الروت دا
)(public IActionResult hamada
{
;)}"return RedirectToRoute("default", new {controller="Home" , action = "Index
}
دلوقتى هنجرب نخلي يدور فى السيجمنت .لو انا قولتله كدا movies/GetMovie/11كدا انا باعتله ال idفى السيجمنت وهيطبعهولى فى الصفحة
public class MoviesController : Controller
{
)public IActionResult GetMovie(int id
;)"}=> Content($"movie with id : {id
}//type in link to test https://localhost:44302/Movies/GetMovie/11 >>result = movie with id : 11
وكمان ال parameterدا ممكن يأخد مني param3مثال int,stringو emplyeeبالشكل دا (هعمل كالس employeeاالول) .
برجاء الدعاء لعمي Ahmeed Mostafa Page 10
public class employee
{
public int id { get; set; }
public string name { get; set; }
}
View
right click+add+controller..+MVC اللى كنت عامله قبل كدا وادوسcontrollers هروح على فولدر الcontroller لو عايز اضيف
view الـcreate بعد كدا هـ. هتالقي نزل معاكController-Empty
Home واسميhome وهنا هعمل فولدر لكنترولر الviews بيكون له فولدر داخل فولدر الcontroller وكلviews هعمل فولدر اسمه
rightclick on HomeFolder + add+view+razorView + name=Index+unchick on layout + وهضيف جوا الفيو بتاعها
. c#وhtml و ريزوربيدج دي معناها انه ملف اقدر اكتب بداخله Add
هقوله }{@ وهكتب الكود بتاعى داخل البراكيتس لو الكود اكتر من سطر ولو سطر واحد هحط @قبل الكودhtml داخل الC# ولو عايز اكتب
<body>
@DateTime.Now @*single line Code*@
@{ // Multi Line Code
int x = 4;
}
</body>
. وبستخدمها وانا برمط ملفات البوتسترب بالصفحة بتاعتىwwwroot *@~ *@تعود على فولدر
وترن وتروت عليه هتالقي البوتستراب مش شغال والسببhtml وبعد ما تعمل الفيو وتضيف ملف البوتستراب في وتضيف اي حاجة ف صفحة ال
. بالظبطapp.routing فوق الconfigure داخل فانكشن الapp.UseStaticFiles(); .. startup ان الزم تقوله فى ال
وهعملهم فيو بالشكل داabout,contact الفانكشن بتاعت كل زرارHome وبعد كدا هضيف داخل الكنتروالر اللى اسمه
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<link rel="styleSheet" href="~/lib/bootstrap/css/bootstrap.min.css" /> @*~ فولدر على تعودwwwroot *@
<title>Index</title>
</head>
<body>
<nav class="navbar navbar-expand-lg bg-light">
<div class="container-fluid">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="/Home/About">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/Home/Contact">Contact</a>
</li>
</ul>
</div>
</nav>
</body>
</html>
// ودا الفيو الخاص بال ابوت وزيي بالظبط الخاص بالكونتكت
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>About</title>
</head>
<body>
<h1>Welcom to About Container</h1>
</body>
</html>
StartUp ودا ملف ال//
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(); // MVC
//services.AddRazorPages(); // Rezor Page
//services.AddControllers(); // Web API
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
endpoints.MapGet("/index", async context =>
{
await context.Response.WriteAsync("Hello From Index!");
});
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id:int?}"
);
});
}
}
ففي الحالة دي بناخدهم وبنحطهم في ملف واحد طيب بيكون فين داhead , footer , navbar دي مشتركين في الviews طيب كل ملفات ال
razor واختارlayout نكتب في السيرشright click + Add+NewItem+ وبدوسshared اسمهviews بعمل فولدر داخل فولدر ال
فانا كل اللى هعمله هأخد الحاجات اللى بتتكرر واحطها في وداخل كل. عاديlayout ملحوظة ممكن يكون عندى اكتر من.. وادوس اوكLayout
وبس كداLayout = "_Layout"; فيو في بروبرتي عندى فوق اخليها كدا
اللى عندى ففى الحالة دى انا بروح اعمل ملف اسمهviews مكررة فى كل الlayout طيب لو الحظنا هنالقي ان البروبرتي بتاعت ال
واقوله اوك وهفتحهrightclick+add+newitem+search in view start ودا بعمل داخل فولدر الفيوزViewStart
هالقي حططلي البروبرتي بتاعتى الالي اوت ف انا هروح امسح كل البروبرتي الموجودة فى الفيوز وبس كدا
@{ // ViewLayout File
Layout = "_Layout";
}
// _Layout File
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<link rel="styleSheet" href="~/lib/bootstrap/css/bootstrap.min.css" /> @*~ فولدر على تعودwwwroot *@
<title>@ViewBag.Title</tItle>
</head>
<li class="nav-item">
<a class="nav-link" href="/Home/About">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/Home/Contact">Contact</a>
</li>
</ul>
</div>
</nav>
<div>
@RenderBody()
</div>
</body>
</html>
// index View واالبوت والكونتكت فيو زيه بالظبط
@{ ViewBag.Title = "Home"; }
@*Tag Helper*@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers // الزم تعملها امبورت فوق خالص ف بداية الملف تكتب كدا وهتالقي لونهم تحت اتغير
<a asp-controller="Home" asp-action="Index" class="nav-link active">Home</a> //طالما لونهم موف يبقا شغالين
asp-action-id="10" //اسم البراميتر-اكشن-لو االكشن بتاعتى بيأخد براميتر هستخدم اسب
طيب لو انا عامل امبورت فى كل الملفات هالقيني مكرر كتير ودا مش افضل حاجة ف هو سهل عليا ومديني اوبشن احطهم كلهم فى ملف واحد بعمله
rightClickOnViewsFolder+Add+newItem+Search on Import + ok _ هعملviewImports واسميviews داخل فولدر ال
ودا بيكون عبارة عن كالس اليبراري ودا مسئول عن التعامل مع الداتابيز وبيكون بداخلهdata Access Layer اول بروجكت هو الـ.1
Migration الـ.3 او الكالسيس اللى بتتحول لجداول فى الداتابيزModels .2 dbContext .1 حاجات وهما3
برجاء الدعاء لعمي Ahmeed Mostafa Page 14
.2تانى بروجكت هو الـ Bussiness Logic Layerوجواها ب Inplementالبيزنيس بتاعنا وهو عبارة عن كالس اليبراري برضو
وبنستخدم جوا two design pattern
.3تالت بروجكت هو الـ Presentation Layerودي ممكن تكون كذا layerودي ممكن تكون ,webapi mvc project
,mobile ,desktopبمعني لو عندى بروجكت كبير ومطلوب كل الحاجات دي ف بضفهم داخل البرزنتيشن الير .
بعد كدا محتاج اربط ال 3بروجكت دول ببعض الداتا اكسيس بتكلم البيزنيس و البيزنيس بيكلم البرزنتيشن فهأخد ريفرنس من الداتا اكسيس احطه عند
البيزنس وهأخد ريفرنس من البيزنيس احطه عند ال برزينتيشن بالشكل اللى ف الصورة دا .واالركتيتشر دا مش حاجة ثابتة عادى ممكن نزود او نقلل
السبب انى اعمل 3بروجكت عشان لو انا شغال على بروجكت كبير mvc,webAPIبدال ما اكرر اللى هعمله ف mvcاكرره ف api
وعندي ديزاين بتيرن تانى اسمه Onion architectureودا بيكون عبارة عن حلقات او دوائر او حلقة بيكون اسمها domain layerودي بيكون
جواها ال modelsاو الكالسيس اللى هتتحول ل جداول تانى حلقة او تانى layerواسمها repository layerوبيكون جواها dbcontext
والديزاين باتيرن اللى اسمه repositoryودي معناها مخزن او مستودع وبيكون جواها جزء من البيزنيس وتالت حلقة ودي بيكون جواها ال
service layerوبيكون جواها الجزء التانى من البيزنيس ورابع حلقة هي ال . presentation layersوممكن يكون في اكتر من حلقة عادى
هعمل بروجكت جديد المرة دي هختار التمبلت الجاهزة ) ASP.NET Core Wep App (Model-View-Controllerوهسمي Demo.PL
وهي اختصار ل presentation Layerوهنا عندى هيكون بروجكت ال MVCفقط .بعد كدا هضيف new projectوهيكون نوعه Library
وهختار class Libraryوهسمي Demo.DALاختصار ل data access layerهيعملهولي وهمسح ملف الكالس اللى هو عمله دا وانا هعمل
واحد جديد بعدين .تالت حاجة هضيف new projectوهيكون نوعه Libraryوهختار class Libraryوهسمي Demo.BLLاختصار
Bussiness Logic Layerوبرضو همسح ملف الكالس دا ..بعد كدا هربط البروجكتيس دي ببعض هروح على ال BLLوهقف ع
dependanceو right click+addReference+selectDEMO.DALوبعد كدا هروح على ال DEMO.PLوهقف على
dependanceو rightClick+AddRefer+selectOnDEMO.BLLوبس كدا .
ملحوظة :الـ stringفى .net 5الديفولت بتاعه not Requiredاما فى .net 6الديفولت بتاعه Requiredوعشان اخلي Notهعمله ?string
او هحط ال داتا انوتيشن ])" [Required(ErrorMessage ="Name is Requiredودى بتظهر في ال htmlمع الفورم تلقائيا .
}
// in contexts folder add context Class in contexts folder in DAL project
public class CompanyContext : DbContext بعمله بابليك عشان اقدر اشوفه ف بروجكت اللى هيكون في الريبوستري //
{
)protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder
;=> optionsBuilder.UseSqlServer("server=DESKTOP-4EFPBS4\\SQLEXPRESS; database=CompanyMVC
;)";Trusted_Connection=true; MultipleActiveResultSets = true
سيتس ريسلت من اكتر جوا نبعت ممكن بتاعنا الريكوست ان معناها ;// MultipleActiveResultSets = true
.2بعد كدا داخل بروجكت BLLهعمل في الديزاين بتيرن repositoryبالطريقة دي هعمل فولدر اسمه Interfacesوفولدر اسمه
Repositoriesفاللى انا بعمله بروح اعمل انترفيس و ريبو ل اي موديل (كالس|جدول) عندى وهنا هعمل للديبرتمنت فقط واالنترفيس
بيكون شايل السجنيتشر بتاعت 5حاجات 5ميزود وهما
internal interface IDepartmentRepository
{
;)(IEnumerable<Department> GetAll
;)Department Get(int id
;)int Add(Department Department
;)int Update(Department Department
;)int Delete(Department Department
}
وبروح اعمل كالس ديبرتمنت ريبوستري وهخلي يورث من االنترفيس دا وهخلي ي امبلمنت منه بالشكل دا
ملحوظة انا عشان اخلي كالس DepartmentRepositoryيقدر انه يعمل Addفى جدول ال Departmentمحتاج اني اخلي يكلم كالس ال
dbContextالنه المسئول عن التعامل مع الداتا بيز ف انا محتاج اني اكريت اوبجكت من ال dbContextوهكريته داخل كالس ال
DepartmentRepositoryوهخلي برايفت وهخلي ريد اونلي عشان محدش يقدر يعدل عليه وال يشوفه غيره وهعمل كونستراكتور ل
DepartmentRepositoryوهفتح الكونكشن مع الداتا بيز من خالل الكونستراكتور دا بيروح يسأل ال CLRاالول عشان ينشأ االوبجكت النى
وانا بنفذ ال Addمثال محتاج اني افتح كونكشن مع الداتا بيز عشان هيضيف فيها ففى الوقت دا محتاج انى افتح كونكشن معاها عشان كدا انا انشاءت
االوبجكت في الكونستراكتور دا وهروح فى ال startup fileاخلي ي allowال depandency enjectionبالشكل دا
;)(>services.AddDbContext<CompanyContext
عشان اكريت اوبجكت من ال DepartmentRepositoryاالوبجكت دا بيعتمد علي حقن اوبجكت من كالس ال dbContextف انا بعمل
كونستراكتور ومنه بطلب من ال CLRانه يكريتلي اوبجكت من ال DbContextف ال CLRهيروح يكريت االوبجكت ولما يروح هناك هيالقي
كونستراكتور انا عاملهوله بالشكل دا
)public CompanyContext(DbContextOptions<CompanyContext> options):base(options
} {
options ان الكونستراكتور دا بيعتمد على حقن اوبجكت من كالس اسمه DbContextOptionsودي بنبعتها فى حاجة اسمها ف ال CLRهيالقي
بنروح نبعتها فى ال startupبقول لل CLRلما تحتاج تكريت اوبجكت من ال dbContextهتحتاج حاجة اسمها اوبشن ف خدها معاك من ال
startUpفهو هيأخدها ويبعتها لل baseاللى هو ال dbContextكالس االساسي هيبعتها للكونستراكتور بتاعه وهو عنده فانكشن اسمها
// in Db Context OnConfiguringبس كدا ففى الطريقة دى انا بعمل كونفيجرينج عنده هو .
برجاء الدعاء لعمي Ahmeed Mostafa Page 16
public class CompanyContext : DbContext
{
public CompanyContext(DbContextOptions<CompanyContext> options):base(options)
{ }
public DbSet<Department> Departments { get; set; }
}
// in StartUp file
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// دى انا اللى بعملها
services.AddDbContext<CompanyContext>(options =>
{
options.UseSqlServer("server=DESKTOP-4EFPBS4\\SQLEXPRESS; database=CompanyMVC;
Trusted_Connection=true; MultipleActiveResultSets = true;");
});
}
// in DepartmentRepository
internal class DepartmentRepository : IDepartmentRepository
{
private readonly CompanyContext _dbContext;
Session 03
) ف االفضل انى انقله من مكانه دا عشان بعد كدا بعملstartUp file الكونيكشن استرينج مش افضل حاجة انى اضيفه ف الكود بتاعى (الـ
ف السيرفر هنا هيتغير ف كل مرة ف انا مش ف كل مرة هعمل فيها دبلوي...production والtesting على سيرفر الdeploye للبروجكت
. وهضيف فى االستارت اب حاجة بالشكل دا وبس داappsettings.json هروح اغير ف اسم السيرفر اغير ف الكود ف انا هنقله فى ال
"ConnectionStrings": {
"defaultConnection": "server=DESKTOP-4EFPBS4\\SQLEXPRESS; database=CompanyMVC;
Trusted_Connection=true; MultipleActiveResultSets = true;"
wwwroot واحد للملف بتاعى والتانى للملفات المربوطة بالبروجكت الموجودة فىrequest 2 دي بتروح تبعتapp.UseStaticFiles(); -
عندنا وتمشي في الروت دا والروت عندنا موجود فى الـroute انهىmatch وبتشوفه بيـurl دي بتأخد مني الـ app.UseRouting(); -
. app.UseEndpoints ميدل وير اللى اسمها-
PL بقا فهدخل جوا بروجكت الcontroller هحتاج اني اعملهdepartment احنا كنا جهزنا مودل ال.4
تمام كدا وهضيف عنده اتربيوت.. rightClickOnFolderController + add +Controller+MVC Controller-Emptyو
وDepartmentController عشان نقدر نكلمه فاصبح ان العالقة بينIDepartmentRepository من الـ
DepartmentController has a IDepartmentRepository ّ اذاHas a عالقةIDepartmentRepository
انا قولتله يورث من االنترفيس عشان ميكونش حياته واقفة على الريبوزتري الن بعد كدا وانا بعمل تيستنج هعمل ريبوزتري فمش هاجي هنا اغيره
اوبجيكت من الcreate عشان اdepandancy enjiction وهعملهDepartmentController للـconstractor بعد كدا هعمل
تسمح لالنجيكشن بالشكل داAllow اعمل سيرفس هناك عشان تـstartUp وهروح في الIdepartmentRepository
public class DepartmentController : Controller
{
private readonly IDepartmentRepository _DepartmentRepository;
public DepartmentController(IDepartmentRepository DepartmentRepository)
{
_DepartmentRepository = DepartmentRepository;
}
public IActionResult Index()
{
var Departments = _DepartmentRepository.GetAll();
return View(Departments);
}
} // in startUp File
services.AddScoped<IDepartmentRepository, DepartmentRepository>();
بتأخد مني اسم الفيو لو.2 مبتأخدش حاجة ودى بترجعلى الفيو لو هو بنفس اسم االكشن بتاعها.1 overload 4 ليهاView() الفانشكن اللى اسمها
بتأخد منى اسم الفيو والموديل.4 وبترجعلي الداتا بتاعتهDepartments بتأخد مني موديل زي ال.3 هو مش بنفس اسم االكشن
وهختار الجاهز وقوله اوك فقطaddView واختارIndex على اكشنrightClick هدوسDepartmentController للـview بعد كدا هعمل
دي من النوعGetAll ونا عامل الGetAll للمودل بتاعنا وهنا انا بـimport وبعد كدا هحتاج انى احدد نوع الداتا اللى هتكون فى الفيو دا فهعمل
لموديلز بروجكت الـimport @ وهعملmodel IEnumerable<Department>; فهضفها ف اول الصفحة بالشكل داIEnumerable<Department>
@using DEMO.DAL.Models عشان يكون جلوبل على كل البروجكت ومقعدش اكرره في كل الفيوزViewImports_ في ملف الDAL
<thead>
<tr>
<th scope="col">@Html.DisplayNameFor(d => d.Code)</th>
<th scope="col">@Html.DisplayNameFor(d => d.Name)</th>
<th scope="col">@Html.DisplayNameFor(d => d.DateOfCreation)</th>
<th scope="col">Details</th>
<th scope="col">Update</th>
<th scope="col">Delete</th>
</tr>
</thead>
<tbody>
@foreach (var Department in Model)
{
<tr>
<td>@Department.Code</td>
<td>@Department.Name</td>
<td>@Department.DateOfCreation</td>
<td>
<a asp-controller="Department" asp-action="Details" asp-route-
id="@Department.Id" class="btn btn-warning">
<i class="fas fa-eye"></i> Details
</a>
</td>
<td>
<a asp-controller="Department" asp-action="Details" asp-route-
id="@Department.Id" class="btn btn-warning">
<i class="fa-solid fa-pencil"></i> Update
</a>
</td>
<td>
<a asp-controller="Department" asp-action="Details" asp-route-
id="@Department.Id" class="btn btn-warning">
<i class="fa-solid fa-trash"></i> Delete
</a>
</td>
</tr>
عليهBind وهعمله فيو له واحدد بداخله الموديل اللى الفيو بيـDepartmentController هعمله فى الـcreate بعد كدا محتاج اعمل االكشن
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
// [ValidateAntiForgeryToken] // بستخدمه عشان مخليش اي تول خارجية تقدر تعدل ومحدش يقدر يعدل غير من االبلكيشن بتاعى فقط
public IActionResult Create(Department department)
{
if (ModelState.IsValid) // server side Validation [chick validation]
{
_DepartmentRepository.Add(department);
return RedirectToAction(nameof(Index));
}
return View(department);
} // Create View HTML
@model Department
@{
ViewData["Title"] = "Create";
}
<form asp-action="Create">
<div class="mb-3">
<label asp-for="Code" class="form-label"></label>
<input asp-for="Code" class="form-control" placeholder="123">
<span asp-validation-for="Code" class="text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="Name" class="form-label"></label>
<input asp-for="Name" class="form-control" placeholder="HR">
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="DateOfCreation" class="form-label"></label>
<input asp-for="DateOfCreation" class="form-control" placeholder="04/10/2023 03:26 PM">
<span asp-validation-for="DateOfCreation" class="text-danger"></span>
</div>
if (department is null)
return NotFound();
return View(department);
} // Create Details HTML
@model Department
@{
ViewData["Title"] = "Details";
}
<div class="mb-3">
<label asp-for="Code" class="form-label"></label>
<input asp-for="Code" class="form-control" placeholder="123" readonly />
</div>
<div class="mb-3">
<label asp-for="Name" class="form-label"></label>
<input asp-for="Name" class="form-control" placeholder="HR" readonly />
</div>
<div class="mb-3">
<label asp-for="DateOfCreation" class="form-label"></label>
<input asp-for="DateOfCreation" class="form-control" placeholder="04/10/2023 03:26 PM"
readonly />
</div>
عليهBind وهعمله فيو له واحدد بداخله الموديل اللى الفيو بيـDepartmentController هعمله اكشن داخلEdit بعد كدا محتاج اظبط زرار الـ
public IActionResult Edit(int? id)
{
if (id is null)
return BadRequest();
if (department is null)
return NotFound();
return View(department);
}
[HttpPost]
// [ValidateAntiForgeryToken] // بستخدمه عشان مخليش اي تول خارجية تقدر تعدل ومحدش يقدر يعدل غير من االبلكيشن بتاعى فقط
public IActionResult Edit([FromRoute]int id , Department department)
{
if (id != department.Id)
{
ModelState.AddModelError(string.Empty, ex.Message);
}
}
return View(department);
} // Create Edit HTML
@model Department
@{
ViewData["Title"] = "Edit";
}
<div class="mb-3">
<label asp-for="Name" class="form-label"></label>
<input asp-for="Name" class="form-control" placeholder="HR">
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="DateOfCreation" class="form-label"></label>
<input asp-for="DateOfCreation" class="form-control" placeholder="04/10/2023 03:26 PM">
<span asp-validation-for="DateOfCreation" class="text-danger"></span>
</div>
ملحوظة إلختصار الكود لو عندى اكشن شبه االكشن التانى هخلي يروح يريتيرن الفيو بتاع االكشن المتشابه بدل ما اكرر الكود مثل الديتيلز واالديت
public IActionResult Details(int? id , string viewName = "Details" )
{
if (id is null)
return BadRequest();
return View(department);
}
// Edit Action Code
public IActionResult Edit(int? id)
{
if (id is null)
return BadRequest();
if (department is null)
return NotFound();
return View(department);
} هنا هنالقي ان نفس الكود بالظبط ف بدل ما اكرر هقوله ريتيرت اكشن الديتيلز بالشكل دا
if (department is null)
return NotFound();
عليهBind وهعمله فيو له واحدد بداخله الموديل اللى الفيو بيـDepartmentController هعمله اكشن داخلDelet بعد كدا محتاج اظبط زرار الـ
<form asp-action="Delete">
<div asp-validation-summary="All"></div>
<div class="mb-3">
<label asp-for="Code" class="form-label"></label>
<input asp-for="Code" class="form-control" placeholder="123" readonly />
</div>
<div class="mb-3">
<label asp-for="Name" class="form-label"></label>
<input asp-for="Name" class="form-control" placeholder="HR" readonly />
</div>
<div class="mb-3">
<label asp-for="DateOfCreation" class="form-label"></label>
<input asp-for="DateOfCreation" class="form-control" placeholder="04/10/2023 03:26 PM"
readonly />
</div>
wwwroot+lib+ فهفتح فولدرcreate , edit الخاص بـview وهنا هستخدمهم معfrontend Validation بعد كدا هشغل الـ.1
min سكريبت هسيب ال2 هسحبه ف الكود هيضفليjquery.validate.js هسحب ملفjquery-validation+dist+
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
فقطmin وهسحبه ف الكود وهسيب الjquery-validation-unobtrusive وهسحب ملف تانى من الفولدر اللى اسمه
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
بس كدا مش هيكون شغال معايا ليه بقا عشان خاطر انا ضفته ف في االتش تي ام ال بتاعت الكريت مثال فهو بياخد الكود اللى ف الصفحة
االصلي موجودjquery من فوق وملف الbody @ فهو كدا هيضيفه في الRenderBody() دي ويروح يحطه ف فانكشن ال
تحت خالص في الالياوت والملفات دي الزم تكون تحت ملف الجيكويري االصلي عشان يشتغلو ف الحل اي بقا
@section validationScriptSection{
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
} // In _layout file هنضيفه تحت خالص تحت االسكريبتات الموجودة هناك
@await RenderSectionAsync("validationScriptSection", required: false)
. وبس كدا هو كدا هيشتغل معايا ع طول بدون ما اعمل اي حاجة تانيه خالص
Generic repositry
هعمل ملف انترفيس جديد وبكدا هيكون داخل فولدر االنترفيسGeneric محتاجين نحسن الكود بتاعنا ويكون دينامك شوية فهنعدل عليه نخلي
ملفات واحد جينارك والتانى للموظفين والتالت لالقسام بالشكل دا3 بداخله
// IGenericRepository file
public interface IGenericRepository<T> where T : class
{
IEnumerable<T> GetAll();
T Get(int id);
جديدة داخل فولدر الريبو واحد للجينارك والتاني لل ريبو موظفين والتالت للريبو اقسام بالشكل داRepository ملفات3 وهعمل
// GenericRepository file
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private readonly CompanyContext _dbContext;
Session 04
{
// Binding is One Way Binding at MVC :
// ----------------------------------
// 2. ViewBag
// Can't Enforce Type Safety -> Not Requires Casting [Weekly Type]
string VBagMessage = ViewBag.Meessage;
بس الفيوداتا اسرع الن نوعها متحدد من االول. واالستخدام على حسب االستخدام وعلى حسب انا محتاج اي والموضوع بيرجعلي انا فى االخر
request to request هي عبارة عن داتا مؤقتة بستخدمها عشان ابعت معلومة من اكشن ل اكشن تاني او من: TempData .3
Done وهنطبق على مثال عند الكريت وانا راجع لالندكس اقوله اظهرلي مسدج توحي بانهDectionary Object وهي عبارة عن
public IActionResult Create(Employee employee)
{
if (ModelState.IsValid) // server side Validation [chick validation]
{
int count = _employeeRepository.Add(employee);
if(count > 0)
TempData["checkSuccess"] = "Employee is created Successfully";
return RedirectToAction(nameof(Index));
}
return View(employee);
}
Partial View
وبنعمل الـpartial هو جزء من الفيو فلو انا عندي جزء من الفيو بيتكرر فى الكود ف اكتر من فيو ف انا باخد الجزء دا لوحده بحطه في ال
فهنا اناrightClick+add+view+razorView+checkOnPartialView بدوسShared دا فى فولدر الـpartial view
: مثالpartial عندى زراير مكررة فى الموظفين واالقسام ف انا هعملها
</tr>
} // in index Department
@foreach (var Department in Model)
{
<tr>
<td>@Department.Code</td>
<td>@Department.Name</td>
<td>@Department.DateOfCreation</td>
</tr>
}
وكمان عندى اسكريبت الفاليديشن اللى انا بضيفه فى الكريت وااليديت هما عندهم بارشل فيو جاهز ممكن استخدمه وانادي عليه وهطبق دا على اي
حاجة متشابها عندى بالشكل دا
<div class="mb-3">
<label asp-for="Name" class="form-label"></label>
<input asp-for="Name" class="form-control" placeholder="HR">
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="DateOfCreation" class="form-label"></label>
<input asp-for="DateOfCreation" class="form-control" placeholder="04/10/2023 03:26 PM">
<span asp-validation-for="DateOfCreation" class="text-danger"></span>
</div> // in Create Department view
<form asp-action="Create">
Relationship
هعمل ريليشن شيب ما بين الموظفين واالقسام هروح اضيف نافيجشن بروبرتي وان عند الموظفين وميني عند االقسام وبعد كدا هعمل مايجريشن و
عشانSelectlist هعمل ابديت للداتا بيز وبعد كدا هعرضهم في الجدول بتاعى هروح فى البارشل فيو بتاع الكريت وااليديت وهضيف في
اختار منها القسم الفالنى وهروح على الكنترولر بتاع الموظفين هخلي يجبلي االقسام في الليست بتاعتى وبعد كدا هحتاج اظهرهم فى الجدول بتاعى
بعد الحفظ بالشكل دا
// Navigational prop [ONE] in Employee Model
public Department Department { get; set; }
<div class="mb-3">
<label asp-for="Department" class="form-label"></label>
<select class="form-control" asp-for="DepartmentId" asp-items="@departments">
<option value="@null">--- Select Department ---</option>
</select>
</div>
وهناloading واعملهاGetAll بس لحد هنا مش هالقي ظهر معايا اسم القسم في الجدول فانا محتاج اروح في الجينرك ريبو داخل فانكشن
وهستخدم مسكن لحين الحل بعدينInclude وهستخدم فانكشنEgarLoading ف هعملهاemployee في الone االقسام عالقتها
public IEnumerable<T> GetAll()
{
if (typeof(T) == typeof(Employee))
return (IEnumerable <T>) _dbContext.Employees.Include(E => E.Department).ToList();
else
: AddSingletone .1معناها ان انا عايز امنع اي حد يـ createمالتى اوبجكت من كالس يعنى يكريت اوبجكت واحد بس وهنا
االوبجكت هيفضل عايش طول ما اليوزر فاتح االبلكيشن .
: AddScoped .2معناها لما حد يطلب من الـ clrيـ createاوبجكت من كالس هيـ createاالوبجكت وهيفضل موجود في ال
heapفي الميموري طول ما الـ requestشغال ولما الـ requestيخلص االوبجكت دا هيتشال من الميموري .
: AddTransient .3معناها لما حد يطلب من الـ clrيـ createاوبجكت من كالس هيـ createاالوبجكت دا وال life timeبتكون
perاالوبيريشن اول ما نخلص االوبيريشن بتاعتنا االوبجكت دا هيتشال من الـ heapولو احتاجت اوبجكت هيروح يكريت واحد جديد
طيب امتا استخدم اي حاجة فيهم دا بيكون علي حسب الحاجة يعنى لو انا عايز اكريت اوبجكت يفضل شغال طول ما االبلكيشن مفتوح هستخدم
سنجلتون اما لو عايزه per Al Requestهستخدم سكوب اما لو عايزه per Al Operationهستخدم ترانسينت ..وعلي سبيل المثال مثال
هستخدم سنجيلتون لما اجي اعمل كاش ودا هنستخدمه فى ال APIبس متجيش مثال تعملي ال dbContextسنجيلتون الن لما يجي حدد يكريت
منه اوبجكت هيفتح كونيكشن مع الداتا بيز وخالص على كدا فهنا نستخدم سكوب النى محتاج ان يكون الكونيكشن بير الريكوست وفي المعظم احنا
مع البيزنس سيرفس بنخلي كل حاجة عندنا سكوب .
Mapping
في propertyعندى بيكون ليها تمثيل فى الداتا بيز و propertyبيكون ليها تمثيل كـ frontEndف انا محتاج افصل مابينهم اعمل كالس للـ
properyالخاصة بالفرونت وهيكون اسمه EmployeeViewModelوببدأ اخد كل البروبرتي الموجودة عندى ف المودل كوبي واحطها ف
الكالس الجديد وارجع ل كالس المودل ابدء امسح منه الحاجات اللى ملهاش تمثيل عندي ف الداتا بيز او اللى مش بتريندر في الداتا بيز بالشكل دا
// model
public class Employee
{
} ;public int Id { get; set
][Required
])"[MinLength(2 , ErrorMessage = "MinLength is 2
} ;public string Name { get; set
} ;public int? age { get; set
} ;public decimal salary { get; set
} ;public bool isMarred { get; set
} ;public int? DepartmentId { get; set
بعد كدا بروح بروح امسك كل الفيوز و البارشل فيو اللى عندى بخليهم يكلمو الفيو مودل بدل ما كانو بيكلمو االمبلوي على طول بالشكل دا
@model EmployeeViewModel
وبعد كدا بروح على االمبلوي كنترولر بخلي الميزود اللى عندى تكلم االمبلوي فيو مودل وهيظهرلي ايرور ومعنى االيرور دا هو انى محتاج اعمل
mappingبقا ليهم وعندى طريقة الـ manual Mappingودا مش افضل حاجة عشان بعملهم ب ايدي وممكن اعمل explicit casting
بس برضو مش افضل حاجة النه مانويل برضو بس بطريقة شيك شوية والحل االمثل انى استخدم باكيدج جاهزة اسمها auto mapperهروح
انزلها فى بروجكت ال PLمن خالل nugatواسيرش علي AutoMapper.Extensions.Microsoft.DependencyInjection
وانزلها واروح اطلب من ال clrانه يكريتلي اوبجكت بيامبلمنت االنترفيس اللى اسمه Imapperودا بضيفه ف الكونستراكتور بتاع االمبلوي
كنترول بالشكل دا .
بعد كدا هكون محتاج اعمل بروفايل للمابر هعمل فولدر اسمه Mapper profileداخل الـ PLواضيف كالس اسمه EmployeeProfile
واخلي يورث من كالس Profileودا خاص ببكدج اوتومابر وبعد كدا وهضيف جوا الكالس دا فانكشن CreateMapبالشكل دا
وفي حالة ان لو اسم البروبرتي في المودل مختلف عن اسمها فى الفيومودل هحتاج انى ف البروفايل استخدم فانكشن ForMemberبالشكل دا
public class EmployeeProfile : Profile
{
)(public EmployeeProfile
return View(EmpMapped);
}
[HttpGet]
public IActionResult Create()
{
ViewBag.Departments = _departmentRepository.GetAll();
return View();
}
[HttpPost]
// [ValidateAntiForgeryToken]
public IActionResult Create(EmployeeViewModel employeeVM)
{
if (ModelState.IsValid) // server side Validation [chick validation]
{
var MappedEmp = _mapper.Map<EmployeeViewModel, Employee>(employeeVM);
_employeeRepository.Add(MappedEmp);
return RedirectToAction(nameof(Index));
}
return View(employeeVM);
}
public IActionResult Details(int? id, string viewName = "Details")
{
if (id is null)
return BadRequest();
if (employee is null)
return NotFound();
var EmpMapped = _mapper.Map<Employee , EmployeeViewModel>(employee);
return View(viewName, EmpMapped);
}
Search
حاليا اول حاجة هروح اعمل االنبوت بتاع السيرش وبعد كدا هشغله بالشكل داEmployee هنطبق السيرش على الـ
else
employees = _employeeRepository.searchByName(SearchValue);
بعد كدا هروح على الكنترولرز اللى عندى زي االمبلوي وبدل ما اخلى الكونستركتور يكريت اوبجكت من االمبلوي ريبو والديبرت ريبو هخلي يكريت
اوبجكت من كالس اليونت اوف ورك بالشكل دا ودي كل التعديالت على االمبلوي كنترولر
public class EmployeeController : Controller
{
//private readonly IEmployeeRepository _employeeRepository;
//private readonly IDepartmentRepository _departmentRepository;
private readonly IUnitOfWork _unitOfWork;
private readonly IMapper _mapper;
{
//_employeeRepository = employeeRepository;
//_departmentRepository = DepartmentRepository;
_unitOfWork = UnitOfWork;
_mapper = Mapper;
}
else
employees = _unitOfWork.EmployeeRepository.searchByName(SearchValue);
[HttpGet]
public IActionResult Create()
{
ViewBag.Departments = _unitOfWork.DepartmentRepository.GetAll();
return View();
}
[HttpPost]
// [ValidateAntiForgeryToken]
public IActionResult Create(EmployeeViewModel employeeVM)
{
if (ModelState.IsValid) // server side Validation [chick validation]
{
var MappedEmp = _mapper.Map<EmployeeViewModel, Employee>(employeeVM);
_unitOfWork.EmployeeRepository.Add(MappedEmp);
_unitOfWork.Complite();
return RedirectToAction(nameof(Index));
}
return View(employeeVM);
}
public IActionResult Details(int? id, string viewName = "Details")
{
if (employee is null)
return NotFound();
var EmpMapped = _mapper.Map<Employee , EmployeeViewModel>(employee);
return View(viewName, EmpMapped);
}
ModelState.AddModelError(string.Empty, ex.Message);
}
}
return View(employeeVM);
}
في االستارت اب وهمسح بتوع االقسام والموظفين الن خالص مبقتش محتاجهم كداDependancy Injection الـAllow بعد كدا هروح اا
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<CompanyContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("defaultConnection"));
});
طول الفترة اللى فاتت دى احنا مكناش بنقفل الكونيكشن مع الداتا بيز ف محتاجين اننا نقفلها بقا فهروح اخلي االنترفيس بتاع اليونيت اخلي يورث
. UnitOfWork داخل كالسdispose ومن خالله هستخدم فانكشن اسمهاIdisposable من الكالس اللى اسمه
public interface IUnitOfWork : Idisposable ……. // دا التعديل الوحيد في االنترفيس دا وبس كدا
عندى طريقتين للتعامل مع ال filesاول طريقة اني اخزنه فى الداتا بيز بس دا بيحتاج انى وانا بخزنه احوله ل باينري عشان يتخزن ولما استدعي
هحتاج احوله من باينري الى اصله لو كان صورة مثال والطريقة الثانية انى اخزن على السيرفر(الجهاز بتاعى) واسم الفايل اخزنه فى الداتابيز .
فانا هروح على wwwrootواضيف فيها فولدر اسمه filesوابدأ اقسم الفولدر دا الى images,pdfs,..وهكذا و هطبق على الـ images
;)file.CopyTo(fileSave
وبعد كدا هروح على البارشل فيوEmployeViewModelبعد كدا هروح اضيف فيلد يشيل اسم الصور في كالس الموظفين وهظبطه فى ال
بتاع الكريت وهزود انبوت جديد
بعد كدا داخل االمبلوي كنترولر هضيف السطر دا عشان اكول الفانكشن اللى عملتها اول حاجة هضيفه داخل الكريت بالشكل اللى تحت دا
employeeVM.imageName = DocumentSettings.UploadFiles(employeeVM.Image, "images");
To Delete Files
ودي براحتي لو انا عايز امسح الصورة من على السيرفرر لما اجي امسح الموظف فبروح اعمل فانكشن في كالس الدكيومنت سيتنج
public static void DeleteFile(string fileName, string folderName)
{
if (fileName is not null && folderName is not null)
{
string filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot\\Files",
folderName, fileName);
if (File.Exists(filePath))
File.Delete(filePath);
}
if (count > 0)
DocumentSettings.DeleteFile(EmpMapped.imageName, "images");
if (count > 0)
DocumentSettings.DeleteFile(EmpMapped.imageName, "images");
return RedirectToAction(nameof(Index));
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, ex.Message);
}
return View(employeeVM);
} // وهروح على البارشل فيو بتاع الدليت هضيف فى انبوت السم الصورة وهخلي مخفي بالشكل دا
<input asp-for="imageName" type="hidden" />
Asynchronous
await غير متزامن يعنى تعمل االوبريشن بتاعتك بالالريل مع بعض زي الصورة ولو عايز اقول ل فانكشن او عملية تستنا عملية تانية هقولها
. دا المتزامن يعني الزم الفانكشن االولى او العملية االولي تخلص عشان تدخل فى العملية التانية وهكذاSynchronous اما الـ
// 4. In EmployeeController
public class EmployeeController : Controller
{
private readonly IUnitOfWork _unitOfWork;
private readonly IMapper _mapper;
public EmployeeController(IUnitOfWork UnitOfWork, IMapper Mapper)
{
_unitOfWork = UnitOfWork;
_mapper = Mapper;
}
else
employees = _unitOfWork.EmployeeRepository.searchByName(SearchValue);
[HttpGet]
public async Task<IActionResult> Create()
{
ViewBag.Departments = await _unitOfWork.DepartmentRepository.GetAll();
return View();
}
[HttpPost]
public async Task<IActionResult> Create(EmployeeViewModel employeeVM)
{
if (ModelState.IsValid) // server side Validation [chick validation]
{
employeeVM.imageName = await DocumentSettings.UploadFilesAsync(employeeVM.Image,
"images");
var MappedEmp = _mapper.Map<EmployeeViewModel, Employee>(employeeVM);
await _unitOfWork.EmployeeRepository.Add(MappedEmp);
await _unitOfWork.Complite();
return RedirectToAction(nameof(Index));
}
return View(employeeVM);
}
public async Task<IActionResult> Details(int? id, string viewName = "Details")
{
if (id is null)
return BadRequest(); // 400
if (count > 0)
DocumentSettings.DeleteFile(EmpMapped.imageName, "images");
return RedirectToAction(nameof(Index));
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, ex.Message);
}
return View(employeeVM);
}
===========================================
=> Have a Account at Web App يعنى اليوزر يكون له اكونت عندنا فى االبلكيشن
Step 1 - Authentication
- Active Directory عبارة عن سيرفس زي السيكول سيرفر فمن خاللها اقدر احدد ان اللى هيدخل الزم يكون له يوزر زي ابل المحكمة
- External Server "External Login (Facebook, Google and etc..)" الدخول بواسطة حاجة تانيه زي الفيس
- Federated Server (Souq -> Amazon) مثال عندى اكونت على امازون وامازون اشترت سوق فبكدا اقدر ادخل ع سوق
Step 2 - Authorization
=============================================
- Security at ASP.NET Core => Using Microsoft Identity Package باكيدج جاهزة بستخدمها عشان اعمل السكيورتي
2. Update User
3. Delete User
1. Sign In
2. Sign Out
3. IsSigned
4. Reset Password
5. Two Factor Authentication بيتشك عليك مرتين لما بتدخل على االكونت عشان يتحقق منك
6. OTP Authentication دقيقة33 زي التحقق بتاع فودافون كاش بيبعتلك كود صالح لمدة
1. Create Role
2. Update Role
3. Delete Role
public class CompanyContext : IdentityDbContext //هيكون بالشكل دا انا خدت السطر دا بس بدل ما اخد الكود كله وبعد كدا هعمل مايجريشن
#region Login
// هضيف فيها بعدين
#endregion
} // هروح ادور على تمبلت من اللنت وافضل حاجة من اللينك داhttps://colorlib.com/wp/free-bootstrap-registration-forms/
وقفت عند الدقيقة 31:13متبقي اخر 2فيديو +اخر سيشن (من اول ال . )register