نظرات مطالب
پرسش و پاسخ‌های متداول ایجاد یک وبلاگ بلاگری
تاریخ بالای سایت شما از روش دوستان استفاده کرده.
به قسمت ویرایش html بلاگ مراجعه کنید. این مورد را باید دستی حذف کنید. مواردی که به قالب شما به صورت پیش فرض اعمال شده این‌جا توضیح داده شده است:
http://docs.blogger-fa.com/2008/09/blogger-persian-date.html
اشتراک‌ها
شماهای استاندارد

در این صفحه شما‌های زیاد به صورت موضوع دسته بندی شده که می‌توانید در تگ‌های html استفاده کرده تا حتی رتبه شما در پیش جست و جو گر‌ها و نتیجه جست و جو بر روی وب سایت شما بهینه‌تر بشه

شماهای استاندارد
مطالب
کنترل شرایط تاثیرگذار بر روی یک نقش در ASP.NET MVC
در سایت جاری، مباحث زیادی در مورد دسترسی یک نقش به اکشن متدها مطرح شده است. در این مقالات یاد گرفته‌ایم اگر اکشن متدی به ویژگی Authorization مزین گردد، دسترسی این اکشن متد تنها به کاربران لاگین شده خلاصه شده و اگر پارامتر Roles را با نام نقش‌ها مقداردهی کنیم، تنها کاربرانی که آن نقش را دارند، به این اکشن متد دسترسی خواهند داشت. ولی گاهی اوقات شرایطی ایجاد میشود که مشخص نیست این نقش در حال حاضر باید دسترسی به اکشن متد مورد نظر را داشته باشد یا خیر؛ این مثال را در نظر بگیرید:
در یک سیستم حسابداری یا هر سیستم مشابهی، موقعی که یک سند در سیستم درج میشود، نقش‌های زیادی میتوانند درگیر این عمل باشند:
Create می تواند یک سند حسابداری را ایجاد کند.
Edit میتواند یک سند حسابداری را ویرایش کند.

کاربری که نقش edit را دارد توانایی ویرایش اسناد درج شده در سیستم را دارد ولی اسناد حسابداری تنها در همان روز ثبت، امکان ویرایش دارند و پس از پایان ساعاتی کاری یا از روز بعد دیگر قابل ویرایش نبوده و نباید کسی توانایی ویرایش آن را داشته باشد. به همین دلیل، در این نقطه زمانی، دیگر کاربر Edit نباید بتواند این اکشن متد را صدا بزند. به همین علت باید دسترسی او را بر روی سندهای ماقبل امروز بست.

با نگاهی بر روی بسیاری از کدهای نرم افزارهای مختلف که نوشته شده‌اند میتواند دریافت بسیاری از افراد در اکشن مربوطه یا هر دو اکشن Get و Post یک شرط قرار داده و با بررسی اینکه سند متعلق به امروز نیست پیامی را به کاربر نمایش میدهند؛ ولی این نکته باعث میشود که اکشن متد مربوطه تا حدی اولین اصل از اصول Solid یعنی اصل تک مسئولیتی را زیر سوال ببرد. ما در اینجا قصد داریم این موضوع بررسی را به خارج از اکشن متد مربوطه برده و قبل از رسیدن به اکشن متد مورد نظر جلوی آن را بگیریم.

با گردآوری و جمع بندی مطالب سایت تاکنون می‌توان تکه کد زیر را نوشت: 
در سایت جاری مباحث فیلترها (^ و ^) به طور مکرر مورد بررسی قرار گرفته‌است. طبق منابع ذکر شده یکی از این اکشن متدها ActionFilter بوده که دو متد زیر را در اختیار ما قرار می‌دهد:
// Called after the action method executes
void OnActionExecuted(ActionExecutedContext filterContext)

// Called before an action method executes
void OnActionExecuting(ActionExecutingContext filterContext)
اولین متد بعد از اجرای اکشن متد و دومی قبل از آن صدا زده میشود. از آنجا که ما نیاز داریم کاربر قبل از رسیدن به اکشن متد مسدود گردد؛ متد OnActionExecuting را بازنویسی میکنیم:
    public class BlockDocument : ActionFilterAttribute
    {
        public Func<IDocumentServices> _documentServices { get; set; };

        public string ParamName;
      
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {           
            var id = 0;
            if (filterContext.ActionParameters.ContainsKey(ParamName))
            {
                id =(int) (filterContext.ActionParameters[ParamName]??0);
            }
            if (IsInvalid(id))
            {
                return;
            } 
            var document = _documentServices().GetDocument(id);
            if (document.InserTime.IsPassed())
            {
                filterContext.Result = new HttpStatusCodeResult(403);
            }
        }
    }
در اینجا با استفاده از تزریق وابستگی‌ها و یک FilterProvider سفارشی، سرویس DocumentServices را در یک Func که باعث تاخیر در بارگذاری سرویس تا زمان استفاده از آن می‌گردد قرار میدهیم. سپس پارامتری که کد یا مشخصه‌ای از سند را داراست از ورودی دریافت کرده و بررسی می‌کنیم که آدرس مربوطه شامل این مشخصه میباشد یا خیر. در صورتیکه مشخصه صحت داشته باشد، سند را از طریق سرویس واکشی کرده و اگر زمان درج سند از محدوده زمانی خارج شده باشد، کاربر را به صفحه 403 هدایت میکنیم.
[BlockDocument(ParamName = "id")]
public ActionResult EditDocument(int id)
{
            //...
}
در نهایت اکشن متد مربوطه را به فیلتر نوشته شده مزین میکنیم.
نظرات مطالب
توسعه برنامه های Cross Platform با Xamarin Forms & Bit Framework - قسمت پنجم
در قسمت وصل شدن گوشی اپل به ویژوال استادیو تمام موارد طبق توضیحات شما انجام دادم ولی متاسفانه در قسمت Properties پروژه XamApp.iOS، به تب iOS Bundle signing  که وارد می‌شوم با وجود اینکه در ویژال استادیو با  Apple ID     لاگین کرده ام ولی متاسفانه  Team برای من وجود ندارد یعنی چیزی نمایش داده نمی‌شود. برای نمایش آیا باید کار خاصی را انجام بدهم؟
مطالب
روش نصب اندروید 10 بر روی گوشی‌های قدیمی سامسونگ
چند سال قبل یک گوشی Samsung galaxy J7 را که به صورت پیش‌فرض به همراه اندروید 6 است، تهیه کردم. الان حدود دو هفته‌ای است که اندروید 10 را از طریق LineageOS بر روی این گوشی نصب کرده‌ام که در ادامه روش نصب آن‌را برای علاقمندان توضیح خواهم داد.


LineageOS چیست؟

یکی از مهم‌ترین مزایای استفاده از گوشی‌های اندرویدی نسبت به iOS ای، آزادی نصب نرم افزار و خصوصا سیستم عامل‌های مختلف بر روی آن‌ها است. در حال حاضر، محبوب‌ترین و پر استفاده‌ترین نگارش آزاد اندروید که مستقل از گوگل عمل می‌کند، LineageOS نام‌دارد (لی‌نی‌ایج OS) که پیشتر با نام‌های CyanogenMod و قبل از آن، Cyanogen (سیانوژن) ارائه می‌شد. یکی از مهم‌ترین مزایای آن، امکان نصب آخرین نگارش اندروید بر روی گوشی‌هایی است که دیگر پشتیبانی رسمی نمی‌شوند و خط تولید آن‌ها خاتمه یافته‌است.
به LineageOS یک Custom ROM هم گفته می‌شود. ROM مخفف read-only memory است و دقیقا جائی‌است که هسته‌ی Android در آن مشغول به کار است. بنابراین منظور از Custom ROM، همان نگارش سفارشی از Android است. به عملیات نصب LineageOS در اصطلاح Flashing هم گفته می‌شود که به معنای بازنویسی قسمتی از یک نرم‌افزار، با نرم‌افزار دیگری است.


پیشنیازهای ضروری نصب LineageOS

- داشتن یک گوشی یا تبلت سازگار با آن (متاسفانه سایت lineageos.org با IP ایرانی باز نمی‌شود)
- دسترسی به یک کابل USB مخصوص گوشی
- داشتن یک کامپیوتر دسکتاپ و یا لپ‌تاپ
- دسترسی به اینترنت
- زمان! ... (انجام این عملیات برای من در بار اول، حدودا یک روز طول کشید! (صرف نظر از تحقیقات یک هفته‌ای روش انجام آن) البته نه به علت طولانی بودن زمان نصب آن، بلکه به علت وجود نکات ریزی که در هیچ مستنداتی، به صورت مدون پیدا نخواهید کرد و عدم آشنایی با آن‌ها ممکن است سبب بروز حمله‌ی قلبی، به علت در دست داشتن سخت افزاری شود که هم اکنون کل آن‌را فرمت کرده‌اید و ... راهنماهای ارائه شده‌ی در اینترنت هم بر روی آن کار نمی‌کنند! به یک چنین سخت افزاری، brick یا «پاره آجر» هم گفته می‌شود!)


دریافت Custom ROM سازگار با گوشی یا تبلت

مرحله‌ی اول نصب LineageOS، دریافت Custom ROM آن است. برای این منظور به آدرس download.lineageos.org مراجعه کرده و ابتدا از منوی سمت چپ صفحه، گوشی خود را پیدا کنید و سپس با انتخاب آن، امکان دریافت ROM مخصوص آن‌را خواهید یافت.

نکته‌ی مهم! متاسفانه در اولین دریافت من از این سایت، به علت ناقص بودن دانلود، فایل دریافتی به همراه CRC Error بود و در زمان نصب فایل zip آن، خطای کلی e1001 ظاهر شد و نه هیچ چیز دیگری. این لحظه واقعا لحظه‌ای است که ممکن است عرق سرد بر روی پیشانی شما ظاهر شود! به صورت اتفاقی با بررسی فایل zip آن بر روی کامپیوتر متوجه شدم که فایل، ناقص دریافت شده. به همین جهت پیش از شروع به نصب، فایل zip را در یک برنامه‌ی باز کننده‌ی آن‌ها مانند winrar و یا 7-zip باز کرده و بر روی دکمه‌ی test آن‌ها کلیک کنید. اگر خطایی را گزارش ندادند، شروع به ادامه‌ی مراحل نصب کنید.


دریافت فایل Recovery سفارشی

در اینجا نیاز است با دو واژه‌ی جدید bootloader و recovery آشنا شد. زمانیکه گوشی خودتان را روشن می‌کنید، اولین نرم افزاری که حتی پیش از سیستم عامل اجرا می‌شود، bootloader نام دارد که کار آن آغاز سایر پروسه‌ها است. بعد از بارگذاری بوت‌لودر، برنامه‌ی دیگری به نام recovery، کار بارگذاری سیستم عامل را انجام می‌دهد. بوت‌لودر و recovery پیش‌فرض اندروید، اجازه‌ی نصب یک custom ROM را نمی‌دهند. به همین جهت نیاز است این برنامه‌ی recovery را با یک نمونه‌ی سفارشی بازنویسی کرد که این نمونه‌ی سفارشی در اینجا TWRP نام دارد و نمونه‌ی مخصوص گوشی خود را می‌توانید با جستجوی در لیست https://twrp.me/Devices دریافت کنید. ابتدا نوع گوشی و سپس مدل آن‌را یافته و سپس در صفحه‌ای که ظاهر می‌شود، بر روی download link آن کلیک کنید تا لیست فایل‌های موجود ظاهر شوند. در ابتدا آخرین نگارش موجود را دریافت کنید.

یک تجربه! متاسفانه آخرین نگارش TWRP دریافت شده، بر روی گوشی من کار نکرد و پس از نصب آن، مدام وارد همان سیستم عامل قبلی، با ارائه‌ی پیام «Recovery is NOT SEANDROID Enforcing» می‌شد و هیچ تاثیری را نداشت. در این حالت نصب نگارش قدیمی‌تر 3.3.1، کار کرد. بنابراین بهتر است چندین نگارش آن‌را دریافت کنید؛ تا در صورت لزوم بتوانید یکی یکی، آن‌ها را آزمایش کنید.


دریافت Google Apps

LineageOS به همراه برنامه‌های گوگل، مانند play store و امثال این‌ها نیست. به همین جهت نیاز است آن‌ها را از آدرس https://opengapps.org دریافت کنید. در اینجا دقت داشته باشید که چه چیزی را انتخاب می‌کنید! برای نمونه برای گوشی من گزینه‌های ARM، نگارش 10 و pico انتخاب شدند و سپس کلیک بر روی دکمه‌ی دانلود. گزینه‌ی pico، یکی از کم حجم‌ترین نگارش‌ها است و همینقدر برای شروع به کار، کافی است. نگارش را 10 انتخاب می‌کنیم چون می‌خواهیم اندروید 10 را نصب کنیم و انتخاب معماری CPU گوشی هم مهم است. با استفاده از برنامه‌ای مانند device info، به برگه‌ی CPU آن مراجعه کرده و CPU Type گوشی خود را دقیق بررسی کنید. اگر مانند گوشی من، 32bit بود، باید ARM را انتخاب کنید و اگر 64bit بود، گزینه‌ی ARM64 را انتخاب کنید و اگر یک گوشی قدیمی را مانند ASUS دارید، ممکن است CPU آن از نوع intel و x86 باشد.



دریافت برنامه‌ی فعالسازی دسترسی root

اگر می‌خواهید دسترسی root هم داشته باشید (این گزینه اختیاری است و من آن‌را نصب نکردم)، در نگارش‌های قبلی LineageOS از برنامه‌ای به نام SU برای انجام اینکار استفاده می‌شد. این برنامه دیگر نگهداری نمی‌شود و نباید آن‌را به همراه آخرین نگارش LineageOS نصب کرد (خیلی مهم!)؛ وگرنه گوشی شما را حتما به هم خواهد ریخت. برنامه‌ی جایگزین آن Magisk نام دارد که باز هم من آن‌را توصیه نمی‌کنم! چون اگر به انجمن‌های LineageOS مراجعه کنید، مشاهده شده‌است که پس از نصب به روز رسانی‌های جدید هفتگی LineageOS، ممکن است به علت عدم سازگاری با Magisk، سیستم عامل گوشی شما بالا نیاید و در یک حلقه‌ی بی‌پایان قرار بگیرید. به همین جهت بهتر است از این گزینه صرفنظر کنید.



آماده سازی گوشی برای اتصال USB و اجرای فرامین بر روی آن

مرحله‌ی بعد، نصب برنامه‌ی recovery سفارشی است. برای اینکار نیاز است گوشی خود را توسط سیم USB، به یک کامپیوتر متصل کرده و سپس توسط برنامه‌ای خاص که در ادامه معرفی می‌شود، برنامه‌ی TWRP را بر روی آن نصب کرد. به همین جهت به قسمت «تنظیمات» گوشی اندرویدی خود رفته و گزینه‌ی «درباره‌ی دستگاه (About)» را پیدا کنید. سپس بر روی شماره‌ی build آن «Build Number»، هفت بار ضربه بزنید. اینکار سبب می‌شود تا یک منوی مخفی به نام «Developer Mode» یا «گزینه‌های توسعه دهندگان/برنامه نویسان»، به لیست منوهای تنظیمات سیستم عامل فعلی اضافه شود. پس از فعال شدن «Developer Mode»، به این گزینه وارد شده و دو گزینه‌ی زیر را در آن فعال کنید:
- USB debugging
- OEM unlocking

اکنون اگر گوشی خود را از طریق سیم USB به کامپیوتر متصل کنید، یک دیالوگ باکس پرسشی، در اندروید جاری ظاهر می‌شود که درخواست دسترسی به ADB را از شما سؤال می‌پرسد. گزینه‌ی «Always Allow From This Computer» را انتخاب کرده و با کلیک بر روی OK، این دسترسی را فعال کنید.



دریافت برنامه‌های انتقال اطلاعات به گوشی اندرویدی

پس از دریافت فایل‌های مورد نیاز (TWRP.img, firmware.zip و gapps.zip)، اکنون نوبت به نصب TWRP.img است تا برنامه‌ی recovery پیش‌فرض گوشی را با یک نمونه‌ی سفارشی که امکان نصب custom ROM را میسر می‌کند، بازنویسی کنیم. بر روی گوشی‌های سامسونگ، برنامه‌ی ODIN یک چنین قابلیتی را به همراه دارد.


البته اگر کمی جستجو کنید، به دستورات زیر هم خواهید رسید که توسط برنامه‌ی Minimal_ADB_Fastboot قابل اجرا هستند:
adb devices
adb reboot bootloader
fastboot devices
fastboot flash recovery TWRP.img
fastboot reboot-bootloader
من تمام این دستورات را آزمایش کردم و بر روی گوشی سامسونگ کار نکردند! اما ODIN کار کرد.
البته برنامه‌ی Minimal_ADB_Fastboot، برنامه‌ی بسیار مفیدی است و در ادامه کاربردهایی از آن‌را مطالعه خواهید کرد.


بررسی امنیتی مهم! آیا فایل ROM دریافت شده، بر روی گوشی من نصب می‌شود؟!

در ادامه پیش از نصب، یکبار گوشی را فرمت می‌کنیم. در این حال اگر در حین نصب، پیام سازگار نبودن فایل ROM را دریافت کنیم، بسیار دیر است! به همین جهت پس از نصب برنامه‌ی Minimal_ADB_Fastboot، به پوشه‌ی آن وارد شده و خط فرمان را در آنجا آغاز کنید. برای این منظور فقط کافی است بر روی فایل cmd-here.exe کلیک کنید. سپس فرامین زیر را اجرا کنید (با این فرض که گوشی شما از طریق سیم USB به کامپیوتر متصل است و همچنین دسترسی دیباگی را هم که در گوشی عنوان شد، داده‌اید):
adb devices
adb shell getprop ro.product.device
adb shell getprop ro.build.product
دستور اول، adb server را اجرا کرده و سیستم شما را به گوشی متصل می‌کند. همچنین یک id را هم نمایش می‌دهد که نشان از موفقیت آمیز بودن اتصال دارد. دو دستور بعدی، شماره دستگاه و مدل آن‌را بازگشت می‌دهند. این خروجی‌ها را به دقت بخاطر بسپرید.
سپس فایل custom ROM دریافت شده را باز کرده و به پوشه‌ی «META-INF\com\google\android» آن وارد شوید. در اینجا فایل متنی updater-script را باز کنید. برای مثال در مورد گوشی من، چنین سطری در ابتدای آن درج شده:
assert(getprop("ro.product.device") == "j7elte" || getprop("ro.build.product") == "j7elte"
|| abort("E3004: This package is for device: j7elte; this device is " + getprop("ro.product.device") + "."););
این سطر، دقیقا بررسی می‌کند که اگر خاصیت‌های ro.build.product یا ro.product.device مساوی j7elte نبودند، کل عملیات نصب، abort شود.
بنابراین حتما پیش از مطالعه و اجرای ادامه‌ی بحث، مقادیر این ویژگی‌ها را با سطر اول فایل updater-script انطباق دهید تا اگر یکی نبودند، به اشتباه گوشی خود را فرمت نکنید!
البته در جائی دیدم که عده‌ای برای «خوراندن» rom سفارشی دریافت شده، این سطر بررسی را از فایل یاد شده، پاک کرده و سپس فایل zip جدیدی را تولید و نصب کرده‌اند. بهتر است اینکار را نکنید و با جستجوی دقیق مطمئن شوید که یک چنین تغییری، برای سیستم شما مشکلی را ایجاد نمی‌کند!


بازنویسی برنامه‌ی recovery گوشی توسط ODIN

پس از دریافت برنامه‌ی odin، نیاز است گوشی خود را خاموش کنید. فرض بر این است که پیشتر حداقل از contacts خود پشتیبان تهیه کرده‌اید. چون از این قسمت به بعد، به مراحل بدون بازگشتی قدم خواهیم گذاشت و قرار است گوشی را کاملا فرمت کنیم!
پس از خاموش کردن گوشی، اکنون نیاز است گوشی را در حالت download بالا بیاوریم. برای اینکار سه دکمه‌ی Volume Down + Home + Power با هم بفشارید. بنابراین ابتدا دکمه‌ی «کاهش صدا» را نگه دارید و رها نکنید، سپس دکمه‌ی home را نگه دارید و رها نکنید و در آخر دکمه‌ی power را نگه دارید تا گوشی به حالت ویژه‌ی download وارد شود.
البته در ابتدا یک صفحه‌ی اخطار را نمایش می‌دهد که در آن درج شده برای ادامه نیاز است دکمه‌ی «افزایش صدا» را بفشارید.


پس از ظاهر شدن تصویر فوق، اینبار دکمه‌ی «افزایش صدا» را بفشارید تا وارد حالت دانلود شوید. در اینجا «حالت دانلود» یعنی گوشی قابلیت دریافت فایلی را پیدا کرده‌است.


پس از بالا آوردن گوشی در حالت دانلود، برنامه‌ی odin را باز کنید:


- در اینجا در قسمت AP، فایل tar مربوط به TWRP را انتخاب کنید.
- سپس در برگه‌ی options، تیک گزینه‌ی Auto reboot را بردارید (بسیار مهم!). اگر این تیک را برندارید، پس از کار نوشتن برنامه‌ی recovery سفارشی، گوشی شما reboot شده و ... وارد برنامه‌ی recovery ... نمی‌شود! چون سیستم امنیتی توکار اندروید، آن‌را با نمونه‌ی اصلی جایگزین می‌کند!
- اکنون بر روی دکمه‌ی start کلیک کنید تا کار بازنویسی شروع شود.

پس از پایان بازنویسی برنامه‌ی recovery، باید وارد این برنامه‌ی جدید بشویم که روش ورود به آن به صورت زیر است:
پس از پایان بازنویسی، در بعضی از گوشی‌ها در همین حالت که گوشی، حالت download را نمایش می‌دهد، اگر ترکیب کلید‌های «Volume Up + Power + Home» را بفشارید (اینبار دکمه‌ی «افزایش صدا» است و نه کاهش صدا)، وارد این برنامه‌ی recovery جدید می‌شوید. اما در مورد گوشی من چنین چیزی رخ نداد. در این حالت تنها روشی که پاسخ داد، «خارج کردن باطری گوشی» بود (در همین حالتی که صفحه‌ی آبی رنگ download نمایش داده می‌شود، باطری را خارج کنید)؛ چون حتی در حالت خاموش کردن معمولی هم برنامه‌ی recovery سفارشی را پاک و نمونه‌ی اصلی را جایگزین می‌کرد!
سپس سیستم را به صورت معمولی روشن نکنید. اینبار نیاز است وارد منوی recovery شویم. بنابراین مجددا باطری را قرار داده و اینبار با فشردن ترکیب کلید‌های «Volume Up + Power + Home» به منوی جدید recovery وارد خواهیم شد.


مرحله‌ی آخر! نصب سیستم عامل جدید و برنامه‌های گوگل

تا اینجا باید وارد منوی recovery جدید شده باشید. روش خارج کردن باطری را هم فراموش نکنید! (چون اگر سیستم به صورت معمولی ری‌استارت شود، یا حتی به صورت معمولی خاموش شود، برنامه‌ی recovery سفارشی را بی‌اثر کرده و پاک می‌کند)
- پس از بارگذاری برنامه، پیام «Swipe to Allow Modifications» ظاهر می‌شود. برای این منظور، فلش آبی رنگ ظاهر شده را به سمت راست بکشید تا بتوانید وارد برنامه شوید.
- اکنون این مراحل را طی کنید:

الف) انتخاب Wipe


در اینجا در ابتدا گزینه‌ی Format Data را انتخاب کنید.


سپس مجددا فلش آبی رنگ پایین صفحه را به سمت راست بکشید تا کار فرمت کردن سیستم شروع شود.
در ادامه در همین قسمت گزینه‌ی Advanced Wipe را انتخاب کرده (همیشه با انتخاب دکمه‌ی back می‌توان به منوی اصلی و گزینه‌های آن رسید) و Dalvik / ART Cache,Data, System, Cache, Internal storage را انتخاب کنید. سپس مجددا فلش آبی رنگ پایین صفحه را به سمت راست بکشید تا کار پاک کردن سیستم شروع شود. در اینجا همه چیز را منهای SD Card، پاک خواهیم کرد. بدون انجام اینکار، وارد یک حلقه‌ی بی‌نهایت خواهید شد و سیستم اصلی پس از نصب، راه اندازی نمی‌شود (آزمایش کردم!).


ب) انتقال فایل‌های Custom ROM و GApps به گوشی

اکنون به کامپیوتر خود و پوشه‌ی محل نصب برنامه‌ی Minimal_ADB_Fastboot وارد شده و خط فرمان را در آنجا آغاز کنید. برای این منظور فقط کافی است بر روی فایل cmd-here.exe کلیک کنید. سپس فرامین زیر را اجرا کنید تا فایل‌ها به گوشی منتقل شوند:
adb devices
adb push LINEAGE.zip /sdcard/
adb push GAPPS.zip /sdcard/
دو نکته:
1- فایل‌های custom ROM و GApps دریافت شده را به درون پوشه‌ی Minimal_ADB_Fastboot کپی کنید. در اینجا منظور از LINEAGE.zip نام کاملی مانند lineage-17.1-20210114-nightly-j7elte-signed.zip است که دریافت کرده‌اید و همچنین منظور از GAPPS.zip، نام کاملی مانند open_gapps-arm-10.0-pico-20210116.zip است.
2- برای اجرای این دستورات، نیازی به داشتن یک sdcard نیست. نامی که در اینجا ذکر شده، فقط یک نام پوشه‌ی جدید، در گوشی شما است که قرار است در ادامه فایل‌ها را از آن انتخاب کنیم.

یک نکته‌ی تکمیلی: در حالت منوی recovery و بعد از پاک کردن همه چیز، اگر فولدرهای گوشی در windows explorer مشخص نیستند، باید آن‌ها را mount کرد تا بشود فایل‌ها را به آن‌ها کپی کرد (روش دوم کپی کردن فایل‌ها به گوشی). اگر به منوی ابتدایی TWRP دقت کنید، یک گزینه‌ی mount هم دارد که دقیقا برای همین منظور است. پوشه‌ها را که mount کردید، در windows explorer جهت کپی کردن معمولی ظاهر می‌شوند.


ج) نصب نهایی سیستم عامل و برنامه‌های گوگل

پیش از هر کاری به گزینه‌ی Settings در برنامه‌ی TWRP مراجعه کرده و در برگه‌ی General آن، تیک زیر را بر دارید: Prompt to install TWRP app if not installed!

اکنون که فایل‌های custom ROM و GApps به گوشی کپی شدند، از منوی اصلی TWRP، اینبار گزینه‌ی Install را انتخاب کنید (همانطور که عنوان شد، در اینجا همیشه دکمه‌ی back، برای بازگشت به صفحه‌ی اصلی کار می‌کند).


اگر از طریق دستورات adb فایل‌ها را به پوشه‌ی sdcard منتقل کرده باشید، به صورت خودکار اولین فایل انتخاب شده همان فایل ROM است. سپس بر روی دکمه‌ی «Add more zips» کلیک کرده و فایل zip مربوط به GApps را انتخاب کنید. در بالای صفحه «two of max 10 File queued» باید ظاهر شده باشد (مهم) که به معنای تعداد فایل‌های موجود در صف نصب است. اکنون فلش آبی رنگ پایین صفحه را به سمت راست بکشید تا کار نصب شروع شود.
پس از پایان نصب این دو برنامه، یکبار بر روی دکمه‌ی Wipe cache/dalvik کلیک کنید (به همراه به سمت راست کشیدن دکمه‌ی فلش آبی پایین صفحه) و سپس بر روی دکمه‌ی Reboot System تا ... وارد  اندروید 10 شوید!

یک نکته: در اینجا در حین reboot سؤال می‌پرسد که آیا نیاز است TWRP را نیز به صورت جداگانه‌ای نصب کند. عنوان کنید، خیر.


چگونه به روز رسانی‌های LineageOS را نصب کنیم؟

LineageOS هفته‌ای یکبار، آخرین به روز رسانی‌های اندروید را توزیع می‌کند. برای نصب آن‌ها پیامی را ظاهر کرده و امکان دانلود را فراهم می‌کند. پس از دانلود، اگر بر روی دکمه‌ی install کلیک کنید، به صورت خودکار شما را وارد منوی recovery فوق می‌کند (و نه نصب خودکار). در اینجا تنها کاری را که باید انجام دهید، انتخاب گزینه‌ی install است و سپس انتخاب پوشه‌ی data/lineageos_updates که محل قرار گیری این فایل zip دریافت شده‌است. با انتخاب فایل zip، مراحل نصب آن مانند قبل است. پس از پایان نصب، یکبار بر روی دکمه‌ی پاک کردن کش dalvik کلیک کنید و سپس بر روی reboot. کش dalvik همواره به صورت خودکار توسط اندروید ساخته می‌شود و پاک کردن آن مشکلی را ایجاد نمی‌کند.
پس از راه اندازی مجدد سیستم، به منوی Settings>about phone>lineageOS مراجعه کرده و فایل zip قدیمی را حذف کنید (در همان صفحه‌ای که پیام دریافت و نصب را نمایش می‌داد، اکنون پیام delete ظاهر شده‌است).
نظرات مطالب
ASP.NET MVC #8
من برای تمرین helper تگ img رو بصورت زیر پیاده سازی کردم :
 public static MvcHtmlString MyImage2(this HtmlHelper helper, string src, string alt, int width, int height)
  {
var img=new TagBuilder("img");
img.MergeAttribute("src", VirtualPathUtility.ToAbsolute(src));
img.MergeAttribute("alt", alt);
img.MergeAttribute("width", width.ToString());
img.MergeAttribute("height", height.ToString());
return MvcHtmlString.Create(img.ToString());
  }

آیا استفاده از VirtualPathUtility.ToAbsolute(src) برای بدست آوردن آدرس تصویر که در پوشه content قرار دارد روش درستی است ؟
من جواب گرفتم .ولی می‌خواستم بدون آیا میشه بهتر از این عمل کرد در کلاس helper
نظرات مطالب
سفارشی کردن صفحه بندی WebGrid در ASP.NET MVC
باتشکر.زمانی که از این روش به صورت Ajax ای استفاده می‌کنم آدرس‌های تولید شده صفحه بندی بدین شکل تولید می‌شود :
href="/AreaName/CoontrollerName/ActionName?page=2&__swhg=1516731566998"
که بر روی عملکرد دکمه‌های ویرایش و حذف تاثیر می‌گذاره و عملکردآنها غیر فعال می‌شود
نظرات مطالب
تهیه قالب برای ارسال ایمیل‌ها در ASP.NET Core توسط Razor Viewها
درود
آیا امکان دارد کد داخل فایل view را بصورت string (بعنوان مثال از بانک اطلاعاتی یا ساخته شده بصورت دستی ) مانند همین کد رندر کنیم .
مثال :
کد html ای بصورت string داریم که در بانک اطلاعاتی ذخیره شده است :
@model string
<div>@Model</div>
<div><CutumTagHelper asp-id="1000" /></div>
حال در قسمتی از View اصلی میخواهیم این مقدار string خوانده شده از بانک را ابتدا بصورت یک view مجزا رندر و نتیجه آن را بصورت Html نمایش دهیم :
بجای
...

@Html.Raw(Model.HtmlData)

....
چنین کدی داشته باشیم :

...

@Html.SomeNameLikeRenderedRaw(Model.HtmlData,Model.SomeDataAsDynamicViewModel)

....

مطالب
فرمت کردن اطلاعات نمایش داده شده به کمک Kendo UI Grid
پیشنیازهای بحث:
- «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid »
- «استفاده از Kendo UI templates»

صورت مساله
می‌خواهیم به یک چنین تصویری برسیم؛ که دارای گروه بندی اطلاعات است، فرمت شرطی روی ستون قیمت آن اعمال شده و تاریخ نمایش داده شده در آن نیز شمسی است. همچنین برای مثال ستون قیمت آن دارای ته جمع صفحه بوده و به علاوه یک دکمه‌ی سفارشی به نوار ابزار آن اضافه شده‌است.


مباحث قسمت سمت سرور این مثال با مطلب «صفحه بندی، مرتب سازی و جستجوی پویای اطلاعات به کمک Kendo UI Grid» دقیقا یکی است. فقط یک خاصیت AddDate نیز در اینجا اضافه شده‌است.


تغییر نحوه‌ی نمایش pager

اگر به قسمت pager تصویر فوق دقت کنید، یک دکمه‌ی refresh، تعداد موارد هر صفحه و امکان وارد کردن دستی شماره صفحه، در آن پیش بینی شده‌است. این موارد را با تنظیمات ذیل می‌توان فعال کرد:
            $("#report-grid").kendoGrid({
                // ...
                pageable: {
                    previousNext: true, // default true
                    numeric: true, // default true
                    buttonCount: 5, // default 10
                    refresh: true, // default false
                    input: true, // default false
                    pageSizes: true // default false
                },


بومی سازی پیغام‌های گرید

پیغام‌های فارسی را که در تصویر فوق مشاهده می‌کنید، حاصل پیوست فایل kendo.fa-IR.js هستند:
 <!--https://github.com/loudenvier/kendo-global/blob/master/lang/kendo.fa-IR.js-->
<script src="js/messages/kendo.fa-IR.js" type="text/javascript"></script>


گروه بندی اطلاعات

برای گروه بندی اطلاعات در Kendo UI Grid دو قسمت باید تغییر کنند.
ابتدا باید فیلد پیش فرض گروه بندی در قسمت data source گرید تعریف شود:
            var productsDataSource = new kendo.data.DataSource({
                // ...
                group: { field: "IsAvailable" },
                // ...
            });
همین تنظیم، گروه بندی را فعال خواهد کرد. اگر علاقمند باشید که به کاربران امکان تغییر دستی گروه بندی را بدهید، خاصیت groupable را نیز true کنید.
$("#report-grid").kendoGrid({
// ...
groupable: true, // allows the user to alter what field the grid is grouped by
// ...
در این حالت با کشیدن و رها کردن یک سرستون، به نوار ابزار مرتبط با گروه بندی، گروه بندی گرید بر اساس این فیلد انتخابی به صورت خودکار انجام می‌شود.


اضافه کردن ته جمع‌های ستون‌ها

این ته جمع‌ها که aggregate نام دارند باید در دو قسمت فعال شوند:
            var productsDataSource = new kendo.data.DataSource({
                //...
                aggregate: [
                    { field: "Name", aggregate: "count" },
                    { field: "Price", aggregate: "sum" }
                ]
                //...
            });
ابتدا در قسمت data source مشخص می‌کنیم که چه تابع تجمعی قرار است به ازای یک فیلد خاص استفاده شود.
سپس این متدها را می‌توان مطابق فرمت hash syntax قالب‌های Kendo UI در قسمت footerTemplate هر ستون تعریف کرد:
            $("#report-grid").kendoGrid({
                // ...
                columns: [
                    {
                        field: "Name", title: "نام محصول",
                        footerTemplate: "تعداد: #=count#"
                    },
                    {
                        field: "Price", title: "قیمت",
                        footerTemplate: "جمع: #=kendo.toString(sum,'c0')#"
                    }
                ]
                // ...
            });


فرمت شرطی اطلاعات

در ستون قیمت، می‌خواهیم اگر قیمتی بیش از 2490 بود، با پس زمینه‌ی قهوه‌ای و رنگ زرد نمایش داده شود. برای این منظور می‌توان یک قالب Kendo UI سفارشی را طراحی کرد:
    <script type="text/x-kendo-template" id="priceTemplate">
        #if( Price > 2490 ) {#
        <span style="background:brown; color:yellow;">#=kendo.toString(Price,'c0')#</span>
        #} else {#
        #= kendo.toString(Price,'c0')#
        #}#
    </script>
سپس نحوه‌ی استفاده‌ی از آن به صورت ذیل خواهد بود:
            $("#report-grid").kendoGrid({
                //...
                columns: [
                    {
                        field: "Price", title: "قیمت",
                        template: kendo.template($("#priceTemplate").html()),
                        footerTemplate: "جمع: #=kendo.toString(sum,'c0')#"
                    }
                ]
                //...
            });
توسط متد kendo.template امکان انتساب یک قالب سفارشی به خاصیت template یک ستون وجود دارد.


فرمت تاریخ میلادی به شمسی در حین نمایش

برای تبدیل سمت کلاینت تاریخ میلادی به شمسی از کتابخانه‌ی moment-jalaali.js کمک گرفته شده‌است:
 <!--https://github.com/moment/moment/-->
<script src="js/cultures/moment.min.js" type="text/javascript"></script>
<!--https://github.com/jalaali/moment-jalaali-->
<script src="js/cultures/moment-jalaali.js" type="text/javascript"></script>
پس از آن تنها کافی است متد فرمت این کتابخانه را در قسمت template ستون تاریخ و توسط hash syntax قالب‌های Kendo UI بکار برد:
            $("#report-grid").kendoGrid({
                //...
                columns: [
                    {
                        field: "AddDate", title: "تاریخ ثبت",
                        template: "#=moment(AddDate).format('jYYYY/jMM/jDD')#"
                    }
                ]
                //...
            });


اضافه کردن یک دکمه به نوار ابزار گرید

نوار ابزار Kendo UI Grid را نیز می‌توان توسط یک قالب سفارشی آن مقدار دهی کرد:
            $("#report-grid").kendoGrid({
                // ...
                toolbar: [
                    { template: kendo.template($("#toolbarTemplate").html()) }
                ]
                // ...
            });
برای نمونه toolbarTemplate فوق را به نحو ذیل تعریف کرده‌ایم:
    <script>
        // این اطلاعات برای تهیه خروجی سمت سرور مناسب هستند
        function getCurrentGridFilters() {
            var dataSource = $("#report-grid").data("kendoGrid").dataSource;
            var gridState = {
                page: dataSource.page(),
                pageSize: dataSource.pageSize(),
                sort: dataSource.sort(),
                group: dataSource.group(),
                filter: dataSource.filter()
            };
            return kendo.stringify(gridState);
        }
    </script>

    <script id="toolbarTemplate" type="text/x-kendo-template">
        <a class="k-button" href="\#" onclick="alert('gridState: ' + getCurrentGridFilters());">نوار ابزار سفارشی</a>
    </script>
دکمه‌ی اضافه شده، وضعیت فیلتر data source متصل به گرید را بازگشت می‌دهد. برای مثال مشخص می‌کند که در چه صفحه‌ای با چه تعداد رکورد قرار داریم و همچنین وضعیت مرتب سازی، فیلتر و غیره چیست. از این اطلاعات می‌توان در سمت سرور برای تهیه‌ی خروجی‌های PDF یا اکسل استفاده کرد. وضعیت فیلتر اطلاعات مشخص است. بر همین مبنا کوئری گرفته و سپس می‌توان نتیجه‌ی آن‌را تبدیل به منبع داده تهیه خروجی مورد نظر کرد.



کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید:
KendoUI05.zip
نظرات مطالب
Globalization در ASP.NET MVC - قسمت ششم
برای طراحی یک سامانه مدیرت محتوا با کلی ماژول فکر می‌کنم حرفم منطقی باشه مهندس، در ضمن همونجوری که مهندس یوسف نژاد فرمودن اطلاعات در بازیابی اولیه کش میشه و تا ری ستارت شدن سایت در حافظه می‌مونه، فکر می‌کنم چندان تاثیری بروی کارایی داشته باشه با توجه به فرضیات، فرض کن من 10000 عنوان دارم، 30 تا زبان دارم در این صورت توی یک جدول زبان انگلیسی (en-کالچر انگلیسی) 10000 بار تکرار میشه علاوه بر اون عنوان مثلا "نام کاربری" به ازای 30 زبان 30 بار تکرار میشه زیادم حرف من غیر منظقی نیست و الا حرف شما درسته بله join سرعت پایین میاره اما ما که قرار نیست زیادی دسترسی به این جداول داشته باشیم.
"پس از اولین درخواست برای هر منبع، نمونه تولیدشده از پرووایدر مربوطه در حافظه سرور کش خواهد شد." سخن مهندس یوسف نژاد