<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های فرشید جهان منش</title>
        <link>https://virgool.io/feed/@Farshideshoun</link>
        <description>یک عدد برنامه نویس دات نت .علاقه مند به تکنولوژی های روز. جوون و پر از انگیزه :) همینا برای شناختم کافی نیست؟!</description>
        <language>fa</language>
        <pubDate>2026-06-16 10:01:38</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/269191/avatar/aFjr9D.jpeg?height=120&amp;width=120</url>
            <title>فرشید جهان منش</title>
            <link>https://virgool.io/@Farshideshoun</link>
        </image>

                    <item>
                <title>ngrok برای دات نت کاران</title>
                <link>https://virgool.io/@Farshideshoun/ngrok-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%AF%D8%A7%D8%AA-%D9%86%D8%AA-%DA%A9%D8%A7%D8%B1%D8%A7%D9%86-ezorrs1ckuks</link>
                <description>سلام. امروز قصد دارم درباره  یک ابزار بنام ngrok صحبت کنم. اول از هر چیز باید بگم که این ابزار چیه؟(این آموزش مخصوص کاربران ویندوزی است)ngrok چیست؟خب، کارایی این ابزار اینه که وب سروری که روی لوکال ما در دسترس هست رو اجازه میده که از بیرون از سیستم ما هم در دسترس باشه. این یعنی اینکه بدون اینکه هاستی تهیه کنیم ، به ساده ترین حالت ممکن ، برنامه خودمون رو می تونیم به دیگران در بستر اینترنت نشون بدیم.خب برای کار با این ابزار اول باید داخل سایتش حساب کاربری ایجاد کنیم. (با این لینک)حالا بعد که حساب کاربری رو ایجاد کردید ، یک توکن بهتون توی صفحش میدهتوکن گفته شدهخب حالا فعلا با توکن کار نداشته باشید و از قسمت مربوط به دانلود ، نسخه ویندوزی این ابزار رو دانلود می کنیم.بعد از  دانلود شدن ، فایل دانلود شده رو باز می کنیم (یک فایل زیپ هست که درونش یک فایل exe قرار گرفته) و دستور زیر رو میزنیم ngrok authtoken YourTokenمشخصا به جای YourToken ، توکن مربوط به خودتون که توی بخش قبلی از سایت گرفتید رو وارد می کنید.خب حالا ویژوال استدیو خودتون رو باز کنید و به بخش  Extensions&gt;manage Extensions برید و اونجا ngrok extension رو نصب  کنید. بعد از نصب ، شما یک بار باید ویژوال استدیو خودتون رو ببندید و  مجددا باز کنید و پس از اون می تونید توی تب tools ، گزینه start ngrok  tunnel رو ببینید . حالا یک کار دگ هم باقی مونده.به بخش tools و قسمت options برید ، به دنبال تنظیمات ngrok بگردید و  مقدار گزینه Executable path رو برابر فایلی که از سایت ngrok دانلود کرده  بودید بدید.حالا بعد از اون روی دکمه ok بزنید و از تب tools گزینه start ngrok tunnel رو انتخاب کنید.توی این بخش ، url هایی رو بهتون نشون میده که تنها نیازه اون هارو با  سایرین share کنید تا بتونن به لینک مقابل اون url ها دسترسی بگیرند.همچنین می تونید تمام ریکوست هایی که به سیستمتون میاد رو هم از طریق این صفحه (http://127.0.0.1:4040) دنبال کنید.موفق باشید https://farshidjahanmanesh.ir/Article/30 </description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Mon, 26 Apr 2021 15:55:22 +0430</pubDate>
            </item>
                    <item>
                <title>چه موقع از Base در Ef Context استفاده کنیم؟</title>
                <link>https://virgool.io/@Farshideshoun/%DA%86%D9%87-%D9%85%D9%88%D9%82%D8%B9-%D8%A7%D8%B2-base-%D8%AF%D8%B1-ef-context-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D9%85-t0rdkgrudxb9</link>
                <description>سلام. چند وقتی بود که به این فکر میکردم که دقیقا توی DbContext ، داخل دو متد OnConfiguring و OnModelCreating ، چه چیز هایی قراره داره که ما عادت کردیم و base.OnModelCreating و base.OnConfiguring  رو صدا میزنیم داخل overrride های خودمون مثل مثال زیر. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
   {
               //some code
               base.OnConfiguring(optionsBuilder);
    }
protected override void OnModelCreating(ModelBuilder modelBuilder)
  {
              //some code
              base.OnModelCreating(modelBuilder);
     }             همیشه هم اینکه چرا داریم اینو مینویسیم برام سوال بود ولی هیچ وقت دنبالش نرفتم. امروز رفتم و سورس Ef Core ، کلاس DbContext رو نگاهی انداختم . (این لینک)تصویر بخش مربوطه رو پایین میزارم براتون.خب همونطور که می بیینید ، این دو تابع ، virtual هستن (به همین دلیل میتونیم اونا رو override کنیم) ولی نکته ای که برام جالب بود این بود که داخل این دو متد به صورت پیشفرض خالیه.خب الان یک سوال بوجود میاد که اگر خالیه ، چرا ما عادت کردیم base رو صدا میزنیم وقتی هیچی توش نیست؟!خب این نکته بخاطر امکان ارثبری کردن چند DbContext از هم دگ هست. بزارید با کد نشونتون بدمخب توی مرحله اول ، یک کلاس که از DbContext ارث میبره ایجاد میکنیم. یک کلاس Person هم ایجاد میکنیم و داخل MainContext میایم و یک تنظیم ساده براش انجام میدیم. چون MainContext بالاترین لول از Context های ما هست ، نیاز به فراخوانی متد خودش در کلاس DbContext نداره پس Base.OnModelCreating رو صدا نمیزنیم.حالا توی مرحله بعد ، دو کلاس دگ ایجاد میکنیم.یک کلاس ChildContext که داره از MainContext ارث میبره و داخلش هم یک تنظیمات برای Book انجام میدیم. در اینجا ، base.OnModelCreating ، داره همین تابع رو در والد خودش یعنی MainContext صدا میزنه و تنظیمات اون رو اعمال میکنه. (حالا اینجا به خودمون بستگی داره که بخوایم این تنظیمات ، قبل از تنظیمات ChildContext قرار بگیره یا بعدش).خب حالا اگر یک شی از ChildContext رو از DI  بگیریم و به پراپرتی Database اون بریم و تابع EnsureCreate رو صدا بزنیم ، میتونیم با بریک پوینت ، نحوه فراخوانی شدن هارو ببینیم. اگرم بخوایم از migration استفاده کنیم و ببینیم چی برامون تولید میکنه ، میتونیم از کامند زیر استفاده کنیم.add-migration init -context childContext    خب بعد add-migration  که نام اون migration رو دادیم . بعدشم مشخص میکنیم براش که از چه context ای استفاده کنه.خب می بینید که نتیجه همون چیزیه که مطلوب ماست. پس بطور کلی وقتی قراره یک Context توی برنامه خودمون داشته باشیم ، صدا زدن Base برای متد های OnConfiguring و OnModelCreating سودی به ما نمیرسونه.موفق باشید:) https://farshidjahanmanesh.ir/Article/23 </description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Wed, 31 Mar 2021 14:23:08 +0430</pubDate>
            </item>
                    <item>
                <title>Split Query چیست ؟</title>
                <link>https://virgool.io/@Farshideshoun/split-query-%DA%86%DB%8C%D8%B3%D8%AA-iyupc8mimppa</link>
                <description>خب سلام.وقتی ما از Eager Loading (همون include و thenInclude ) در Ef Core استفاده می کنیم با یک مشکلی تحت عنوان cartesian explosion مواجه می شیم. این موضوع مربوط به اینه که وقتی ما join میزنیم ، دیتاهای تکراری زیادی برای هر join زدن میگیریم. اکثر مواقع این دیتا های تکراری بخوبی مدیریت میشن ولی بعضی وقتا تعدادشون خیلی زیاد میشه و از نظر پرفورمنسی بهمون صدمه میزنن.یک راه حل برای حل این مشکل اینه که کوئری که قصد داریم بزنیم رو به چند کوئری بشکونیم (زمانی که داریم کوئری رو میفرستیم سمت دیتابیس) و موقع برگشتن دیتا ، نتایج رو به هم متصل کنیم . توی ورژن 5ام از Ef Core یک تابع با نام AsSplitQuery اومد تا این کارو برای ما انجام بده.نحوه استفاده کردن ازش در بالا اومده.خب حالا یک تصویر نشون میدم و بعدش دربارش صحبت می کنیم.خب توی بخش اولی ، ما به صورت عادی نوشتیم includeمون رو. نتیجه ای که بهمون برمیگردونه رو هم توی بخش 1 می بیینیم. دور دیتاهای تکراری با رنگ قرمز خط کشیده شده . مشخصا الان تعداد این دیتا های تکراری کمه ولی اگر join های بیشتری و تودرتو داشته باشیم ، این تعداد زیاد میشه و میتونه باعث بروز مشکل برای ما بشهخب حالا بخش پایینی رو نگاه کنید یعنی بخش 2. توی این بخش از AsSplitQuery استفاده شده. خب همون طوری که می بینید این متد باعث میشه که 2 تا کوئری ایجاد بشه برای درخواست ما (تعدادش اینجا 2 تاس ن بصورت کلی 2 تا و ممکنه بیشترم باشه). نتایجی هم که برمیگردونه بصورت جدا از هم هستند و Ef Core این نتایج رو با هم ترکیب میکنه. دو نکته برای استفاده از AsSplitQuery وجود داره.دیتا ممکنه بین کوئری اول و کوئری دوم تغییر کنه . تعداد ریکوست های ما زیادتر میشهموفق باشید.:)</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Wed, 31 Mar 2021 01:13:07 +0430</pubDate>
            </item>
                    <item>
                <title>Cartesian Explosion در EF Core چیست؟</title>
                <link>https://virgool.io/@Farshideshoun/cartesian-explosion-%D8%AF%D8%B1-ef-core-%DA%86%DB%8C%D8%B3%D8%AA-vgqylk6o7hla</link>
                <description>Ef Core یک ORM هست که اومده تا برنامه نویسی رو برای ما ساده تر کنه. الان میخوایم درباره Cartesian Explosion صحبت کنیم.اصلا اینی که نوشتم چیه؟!Cartesian Explosion مرتبط با join زدن های ماست. وقتی ما یک عملیات join انجام میدیم ، ستون های یکی از جداول ما به تعداد X بار توی joined table تکرار میشن.var customers = context.customers
.include(a =&gt; a.address)
.ToList();به طور مثال کد بالا رو در نظر بگیرید . روی جدول customer ها ، اومدیم include زدیم تا آدرس ها رو بدست بیاریم (وقتی include میزنیم در اصل داریم از left join استفاده می کنیم).خب ، کوئری که توسط Ef برای ما تولید میشه رو در زیر میتونید ببینید.Select * From Customers
 Left Join Address 
 on Address.Id = Customers.AddressIdخب همون طوری که میبینید ، ستون های جدول customer ، 500 بار تکرار شدن .(الان ستون خاصی نداره و فقط کلیدش هست). خب حالا فکر کنید که دارید با یک مجموعه داده پیچیده کار میکنید و چندین include هم دارین می زنین. وضعیت وحشتناکی پیش میاد. مگ نه؟! این وضعیت وحشت ناک رو cartesian explosion میگن.یه راه حل دم دستی برای این قضیه اینه که بیاید customer رو جدا لود کنید ، بعد address هارو هم جدا لود کنید و بر اساس قابلیت Fix-Up در Ef Core ، ارتباط بین دیتا ها به درستی ست میشه.ولی توی Ef Core 5 ، یک قابلیت جدید اومد تحت عنوان split queries که می تونید دربارش توی این لینک (مقاله خودم) بخونید.موفق باشید.</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Wed, 31 Mar 2021 01:11:51 +0430</pubDate>
            </item>
                    <item>
                <title>Progress Reporting در c#</title>
                <link>https://virgool.io/@Farshideshoun/progress-reporting-%D8%AF%D8%B1-c-hewbagxtmiof</link>
                <description>سلام.گاهی ما نیاز داریم که وقتی یک عملیات async انجام میدیم ، در حین اون عملیات ، یک سری گزارش ها از اون عملیات دریافت کنیم. یک راه ساده برای این منظور اینه که یک &lt;Action&lt;T پاس بدیم به اون تابع Async خودمون که اون ، هر موقع که نیاز بود (یعنی هر موقع قرار بود گزارشی ثبت بشه) ، از این تابع استفاده کنه.خب یک پروژه کنسولی ایجاد میکنم.یک کلاس داخلش ایجاد میکنم با نام report و دو تابع داخلش قرار میدم. یک تابع با نام DoTask و یک تابع با نام ReportSomeWork.قراره توی تابع reportSomeWork بیایم و درصد اعداد بین صفر تا هزار رو نشون بدیم. کلا به شکل زیر میشهخب داخل تابع DoTask اول میایم و آیدی تردی که داره این تابع رو انجام میده چاپ میکنیم. بعدش  یک اکشن ایجاد میکنیم با نام progress که ورودیش یک عدد int هست (متغیر i) و داخلش ، در مرحله اول میایم و id ترد ای که داره اون رو اجرا میکنه رو چاپ  میکنیم (بعدا میگم چرا) و بعدشم متغیر i رو پرینت میکنیم. حالا در ادامه تابع ReportSomeWork رو صدا میزنیم و اون اکشنی که ساختیم رو بهش پاس میدیم و await میکنیم . داخل تابع ReportSomeWork ، یک task ایجاد میکنیم و اون قراره برای ما یک عملیاتی رو انجام بده. از عدد صفر تا 1000 جلو میره و هر جا که بر 10 بخش پذیر بود ، عدد تقسیم بر ده رو به اکشنمون پاس میده . و بعدشم دوباره ایدی تردی که داره این task رو اجرا میکنه رو چاپ میکنیم (یکم جلوتر علتشو میگم).خب حالا یک شی از این کلاس داخل متد main می سازیم و تابع DoTask رو فراخوانی می کنیم و روش wait میکنیم. حالا اگر پروژه رو اجرا کنیم ، میتونیم خروجی رو ببینیم.خب ایدی تردی که داره شروع به اجرای متد DoTask میکنه ، 1 هست.وقتی اکشن ما اجرا میشه ، تردی که اون رو اجرا میکنه آیدیش 4 هست. دقیقا همین ترد هم هست که داره اون عملیات حلقه for رو انجام میده . یعنی میخوام بگم اون worker thread ای که داخل تابع ReportSomeWork و توسط Task.Run اجرا میشه (task.run ترد ایجاد نمیکنه بلکه از ترد پول یک ترد میگیره)،همون تردی هست که اکشن رو انجام میده. خب این موضوع توی Console App مشکلی نداره (بدیلس عدم وجود ui thread)ولی وقتی میریم مثلا سراغ Windows Form مشکلش مشخص میشه.خب یک پروژه ویندوز فرمی ایجاد میکنیم. توی فرم دیفالت یک لیبل قرار میدیم.دو تابعی که قبلا نوشته بودیم رو داخل این فرم کپی میکنیم (البته با یک تغییر کوچیک)تنها تغییری که دادیم اینه که داخل task.run یک try catch گذاشتیم تا اگر اروری رخ داد ، اون رو catch کنیم.خب توی form1_load هم تابع خودمون رو صدا میزنیم.خب حالا اگر پروژه رو اجرا کنیم و توی Catch ، یک بریک پوینت بزاریم ، اکسپشن رو میبینیممتن خطا رو پایین میزارم.Cross-thread operation not valid: Control &#x27;label1&#x27; accessed from a thread other than the thread it was created onحالا ماجرا چیه؟ بطور کلی element ها و control ها توی پروژه هایی مثل win form ، WPF ، UWP و ... فقط توسط تردی که اونها رو ایجاد کرده قابل دسترس هستند (UI Thread) نه بقیه ترد ها. این مشکلیه که توی console بهش برنخوردیم ولی اینجا می بینیم که ایراد میگیره بهمون.حالا راهکارش چیه؟یک راهکار ابتداییش اینه که از متد Invoke استفاده کنیم. خب یکم کد رو تغییر میدم. به این تکنیک marshal میگن.(البته راه درست تر اینه که از synchronization context استفاده کنیم ولی خب الان محل بحث ما خیلی نیست و مقالات زیادی دربارش وجود داره توی سطح نت (فارسی رو نمیدونم!))خب دو قسمتی که تغییراتی داخلشون اعمال کردم رو نشون دادم. متد invoke یک دلیگیت میگیره و اون رو میره سر Ui Thread اجرا میکنه.برای اینکه کارمون مشخص تر باشه ، یک thread.sleep هم زدم.خب حالا اگر پروژه رو ران کنیم میبینیم که به درستی داره اعداد رو نمایش میده.خب الان یک بحثی اینجا هست. کدی که ما تا اینجا نوشتیم رو میشه راحت توی پروژه هایی از نوع های دگ هم استفاده کرد؟! جوابش رو دیدیم. کد برای اجرا توی نسخه winform نسبت به console ، نیاز به تغییرات داشت. حالا این بسط پیدا میکنه بین بقیه پروژه ها هم (حالا ممکنه فقط تغییر در حد دو سه خط کد باشه (البته مگه کل این کد چند خطه!)).خب قطعا راه حل بهتریم هست. CLR دو تا type برای حل این مشکل ارائه میکنه. یک اینترفیس بنام IProgress  و یک کلاس هم که این اینترفیس رو پیاده سازی کرده با نام Progress که هر دو هم جنریک هستن. سورس کد هر دو رو میزارم اگر کسی دوست داشت مطالعه کنه. (Progress و IProgress)کد رو به سبک زیر تغییر میدیم.حالا پروژه رو اجرا میکنیم و میبینیم که بازم به درستی اجرا میشه. IProgress یک تابع داره با نام Report که یک شی از ما میگیره و اون رو میده به دلیگیتی که براش تعریف کردیم و اون دلیگیت رو سر ui thread بر اساس synchronization context اجرا میکنه. این کلاس  capture میکنه synchronization context رو اگر وجود داشته باشه. (عکس زیر از سورس کد کلاس اومده که لینکش یکم بالا تر هست)تا یادم نرفته بگم کلاس progress یک event ای هم داره با نام ProgressChanged که هر وقت تغییری اتفاق افتاد ، این رویداد فراخوانی میشه.امیدوارم خوشتون اومده باشه. سورسش رو میتونید از طریق این لینک ببینید.موفق باشید</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Sun, 28 Mar 2021 13:25:43 +0430</pubDate>
            </item>
                    <item>
                <title>Razor Class Library چیست؟</title>
                <link>https://virgool.io/dotnetzoom/razor-class-library-%DA%86%DB%8C%D8%B3%D8%AA-tpquj8cv0xjo</link>
                <description>خب سلام. امروز می خوایم یکم درباره razor class library ها صحبت کنیم.razor class library اصلا چیه؟یک library برای asp.net core هست که می تونه شامل pages(razor pages) ، Views ، viewComponents ،controllers و ... بشه. (یک نکته ای که وجود داره اینه که library ها بصورت مستقل اجرا نمیشن (یک فایل dll بهمون میدن و dll اجرایی نیست) بلکه باید داخل یک برنامه دگ استفاده بشن).کلا RCL (razor class library) کار ما رو برای استفاده مجدد از کدهامون ساده میکنه. نکته جالبی که دربارش وجود داره اینه که برنامه ای که داره از یک RCL استفاده میکنه ، این امکان رو داره که view ها (وقتی که بر اساس mvc نوشته شده) و pages ها (وقتی که بر اساس razor pages نوشته شده) رو override کنه. وقتی که یک view یا یک razor page هم در برنامه ما و هم در RCL موجود باشه ، از اون نسخه ای که در برنامه ما هست استفاده میشه .ایجاد پروژه Razor Class Libraryخب برای ایجاد یک پروژه razor class library توی ویژوال استدیو ، مطابق شکل های زیر عمل می کنیم.(RCL توی Asp.net core 2.1 اومد و قاعدتا توی نسخه های قبلی نمیشه ازش استفاده کرد)خب ، نوع پروژه رو razor class library انتخاب میکنیم. بعدش نام پروژه و نام solution رو ست میکنیم و میریم برای مرحله بعد.خب حالا به تصویر پایین نگاه کنید.توی قسمت 1 که نوشتم که مشخصه و ورژن دات نت رو انتخاب می کنیم. ولی اون تیک قسمت 2 رو بنا به نیاز میتونیم بزنیم یا نزنیم.حالا ماجرای این تیک چیه؟ بصورت پیشفرض RCL از razor pages پشتیبانی میکنه. اگر بخواید از views (MVC) هم استفاده کنید ، باید این تیک رو بزنید (هر دو فعال میشن یعنی هم میتونید razor pages استفاده کنید و هم mvc).خب ، بعد از create زدن ، یک پروژه ای مثل شکل زیر برای ما ایجاد میکنه.خب چون من میخوام از MVC استفاده کنم ، پاک میکنم پوشه Areas رو.خب در ابتدا یک پوشه با نام Controllers و یک پوشه با نام views ایجاد میکنم. همینطور برای Assets های مورد استفادم هم پوشه ای با نام  wwwroot ایجاد میکنم.داخل پوشه کنترلر ها ، یک کنترلر با نام sample ایجاد میکنم و view مربوط به اکشن index این کنترلر رو هم در پوشه views ایجاد میکنم. ساختار تا اینجای کار ، همچین حالتی دارهو کنترلر Sample هم به این فرم هست.و view مربوط به اکشن index هم بدین فرمهخب حالا فرض کنید تا همینجا کافیه. بریم از این RCL ای که ساختیم استفاده کنیم.توی همین سلوشن ، یک پروژه Asp.net Core ای ایجاد می کنم با نام DemoRCL.Web.حالا روی Dependecies پروژه ایجاد شدم کلیک راست میکنم و Add projects references رو میزنم و رفرنس میدم به DemoRCL (یعنی همون Razor class library که ایجادش کردیم).حالا پروژه وبی ایجاد شده رو set as startup میکنم (روی پروژه کلیک راست کنید ، گزینه ای با همین نام وجود داره).پروژه رو ران میکنم. با صفحه زیر مواجه میشیم.توی قسمت URL میام و /sample/indexرو وارد میکنم (بر اساس default route خود mvc).نتیجه در تصویر پایین اومده.ریکوست هدایت شده به اون کنترلر و اکشن داخل RCL و View هم ، همونی هست که خودمون نوشتیم. نکته ای که وجود داره این هست که از layout خود پروژه وب من استفاده کرده (توی RCL من براش layout ست نکردم و علت این مورد همینه)اگر الان ما بریم توی پوشه Views مربوط به RCL و یک پوشه به اسم shared بسازیم و layout براش ایجاد کنیم ، باز هم از این layout استفاده نمیشه . توی اوایل همین مقاله بود که گفتم که اگر دو چیز هم نام ،توی RCL و پروژه وب ما وجود داشته باشه ، میاد و نسخه ای که توی پروژه وب ما هست رو استفاده میکنه.خب الان من بجای استفاده از اسم مرسوم Layout_، از LayoutRCL_ استفاده میکنم.و view مربوط به index رو هم بصورت زیر تغییر میدم.حالا پروژه رو ران میکنم و میرم به/sample/indexو میبینیم که تغییر در layout اعمال شدبزارید یک مثال دگ درباره همین قضیه override شدن view ها و page ها بزنم.خب توی RCL توی پوشه views ، ما یک پوشه به اسم sample داریم که یک فایل index.cshtml توشه و از این استفاده داریم میکنیم توی RCL.حالا من میام دقیقا یک پوشه با همین نام و یک فایل با همین نام داخل پوشه views ولی در پروژه وبی خودم ایجاد میکنم.و داخلش هم یک متن ساده مینویسم (متن : این پیغام از سمت پروژه وب است).حالا وقتی برنامه رو ران میکنم و میرم سراغ /sample/indexاین دفعه دگ از View داخل RCL استفاده نمیکنه بلکه میاد و از view داخل خود پروژه وبی ما استفاده میکنه.خب این فولدر sample که ایجاد کردم رو پاک میکنم .خب حالا میخوام Dependency Injection رو نشون بدم. اینجا هم فرقی نداره . یک پوشه Models توی RCL ایجاد میکنم. توش یک کلاس تحت نام UserDataOptions ایجاد میکنم. (قصد دارم از option pattern استفاده کنم).خب حالا به startup پروژه وبی خودم میرم و یک تغییراتی توش اعمال میکنم.خب تغییرات اعمال شده توی اون قسمتی هست که دورش خط قرمز کشیدم .(اگر با options pattern اشنا نیستید روی این لینک کلیک کنید)خب یک تغییری هم توی appsetting میدم.حالا توی SampleController ، در پروژه RCL رو بصورت زیر تغییر میدم.حالا اگر یک بریک پوینت بزارم توی کانستراکتور این کنترلر ، میتونم ببینم که inject بدرستی انجام شده.خب حالا یک نکته دگ بگم و بحث رو ببندم (حداقل برای الان )میخوام از یک تصویر داخل RCL استفاده کنم. یکم این مورد متفاوت هست (بطور کلی استفاده از Assets ها)خب من یک پوشه درست کرده بودم توی پروژه RCL خودم بنام wwwroot. داخل اون یک فولدر دگ ایجاد میکنم به اسم RCLImages و داخل اون هم یک عکس قرار میدم.اصلا با موس نمیشه خط درست درمون کشید:)خب حالا عکس رو میخوام توی صفحه index پروژه RCL نشونش بدم. صفحه رو بصورت زیر تغییر میدمیکم عجیبه مسیر دهی من؟ خب دلیل داره. وقتی که پروژه publish میشه ، تمام assets های داخل پروژه هایی که بهشون رفرنس داریم ، کپی میشن توی فولدر wwwroot اصلی و توی پوشه ای با نام Content_  و یک پوشه هم با نام اون library ایجاد میشه و تمام assets ها داخلش قرار میگیرن. بزارید نشون بدم.اگر پروژه وب رو پابلیش کنید. بعد به پوشه wwwroot ایجاد شده برید.اون موقع با یک همچین چیزی مواجه میشید.که اگر پوشه Content_ رو باز کنید ، اون موقع با پوشه ای که هم نام با RCL شما هست روبرو میشید و در داخل اون، تمام فایل ها و فولدر های موجود در پروژه RCL و در فولدر wwwroot بود ، قرار دارن.خب یادم رفت نتیجه کدی که نوشته بودیم رو نشون بدم.نتیجه اون در پایینهچیز های زیاد تری وجود داره ک اگر عمری بود در قسمت های بعدی میگم.پروژه رو روی گیت هابمم قرار دادم.(این لینک). توی پروژه گیت هابمم ، یک نمونه از override کردن یک فرم و نتیجه اون فرم رو هم قرار دادمموفق باشید.✅مقالات بیشتر در دات نت زومhttps://t.me/DotNetZoom</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Fri, 26 Mar 2021 21:28:43 +0430</pubDate>
            </item>
                    <item>
                <title>تفاوت Re-execute و Redirect در asp.net core</title>
                <link>https://virgool.io/dotnetzoom/%D8%AA%D9%81%D8%A7%D9%88%D8%AA-re-execute-%D9%88-redirect-%D8%AF%D8%B1-aspnet-core-dlktlses6uo7</link>
                <description>خب سلام.توی این مقاله میخوام یکم درباره error handling صحبت کنم. بصورت کلی در asp.net core دو تا میدلویر برای این منظور داریم . یکی DeveloperExceptionPage که در محیط develop ازش استفاده می کنیم چون اطلاعات بهمون درباره خطای که رخ داده میده. (Stack trace - query string - cookies - headers). و اصولا چه از نظر زیبایی و چه از نظر امنیتی درست نیست که اطلاعات خطای درون برنامه خودمون رو به کاربر نشون بدیم.دومی UseExceptionHandler که از این طریق هم میتونیم که صفحه رو به کاربر برگردونیم و توی محیط production ازش استفاده میشه.یک بحث فقط اینجا مطرح میشه و اونم اینه که این دو تا میدلویر ، کاری با status code ها ندارن و کلا روال کارشون ثابته و فرقی براشون بین استاتوس کد 400 و 500 (بطور مثال) وجود نداره.برای حل مشکل بالا میتونیم از میدلویر StatusCodePages استفاده کنیم.خب بطور مثال کد زیر رو در نظر بگیرید.public class HomeController : Controller
{
    public IActionResult Problem()
    {
        return StatusCode(500);
    }  
}توی این کد یک Action تعریف کردیم به نام problem که statusCode 500 رو برمیگردونه. این تابع statusCode داره یک statusCodeResult برمیگردونه و ورودیش یک int هست که همون statuscode هست .(البته میشه object ای هم بهش به عنوان پارامتر دوم پاس داد که اگر این کارو بکنیم نوع بازگشتی ObjectResult میشه). برای نوع بازگشتی این اکشن هم میشه از IActionResult استفاده کرد که والد همه این نوع هاست (حالا ن دقیقا خودش بلکه فرزند هاش ، مثلا StatusCodeResult داره ارثبری میکنه از کلاس ActionResult که خود ActionResult هم داره IActionResult رو پیاده سازی میکنه).خب بریم سراغ ادامه بحث.حالا توی متد Configure می خوایم بریم.public void Configure(IApplicationBuilder app)
{
    app.UseStatusCodePages();

    app.UseStaticFiles();
    app.UseRouting();
    app.UseEndpoints(endpoints =&gt;
   {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapRazorPages();
   });
}  خب چیز خاصی برای توضیح نیست. یک سری میدلویر قرار دادیم صرفا. حالا اگر یک ریکوست به یک محل اشتباه بزنیم ، به صفحه زیر مواجه میشیم.این خطا ، توسط میدلویر UseStatusCodePages ایجاد شده.حالا اگر ریکوست خودمون رو به اکشن Problem ای که ایجاد کرده بودیم بزنیم ، با صفحه دگ ای مواجه میشیم که در زیر می بینید.خب مشخصا می بینیم که این دو خطا متفاوت از هم نشون داده شدن.خب ، الان مشکلی که توی دو تصویر بالا دیدیم چی هست؟صفحه دیفالت ساخته میشه و قابلیت custom کردن رو نداریم. برای حل این مشکل می تونیم از دو تا میدلویر دگ استفاده کنیم. اولی UseStatusCodePagesWithRedirects و دومی UseStatusCodePagesWithReExecute هست. خروجی این دو تا متد تقریبا یکی هست و جفتشون بهمون این اجازه رو میدن که صفحات error شخصی سازی شده ای رو برای کاربر هامون ایجاد کنیم. (ولی بطور معمول از re-execute استفاده می کنیم که جلوتر دلیلش رو میگم).تصویر زیر داخل UseStatusCodePagesWithRedirects  اتفاق می افته.ریکوست به یک محل ارسال میشه از سمت کاربر. اون اکشن ، اکسپشن صادر میکنه (status code 500). بعدش در زمان برگشت ، موقعی که دوباره به میدلویر UseStatusCodePagesWithRedirects   می رسیم ، میاد و اون status code رو از 500 به 302 (ریدایرکت) تغییر میده و آدرس محلی که باید مرورگر کاربر به اون ریدایرکت کنه (یعنی اون صفحه ارور ما ) رو هم داخلش قرار میده. حالا توی مرحله بعدی ، مرورگر بصورت خودکار یک ریکوست به اون صفحه مربوطه میزنه و صفحه شخصی سازی شده ما با Status code 200 به کاربر برگشت داده میشه.در حقیقت ما در روش بالا ، بار اول به کاربر ارور رو نمیدیم. کاربر رو مجبور میکنیم که یک ریکوست دگ هم به سایت بده و بعد ارور رو بهش نمایش میدیم.خب حالا میخوایم بریم سراغ روش دوم یعنی Re-Execute. نحوه کارش در تصویر زیر قابل مشاهده هست.خب توی این روش ، ریکوست از سمت کاربر میاد (به یک اکشنی که اکسپشن قراره صادر کنه برامون) ، بعدش از میدلویر ها میگذره و وارد اون اکشن میشه و اکسپشن صادر میشه . حالا توی مسیر برگشت وقتی به میدلویر UseStatusCodePagesWithReExecute رسید ، این میدلویر دوباره ریکوست رو به همون pipeline برمیگردونه ولی این بار مسیرش رو ، مسیر error ای که ما تنظیم کردیم میده. اون صفحه ارور به درستی ساخته میشه و به همراه status code 200 به کاربر برگشت داده میشه.خب مشخصا این روش بهتره و این کاملا واضح هست.نکته ای که درباره این میدلویر وجود داره اینه که باید ، اونو قبل از میدلویر UseRouting قرار بدید که وقتی ریکوست رو دوباره generate میکنه ، Route مربوط به ارور انتخاب بشه .public void Configure(IApplicationBuilder app)
{
    app.UseStatusCodePagesWithReExecute(&amp;quot/Home/Error&amp;quot, &amp;quot?statusCode={0}&amp;quot);
    app.UseStaticFiles();
    app.UseRouting();
    app.UseEndpoints(endpoints =&gt;
   {
        endpoints.MapDefaultControllerRoute();
        endpoints.MapRazorPages();
   });
}  خب ، کد بالا فقط اون میدلویر اولی جای صحبت کردن داره . به عنوان اولین ورودی بهش محلی که باید بهش ریکوست ارسال بشه رو میدیم (توی مثال بالا کنترلر home و اکشن error) و بعدشم می تونیم بهش کوری استرینگ پاس بدیم. که اینجا ما statusCode رو پاس دادیم. بطور کلی داخل این میدلویر هر جا ما {0} placeHolder رو قرار بدیم، اون رو با StattusCode مربوطه جایگزین میکنهکد زیر هم مربوط به اکشن error هست که ایجاد کردیم.public class HomeController : Controller
{
    public IActionResult Error(int? statusCode = null)
    {
        if (statusCode.HasValue)
        {
            if (statusCode.Value == 404 || statusCode.Value == 500)
            {
                var viewName = statusCode.ToString();
                return View(viewName);
            }
        }
        return View();
    }
}این مقاله ای که خوندید ترجمه (با مقداری تغییر و تحریف در اصل متن و اپدیت کردن بخش هاییش ) از سایت آقای andrewlock بود .امیدوارم مفید براتون بوده باشه.✅مقالات بیشتر در دات نت زومhttps://t.me/DotNetZoom</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Thu, 25 Mar 2021 12:38:45 +0430</pubDate>
            </item>
                    <item>
                <title>Directory browsing چیست؟</title>
                <link>https://virgool.io/dotnetzoom/directory-browsing-%DA%86%DB%8C%D8%B3%D8%AA-cja4qzi3zmi0</link>
                <description>خب سلام. میخوام درباره قابلیت Directory browsing یکم حرف بزنیم. خب این قابلیت کارش اینه که به یوزر ما اجازه بده که بتونه توی فایل ها و فولدر های موجود داخل یک فولدر خاص ، حرکت کنه.منظورم بطور کلی یک چیزی مثل تصویر بالایی هست.این قابلیت بطور کلی غیر فعاله توی asp.net core  ولی وجود داره و در صورت نیاز میشه که فعال بشه.برای فعال کردن این قابلیت ، کافیه توی متد ConfigureServices ، اکستنشن متد AddDirectoryBrowser رو سر IServiceCollection صدا بزنید.services.AddDirectoryBrowser();حالا توی مرحله بعد ، باید توی متد Configure یک میدلویر به pipeline اضافه کنید.app.UseDirectoryBrowser();خب ، وقتی این میدلویر اضافه بشه ، شما با وارد کردن نام دایرکتوری (که داخل پوشه wwwroot هست) می تونید فایل ها و دایرکتوری های دگ ای که داخل همون پوشه هستن رو ببینید و توشون حرکت کنید ولی عملا همه دایرکتوری های موجود توی wwwroot باز هستن و هیچ محدودیتی نیست.خب این رو هم میشه به روش زیر حل کردapp.UseDirectoryBrowser(new DirectoryBrowserOptions(
{
                FileProvider = new PhysicalFileProvider(
               Path.Combine(env.ContentRootPath, &amp;quotwwwroot\\lib&amp;quot)),
               RequestPath = &amp;quot/files&amp;quot
  });کافیه به میدلویر مربوطه ، یک شی از جندس DirectoryBrowserOptions بدید. دو پراپرتی FileProvider و RequestPath رو هم براش ست کنید. FileProvider در اصل از نوع IFileProvider هست که ما اینجا بهش یک شی از PhysicalFileProvider اختصاص میدیم که توی اون ، آدرس اون پوشه ای که قصد داریم اجازه بدیم بشه بهش دسترسی گرفت رو قرار دادیم.و بعدش هم RequestPath که url ای هست که کاربر باید توی مرورگرش بزنه تا بتونه به این فولدر ما دسترسی پیدا کنه.یک چیز دگ هم بگم. هیچ لزومی نداره که حتما اگر نیازه این قابلیت رو فعال کنید ، تصاویر و یا .... رو داخل wwwroot بزارید . میتونید توی هر پوشه دگ ای توی پروژتون بزارید و از همین روش استفاده کنید.این میدلویر هم قبل از میدلویر UseRouting  قرار میگیره.خب در آخر مجددا بگم که این قابلیت استفاده ازش خوب نیست و به دلیل مشکلات امنیتی که میتونه بوجود بیاره غیر فعاله ولی شاید یک موقعی نیاز شد!. کسی چه میدونه!!موفق باشید.✅مقالات بیشتر در دات نت زومhttps://t.me/DotNetZoom</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Thu, 25 Mar 2021 02:02:40 +0430</pubDate>
            </item>
                    <item>
                <title>hsts چیست؟</title>
                <link>https://virgool.io/dotnetzoom/hsts-%DA%86%DB%8C%D8%B3%D8%AA-fodcc2ttnahc</link>
                <description>فرض کنید که به یک رستوران رفتید و قصد دارید از wifi رایگان آنجا استفاده کنید. دقت کردید که رمز wifi با یک برگه به دیوار چسبیده و هر کسی بخواد می تونه از اون استفاده کنه ؟ممکنه همزمان با شما ، یک هکر هم داخل همون رستوران باشه. خب مشخصا اون هکر میتونه تمام اتصالات نا امن رو به سادگی شنود کنه. هکر می تونه تمام ترافیک های شبکه ای که از پروتکل http استفاده می کنن برای هر سایتی و فقط متکی به ریدایرکت کردن کاربر از http به https هستند رو شنود کنه. خب ، اگر دقت کنیم موقعی که این اتفاق می افته دگ اصلا ssl بی معنی میشه و دیتا های ما کاملا در دست هکر هست.این دلیلیه که ما صرفا به ریدایرکت کردن کاربر از http به https بسنده نکنیم و به سراغ چیز دیگه ای بنام hsts بیایم.(البته خود این تبدیل http به https هم زمان بر هست که با HSTS برطرف میشه)سوال اول. HSTS چیه؟کلمه HSTS مخفف http strict transport security  هست.  HSTS یک هدر واکنشی هست که به مرورگر اطلاع میده که وب سایت های فعال شده فقط از طریق HTTPS قابل دسترسی هستند. بعد از فعال شدن HSTS بر روی سایت ، مرورگر مجبور می شود تا فقط به نسخه https دسترسی داشته باشد.سوال دوم.HSTS چگونه کار می کند؟وقتی ما یک آدرس سایت رو در مرورگرمون می زنیم ، عموما Schema اون رو وارد نمیکنیم. در این حالت بصورت پیش فرض ، http در نظر گرفته میشه و یک درخواست http به سرور ارسال می شه. سرور اون درخواست رو ریدایرکت میکنه (استاتوس کد 301) به https . و پس از اون، مجددا مرورگر یک ریکوست به سرور میده ولی این بار بصورت https . در این مرحله ، HSTS یک هدر روی response ای که به کاربر برگردوند قرار میده.Strict-Transport-Security: max-age=31536000; includeSubDomainsاین هدر تعداد دستور العمل به مرورگر ما میده. یکی از اون ها max-age هست به این معنی که از الان ، تا زمانی که اون تایم تموم بشه (یک سال) هر ریکوستی که به سایت مرورگر بخواد بده ، باید روی https باشه. اگر ریکوستی با پروتکل http به مرورگر بیاد ، مرورگر خودش اون رو جایگزین میکنه با https . برای اینکه این موضوع روی ساب دامین ها هم اعمال بشه ، دستورالعمل includeSubDomains هم در هدر قرار میگیره.سوال سوم. آیا HSTS کاملا امن هست؟متاسفانه بار اولی که به وبسایت دسترسی میگیریم ، از HSTS استفاده نمیشه. اگر وب سایت بیاد و هدر HSTS رو به ریکوست http که براش اومده ، اتصال بده ، اون هدر نادیده گرفته میشه چون هکر میتونه خیلی راحت اون هدر رو پاک کنه یا دستکاری کنه (بدلیل http بودن ). بطور کلی هدر HSTS قابل اعتماد نیست مگر زمانی که از HTTPS استفاده بشه.نکته دگ اینکه هر بار که مرورگر هدر مربوط به HSTS رو ببینه max-age رفرش میشه و maximum اون هم دو سال هست. اگر max-age رو برابر 0 بزاریم ، مرورگر از ریکوست های بعدی اینطوری در نظر میگیره که این سایت یک سایت جدید هست و میتونه ریکوست http بهش بده.چجوری از HSTS داخل ASP.Net Core استفاده کنیم؟خب توی مرحله اول ، باید توی متد ConfigureService ، کد زیر رو بنویسیم. services.AddHsts(opts =&gt; {
opts.MaxAge = TimeSpan.FromDays(1);
opts.IncludeSubDomains = true;
});توی بخش configuration چند تا پراپرتی وجود داره که می تونیم ست کنیم (در اصل همون دستور العمل هایی هستن که توی هدر ست میشن و به مرورگر داده میشن).یکیش max-age هست که خب قبلا دربارش صحبت کردیم. اگر مقداری براش ست نکنیم ، مقدار پیش فرضش 30 روز هست. بعدی IncludeSubDomains هست که باز هم قبلا دربراش صحبت شد. اگر ست نشه پیشفرضش false هست .مورد بعدی ExcludeHosts هست که اون هاست هایی که هدر hsts نباید ست بشه براشون رو مشخص میکنه. بصورت پیش فرض داخلش localhost و 127.0.0.1 و [1::] هست یعنی برای هیچ کدوم از اینها هدر hsts ست نمیشه . میتونیم خودمون هم هر هاستی که بخوایم رو اضافه کنیم.حالا میریم سراغ متد configure .طبق همین pipeline ای که مایکروسافت در داکیومنتش قرار داده رفتار می کنیم.(الان محل بحث ما فقط https و HSTS هست).اول میدلویر HSTS اضافه میشه و بعد از اون میدلویر مربوط به ریدایرکت به https. فقط نکته ای که وجود داره اینه که نیاز نیست HSTS رو برای بخش development قرار بدید (اصلا کار هم نمیکنه چون بصورت پیشفرض سر لوکال هاست و ... که بالاتر گفتم کار نمیکنه و اون هدر مربوطه رو ست نمیکنه).فقط برای production قرارش بدید.میدلویر مربوط به HSTS اسمش UseHsts هست و میدلویر مربوط به ریدایرکت از http به https ، اسمش UseHttpsRedirection هست.موفق باشید.✅مقالات بیشتر در دات نت زومhttps://t.me/DotNetZoom</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Tue, 23 Mar 2021 12:44:42 +0430</pubDate>
            </item>
                    <item>
                <title>الگوریتم بررسی پالیندروم بودن یک string در سی شارپ</title>
                <link>https://virgool.io/@Farshideshoun/%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85-%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%D9%BE%D8%A7%D9%84%DB%8C%D9%86%D8%AF%D8%B1%D9%88%D9%85-%D8%A8%D9%88%D8%AF%D9%86-%DB%8C%DA%A9-string-%D8%AF%D8%B1-%D8%B3%DB%8C-%D8%B4%D8%A7%D8%B1%D9%BE-poskbzrcx6qz</link>
                <description>داشتم تجربه مصاحبه یکی از دوستان را میخواندم که یک سوالی پرسیده بودند که خیلی زمان از بررسی موضوع مشابهی  برام گذشته بود بنابراین تصمیم گرفتم یک فلش بک به این موضوع داشته باشم و  با شما به اشتراک بذارم.خب فرض کنید یک عبارت بهمون میدن مثل &quot;abba&quot; و یا &quot;madam&quot; و حالا میگن پالیندروم بودنش رو بررسی کنید.(یعنی reverse عبارت با خود عبارت یکی بشه).خب این کار رو با ساختار stack میشه به راحتی انجام داد.کدشو نوشتم و در پایین قرار دادم.خب برای راحتی کار یک extension متد نوشتم که روی string ها کار میکنه .در ابتدا نیمه اول اون عبارت رو وارد یک stack میکنیم. (البته اگر تعداد کارکتر ها فرد باشه ، عنصر وسط وارد نمیشه) .حالا تا اینجا ما یک پشته داریم که مثلا برای عبارت madam داخلش am قرار گرفته (a در بالای پشته و m در پایین پشته). در مواقعی که تعداد کارکتر ها فرد هست ، عنصر وسط سر جاش باقی میمونه و اصلا نیازی به چک کردنش نیست برای همین چک میکنیم که اگر تعدا کارکتر ها فرد بود ، i رو اضافه میکنیم .در مرحله بعد از نصفه دوم پشته تا انتها جلو میریم و هر بار از پشته یک حرف رو pop میکنیم و قیاس با مقدار ادامه نصفه دوم پشته میکنیم. اگر مساوی نبودند قاعدتا اون رشته Palindrome نیست و این کار را تا زمان تمام شدن رشته انجام میدهیم.با فرض بر اینکه push و pop کردن هزینه اجرایی 1 دارن برامون ، چون حلقه های while ما تا len/2 جلو میرن پس میتونیم نتیجه بگیریم پیچیدگی زمانی ما همین میشه.</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Sat, 21 Nov 2020 13:54:55 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش RedBeanORM (PHP ORM) پارت دوم</title>
                <link>https://virgool.io/@Farshideshoun/redbeanparttwo-bqxybtyujbmy</link>
                <description>خب ، توی مقاله قبلی (یعنی این مقاله) یک سری مقدمات درباره RedBean گفتیم. حالا اینجا می خوایم عملیات های crud رو پیاده سازی کنیم که نیاز اکثر اپلیکیشن ها هستن.قبل شروع کردن بحث خوبه که بگم که RedBean از یک ساختاری بنام Beans برای کارهاش استفاده میکنه. اکثر کنش هاش بر روی دیتابیس توسط همین bean ها اتفاق می افته و مورد استفادشون برای حمل داده بین ما و بین دیتابیس هست.هر Bean یک type و یک id داره.type برای ما مشخص میکنه که داریم روی چه جدولی تغییرات اعمال میکنیم. id هم primary key رکورد متناظر خودش توی دیتابیس هست.خب پس توی ادامه مقاله سعی میکنیم با ادبیات خود RedBean با هم صحبت کنیم.توضیحات این بخش در مقاله قبلی آمدهخب میبینیم که یک bean ایجاد کردیم تحت عنوان post و ستون براش ایجاد کردیم.حالا میخوایم یک سری نکته جدید یاد بگیریم. RedBean برای ما فقط ساختار داده ضروری مورد نیازمون رو ایجاد میکنه و اصلا کاری با index ها و constraint ها نداره و اگر قصد داشته باشیم این موارد رو اضافه کنیم ، باید بصورت دستی به دیتابیس اضافه کنیم.خب نکته بعدی توی نام گذاری اسم Bean ها هست . اسم Bean ها اجبارا باید تشکیل شده از حروف کوچک الفبا باشه و حق استفاده از حروف بزرگ ، _ و علائم رو نداریم.نام گذاری خاص فقط مرتبط با اسم Bean نیست بلکه روی ایجاد ستون ها هم تاثیر گذاره. بطور مثال ما حق نداریم ستونی داشته باشیم که در انتهای نام اون ستون ، id_ آمده باشه چون این مورد برای RedBean رزرو شده هست (دلیل رزرو شدنش استفاده از این نحوه نوشتن نام برای relation هاست).یا اگر ما نام ستون هارو بصورت camel case بنویسیم (بطور مثال : areYouSure) بصورت خودکار به snake case تبدیلش میکنه(یعنی تبدیل میشه به are_you_sure).خب بریم سراغ مرحله بعد یعنی load داده از دیتابیس .این مورد رو هم توی مقاله قبلی دیدیم ولی الان میخوایم با جزئیات بیشتری بهش نگاه کنیم.توضیحات این تصویر در مقاله قبلی آمده استخب ما داریم تلاش میکنیم که از Bean با نام post ، یک ردیف با id 1 رو بخونیم.حالا اگر همچین Bean ای وجود نداشته باشه (فرضا اشتباه تایپی داشتیم توی نوشتن نام Bean ) چه اتفاقی می افته؟ در پاسخ به پرسش بالا باید بگم که یک Bean خالی برگشت داده میشه که فیلد id داره و مقدار این فیلد برابر 0 هست. البته صفر بودنش دو معنی میتونه داشته باشه : 1-ردیفی با همچین id ای موجود نیست2- همچین bean ای در دیتابیس موجود نیستخب نکته بعدی اینه که RedBean بطور پیشفرض فقط string برمیگردونه از دیتابیس (هر چیزی رو تبدیل میکنه به string و برمیگردونه ) و اگر به هر دلیلی قصد تغییر این رفتار رو داشته باشیم ، می تونیم از کد زیر استفاده کنیم.R::getDatabaseAdapter()-&gt;getDatabase()-&gt;getPDO()-&gt;setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);در زیر ساخت RedBean داره از PDO استفاده میکنه.PDO مخفف php data object هست که یک ابزار برای ارتباط با دیتابیس هست ولی عمل mapping و توابع آماده برای query های پیش فرض رو نداره (برخلاف ORM ها).خب بریم سراغ ادامه مطلب.ما گاهی دیتا رو از دیتابیس میخونیم و فقط قصدمون display کردن اون دیتا به کاربر هست ولی برخی موارد هم قصد ویرایش داریم بر روی اون دیتا. RedBean این قابلیت رو به ما میده که بتونیم رکورد مروبطه رو lock کنیم که شخص دگ ای نتونه کاری با اون انجام بده تا زمانی که ما کارمون (یا اصطلاحا transaction مون) تموم بشه و بعد اون رکورد از lock در میاد. برای استفاده از این مورد بجای فراخوانی Load عادی ، از تابع loadForUpdate استفاده میکنیم (این مورد برای ورژن 5 به بالا اومده و اگر از قبل این ورژن استفاده میکنید دسترسی به این امکان رو ندارید).علاوه بر خوندن یک bean از دیتابیس با تابع load ، ما میتونیم چندین bean رو هم بخونیم و این کار توسط تابع LoadAll اتفاق میافته.خب loadAll یک آرایه از id ها میگیره و به ما یک آرایه از Bean ها برمیگردونه و بعدش با یک حلقه foreach چاپشون رو انجام دادم تا مشخص بشه که درست کار کرده که در تصویر زیر میبینید.خب حالا بریم سراغ مبحث بعدی یعنی update کردن دیتا درون دیتابیس . قبل از شروع باید بگم که با RedBean هم میتونید دیتای درون دیتابیس رو آپدیت کنید و هم میتونید ساختار Beanرو آپدیت کنید(بطور مثال ستونی بهش اضافه کنید).اگر خاطرتون باشه ما یک bean توی مقاله قبلی تحت عنوان post ایجاد کردیم و دو ستون author_ و title_ داشت. حالا قصد دارم اینجا یک ستون اضافه کنم تحت عنوان date_ و مقدار title یکی از سطر هارو هم تغییر بدم.خب خیلی از کد هایی که بالا میبییند رو توی مراحل قبلی توضیح دادیم و ازشون میگذرم. بطور کلی در ابتدا row مربوطه که قصد داریم title اون رو تغییر بدیم رو از دیتابیس میخونیم. حالا ما هیچ ستونی تحت عنوان date_ توی دیتابیس نداریم و فقط کافیه مثل بالا ، شی آمده از دیتابیس رو براش یک فیلد تحت عنوان مد نظرمون قرار بدیم که این باعث میشه که بعد از store کردن یک ستون با اون نام برامون ایجاد بشه.حالا قصد داریم داخلش هم مقدار قرار بگیره و null نباشه مقدارش . برای این مورد میتونیم از خود RedBean برای دریافت زمان فعلی سیستم استفاده کنیم که کدش در تصویر قابل مشاهده است.برای تغییر مقدار یک ستون دگ از ردیف واکشی شده از دیتابیس هم فقط کافیه مثل بالا مقدار مد نظرمون رو بهش تخصیص بدیم.بطور کلی فرقی بین زمانی که میخوایم یک ستون جدید بسازیم یا یک مقدار تخصیص بدیم از سمت ما نیست و در پشت صحنه خود RedBean چک میکنه که آیا همچین ستونی وجود داره یا ن و اگر وجود داشت که خب مقدار رو آپدیت میکنه و اگر نبود، اون ستون رو ایجاد میکنه برای جدول.خب تغییرات مربوطه اعمال شدن. فقط یک نکته وجود داره اونم اینه که ستون date_ مقدارش برای بقیه رکورد ها null قرار میگیره .خب حالا بریم سراغ delete کردن اطلاعات از دیتابیس. برای حذف اطلاعات از دیتابیس ما میتونیم هم بصورت تکی این کار رو انجام بدیم هم بصورت جمعی.تابع trash که یک ورودی میگیره که bean ما هست و اون رو از دیتابیس حذف میکنه.تابع trashAll که یک آرایه ای از Bean ها میگیره و همه اون هارو حذف میکنه.همچنین ما میتونیم تمام Bean هایی که از یک نوع هستند رو هم همزمان حذف کنیم که این کار توسط تابع wipe انجام میشه و یک ورودی میگیره و ورودی اون ، type bean هست که قصد داریم تمام bean هاش حذف بشه.</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Sat, 21 Nov 2020 11:31:28 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش  RedBeanORM (PHP ORM) پارت اول</title>
                <link>https://virgool.io/@Farshideshoun/redbeanorm-j6kqdcazgjcg</link>
                <description>سلام به دوستان .من برنامه نویس دات نتم ولی بنا به دلایلی نیاز شده که کمی تا حدودی (!!!) آشنایی با php هم داشته باشم و برای ارتباط با دیتابیس اول رفتم سراغ mysqli که بعدش گفتم خب چرا ORM ن؟!رفتم و درباره ORM های php خوندم و دیدم یکی از بهترین هاش  RedBean هست که در کمال تعجب آموزش درست حسابی هم ندیدم توی وب فارسی(شاید من ندیدم و باشه!) و گفتم یکم خودم دربارش بنویسم.خلاصه که قراره دات نتا رو بریزم تو php ها (اقتباسی از قیمه ها درون ماست ها:) ).خب اول بریم سراغ مفهوم ORM . ORM مخفف شده object relational mapper هست که ترجمه فارسیش میشه نگاشت رابطه ای اشیا (!!!!!) که اصلا بیخیال...خب ادامه بدیم ، ORM در حقیقت یک لایه بین زبان برنامه نویسی و پایگاه داده هست.وقتی بطور معمول شما میخواید دیتا از دیتابیس بخونید ، نیاز دارید تا دستور های SQL ای ارسال کنید سمت دیتابیس و result اون رو بطور دستی ، به object های زبان مورد نظرتون map کنید.خب چی میشه اگ یک کتابخانه اون وسط قرار بگیره که کار تولید کد های SQL ای (حداقل اونایی که خیلی ساده هستن) و همین طور map کردن رو برای ما انجام بده؟خب قطعا این باعث میشه که برنامه نویس نیاز نباشه زیاد وارد دنیای دیتابیس ها بشه و توی همون دنیای OOP خودش باقی بمونه و فقط با اشیا سرو کار داشته باشه.خب بریم برای شروع.توی مرحله اول بسته به نسخه php مورد استفادتون از این لینک فایل مربوطه رو دانلود کنید. بعد دانلود می بینید که یک فایل php بهتون تحویل میده که اون رو باید کنار اسکریپت های php خودتون قرار بدید.خب حالا میریم به phpmyadmin و یک دیتابیس ایجاد می کنیم تحت عنوان RedBeanDB و هیچی داخلش قرار نمیدیم.(خب یک نکته رو همینجا بگم ، user ای که داخل phpmyadmin دارید و از اون در مراحل بعد قصد استفاده داریم ، باید دسترسی های مرتبط با structure ها رو داشته باشه)خب حالا میخوایم بریم سراغ کد های phpخب بریم برای توضیحات . فایلی که ابتدای بحث از سایت مرجع دانلود شد اسمش rb هست و پسوندش هم .php (مگر اینکه نسخه خاصی ازش رو دانلود کنید که یکم توی نام گذاریش متفاوته ولی روال کار ثابته).اول اون فایل رو به برنامه خودمون اضافه میکنیم. توی مرحله بعد باید تنظیمات ابتدایی دیتابیس رو انجام بدیم . اگر می خوایم از SqlLite استفاده کنیم کافیه ;() R::setup را فراخوانی کنیم ولی خب چون الان قصد داریم بریم سراغ mysql ، این کار رو انجام نمیدیم. R که داریم ازش استفاده میکنیم یک کلاس هست که داخل همون فایل rb.php قرار گرفته و از کلاس Facade (که بازم توی همون فایل هست ) ارثبری کرده.(توضیحات اضافه توی این زمینه بنظرم حوصله رو سر میبره ولی می تونید راحت سورس کدش رو بخونید و دستتون میاد چخبره اون پشت).خب متد setup در اصل 4 ورودی میگیره . ورودی اول dns هست که ست کردیم براش (: mysql برای کار با دیتابیس mysql اجباریه - host هم اسم هاست رو باید وارد کنیم که حالا اگر روی سرور خاصی باشه ip اون و اگر روی لوکال باشه هم لوکال هاست - dbname هم نام دیتابیس هست ). ورودی دوم username ما رو میگیره و ورودی سوم هم رمز مارو میگیره. ورودی چهارم یک bool از ما میگیره و بطور پیشفرض false هست و اگر اون رو true کنیم ، باعث میشه که setup ما توی frozen mode اجرا بشه که ما باهاش کاری نداریم.خب بعد از اعمال تنظیمات حالا می خوایم یک جدول بنام post ایجاد کنیم. اینکار با استفاده از تابع dispense انجام میشه. ورودی این تابع نام جدول ما هست. (یک نکته که باید بگم اینه که اگر بطور مثال شما ده بار تابع dispense  رو با یک نام خاص مثلا post صدا بزنید ، فقط همون بار اول جدول براتون ایجاد میشه و در خواست های بعدی که قصد داریم جدول با همون نام بسازیم ignore میشن و هیچ exception ای هم صادر نمیشه).خب حالا جدول رو ساختیم . قصد داریم درون این جدول ، دو ستون ایجاد کنیم با نام های author_ و title_ .کافیه بدین صورت که در تصویر بالا هست رفتار کنیم تا برای ما ستون ها ایجاد بشن. type این ستون ها در دیتابیس بر اساس مقدار هایی که بهشون پاس میدیم قرار میگیرن.در اخرم تابع store رو صدا میزنیم تا تغییرات مد نظرمون بر روی دیتابیس اعمال بشن.فقط یک نکته وجود داره اونم اینه که تابع store مقدار id ای که ذخیره کرده داخل دیتابیس رو برای ما بر میگردونه که بعدا ازش استفاده می کنیم.خب حالا بریم دیتابیس رو چک کنیم و ببینیم چه اتفاقی افتاد.خب میتونید ببینید که هم جدول با نام post ایجاد شد و هم درون اون جدول ستون های مد نظر ما و مقادیری که بهشون پاس دادیم هم قرار گرفت.حالا بریم که این بار از دیتابیسمون دیتا بخونیم.خب من اینجا id رو بصورت دستی وارد کردم ولی خب میشد از store مرحله قبل هم id رو گرفت ولی نیاز داشت که دوباره یک row (tuple ) به جدول اضافه بشه که ترجیح دادم این کارو نکنم.با استفاده از تابع load می تونیم که دیتا رو از دیتابیس load کنیم. ورودی اول این تابع ، نام جدول هست و ورودی دومش id مربوطه هست که قصد خوندنش رو داریم (کاملا واضحه که برای خوندن تمامی row ها ازش استفاده نمیشه چون صرفا یک id خاص رو از دیتابیس می خونه).خب حالا خروجی کد بالا رو بریم ببینیم.خب می بینیم ک به سادگی تونستیم با فراخوانی یک تابع ، از دیتابیس خودمون داده بخونیم .البته برای استفاده کردن از دیتا های خوانده شده می تونیم به شیوه کار با آرایه ها هم باهاشون رفتار کنیم. مثالش در تصویر پایین قرار گرفته خب حالا بریم سراغ حذف کردن یک row از جدول. حذف از جدول با تابع trash انجام میشه و برای حذف کردن اول باید اون row رو اول از دیتابیس load کنیم و بعد اقدام به حذف کنیم.خب بخش اول این مقاله رو بهتره همینجا تموم کنم.موفق و درگیر کد نویسی باشید :)لینک مقاله دوم</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Fri, 20 Nov 2020 23:55:29 +0330</pubDate>
            </item>
                    <item>
                <title>کار  DetectChanges در EF چیست؟</title>
                <link>https://virgool.io/@Farshideshoun/%DA%A9%D8%A7%D8%B1-detectchanges-%D8%AF%D8%B1-ef-%DA%86%DB%8C%D8%B3%D8%AA-i1uuaiqewt34</link>
                <description>خب امروز میخوام درباره متد DetectChanges صحبت کنم.قاعدتا کسایی که این مطلب رو میخونن ، باید حداقل دانش اولیه ای نسبت به   Entity Framework (چه full و چه Core) داشته باشند.خب بریم سراغ بحث اصلی.قبل از پرداختن به خود DetectChanges ، اول یکم درباره ChangeTracker صحبت کنیم.کلاس ChangeTracker ، داخل فضای نام Microsoft.EntityFrameworkCore.ChangeTracking قرار گرفته و به ما امکان ردیابی state تمام entity هایی که در حال حاظر در DbContext ما موجود هستن رو میده. زمانی که ما یک شی رو به context اضافه میکنیم و یا تغییری در اون انجام میدیم و یا حذفش میکینم ، این اعمال ها توسط Track، ChangeTracker میشوند و اگر قبل اینکه SaveChanges انجام بدیم ، Context ما Dispose بشه ، تمام اون تغییرات از بین میرن.بطور کلی ، ChangeTracker دارای State های زیر هست :AddedModifiedDeletedUnchangedDetachedخب.تا همینجا صحبت مقدماتی درباره changeTracker بنظرم کفایت میکنه.بریم سراغ بحث اصلی یعنی متد DetectChanges  .using (var context = new AnotherBlogContext())
{
    var post = context.Posts
                   .Single(p =&gt; p.Title == &amp;quotMy First Post&amp;quot);

    post.Title = &amp;quotMy Best Post&amp;quot
    context.SaveChanges();
}کد بالا رو نگاه کنید.یک کوئری روی دیتابیس زده میشه ، یک رکورد از جدول خونده میشه و Title اون رکورد تغییر میکنه و بعدش SaveChanges فراخوانی میشه.حالا یک سوال مطرح میشه و اونم اینه که ما ، توی Entity هامون (عموما کلاس های poco هستند ) ساختار های Track کردن دیتا قرار ندادیم.چطور متد SaveChanges متوجه میشه که باید چه property هایی رو تغییر بده؟!انتیتی فریم ورک ، یک snapshot از property های entity هایی که با کوئری از دیتابیس دریافت کرده تهیه میکنه.وقتی متد SaveChanges فراخوانی میشه ،بصورت اتوماتیک متد DetectChanges رو فراخوانی میکنه.این متد ، میاد و تمام entity های داخل Context رو اسکن میکنه و اون ها رو با دیتا های اورجینال وجود در SnapShot مقایسه میکنه.اگر پراپرتی تغییر کرده بود ، متوجه میشه که باید یک کوئری سمت دیتابیس زده بشه.مثلا برای مثال بالا متوجه میشه که Title تغییر کرده و یک کوئری Update سمت دیتابیس باید فرستاده بشه.البته متد DetectChanges  کار بیشتری نسبت به چیزی که در بالا توضیح دادم انجام میده.using (var context = new AnotherBlogContext())
{
    context.Blogs.Load();
    var post = context.Posts
                   .Single(p =&gt; p.Title == &amp;quotMy First Post&amp;quot);

    post.Title = &amp;quotMy Best Post&amp;quot
    post.BlogId = 7;
    context.SaveChanges();
}
کد بالا رو در نظر بگیرید. همونطور که صحبت شد ، وقتی SaveChanges فراخوانی میشه ، درون خودش DetectChanges  رو فراخوانی میکنه.میبینیم که در بالا ، ابتدا تمام Blogs ها رو Load کردیم و در خط قبل از BlogId ، SaveChanges رو برابر 7 قرار میدیم.حالا DetectChanges وقتی فراخوانی میشه ، علاوه بر اون کارهایی که قبلا گفتیم ، نگاه میکنه که آیا داخل Context ، یک BlogId با Id برابر 7 وجود داره یا نه.اگر وجود داشت navigation property اون Blog رو به این entity جدید متصل میکنه.در اصل میشه اینطوری گفت که DetectChanges چک میکنه که navigation property ها Update بشن.آیا DetectChanges  کار اضافه و بیهوده ای است؟اگر Context ما تعداد زیادی Entity داشته باشه و با اون ها کار کنیم، قطعا این مبحث DetectChanges  برای ما هزینه هایی خواهد داشت ولی این هزینه در اکثر برنامه های ما ، منجر به تولید گلوگاه برای برنامه نمیشه.در مقاله بعدی به زودی درباره اینکه دقیقا چه زمانی و چگونه متد DetectChanges  فراخوانی میشه صحبت میکنیم.:)</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Mon, 21 Sep 2020 15:34:40 +0330</pubDate>
            </item>
                    <item>
                <title>آیا این NULL ، Object است؟(#c)</title>
                <link>https://virgool.io/@Farshideshoun/null-checking-y1k1hltnxrhe</link>
                <description>خب سلام خدمت همه دوستان عزیز.یک داستانی که من همیشه داشتم سر این بود که این null بودن یک object رو چجوری چک کنم؟قطعا طریق های مختلفی برای این منظور هست و گفتم امروز اون هایی رو که من باهاشون آشنایی دارم و بنظرم باحال هستند رو بهتون معرفی کنم.مسائل گفته شده توی این مطلب همه برای c# هست:)خب یکی از ساده ترین کارهایی که همیشه میکنیم چیه ؟ if و دیگر هیچ:)if (myobject == null)   
 {     
      throw new ArgumentNullException(nameof(myobject)); 
 }قطعا همه با این شیوه اشنایی داریم و خب نیاز نیست سرش توضیحی داده بشه.از زمان c# ورژن 7 به بعد میشه از عملگر is هم برای چک کردن null بودن یا نبودن استفاده کرد.if (myobject is null)
  {
    throw new ArgumentNullException(nameof(myobject));
  }که چه میکنه که اون متغیر null هست یا خیر .تا اینجاشم که چیزی نداشت:)همون طور که همه میدونیم ، هر typeی توی دات نت ، داره از کلاس object ارثبری میکنه و به بیان دیگر ، والد هر type که ما میسازیم یا از قبل موجود هست ، کلاس object هست.داخل این کلاس یک متد بنام ReferenceEquals وجود داره که کد این متد رو پایین میزارم.( از طریق این سایت میتونید سورس کد دات نت کور رو ببینید).public static bool ReferenceEquals(object? objA, object? objB)
 {
       return objA == objB;
 }خب میبینیم که این تابع هم کار خیلی خاصی انجام نمیده.دو تا object (که صد البته هر کدومشون میتونن null باشن (به عملگر ? دقت کنید)) دریافت میکنه و یک مقایسه ساده از همون نوع مقایسه ساده خودمون که توی if انجام میدادیم ، انجام میده و نتیجه رو برمیگردونه.if(object.ReferenceEquals(myobject,null))
{
   //bla bla bla :)
}خب اینم راه ساده سوم هست برای این منظور.خب قضیه همینجا تموم نمیشه:)توی c#7 یک امکان دیگ هم بود به اسم Discards.حالا جریانش چیه؟بطور خیلی ساده و خلاصه ، یک یا چند متغیر کمکی هستند که داخل کد برنامه بهشون نیازی نداریم.این متغیر ها چیزی داخلشون ذخیره نمیشه و اصلا فضایی هم از حافظه نمیگیرن.حالا مثال براش چی هست؟_ = myobject ?? throw new ArgumentNullException(nameof(myobject));خب کد بالا چک میکنه اگر myobject برابر null بود ، یک exception رخ میده و اگر هم نبود اتفاق خاصی نمیافته.   _(underscore) همون discard هست .خب قضیه به همینجا هم ختم نمیشه:)یک راه دگ هم داریم براش که توی c# 9 رسید.if(myobject is not null){
//some code
}خب is که قبلا هم بود (بالا تر یکم دربارش حرف زدیم).این دفعه not هم جلوش اومد.اگر null , myobject نباشه وارد میشه (به ! میتونیم بگیم که اگر null بود وارد بشه)متد Equals هم داخل کلاس object وجود داره که نسبت به ReferenceEquals کارهای بیشتری انجام میده.پیشنهاد میدم سورسش رو بخونید(لینک).(البته یکم سر بحث reference type ها و value type ها متفاوت کار انجام میده که توی خود سورس دات نت کور ، یک توضیح مختصری هم بالای کدش داده )برای رسیدن به null checking هزاران راه است :) شما هم اگر دوست داشتید راه های مورد علاقتون رو بگید:)</description>
                <category>فرشید جهان منش</category>
                <author>فرشید جهان منش</author>
                <pubDate>Mon, 21 Sep 2020 10:36:49 +0330</pubDate>
            </item>
            </channel>
</rss>