eitaa logo
پروژه ASP.Net Core MVC (وب و سی شارپ)
120 دنبال‌کننده
168 عکس
38 ویدیو
376 فایل
❁﷽❁ آموزش 📖 برنامه نویسی ASP.Net Core MVC (وب و سی شارپ) Admin: @alialirezapanahi برنامه نویسی برنامه نویسی سی شارپ eitaa.com/sisharpapp برنامه نویسی وب eitaa.com/aspdatnet ویراستی virasty.com/alialirezapanahi آپارات aparat.com/alialirezapanahi
مشاهده در ایتا
دانلود
پروژه ASP.Net Core MVC (وب و سی شارپ)
پروژه داشبورد گزارش‌گیری و نمودارها
> پروژه : SmartReports - داشبورد گزارش‌گیری و نمودارها --- ## ✅ لیست کامل پروژه سوم و کارهایی که انجام دادیم ### 1. هدف پروژه ساخت یک داشبورد گزارش‌گیری با تمرکز بر: - سفارش‌ها، مشتریان، محصولات - نمایش نمودارهای آماری با Chart.js - طراحی واکنش‌گرا با Bootstrap - اجرای آفلاین با فایل‌های محلی JS و CSS --- ### 2. ساختار پروژه | بخش | توضیحات | |-----|---------| |
Controllers/ReportsController.cs
| کنترلر اصلی گزارش‌ها شامل اکشن‌های روزانه، مشتریان، محصولات | |
Models/Report/*.cs
| مدل‌های گزارش مثل
DailyOrderReport
,
TopProductReport
,
CustomerActivityReport
| |
Views/Reports/*.cshtml
| ویوهای گزارش‌ها و نمودارها | |
wwwroot/js/
| فایل‌های آفلاین: chart.js,
jquery v3.6.0.js
,
bootstrap v4.6.2.js
| |
wwwroot/css/
| فایل آفلاین: bootstrap-v4.6.2.css | | Layout.cshtml | اضافه کردن فایل‌های آفلاین و ساخت ظاهر حرفه‌ای | | appsettings.json | اتصال به دیتابیس و تنظیمات پروژه | --- ### 3. اکشن‌هایی که نوشتیم #### 🔹
DailyOrders()
- گروه‌بندی سفارش‌ها بر اساس تاریخ - محاسبه تعداد سفارش و مجموع قیمت - استفاده از
Include(o => o.Products)
- اضافه کردن
AsNoTracking()
برای بهینه‌سازی - ارسال داده‌ها به View برای نمایش نمودار #### 🔹
TopProducts()
- نمایش محصولات پرفروش بر اساس تعداد سفارش - ساخت مدل
TopProductReport
- مرتب‌سازی نزولی بر اساس فروش #### 🔹
CustomerActivity()
و
ActiveCustomers()
- نمایش همه مشتریان و مشتریان فعال - محاسبه تعداد سفارش و آخرین تاریخ سفارش - ارسال عنوان پویا با ViewBag.Title --- ### 4. نمودارها با Chart.js - ساخت نمودار ستونی برای سفارش‌ها - رنگ‌بندی سفارشی ستون‌ها - نمایش تعداد سفارش بالای هر ستون با
DataLabels
- حذف مجموع از Tooltip و نمایش فقط مقدار هر ستون - عنوان پویا مثل:
نمودار تعداد سفارش‌ها — مجموع: ۱۰ عدد
--- ### 5. رفع خطاها و بهینه‌سازی‌ها - اضافه کردن
AsNoTracking()
برای جلوگیری از ردیابی اضافی - اصلاح
decimal(8,2)
به
decimal(18,2)
برای جلوگیری از خطای Overflow - بررسی خطای
OverflowException
و تبدیل امن عددهای بزرگ - استفاده از
string
یا
double?
برای ورودی عددی با کنترل دستی - طراحی فوتر با Bootstrap که روی دکمه‌ها نیفته - تنظیم فایل‌های آفلاین برای اجرای بدون اینترنت --- ### 6. فایل‌های آفلاین که استفاده کردی
<!-- CSS -->
<link href="~/css/bootstrap-v4.6.2.css" rel="stylesheet" />

<!-- JS -->
<script src="~/js/jquery v3.6.0.js"></script>
<script src="~/js/bootstrap v4.6.2.js"></script>
<script src="~/js/chart.js"></script>
--- ## 🎯 نتیجه نهایی پروژه سوم - داشبورد گزارش‌گیری کامل و قابل توسعه - نمودارهای حرفه‌ای و قابل شخصی‌سازی - اجرای آفلاین بدون نیاز به CDN - رعایت اصول معماری MVC و بهینه‌سازی EF Core - پایه‌ای برای آموزش تولید محتوا و پروژه‌های واقعی
ترجمه_مقادیر_فنی_به_متن_فارسی_در_سی_شارپ__کالبدشکافی_الگوی_Enum.mp3
زمان: حجم: 5.4M
ترجمه مقادیر فنی به متن فارسی در سی شارپ کالبد شکافی الگوی enum در ASP.Net Core MVC ساخته شده از هوش مصنوعی
پروژه ASP.Net Core MVC (وب و سی شارپ)
ترجمه مقادیر فنی به متن فارسی در سی شارپ کالبد شکافی الگوی enum در ASP.Net Core MVC ساخته شده از هو
بیایم این کد رو کلمه به کلمه و خط به خط بررسی کنیم تا دقیقاً بفهمی چطور enum با DisplayAttribute و EnumHelper ترکیب شده و در کنترلر استفاده شده. --- ✅ بخش اول: تعریف Enum با نام‌های نمایشی
csharp
public enum OrderStatus
{
    [Display(Name = "در انتظار")]
    Pending,

    [Display(Name = "تأیید شده")]
    Confirmed,

    [Display(Name = "ارسال شده")]
    Shipped,

    [Display(Name = "تحویل داده شده")]
    Delivered,

    [Display(Name = "لغو شده")]
    Canceled
}
🔹 enum OrderStatus تعریف یک نوع شمارشی برای وضعیت سفارش‌ها 🔹 [Display(Name = "...")] مشخص کردن نام نمایشی فارسی برای هر مقدار مثلاً OrderStatus.Pending در View به صورت «در انتظار» نمایش داده می‌شه --- ✅ بخش دوم: کلاس کمکی برای گرفتن نام نمایشی
csharp
public static class EnumHelper
{
    public static string GetDisplayName(Enum value)
    {
        var field = value.GetType().GetField(value.ToString());
        var attr = field?.GetCustomAttribute<DisplayAttribute>();
        return attr?.Name ?? value.ToString();
    }
}
🔹 GetDisplayName(Enum value) متدی برای گرفتن نام نمایشی از Enum 🔹 value.GetType().GetField(value.ToString()) دریافت اطلاعات فیلد مربوط به مقدار Enum 🔹 GetCustomAttribute<DisplayAttribute>() بررسی اینکه آیا ویژگی [Display(Name = "...")] وجود دارد یا نه 🔹 attr?.Name ?? value.ToString() اگر DisplayAttribute وجود داشت، مقدار Name را برمی‌گرداند اگر نبود، نام اصلی Enum را برمی‌گرداند (مثلاً Pending) --- ✅ بخش سوم: اکشن Index برای صفحه اصلی فروشگاه
csharp
public IActionResult Index()
{
    var recentOrders = _context.Orders
        .Include(o => o.OrderProducts)
            .ThenInclude(op => op.Product)
        .OrderByDescending(o => o.OrderDate)
        .Take(5)
        .ToList()
        .Select(o => new
        {
            o.Id,
            o.CustomerName,
            o.OrderDate,
            StatusText = EnumHelper.GetDisplayName(Enum.Parse<OrderStatus>(o.Status)),
            ProductCount = o.OrderProducts.Count,
            TotalAmount = o.OrderProducts.Sum(op => op.Product.Price * op.Quantity)
        })
        .ToList();

    var topProducts = _context.Products
        .Where(p => p.IsAvailable)
        .OrderByDescending(p => p.Price)
        .Take(5)
        .ToList();

    ViewBag.RecentOrders = recentOrders;
    ViewBag.TopProducts = topProducts;

    return View();
}
🔹 Include و ThenInclude برای بارگذاری سفارش‌ها و محصولات مرتبط 🔹 OrderByDescending(o => o.OrderDate) مرتب‌سازی سفارش‌ها از جدید به قدیم 🔹 Enum.Parse<OrderStatus>(o.Status) تبدیل رشته‌ی Status به مقدار enum از نوع OrderStatus 🔹 EnumHelper.GetDisplayName(...) گرفتن نام فارسی وضعیت سفارش 🔹 ProductCount و TotalAmount تعداد محصولات و مجموع قیمت سفارش --- ✅ بخش چهارم: اکشن OrderDetails
csharp
public IActionResult OrderDetails(int id)
{
    var order = _context.Orders
        .Include(o => o.OrderProducts)
            .ThenInclude(op => op.Product)
        .FirstOrDefault(o => o.Id == id);

    if (order == null)
        return NotFound();

    var status = OrderStatus.Shipped;
    var displayName = EnumHelper.GetDisplayName(status);
    ViewBag.StatusText = displayName;

    return View(order);
}
🔹 Include و ThenInclude بارگذاری سفارش و محصولات مرتبط 🔹 OrderStatus.Shipped مقدار Enum به‌صورت مستقیم 🔹 EnumHelper.GetDisplayName(status) گرفتن نام فارسی «ارسال شده» --- ✅ بخش پنجم: اکشن ProductDetails
csharp
public IActionResult ProductDetails(int id)
{
    var product = _context.Products.Find(id);

    if (product == null)
        return NotFound();

    return View(product);
}
🔹 Find(id) یافتن محصول با شناسه 🔹 return View(product) ارسال محصول به View برای نمایش جزئیات --- 🎯 نتیجه‌گیری - Enum با DisplayAttribute برای نمایش فارسی وضعیت‌ها استفاده شده - کلاس EnumHelper به‌صورت عمومی قابل استفاده در همه جا هست - در کنترلر، مقدار Enum از دیتابیس تبدیل می‌شه و نام نمایشی گرفته می‌شه - این ساختار هم خوانا، هم قابل توسعه، و هم مناسب برای چندزبانه‌سازیه
بیایم این سه اکشن مهم رو با مثال‌های ساده و توضیح مرحله‌به‌مرحله بررسی کنیم تا دقیقاً بفهمی چه اتفاقی می‌افته و چطور با هم کار می‌کنن. این سه اکشن مربوط به سناریویی هستن که: > کاربر می‌خواد محصولی رو ویرایش کنه، ولی اگر اون محصول در سفارش‌ها استفاده شده باشه و بخواد غیرفعالش کنه، باید اول تأیید کنه که از سفارش‌ها حذف بشه. --- ✅ ۱. اکشن [HttpPost] Edit — ویرایش محصول
csharp
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, Product updatedProduct)
🔹 هدف: ویرایش اطلاعات محصولی که شناسه‌اش id هست با داده‌های جدیدی که از فرم اومده (updatedProduct) --- 🔹 مرحله‌به‌مرحله: 1. پیدا کردن محصول اصلی از دیتابیس
csharp
   var product = _context.Products.Find(id);
   if (product == null)
       return NotFound();
   
2. بررسی تکراری بودن نام محصول
csharp
   bool exists = _context.Products
       .Any(p => p.Name == updatedProduct.Name && p.Id != id);
   if (exists)
       ModelState.AddModelError("Name", "نام محصول تکراری است.");
   
3. بررسی اینکه آیا کاربر می‌خواد محصول فعال رو غیرفعال کنه
csharp
   if (product.IsAvailable && !updatedProduct.IsAvailable)
   {
       var hasOrders = _context.OrderProducts
           .Any(op => op.ProductId == product.Id);
       if (hasOrders)
       {
           TempData["ConfirmDeleteFromOrders"] = true;
           TempData["ProductId"] = product.Id;
           return RedirectToAction("ConfirmProductRemoval");
       }
   }
   
4. اگر همه چیز درست بود، ذخیره تغییرات
csharp
   if (ModelState.IsValid)
   {
       product.Name = updatedProduct.Name;
       product.Price = updatedProduct.Price;
       product.IsAvailable = updatedProduct.IsAvailable;

       _context.SaveChanges();
       TempData["Success"] = "محصول با موفقیت ویرایش شد.";
       return RedirectToAction(nameof(Index));
   }
   
5. اگر خطا وجود داشت، نمایش فرم با خطاها
csharp
   return View(updatedProduct);
   
--- ✅ ۲. اکشن ConfirmProductRemoval — نمایش تأیید حذف از سفارش‌ها
csharp
public IActionResult ConfirmProductRemoval()
🔹 هدف: نمایش صفحه‌ای به کاربر که تأیید کنه آیا می‌خواد محصولی که در سفارش‌ها استفاده شده، حذف بشه یا نه --- 🔹 مرحله‌به‌مرحله: 1. گرفتن شناسه محصول از TempData
csharp
   int productId = (int)TempData["ProductId"];
   
2. پیدا کردن محصول از دیتابیس
csharp
   var product = _context.Products.Find(productId);
   
3. ارسال محصول به View برای نمایش اطلاعات و دکمه تأیید
csharp
   return View(product);
   
--- ✅ ۳. اکشن [HttpPost] RemoveProductFromOrders — حذف محصول از سفارش‌ها
csharp
[HttpPost]
public IActionResult RemoveProductFromOrders(int productId)
🔹 هدف: حذف همه سفارش‌هایی که شامل این محصول هستن، و سپس غیرفعال کردن محصول --- 🔹 مرحله‌به‌مرحله: 1. پیدا کردن همه سفارش‌های مربوط به محصول
csharp
   var orderItems = _context.OrderProducts
       .Where(op => op.ProductId == productId)
       .ToList();
   
2. حذف همه سفارش‌ها از جدول OrderProducts
csharp
   _context.OrderProducts.RemoveRange(orderItems);
   
3. پیدا کردن محصول و غیرفعال کردنش
csharp
   var product = _context.Products.Find(productId);
   product.IsAvailable = false;
   
4. ذخیره تغییرات در دیتابیس
csharp
   _context.SaveChanges();
   
5. نمایش پیام موفقیت و برگشت به صفحه اصلی
csharp
   TempData["Success"] = "محصول از سفارش‌ها حذف شد و غیرفعال گردید";
   return RedirectToAction("Index");
   
--- 🎯 جمع‌بندی تصویری
ویرایش محصول
   ↓
اگر غیرفعال شد و در سفارش‌ها بود
   ↓
نمایش تأییدیه حذف از سفارش‌ها
   ↓
اگر کاربر تأیید کرد
   ↓
حذف سفارش‌ها + غیرفعال کردن محصول
---
بررسی تکراری بودن نام محصول csharp bool exists = _context.Products .Any(p => p.Name == updatedProduct.Name && p.Id != id); if (exists) ModelState.AddModelError("Name", "نام محصول تکراری است."); بذار با مثال ساده و دقیق برات توضیح بدم تا کاملاً جا بیفته: --- ✅ سناریو: بررسی تکراری بودن نام محصول در اکشن ویرایش فرض کن در دیتابیس محصولی داریم با:
plaintext
Id = 1
Name = "گوشی"
حالا کاربر می‌خواد محصولی با Id = 1 رو ویرایش کنه. --- 🔹 حالت اول: کاربر نام محصول رو به "گوشی" تغییر می‌ده ولی محصول دیگری با همین نام وجود دارد
csharp
bool exists = _context.Products
    .Any(p => p.Name == updatedProduct.Name && p.Id != id);
این شرط یعنی: > آیا محصولی با همین نام وجود دارد ولی شناسه‌اش با محصول فعلی فرق دارد؟ ✅ اگر محصول دیگری با نام "گوشی" و Id ≠ 1 وجود داشته باشه، شرط exists == true می‌شه و خطا نمایش داده می‌شه: «نام محصول تکراری است.» --- 🔹 حالت دوم: کاربر فقط قیمت یا وضعیت محصول را تغییر می‌دهد و نام را همان "گوشی" باقی می‌گذارد در این حالت: - updatedProduct.Name == product.Name - و چون Id == id، شرط p.Id != id باعث می‌شه خود محصول فعلی در بررسی تکراری بودن محاسبه نشه ✅ بنابراین شرط exists == false می‌شه ✅ و خطای "نام محصول تکراری است" نمایش داده نمی‌شه --- 🎯 نتیجه‌گیری | وضعیت | آیا خطا نمایش داده می‌شود؟ | |-------|-----------------------------| | تغییر نام به نام محصول دیگری | ✅ بله، چون نام تکراری است و شناسه فرق دارد | | نام محصول تغییر نکرده | ❌ نه، چون خودش است و تکراری محسوب نمی‌شود |
Shop & Orders (4).zip
حجم: 24.9M
حذف @functions و آوردن تابع کمکی در کنترلر order
پروژه ASP.Net Core MVC (وب و سی شارپ)
حذف @functions و آوردن تابع کمکی در کنترلر order
بیایم خیلی خلاصه و دقیق فقط روی تغییرات لازم تمرکز کنیم، نه توضیح تئوری: --- ## ✅ تغییر در @functions - ❌ حذف @functions از View - ✅ تبدیل تابع
GetStatusList()
به تابع
private
در کنترلر - ✅ استفاده از خروجی تابع در ViewBag.StatusList --- ## ✅ تغییر در اکشن
Edit
### در حالت
GET
:
public IActionResult Edit(int id)
{
    var order = _context.Orders
        .Include(o => o.OrderProducts)
        .FirstOrDefault(o => o.Id == id);

    if (order == null)
        return NotFound();

    LoadFormData(); // ✅ آماده‌سازی لیست‌ها

    return View(order);
}
### در حالت
POST
:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, Order updatedOrder, List<int> selectedProductIds)
{
    var order = _context.Orders
        .Include(o => o.OrderProducts)
        .FirstOrDefault(o => o.Id == id);

    if (order == null)
        return NotFound();

    if (ModelState.IsValid)
    {
        // به‌روزرسانی سفارش
        ...
        _context.SaveChanges();
        TempData["Success"] = "سفارش با موفقیت ویرایش شد.";
        return RedirectToAction(nameof(Index));
    }

    LoadFormData(); // ✅ نمایش مجدد فرم با لیست‌ها

    return View(updatedOrder);
}
--- ## ✅ تابع کمکی در کنترلر
private void LoadFormData()
{
    ViewBag.Products = _context.Products
        .Where(p => p.IsAvailable)
        .OrderBy(p => p.Name)
        .ToList();

    ViewBag.StatusList = Enum.GetValues(typeof(OrderStatus))
        .Cast<OrderStatus>()
        .Select(s => new SelectListItem
        {
            Value = s.ToString(),
            Text = s.GetType()
                .GetMember(s.ToString())
                .First()
                .GetCustomAttribute<DisplayAttribute>()?.Name ?? s.ToString()
        }).ToList();
}
--- ## ✅ تغییر در View
<select asp-for="Status" class="form-select" asp-items="ViewBag.StatusList"></select>
--- این تغییرات باعث می‌شن کدت تمیزتر، قابل نگهداری‌تر و حرفه‌ای‌تر باشه.
پروژه ASP.Net Core MVC (وب و سی شارپ)
حذف @functions و آوردن تابع کمکی در کنترلر order
اگه همه منطق‌ها رو در یک کلاس مشترک قرار بدی و هم در اکشن GET و هم در POST صدا بزنی، این کار کاملاً قابل قبول و رایج هست — مخصوصاً در مراحل ابتدایی جداسازی منطق از کنترلر. --- ✅ مزایای کلاس مشترک برای GET و POST - کاهش تکرار کد: مثلاً تابع LoadFormData() یا GetStatusList() فقط یک‌بار نوشته می‌شه - افزایش خوانایی کنترلر: کنترلر فقط صدا می‌زنه، خودش درگیر جزئیات نیست - آمادگی برای جداسازی بیشتر: بعداً می‌تونی همین کلاس رو به سرویس یا لایه‌های CQRS تبدیل کنی - تست‌پذیری بهتر: کلاس جدا راحت‌تر تست می‌شه نسبت به کد داخل کنترلر --- ⚠️ نکته مهم اگر کلاس مشترک خیلی بزرگ بشه و هم منطق خواندن (GET) و هم منطق نوشتن (POST) رو با هم نگه داره، ممکنه: - وابستگی زیاد بین متدها ایجاد بشه - تست‌پذیری سخت‌تر بشه - اصل Single Responsibility نقض بشه --- ✅ راه‌حل حرفه‌ای‌تر در آینده وقتی آماده شدی برای معماری تمیز‌تر، می‌تونی: - کلاس رو به دو بخش تقسیم کنی: - OrderQueryService برای GET - OrderCommandService برای POST یا حتی با CQRS: - EditOrderQueryHandler برای گرفتن اطلاعات - EditOrderCommandHandler برای ذخیره تغییرات --- 🎯 نتیجه الان که در مرحله توسعه هستی، کلاس مشترک کاملاً خوبه و منطقیه. بعداً که پروژه بزرگ‌تر شد، می‌تونی با تقسیم وظایف و CQRS ساختار حرفه‌ای‌تری بسازی.
SmartShopPlus.zip
حجم: 25.3M
ترکیب سه پروژه قبل به یک پروژه + زبان نکته : پروژه در ظاهر اول نگاه کنی ظاهر خوبی ندارد ولی پروژه فقط برای آموزش ساخته شده و اگر کامل نیست خودتون کامل کنید مخصوصا زبان که فقط یک کلمه را ترجمه می کند و کل سایت را خودتون ترجمه و @inject SmartShopPlus.Service.ILanguageService Lang در بالای ویو <h1>@Lang.Translate("Dashboard.Title")</h1> در همه جا قرار دهید و ترجمه کنید