Top Issues Fixed in Visual Studio 2019 version 16.2.5
- Visual Studio stops respsonding on creating a new SSIS project
- Fixed UI freezes occurring after extended usage of the editor.
Security Advisory Notices
CVE-2019-1232 Diagnostics Hub Standard Collector Service Elevation of Privilege Vulnerability
An elevation of privilege vulnerability exists when the Diagnostics Hub Standard Collector Service improperly impersonates certain file operations. An attacker who successfully exploited this vulnerability could gain elevated privileges. An attacker with unprivileged access to a vulnerable system could exploit this vulnerability. The security update addresses the vulnerability by ensuring the Diagnostics Hub Standard Collector Service properly impersonates file operations.
CVE-2019-1301: Denial of Service Vulnerability in .NET Core
A denial of service vulnerability exists when .NET Core improperly handles web requests. An attacker who successfully exploited this vulnerability could cause a denial of service against a .NET Core web application. The vulnerability can be exploited remotely, without authentication.
The update addresses the vulnerability by correcting how the .NET Core web application handles web requests.
جایگزینی مناسب برای ASP.Net Identity
MembershipReboot is a user identity management and authentication library. It has nothing to do with the ASP.NET Membership Provider, but was inspired by it due to frustrations with the built-in ASP.NET Membership system. The goals are to improve upon and provide missing features from ASP.NET Membership. It is designed to encapsulate the important security logic while leaving most of the other aspects of account management either configurable or extensible for application developers to customize as needed.
سازماندهی برنامههای Angular توسط ماژولها
ویژگی جدیدی به Angular 6 به نام tree-shakable providers اضافه شدهاست که نمونهای از کاربرد آن به صورت پیشفرض در حین «ایجاد پروژهی «کتابخانه» توسط Angular CLI 6.0» ارائه میشود. به این معنا که با استفادهی از آن دیگر نیازی نیست تا سرویسهای سراسری برنامه را در قسمت providers مربوط به CoreModule ثبت کرد. همینقدر که یک سرویس سراسری را به صورت ذیل تعریف کنید:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class MyCoreService { }
در این حالت تزریق وابستگیهایی که در مطلب «تزریق وابستگیها فراتر از کلاسها در برنامههای Angular» نیز بحث شدند، پشتیبانی میشود:
@Injectable({ providedIn: 'root', useClass: LazyFlightCancellingService, deps: [NgModuleFactoryLoader, Injector] }) export class FlightCancellingService { }
به عنوان مثال کدهای مخزن کد «اعتبارسنجی کاربران در برنامههای Angular» جهت استفادهی از این قابلیت به روز شد.
Asp.Net Identity #1
- سرویس لاگر سفارشی مبتنی بر EF Core
- کنترلر نمایش اطلاعات آن
- View مرتبط
- ثبت آن در سیستم: ^ و ^
- کنترلری که خطاهای سیستم را لاگ میکند و هدایت خطاها به این کنترلر
نیاز به یک چنین قسمتی در برنامه دارید تا بتوانید از خطاهای لاگ شده گزارش بگیرید و آنها را بررسی کنید.
سؤال: آیا میشود دسترسی به فایلهای قرار گرفته در این پوشه عمومی را کنترل کرد؟ به نحوی که فقط کاربران عضو سایت پس از اعتبارسنجی بتوانند آنها را دریافت کنند؟
پاسخ: شاید عنوان کنید که میتوان از تگ location در فایل web.config برای اینکار استفاده کرد:
<location path="Export"> <system.web> <authorization> <deny users="?" /> </authorization> </system.web> </location>
سؤال: آیا راه حلی وجود دارد که بتوان فایلهای استاتیک را صرفنظر از نوع، نگارش و حالت اجرای IIS توسط موتور ASP.NET مدیریت کرد؟
پاسخ: بلی. در ASP.NET MVC با تنظیم یک سطر ذیل، اینکار انجام میشود:
public static void RegisterRoutes(RouteCollection routes) { // ... routes.RouteExistingFiles = true; // ... }
RouteCollection در ASP.NET MVC به کمک امکانات MapPathBasedVirtualPathProvider خود، ابتدا درخواست رسیده را بررسی میکند. اگر این درخواست به یک فایل عمومی اشاره کند، کل سیستم مسیریابی را غیرفعال میکند. اما با تنظیم RouteExistingFiles دیگر این بررسی صورت نخواهد گرفت (به عبارتی در بالا بردن سرعت نمایشی سایت نیز تاثیر گذار خواهد بود؛ چون یکی از بررسیها را حذف میکند).
ایجاد کنترلری به نام پوشهای که قرار است محافظت شود
نام پوشه قرار گرفته در ریشه سایت، Export است. بنابراین برای هدایت درخواستهای رسیده به آن (پس از تنظیم فوق)، نیاز است یک کنترلر جدید را به نام Export نیز ایجاد کنیم:
using System.IO; using System.Web.Mvc; namespace Mvc4RouteExistingFiles.Controllers { public class ExportController : Controller { public ActionResult Index(string id) { if (string.IsNullOrWhiteSpace(id)) { return Redirect("/"); } var fileName= Path.GetFileName(id); var path = Server.MapPath("~/export/"+ fileName); return File(path, System.Net.Mime.MediaTypeNames.Application.Octet, fileName); } } }
برای اینکه بررسی کنیم، آیا واقعا فایلهای استاتیک قرار گرفته در پوشه Export به این کنترلر هدایت میشود یا خیر، یک breakpoint را بر روی سطر اول اکشن متد Index قرار میدهیم. برنامه را اجرا کنید ... کار نخواهد کرد، زیرا مسیر یک فایل فرضی به صورت ذیل:
http://localhost/export/test.pdf
برای حل این مشکل فقط کافی است مسیر یابی متناظری را تعریف کنیم:
using System.Web.Mvc; using System.Web.Routing; namespace Mvc4RouteExistingFiles { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.RouteExistingFiles = true; routes.MapRoute( name: "ExportRoute", url: "Export/{id}", defaults: new { controller = "Export", action = "Index", id = UrlParameter.Optional } ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
اینبار اگر برنامه را اجرا کنیم، breakpoint ما کار خواهد کرد:
تنظیمات ثانویه پس از فعال سازی RouteExistingFiles
در این حالت با فعال سازی مسیریابی فایلهای موجود، دیگر هیچ فایل استاتیکی به صورت معمول در اختیار کاربران قرار نخواهد گرفت و اگر همانند توضیحات قبل برای آنها کنترلر جداگانهای را تهیه نکنیم، عملا سایت از کار خواهد افتاد.
برای رفع این مشکل، در ابتدای متد RegisterRoutes فوق، تنظیمات ذیل را اضافه کنید تا پوشههای content، scripts و همچنین یک سری فایل با پسوند مشخص، همانند سابق و مستقیما توسط سرور ارائه شوند؛ در غیراینصورت کاربر پیغام 404 را پس از درخواست آنها، دریافت خواهد کرد:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.IgnoreRoute("content/{*pathInfo}"); routes.IgnoreRoute("scripts/{*pathInfo}"); routes.IgnoreRoute("favicon.ico"); routes.IgnoreRoute("{resource}.ico"); routes.IgnoreRoute("{resource}.png"); routes.IgnoreRoute("{resource}.jpg"); routes.IgnoreRoute("{resource}.gif"); routes.IgnoreRoute("{resource}.txt");
public class Startup { public void ConfigureServices(IServiceCollection services) { // ... services.AddTransient<ICustomerService, DefaultCustomerService>(); // ... } }
public class SupportController { // DefaultCustomerService will be injected here: public SupportController(ICustomerService customerService) { // ... } }
برای سفارشی سازی مراحل وهله سازی اشیاء توسط IoC Container توکار برنامه و امکان دخالت در آن، قابلیتی تحت عنوان «factory registration» نیز پیش بینی شدهاست که در ادامه آنرا بررسی میکنیم.
Factory Registration چیست؟
اگر در اسمبلی Microsoft.Extensions.DependencyInjection.Abstractions و فضای نام Microsoft.Extensions.DependencyInjection آن به کلاس ServiceCollectionServiceExtensions که متدهای الحاقی مانند AddScoped را ارائه میکند، بیشتر دقت کنیم، تک تک این متدها امضاهای دیگری را نیز دارند:
namespace Microsoft.Extensions.DependencyInjection { public static class ServiceCollectionServiceExtensions { public static IServiceCollection AddScoped<TService>( this IServiceCollection services) where TService : class; public static IServiceCollection AddScoped( this IServiceCollection services, Type serviceType, Type implementationType); public static IServiceCollection AddScoped( this IServiceCollection services, Type serviceType, Func<IServiceProvider, object> implementationFactory); public static IServiceCollection AddScoped<TService, TImplementation>(this IServiceCollection services) public static IServiceCollection AddScoped( this IServiceCollection services, Type serviceType); public static IServiceCollection AddScoped<TService>( this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory) where TService : class; public static IServiceCollection AddScoped<TService, TImplementation>( this IServiceCollection services, Func<IServiceProvider, TImplementation> implementationFactory) // ... } }
مثال 1 : تزریق وابستگیها در حالتیکه کلاس سرویس مدنظر دارای تعدادی پارامتر ثابت است
IoC Container توکار برنامههای NET Core.، به صورت خودکار وابستگیهای تزریق شدهی در سازندههای سرویسهای مختلف را تا هر چند سطح ممکن، به صورت خودکار وهله سازی میکند؛ به شرطیکه این وابستگیهای تزریق شده نیز خودشان سرویس بوده باشند و در تنظیمات ابتدایی آن ثبت و معرفی شده باشند. به عبارتی زمانیکه با سیستم تزریق وابستگیها کار میکنیم، مهم نیست که نگران مقدار دهی پارامترهای سازندهی تزریق شدهی در سازندههای سرویسی خاص باشیم. اما ... برای نمونه سرویس زیر را که یک رشته را در سازندهی خود دریافت میکند درنظر بگیرید:
namespace CoreIocServices { public interface IParameterizedService { string GetConstructorParameter(); } public class ParameterizedService : IParameterizedService { private readonly string _connectionString; public ParameterizedService(string connectionString) { _connectionString = connectionString; } public string GetConstructorParameter() { return _connectionString; } } }
services.AddTransient<IParameterizedService, ParameterizedService>();
services.AddTransient<IParameterizedService>(serviceProvider => { return new ParameterizedService("some value ...."); });
services.AddTransient<IParameterizedService>(serviceProvider => new ParameterizedService("some value ...."));
در اینجا چون serviceProvider نیز در اختیار ما است، حتی میتوان این مقدار را از سرویسی دیگر دریافت کرد و سپس مورد استفاده قرار داد:
services.AddTransient<IParameterizedService>(serviceProvider => { var config = serviceProvider.GetRequiredService<ITestService>().GetConfigValue(); return new ParameterizedService(config); });
نمونهی دیگری از این دست، کار با IUrlHelper توکار ASP.NET Core است. این سرویس برای اینکه پاسخ درستی را ارائه دهد، نیاز به ActionContext جاری را دارد تا بتواند از طریق آن به تمام جزئیات اکشن متد یک کنترلر و درخواست رسیده دسترسی داشته باشد. در این حالت برای ساده سازی کار با آن، بهتر است تامین وابستگیهای لحظهای این سرویس را با سفارشی سازی نحوهی وهله سازی آن، انجام دهیم، تا اینکه این قطعه کد تکراری را در هر جائیکه به IUrlHelper نیاز است، تکرار کنیم:
services.AddScoped<IUrlHelper>(serviceProvider => { var actionContext = serviceProvider.GetRequiredService<IActionContextAccessor>().ActionContext; var urlHelperFactory = serviceProvider.GetRequiredService<IUrlHelperFactory>(); return urlHelperFactory.GetUrlHelper(actionContext); });
مثال 2: وهله سازی در صورت نیاز به وابستگیهای یک سرویس، به کمک Lazy loading
فرض کنید دو سرویس را در سازندهی سرویس دیگری تزریق کردهاید:
namespace Services { public class OrderHandler : IOrderHandler { private readonly IAccounting _accounting; private readonly ISales _sales; public OrderHandler(IAccounting accounting, ISales sales) {
روش انجام یک چنین کارهایی با استفاده از کلاس Lazy اضافه شدهی به NET 4x. قابل انجام است:
public class OrderHandlerLazy : IOrderHandler { public OrderHandlerLazy(Lazy<IAccounting> accounting, Lazy<ISales> sales) {
services.AddTransient<IOrderHandler, OrderHandlerLazy>(); services.AddTransient<IAccounting, Accounting>() .AddTransient(serviceProvider => new Lazy<IAccounting>(() => serviceProvider.GetRequiredService<IAccounting>())); services.AddTransient<ISales, Sales>() .AddTransient(serviceProvider => new Lazy<ISales>(() => serviceProvider.GetRequiredService<ISales>()));
- سپس سرویسهایی که قرار است به صورت Lazy نیز واکشی شوند، بار دیگر توسط روش factory registration با وهله سازی new Lazy از نوع سرویس مدنظر و فراهم آوردن پیاده سازی آن با استفاده از serviceProvider.GetRequiredService، مجددا معرفی خواهند شد.
پس از این تنظیمات، اگر سرویس IOrderHandler را از طریق سیستم تزریق وابستگیها درخواست کنید، وابستگیهای تزریق شدهی در سازندهی آن فقط زمانی و در محلی وهله سازی میشوند که از طریق خاصیت Value شیء Lazy آنها مورد استفاده قرار گرفته شده باشند.
مثال کامل IOrderHandler را از فایل پیوستی انتهای مطلب میتوانید دریافت. اگر آنرا اجرا کنید (برنامهی کنسول آنرا)، در خروجی آن، فقط اجرا شدن سازندهی سرویسی را مشاهده میکنید که مورد استفاده قرار گرفته و نه وابستگی دومی که تزریق شده، اما استفاده نشدهاست.
مثال 3: چگونه بجای اینترفیسها، یک وهله از کلاسی مشخص را از سیستم تزریق وابستگیها درخواست کنیم؟
فرض کنید سرویسی را به صورت زیر به سیستم تزریق وابستگیها معرفی کردهاید:
services.AddTransient<IMyDisposableService, MyDisposableService>();
public class AnotherController { public AnotherController(MyDisposableService customerService) { // ... } }
An unhandled exception occurred while processing the request. InvalidOperationException: Unable to resolve service for type ‘MyDisposableService’ while attempting to activate ‘AnotherController’. Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
services.AddTransient<IMyDisposableService, MyDisposableService>(); services.AddTransient<MyDisposableService>(serviceProvider => serviceProvider.GetRequiredService<IMyDisposableService>() as MyDisposableService);
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: CoreDependencyInjectionSamples-06.zip