مطالب
مدیریت اسپم‌ها در SignalR
سناریویی را در نظر بگیرید که در آن یک برنامه‌ی چت را با استفاده از SignalR نوشته‌اید و قصد دارید از آن در یک سایت شلوغ استفاده کنید. در حالت عادی برنامه به خوبی کار می‌کند؛ تا زمانیکه کسی شروع به ارسال Spam در سیستم چت شما نکرده باشد. برای کنترل ارسال spam، اولین راهی که به ذهن می‌رسد این است که سمت کلاینت کلید ارسال پیغام را چند ثانیه غیر فعال کنیم تا کاربران نتوانند در عرض به طور مثال 3 ثانیه، تعداد زیادی پیام را ارسال کنند. برای کاربران معمولی وب سایت ما این راه حل جواب می‌دهد و مشکلی نیست. ولی اگر کاربر وب‌سایت آشنایی مختصری با JavaScript و نحوه‌ی اتصال به signalR داشته باشد چطور؟ خیلی ساده می‌تواند در کنسول browser خود یک لوپ نوشته و شروع به ارسال spam به برنامه‌ی چت ما کند. اینجاست که مجبوریم به علاوه‌ی کنترل سمت کلاینت، سمت سرور هم زمان ارسال پیام‌ها را کنترل کنیم که در ادامه به یکی از روش‌های انجام این کار می‌پردازیم.

کد اولیه‌ی هاب چت برنامه:
<HubName("chat")>
Public Class ChatHub
    Inherits Hub
    Public Sub sendMessage(msg As String) 
         Clients.All.getMessage(msg) 'Call getMessage function client side
    End Sub
End Class
برای شروع کار ابتدا نیاز به کلاسی داریم که اطلاعات فعالیت‌های کانکشن‌ها را برای ما نگه‌داری کند:
Public Class ActivityInfo
    Sub New(connectionId As String)
        Me.ConnectionID = connectionId
        Me.Time = Now
    End Sub
    Public Property ConnectionID As String
    Public Property Time As DateTime
End Class
سپس برای اینکه بتوانیم تمامی درخواست‌های ارسالی از سمت کلاینت‌ها را مدیریت کنیم، به یک کلاس از نوع HubPipelineModule احتیاج داریم که ما در اینجا با استفاده از کلاس SpamDetectionPiplelineModule که از HubPipelineModule مشتق شده، این کار را انجام می‌دهیم.
Public Class SpamDetectionPiplelineModule
    Inherits HubPipelineModule
    Public Property SpamDetection As New HashSet(Of ActivityInfo)
    Private _SpamDetectionLock As New Object
    Public Function IsSpam(ConnectionId As String) As Boolean
        SyncLock _SpamDetectionLock
            'Remove all old info before 3 seconds ago
            SpamDetection.RemoveWhere(Function(q) q.Time < Now.AddSeconds(-3))

            SpamDetection.Add(New ActivityInfo(ConnectionId))

            'Check activities from 3 seconds ago
            If SpamDetection.Where(Function(q) q.ConnectionID = ConnectionId).Count > 2 Then
                Return True
            Else
                Return False
            End If
        End SyncLock
    End Function
    Protected Overrides Function OnBeforeIncoming(context As IHubIncomingInvokerContext) As Boolean
        If IsSpam(context.Hub.Context.ConnectionId) Then
            Return False
        End If
        Return MyBase.OnBeforeIncoming(context)
    End Function
End Class
در کدهای بالا ابتدا یک HashSet را جهت نگه داشتن فعالیت کاربران ایجاد کردیم که بعد از هر درخواستی که به سمت سرور ارسال می‌شود، به‌روز خواهد شد. متد OnBeforeIncoming قبل از اینکه درخواست کاربر به Hub برنامه برسد، اجرا می‌شود که میتوانیم با استفاده از آن، فعالیت‌های کانکشن کاربر را در طی چند ثانیه‌ی اخیر کنترل کنیم که برای مثال چه تعدادی درخواست را در طی 3 ثانیه‌ی قبل ارسال کرده است. اگر تعداد درخواست‌های ارسالی در طی 3 ثانیه‌ی قبل، بیشتر از تعداد مورد نظر ما بود، با بازگشت دادن False، از اجرای درخواست آن جلوگیری می‌کنیم. (در اینجا ما کاربران را به ارسال 2 پیام در طی هر 3 ثانیه، محدود کرده‌ایم).
حال برای استفاده‌ی از PipelineModule سفارشی خودمان، باید آن را قبل از مپ کردن SignaR، در StartUp برنامه اضافه کنیم:
Public Class Startup
    Public Sub Configuration(app As IAppBuilder)
        GlobalHost.HubPipeline.AddModule(New SpamDetectionPiplelineModule)
        app.MapSignalR
    End Sub
End Class
نظرات مطالب
روش نصب اندروید 10 بر روی گوشی‌های قدیمی سامسونگ
روش اصلاح daylight saving time در سیستم عامل اندروید


باتوجه به اینکه از امسال دیگر تغییر ساعت بهاری و تابستانی را نداریم، از ابتدای سال، سیستم عامل‌های اندرویدی، یک ساعت جلوتر را نمایش می‌دهند که در ابتدا تصور بر این بود که مشکل از اپراتورهاست، اما اینطور نیست! ساعت ارسالی توسط آن‌ها صحیح است. مشکل از قدیمی بودن بانک اطلاعاتی tzdata سیستم عامل‌های اندرویدی است.

نگارش جدید و کامپایل شده‌ی این فایل‌ها را از اینجا می‌توانید دریافت کنید: tzdata-new.zip

محل ذخیره شدن بانک اطلاعاتی time-zones در اندروید

بسته به نگارش اندروید شما، یکی از مکان‌های زیر، محل ذخیره سازی دو فایل tzdata و tz_version است:
/data/misc/zoneinfo/tzdata
/system/usr/share/zoneinfo
/apex/com.android.tzdata/etc/tz/tzdata
برای مثال بر روی اندروید 10 من (که روش نصب آن در این مطلب آمده)، مسیر آخری، مسیر اصلی و تاثیرگذار است.


مشکل! به روز رسانی مسیرهای سیستمی اندروید، نیاز به دسترسی root دارند!

تا اینجا مشخص شد که برای رفع مشکل time-zone و به روز رسانی اطلاعات آن، باید دو فایل tzdata و tz_version را در مسیرهای یاد شده، بازنویسی کنیم؛ اما ... اندروید چنین اجازه‌ای را نمی‌دهد!
در سیستم عامل LineageOS 17.1 ای که من نصب کردم، می‌توان با نصب برنامه‌ی معروف Magisk، دسترسی روت پیدا کرد. روش نصب آن هم به صورت زیر است:
1) فایل apk آن‌را از این آدرس دریافت کرده و پسوند آن‌را به zip. تغییر دهید.
2) سیستم را ری‌استارت کرده و رفتن به گزینه‌ی recovery را انتخاب کنید تا پس از ری‌استارت سیستم، وارد برنامه‌ی TWRP شویم (که روش نصب آن در مطلب جاری بحث شده).
3) در برنامه‌ی TWRP، گزینه‌ی install را انتخاب و سپس فایل zip. برنامه‌ی magisk را انتخاب و نصب کنید.
4) پس از نصب، یکبار هم کش را پاک کنید (Wipe cache/dalvik).
5) در آخر بر روی دکمه‌ی Reboot System تا ... وارد اندروید شوید.
 6) پس از راه اندازی سیستم، برنامه‌ی Magisk را اجرا کنید تا مرحله‌ی آخر نصب آن به پایان برسد (یکسری از فایل‌ها را نیاز دارد تا از اینترنت دریافت و نصب کند؛ این نصب، از github و به صورت خودکار است).

پس از نصب magisk، برنامه‌ی total commander را هم نصب کنید. به محض اجرای آن، پیام درخواست دسترسی root آن هم ظاهر می‌شود (این برنامه‌ی magisk هست که این درخواست را تشخیص داده و مدیریت می‌کند) و نیاز است این دسترسی را بدهید تا بتوان:
 1) به مسیر file system root و سپس apex/com.android.tzdata/etc/tz/tzdata وارد شد و دو فایل موجود و قدیمی tzdata و tz_version را به نحو متداولی پاک کرد.
 2) سپس دو فایل جدید tzdata و tz_version را (که لینک دریافت آن کمی بالاتر ارائه شد) به سیستم خود منتقل کنید (همانند تمام فایل‌های دیگر از طریق usb) و در آخر با استفاده از total commander ای که اکنون دسترسی root هم دارد، این فایل‌ها را به مسیر یاد شده، کپی کنید.
 3) اکنون سیستم را ری‌استارت کنید تا تنظیمات جدید خوانده شوند (همانند تصویر زیر، که در آن منطقه زمانی جدید 3:30+ قابل مشاهده‌است):

یک نکته: « Magisk-Modules-Repo / Systemless_TZData » در صورت به روز شدن، این کار نصب دستی tzdata را به صورت خودکار انجام می‌دهد که در زمان نگارش این مطلب، هنوز به‌روز نشده.

نظرات مطالب
VS Code برای توسعه دهندگان ASP.NET Core - قسمت دوم - ایجاد و اجرای اولین برنامه
در ادامه یکی از فایل‌های #C آن‌را گشوده و منتظر شوید تا کار دریافت خودکار بسته‌های مرتبط با افزونه‌ی #C ایی 
موقع دریافت اکستنشن‌ها به ارور زیر برخورد می‌کنم.
The editor could not be opened due to an unexpected error: XHR timeout: undefinedms
با ش.ک.ن‌ها مشکل حل می‌شود اما متاسفانه پایدار نیستند. راه حل بهتری به نظرتان می‌رسد؟
البته برای برخی از اکستنشن‌ها یک پیام دیگر می‌آید که اگر مایلید به صورت دستی فایل .vsxl رو دانلود کنید و نصب کنید که خوب راهگشاست. اما برای بعضی از اکستنشن‌ها این پیام نمی‌آید.
نظرات مطالب
اجرای وظایف زمان بندی شده با Quartz.NET - قسمت اول
با سلام؛ من برای ارسال پیامک‌های زمانبندی شده، از همین روش استفاده کردم، اما یک مشکل دارم.
اونم اینه که در صورتی که چند job به طور همزمان اجرا بشن تداخل پیدا میکنن. برای توضیح بیشتر، زمانی که چند job رو با عبارت cron یکسان ثبت میکنم -> مثلا:
0 33 10 * * ?
پس از اجرا و ارسال پیام که باید تراکنش مالی اون ثبت بشه(لازم به توضیح است که من عملیات ارسال پیام و ثبت تراکنشات مالی رو در متد execute نوشتم)، ثبت نمیشه و اجرای بقیه job‌ها ادامه پیدا میکنه. ممنون میشم بنده رو راهنمایی کنین.
نظرات نظرسنجی‌ها
ایجاد یک پیام رسان کدباز بومی با استقبال کاربران ایرانی روبرو میشود؟
در جواب مورد اول نباید فراموش کنیم که توصیه کارشناسان و متخصصان توی رواج یک پیام رسان یا شبکه اجتماعی بی تاثیر نیست، اتفاقی که در ابتدای کار برای خود تلگرام هم رخ داد و بسیاری از عامه مروم به توصیه افراد متخصص در این زمینه(بخاطر امنیت و کیفیت بالا) به سمت این اپ رفتن.
اما باقی مواردی که مطرح کردید الزاما در مورد پیام رسان‌ها نیست و در موردهمه اپ‌های ایرانی مصداق پیدا میکنند، که البته باید ببینین واقعا هیچ اپ کارامد و در کلاس جهانی در ایران تولید نشده است تا کنون؟! 
مطالب
بررسی اجمالی Redis
نام Redis از Remote Dictionary server گرفته شده‌است. Redis یکی از محبوب‌ترین key-value store‌ها می‌باشد و هم چنین توسط برند‌های بزرگ IT جهان استفاده می‌شود. لازم به ذکر است  Amazon Elastic Cache از Redis پشتیبانی می‌کند. Redis یک دیتابیس No SQL است و بر روی مفهوم زوج  کلید-مقدار (key-value ) کار می‌کند. key-value store امکانی را برای ذخیره داده‌ها که Value  نامیده میشود، در یک Key فراهم می‌کند. شما می‌توانید بعدا این داد‌ه‌ها را دریافت کنید، تنها اگر نام دقیق کلیدی را که برای ذخیره داده استفاده کرده‌اید، بدانید.

What Is In-Memory, Key-Value Store  

Key-Value store یک سیستم ذخیره سازی است؛ جایی که داده‌ها به صورت زوج کلید-مقدار ذخیره می‌شوند. وقتی که میگوییم in-memory key-value store (زوج کلید-مقدار مقیم در حافظه)، منظور این است که زوج کلید-مقدار در حافظه اصلی RAM ذخیره می‌شوند. بنابراین می‌توانیم بگوییم Redis داده‌ها را در حافظه به شکل زوج کلید-مقدار ذخیره کرده است. 
در Redis کلید‌ها باید string باشند؛ ولی value ‌ها می‌توانند یک string ، list ، set ، sorted set یا hash باشند. 
 
Advantage And Disadvantage of Redis over DBMS  

Database Management systems همه چیز را در حافظه ثانویه ذخیره می‌کند که باعث می‌شود خواندن و نوشتن عملیات، تا اندازه‌ای کند باشد. این در حالی است که Redis  همه چیز را در حافظه اصلی ذخیره می‌کند و همین موضوع باعث می‌شود که خواندن و نوشتن داده‌ها توسط آن خیلی سریع باشند. 
حافظه اصلی محدود است. بنابراین Redis نمی‌تواند فایل‌های بزرگ یا binary data را ذخیره کند و تنها اطلاعات متنی کوچک را ذخیره می‌کند که نیاز است قابل دسترسی و اصلاح باشند و با نرخ خیلی سریعی قابل درج باشند. اگر تلاش کنیم که داده‌های بیشتری را نسبت به حافظه موجود بنویسیم، در این حالت خطا دریافت خواهیم کرد.

 Redis  RDBMS
Redis  همه چیز را در حافظه اصلی ذخیره می‌کند. RDBMS همه چیز را در حافظه ثانویه ذخیره می‌کند.
در Redis بخاطر ذخیره سازی داده‌ها در حافظه اصلی، خواندن و نوشتن عملیات به شدت سریع می‌باشد. در RDBMS بخاطر ذخیره سازی داده‌ها در حافظه ثانویه، خواندن و نوشتن
عملیات کند است.
حافظه اصلی از نظر size کوچکتر و از لحاظ قیمت نسبت به حافظه ثانویه گرانتر می‌باشد. Redis نمی‌تواند داده‌های بزرگ یا binary data را ذخیره کند.    حافظه ثانویه از نظر size  بزرگتر و از لحاظ قیمت نسبت به حافظه اصلی ارزان‌تر می‌باشد. RDBMS به آسانی می‌تواند با انواع فایل‌ها کار کند.   


Redis Advantages

  • Redis  : Exceptionally fast خیلی سریع است و می‌تواند حدود 110000  ، SET   و 81000 ،  GET را به ازای هر ثانیه انجام دهد.
  • Redis : Supports rich data type بیشتر دیتا تایپ‌ها را  که توسعه دهندگان قبلا آن‌ها را شناخته‌اند، پشتیبانی می‌کند؛ از قبیل string ، list ، set ، sorted set یا hash .
  •  Operations are atomic  : تمام عملیات Redis اتمیک می‌باشند که این اطمینان خاطر را میدهد اگر دو کلاینت به صورت همزمان به آن دسترسی داشته باشند، Redis server مقدار update شده را دریافت خواهد کرد. 
  • Redis : Multi-utility tool یک ابزار چند منظوره است که می‌تواند در برخی از سناریو‌ها استفاده شود از قبیل:  Redis ) messaging-queues , caching   به صورت بومی از Publish/Subscribe پشتیبانی می‌کند ) , هر داده ای با طول عمر کوتاه در Application مانند web application sessions , ... .
 

Redis Single Instance Architecture 

معماری Redis شامل دو پروسه اصلی است: 
1- Redis client
2- Redis Server


Redis client و Redis Server هر دو می‌توانند در یک کامپیوتر یا کامپیوتر‌های متفاوت باشند. Redis server مسئول ذخیره سازی داده‌ها در حافظه می‌باشد. همانطور که متوجه هستیم، Redis همه چیز را در حافظه اصلی ذخیره می‌کند و حافظه اصلی فرار است؛ از این رو زمانیکه Redis server یا کامپیوتر را راه اندازی مجدد (restart) می‌کنیم، همه داده‌های ذخیره شده را از دست خواهیم داد. بنابراین نیازمند یک راه‌حل، جهت ماندگاری datastore می‌باشیم. 


Redis Persistance 
 
سه راه متفاوت وجود دارد که Redis را پایدار می‌کند : RDB ، AOF و دستور SAVE

1-  RDB : RDB Mechanism یک نمونه از تمام داده‌های در حافظه را تهیه و آن‌ها را در حافظه ثانویه ذخیره می‌کند (ذخیره سازی ماندگار) که در یک وقفه مشخص اتفاق می‌افتد. بنابراین این شانس وجود دارد که شما داده‌هایی را از دست بدهید که بعد از آخرین Set , RDB’s snapshot  شده‌اند . 

2-AOF : AOF همه عملیات نوشتن دریافت شده توسط سرور را ثبت می‌کند. بنابراین همه چیز پایدار است. مشکل استفاده از AOF  این است که برای هر عملیات، شروع به نوشتن در دیسک می‌کند و این یک کار هزینه‌بر است و هم چنین اندازه فایل AOF بزرگتر از RDB می‌باشد. 

3-SAVE Command : شما می‌توانید Redis server را مجبور کنید که یک RDB snapshot را ایجاد کند؛ هر زمانکه Redis console client از دستور SAVE استفاده می‌کند.

در ضمن می‌توانید از AOF  و RDB با هم استفاده کنید تا بهترین نتیجه ماندگاری را داشته باشید. 
 
Redis Replication 

Replication یک تکنیک است که کامپیوتر‌ها را درگیر می‌کند تا دسترسی پذیری داده‌ها و تحمل خطا را با ضریب بیشتری امکان پذیر کنند. در یک محیط Replication، کامپیوتر‌ها، داده‌های یکسانی را با یکدیگر به اشتراک می‌گذارند؛ حتی اگر چندین کامپیوتر دچار مشکل شوند، باز هم، همه داده‌ها در دسترس خواهند بود که به صورت Master/Slaves  می‌باشند.


تمام slave‌ها شامل داده‌های یکسانی همانند master می‌باشند. وقتی‌که یک slave جدید در محیط Replication ایجاد می‌شود، master به صورت خودکار همه داده‌ها را با sync ، slave می‌کند.
تمام Query ‌ها به سرور master هدایت می‌شوند و سپس سرور master عملیات را اجرا می‌کند. وقتی‌که یک عملیات نوشتن اتفاق می‌افتد، سرور master داده‌هایی را که به‌تازگی نوشته شده‌اند، در تمام slave‌ها تکثیر می‌کند. 
 اگر اتفاقی در سرور master رخ دهد، تمام داده‌ها از بین می‌روند؛ در این حالت باید یک slave را به master تبدیل کنیم. 

Clustering In Redis 

Clustering یک تکنیک می‌باشد که توسط آن می‌توان داده‌ها را در چندین کامپیوتر تقسیم بندی کرد. فرض کنید که یک سرور Redis را با 64GB حافظه در اختیار داریم. در این حالت می‌توانیم 64GB داده داشته باشیم. اگر  10 تا clustered computer را که هر کدام 64GB حافظه اصلی دارند، داشته باشیم، در این حالت می‌توان 640GB  داده را ذخیره کرد. 
 

در تصویر بالا می‌توانیم ببینیم که داده‌ها در چهار node، ذخیره شده‌اند. هر node یک Redis Server پیکربندی شده می‌باشد؛ به عنوان یک cluster node. اگر یکی از node ‌ها دچار مشکل شوند، سپس کل cluster متوقف می‌شود. 

Redis Client 

وب سایت Try Redis ، یک Redis console client  آنلاین است و به شما کمک می‌کند تا یاد بگیرید چگونه از Redis console client  استفاده کنید.


در قسمت بعد در رابطه با نصب Redis  بر روی سیستم عامل ویندوز و دیتا تایپ‌ها در Redis صحبت خواهیم کرد.
اشتراک‌ها
رندر سمت سرور کامپوننت‌های Blazor در دات نت 8

  The "Blazor United" effort is really a collection of features we're adding to Blazor so that you can get the best of server & client based web development. These features include: Server-side rendering, streaming rendering, enhanced navigations & form handling, add client interactivity per page or component, and determining the client render mode at runtime. We've started delivering server-side rendering support for Blazor with .NET 8 Preview 3, which is now available to try out. We plan to deliver the remaining features in upcoming previews. We hope to deliver them all for .NET 8, but we'll see how far we get. 

رندر سمت سرور کامپوننت‌های Blazor در دات نت 8
اشتراک‌ها
معماری Vertical Slice بهتر است از کار با لایه‌ها!

Vertical Slice Architecture, not Layers! 

Why Vertical Slice Architecture? Nobody wants to deal with a system that is hard to change and easy to introduce bugs because it's a spaghetti code mess of various technical concerns. Clean Architecture is popular because it separates concerns into many different layers. But why are we organizing code by layers? Does adding a new feature require you to modify files across multiple projects in your UI, business, and data access layers? Vertical Slice Architecture is about how you organize code and focus on features instead of technical layers will make your system easier to change. 

معماری Vertical Slice بهتر است از کار با لایه‌ها!
اشتراک‌ها
نگاهی به نوع‌های جدید DateOnly و TimeOnly در NET 6.

In .NET 6 (preview 4), two long-awaited types have been introduced as part of the core library. DateOnly and TimeOnly allow developers to represent either the date or time portion of a DateTime. These two new types are structs (value types) and may be used when your code deals with date or time concepts independently. Both types can be found in the System namespace. Using these new types may align well with how databases allow similar data to be represented. Specifically, these types align well with the SQL Server date and time data types. 

نگاهی به نوع‌های جدید DateOnly و TimeOnly در NET 6.
اشتراک‌ها
با سی شارپ 8 از دست NullReferenceExceptions ها خلاص شوید

A .NET guideline specifies that an application should never throw a NullReferenceException. However, many applications and libraries do. The NullReferenceException is the most common exception happening. That’s why C# 8 tries to get rid of it. With C# 8, reference types are not null be default. This is a big change, and a great feature. However, what about all the legacy code? Can old libraries be used with C# 8 applications, and can C# 7 applications make use of C# 8 libraries?

This article demonstrates how C# 8 allows mixing old and new assemblies. 

با سی شارپ 8 از دست NullReferenceExceptions ها خلاص شوید