<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های ضحی شبر</title>
        <link>https://virgool.io/feed/@zoha_shobbar</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-16 13:35:02</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/831736/avatar/I5ZibE.jpg?height=120&amp;width=120</url>
            <title>ضحی شبر</title>
            <link>https://virgool.io/@zoha_shobbar</link>
        </image>

                    <item>
                <title>چطور هر بار یک Implementation از یک سرویس رو بر اساس یک شرط استفاده کنیم؟</title>
                <link>https://virgool.io/@zoha_shobbar/%DA%86%D8%B7%D9%88%D8%B1-%D8%A8%D8%B1-%D8%A7%D8%B3%D8%A7%D8%B3-%DB%8C%DA%A9-%D8%B4%D8%B1%D8%B7-%D9%87%D8%B1-%D8%A8%D8%A7%D8%B1-%DB%8C%DA%A9-%D8%A7%D9%85%D9%BE%D9%84%D9%85%D9%86%D8%AA%DB%8C%D8%B4%D9%86-%D8%A7%D8%B2-%DB%8C%DA%A9-%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%D8%B1%D9%88-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D9%85-a7dvhwnm5xgb</link>
                <description>چند وقت پیش داشتم روی پروژه ای کار میکردم که موضوعی پیش اومد و با خودم گفتم شاید برای شما هم جالب و کاربردی باشه. موضوع از این قرار بود که ما یک سرویس ارسال SMS داشتیم که در اون چند متد متفاوت برای ارسال داشتیم و چند provider هم داشتیم که بر اساس یک شرط خاص بین اون ها سوئیچ میکردیم.  در یک حالت ساده تصور کنید که ما یک تنظیمی رو در appsetting پروژه گذاشتیم و هر بار که اون رو تغییر میدیم از یک Provider برای ارسال SMS استفاده می شه.من از این روش استفاده کردم. اگر شما از روش دیگه ای استفاده میکنید خوشحال میشم اون رو به اشتراک بگذارید.من برای اینکه مشخص کنم از چه Provider ای استفاده بشه در فایل appsettings  یک چنین تنظیماتی ایجاد کردم :  &amp;quotSmsSettings&amp;quot: {
      &amp;quotDefualtProvider&amp;quot: &amp;quotKavenegar&amp;quot,
      &amp;quotKavenegarSetting&amp;quot: {
          &amp;quotApiKey&amp;quot: &amp;quotMyApiKey&amp;quot,
          &amp;quotSenderLine&amp;quot: &amp;quot123456&amp;quot
      },
      &amp;quotFarazSetting&amp;quot: {
          &amp;quotUserName&amp;quot: &amp;quotMyUserName&amp;quot,
          &amp;quotPassword&amp;quot: &amp;quotPassword&amp;quot,
          &amp;quotSenderLine&amp;quot: &amp;quot123456&amp;quot
      }
  }و یک اینترفیس هم ایجاد کردم که در اون متد مورد نظرم پیاده شده :    public interface IGetwaySmsService
    {
        Task SendSimpleSms(SmsMessage message);
    }در چند تا سرویس که داشتم هم این متد ها رو پیاده سازی کردم ( البته که پیاده سازی هر متد توی هر سرویس روش خاص خودش رو داره اما اینجا من به صورت خیلی ساده اونها رو ایجاد کردم).برای مثال کلاس اول رو به این شکل پیاده کردم:    public class FarazService : IGetwaySmsService
    {
        private readonly AppSettings _settings;
        public FarazService(IOptionsSnapshot&lt;AppSettings&gt; settings)
        {
            _settings = settings.Value;
        }

        public async Task SendSimpleSms(SmsMessage message)
        {
            await Farazsms.SendSmsAsync(message.PhoneNumber, message.Text);
        }
}و کلاس دوم رو هم به این شکل :   public class Kavenegar : IGetwaySmsService
    {
        private readonly AppSettings _settings;

        public Kavenegar(IOptionsSnapshot&lt;AppSettings&gt; settings)
        {
            _settings = settings.Value;
        }

        public async Task SendSimpleSms(SmsMessage message)
        {
            await KavenegarSms.SendSmsAsync(message.PhoneNumber, message.Text);
        }
    }حالا نوبت به کلاسی هست که قراره این اینترفیس رو استفاده کنه و بر اساس تنظیماتی که در appsettings گذاشتم انتخاب کنه که از یکی از این سرویس ها استفاده کنه. تنظیمات appsettings رو خوندم و در کلاس AppSettings گذاشتم. بعد برای اینکه مشخص کنم Interface ای که دارم ازش استفاده می کنم قرار هست که از کدوم یکی از این سرویس های Implement شده استفاده کنه، یک delegate به نام getwaysmsService ایجاد کردم و در زمانی که میخوام یکی از متد های اینترفیس رو صدا بزنم اون رو با مقداری که توی appsetting در DefualtProvider قرار دادم مقدار دهی کردم(شما میتونید از هر روش دیگه ای برای این مقدار دهی استفاده کنید). به این صورت :public class NotificationSenderService
{
    private readonly AppSettings _settings;
    private readonly Func&lt;string, IGetwaySmsService&gt; _getwaysmsService;

    public BackgroundNotificationSenderService(
        Func&lt;string, IGetwaySmsService&gt; getwaysmsService )
    {
        _getwaysmsService = getwaysmsService;
        _settings = settings.Value;
    }

    public async Task SendSimpleSms(SmsMessage message)
    {
        var smsService = _getwaysmsService(_settings.SmsSettings.DefualtProvider);        
        await smsService.SendSimpleSms(message);
    }
}در نهایت باید سرویس هام رو در Startup رجیستر کنم. اما نکته ای که اینجا باید بهش دقت کنیم این هست که لازمه سرویس ها رو به صورت Transient رجیستر کنیم تا در هر بار درخواست بررسی کنه که از کدوم سرویس میخواد استفاده کنه.         services.AddTransient&lt;FarazService&gt;();
        services.AddTransient&lt;KavenegarService&gt;();
        services.AddTransient&lt;Func&lt;string, IGetwaySmsService&gt;&gt;(serviceProvider =&gt; key =&gt;
        {
            switch (key)
            {
                case &amp;quotKavenegar&amp;quot:
                    return serviceProvider.GetService&lt;KavenegarService&gt;();
                case &amp;quotFaraz&amp;quot:
                    return serviceProvider.GetService&lt;FarazService&gt;();
                default:
                    throw new NotImplementedException();
            }
        });نکته ای که بازم باید تکرار بشه این هست که در اینجا یک key  پاس داده شده و بر اساس همین key هست که مشخص میشه از کدوم سرویس استفاده بشه. اگر کلاس بالا رو نگاه کنید این key رو از طریق apsettings دارم میخونم. شما میتونید به هر روش دیگه ای این key رو پاس بدید :) .به این ترتیب شما هم میتونید بر اساس یک شرط هر بار یک Implementation از یک سرویس رو استفاده کنید.</description>
                <category>ضحی شبر</category>
                <author>ضحی شبر</author>
                <pubDate>Sat, 21 Jan 2023 21:52:18 +0330</pubDate>
            </item>
                    <item>
                <title>چطوری دیگه زحمت وارد کردن تک تک انتیتی ها رو در DbContext نکشیم؟!!</title>
                <link>https://virgool.io/@zoha_shobbar/%DA%86%D8%B7%D9%88%D8%B1%DB%8C-%D8%AF%DB%8C%DA%AF%D9%87-%D8%B2%D8%AD%D9%85%D8%AA-%D9%88%D8%A7%D8%B1%D8%AF-%DA%A9%D8%B1%D8%AF%D9%86-%D8%AA%DA%A9-%D8%AA%DA%A9-%D8%A7%D9%86%D8%AA%DB%8C%D8%AA%DB%8C-%D9%87%D8%A7-%D8%B1%D9%88-%D8%AF%D8%B1-dbcontext-%D9%86%DA%A9%D8%B4%DB%8C%D9%85-ioceklm6p8qq</link>
                <description>یکی از اتفاقات کسل کننده در نوشتن برنامه های که در اونها از Entity Framework استفاده میکنیم ثبت کردن تک به تک انتیتی ها یا همون مدل هامون توی فایل DbContext هست. این مساله زمانی بیشتر خسته کننده میشه که تعداد این مدل ها زیاد بشه. تصورش رو بکنید که اگر توی برنامه تون بالای 30 تا مدل داشته باشید چقدر تعداد کدهای فایل تون زیاد میشه و ممکنه خوانایی کدهاتون رو بیاره پایین.در حالت عادی وقتی ما میخوایم مدل هامون رو توی DbContext تعریف کنیم، به ازای هر کدوم از اون مدل ها یک DbSet می سازیم. و فایل DbContext ما تقریبا یه چنین چیزی میشه:public class DataContext : DbContext
{
      public DataContext(DbContextOptions options) : base(options) { }    
      public DbSet&lt;Employee&gt; Employees { get; set; }
      public DbSet&lt;Department&gt; Departments { get; set; }
      ...
}اما الان میخوام روشی رو معرفی کنم که دیگه نیاز نباشه تک تک این انتیتی ها رو دستی وارد کنید بلکه به صورت یکباره و داینامیک این کار انجام بشه. برای این کار لازمه یک کلاس Abstact یا یه Interface داشته باشیم تا تمام انتیتی هایی که میخوایم به صورت اتوماتیک add بشن ازش ارث بری کنن و اینطوری اونها رو شناسایی کنیم. من معمولا پراپرتی هایی که توی همه مدل هام هستن رو توی یه کلاس میگذارم از چنین کلاسی استفاده میکنم تا دیگه فیلدهای تکراری رو وارد نکنم:public abstract class BaseEntity
{
    public int Id { get; set; }
    public DateTime CreationDate { get; set; }
    public DateTime? LastModifiedDate { get; set; }
    public bool IsDeleted { get; set; }
}بعد از اون تمام مدل هام از این کلاس ارث بری می کنن. برای نمونه کلاس Employee  این طوری خواهد شد:public class Employee : BaseEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Position { get; set; }
    public string Office { get; set; }
    public int DepartmentId { get; set; }
    public Department Department { get; set; }
}حالا یه Extension method از ModelBuilder می سازم. توی این متد از Reflection استفاده شده و تمام کلاس هایی که از BaseEntity استفاده کردن رو پیدا میکنه و توی DbContext به عنوان یه انتیتی رجیستر میکنه:public static class ModelBuilderExtensions
{
    public static void RegisterAllEntities&lt;BaseType&gt;(this ModelBuilder modelBuilder, params Assembly[] assemblies)
        {
            IEnumerable&lt;Type&gt; types = assemblies.SelectMany(a =&gt; a.GetExportedTypes())
                                              .Where(c =&gt; c.IsClass &amp;&amp; !c.IsAbstract &amp;&amp; c.IsPublic &amp;&amp; 
                                               typeof(BaseType).IsAssignableFrom(c));
            foreach (Type type in types)
                modelBuilder.Entity(type);
        }
    }دقت داشته باشید که کد بالا داره کلاس abstact مورد نظر ما رو که اینجا BaseEntity هست رو به صورت جنریک دریافت میکنه و لازمه که موقع استفاده از این متد کلاسمون رو بهش معرفی کنیم.توی مرحله بعد کافیه از این متد توی OnModelCreating استفاده کنم. به این صورت:protected override void OnModelCreating(ModelBuilder modelBuilder)
{
        base.OnModelCreating(modelBuilder);
        var entitiesAssembly = typeof(BaseEntity).Assembly;
       modelBuilder.RegisterAllEntities&lt;BaseEntity&gt;(entitiesAssembly);        
    }حالا با خیال آسوده مایگریشن بزنید و کارتون رو ادامه بدید :) </description>
                <category>ضحی شبر</category>
                <author>ضحی شبر</author>
                <pubDate>Mon, 18 Jul 2022 01:49:02 +0430</pubDate>
            </item>
            </channel>
</rss>