نظرات مطالب
ASP.NET MVC #22
فایل al.exe پوشه C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools را نمی‌تواند پیدا کند. بررسی کنید آیا وجود دارد یا خیر؟ با نصب کامل VS.NET، باید موجود باشد. اگر خیر، باید دستی SDK ویندوز را نصب کنید: برای ویندوز 7، برای ویندوز 8
ضمنا باز هم مسیر C:\Program Files (x86)\Microsoft SDKs\Windows را برای یافتن al.exe جستجو کنید. اگر موجود است، مسیر یاد شده را دستی درست کرده و فایل al.exe و کانفیگ‌اش را در آنجا کپی کنید.
اطلاعات بیشتر
مطالب
بررسی خطاهای ممکن در حین راه اندازی اولیه برنامه‌های ASP.NET Core در IIS
نحوه‌ی نصب و راه اندازی برنامه‌های ASP.NET Core را در IIS، پیشتر در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 22 - توزیع برنامه توسط IIS» بررسی کردیم. در این مطلب می‌خواهیم به تعدادی از خطاهای ممکن در حین راه اندازی اولیه‌ی این نوع برنامه‌ها بپردازیم.


خطای 500.19


این خطا زمانی رخ می‌دهد که ماژول هاستینگ ASP.NET Core، توسط IIS شناسایی نشده باشد. نصب مجدد آن این مشکل را برطرف می‌کند.
لیست تمام ماژول‌های هاستینگ را همواره در اینجا می‌توانید پیدا کنید.


خطای 502.5 و یا گاهی از اوقات 502


باید دقت داشته باشید که اگر تنظیم disableStartUpErrorPage در IIS فعال باشد (قابل افزودن به تگ aspNetCore تنظیمات وب کانفیگ ذیل)، صرفا خطای 502 را دریافت می‌کنید.

این خطا به معنای شکست در اجرای ماژول هاستینگ ASP.NET Core است و ممکن است به یکی از دلایل ذیل ایجاد شده باشد:
الف) در حین اجرای برنامه‌ی شما، استثنایی در کدهای فایل آغازین startup.cs برنامه، رخ داده‌است.
ب) پورت مورد استفاده‌ی برنامه، توسط پروسه‌ی دیگری در حال استفاده است.
ج) برنامه‌ی شما برای SDK با نگارش 1.1.2 تنظیم و کامپایل شده‌است؛ اما بر روی سرور حداکثر، SDK نگارش 1.1.1 نصب شده‌است.
د) ممکن است پروسه‌ی IIS قادر به یافتن و حتی اجرای dotnet.exe نباشد.

برای لاگ کردن مورد «الف»، باید لاگ کردن خطاهای برنامه را در web.config آن فعالسازی کنید:
<system.webServer>
   <handlers>
     <add name="aspNetCore" path="*" verb="*"
modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="dotnet" arguments=".\MyApp.dll" stdoutLogEnabled="true"
stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="true" />
</system.webServer>
چند نکته:
- اگر این مورد به مسیر logs\stdout\. تنظیم شده‌است، باید پوشه‌ی logs را در ریشه‌ی پروژه به صورت دستی ایجاد کنید؛ و گرنه IIS آن‌را به صورت خودکار ایجاد نخواهد کرد.
- کاربر App Pool برنامه (با نام پیش‌فرض « IIS AppPool\DefaultAppPool») باید دسترسی نوشتن در این پوشه را داشته باشد؛ وگرنه فایل لاگی در آن ایجاد نخواهد شد.
- همچنین اگر با رعایت تمام این موارد، محتوای این فایل تولید شده باز هم خالی بود، یکبار IIS را ری‌استارت کنید. ممکن است IIS کار نوشتن در فایل لاگ را تمام نکرده باشد و با این کار مجبور به تکمیل و بستن فایل می‌شود.  

- برای حالت «ب» قبل از هر تغییری، یکبار کل سرور را ری‌استارت کنید.

- برای مورد «ج» نیز باید آخرین SDK هاستینگ را بر روی سرور نصب کنید.
لیست تمام SDKهای نصب شده‌ی بر روی سیستم را در مسیر «C:\Program Files\dotnet\sdk» می‌توانید مشاهده کنید. همچنین دستور «dotnet --list-sdks» نیز لیست SDKهای نصب شده را نمایش می‌دهد.

- برای رفع حالت «د»، نیاز است این موارد را بررسی کنید:
1- «Load User Profile» را به true تنظیم کنید.


برای اینکار به قسمت Application pools مراجعه کرده و تنظیمات پیشرفته‌ی App pool مورد استفاده را ویرایش کنید (تصویر فوق).
این تنظیم برای دائمی کردن کلیدهای رمزنگاری برنامه‌های ASP.NET Core نیز ضروری است و باید جزو چک لیست نصب برنامه‌های ASP.NET Core قرار گیرد.
2- مورد «د» حتی می‌تواند به علت عدم تعریف مسیر «C:\Program Files\dotnet\» در path ویندوز باشد. برای این منظور دستور env:path$ را در power shell اجرا کنید و بررسی کنید که آیا این مسیر در خروجی آن موجود است یا خیر؟ اگر نبود، پس از اضافه کردن آن به path ویندوز، باید یکبار IIS را هم ریست کنید تا این تنظیمات جدید را بخواند.
3- مورد «د» ممکن است به علت اشتباه تنظیم پوشه‌ی اصلی برنامه در IIS نیز باشد. یعنی dotnet.exe قادر به یافتن اسمبلی‌های برنامه نیست.
4- برای رفع مورد «د» دو دسترسی دیگر را نیز باید بررسی کنید:
الف) آیا کاربر Application pool برنامه به پوشه‌ی برنامه دسترسی read & execute را دارد یا خیر؟
ب) آیا کاربر Application pool برنامه به پوشه‌ی C:\Program Files\dotnet دسترسی read & execute را دارد یا خیر؟
اگر خیر، نحوه‌ی دسترسی دادن به آن‌ها به صورت زیر است:
Right click on the folder -> Properties -> Security tab -> Click at Edit button ->
Enter `IIS AppPool\DefaultAppPool` user (IIS AppPool\<app_pool_name>) -> Click at Check names -> OK ->
Then give it `read & execute` or other permissions.


خطای 502.3 و یا گاهی از اوقات 500


این خطا به صورت خلاصه به معنای «Bad Gateway: Forwarder Connection Error» است و زمانی رخ می‌دهد که پروسه‌ی dotnet.exe به درخواست رسیده شده یا پاسخی نداده‌است (مشاهده خطای 0x80072EE2  یا  ERROR_WINHTTP_TIMEOUT) و یا بیش از اندازه این پاسخ دهی طول کشیده‌است (این تنظیمات را در configuration editor می‌توانید مشاهده کنید که در حقیقت همان تگ aspNetCore در تنظیمات وب کانفیگ فوق است).


برای دیباگ بهتر این مورد نیاز است علاوه بر تنظیم web.config فوق، به فایل appsettings.json مراجعه کرده و سطح پیش فرض لاگ کردن اطلاعات را که warning است به information تغییر دهید:
"Console": {
     "LogLevel": {
        "Default": "Information"
     }
}
در این حالت درخواستی که پردازش نشده‌است نیز در لاگ‌ها حضور خواهد داشت و ممکن است این درخواست به علت عدم تنظیم CORS بدون پاسخ باقی مانده باشد.
و یا اگر پردازشی دارید که بیش از 2 دقیقه طول می‌کشد (مطابق تنظیمات تصویر فوق)، می‌توانید مقدار request time out را بیشتر کنید.


خطای 0x80004005 : 80008083

Application ‘<IIS path>’ with physical root ‘<Application path>’ failed to start 
process with commandline ‘”dotnet” .\MyApp.dll’, ErrorCode = ‘0x80004005 : 80008083.
خطای 0x80008083 به معنای تداخل نگارش‌ها است و خطای 0x80004005 به معنای مفقود بودن یک فایل یا عدم دسترسی به آن است.
این خطا زمانی رخ می‌دهد که برنامه‌ی خود را ارتقاء داده باشید، اما ماژول هاستینگ ASP.NET Core را بر روی سرور به روز رسانی نکرده باشید.


خطای 500.19

HTTP Error 500.19 - Internal Server Error
The requested page cannot be accessed because the related configuration data for the page is invalid.
اگر برنامه‌ی شما از امکانات URL Rewrite خود IIS استفاده می‌کند، عدم نصب بودن آن بر روی سرور، این خطا را سبب خواهد شد.
برای اینکار ابتدا IIS را متوقف کنید. سپس SDK جدید را نصب و پس از آن IIS را مجددا راه اندازی نمائید.


خطای 503

برنامه اجرا نشده و سطر ذیل در Event Viewer ویندوز قابل مشاهده است:
 The Module DLL C:\WINDOWS\system32\inetsrv\aspnetcore.dll failed to load.  The data is the error.
اگر اخیرا سیستم عامل را ارتقاء داده‌اید، ممکن است این خطا را دریافت کنید. راه حل آن نصب مجدد ماژول هاستینگ ASP.NET Core است تا نصب قبلی تعمیر شود.
نظرات مطالب
ASP.NET Web API - قسمت اول
تو مقدمه به این مطلب اشاره شده دوست عزیز
این سبک جدید برای ایجاد وب سرویس ها، می‌تواند در انواع پروژه‌های NET. مانند ASP.NET MVC، ASP.NET Web Forms، Windows Application و ... استفاده شود. 
مطالب
پیاده سازی Basic Authentication در ASP.NET MVC
در سیستم‌های اتصال از راه دور به خصوص اتصال تلفن‌های همراه به وب سرویس، یکی از مواردی که مرتبا قبل از هر درخواستی بررسی میگردد، صحت نام کاربری و کلمه عبور درخواستی است. در این روش کاربر، الزامات امنیتی (نام کاربری و کلمه عبور) را در بدنه درخواست قرار داده و هر api باید قبل از انجام عملیات، صحت آن را بررسی کند. این مورد باعث میشود که کدها از حالت بهینه خارج شده و در سمت سرور، Api مربوطه باید صحت آن را بررسی کند. در این مقاله قصد داریم با پیاده سازی Basic Authentication این مشکل را رفع کرده تا به کد یکدست‌تری برسیم. Basic Authentication طبق گفته ویکی پدیا در واقع یک روش در درخواست‌های ارسالی http میباشد که با فراهم سازی الزامات امنیتی، درخواست خود را به سرور ارائه میدهد. در این روش نام کاربری و کلمه عبور به جای ارسال در بدنه درخواست، در هدر درخواست قرار گرفته و الزامات امنیتی به صورت رمزگذاری شده (عموما Base64) به سمت سرور ارسال می‌شوند.
این روش به دلیل عدم وجود ذخیره کوکی، ایجاد Session و دیگر مباحث امنیتی، جز ساده‌ترین روش‌های تشخیص هویت میباشد و همچنین مشخص است به دلیل رمزگذاری ساده‌ای چون Base64 و همچنین در صورت ارسال از طریق http نه https، حفاظت چندانی در ارسال الزامات امنیتی ندارند. ولی عموما برای گوشی‌های همراه تا حد زیادی قابل قبول است. همچنین در این روش مکانیزم logout فراهم نیست و تنها در طی یک درخواست پردازش اطلاعات انجام شده و بعد از آن هویت شما نابود خواهد شد.

برای ارسال اطلاعات در هدر درخواستی، به شیوه زیر اطلاعات را ارسال میکنیم:
Authorization: Basic  Username:Password
از آنجا که گفتیم اطلاعات بالا بهتر هست در قالب خاصی رمزگذاری (encoding) شوند، خط بالا به صورت نهایی، به شکل زیر خواهد بود:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
از آنجا که این کد اعتبارسنجی باید مرتبا بررسی شود، باعث میشود که اصل تک مسئولیتی اکشن زیر سوال رفته و کدها در ابتدا مرتبا تکرار شوند. این وظیفه را بر عهده Attribute ‌ها میگذاریم. در Attribute‌های موجود در سیستم دات نت، می‌توان به AuthorizationFilterAttribute اشاره کرد که امکانات Authorization را در اختیار ما قرار میدهد. کد زیر را برای آن وارد میکنیم:
public class BasicAuthetication:AuthorizationFilterAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            if (actionContext.Request.Headers.Authorization == null)
            {
                SayYouAreUnAuthorize(actionContext);
                return;
            }

            var param = actionContext.Request.Headers.Authorization.Parameter;
            var decodedCridential = Encoding.UTF8.GetString(Convert.FromBase64String(param));
            var splitedArray = decodedCridential.Split(':');
            if (splitedArray[0] == "username" && splitedArray[1] == "password")
            {
                var userId = 1;
                var genericIdentity=new GenericIdentity(userId.ToString());
                var genericPrincipal=new GenericPrincipal(genericIdentity,null);
                Thread.CurrentPrincipal = genericPrincipal;
                return;
            }
            SayYouAreUnAuthorize(actionContext);
        }

        private void SayYouAreUnAuthorize(HttpActionContext actionContext)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);            
        }
    }

  در اولین خط از کد بررسی میشود که خاصیت Authorization در هدر درخواست وجود دارد یا خیر؛ در صورت که وجود نداشته باشد متد SayYouAreUnAuthorize  صدا زده میشود. این متد وظیفه دارد، در صورتیکه صحت نام کاربری و کلمه عبور تایید نشد، خطای مورد نظر را که با کد 401 شناخته میشود، بازگرداند که در متد اصلی دو بار مورد استفاده قرار گرفته است. با استفاده از این بازگردانی و دادن پاسخ کاربر، دیگر api مورد نظر به مرحله اجرا نمیرسد.

در صورتیکه کد ادامه پیدا کند، مقدار تنظیم شده Authorization را دریافت کرده و در خط بعدی آن را از حالت انکود شده خارج میکنیم. از آنجاکه الگوی ارسالی ما به شکل username:password میباشد، با استفاده از متد الحاقی Split هر دو عبارت را جدا کرده و در خط بعد، صحت آن دو را مشخص میکنیم. از آنجا که این تکه کد تنها یک تست است، من آن را به شکل ساده و استاتیک نوشته‌ام. بدیهی است که در یک مثال واقعی، این تایید صحت توسط یک منبع داده انجام می‌شود. در صورتی که صحت آن تایید نشود مجددا متد SayYouAreUnAuthorize مورد استفاده قرار میگیرد. در غیر این صورت باید این تایید هویت را در ترد جاری تایید کرده و حفظ کنیم و حتی در صورت لزوم Id کاربر و نقش‌های آن را ذخیره کنیم تا اگر api مورد نظر بر اساس آن تصمیم میگیرد، آن‌ها را در اختیار داشته باشیم. به عنوان مثال ممکن است اطلاعات دریافتی پرداختی‌های یک کاربر باشد که به UserId نیاز است.

از آنجا که در این روش نه ذخیره session و نه کوکی و نه مورد دیگری داریم و قصد داریم تنها در ترد یا درخواست جاری این اعتبار را نگه داریم، میتوانیم از thread.CurrentPrincipal استفاده کنیم. این خصوصیت نوع GenericPrincipal را نیاز دارد که دو پارامتر   GenereicIdentity و آرایه‌ای از نوع رشته را دریافت میکنید. این آرایه‌ها متعلق به زمانی است که شما قصد دارید نقش‌های یک کاربر را ارسال کنید و شیء GenericIdentity شیءایی است که شامل اطلاعات Authorization بوده و هیچ وابستگی به windows Domain ندارد. این شیء از شما تنها یک نام را به صورت رشته میگیرد که میتوانیم از طریق آن UserId را پاس کنیم. برای دریافت آن نیز داریم:
var userId=int.Parse(Thread.CurrentPrincipal.Identity.Name);
حال برای api به کد زیر نیاز داریم:
[BasicAuthetication]
        public HttpResponseMessage GetPayments(int type)
        {
            var userId = int.Parse(Thread.CurrentPrincipal.Identity.Name);
            if (type == 1)
            {
                return Request.CreateResponse(HttpStatusCode.OK, new
                {
                    Id = 4,
                    Price = 20000,
                    userId=userId
                });
            }
          
                return Request.CreateResponse(HttpStatusCode.OK, new
                {
                    Id = 3,
                    Price = 10000,
                    userId = userId
                });
            
        }

در api بالا attribute مدنظر بر روی آن اعمال شده و تنها مقادیر ورودی این api همان پارامترهای درخواست اصلی میباشد و ویژگی BasicAuthentication کدهای اعتبارسنجی را از کد اصلی دور نگه داشته است و api اصلی هیچگاه متوجه قضیه نمی‌شود و تنها کار اصلی خود را انجام می‌دهد. همچین در اینجا از طریق کلاس thread به UserId دسترسی داریم.

حال تنها لازم است کلاینت، قسمت هدر را پر کرده و آن را به سمت سرور ارسال کند. در اینجا من از نرم افزار I'm only resting استفاده میکنیم تا درخواست رسیده را در WebApi تست نمایم.


نظرات مطالب
کار با اسکنر در برنامه های تحت وب (قسمت دوم و آخر)
اتفاقا من این پروژه رو روی ویندوز سرویس هاست کرده بودم و مشکلی هم نداشت!
در واقع این شما نیستید که بخواهید فرمی را نشان بدهید، این مورد بر عهده کتابخانه WIA می‌باشد.
برای اون مشکل یعنی با کلاس CORSSupportBehavior هم حل نشده؟
بحث‌های نصب یک سرویس که خارج از مطلب هست اما به سادگی می‌تونید پیدا کنید، پس از نصب سرویس شما در متد OnStart این کد‌ها را خواهید داشت
    _host = new ServiceHost(typeof(WcfServiceScanner.ScannerService), _baseAddress);
    _host.Open();
و در متد OnStop هم
_host.Close();
بقیه موارد فرقی با هاست روی یک پروژه کنسول نمی‌کند.
مطالب
بلاگر و دومین سفارشی

سلام؛ نوروز مبارک!
امیدوارم در این سال جدید برقرار به مانند سیسکو، محبوب مثل گوگل، پایدار همانند اینتل، به دور از گزند مثل ویندوز 7 و موفق همانند مایکروسافت باشید!

یک دامنه‌ی جدید به نام dotnettips.info برای وبلاگ تهیه و تنظیم کردم که شرح انجام آن برای علاقمندان به صورت زیر است:

الف) خرید یک دامنه (برای مثال من از اینجا تهیه کردم)
ب) تنظیمات CNAME و A Records آن دامنه
برای مثال ممکن است کنترل پنل دامنه‌ی شما به صورت زیر باشد. در این حالت به قسمت DNS مراجعه کرده:



و در ادامه تغییرات ذیل را اعمال نمائید:
در قسمت A Records چهار آدرس IP مربوط به گوگل باید وارد شوند:



4 رکورد جدید را باید ایجاد کنید:



سپس CNAME مربوط به بلاگر باید وارد شود:



ج) اکنون به تنظیمات بلاگ خود مراجعه کرده و نام دامنه جدید را وارد نمائید:



اعمال این تغییرات بین 7 ساعت تا 24 ساعت طول خواهد کشید (مدتی طول می‌کشد تا گوگل آدرس شما را فعال کند؛ مدتی هم طول خواهد کشید تا اطلاعات DNS شما در سراسر سرورهای مرتبط در دنیا به روز شود). بنابراین در این بین، انجام این تنظیمات و رها کردن سایت به حال خود کفایت می‌کند.

ماخذ IP ها و همچنین CNAME فوق مستندات رسمی گوگل است: (+)

اگر هم برای سایت خود یک فید از نوع feedburner ثبت کرده باشید، خوانندگان فید وبلاگ شما نیاز به هیچ نوع تغییر و تنظیمی نخواهند داشت.

نظرات اشتراک‌ها
معرفی Mozilla Firefox Accounts
این امکان رو گوگل کروم قبلا اضافه کرده بود.