eitaa logo
پروژه ASP.Net Core MVC (وب و سی شارپ)
119 دنبال‌کننده
168 عکس
38 ویدیو
376 فایل
❁﷽❁ آموزش 📖 برنامه نویسی ASP.Net Core MVC (وب و سی شارپ) Admin: @alialirezapanahi برنامه نویسی برنامه نویسی سی شارپ eitaa.com/sisharpapp برنامه نویسی وب eitaa.com/aspdatnet ویراستی virasty.com/alialirezapanahi آپارات aparat.com/alialirezapanahi
مشاهده در ایتا
دانلود
Shop & Orders (2).zip
حجم: 24.9M
این دو قطعه کد با هم کار می‌کنن تا وقتی کاربر هیچ محصولی انتخاب نکرده، یک پیام خطا به‌صورت واضح در صفحه نمایش داده بشه. بیایم مرحله‌به‌مرحله و ساده بررسی کنیم که هر کدوم چه کاری انجام می‌دن: --- ## 🧩 بخش اول: کنترلر – اعتبارسنجی انتخاب محصول if (selectedProductIds == null || !selectedProductIds.Any()) { ModelState.AddModelError("", "حداقل یک محصول باید انتخاب شود"); } ### ✅ توضیح: -
selectedProductIds == null
یعنی هیچ لیستی ارسال نشده -
!selectedProductIds.Any()
یعنی لیست خالیه (هیچ محصولی انتخاب نشده) - اگر یکی از این دو شرط برقرار باشه، یعنی کاربر هیچ محصولی انتخاب نکرده ### 🔔 نتیجه: با ModelState.AddModelError("", "...") یک خطا به مدل اضافه می‌شه 🔹 چون کلید خالی (
""
) استفاده شده، این خطا به هیچ فیلد خاصی وصل نیست 🔹 پس باید با
ValidationSummary
نمایش داده بشه --- ## 🧩 بخش دوم: View – نمایش پیام خطا @Html.ValidationSummary(true, "", new { @class = "text-danger" }) ### ✅ توضیح: -
true
یعنی خطاهای غیرفیلدی هم نمایش داده بشن (مثل همین مورد که کلیدش
""
هست) -
""
یعنی هیچ متن اضافی قبل از لیست خطاها نمایش داده نشه -
new { @class = "text-danger" }
یعنی خطاها با رنگ قرمز (کلاس Bootstrap) نمایش داده بشن --- ## 🧠 مثال تصویری در صفحه: اگر کاربر هیچ محصولی انتخاب نکنه، این پیام در بالای فرم نمایش داده می‌شه: ❌ حداقل یک محصول باید انتخاب شود و چون
text-danger
استفاده شده، قرمز دیده می‌شه.
لیستی کامل و دسته‌بندی‌شده از مهم‌ترین کدهای Fluent API در Entity Framework Core برات آماده کردم—با توضیح فارسی کنار هر کد، تا هم راحت یاد بگیری، هم اشتباه نکنی. --- ## 🔷 ۱. تنظیم پراپرتی‌ها (Property Configuration) entity.Property(x => x.Name).IsRequired(); // اجباری بودن فیلد entity.Property(x => x.Name).HasMaxLength(100); // محدودیت طول entity.Property(x => x.Price).HasColumnType("decimal(18,2)"); // نوع دیتابیس entity.Property(x => x.CreatedAt).HasDefaultValueSql("GETDATE()"); // مقدار پیش‌فرض از SQL entity.Property(x => x.IsActive).HasDefaultValue(true); // مقدار پیش‌فرض بولی entity.Property(x => x.Description).IsUnicode(false); // ذخیره به‌صورت غیر یونیکد --- ## 🔷 ۲. تنظیم کلید اصلی و کلید خارجی entity.HasKey(x => x.Id); // کلید اصلی entity.HasAlternateKey(x => x.Code); // کلید جایگزین (Unique) entity.HasIndex(x => x.Email).IsUnique(); // ایندکس یکتا entity.HasIndex(x => new { x.Title, x.AuthorId }).IsUnique(); // ایندکس ترکیبی یکتا --- ## 🔷 ۳. تنظیم رابطه‌ها (Navigation & Relationships) ### 🔹 یک‌به‌چند (One-to-Many) entity.HasMany(x => x.Books) .WithOne(x => x.Author) .HasForeignKey(x => x.AuthorId) .OnDelete(DeleteBehavior.Restrict); // جلوگیری از حذف نویسنده دارای کتاب ### 🔹 یک‌به‌یک (One-to-One) entity.HasOne(x => x.Profile) .WithOne(x => x.User) .HasForeignKey<UserProfile>(x => x.UserId); ### 🔹 چند‌به‌چند (Many-to-Many) entity.HasMany(x => x.Tags) .WithMany(x => x.Posts) .UsingEntity(j => j.ToTable("PostTags")); // جدول واسط --- ## 🔷 ۴. تغییر نام جدول و ستون entity.ToTable("Authors"); // نام جدول entity.Property(x => x.FullName).HasColumnName("AuthorName"); // نام ستون --- ## 🔷 ۵. تنظیم رفتار حذف (Delete Behavior)
.OnDelete(DeleteBehavior.Cascade); // حذف همراه با وابسته‌ها
.OnDelete(DeleteBehavior.Restrict); // جلوگیری از حذف اگر وابسته وجود دارد
.OnDelete(DeleteBehavior.SetNull); // مقدار کلید خارجی null می‌شود
--- ## 🔷 ۶. تنظیم ترتیب و ترتیب بارگذاری entity.HasIndex(x => x.CreatedAt).HasDatabaseName("IX_CreatedAt"); // نام ایندکس entity.HasData(new Author { Id = 1, FullName = "علیرضا" }); // مقدار اولیه (Seed Data) --- ## ✨ جمله یادسپاری: > «Fluent API یعنی کنترل دقیق ساخت جدول‌ها، رابطه‌ها، محدودیت‌ها و رفتارها—با کدهای زنجیره‌ای و قابل فهم.»
بیایم بررسی کنیم که آیا در این خط ساده:
var author = _context.Authors.Find(id);
استفاده از
.AsNoTracking()
لازم هست یا نه. --- ## 🧩 اول بفهمیم
.Find(id)
چی‌کار می‌کنه -
Find(id)
از EF Core استفاده می‌کنه تا رکوردی با کلید اصلی (
Id
) رو پیدا کنه - این متد همیشه با Tracking کار می‌کنه - یعنی EF تغییرات روی
author
رو ردگیری می‌کنه و اگر بعداً
SaveChanges()
بزنی، تغییرات ذخیره می‌شن --- ## ✅ آیا می‌تونی
.AsNoTracking()
بزنی؟ نه ❌ روی
Find(id)
نمی‌تونی
.AsNoTracking()
بزنی چون
Find()
از ردگیری داخلی EF استفاده می‌کنه و اگر قبلاً اون رکورد رو لود کرده باشه، از حافظه خودش برمی‌داره. --- ## 🔧 اگر بخوای نسخه بدون Tracking داشته باشی: باید از
FirstOrDefault()
یا
SingleOrDefault()
استفاده کنی:
var author = _context.Authors
    .AsNoTracking()
    .FirstOrDefault(a => a.Id == id);
✅ این نسخه داده رو بدون ردگیری میاره، مناسب برای نمایش فقط ❌ ولی اگر بخوای داده رو ویرایش کنی، نباید
AsNoTracking()
بزنی --- ## ✨ جمله یادسپاری: > «
Find(id)
همیشه با Tracking کار می‌کنه—اگر فقط می‌خوای نمایش بدی، از
FirstOrDefault
با
AsNoTracking
استفاده کن.» ---
سلام دوستان عزیز 🌱 می‌خواستم یه نکته مهم رو باهاتون در میون بذارم: من تولیدکننده حرفه‌ای محتوا نیستم، فقط یه علاقه‌مند به برنامه‌نویسی‌ام که مثل خیلی از شما، در مسیر یادگیری قدم گذاشته. با توجه به شرایط کاری‌ام، فقط جمعه‌ها فرصت دارم که تمرین کنم و چیزهایی که یاد می‌گیرم رو با شما به اشتراک بذارم. محتواهایی که منتشر می‌کنم ممکنه پایه‌ای یا برای بعضی‌ها تکراری باشه، اما برای من هر بخش کوچکی از کد یه قدم مهمه برای فهم عمیق‌تر. هدفم اینه که با تمرین‌های مداوم، حتی اگر تعداد پروژه‌ها زیاد بشه، مفاهیم رو به‌خوبی درک کنم و ملکه ذهنم بشه. اگر محتواها ساده یا ابتدایی هستن، منو ببخشید 🙏 من استاد نیستم، فقط یه یادگیرنده‌ام—مثل شما. و هر چیزی که یاد می‌گیرم، با عشق و صداقت منتشر می‌کنم.
BookSelect (4).zip
حجم: 24.7M
صفحه‌بندی پیشرفته با Razor و Bootstrap در این ساختار، فقط چند شماره اطراف صفحه فعلی نمایش داده می‌شن، با دکمه‌های «اول»، «قبلی»، «بعدی» و «آخر» برای حرکت سریع. نقطه‌چین‌ها قبل و بعد از صفحات، به کاربر کمک می‌کنن مسیر طولانی رو بهتر درک کنه. ظاهر با کلاس‌های Bootstrap طراحی شده تا هم زیبا باشه، هم واکنش‌گرا.
Shop & Orders (3).zip
حجم: 24.9M
ساده کردن کدهای enum helper ساده‌سازی نمایش Enum در پروژه‌های MVC برای تبدیل مقادیر Enum به متن قابل‌نمایش (مثل فارسی)، می‌تونیم از ویژگی
[Display(Name = "...")]
استفاده کنیم. به‌جای نوشتن کدهای طولانی در کنترلر، با ساخت یک تابع ساده مثل `GetDisplayName()`، هم در کنترلر و هم در View می‌تونیم متن مناسب رو دریافت کنیم. این کار باعث تمیز شدن کد، کاهش تکرار، و افزایش خوانایی پروژه می‌شه.
پروژه ASP.Net Core MVC (وب و سی شارپ)
ویرایش پروژه
بیایم این چهار بخش کد رو مرحله‌به‌مرحله بررسی کنیم تا دقیقاً بدونی چه تفاوت‌هایی دارن و کد درست برای فرم ویرایش چیه: --- ## ✅ 1. لیست ساده با
Select
و آبجکت ناشناس ViewBag.Authors = _context.Authors .Select(a => new { a.Id, a.FullName }) .ToList(); - فقط یه لیست ساده از
Id
و
FullName
می‌سازه - خروجی:
List<object>
- ❌ برای DropDown قابل استفاده نیست چون ساختارش مناسب
asp-items
نیست --- ## ✅ 2. لیست آماده با
SelectList
ViewBag.Authors = new SelectList(_context.Authors.ToList(), "Id", "FullName"); - ساختار مناسب برای DropDown - خروجی:
SelectList
- ✅ در View با
asp-items="ViewBag.Authors"
قابل استفاده - ❌ اگر مقدار انتخاب‌شده رو مشخص نکنی، DropDown خالی می‌مونه --- ## ✅ 3. بررسی وجود کتاب تکراری در فرم ویرایش
bool exists = _context.Books
    .Any(b => b.Title == book.Title && b.AuthorId == book.AuthorId);

if (exists)
{
    ModelState.AddModelError("Title", "این نویسنده قبلاً کتابی با این عنوان دارد.");
}
- بررسی می‌کنه که آیا همین نویسنده قبلاً کتابی با همین عنوان ثبت کرده یا نه - اگر بله، خطا به
ModelState
اضافه می‌شه و فرم دوباره نمایش داده می‌شه - ✅ این بخش کاملاً درسته و برای جلوگیری از داده‌های تکراری استفاده می‌شه ❌ ولی برای افزودن و برای ویرایش مناسب نیست --- ## ✅ 4. ساخت دستی لیست DropDown با
SelectListItem
ViewBag.Authors = _context.Authors .Select(a => new SelectListItem { Value = a.Id.ToString(), Text = a.FullName }) .ToList(); - خروجی:
List<SelectListItem>
- ✅ قابل استفاده در View با
asp-items="ViewBag.Authors"
- می‌تونی برای هر آیتم
Selected = true
بزنی - مناسب برای فرم‌هایی که مقدار انتخاب‌شده رو از قبل داری --- ## 🔍 نتیجه‌گیری کلی: | روش | خروجی | مناسب DropDown | کنترل انتخاب‌شده | |------|--------|----------------|-------------------| | Select با آبجکت ناشناس | List<object> | ❌ | ❌ | | SelectList | SelectList | ✅ | با پارامتر چهارم | | SelectListItem دستی | List<SelectListItem> | ✅ | با
Selected = true
| --- ## ✨ جمله یادسپاری: > «در فرم ویرایش، یا از SelectList با پارامتر چهارم استفاده کن، یا از SelectListItem با شرط Selected—هر دو روش حرفه‌ای هستن.»
[Required(ErrorMessage = "قیمت محصول الزامی است")] [Range(1, 1000000, ErrorMessage = "قیمت باید بین ۱ تا ۱,۰۰۰,۰۰۰ باشد.")] [Column(TypeName = "decimal(18,2)")] [Display(Name = ":قیمت")] public decimal Price { get; set; } بیایم هر کد رو جداگانه بررسی کنیم تا تفاوتشون کاملاً برات روشن بشه: --- 🧮 1. [Column(TypeName = "decimal(18,2)")] این خط مربوط به تنظیم نوع ستون در دیتابیس هست: - decimal(18,2) یعنی: - مجموعاً ۱۸ رقم - ۲ رقم بعد از اعشار - یعنی می‌تونی عددی مثل 1234567890123456.78 ذخیره کنی 📌 این فقط روی ساختار دیتابیس تأثیر داره، نه روی اعتبارسنجی فرم یا محدودیت‌های ورود کاربر. --- ✅ 2. [Range(1, 1000000, ErrorMessage = "...")] این خط مربوط به اعتبارسنجی در فرم و سمت سرور هست: - یعنی کاربر فقط می‌تونه عددی بین ۱ تا ۱,۰۰۰,۰۰۰ وارد کنه - اگر عددی خارج از این بازه وارد بشه، پیام خطا نمایش داده می‌شه 📌 این فقط روی ورودی کاربر تأثیر داره، نه روی نوع ستون در دیتابیس. --- 🧠 نتیجه‌گیری | ویژگی | مربوط به | توضیح | |-------|-----------|--------| | decimal(18,2) | دیتابیس | ظرفیت ذخیره عدد بزرگ با دقت بالا | | Range(1,1000000) | اعتبارسنجی | محدودیت ورود عدد توسط کاربر | 🔹 پس حتی اگر دیتابیس اجازه بده عددی مثل 9999999999999999.99 ذخیره بشه، اعتبارسنجی فرم جلوی ورود عدد بالاتر از 1,000,000 رو می‌گیره.
پروژه ASP.Net Core MVC (وب و سی شارپ)
[Required(ErrorMessage = "قیمت محصول الزامی است")] [Range(1, 1000000, ErrorMessage = "قیمت باید بین
اگر منظورت اینه که در این خط:
csharp
[Column(TypeName = "decimal(18,2)")]
عدد ۱۸ رو به ۸ تغییر بدیم و بشه:
csharp
[Column(TypeName = "decimal(8,2)")]
بله، می‌تونی این کار رو انجام بدی، ولی باید بدونی دقیقاً چه تأثیری داره: --- 🔍 تفاوت decimal(18,2) با decimal(8,2) | نوع | توضیح | |-----|-------| | decimal(18,2) | عددی با حداکثر ۱۸ رقم، که ۲ رقم آن بعد از اعشار است. یعنی تا 9999999999999999.99 قابل ذخیره است. | | decimal(8,2) | عددی با حداکثر ۸ رقم، که ۲ رقم آن بعد از اعشار است. یعنی تا 999999.99 قابل ذخیره است. | 🔹 پس اگر از decimal(8,2) استفاده کنی، بیشترین مقدار قابل ذخیره می‌شه حدود ۹۹۹ هزار تومان 🔹 اگر محصولاتی با قیمت بالاتر داری، ممکنه خطای overflow یا ذخیره ناقص رخ بده --- ✅ پیشنهاد من چون در اعتبارسنجی Range(1, 1000000) استفاده کردی، decimal(8,2) کفایت می‌کنه و با اون بازه هماهنگه. پس بله، می‌تونی با خیال راحت عدد ۱۸ رو به ۸ تغییر بدی تا فضای دیتابیس بهینه‌تر بشه.
مشکل اینجاست که وقتی عدد خیلی بزرگ وارد می‌کنی، قبل از اینکه اعتبارسنجی
[Range]
فرصت بررسی داشته باشه، مدل‌سازی (`Model Binding`) در ASP.NET Core با خطای `OverflowException` متوقف می‌شه**—چون عدد از محدوده‌ی `int` یا `decimal` خارج شده و تبدیل مستقیم شکست می‌خوره. --- ## ✅ راه‌حل قطعی: اعتبارسنجی قبل از تبدیل برای اینکه اعتبارسنجی واقعاً کار کنه و خطای سرریز رخ نده، باید: --- ### 1. **نوع فیلد ورودی را از `int` به `string` تغییر بده در مدل ویو (ViewModel) یا مدل فرم، فیلد عددی را به
string
تبدیل کن تا اول اعتبارسنجی انجام بشه، بعد تبدیل:
[Required]
[RegularExpression(@"^\d{1,7}$", ErrorMessage = "عدد باید بین ۱ تا ۹۹۹۹۹۹۹ باشد.")]
public string QuantityInput { get; set; }
🔹 این یعنی فقط عددهای تا ۷ رقم مجاز هستن 🔹 هیچ تبدیل به
int
انجام نمی‌شه تا زمانی که خودت کنترل کنی --- ### 2. در کنترلر، تبدیل امن انجام بده
if (!ModelState.IsValid)
{
    return View(model); // ✅ نمایش پیام خطا
}

if (!int.TryParse(model.QuantityInput, out int quantity))
{
    ModelState.AddModelError("QuantityInput", "عدد وارد شده معتبر نیست.");
    return View(model);
}

if (quantity < 1 || quantity > 1000000)
{
    ModelState.AddModelError("QuantityInput", "عدد باید بین ۱ تا ۱,۰۰۰,۰۰۰ باشد.");
    return View(model);
}

// ✅ حالا می‌تونی با quantity ادامه بدی
--- ### 3. در View از `Html.ValidationMessageFor` استفاده کن
<div class="form-group">
    <label for="QuantityInput">تعداد</label>
    <input asp-for="QuantityInput" class="form-control" />
    <span asp-validation-for="QuantityInput" class="text-danger"></span>
</div>
--- ## 🎯 نتیجه نهایی - عدد خیلی بزرگ باعث خطای سرریز نمی‌شه چون اول به‌صورت
string
گرفته می‌شه - اعتبارسنجی کامل انجام می‌شه - پیام خطا به‌صورت زیبا نمایش داده می‌شه - هیچ خطای
Unhandled Exception
یا
OverflowException
نمی‌بینی
SmartReports.zip
حجم: 25.3M
پروژه داشبورد گزارش‌گیری و نمودارها