نظرات مطالب
نحوه ارتقاء برنامه‌های موجود MVC3 به MVC4
قبل از اینکه جوابتونو ببینم تماس گرفتم به سرویس دهنده‌ی هاست که مشکلم کامل حل شد :ایکس ... مشکل همونی هست که شما میگین ولی رو وب سایت پنل خودشون رو asp.net 2 تنظیم بود که درسش کردم. 
الان با این شرایط که من میبینم و اونا هم ساپورت mvc 4 ندارند پس نیازی به روی هاست بودن mvc 4 نیست چون پروژم کاملا داره کار میکنه :دی 
نظرات مطالب
انجام کارهای زمانبندی شده در برنامه‌های ASP.NET توسط DNT Scheduler
«a task was canceled» صرفا مرتبط هست به زنده نگه داشتن app pool برنامه؛ در زمانیکه سایت بازدید کننده‌ای ندارد. نظرات بحث را از ابتدا دنبال کنید؛ در مورد سرویس ping و امثال آن بحث شده.
مطالب
ارسال فایل و تصویر به همراه داده‌های دیگر از طریق jQuery Ajax
یکی از سوالات رایجی که زیاد پرسیده می‌شود این است که چطور باید یک تصویر را به همراه فیلدهای دیگر به سمت سرور ارسال کرد. اکثر مثال‌های آپلود عکس بدین صورت هستند که از یک کتابخانه پویا استفاده می‌کنند که همان لحظه عکس را به سمت سرور ارسال میکنند. ولی یک مثال و کاربرد بسیار ساده این است که من میخواهم اطلاعات فرم و عکس Input File را به همراه یکدیگر همزمان ارسال نمایم که اتفاقا این مسئله به شدت هم اتفاق می‌افتد. برای مثال شما اطلاعات یک دانش آموز را وارد سیستم میکنید که به صورت ایجکسی به سمت سرور ارسال می‌شوند و حالا نیاز است که تصویر دانش آموز هم وارد سیستم شود که ارسال این تصویر نیز از طریق یک input File رخ می‌دهد. نحوه کار با یک input File در سمت سرور در سایت جاری پرداخته شده است که برای پرهیز از تکرار از آن خودداری میکنم.

XMLHttpRequest رابطی است که به شما امکان نقل و انتقالات را از سمت کاربر، به سمت سرور و سپس دریافت پاسخ آن را می‌دهد. این رابط طوری طراحی شده‌است که دیگر برای این جابجایی نیازی به بارگزاری مجدد کل صفحه نباشد و قسمتی از اطلاعات صفحات به روز شوند، مزاحمتی برای کاربر ایجاد نشود. به همین دلیل از این رابط، در پشت صحنه‌های عملیات ایجکسی استفاده زیادی می‌شود. در این مقاله با استفاده از خصوصیتی به نام request.IsAjax بررسی می‌شود که آیا درخواست رسیده به سرور از نوع ایجکسی است یا خیر. اگر به سورس نوشته شده این متد نگاه دقیق‌تری بیندازیم، متوجه می‌شویم کاری که این متد انجام می‌دهد، در واقع در یک خط خلاصه می‌شود و آن بررسی هدری برای وجود درخواست از نوع XMLHttpRequest است:
return request.Headers["X-Requested-With"] == "XMLHttpRequest";
برای اطلاعات بیشتر در مورد این رابط، خصوصیت‌ها، متدهایش و پشتیبانی سایر مرورگرها از این خواص، بهتر است به صفحه مستندات موزیلا نگاهی بیندازید.

یکی از متدهای این رابط، متد ارسال آن (send) می‌باشد که میتواند رابطی به نام formData را انتقال دهد و این رابط از نوع مجموعه‌ای از کلید و مقدارهاست. این رابط زمانی به کار گرفته می‌شود که انکدینگ فرم خود را بر روی multipart/form-data قرار داده باشید. این ساختار می‌تواند توسط دستور for of بررسی گردد. برای آشنایی بیشتر با متدهای آن این صفحه را مطالعه فرمایید.
هنگام ارسال فایل در حالت postback، ما فرم را بر روی multipart قرار می‌دهیم تا امکان ارسال آن توسط formData مهیا شود. ولی از آنجاکه ما از ایجکس استفاده می‌کنیم، بهتر است که خودمان مستقیما از این ساختار استفاده کنیم.

بخشی از فرم Html
<div>
  <label>تصویر</label>
  <div>
    <input id="picture" type="file" data-buttonText="انتخاب تصویر">
  </div>
</div>

<div>
  <label>کد ملی</label>
  <div>
    <input id="txtNationalCode" required="" maxlength="10" type="text">
  </div>
</div>

<div>
  <label>نام</label>
  <div>
    <input id="txtName" type="text" maxlength="50" required="">
  </div>
</div>

<div class="form-group">
  <div class="col-sm-4 col-sm-offset-2">
    <button class="btn btn-primary" id="btnSubmit" type="submit">ذخیره</button>
    <button class="btn btn-white" id="btnClear" type="submit">لغو</button>
  </div>
</div>
برای زیباسازی  کار، برای المان input File در بالا، از کتابخانه Bootstrap FileStyle استفاده شده‌است.
سپس کد جی کوئری زیر را می‌نویسیم:
 var formData = new FormData();
        formData.append('FirstName', $("#txtName").val());
        formData.append('NationalCode', $("#txtNationalCode").val());

        jQuery.each($('#picture')[0].files, function (i, file) {
            formData.append('picture-'+i, file);
        });

 $.ajax({
            type: "POST",
            dataType: "json",
            url: address,
            data: formData,
            success:
                function (data) {
                //.....

                },
            error:
                function (data) {
                  //......
                }
        });
در کد بالا ابتدا یک شیء FormData ایجاد می‌شود و سپس کلیدو مقدارهایی نیز به آن انتساب داده می‌شوند. در صورتیکه Input File شما، امکان آپلود چندین فایل همزمان را می‌دهد، می‌توانید با استفاده از حلقه‌ی مورد نظر، یکی یکی آن‌ها را به این شیء اضافه کنید و به ترتیب اسامی pictue-0 ,picture-1 و ... به آن‌ها انتساب داده می‌شود. در نهایت تنها کاری که لازم است انجام دهید این است که روال همیشگی را طی کنید و این شیء را به عنوان data، در اختیار متد ajax قرار دهید تا ارسال شود.

توجه به این نکته ضروری است و با توجه کدهایی که در نت دیدم و بسیاری از آن حتی به عنوان پاسخ صحیح در نظر گرفته شده بودند این است که شیء FormData شامل هیچ سازنده‌ای نیست و باید با استفاده از متد append آن‌ها را اضافه کنید.
مطالب
سیستم‌های توزیع شده در NET. - بخش دوم - چرا یک سخت افزار به تنهایی پاسخگوی نیازمندی‌های ما نیست؟
 قبل از شروع به بحث در مورد سیستم‌های توزیع شده، بهتر است ابتدا به سوالی اساسی که اساس بوجود آمدن سیستم‌های توزیع شده است، پاسخ دهیم:

چرا یک سخت افزار به تنهایی پاسخگوی همه نیاز‌های ما نیست؟

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

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

راه حل چیست؟

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


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

مشکل سیستمهای Parallel مشخص است. کارآیی این نوع سیستم، کاملا به سخت افزار و نوع پیاده سازی آنها وابسته است. یعنی در صورت نیاز به کارآیی بیشتر، تنها راه ارتقاء سخت افزار و بهینه کردن کدهاست. اما این روال را تا کجا می‌توانیم انجام دهیم؟

برای روشن شدن مشکل بالا بیایید یک Web Application را بر روی یک سخت افزار اجرا کنیم. در یک Web Application یک Thread Pool شامل مجموعه‌ای از Threadها می‌باشد که هر Thread وظیفه اجرای یک درخواست را بر عهده دارد. یعنی با دریافت یک درخواست، یک Thread از این مجموعه کم می‌شود و وظیفه پاسخ دهی به آن در خواست را بر عهده می‌گیرد. تعداد Thread هایی که در یک Thread Pool می‌باشند نیز وابسته به تعداد هسته‌های پردازنده می‌باشد. برای این تعداد بصورت پیشفرض مقداری در نظر گرفته می‌شود که بیشترین کارآیی را در یک هسته داشته باشد؛ مثلا در ASP.NET بصورت پیشفرض به ازای هر هسته‌ی از CPU، تعداد 20 Thread به این مجموعه اضافه می‌شود. یعنی ما در یک پردازنده 2 هسته‌ای تنها می‌توانیم تعداد 40 درخواست را بصورت همزمان دریافت کنیم. در صورتیکه تعداد در خواستها در یک لحظه بیشتر از این تعداد باشد، تمام درخواست‌های اضافی در صف دریافت قرار می‌گیرند تا یکی از این Thread‌ها به درخواست خودش پاسخ دهد و به Thread Pool بازگردد و آماده اجرای درخواست بعدی باشد.

حال با فرض اینکه بصورت میانگین به هر درخواست در مدت 2 ثانیه پاسخ داده شود و در طول هر 2 ثانیه ما تعداد 200 درخواست جدید دریافت کنیم، یعنی در هر 2 ثانیه تعداد 160 درخواست در صف پردازش درخواست باقی می‌مانند. یعنی در مدت 10 ثانیه تعداد 800 درخواست پردازش نشده در این صف وجود دارند. در صورتیکه این روال ادامه پیدا کند، صف پردازش بزرگتر و بزرگتر می‌شود؛ تا جایی که دیگر حافظه‌ای برای دریافت درخواستهای جدید نباشد. اینجاست که سیستم ما از دسترس خارج می‌شود. پس تصمیم می‌گیریم سخت افزار خود را ارتقاء دهیم و کدهای خود را نیز بهینه کنیم. مثلا جاییکه عملیات I/O را انجام می‌دهیم، برای استفاده‌ی بهینه از Thread‌های موجود، کدهای خود را بصورت Async اجرا کنیم.

تا حدودی مشکل ما فعلا حل شده‌است. بعد از مدتی بدلیل اضافه شدن نیازمندی‌های جدید، تعدادکاربران فعال سیستم زیاد می‌شود و دوباره مشکل پوشش دادن تعداد بیشتر درخواست بوجود می‌آید. مجبوریم دوباره عملیات Scale-up یا Vertical scaling را انجام دهیم. بله؛ عملیاتی که ما در این سیستم‌ها برای مقیاس‌پذیری انجام می‌دهیم، اصطلاحا  Vertical scaling یا Scale-up نام دارد. یعنی با افزایش تعداد کاربران یا تعداد درخواست، کدها بهینه‌تر و سخت افزار ارتقاء پیدا می‌کند.

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

فرض کنید از سمت پایگاه داده نیز با مشکل روبرو شده‌ایم. حجم داده‌های ما روبه افزایش است. فضای حافظه‌ی آزاد تنها Server ی که داده‌های ما را ذخیره می‌کند، رو به اتمام است. چاره چیست؟ آن را ارتقا دهیم؟ بله برای مدتی سرور را از دسترس خارج کرده و فضای آزاد را افزایش می‌دهیم. در این بین تمام سرویس‌های ما که وابسته به این سرور هستند، از دسترس خارج می‌شوند. این کار برای داده‌هایی که ذاتا همیشه رو به افزایش هستند، چقدر باید تکرار شوند؟ چقدر باید هزینه کنیم تا این داده‌ها که تمام سرویس‌های ما به آنها وابسته هستند، با مشکل مواجه نشوند، یا کارآیی بازیابی آنها پایین نیاید؟

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

اینجاست که مفهوم سیستمهای توزیع شده به کمک سیستمهای Parallel می‌آید و مفهوم Scale-up یا Vertical scaling  با مفهموم Horizontal Scaling یا Scale-out ادغام می‌شود. در قسمت بعدی، با مفاهیم، خصوصیات و اصطلاحات موجود در این سیستم‌ها آشنا می‌شویم.
مطالب
مقدمه‌ای بر داکر، قسمت سوم
در قسمت قبلی با Volume آشنا شدیم و نحوه‌ی اجرا کردن یک Source Code را درون Container یاد گرفتیم. در این قسمت میخواهیم یک Image شخصی ساخته، آن‌را اجرا و درون Docker hub ارسال نماییم.


Dockerfile چیست؟
Dockerfile عملا چیزی بیشتر از یک دستور العمل از نوع متنی برای build و ساخت یک docker image از آن نمیباشد. ضمن اینکه مراحل build شدن، cache شده و build‌های بعدی با سرعت خیلی بیشتری اجرا خواهند شد. بعد از نوشتن چند dockerfile متوجه خواهیم شد که مراحلش بسیار ساده است.
ساخت اولین Dockerfile
قبل از ساخت dockerfile، مثل جلسه‌ی قبل یک پروژه‌ی ساده‌ی nodejsی را با فایل index.js میسازیم:
const express = require('express')
const app = express()
const PORT = 3000;
app.get('/', (req, res) => {
  res.send('Hello World')
})
app.listen(PORT, () => {
  console.log(`listening on port ${PORT}!`)
})
درون  package.json هم این قسمت را تغییر میدهیم:
"scripts": {
    "start": "node index"
  },
حال فایل Dockerfile را ساخته و دستورالعمل‌های زیر را درون آن مینویسیم:
FROM node
ENV NODE_ENV=production
COPY . /var/www
WORKDIR /var/www
RUN npm i
EXPOSE 3000
ENTRYPOINT npm start
توضیحات دستورات فوق
1) FROM node یک imageی است که برنامه‌ی شما از آن استفاده میکند.
2) از environment variable استفاده کرده و نوع آن را روی production میگذاریم.
3) COPY کردن تمام فایل‌های دایرکتوری جاری پروژه درون فایل سیستم container به آدرس فوق.
4) عوض کردن work directory روی آدرسی که پروژه کپی شده است.
5) اجرا کردن دستور npm i برای نصب شدن Dependencies‌های پروژه.
6) EXPOSE کردن یک port برای ایجاد دسترسی.
7) نقطه‌ی شروع برنامه و دستور npm start که درون package.json قبل تعریف نموده بودیم.
 
بعد از ساخت Dockerfile فوق نوبت به build گرفتن از آن میرسد که با استفاده از دستور زیر میباشد:
docker build -f Dockerfile -t alikhll/testnode1 .
نکته: اگر image node را روی سیستم خود نداشته باشید ابتدا بصورت خودکار آن را pull مینماید.
1) پرچم f- که برای شناساندن فایل Dockefile میباشد، بدلیل این است که نام این فایل قابل تغییر میباشد.
2) پرچم t- برای نام image ساخته شده میباشد. همچنین . نیز به دایرکتوری جاری اشاره میکند.
بعد از ساخته شدن image با استفاده از دستور docker images میتوانید آن را مشاهده نمایید.
برای اجرای image نیز از دستور زیر استفاده میکنیم:
docker run -d -p 8080:3000 alikhll/testnode1
حال با استفاده از port 8080 میتوانید اپلیکیشن را اجرا نمایید.
از آنجایی که اکثر خوانندگان این مجموعه برنامه نویسان دات نت هستند یک Dockerfile دات نتی نیز برای تسلط بیشتر مینویسیم.
ابتدا دستورات زیر را درون ترمینال خود وارد کرده و یک پروژه‌ی وب از نوع Net Core. را میسازیم:
dotnet new web
dotnet restore
dotnet run
حال روی localhost قابلیت اجرا خواهد داشت؛ اما میخواهیم این app را بر روی container اجرا کنیم. بنابراین Dockerfile را اینگونه مینویسیم:
FROM microsoft/dotnet
ENV ASPNETCORE_URLS http://*:3000
COPY . /var/www
WORKDIR /var/www
RUN dotnet restore
EXPOSE 3000
ENTRYPOINT dotnet run
همه چیز خیلی شبیه به داکرفایل قبلی است، با این تفاوت که از ایمیج microsoft/dotnet استفاده کرده‌ایم (از imageهای سبکتری برای محیط production استفاده میکنیم! ضمن اینکه image فوق از Debian استفاده میکند. image جدیدی روی توزیع Alpine ایجاد شده است که حجم خیلی پایینی داشته و برای مطالعه بیشتر به اینجا رجوع کنید).
نکته‌ی مهم ASPNETCORE_URLS میباشد چون میخواهیم بتوانیم از خارج از محیط container با استفاده از IP، به آن دسترسی داشته باشیم (محیط local نیست).
 دستورات زیر را برای build و اجرا وارد مینماییم:
docker build -f Dockerfile -t alikhll/testasp1 .
docker run -d -p 8080:3000 alikhll/testasp1
اکنون app شما باید روی پورت خارجی 8080 قابل اجرا باشد.
نکته: من container قبلی nodejsی را stop کرده بودم وگرنه این پورت قابل استفاده‌ی مجدد نبود!
پابلیش کردن روی Docker Hub
انتشار دادن روی Docker hub ّبسیار ساده است. میتوانید یک اکانت به صورت رایگان ساخته و image‌های خود را بر روی آن انتشار دهید.
نکته: پروژه‌های تستی خود را میتوانید آنجا انتشار داده که البته قابلیت private بودن را ندارند. در صورتیکه برای یک پروژه‌ی واقعی که image‌های عمومی نیستند و فقط درون سازمان باید به آن دسترسی داشته باشند، میتوانید اکانت enterprise تهیه کرده و image‌های خود را درون آن مدیریت نمایید. همچنین از سرویس‌های ابری Azure, Amazon نیز برای انتشار دادن imageهای خصوصی میتوان استفاده نمود.
دستور زیر برای انتشار دادن imageی که ساختیم روی docker hub میباشد. ابتدا login کرده user/password را وارد کرده سپس push مینماییم:
docker login
docker push alikhll/testnode1
نکته: به جای alikhll باید username شخصی خود را وارد نمایید.
اکنون به راحتی با استفاده از دستور زیر روی یک ماشین دیگر که داکر روی آن نصب شده است، میتوانید image را pull کرده و اجرا نمایید:
docker pull alikhll/testnode1
مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 10 - بررسی تغییرات Viewها
تا اینجا یک پروژه‌ی خالی ASP.NET Core 1.0 را به مرحله‌ی فعال سازی ASP.NET MVC و تنظیمات مسیریابی‌های اولیه‌ی آن رسانده‌ایم. مرحله‌ی بعد، افزودن Viewها، نمایش اطلاعاتی به کاربران و دریافت اطلاعات از آن‌ها است و همانطور که پیشتر نیز عنوان شد، برای «ارتقاء» نیاز است «15 مورد» ابتدایی مطالب ASP.NET MVC سایت را پیش از ادامه‌ی این سری مطالعه کنید.

معرفی فایل جدید ViewImports

پروژه‌ی خالی ASP.NET Core 1.0 فاقد پوشه‌ی Views به همراه فایل‌های آغازین آن است. بنابراین ابتدا در ریشه‌ی پروژه، پوشه‌ی جدید Views را ایجاد کنید.
فایل‌های آغازین این پوشه هم در مقایسه‌ی با نگارش‌های قبلی ASP.NET MVC اندکی تغییر کرده‌اند. برای مثال در نگارش قبلی، فایل web.config ایی در ریشه‌ی پوشه‌ی Views قرار داشت و چندین مقصود را فراهم می‌کرد:
الف) در آن تنظیم شده بود که هر نوع درخواستی به فایل‌های موجود در پوشه‌ی Views، برگشت خورده و قابل پردازش نباشند. این مورد هم از لحاظ مسایل امنیتی اضافه شده بود و هم اینکه در ASP.NET MVC، برخلاف وب فرم‌ها، شروع پردازش یک درخواست، از فایل‌های View شروع نمی‌شود. به همین جهت است که درخواست مستقیم آن‌ها بی‌معنا است.
در ASP.NET Core، فایل web.config از این پوشه حذف شده‌است؛ چون دیگر نیازی به آن نیست. اگر مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 4 - فعال سازی پردازش فایل‌های استاتیک» را به خاطر داشته باشید، هر پوشه‌ای که توسط میان افزار Static Files عمومی نشود، توسط کاربران برنامه قابل دسترسی نخواهد بود و چون پوشه‌ی Views هم به صورت پیش فرض توسط این میان افزار عمومی نمی‌شود، نیازی به فایل web.config، جهت قطع دسترسی به فایل‌های موجود در آن وجود ندارد.

ب) کاربرد دیگر این فایل web.config، تعریف فضاهای نام پیش فرضی بود که در فایل‌های View مورد استفاده قرار می‌گرفتند. برای مثال چون فضای نام HTML Helperهای استاندارد ASP.NET MVC در این فایل web.config قید شده بود، دیگر نیازی به تکرار آن در تمام فایل‌های View برنامه وجود نداشت. در ASP.NET Core، برای جایگزین کردن این قابلیت، فایل جدیدی را به نام ViewImports.cshtml_ معرفی کرده‌اند، تا دیگر نیازی به ارث بری از فایل web.config وجود نداشته باشد.


برای مثال اگر می‌خواهید بالای Viewهای خود، مدام ذکر using مربوط به فضای نام مدل‌ها برنامه را انجام ندهید، این سطر تکراری را به فایل جدید view imports منتقل کنید:
 @using MyProject.Models

و این فضاهای نام به صورت پیش فرض برای تمام viewها مهیا هستند و نیازی به تعریف مجدد، ندارند:
• System
• System.Linq
• System.Collections.Generic
• Microsoft.AspNetCore.Mvc
• Microsoft.AspNetCore.Mvc.Rendering


افزودن یک View جدید

در نگارش‌های پیشین ASP.NET MVC، اگر بر روی نام یک اکشن متد کلیک راست می‌کردیم، در منوی ظاهر شده، گزینه‌ی Add view وجود داشت. چنین گزینه‌ای در نگارش RTM اول ASP.NET Core وجود ندارد و مراحل ایجاد یک View جدید را باید دستی طی کنید. برای مثال اگر نام کلاس کنترلر شما PersonController است، پوشه‌ی Person را به عنوان زیر پوشه‌ی Views ایجاد کرده و سپس بر روی این پوشه کلیک راست کنید، گزینه‌ی add new item را انتخاب و سپس واژه‌ی view را جستجو کنید:


البته یک دلیل این مساله می‌تواند امکان سفارشی سازی محل قرارگیری این پوشه‌ها در ASP.NET Core نیز باشد که در ادامه آن‌را بررسی خواهیم کرد (و ابزارهای از پیش تعریف شده عموما با مکان‌های از پیش تعریف شده کار می‌کنند).


امکان پوشه بندی بهتر فایل‌های یک پروژه‌ی ASP.NET Core نسبت به مفهوم Areas در نگارش‌های پیشین ASP.NET MVC

حالت پیش فرض پوشه بندی فایل‌های اصلی برنامه‌های ASP.NET MVC، مبتنی بر فناوری‌ها است؛ برای مثال پوشه‌های views و Controllers و امثال آن تعریف شده‌اند.
Project   
- Controllers
- Models
- Services
- ViewModels
- Views
روش دیگری را که برای پوشه بندی پروژه‌های ASP.NET MVC پیشنهاد می‌کنند (که Area توکار آن نیز زیر مجموعه‌ی آن محسوب می‌شود)، اصطلاحا Feature Folder Structure نام دارد. در این حالت برنامه بر اساس ویژگی‌ها و قابلیت‌های مختلف آن پوشه بندی می‌شود؛ بجای اینکه یک پوشه‌ی کلی کنترلرها را داشته باشیم و یک پوشه‌ی کلی views را که پس از مدتی، ارتباط دادن بین این‌ها واقعا مشکل می‌شود.
هرکسی که مدتی با ASP.NET MVC کار کرده باشد حتما به این مشکل برخورده‌است. درحال پیاده سازی قابلیتی هستید و برای اینکار نیاز خواهید داشت مدام بین پوشه‌های مختلف برنامه سوئیچ کنید؛ از پوشه‌ی کنترلرها به پوشه‌ی ویووها، به پوشه‌ی اسکریپت‌ها، پوشه‌ی اشتراکی ویووها و غیره. پس از رشد برنامه به جایی خواهید رسید که دیگر نمی‌توانید تشخیص دهید این فایلی که اضافه شده‌است ارتباطش با سایر قسمت‌ها چیست؟
ایده‌ی «پوشه بندی بر اساس ویژگی‌ها»، بر مبنای قرار دادن تمام نیازهای یک ویژگی، درون یک پوشه‌ی خاص آن است:


همانطور که مشاهده می‌کنید، در این حالت تمام اجزای یک ویژگی، داخل یک پوشه قرار گرفته‌اند؛ از کنترلر مرتبط با Viewهای آن تا فایل‌های css و js خاص آن.
برای پیاده سازی آن:
1) نام پوشه‌ی Views را به Features تغییر دهید.
2) پوشه‌ای را به نام StartupCustomizations به برنامه اضافه کرده و سپس کلاس ذیل را به آن اضافه کنید:
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Razor;
 
namespace Core1RtmEmptyTest.StartupCustomizations
{
  public class FeatureLocationExpander : IViewLocationExpander
  {
   public void PopulateValues(ViewLocationExpanderContext context)
   {
    context.Values["customviewlocation"] = nameof(FeatureLocationExpander);
   }
 
   public IEnumerable<string> ExpandViewLocations(
    ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
   {
    return new[]
    {
      "/Features/{1}/{0}.cshtml",
      "/Features/Shared/{0}.cshtml"
    };
   }
  }
}
حالت پیش فرض ASP.NET MVC، یافتن فایل‌ها در مسیرهای Views/{1}/{0}.cshtml و Views/Shared/{0}.cshtml است؛ که در اینجا {0} نام view است و {1} نام کنترلر. این ساختار هم در اینجا حفظ شده‌است؛ اما اینبار به پوشه‌ی جدید Features اشاره می‌کند.
RazorViewEngine برنامه، بر اساس وهله‌ی پیش فرضی از اینترفیس IViewLocationExpander، محل یافتن Viewها را دریافت می‌کند. با استفاده از پیاه سازی فوق، این پیش فرض‌ها را به پوشه‌ی features هدایت کرده‌ایم.
3) در ادامه به کلاس آغازین برنامه مراجعه کرده و پس از فعال سازی ASP.NET MVC، این قابلیت را فعال سازی می‌کنیم:
public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();
  services.Configure<RazorViewEngineOptions>(options =>
  {
   options.ViewLocationExpanders.Add(new FeatureLocationExpander());
  });
4) اکنون تمام فایل‌های مرتبط با یک ویژگی را به پوشه‌ی خاص آن انتقال دهید. منظور از این فایل‌ها، کنترلر، فایل‌های مدل و ویوومدل، فایل‌های ویوو و فایل‌های js و css هستند و نه مورد دیگری.
5) اکنون باید پوشه‌ی Controllers خالی شده باشد. این پوشه را کلا حذف کنید. از این جهت که کنترلرها بر اساس پیش فرض‌های ASP.NET MVC (کلاس ختم شده‌ی به کلمه‌ی Controller واقع در اسمبلی که از وابستگی‌های ASP.NET MVC استفاده می‌کند) در هر مکانی که تعریف شده باشند، یافت خواهند شد و پوشه‌ی واقع شدن آن‌ها مهم نیست.
6) در آخر به فایل project.json مراجعه کرده و قسمت publish آن‌را جهت درج نام پوشه‌ی Features اصلاح کنید (تا در حین توزیع نهایی استفاده شود):
"publishOptions": {
 "include": [
  "wwwroot",
  "Features",
  "appsettings.json",
  "web.config"
 ]
},


در اینجا نیز یک نمونه‌ی دیگر استفاده‌ی از این روش بسیار معروف را مشاهده می‌کنید.


امکان ارائه‌ی برنامه بدون ارائه‌ی فایل‌های View آن

ASP.NET Core به همراه یک EmbeddedFileProvider نیز هست. حالت پیش فرض آن PhysicalFileProvider است که بر اساس تنظیمات IViewLocationExpander توکار (و یا نمونه‌ی سفارشی فوق در مبحث پوشه‌ی ویژگی‌ها) کار می‌کند.
برای راه اندازی آن ابتدا نیاز است بسته‌ی نیوگت ذیل را به فایل project.json اضافه کرد:
{
  "dependencies": {
        //same as before
   "Microsoft.Extensions.FileProviders.Embedded": "1.0.0"
  },
سپس تنظیمات متد ConfigureServices کلاس آغازین برنامه را به صورت ذیل جهت معرفی EmbeddedFileProvider تغییر می‌دهیم:
services.AddMvc();
services.Configure<RazorViewEngineOptions>(options =>
{
  options.ViewLocationExpanders.Add(new FeatureLocationExpander());
 
  var thisAssembly = typeof(Startup).GetTypeInfo().Assembly; 
  options.FileProviders.Clear();
  options.FileProviders.Add(new EmbeddedFileProvider(thisAssembly, baseNamespace: "Core1RtmEmptyTest"));
});
و در آخر در فایل project.json، در قسمت build options، گزینه‌ی embed را مقدار دهی می‌کنیم:
"buildOptions": {
  "emitEntryPoint": true,
  "preserveCompilationContext": true,
  "embed": "Features/**/*.cshtml"
},
در اینجا چند نکته را باید مدنظر داشت:
1) اگر نام پوشه‌ی Views را به Features تغییر داده‌اید، نیاز به ثبت ViewLocationExpanders آن‌را دارید (وگرنه، خیر).
2) در اینجا جهت مثال و بررسی اینکه واقعا این فایل‌ها از اسمبلی برنامه خوانده می‌شوند، متد options.FileProviders.Clear فراخوانی شده‌است. این متد PhysicalFileProvider  پیش فرض را حذف می‌کند. کار PhysicalFileProvider  خواندن فایل‌های ویووها از فایل سیستم به صورت متداول است.
3) کار قسمت embed در تنظیمات build، افزودن فایل‌های cshtml به قسمت منابع اسمبلی است (به همین جهت دیگر نیازی به توزیع آن‌ها نخواهد بود). اگر صرفا **/Features را ذکر کنید، تمام فایل‌های موجود را پیوست می‌کند. همچنین اگر نام پوشه‌ی Views را تغییر نداده‌اید، این مقدار همان Views/**/*.cshtml خواهد بود و یا **/Views


4) در EmbeddedFileProvider می‌توان هر نوع اسمبلی را ذکر کرد. یعنی می‌توان برنامه را به صورت چندین و چند ماژول تهیه و سپس سرهم و یکپارچه کرد (options.FileProviders یک لیست قابل تکمیل است). در اینجا ذکر baseNamespace نیز مهم است. در غیر اینصورت منبع مورد نظر از اسمبلی یاد شده، قابل استخراج نخواهد بود (چون نام اسمبلی، قسمت اول نام هر منبعی است).


فعال سازی کامپایل خودکار فایل‌های View در ASP.NET Core 1.0

این قابلیت به زودی جهت یافتن مشکلات موجود در فایل‌های razor پیش از اجرای آن‌ها، اضافه خواهد شد. اطلاعات بیشتر
نظرات مطالب
Contact me
سلام، حقیقتش کار فوروم رو اینجا انجام دادن مشکل است چون مستلزم این خواهد بود که شما دقیقا متن خطا و سایر جزئیات را هم ذکر کنید و غیره و غیره که اساسا کار یک وبلاگ این نیست.
کاری هم که شما کردید سبب هک شدن سایت شما خواهد شد چون دسترسی به آپلودر بدون اعتبار سنجی و با دانستن مسیر آن (با توجه به سورس باز بودن این ادیتور) میسر است.
برای این حالت هم می‌تونید از یک متغیر سشن استفاده کنید. اگر ست شده بود یعنی کاربر لاگین کرده، اگر نه، خیر. (روش ایده‌آلی نیست ولی کار میکنه)

خودم در اکثر موارد از این ادیتور استفاده می‌کنم:
freeTextBox.Com
امکان آپلود عکس و غیره رو هم داره با یک نکته البته، دکمه‌ی InsertImageFromGallery را باید دستی در خواص آن ست کرد که البته در مستندات سایت آن موجود است.
نظرات مطالب
یکی از مزایای استفاده از SVN در یک پروژه تک نفره
نوشته خیلی خوبی و سودمندی بود. من شخصا برای PHP از SVN آنلاین سایت http://xp-dev.com استفاده می‏کنم. بد نیست نگاهی بیاندازید. سایت خیلی خوبی است و خدماتش کلا رایگان است. سایت شما را در لیست دوستان لینک کردم.
اشتراک‌ها
تشخیص اطلاعات فنی از یک وب سایت

عموما برخی از برنامه نویسان کنجکاو وقتی یک سایت جالب و یا خاصی را مرور میکنند دوست دارند بدانند که این سایت از چه تکنولوژی‌های استفاده کرده یا با چه زبانی توسعه یافته و ... . این وب سایت با دریافت آدرس سایت مورد نظر ، برخی از اطلاعات فنی مورد نیاز را ارائه میدهد.

تشخیص اطلاعات فنی از یک وب سایت
مطالب
استفاده از popBox برای کوچک کردن خودکار تصاویر بزرگ

یکی از دوستان در قسمت تماس با من پیغام گذاشته بود که چگونه تصاویر یک صفحه را می‌شود به صورت موقت کوچک کرد؟ برای نمونه، این مشکلی است که در فوروم‌ها زیاد وجود دارد. گاهی از اوقات یکی از کاربران تصویری را ارسال می‌کند که اندازه‌ی آن در حد یک تابلوی دیواری است!
با استفاده از محصول سورس بازی به نام popBox می‌توان تصاویر دلخواهی را ابتدا با اندازه‌ی کوچک در صفحه نشان داد و پس از کلیک بر روی آن، تصویر به اندازه اصلی آن نمایش داده خواهد شد. به این صورت صفحه از شکل نخواهد افتاد. این اسکریپت از آدرس زیر قابل دریافت است:
http://www.c6software.com/products/popbox/default.aspx
نحوه استفاده و مثال‌های مربوطه هم در همان آدرس قابل مشاهده است و نکته خاصی ندارد.

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

با استفاده از jQuery ، اسکریپت selectAll.js را به این مجموعه اضافه کردم. ابتدا تمامی تصاویر صفحه پیدا می‌شوند و سپس به آنهایی که طول و عرض بزرگتری از حد مجاز دارند به صورت خودکار ویژگی‌های popBox افزوده خواهد شد. چون این روش اسکریپتی است : الف) نیازی به تغییر در سورس‌های موجود نیست. ب) توسط هر تکنولوژی سمت سروری نیز قابل استفاده است. ج) به صورت خودکار به تمامی تصاویر بزرگ صفحه اعمال می‌شود و نیازی به ویرایش دستی هیچ موردی جهت اعمال ویژگی‌های مورد نظر وجود نخواهد داشت.

نکته جالبی که با jQuery وجود دارد، روال رخ‌داد گردان document.ready آن است. این رخداد پیش از window.onload استاندارد و زمانیکه DOM آماده استفاده است فراخوانی می‌شود.

برای استفاده از آن ابتدا باید دو فولدر scripts و images به سرور کپی شوند. سپس سه سطر زیر را به هدر صفحه اضافه کنید (به سورس صفحه sample.html فایل پیوست می‌توان مراجعه کرد):

<script src="scripts/jquery.min.js" type="text/javascript"></script>
<script src="scripts/PopBox.js" type="text/javascript"></script>
<script type="text/javascript" src="scripts/selectAll.js"></script>

در مورد سایر تنظیمات، فایل selectAll.js را گشوده و موارد زیر را در صورت لزوم ویرایش نمائید:
popBoxWaitImage.src = "images/spinner40.gif";
popBoxRevertImage = "images/magminus.gif";
popBoxPopImage = "images/magplus.gif";
popBoxRevertText = "کوچک‌ نمایی";
popBoxPopText = "بزرگ‌ نمایی";
popBoxCaptionMoreText = "بیشتر";
popBoxCaptionLessText = "کمتر";
MaximumAllowedWidth = 500;
MaximumAllowedHeight = 480;

در این فایل قسمتی از تابع rescaleImage از سایت stack overflow قرض گرفته شد و تغییرات لازم جهت اعمال ویژگی‌های popbox‌ به آن اعمال گردید. با استفاده از این تابع نسبت‌های طول و عرض تصویر به میزان ثابتی کوچک می‌شوند و تصویر کوچک شده با کیفیت بهتری نمایش داده خواهد شد.
موارد ذکر شده را از این آدرس می‌توانید دریافت نمائید.