نظرات مطالب
Blazor 5x - قسمت 33 - احراز هویت و اعتبارسنجی کاربران Blazor WASM - بخش 3- بهبود تجربه‌ی کاربری عدم دسترسی‌ها
یا اگر نمونه‌ی AuthorizationHandler سفارشی آن‌را نیاز داشتید، به صورت زیر است:
- ابتدا یک IAuthorizationRequirement و AuthorizationHandler سفارشی را ایجاد می‌کنیم که در هندلر آن دسترسی کاملی به اطلاعات کاربر وارد شده‌ی به سیستم وجود دارد:
public class UserCanSeeProjectRequirement : IAuthorizationRequirement
{
    public UserCanSeeProjectRequirement() { }

}


public class UserCanSeeProjectHandler : AuthorizationHandler<UserCanSeeProjectRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, 
                                                   UserCanSeeProjectRequirement requirement)
    {
        //claim-based validation
        if (context.User.HasClaim("permission.cansee", "CanSee"))
                context.Succeed(requirement);

        //role-based validation
        if (context.User.IsInRole("admin") || context.User.IsInRole("user"))
                context.Succeed(requirement);

        return Task.CompletedTask;
    }
}
سپس نیاز است این اطلاعات را به برنامه‌ی کلاینت معرفی کرد:
namespace BlazorWasm.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            // ...

            services.AddScoped<IAuthorizationHandler, UserCanSeeProjectHandler>();
            services.AddAuthorizationCore(options => {
                options.AddPolicy("UserCanSeeProjectPolicy", policy => policy.Requirements.Add(new UserCanSeeProjectRequirement()));
            });

            // ...
        }
    }
}
و در نهایت می‌توان Policy جدید فوق را که با نام UserCanSeeProjectPolicy معرفی شده، یا به صورت زیر در ابتدای یک صفحه:
@attribute [Authorize(Policy = "UserCanSeeProjectPolicy")]
و یا در قسمتی از آن صفحه استفاده کرد:
<AuthorizeView Policy="UserCanSeeProjectPolicy">
    <NotAuthorized>
       <h2 class="mt-5">You are not authorized to view this page</h2>
    </NotAuthorized>
    <Authorized>
      <div class="container my-profile">
        --- Place here all the content you want your user to view ----
      </div>
    </Authorized>
</AuthorizeView>
نظرات مطالب
ارسال ایمیل در ASP.NET Core
ممنون از راهنمایی شما و با تشکر از تهیه سرویس‌های مفید در کتابخانه DNT

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

اول اینکه فرمودید ارسال ایمیل آنی است: برای یک ایمیل طبعا چنین به نظر میاد ولی برای تعداد بالای ایمیل، UI قفل میشه با استفاده از سرویس WebMailService  در کتابخانه‌ی DNT و البته برای اجتناب از این مشکل نمیشه هم که بدون await ازش استفاده کرد به خاطر نیازمندی‌های سرویس رندرویو در این کتابخانه.

دوم اینکه عنوان شده بود که سرویس هایی که به صورت بکگراند معرفی میشن غالبا غیر HTTP هستن و اما بنده به سرویس HttpContextAccessor نیاز دارم برای کار مورد نظرم و از طرفی خود شما هم در ارسال ایمیل به صورت قالب‌های از پیش تعیین شده HTML و در داخل سرویس ویورند کتابخانه DNT از HttpContextAccessor   استفاده کردید. 

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

چهارم اینکه در این نوع سرویس‌ها ظاهرا فقط یکبار در ابتدای برنامه متد ExecuteAsync   اجرا میشه که تعداد و نوع پارامترهای ورودیش مشخصه که فقط یک CancellationToken هست و بنابراین چطور میشه بهش اطلاع داد که چه زمانی (نه به صورت زمان بندی شده و بلکه به صورت آنی) کار مورد نظر رو انجام بده  (مثلا ارسال ایمیل از طریق سرویس  WebMailService موجود در کتابخانه DNT شما به تعدادی کاربر)

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

ممنون از حوصله و راهنمایی شما.
نظرات مطالب
معرفی System.Text.Json در NET Core 3.0.
یک نکته‌ی تکمیلی: روش تزریق وابستگی‌ها به تنظیمات MvcBuilder در متد ConfigureServices

- روش دیگر آن به کمک IConfigureOptions و معرفی آن به سیستم تزریق وابستگی‌ها است تا وابستگی‌های آن‌را به صورت خودکار تامین کند:
    public class AppJsonOptions : IConfigureOptions<JsonOptions>
    {
        private readonly IHttpContextAccessor _accessor;

        public AppJsonOptions(IHttpContextAccessor accessor)
        {
            _accessor = accessor;
        }

        public virtual void Configure(JsonOptions options)
        {
            options.JsonSerializerOptions.Converters.Add(new BooleanConverter(_accessor));
        }
    }

پس از این تعریف، نحوه‌ی معرفی آن به سیستم به صورت زیر خواهد بود:
    public void ConfigureServices(IServiceCollection services)
    {
       services.AddHttpContextAccessor();
       services.AddSingleton<IConfigureOptions<JsonOptions>, AppJsonOptions>();

و Converter تعریف شده هم به این نحو می‌تواند به وابستگی‌ها دسترسی پیدا کند:
    public class BooleanConverter : JsonConverter<bool>
    {
        private readonly IHttpContextAccessor _accessor;

        public BooleanConverter(IHttpContextAccessor accessor)
        {
            _accessor = accessor;
        }

        public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var testService = _accessor.HttpContext.RequestServices.GetRequiredService<TestService>();

            // ...
            throw new NotSupportedException();
        }

        public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
        {
        }
    }

علت استفاده‌ی از IHttpContextAccessor در اینجا این است که چون IConfigureOptions به صورت Singleton ثبت می‌شود، بنابراین فقط سرویس‌هایی با طول عمر Singleton را هم می‌توان به آن تزریق کرد؛ اما RequestServices.GetRequiredService این محدودیت را ندارد.
نظرات مطالب
ابزارهای سراسری در NET Core 2.1.
یک نکته‌ی تکمیلی: معرفی ابزارهای محلی در NET Core 3.0.

تا پیش از NET Core 3.0.، ابزارهای NET Core. به عنوان NET Core Global Tools. شناخته می‌شدند. اما اگر به ازای پروژه‌های مختلف، بخواهیم از نگارش‌های مختلفی از این ابزارها استفاده کنیم، چطور؟ این مشکل با معرفی NET Core Local Tools. در NET Core 3.0. برطرف شده‌است.
برای کار با آن، ابتدا نیاز است فایل خالی manifest ای را تولید کرد:
dotnet new tool-manifest
که برای نمونه در مسیر config/dotnet-tools.json. پروژه‌ی جاری با محتوای زیر تولید می‌شود:
{
  "version": 1,
  "isRoot": true,
  "tools": {}
}
سپس می‌توان tools مدنظر را به این فایل اضافه کرد. مثلا ابزار Cake.Tool را به صورت محلی در آن نصب و ثبت کرد:
dotnet tool install Cake.Tool
که دستور فوق، فایل dotnet-tools.json پروژه را به صورت زیر ویرایش می‌کند:
{
  "version": 1,
  "isRoot": true,
  "tools": {
    "cake.tool": {
      "version": "0.34.1",
      "commands": [
        "dotnet-cake"
      ]
    }
  }
}
پس از آن دستورات کار با این ابزار، در پوشه‌ی پروژه‌ی جاری میسر می‌شوند و بدیهی است شماره نگارش این ابزار محلی نصب شده، در هر پروژه‌ای می‌تواند متفاوت باشد.

یک نکته: اگر مسیر config/dotnet-tools.json. را به سورس کنترل خود اضافه کردید، دیگران برای بازیابی و کار با آن، می‌توانند دستور زیر را اجرا کنند:
dotnet tool restore
نظرات مطالب
مهارت‌های تزریق وابستگی‌ها در برنامه‌های NET Core. - قسمت چهارم - پرهیز از الگوی Service Locator در برنامه‌های وب
ارتقاء به ASP.NET Core 3.0: محدود شدن امکان تزریق وابستگی‌ها در سازنده‌ی کلاس آغازین برنامه

یکی از تغییرات مهم ASP.NET Core 3.0 نسبت به نگارش‌های قبلی، جنریک شدن Host آن است (چون حالت‌های هاستینگ بیشتری را نسبت به حالت صرف MVC پشتیبانی می‌کند). به این ترتیب HostBuilder نگارش 2x:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                 WebHost.CreateDefaultBuilder(args)
                 .UseStartup<Startup>();
اکنون در نگارش 3x به این صورت در آمده‌است:
public static IHostBuilder CreateHostBuilder(string[] args) =>
               Host.CreateDefaultBuilder(args)
                     .ConfigureWebHostDefaults(webBuilder =>
                     {
                        webBuilder.UseStartup<Startup>();
                     });
این مورد، یک تغییر مهم را هم در وضعیت تزریق وابستگی‌های سفارشی در کلاس آغازین برنامه ایجاد کرده‌است: در نگارش 3x، فقط و فقط سرویس‌های IHostEnvironment ،IWebHostEnvironment و IConfiguration را می‌توانید به سازنده‌ی کلاس آغازین آن تزریق کنید.
علت اینجا است که در ASP.NET Core 3x، یک باگ بسیار مهم سیستم تزریق وابستگی‌های ASP.NET Core برطرف شده‌است: اکنون فقط یک dependency injection container به ازای کل برنامه‌ی ASP.NET Core 3x ساخته می‌شود. در نگارش‌های قبلی، یک container برای برنامه و یک container مجزا برای host تولید می‌شدند. در این حالت اگر یک سرویس Singleton را در فایل program.cs معرفی می‌کردید:
WebHost.CreateDefaultBuilder()
             .UseStartup<Startup>()
             .ConfigureServices(services => 
                     services.AddSingleton<MySingleton>())
             .Build()
             .Run();
برخلاف تصور، این سرویس Singleton رفتار نمی‌کرد؛ چون همانطور که عنوان شد، دو container، برنامه را مدیریت می‌کردند (یعنی دوبار توسط دو ظرف متفاوت نگهدارنده‌ی اشیاء، وهله سازی می‌شد) که اکنون در نگارش 3x به یک مورد کاهش یافته‌است.
در اینجا هرچند متد ConfigureServices وجود دارد، اما اگر از آن استفاده کنید، سرویس معرفی شده‌ی توسط آن، در سازنده‌ی کلاس Startup شناسایی نمی‌شود.
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 2 - بررسی ساختار جدید Solution
ارتقاء به ASP.NET Core 3.0 و تغییرات نقطه‌ی آغازین برنامه

ASP.NET Core 3.0 از Generic Host بجای Web Host قبلی استفاده می‌کند. در این حالت فایل Program.cs آن از:
public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}
در نگارش 2.2، به حالت زیر در نگارش 3 تغییر یافته‌است:
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}
البته باید درنظر داشت که روش قبلی 2.2، هنوز هم در نگارش 3 کار می‌کند، اما به صورت deprecated و منسوخ شده معرفی خواهد شد و در نگارش‌های بعدی حذف می‌گردد.
در این حالت هاستینگ برنامه دیگر به Kestrel و یا حتی خود ASP.NET Core وابسته نخواهد بود. یعنی می‌توان هاستی را ایجاد کرد که به همراه راه اندازی وب سرور Kestrel نباشد. علت این جنریک شدن چیست؟
در نگارش سوم، هاست‌های دیگری هم معرفی شده‌اند؛ مانند امکان اجرای یک worker service بدون راه اندازی یک وب سرور و یا Blazor از روش هاستینگ متفاوتی درون یک web assembly استفاده می‌کند: «ارتقاء به NET Core 3.0.: پشتیبانی از ایجاد سرویس‌های پس‌زمینه»

یک نکته: جزئیات متد CreateDefaultBuilder و سرویس‌هایی را که به صورت خودکار اضافه می‌کند، در اینجا در فایل src/DefaultBuilder/src/WebHost.cs می‌توانید مشاهده کنید.
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 10 - بررسی تغییرات Viewها
در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 11 - بررسی بهبودهای Razor» قسمت «نحوه‌ی سفارشی سازی کلاس پایه‌ی تمام Viewهای برنامه و معرفی inherits@ »، این مورد را توضیح دادم. برای نمونه اگر به فایل Views\_ViewStart.cshtml مراجعه کنید، یک چنین مقدار دهی عمومی در آن هست:
@{
    Layout = "_Layout";
}
این خاصیت عمومی Layout در کلاس پایه‌ی تمام ویووها تعریف شده‌است. اگر می‌خواهید معادل آن‌را داشته باشید، باید یک کلاس سفارشی پایه را با ارث بری از RazorPage ایجاد کنید:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Internal;

namespace Core1RtmTestResources.StartupCustomizations
{
    public abstract class MyCustomBaseView<TModel> : RazorPage<TModel>
    {
        //روش خاص تزریق وابستگی‌ها در فایل ویژه‌ی جاری
        [RazorInject]
        public IHtmlLocalizerFactory MyHtmlLocalizerFactory { get; set; }

        public IHtmlLocalizer MySharedLocalizer => MyHtmlLocalizerFactory.Create(
            baseName: "SharedResource" /*مشخصات*/,
            location: "Core1RtmTestResources.ExternalResources" /*نام اسمبلی ثالث*/);

        public bool IsAuthenticated()
        {
            return Context.User.Identity.IsAuthenticated;
        }

#pragma warning disable 1998
        public override async Task ExecuteAsync()
        {
        }
#pragma warning restore 1998
    }
}
در اینجا چند نکته مهم هستند:
- در کلاس پایه‌ی سفارشی، امکان تزریق وابستگی‌ها در سازنده‌ی کلاس وجود ندارد. اما از طریق ویژگی RazorInject می‌توان این‌کار را انجام داد.
- RazorInject نیاز به نصب وابستگی ذیل را دارد:
{
    "dependencies": {
        //same as before
        "Microsoft.AspNetCore.Mvc.Razor": "1.0.0"
    }
}
- پس از تعریف این کلاس پایه، برای معرفی آن به فایل Views\_ViewImports.cshtml مراجعه کنید:
@using Core1RtmTestResources
@using Microsoft.AspNetCore.Mvc.Localization
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@inherits Core1RtmTestResources.StartupCustomizations.MyCustomBaseView<TModel>
اکنون در تمام ویووهای برنامه به خاصیت عمومی MySharedLocalizer واقع در کلاس پایه‌ی سفارشی برنامه، دسترسی خواهید داشت:
MySharedLocalizer from MyCustomBaseView: @MySharedLocalizer["About Title"]
مطالب
آشنایی با ویژگی DebuggerTypeProxy در VS.Net
در مطالب قبلی، ویژگی DebuggerDisplay معرفی شده بود. ویژگی دیگری شبیه به این ویژگی وجود دارد به نام DebuggerTypeProxy که در ادامه به معرفی آن می‌پردازیم.

کلاس زیر را در نظر بگیرید:
public class Data
{
    public string Name { get; set; }
    public string ValueInHex { get; set; }
}  
پس از اجرای برنامه ، مقادیر کلاس ایجاد شده به این صورت خواهند بود :


در اینجا مقدار Hex برایمان قابل فهم نیست. سناریویی را در نظر بگیرید که مقادیر باید داخل دیتابیس به صورت Hex نگهداری شوند، اما می‌خواهیم هنگام دیباگ، مقدار پراپرتی HexValue به صورت قابل درک و decimal آن نمایش داده شود.

برای انجام اینکار میتوانیم از DebuggerTypeProxy استفاده کنیم. ابتدا کلاسی ایجاد میکنیم که بعنوان proxy، مقادیر را به شکلی که نیاز داریم نمایش دهد. این کلاس object اصلی را در Constructor دریافت کرده و مقادیر مورد نظرمان، از طریق property هایی که در آن تعریف می‌کنیم قابل دسترسی هستند:

public class DataDebugView
{
    private readonly Data _data;

    public DataDebugView(Data data)
    {
        _data = data;
    }

    public string DecimalValue
    {
        get
        {
            bool isValidHex = int.TryParse(_data.HexValue, System.Globalization.NumberStyles.HexNumber, null, out var value);
            return isValidHex ? value.ToString() : "INVALID HEX STRING";
        }
    }
}

در نهایت برای اعمال کردن این کلاس proxy، از ویژگی DebuggerTypeProxy بر روی کلاس اصلی استفاده می‌کنیم:

[DebuggerTypeProxy(typeof(DataDebugView))]
public class Data
{
    public string Name { get; set; }

    public string HexValue { get; set; }
}

بعد از اعمال تغییرات و اجرای دوباره برنامه، نحوه نمایش مقادیر کلاس به این صورت تغییر خواهند یافت:

مطالب
استفاده از Inoreader برای ساده سازی به اشتراک گذاری در dotnettips.info
اگر بعنوان فردی که روزانه بیش از 300 عنوان خبری مربوط به آی‌تی را مانند دیگر توسعه‌دهندگان، قسمتی از فعالیت روزانه‌ی خود کرده‌اید، مطمئنا بدنبال راه‌های ساده‌ی اشتراک گذاری و یا به قول آقای هنسلمن TIf this thenhat یا باختصار IFTT هستید. من برای مرور و دسته بندی فیدها از فیدخوان Inoreader.com (دارای یک API برای توسعه ) استفاده می‌کنم و برای اشتراک مطالب در این سایت از امکان موجود در هر دو سایت، استفاده می‌کنم.
در سایت جاری و در قسمت ارسال لینک‌های خبری، امکانی فراهم شده‌است تا کسانیکه از فایرفاکس استفاده می‌کنند بتوانند به راحتی صفحه‌ی در حال تماشا را برای اشتراک ارسال کنند. تصویر زیر قسمتی از صفحه‌ی ارسال لینک‌های خبری است که دکمه‌ی اشتراک فایرفاکس در آن وجود دارد:

که لینک آن دارای یک دستور جاوااسکریپتی است که کار ارسال لینک و عنوان encode شد‌ه‌ی مطلب را انجام می‌دهد:
javascript:location.href='https://www.dntips.ir/dailylinks?url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)
در Inoreader نیز میتوان برای اشتراک آیتم‌ها، لینکی سفارشی را ایجاد و استفاده کرد تا کار اشتراک گذاری به راحتی در تمام مرورگرهای متداول و نه فقط فایرفاکس، انجام پذیرد. به این صورت که در گوشه‌ی سمت راست و پایین آیتم باز شده، تعداد زیادی از شبکه‌های اجتماعی برای اشتراک وجود دارند و نیز قسمتی هم برای معرفی یک Custom Site:


که برای تعریف یک مقصد اشتراک، پارامترهای زیر را در اختیار می‌گذارد:
[TITLE]: عنوان آیتم با انکدینگ
[TITLE_NOENC]: عنوان آیتم بدون انکدینگ
[URL]: آدرس آیتم
[CONTENT]: محتوای آیتم
[SOURCE]: منبع، که در اینجا کلمه‌ی Inoreader جایگزین میشود.

حالا با استفاده از الگوی معرفی شده‌ی لینک اشتراک سایت DNT و جایگزینی با آیتمهای بالا میتوان یک Custom Site را به Inoreader اضافه کرد:
https://www.dntips.ir/dailylinks?url=[URL]&title=[TITLE]
که البته همانطور که مشخص است سایت جاری فقط دو پارامتر از پنج پارامتر را قبول می‌کند (پارامترهای دارای encoding):


حالا این مورد نیز به لیست اشتراک گذاری در Inoreader اضافه شده و می‌توانید نتیجه‌ی تست آن را در زیر ببینید:

مطالب
آشنایی با ساختار IIS قسمت پنجم
در مطالب قبلی در مورد ماژولار بودن IIS زیاد صحبت کردیم، ولی اجازه بدهید این مورد را به صورت کاربردی‌تر و موشکافانه‌تر بررسی کنیم. برای اینکه به مشکلی در طول این سری از مطالب برنخورید، IIS را به صورت کامل یعنی full feature نصب نمایید. از بخش control panel>programs & features>Turn Windows features on or off اقدام نمایید و هرچه زیر مجموعه Internet information service هست را برگزینید. در صورتی که از نسخه‌های ویندوز سرور 2008 استفاده می‌کنید از طریق server manager>roles>web server اقدام نمایید.
برای نصب یک ماژول باید دو مرحله را انجام داد:
  1. نصب ماژول
  2. فعال سازی ماژول
نکته ای که در مورد ماژول‌های native وجود دارد این هست که این ماژول‌ها دسترسی بدون محدودیتی به منابع سروری دارند و از این رو حتما باید این نکته را دقت کنید که ماژول native شما از یک منبع مورد اعتماد دریافت شده باشد.

نصب یک native module
برای نصب می‌توانید یکی از سه راه زیر را استفاده کنید:
  1. ویرایش دستی فایل کانفیگ و از نسخه IIS7.5 به بعد هم می‌توانید از configuration editor هم استفاده کنید.
  2. استفاده از محیط گرافیکی IIS
  3. استفاده از خط فرمان با دستور Appcmd
مزیت روش دستی این هست که شما دقیقا می‌دانید در پشت صحنه چه اتفاقی می‌افتد و نتیجه هر کدام از این سه روش، اضافه شدن یک مدخل ورودی به تگ <globalmodules> است. برای اعمال تغییرات، مسیر زیر را بروید:
%windir%\system32\inetsrv\config\applicationhost.config
کسی که نیاز به دسترسی به این مسیر و انجام تغییرات دارد باید در بالاترین سطح مدیریتی سرور باشد.
اگر فایل را باز کنید و تگ globalmodule را پیدا کنید متوجه می‌شوید که تمامی ماژول‌ها در این قسمت معرفی شده‌اند و برای خود یک مدخل ورودی یا همان تگ add را دارند که در آن مسیر فایل dll هم ذکر شده است:
<globalModules> 
 
 <addname="DefaultDocumentModule"image="%windir%\system32\inetsrv\defdoc.dll"/> 
 
 <addname="DirectoryListingModule"image="%windir%\system32\inetsrv\dirlist.dll"/> 

<add name="StaticFileModule"image="%windir%\system32\inetsrv\static.dll"/>
...

 </globalModules>

برای حذف یا جایگزینی یک ماژول به راحتی می‌توانید مدخل ورودی یک ماژول را به صورت دستی حذف نمایید و برای جایگزینی هم بعد از حذف، ماژول خود را معرفی کنید. ولی توجه داشته باشید که این حذف به معنی حذف این ماژول از تمامی اپلیکیشن‌های موجود بر روی IIS هست و سپس اضافه کردن یک ماژول به این بخش. همچنین اگر قصد شما فقط حذف یک ماژول از روی یکی از اپلیکشن‌ها باشد باید از طریق فایل کانفیگ سایت از مسیر تگ‌های <system.webserver><modules> و با استفاده از تگ‌های add و remove به معرفی یک ماژول مختص این اپلیکیشن و یا حذف یک ماژول خاص اقدام نمایید.

PreConditions
این ویژگی می‌تواند در خط معرفی ماژول، مورد استفاده قرار بگیرد. اگر به فایل نگاه کنید می‌بینید که در بعضی خطوط این ویژگی ذکر شده است. تعریف این ویژگی به هسته IIS می‌گوید که این ماژول در چه مواردی و به چه شیوه ای باید به کار گرفته شود.
 <add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" /> 
 
 <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" /> 
 
<add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" /> 
 
<add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />

مقادیری که precondition میتواند بگیر شامل موارد زیر هستند:
bitness
این گزینه به دو صورت bitness32 و bitness64 یافت می‌شود. امروزه پردازنده‌های 64 بیتی بسیار متداول شده اند و بسیاری از تولید کنندگان دارند به سمت عرضه ابزارهای 64 بیتی رو می‌آورند و به زودی عرضه‌های 32 بیتی را متوقف می‌کنند و به سمت سیستم عامل‌های 64 بیت سوییچ خواند کرد ولی باز هم هنوز برنامه‌های 32 بیتی زیادی هستند که مورد استفاده قرار می‌گیرند و نمی‌توان آن‌ها را نادیده گرفت. برای همین ویندوزهای 64 بیتی مایکروسافت در کنار محیط 64 بیتی‌شان از یک محیط 32 بیت به اسم WOW64 استفاده می‌کنند. در این حالت این امتیاز به شما داده می‌شود که از پروسه‌های کارگر 32 بیتی در کنار پروسه‌های کارگر 64 بیتی استفاده کنید و PreCondition به bitness32 یا bitness64 تنظیم می‌شود تا از صحت بارگزاری dll در یک محیط درست مطمئن شود. در صورتی که این خصوصیت ذکر نشود یک هندلر 32 بیتی و 64 بیتی و یک module map اجرا می‌شود.

Runtime version
اگر ماژول خاصی برای اجرا به ورژن خاصی از net framwork. نیاز دارد، این ویژگی ذکر می‌شود. در صورتی که ماژولی قصد اجرای بر روی فریم ورک اشتباهی داشته باشد سبب خطا خواهد شد.

Mana gedHandler 
با معرفی IIS7 ما با یک مدل توسعه پذیر روبرو شدیم و می‌توانستیم ماژول‌ها و هندلرهای خود را بنویسیم و مستقیما در Pipeline قرار دهیم ولی سوییچ کردن بین دو بخش کدهای مدیریت شده و native یک عمل سنگین برای سیستم به شمار می‌آید و به منظور کاهش این بار گزینه managedhandler قرار داده شده است تا تعیین کند مواقعی که درخواست نیازی به این ماژول ندارد، این ماژول اجرا نگردد. به عنوان مثال فایل‌های ایستا چون jpg یا html و... شامل این ماژول نخواهند شد. واضح‌ترین مثال در این زمینه Forms Authentication می‌باشد و موقعی اجرا می‌شوند که درخواست فایل‌های aspx شده باشد و اگر یک فایل html را درخواست کنید این ماژول امنیتی روی آن اثری ندارد و عملیات شناسایی هویت روی آن اجرا نمی‌شود و اگر می‌خواهید روی همه فایل‌ها، این عملیات شناسایی انجام شود باید خصوصیت "precondition="managedhandler حذف شود.
در صورتی که تگ module را به صورت زیر بنویسید تمامی ماژول‌ها برای تمامی درخواست‌ها اجرا خواهد شد، صرف نظر از اینکه آیا ماژولی به صورت "precondition="managedmodule مقداردهی شده است یا خیر.
<modules runAllManagedModulesForAllRequests="true"/>
 
The Mode Precondition 
تا به الان گفتیم که چگونه میتوانیم یک ماژول و یا هندلر مدیریت شده‌ای را به Pipeline اضافه کنیم؛ ولی IIS7 به بالا نیاز دارد که تا پروسه‌های کارگر را به روشی خاص به این منظور اجرا کند و فریم ورک دات نت را برای اجرای آن‌ها بارگزاری کند. همچنین به اجرای ماژولی به اسم webengine.dll برای مدیریت  ماژولهای مدیریت شده نیازمند است و خود IIS در مورد کدهای مدیریت شده چیزی متوجه نمی‌شود. پس ما برای اینکه IIS را متوجه این موضوع نمائیم، باید Integrated mode را به آن معرفی کنیم.
در نسخه‌های قبلی IIS یک روش قدیمی برای کدهای مدیریت شده وجود داشت که از طریق اینترفیسی به نام ISAPI صورت می‌گرفت. در این حالت ASPNET_ISAPI.DLL مسئول این کار بود و اگر هنوز هم میخواهید از این dll در نسخه‌های جدیدتر IIS کمک بگیرید باید به جای معرفی classic mode ، integration mode را معرفی کنید.
با برابر کردن precondtion به مقدار "intgretedmode" هندلر یا ماژول شما در یک پول با خصوصیت integrated بارگزاری خواهد شد و اگر مقدار آن "classicmode" باشد در یک پول بدون خاصیت integrated بارگزاری می‌شود.
تفاوت بین دو روش کلاسیک و مجتمع integrated بر سر این هست که در روش جدید، ماژول شما به عنوان یک پلاگین برای IIS دیده نمی‌شود و کد شما را جزئی از کامپوننت‌های خود به شمار می‌آورد. به صورت واضح‌تر در حالت کلاسیک موقعی که درخواستی وارد pipeline میشد ابتدا از کامپوننت‌ها و ماژول‌های داخلی خود IIS عبور داده میشد و بعد فایل ASPNET_ISAPI.DLL جهت پردازش کدهای مدیریت شده صدا زده میشد و با توجه به کدهای شما، بعضی مراحل تکرار میشد؛ مثلا اگر کد شما در مورد Authentication بود و بعد از گذر از مراحل auth داخل خود IIS و بقیه موارد دوباره نوبت کد شما و گذر از مراحل authentication بود. یعنی وجود دو pipeline؛ ولی در حالت مجتمع این دوبار انجام وظیفه از بین رفته است چرا که کدهای شما به طور مستقیم در pipeline قرار دارند و آن‌ها را جزئی از خود می‌داند، نه یک پلاگین که افزون بر فعالیت خودشان، اجرای کدهای شما رو هم بر دوش بکشند.
شکل زیر نمونه ای از حالت کلاسیک را نشان می‌دهد که در آن دو بار عمل auth دارد انجام میگیرد.
 



شکل زیر هم نمونه ای حالت مجتمع هست:

 
در کل امروزه دیگر استفاده از روش کلاسیک راهکار درستی نیست و این ویژگی تنها به عنوان یک سازگاری با نمونه کارهای قدیمی است.
تگ‌هایی که از خصوصت precondition استفاده می‌کنند به شرح زیر هستند:
  • ISAPI filters 
  • globalModules 
  • handlers 
  • modules 

در مورد بقیه تگ‌ها در آینده بیشتر بحث می‌کنیم. بهتر هست مطلب را با توضیح precondition جهت ممانعت از طولانی و طومار شدن در اینجا ببندیم و در قسمت آینده دیگر روش‌های نصب ماژولمان را دنبال کنیم.