اشتراک‌ها
بکارگیری Microsoft Report در Mvc

In this post, I explain how to use Microsoft Report in MVC 4. Most of the developer use Microsoft Report (rdlc) for generating report  in asp.net application. Here I have explained how we can use Microsoft Report (rdlc) in MVC 

بکارگیری Microsoft Report در Mvc
نظرات مطالب
نحوه اضافه کردن Auto-Complete به جستجوی لوسین در ASP.NET MVC و Web forms
نحوه استفاده از افزونه Firebug برای دیباگ برنامه‌های ASP.NET مبتنی بر jQuery  
- بررسی کنید آیا ID جعبه متنی در آن صفحه، term است یا چیز دیگری؟ اگر تغییر کرده، ClientIDMode=Static بهتر است تنظیم شود.
مطالب
جلوگیری از ورود همزمان کاربران با نام کاربری و رمز عبور یکسان
در اکثر برنامه‌های وب، کاربر قادر است با یک نام کاربری و رمز عبور در چند Session همزمان لاگین کند. ممکن است سیاست برخی مدیران محصول این باشد که جلوی این مورد را بگیرند تا به عنوان مثال کاربران را به جای استفاده‌ی همزمان از یک نام کاربری و رمز عبور، مجبور به خرید مجوز‌های بیشتری کنند. ASP.NET Identity به صورت پیش فرض این مورد را پشتیبانی نمی‌کند؛ اما به کمک استفاده از امکانات درونی آن می‌توان این پشتیبانی را اضافه کرد.
یکی از فیلد‌های جدول AspNetUsers فیلد SecurityStamp می‌باشد. SecurityStamp یک مقدار تصادفی است:


Security Stamp باید با هربار تغییر اطلاعات احراز هویت (مانند رمز عبور) و اختیارات کاربر(Role) تغییر کند. به عنوان مثال کاربری در چند مرورگر لاگین کرده و گزینه‌ی مرا به خاطر داشته باش را انتخاب کرده است. اگر این کاربر رمز عبورش از هر جایی عوض شود، باید لاگین او در همه‌ی Session‌ها غیر معتبر شود. این مورد با تغییر کردن SecurityStamp بعد از تغییر رمز عبور صورت می‌گیرد. ASP.NET مقدار SecurityStamp را در کوکی کاربر نگه می‌دارد و در بازه‌های زمانی، این مقدار را با مقدار درون دیتابیس مقایسه می‌کند و در صورت عدم برابری، کاربر را احراز هویت نمی‌کند. بازه‌ی زمانی این بررسی در متد ConfigureAuth قابل تنظیم است که در ادامه شرح داده خواهد شد.
صورت مساله یافتن راه حلی جهت جلوگیری از ورود همزمان چند کاربر با یک نام کاربری و رمز عبور به سیستم می‌باشد. یکی از راه‌حل هایی که در ابتدا به ذهن می‌آید استفاده از Session و نگهداری کاربران لاگین کرده در حافظه می‌باشد. پیاده سازی این راه حل می‌تواند به کمک یک کلاس Static صورت پذیرد، اما قسمت چالشی این موضوع این است که چه زمانی باید کاربر از لیست حذف گردد؟ اگر اتصال کاربر قطع شود چه عملی باید صورت گیرد؟
راه حل دیگر استفاده از SecurityStamp هست؛ به این صورت که با هربار لاگین کاربر این مقدار تصادفی به‌روز گردد و ASP.NET Identity به گونه‌ای تنظیم شود که با هر درخواست HTTP، صحت SecurityStamp بررسی گردد. مقدار پیش فرض بازه‌ی زمانی بررسی، هر 30 دقیقه یک بار است.
در مثال‌های رسمی ASP.NET Identity لاگین به صورت ذیل پیاده سازی شده است:
   
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }
            // This doesn't count login failures towards account lockout
            // To enable password failures to trigger account lockout, change to shouldLockout: true
            var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
            switch (result)
            {
                case SignInStatus.Success:
                    return RedirectToLocal(returnUrl);
                case SignInStatus.LockedOut:
                    return View("Lockout");
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "Invalid login attempt.");
                    return View(model);
            }
        }
این کد را باید به گونه‌ای تغییر داد که اگر نام کاربری و رمز عبور معتبر بودند، مقدار SeucrityStamp به‌روز گردد. به همین منظور قبل از فراخوانی PasswordSignInAsync کد ذیل اضافه می‌گردد:
       var loggedinUser = await UserManager.FindAsync(model.Email, model.Password);
            if (loggedinUser != null)
            {
                await UserManager.UpdateSecurityStampAsync(loggedinUser.Id);
            }
همانطور که مشاهده می‌شود، جهت بروز رسانی SecurityStamp از سازوکار درونی ASP.NET Identity، در واقع متد UpdateSecurityStampAsync بهره گرفته شده است.
اکنون باید تنظیمات پیش‌فرض بازه‌ی زمانی بررسی صحت SecurityStamp تغییر داده شود. این تنظیمات در فایل Startup.Auth.cs در پوشه‌ی App_Start قرار دارند:
     app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    // Enables the application to validate the security stamp when the user logs in.
                    // This is a security feature which is used when you change a password or add an external login to your account.  
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });
در کد بالا OnValidateIdentity باید مقدار ذیل را بگیرد:
OnValidateIdentity =
                        SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                            TimeSpan.FromMinutes(0), // <-- Note the timer is set for zero
                            (manager, user) => user.GenerateUserIdentityAsync(manager))
اکنون Framework موظف است در هر درخواست HTTP، صحت SeucirtyStamp را بررسی کند. بنابراین اگر کاربری در سیستم لاگین باشد و کاربر دیگری با همان نام کاربری و رمز عبور لاگین کند، کاربر اول از سیستم لاگ اوت می‌شود؛ چرا که مقدار SecurityStamp او دیگر معتبر نیست. باید در نظر گرفته شود این عمل در سیستم‌های با تعداد کاربر زیاد باعث افزایش درخواست‌های دیتابیس می‌شود. 
اکنون جهت تست، اگر با مرورگر اول در سیستم لاگین صورت گیرد، سپس با همان اطلاعات در مرورگری دیگر، لاگین صورت گیرد، کاربر اول پس از درخواست بعدی، از سیستم لاگ اوت می‌شود. در مثال انتهای مطلب، صفحه‌ی About به صورت غیر عمومی درآمده که می‌توان بررسی راه حل جاری را در آن صفحه صورت داد. 
اگر بخواهیم لاگ اوت شدن کاربر را آنی کنیم، می‌توان در فواصل زمانی مشخصی، یک درخواست Ajax از سمت کلاینت به سرور ارسال کرد و تصدیق هویت کاربر را بررسی کرد:
        window.setInterval(function() {
            $.ajax({
                url:,
                type: "Post",
                dataType: "json",
                success: function(data) {
                    if (!data) {
                        alert("Someone has logged in using your username and password!");
                        location.reload();
                    }
                }
            });
        }, 60000);
در کد بالا به کمک window.setInterval، هر یک دقیقه یک بار لاگین بودن کاربر بررسی می‌گردد و در صورت لاگین نبودن، پیغام لازم به کاربر نمایش داده می‌شود. در نظر داشته باشید، این کد تنها باید در صفحات غیر عمومی قرار داده شود.
کد اکشن بررسی لاگین بودن به سادگی ذیل است:
        [AllowAnonymous]
        public virtual ActionResult Authenticated()
        {
            return Json(User.Identity.IsAuthenticated);
        }

نکته‌ی مهم این است که خصیصه‌ی AllowAnonymous بالای اکشن قرار گرفته باشد تا در صورتیکه Controller به صورت عمومی در دسترس نیست، اکشن همیشه و حتی وقتی کاربر لاگ اوت شده در دسترس باشد. در مثال انتهای مطلب صفحه‌ی About تنها در اختیار کاربران احراز هویت شده قرار گرفته است، بنابراین اگر دو کاربر با اطلاعات یکسانی به سیستم لاگین کنند، کاربر اول پیغام خطای ذیل را گرفته و به صفحه‌ی لاگین می‌رود. این کد در صفحه‌ی About در مثال انتهای مطلب قرار گرفته است:

اشتراک‌ها
پروژه coolstore براساس معماری مایکروسرویس ها

CoolStore is a containerised polyglot microservices application consisting of services based on .NET Core, NodeJS and more running on Service Mesh. It demonstrates how to wire up small microservices into a larger application using microservice architectural principals. 

پروژه coolstore براساس معماری مایکروسرویس ها
مطالب
C# 8.0 - پیشنیاز و روش راه اندازی
پیشنیاز کار با C# 8.0

هرچند بسیاری از قابلیت‌های C# 8.0 در خود کامپایلر #C پیاده سازی شده‌اند، اما برای مثال قابلیتی مانند «پیاده سازی پیش‌فرض اینترفیس‌ها» نیاز به یک runtime جدید دارد که به همراه NET Core 3.0. ارائه می‌شود. بنابراین NET Full 4x. شاهد پیاده سازی C# 8.0 نخواهد بود. همچنین یک سری از قابلیت‌های C# 8.0 وابسته‌ی به NET Standard 2.1. و  netcoreapp3.0  هستند؛ مانند نوع‌های جدید System.IAsyncDisposable و یا System.Range. به همین جهت است که برای کار با C# 8.0، حتما نیاز به نصب NET Core 3.0. نیز می‌باشد و به روز رسانی کامپایلر #C کافی نیست.


چه نگارش‌هایی از Visual Studio از NET Core 3.0. پشتیبانی می‌کنند؟

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

.NET Core SDK .NET Core Runtime Compatible Visual Studio MSBuild Notes
2.1.5nn 2.1 2017 15 Installed as part of VS 2017 version 15.9
2.1.6nn 2.1 2019 16 Installed as part of VS 2019
2.2.1nn 2.2 2017 15 Installed manually
2.2.2nn 2.2 2019 16 Installed as part of VS 2019
3.0.1nn 3.0 (Preview) 2019 16 Installed manually

بنابراین فقط VS 2019 است که قابلیت پشتیبانی از NET Core 3.0. را دارد. به همین جهت اگر قصد دارید با ویژوال استودیو کار کنید، نصب VS 2019 برای کار با C# 8.0 الزامی است.


فعالسازی C# 8.0 در ویژوال استودیو 2019

در زمان نگارش این مطلب، NET Core 3.0. در حالت پیش‌نمایش، ارائه شده‌است. به همین جهت جزء یکپارچه‌ی VS 2019 محسوب نشده و باید جداگانه نصب شود:


- برای این منظور ابتدا نیاز است آخرین نگارش NET Core 3.0 SDK. را دریافت و نصب کنید.
- سپس از منوی Tools | Options، گزینه‌ی Projects and Solutions را انتخاب و در ادامه گزینه‌ی Use previews of the .NET Core SDK را انتخاب کنید.
- پس از آن، این SDK جدید NET Core. به صورت زیر قابل انتخاب خواهد بود:


البته انتخاب شماره SDK صحیح به تنهایی برای کار با C# 8.0 کافی نیست؛ بلکه باید شماره‌ی زبان مورد استفاده را نیز صریحا انتخاب کرد:


برای اینکار بر روی پروژه کلیک راست کرده و گزینه‌ی Properties آن‌را انتخاب کنید. سپس در اینجا در برگه‌ی Build، بر روی دکمه‌ی Advanced کلیک کنید تا بتوان شماره نگارش زبان را مطابق تصویر فوق انتخاب کرد. در اینجا بجای C# 8.0 (beta)، گزینه‌ی unsupported preview را نیز می‌توانید انتخاب کنید.

یک نکته: خلاصه‌ی تمام این مراحل، منوها و تصاویر، همان تنظیمات فایل csproj است که در ادامه بررسی می‌کنیم.


فعالسازی C# 8.0 در VSCode

مدت‌ها است که برای کار با NET Core. نیازی به استفاده‌ی از نگارش کامل ویژوال استودیو نیست. همینقدر که VSCode را به همراه افزونه‌ی #C آن نصب کرده باشید، می‌توانید برنامه‌های مبتنی بر NET Core. را بر روی سیستم عامل‌های مختلفی که NET Core SDK. بر روی آن‌ها نصب شده‌است، توسعه دهید.
پشتیبانی ابتدایی از C# 8.0، با نگارش v1.18.0 افزونه‌ی #C مخصوص VSCode ارائه شد. بنابراین هم اکنون اگر آخرین نگارش آن‌را نصب کرده باشید، امکان کار با پروژه‌های NET Core 3.0 و C# 8.0 را نیز دارید.
بنابراین در اینجا به صورت خلاصه:
- ابتدا باید NET Core 3.0 SDK. را به صورت جداگانه‌ای دریافت و نصب کنید.
- سپس آخرین نگارش افزونه‌ی #C مخصوص VSCode را نیز نصب کنید.
- در آخر، یک پوشه‌ی جدید را ایجاد کرده و در خط فرمان دستور dotnet new console را صادر کنید. این دستور بر اساس آخرین شماره نگارش SDK نصب شده، یک پروژه‌ی جدید کنسول را ایجاد می‌کند که ساختار فایل csproj آن به صورت زیر است:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>
</Project>
همانطور که مشاهده می‌کنید، TargetFramework را به آخرین SDK نصب شده، تنظیم کرده‌است (معادل دومین تصویر این مطلب). مرحله‌ی بعد، تنظیم شماره نگارش زبان آن است. برای این منظور یکی از دو حالت زیر را می‌توان انتخاب کرد:
- یا معادل همان گزینه‌ی unsupported preview در تصویر سوم این مطلب:
<Project Sdk="Microsoft.NET.Sdk"> 
   <PropertyGroup> 
      <OutputType>Exe</OutputType> 
      <TargetFramework>netcoreapp3.0</TargetFramework> 
      <LangVersion>preview</LangVersion> 
   </PropertyGroup>
 </Project>
- و یا تعیین صریح شماره نگارش C# 8.0 (beta) به صورت زیر:
<Project Sdk="Microsoft.NET.Sdk"> 
   <PropertyGroup> 
      <OutputType>Exe</OutputType> 
      <TargetFramework>netcoreapp3.0</TargetFramework> 
      <LangVersion>8.0</LangVersion> 
   </PropertyGroup>
</Project>

یک نکته: در اینجا نمی‌توان LangVersion را به latest تنظیم کرد؛ چون C# 8.0 هنوز در مرحله‌ی بتا است. زمانیکه از مرحله‌ی بتا خارج شد، مقدار پیش‌فرض آن دقیقا latest خواهد بود و ذکر صریح آن غیر ضروری است. انتخاب latest در اینجا به latest minor version یا همان نگارش C# 7.3 فعلی (آخرین نگارش پایدار زبان #C در زمان نگارش این مطلب) اشاره می‌کند.



Rider و پشتیبانی از C# 8.0

Rider 2019.1 نیز به همراه پشتیبانی از C# 8.0 ارائه شده‌است و می‌تواند گزینه‌ی مطلوب دیگری برای توسعه‌ی برنامه‌های مبتنی بر NET Core. باشد.


نصب NET Core 3.0 SDK. و عدم اجرای برنامه‌های پیشین

یکی از مزایای کار با NET Core.، امکان نصب چندین نوع مختلف SDK آن، به موازت هم است؛ بدون اینکه بر روی یکدیگر تاثیری بگذارند. البته این نکته را باید درنظر داشت که برنامه‌های NET Core. بدون وجود فایل مخصوص global.json در پوشه‌ی ریشه‌ی آن‌ها، همواره از آخرین نگارش SDK نصب شده، برای اجرا استفاده خواهند کرد. اگر این مورد بر روی کار شما تاثیرگذار است، می‌توانید شماره SDK مورد استفاده‌ی برنامه‌ی خود را قفل کنید، تا SDKهای جدید نصب شده، به عنوان SDK پیش‌فرض برنامه‌های پیشین، انتخاب نشوند. بنابراین ابتدا لیست SDKهای نصب شده را با دستور زیر پیدا کنید:
> dotnet --list-sdks
سپس برای پروژه‌های قدیمی خود که فعلا قصد به روز رسانی آن‌ها را ندارید، یک فایل global.json را به صورت زیر‌، در ریشه‌ی پروژه تولید کنید:
> dotnet new globaljson --sdk-version 2.2.300
> type global.json
در اینجا 2.2.300 یکی از شماره‌هایی است که توسط دستور dotnet --list-sdks یافته‌اید و پروژه‌ی قبلی شما بر اساس آن کار می‌کند.
نظرات مطالب
اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity
خیر. شیء this.User با اطلاعات جدول کاربران، تناظر یک به یک ندارد. از نگارش‌های پیشین ASP.NET ، هنوز هم اطلاعات شیء User مانند User.Identity.Name در ASP.NET Core نیز در دسترس هستند. به این ترتیب زمانیکه کاربری به سیستم وارد شد، دیگر نیازی نیست تا جهت یافتن Name او، از بانک اطلاعاتی کوئری گرفت. خاصیت Name یاد شده به صورت خودکار از کوکی رمزنگاری شده‌ی و یا در اینجا از توکن او دریافت شده و در اختیار برنامه قرار می‌گیرد. این Name در ASP.NET Core Identity، اصطلاحا یک User Claim پیش‌فرض نام دارد و به صورت خودکار ایجاد و مقدار دهی می‌شود. روش مقدار دهی اولیه‌ی آن هم در متد createAccessTokenAsync مشخص است. هر زمانیکه این توکن به سمت سرور ارسال می‌شود، پس از اعتبارسنجی توکن و پذیرش آن، این Claims هم پردازش شده و جزئی از اطلاعات شیء this.User می‌شوند.