بازخوردهای پروژه‌ها
t4 برای Context Per Request
با سلام و احترام
میخواستم ببینم شما برای معماری که در قسمت 12 مربوط به EFCodeFirst معرفی کردید  فایل t4   میشه معرفی کنید که نزدیک به این معماری یا اینکه خود این باشه؟


مسیرراه‌ها
React 16x
پیش نیاز ها
کامپوننت ها
ترکیب کامپوننت ها
طراحی یک گرید
مسیریابی 
کار با فرم ها
ارتباط با سرور
احراز هویت و اعتبارسنجی کاربران 
React Hooks  
توزیع برنامه

مدیریت پیشرفته‌ی حالت در React با Redux و Mobx   

       Redux
       MobX  

مطالب تکمیلی 
    بازخوردهای دوره
    بایدها و نبایدهای استفاده از IoC Containers
    - خیر. به زبان ساده اگر وابستگی‌ها از طریق سازنده کلاس یا خواص آن در اختیار کلاس قرار گیرنده و در این بین ابزاری یا کتابخانه‌ای این تزریق را انجام دهد، به آن ابزار IoC Container می‌گویند. اگر در یک کلاس مستقیما از امکانات IoC Container برای دریافت وابستگی‌ها استفاده شود، الگوی Service locator نام دارد و در این حالت خود IoC Container یک وابستگی در طراحی شما به حساب می‌آید.
    - بله و خیر. بله اگر مستقیما داخل یک کلاس مثلا لایه سرویس یا یک کنترلر و امثال آن استفاده شود. اگر از آن در یک کلاس فکتوری مانند که کار وهله سازی مثلا کنترلرها و امثال آن را عهده دار است، استفاده شود دیگر الگوی Service locator نیست و تزریق وابستگی‌های استاندارد است.
    - بله و خیر. مانند قبل.
    نظرات مطالب
    مهارت‌های تزریق وابستگی‌ها در برنامه‌های NET Core. - قسمت چهارم - پرهیز از الگوی Service Locator در برنامه‌های وب
    - از FromServices نباید در پارامترهای سازنده‌ی کلاس‌ها استفاده شود ( فقط در پارامترهای اکشن متدهای کنترلرها کاربرد دارد).
    - اگر IoC Container از پیش تنظیم شده‌ای وجود داشته باشد که کار وهله سازی TicketCreatedEventHandler شما را انجام می‌دهد، وهله سازی و مقدار دهی پارامترهای تزریق شده‌ی در سازنده‌ی کلاس را نیز به صورت خودکار انجام خواهد داد.
    - اگر IoC Container از پیش تنظیم شده‌ای وجود نداشته باشد، کار وهله سازی service provider را باید خودتان دقیقا معادل کاری که در برنامه‌های کنسول انجام می‌شود، انجام دهید و یا اگر می‌توانید به service provider موجودی دسترسی پیدا کنید که چه بهتر.
    - اگر IoC Container از پیش تنظیم شده‌ای وجود نداشته باشد و همچنین وهله سازی کلاس TicketCreatedEventHandler توسط شما قابل کنترل نیست، تنها راه حل ممکن، حذف پارامترهای سازنده‌ی کلاس و استفاده از الگوی Service locator برای دسترسی به سرویس‌های مدنظر است.
    مطالب
    مدیریت پیشرفته‌ی حالت در React با Redux و Mobx - قسمت هشتم - تنظیمات پروژه‌های React برای کار با Mobx decorators
    تا اینجا دو مثالی را که از Mobx بررسی کردیم (مثال ورود متن و مثال کامپوننت شمارشگر)، به عمد به همراه decoratorهای @ دار آن نبودند. برای مثال در قسمت قبل، یک کلاس را با یک خاصیت ایجاد کردیم که روش مزین سازی خاصیت value آن را با  observable decorator، توسط متد decorate انجام دادیم و این هم یک روش کار با MobX است؛ بدون اینکه نیاز به تنظیمات خاصی را داشته باشد:
    import { decorate } from "mobx";
    
    class Count {
      value = 0;
    }
    
    decorate(Count, { value: observable });
    const count = new Count();
    اما اگر همان مثال بسیار ساده‌ی ورود متن را بخواهیم توسط decoratorهای @ دار MobX پیاده سازی کنیم ... پروژه‌ی استاندارد React ما کامپایل نخواهد شد که در این قسمت، روش رفع این مشکل را بررسی می‌کنیم.


    بازنویسی مثال ورود متن و نمایش آن با Mobx decorators

    در اینجا یک text-box، به همراه دو div در صفحه رندر خواهند شد که قرار است با ورود اطلاعاتی در text-box، یکی از آن‌ها (text-display) این اطلاعات را به صورت معمولی و دیگری (text-display-uppercase) آن‌را به صورت uppercase نمایش دهد. روش کار انجام شده هم مستقل از React است و به صورت مستقیم با استفاده از DOM API عمل شده‌است. این مثال را پیشتر در اولین قسمت بررسی MobX، ملاحظه کردید. اکنون اگر بخواهیم بجای شیءای که توسط متد observable کتابخانه‌ی MobX محصور شده‌است:
    const text = observable({
      value: "Hello world!",
      get uppercase() {
        return this.value.toUpperCase();
      }
    });
    از یک کلاس ES6 به همراه Mobx decorators استفاده کنیم، به یک چنین پروژه‌ی جدیدی خواهیم رسید:
    ابتدا یک پروژه‌ی جدید React را ایجاد می‌کنیم:
    > create-react-app state-management-with-mobx-part3
    > cd state-management-with-mobx-part3
    > npm start
    در ادامه کتابخانه‌ی mobx را نیز نصب می‌کنیم. برای این منظور پس از باز کردن پوشه‌ی اصلی برنامه توسط VSCode، دکمه‌های ctrl+` را فشرده (ctrl+back-tick) و دستور زیر را در ترمینال ظاهر شده وارد کنید:
    > npm install --save mobx
    در ادامه، ابتدا فایل public\index.html را جهت نمایش دو div و یک text-box، ویرایش می‌کنیم:
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <title>MobX Basics, part 3</title>
        <meta charset="UTF-8" />
        <link href="src/styles.css" />
      </head>
    
      <body>
        <main>
          <input id="text-input" />
          <p id="text-display"></p>
          <p id="text-display-uppercase"></p>
        </main>
    
        <script src="src/index.js"></script>
      </body>
    </html>
    سپس محتویات فایل src\index.js را نیز به نحو زیر تغییر می‌دهیم:
    import { autorun, computed, observable } from "mobx";
    
    const input = document.getElementById("text-input");
    const textDisplay = document.getElementById("text-display");
    const loudDisplay = document.getElementById("text-display-uppercase");
    
    class Text {
      @observable value = "Hello World";
      @computed get uppercase() {
        return this.value.toUpperCase();
      }
    }
    
    const text = new Text();
    
    input.addEventListener("keyup", event => {
      text.value = event.target.value;
    });
    
    autorun(() => {
      input.value = text.value;
      textDisplay.textContent = text.value;
      loudDisplay.textContent = text.uppercase;
    });
    تنها تفاوت این نگارش با نگارش قبلی آن، استفاده از کلاس Text که یک کلاس ES6 به همراه MobX Decorators است، بجای یک شیء ساده‌ی جاوا اسکریپتی می‌باشد. در اینجا خاصیت value به صورت observable@ تعریف شده و در نتیجه‌ی تغییر مقدار آن در کدهای برنامه، خاصیت محاسباتی وابسته‌ی به آن یا همان uppercase که با computed@ تزئین شده، به صورت خودکار به روز رسانی خواهد شد. متد autorun نیز به این تغییرات که حاصل فشرده شدن کلیدها هستند، واکنش نشان داده و متن دو div موجود در صفحه را به روز رسانی می‌کند.

    اکنون اگر در همین حال، برنامه را با دستور npm start اجرا کنیم، با خطای زیر متوقف خواهیم شد:
    ./src/index.js
    SyntaxError: \src\index.js: Support for the experimental syntax 'decorators-legacy' isn't currently enabled (8:3):
    
       6 | 
       7 | class Text {
    >  8 |   @observable value = "Hello World";
         |   ^
       9 |   @computed get uppercase() {
      10 |     return this.value.toUpperCase();
      11 |   }

    راه حل اول: از Decorators استفاده نکنیم!

    یک راه حل مشکل فوق این است که بدون هیچ تغییری در ساختار پروژه‌ی React خود، اصلا از decorator syntax استفاده نکنیم. برای مثال اگر یک کلاس متداول MobX ای چنین شکلی را دارد:
    import { observable, computed, action } from "mobx";
    
    class Timer {
      @observable start = Date.now();
      @observable current = Date.now();
    
      @computed
      get elapsedTime() {
        return this.current - this.start + "milliseconds";
      }
    
      @action
      tick() {
        this.current = Date.now();
      }
    }
    می‌توان آن‌را بدون استفاده از decorator syntax، به صورت زیر نیز تعریف کرد:
    import { observable, computed, action, decorate } from "mobx";
    
    class Timer {
      start = Date.now();
      current = Date.now();
    
      get elapsedTime() {
        return this.current - this.start + "milliseconds";
      }
    
      tick() {
        this.current = Date.now();
      }
    }
    
    decorate(Timer, {
      start: observable,
      current: observable,
      elapsedTime: computed,
      tick: action
    });
    نمونه‌ی این روش را در قسمت قبل با تعریف شیء شمارشگر مشاهده کرده‌اید. در اینجا با توجه به اینکه Decorators در جاوا اسکریپت چیزی نیستند بجز بیان زیبای higher-order functions و higher-order functions هم توابعی هستند که توابع دیگر را با ارائه‌ی قابلیت‌های بیشتری، محصور می‌کنند، به همین جهت هر کاری را که بتوان با تزئین کننده‌ها انجام داد، همان را با توابع معمولی جاوا اسکریپتی نیز می‌توان انجام داد. اینکار را در مثال فوق توسط متد decorate مشاهده می‌کنید. این متد ابتدا نوع کلاس خاصی را دریافت کرده و سپس در پارامتر دوم آن می‌توان شیءای را تعریف کرد که خواص آن، همان خواص کلاس پارامتر اول است و مقادیر این خواص، تزئین کننده‌هایی هستند که قرار است برای آن‌ها بکار گرفته شوند. مزیت این روش بدون تغییر باقی ماندن تعریف کلاس Timer در اینجا و همچنین انجام هیچگونه تغییری در ساختار پروژه‌ی React، بدون نیاز به نصب بسته‌های کمکی اضافی است.

    همچنین در این حالت بجای استفاده از کامپوننت‌های کلاسی، باید از روش بکارگیری متد observer برای محصور کردن کامپوننت تابعی تعریف شده استفاده کرد (تا دیگر نیازی به ذکر observer class@ نباشد):
    const Counter = observer(({ count }) => {
      return (
       // ...
      );
    });


    راه حل دوم: از تایپ‌اسکریپت استفاده کنید!

    create-react-app امکان ایجاد پروژه‌های React تایپ‌اسکریپتی را با ذکر سوئیچ typescript نیز دارد:
    > create-react-app my-proj1 --typescript
    پس از ایجاد پروژه، فایل tsconfig.json آن‌را یافته و experimentalDecorators آن‌را به true تنظیم کنید:
    {
      "compilerOptions": {
        // ...
        "experimentalDecorators": true
      }
    }
    این تنها تغییری است که مورد نیاز می‌باشد و پس از آن برنامه‌ی React جاری، بدون مشکلی می‌تواند با decorators کار کند.


    فعالسازی MobX Decorators در پروژه‌های استاندارد React مبتنی بر ES6

    MobX از legacy" decorators spec" پشتیبانی می‌کند. یعنی اگر پروژه‌ای از spec جدید استفاده کند، دیگر نخواهد توانست با MobX فعلی کار کند. این هم مشکل MobX نیست. مشکل اینجا است که باید دانست کلا decorators در زبان جاوااسکریپت هنوز در مرحله‌ی آزمایشی قرار دارند و تکلیف spec نهایی و تائید شده‌ی آن مشخص نیست.
    برای فعالسازی decorators در یک پروژه‌ی React استاندارد مبتنی بر ES6، شاید کمی جستجو کنید و به نتایجی مانند افزودن فایل babelrc. به ریشه‌ی پروژه و نصب افزونه‌هایی مانند babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties@ برسید. اما ... این‌ها بدون اجرای دستور npm run eject کار نمی‌کنند و اگر این دستور را اجرا کنیم، در نهایت به یک فایل package.json بسیار شلوغ خواهیم رسید (اینبار ارجاعات به Babel، Webpack و تمام ابزارهای دیگر نیز ظاهر می‌شوند). همچنین این عملیات نیز یک طرفه‌است. یعنی از این پس قرار است کنترل تمام این پشت صحنه، در اختیار ما باشد و به روز رسانی‌های بعدی create-react-app را با مشکل مواجه می‌کند. این گزینه صرفا مختص توسعه دهندگان پیشرفته‌ی React است. به همین جهت نیاز به روشی را داریم تا بتوانیم تنظیمات Webpack و کامپایلر Babel را بدون اجرای دستور npm run eject، تغییر دهیم تا در نتیجه، decorators را در آن فعال کنیم و خوشبختانه پروژه‌ی react-app-rewired دقیقا برای همین منظور طراحی شده‌است.

    بنابراین ابتدا بسته‌های زیر را نصب می‌کنیم:
    > npm i --save-dev customize-cra react-app-rewired
    بسته‌ی react-app-rewired، امکان بازنویسی تنظیمات webpack پروژه‌ی react را بدون eject آن میسر می‌کند. customize-cra نیز با استفاده از امکانات همین بسته، نگارش‌های جدیدتر create-react-app را پشتیبانی می‌کند.

    پس از نصب این پیشنیازها، فایل جدید config-overrides.js را به ریشه‌ی پروژه، جائیکه فایل package.json قرار گرفته‌است، با محتوای زیر اضافه کنید تا پشتیبانی ازlegacy" decorators spec" فعال شوند:
    const {
      override,
      addDecoratorsLegacy,
      disableEsLint
    } = require("customize-cra");
    
    module.exports = override(
      // enable legacy decorators babel plugin
      addDecoratorsLegacy(),
    
      // disable eslint in webpack
      disableEsLint()
    );
    در ادامه فایل package.json را گشوده و قسمت scripts آن‌را برای استفاده‌ی از react-app-rewired، به صورت زیر بازنویسی کنید تا امکان تغییر تنظیمات webpack به صورت پویا در زمان اجرای برنامه، میسر شود:
      "scripts": {
        "start": "react-app-rewired start",
        "build": "react-app-rewired build",
        "test": "react-app-rewired test",
        "eject": "react-app-rewired eject"
      },
    پس از این تغییرات، نیاز است دستور npm start را یکبار دیگر از ابتدا اجرا کنید. اکنون برنامه بدون مشکل کامپایل شده و خروجی بدون خطایی در مرورگر نمایش داده خواهد شد.


    تنظیمات ESLint مخصوص کار با decorators

    فایل ویژه‌ی eslintrc.json. که در ریشه‌ی پروژه قرار می‌گیرد (این فایل بدون نام است و فقط از پسوند تشکیل شده)، برای پروژه‌های MobX، باید حداقل تنظیم زیر را داشته باشد تا ESLint بتواند legacyDecorators را نیز پردازش کند:
    {
      "extends": "react-app",
      "parserOptions": {
        "ecmaFeatures": {
          "legacyDecorators": true
        }
      }
    }
    و یا یک نمونه‌ی غنی شده‌ی فایل eslintrc.json. مخصوص برنامه‌های React به صورت زیر است:
    {
        "env": {
            "node": true,
            "commonjs": true,
            "browser": true,
            "es6": true,
            "mocha": true
        },
        "settings": {
            "react": {
                "version": "detect"
            }
        },
        "parserOptions": {
            "ecmaFeatures": {
                "jsx": true,
                "legacyDecorators": true
            },
            "ecmaVersion": 2018,
            "sourceType": "module"
        },
        "plugins": [
            "babel",
            "react",
            "react-hooks",
            "react-redux",
            "no-async-without-await",
            "css-modules",
            "filenames",
            "simple-import-sort"
        ],
        "rules": {
            "no-const-assign": "warn",
            "no-this-before-super": "warn",
            "constructor-super": "warn",
            "strict": [
                "error",
                "safe"
            ],
            "no-debugger": "error",
            "brace-style": [
                "error",
                "1tbs",
                {
                    "allowSingleLine": true
                }
            ],
            "no-trailing-spaces": "error",
            "keyword-spacing": "error",
            "space-before-function-paren": [
                "error",
                "never"
            ],
            "spaced-comment": [
                "error",
                "always"
            ],
            "vars-on-top": "error",
            "no-undef": "error",
            "no-undefined": "warn",
            "comma-dangle": [
                "error",
                "never"
            ],
            "quotes": [
                "error",
                "double"
            ],
            "semi": [
                "error",
                "always"
            ],
            "guard-for-in": "error",
            "no-eval": "error",
            "no-with": "error",
            "valid-typeof": "error",
            "no-unused-vars": "error",
            "no-continue": "warn",
            "no-extra-semi": "warn",
            "no-unreachable": "warn",
            "no-unused-expressions": "warn",
            "max-len": [
                "warn",
                80,
                4
            ],
            "react/prefer-es6-class": "warn",
            "react/jsx-boolean-value": "warn",
            "react-hooks/rules-of-hooks": "error",
            "react-hooks/exhaustive-deps": "warn",
            "react/prop-types": "off",
            "react-redux/mapDispatchToProps-returns-object": "off",
            "react-redux/prefer-separate-component-file": "off",
            "no-async-without-await/no-async-without-await": "warn",
            "css-modules/no-undef-class": "off",
            "filenames/match-regex": [
                "off",
                "^[a-zA-Z]+\\.*\\b(typescript|module|locale|validate|test|action|api|reducer|saga)?\\b$",
                true
            ],
            "filenames/match-exported": "off",
            "filenames/no-index": "off",
            "simple-import-sort/sort": "error"
        },
        "extends": [
            "react-app",
            "eslint:recommended",
            "plugin:react/recommended",
            "plugin:react-redux/recommended",
            "plugin:css-modules/recommended"
        ],
        "globals": {
            "Atomics": "readonly",
            "SharedArrayBuffer": "readonly",
            "process": true
        }
    }
    البته برای اینکه این تنظیمات کار کند، باید افزونه‌های زیر را نیز به صورت محلی در ریشه‌ی پروژه‌ی جاری نصب کنید (این مورد از ESLint 6x به بعد اجباری است و از بسته‌های global استفاده نمی‌کند):
    >npm i --save-dev eslint babel-eslint eslint-config-react-app eslint-loader eslint-plugin-babel eslint-plugin-react eslint-plugin-css-modules eslint-plugin-filenames eslint-plugin-flowtype eslint-plugin-import eslint-plugin-no-async-without-await eslint-plugin-react-hooks eslint-plugin-react-redux eslint-plugin-redux-saga eslint-plugin-simple-import-sort eslint-loader typescript
    پس از آن می‌توان فایل config-overrides.js را به صورت زیر نیز بر اساس تنظیمات فوق، بهبود بخشید:
    const {
      override,
      addDecoratorsLegacy,
      useEslintRc
    } = require("customize-cra");
    
    module.exports = override(
      addDecoratorsLegacy(),
      useEslintRc(".eslintrc.json")
    );


    رفع اخطار مرتبط با decorators در VSCode

    تا اینجا کار تنظیم کامپایلر babel، جهت پردازش decorators انجام شد. اما خود VSCode نیز چنین اخطاری را در پروژه‌هایی که از decorates استفاده می‌کنند، نمایش می‌دهد:
    Experimental support for decorators is a feature that is subject to change in a future release.
    Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig' to remove this warning.ts(1219)
    برای رفع آن، فایل جدید tsconfig.json را در ریشه‌ی پروژه ایجاد کرده و آن‌را به صورت زیر تکمیل کنید تا ادیتور تایپ‌اسکریپتی VSCode، دیگر خطاهای مرتبط با decorators را نمایش ندهد:
    {
        "compilerOptions": {
            "experimentalDecorators": true,
            "allowJs": true
        }
    }

    کدهای کامل این قسمت را می‌توانید از اینجا دریافت کنید: state-management-with-mobx-part3.zip
    نظرات مطالب
    مفاهیم برنامه نویسی ـ آشنایی با سازنده‌ها
    ضمن تشکر از دوستانی که در بحث شرکت کردند و پوزش به دلیل اینکه چند هفته ای در سفر هستم و تهیه مطالب با تأخیر انجام خواهد شد.
    برای پاسخ به پرسش دوست گرامی آقای نجف زاده ابتدا بخشی از این مطلب را یادآوری می‌کنم.
    "... مساحت را این بار به جای متد به صورت یک پروپرتی پیاده سازی می‌کنیم. اگرچه در آینده بیشتر راجع به چگونگی انتخاب برای پیاده سازی یک عضو کلاس به صورت پروپرتی یا متد بحث خواهیم کرد اما به عنوان یک قانون کلی در نظر داشته باشید عضوی که به صورت منطقی به عنوان داده مطرح است را به صورت پروپرتی پیاده سازی کنید. مانند نام دانشجو. از طرفی اعضایی که دلالت بر انجام عملی دارند را به صورت متد پیاده سازی می‌کنیم. مانند متد تبدیل به نوع داده دیگر. (مثلاً ()Object.ToString) ..."

    بنابراین به نکات زیر توجه فرمایید.
    ۱. در این مطالب سعی شده است امکان پیاده سازی یک مفهوم به دو صورت متد و پروپرتی نشان داده شود تا در ذهن خواننده زمینه ای برای بررسی بیشتر مفهوم متد و پروپرتی و تفاوت آن‌ها فراهم گردد. این زمینه برای کنجکاوی بیشتر معمولاً با انجام یک جستجوی ساده سبب توسعه و تثبیت علم شخص می‌گردد.
    ۲. در متن بالاً به صورت کلی اشاره شده است هر یک از دو مفهوم متد و پروپرتی در کجا باید استفاده شوند و نیز خاطرنشان شده است در مطالب بعدی در مورد این موضوع بیشتر صحبت خواهد شد.
    ۳. نکته مهم در طراحی کلاس، پایگاه داده و ... خرد جهان واقع یا محیط عملیاتی مورد نظر طراح است. به عبارت دیگر گسی نمی‌تواند به یک طراح بگوید به طور مثال مساحت باید متد باشد یا باید پروپرتی باشد. طراح با توجه به مفهوم و کارکردی که برای هر مورد در ذهن دارد بر اساس اصول و قواعد، متد یا پروپرتی را بر می‌گزیند. مثلاً در خرد جهان واقع موجود در ذهن یک طراح مساحت به عنوان یک عمل یا اکشنی که شیء انجام می‌دهد است و بنابراین متد را انتخاب می‌کند. طراح دیگری در خرد جهان واقع دیگری در حال طراحی است و مثلاً متراژ یک شیء خانه را به عنوان یک ویژگی ذاتی و داده ای می‌نگرد و گمان می‌کند خانه نیازی به انجام عملی برای بدست آوردن مساحت خود ندارد بلکه یکی از ویژگی‌های خود را می‌تواند به اطلاع استفاده کننده برساند. پس شما به طراح دیگر نگویید اکشن تلقی میشه پس باید متد استفاده شود. اگر خود در پروژه ای چیزی را اکشن تلقی نمودید بله باید متد به کار ببرید. تلقی‌ها بر اساس خرد جهان واقع معنا دارند.
    ۴. پروپرتی و متد از نظر شیوه استفاده و ... با هم تفاوت دارند. اما یک تفاوت مهم بین آنها بیان نوع مفاهیم موجود در ذهن طراح به کد مشتری است. فراموش نکنید خود پروپرتی دارای اکسسور است که چیزی مانند متد است. در خیلی از موارد صحیح‌تر بودن پیاده سازی با متد یا با پروپرتی معنا ندارد. انتخاب ما بین متد یا پروپرتی بر اساس نحوه استفاده مطلوب در کد مشتری و نیز اطلاع به مشتری که مثلاً فلان مفهوم از دید ما یک اکشن است و فلان چیز داده صورت می‌گیرد.

    مطالب
    اضافه شدن پشتیبانی از unsigned right shift به C# 11
    به C# 11، عملگر جدیدی به شکل <<< و به معنای unsigned right shift اضافه شده‌است که ... در زبان جاوا از نگارش ابتدایی آن حضور داشته‌است. اما ... چرا از این لحاظ بین این دو زبان، تفاوت وجود داشته‌است؟


    مفهوم عملگر شیفت در #C

    عملگر شیفت به سمت راست و یا <<، عددی را به تعداد بیت مشخص شده (x >> count)، به سمت راست منتقل می‌کند و دو نوع دارد:
    الف) شیفت به راست منطقی
    برای مثال اگر عدد 12 را به صورت باینری نمایش دهیم، به صورت زیر خواهد بود:
    00000000 00000000 00000000 00001100
    و اگر آن‌را به اندازه‌ی یک بیت به سمت راست هدایت کنیم، که با 1 <<< 12  نمایش داده می‌شود:
    00000000 00000000 00000000 00000110
    به عدد 6 خواهیم رسید.
    در این حالت همواره فرض می‌شود که عدد مدنظر، unsigned است.

    ب) شیفت به راست ریاضی
    شیفت به راست ریاضی، دقیقا مانند شیفت به راست منطقی است؛ مانند مثال زیر که عدد 1001  باینری را دو بیت به سمت راست منتقل می‌کند:
    uint e = 0b_1001;
    Console.WriteLine($"Before: {Convert.ToString(e, toBase: 2),4}");
    // Before: 1001
    
    uint f = e >> 2;
    Console.WriteLine($"After:  {Convert.ToString(f, toBase: 2).PadLeft(4, '0'),4}");
    // After:  0010
    اما ... بجای اینکه همانند شیفت به راست منطقی، سمت چپ را با صفر پر کند، آن‌را با «با ارزش‌ترین بیت یا همان بیت علامت» پر می‌کند. یعنی در اینجا بیتی که بیانگر مثبت و منفی بودن عدد است، حفظ می‌شود. یعنی این نوع شیفت، با اعداد signed هم کار می‌کند.
    برای مثال نمایش باینری عدد منفی 2,147,483,552-  به صورت زیر است:
    10000000 00000000 00000000 01100000
    و اگر آن‌را چهار بیت به سمت راست هدایت کنیم (یعنی 4 << 2,147,483,552 -)، به عدد 134,217,722- می‌رسیم که معادل عدد باینری زیر است:
    11111000 00000000 00000000 00000110
    به این ترتیب با شیفت به راست ریاضی، علامت عدد منفی حفظ شده‌است. مثالی دیگر:
    int x = -8;
    Console.WriteLine($"Before: {x,11}, hex: {x,8:x}, binary: {Convert.ToString(x, toBase: 2),32}");
    // Before: -8, hex: fffffff8, binary: 11111111111111111111111111111000
    
    int y = x >> 2;
    Console.WriteLine($"After  >>: {y,11}, hex: {y,8:x}, binary: {Convert.ToString(y, toBase: 2),32}");
    // After  >>: -2, hex: fffffffe, binary: 11111111111111111111111111111110
    
    int z = x >>> 2;
    Console.WriteLine($"After >>>: {z,11}, hex: {z,8:x}, binary: {Convert.ToString(z, toBase: 2).PadLeft(32, '0'),32}");
    // After >>>:  1073741822, hex: 3ffffffe, binary: 00111111111111111111111111111110


    سؤال: در زبان جاوا، عملگر <<< به معنای unsigned right shift است؛ اما چنین عملگری در زبان #C تا نگارش 11 آن وجود ندارد؛ چرا؟!

    پاسخ: چون زبان جاوا، فاقد نوع‌های داده‌ای توکار unsigned integers است (^)؛ برخلاف #C از نگارش یک آن. حتی به ظاهر، این امکان در Java 8 اضافه شده‌است، اما در حقیقت با نوع‌های int و long، فقط مانند اینکه unsigned هم می‌توانند باشند، رفتار می‌کند (^). البته نوع char در زبان Java، تنها نوع unsigned واقعی است.
    همانطور که عنوان شد، در زبان #C فقط کافی است بر روی unsigned types مانند ulong, uint, ushort، عملگر << را بکار برد تا به  unsigned right shift جاوا رسید (به همین جهت عملگر اضافه‌تری برای آن ارائه نشده بود). البته باید دقت داشت که در اینجا عملگر << کار پر کردن MSB یا «با ارزش‌ترین بیت یا همان بیت علامت» را هم با صفر انجام می‌دهد؛ حتی اگر MSB مقدار دهی شده باشد (چون این کاری است که << بر روی unsigned types انجام می‌دهد).
    تا پیش از C# 11 اگر نیاز به کار بر روی signed types جهت رسیدن به نتیجه‌ی عملگر <<< وجود داشته باشد (انجام شیفت منطقی؛ یعنی صرفنظر کردن از نوع علامت عدد)، می‌توان از متدهای الحاقی زیر استفاده کرد که ابتدا آن‌ها را به نمونه‌های unsigned تبدیل می‌کند و کار شیفت را انجام می‌دهد و سپس نوع اصلی را بازیابی می‌کند:
    public static int UnsignedRightShift(this int signed, int places)
    {
        unchecked
        {
            var unsigned = (uint)signed;
            unsigned >>= places;
            return (int)unsigned;
        }
    }
    
    public static long UnsignedRightShift(this long signed, int places)
    {
        unchecked
        {
            var unsigned = (ulong)signed;
            unsigned >>= places;
            return (long)unsigned;
        }
    }
    مطالب
    Tuple در دات نت 4

    نوع جدیدی در دات نت 4 به نام Tuple اضافه شده است که در این مطلب به بررسی آن خواهیم پرداخت.
    در ریاضیات، Tuple به معنای لیست مرتبی از اعضاء با تعداد مشخص است. Tuple در زبان‌های برنامه نویسی Dynamic مانند اف شارپ، Perl ، LISP و بسیاری موارد دیگر مطلب جدیدی نیست. در زبان‌های dynamic برنامه نویس‌ها می‌توانند متغیرها را بدون معرفی نوع آن‌ها تعریف کنند. اما در زبان‌های Static مانند سی شارپ، برنامه نویس‌ها موظفند نوع متغیرها را پیش از کامپایل آن‌ها معرفی کنند که هر چند کار کد نویسی را اندکی بیشتر می‌کند اما به این صورت شاهد خطاهای کمتری نیز خواهیم بود (البته سی شارپ 4 این مورد را با معرفی واژه‌ی کلیدی dynamic تغییر داده است).
    برای مثال در اف شارپ داریم:
    let data = (“John Doe”, 42)

    که سبب ایجاد یک tuple که المان اول آن یک رشته و المان دوم آن یک عدد صحیح است می‌شود. اگر data را بخواهیم نمایش دهیم خروجی آن به صورت زیر خواهد بود:
    printf “%A” data
    // Output: (“John Doe”,42)

    در دات نت 4 فضای نام جدیدی به نام System.Tuple معرفی شده است که در حقیقت ارائه دهنده‌ی نوعی جنریک می‌باشد که توانایی در برگیری انواع مختلفی را دارا است :
    public class Tuple<T1>
    up to:
    public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>

    همانند آرایه‌ها، اندازه‌ی Tuples نیز پس از تعریف قابل تغییر نیستند (immutable). اما تفاوت مهم آن با یک آرایه در این است که اعضای آن می‌توانند نوع‌های کاملا متفاوتی داشته باشند. همچنین تفاوت مهم آن با یک ArrayList یا آرایه‌ای از نوع Object، مشخص بودن نوع هر یک از اعضاء آن است که type safety بیشتری را به همراه خواهد داشت و کامپایلر می‌تواند در حین کامپایل دقیقا مشخص نماید که اطلاعات دریافتی از نوع صحیحی هستند یا خیر.

    یک مثال کامل از Tuples را در کلاس زیر ملاحظه خواهید نمود:

    using System;
    using System.Linq;
    using System.Collections.Generic;

    namespace TupleTest
    {
    class TupleCS4
    {
    #region Methods (4)

    // Public Methods (4)

    public static Tuple<string, string> GetFNameLName(string name)
    {
    if (string.IsNullOrWhiteSpace(name))
    throw new NullReferenceException("name is empty.");

    var nameParts = name.Split(',');

    if (nameParts.Length != 2)
    throw new FormatException("name must contain ','");

    return Tuple.Create(nameParts[0], nameParts[1]);
    }

    public static void PrintSelectedTuple()
    {
    var list = new List<Tuple<string, int>>
    {
    new Tuple<string, int>("A", 1),
    new Tuple<string, int>("B", 2),
    new Tuple<string, int>("C", 3)
    };

    var item = list.Where(x => x.Item2 == 2).SingleOrDefault();
    if (item != null)
    Console.WriteLine("Selected Item1: {0}, Item2: {1}",
    item.Item1, item.Item2);
    }

    public static void PrintTuples()
    {
    var tuple1 = new Tuple<int>(12);
    Console.WriteLine("tuple1 contains: item1:{0}", tuple1.Item1);

    var tuple2 = Tuple.Create("Item1", 12);
    Console.WriteLine("tuple2 contains: item1:{0}, item2:{1}",
    tuple2.Item1, tuple2.Item2);

    var tuple3 = Tuple.Create(new DateTime(2010, 5, 6), "Item2", 20);
    Console.WriteLine("tuple3 contains: item1:{0}, item2:{1}, item3:{2}",
    tuple3.Item1, tuple3.Item2, tuple3.Item3);
    }

    public static void Tuple8()
    {
    var tup =
    new Tuple<int, int, int, int, int, int, int, Tuple<int, int>>
    (1, 2, 3, 4, 5, 6, 7, new Tuple<int, int>(8, 9));

    Console.WriteLine("tup.Rest Item1: {0}, Item2: {1}",
    tup.Rest.Item1,tup.Rest.Item2);
    }

    #endregion Methods
    }
    }

    using System;

    namespace TupleTest
    {
    class Program
    {
    static void Main()
    {
    var data = TupleCS4.GetFNameLName("Vahid, Nasiri");
    Console.WriteLine("Data Item1:{0} & Item2:{1}",
    data.Item1, data.Item2);

    TupleCS4.PrintTuples();

    TupleCS4.PrintSelectedTuple();

    TupleCS4.Tuple8();

    Console.WriteLine("Press a key...");
    Console.ReadKey();
    }
    }
    }

    توضیحات :
    - روش‌های متفاوت ایجاد Tuples را در متد PrintTuples می‌توانید ملاحظه نمائید. همچنین نحوه‌ی دسترسی به مقادیر هر کدام از اعضاء نیز مشخص شده است.
    - کاربرد مهم Tuples در متد GetFNameLName نمایش داده شده است؛ زمانیکه نیاز است تا چندین خروجی از یک تابع داشته باشیم. به این صورت دیگر نیازی به تعریف آرگومان‌هایی به همراه واژه کلیدی out نخواهد بود یا دیگر نیازی نیست تا یک شیء جدید را ایجاد کرده و خروجی را به آن نسبت دهیم. به همان سادگی زبان‌های dynamic در اینجا نیز می‌توان یک tuple را ایجاد و استفاده کرد.
    - بدیهی است از Tuples در یک لیست جنریک و یا حالات دیگر نیز می‌توان استفاده کرد. مثالی از این دست را در متد PrintSelectedTuple ملاحظه خواهید نمود. ابتدا یک لیست جنریک از Tuple ایی با دو عضو تشکیل شده است. سپس با استفاده از امکانات LINQ ، عضوی که آیتم دوم آن مساوی 2 است یافت شده و سپس المان‌های آن نمایش داده می‌شود.
    - نکته‌ی دیگری را که حین کار با Tuples می‌توان در نظر داشت این است که اعضای آن حداکثر شامل 8 عضو می‌توانند باشند که عضو آخر باید یک Tuple تعریف گردد و بدیهی است این Tuple‌ نیز می‌تواند شامل 8 عضو دیگر باشد و الی آخر که نمونه‌ای از آن را در متد Tuple8 می‌توان مشاهده کرد.

    مطالب
    Strong Name
    نام قوی (Strong Name یا به‌صورت مخفف SN) تکنولوژی‌ای است که با ورود دانت نت معرفی شده و امکانات متنوعی را در زمینه حفاظت از هویت اسمبلی فراهم کرده است. اما بسیاری از برنامه‌نویسان به اشتباه آن را به‌عنوان ابزاری برای فعال‌سازی امنیت می‌پندارند، درصورتی‌که «نام قوی» درواقع یک تکنولوژی تعیین «هویتِ منحصربه‌فرد» اسمبلی‌ها است. یک نام قوی حاوی مجموعه‌ای از مشخصات یک اسمبلی (شامل نام ساده، نسخه و داده‌های کالچر (culture) آن در صورت وجود) به‌همراه یک کلید عمومی و یک امضای دیجیتال است. در زیر یک نمونه از یک اسمبلی دارای نام قوی را مشاهده می‌کنید:
    System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35
    این نام با استفاده از داده‌های موجود در فایل اصلی یک اسمبلی و نیز یک کلید خصوصی تولید می‌شود. (فایل اصلی اسمبلی فایلی است که حاوی مانیفست اسمبلی است که این مانیفست خود شامل عنوان و هش‌کدهای تمام فایل‌هایی است که اسمبلی را می‌سازند. دات نت از MultiFile Assembly پشتیبانی می‌کند. برای مدیریت این نوع از اسمبلی‌ها می‌توان از (Assembly Linker (al.exe استفاده کرد. البته درحال حاضر امکان توسعه این نوع از اسمبلی‌ها در ویژوال استودیو موجود نیست.) در sdkهای مایکروسافت ابزارهایی برای تولید نام‌های قوی برای اسمبلی‌ها وجود دارد که در ادامه در مورد نحوه استفاده از یک مورد از آن‌ها توضیح داده خواهد شد.
    اسمبلی‌هایی که نام‌های قوی یکسانی دارند همانند و یکسان هستند. با اختصاص دادن یک نام قوی به یک اسمبلی می‌توان اطمینان حاصل کرد که نام آن منحصربه‌فرد خواهد شد. به‌طور کلی نام‌های قوی نیازمندی‌های زیر را برطرف می‌کنند:
    - نام‌های قوی منحصربه‌فرد بودن نام یک اسمبلی را براساس جفت‌کلیدهای یکتا فراهم می‌کنند. هیچ‌کس دیگری امکان تولید همان اسمبلی‌ای را که شما تولید کرده‌اید ندارد، زیرا اسمبلی‌ای که با یک کلید خصوصی تولید شده است نسبت به اسمبلی دیگری که با یک کلید خصوصی دیگر تولید شده است نام متفاوتی خواهد داشت چون کلید عمومی متناظر با این کلید خصوصی بخشی از نام قوی نهایی تولید شده خواهد بود.
    - نام‌های قوی از خط تولید نسخه‌های یک اسمبلی محافظت می‌کنند. یک نام قوی اطمینان می‌دهد تا شخص دیگری نتواند نسخه دیگری از اسمبلی شما را تولید کند. مصرف‌کنندگان می‌توانند مطمئن باشند که نسخه‌ای از اسمبلی را که بارگذاری می‌کنند از همان توزیع‌کننده اسمبلی می‌آید که این نسخه از اسمبلی را تولید کرده است.
    - نام‌های قوی بررسی هویت مستحکمی را فراهم می‌کنند. عبور از دروازه امنیتی دات نت فریمورک نشان‌دهنده این است که محتوای اسمبلی پس از تولید آن تغییر نکرده است.
    هنگامی‌که به یک اسمبلیِ دارای نام قوی در اسمبلی دیگری ریفرنس داده می‌شود، تا زمانی که به اسمبلی مقصد نیز یک نام قوی داده نشود نمی‌توان در نهایت از مزایای یک نام قوی بهره برد. درواقع در دنیای دات نت به اسمبلی‌های دارای نام قوی تنها می‌توان اسمبلی‌هایی ریفرنس داد که خود نیز دارای نام قوی هستند.
    نام قوی یک تکنولوژی براساس اصول کریپتوگرافی و امضاهای دیجیتال است که ایده پایه‌ای آن را می‌توان در تصویر زیر دید:

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

    1. تولید و مدیریت جفت‌کلیدهای قوی- نام‌گذاری‌شده (Strongly Named Key Pairs)

    همان‌طور که در قسمت قبل اشاره شد برای نام‌گذاری قوی یک اسمبلی به یک کلید عمومی (public key) و یک کلید خصوصی (private key) که در مجموع به آن یک جفت کلید (key pair) می‌گویند، نیاز است.برای این‌کار می‌توان با استفاده از برنامه sn.exe (عنوان کامل آن Microsoft .Net Framework Strong Name Utility است) یک جفت کلید تولید کرده و آن را در یک فایل و یا در CSP (یا همان cryptographic service provider) ذخیره کرد. هم‌چنین این‌کار را می‌توان توسط ویژوال استودیو نیز انجام داد. امکان موردنظر در فرم پراپرتی یک پروژه و در تب Signing آن وجود دارد.

    نکته: یک CSP عنصری از API کریپتوگرافی ویندوز (Win32 CryptoAPI) است که سرویس‌هایی چون اینکریپشن، دیکریپشن، و تولید امضای دیجیتال را فراهم می‌کند. این پرووایدرها هم‌چنین تسهیلاتی برای مخازن کلیدها فراهم می‌کنند که از اینکریپشن‌های قوی و ساختار امنیتی سیستم عامل (سیستم امنیتی و دسترسی کاربران ویندوز) برای محافظت از تمام کلیدهای کریپتوگرافی ذخیره شده در مخزن استفاده می‌کند. به‌طور خلاصه و مفید می‌شود اشاره کرد که می‌توان کلیدهای کریپتوگرافی را درون یک مخزن کلید CSP ذخیره کرد و تقریبا مطمئن بود که تا زمانی‌که هیچ‌کس کلمه عبور سیستم عامل را نداند، این کلیدها امن خواهند ماند. برای کسب اطلاعات بیشتر به داده‌های CryptoAPI در اسناد SDK سیستم عامل خود مراجعه کنید.

    برنامه sn به همراه SDKهای ویندوز نصب می‌شود. البته با نصب ویژوال استودیو تمام SDKهای موردنیاز مطابق با نسخه‌های موجود، نصب خواهد شد. مسیر نسخه 4 و 32 بیتی این برنامه در سیستم عامل Windows 7 به‌صورت زیر است:

    C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sn.exe

    با استفاده از آرگومان k همانند دستور زیر یک جفت‌کلید جدید تولید شده و در فایل MyKeys.snk در ریشه درایو d: ذخیره می‌شود:

    sn –k d:\MyKeys.snk

    نکته: به بزرگی و کوچکی حروف سوییچ‌های دستورات برنامه sn دقت کنید!

    این کار یک جفت کلید کریپتوگرافی 1024 بیتی به‌صورت تصادفی تولید می‌کند. این دستور را باید در خط فرمانی (Command Prompt) اجرا نمود که مسیر فایل sn.exe را بداند. برای راحتی کار می‌توان از خط فرمان ویژوال استودیو (Visual Studio Command Prompt) استفاده کرد.

    نکته: اجرای عملیات فوق در یک شرکت یا قسمت توسعه یک شرکت، تنها یک بار نیاز است زیرا تمام اسمبلی‌های تولیدی تا زمانی‌که عناوین ساده متمایزی دارند می‌توانند از یک جفت کلید مشترک استفاده کنند.

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

    فایل تولید شده حاوی هر دو کلید «عمومی» و «خصوصی» است. می‌توان با استفاده از دستور زیر کلید عمومی موجود در فایل mykeys.snk را استخراج کرده و در فایل mypublickey.snk ذخیره کرد:

    sn –p d:\mykeys.snk d:\mypublickey.snk

     با استفاده از فایل حاوی کلید عمومی می‌توان با استفاده از دستور زیر کلید عمومی موجود در آن را بدست آورد:
    sn -tp MyPublicKey.snk

     مقدار نمایش داده در انتهای تصویر فوق به‌عنوان «توکِن کلید عمومی» (Public key Token) درواقع 8 بایت پایانی کد هش‌شده کریپتوگرافیِ محاسبه‌شده از کلید عمومی است. چون خود کلید عمومی همان‌طور که مشاهده می‌شود بسیار طولانی است، دات‌نت‌فریمورک معمولا از این توکِن برای نمایش آن و ریفرنس دادن اسمبلی‌ها استفاده می‌کند. نیازی نیست تا راز این کلیدها توسط توسعه‌دهنده حفظ شود! پس از نام‌گذاری قوی اسمبلی (که در ادامه توضیح داده می‌شود) کامپایلر با استفاده از کلید خصوصی فراهم شده یک امضای دیجیتالی (یک کد اینکریپت شده) با استفاده از داده‌های «مانیفست اسمبلی» تولید می‌کند. در ادامه کامپایلر این «امضای دیجیتال» و «کلید عمومی» را درون اسمبلی قرار می‌دهد تا مصرف‌کننده‌های اسمبلی بتوانند این امضای دیجیتال را تایید کنند. حفظ کردن «کلید خصوصی» بسیار مهم است! اگر کسی به کلید خصوصی اسمبلی دست یابد می‌تواند با استفاده از آن نسخه‌ای تغییریافته از اسمبلی را امضا کرده و در اختیار مصرف‌کنندگان قرار دهد. مصرف‌کنندگان نیز بدون اینکه متوجه شوند می‌توانند از این نسخه تغییر یافته با همان توکِن کلید عمومی که در اختیار دارند استفاده کنند. درحال حاضر روشی برای فهمیدن این تغییر وجود ندارد. اگر کلید خصوصی لو رفت، باید یک جفت کلید دیگر تولید و با استفاده از کلید خصوصی جدید اسمبلی را دوباره امضا کرد و در اختیار مصرف‌کنندگان قرار داد. هم‌چنین باید مشتریانِ اسمبلی را از این تغییر آگاه ساخت و کلید عمومی مورد اطمینان را در اختیار آن‌ها قرار داد.
    نکته: معمولا گروه کوچکی از افراد مورد اطمینان (که دسترسی امضای اسمبلی را دارند: signing authority) مسئولیت کلیدهای نامگذاری قوی یک شرکت را بر عهده دارند و برای امضای تمام اسمبلی‌ها قبل از ریلیز نهایی آن‌ها مسئول هستند.
    قابلیت امضای تاخیری اسمبلی (که در ادامه بحث می‌شود) تسهیلاتی را برای بهره‌برداری راحت‌تر از این روش و جلوگیری از توزیع کلیدهای خصوصی میان تمام توسعه‌دهندگان را فراهم می‌کند.
    یکی از روش‌هایی که sn برای افزایش امنیت کلیدها ارائه می‌دهد، استفاده از مخزن کلید CSP است. پس از تولید فایل حاوی جفت کلید، می‌توان با استفاده از دستور زیر این کلیدها را درون CSP با نام MyStrongNameKeys ذخیره کرد:
    sn -i MyKeys.snk MyStrongNameKeys
    سپس می‌توان فایل حاوی جفت کلید را حذف کرد.

    نکته مهمی که درباره مخازن کلید CSP باید بدان اشاره کرد این است که این مخازن شامل مخازن تعریف‌شده توسط «کاربر» و نیز مخازن «سیستمی» است. سیستم امنیتی ویندوز به کابران اجازه دسترسی به مخازنی غیر از مخازن خودشان و مخازن سیستمی را نمی‌دهد. برنامه sn به‌صورت پیش‌فرض کلیدها را درون مخازن سیستمی ذخیره می‌کند. بنابراین هر کسی که بتواند به سیستم لاگین کند و نیز از نام مخزن مربوطه آگاه باشد، به‌راحتی می‌تواند اسمبلی شما را امضا کند! برای اینکه ابزار sn کلیدها را در مخازن کاربری ذخیره کند باید از دستور زیر استفاده کرد:
    sn –m n
    برای برگرداند تنظیم به ذخیره در مخازن سیستمی نیز باید از دستور زیر استفاده کرد:
    sn –m y

     برای حذف کلیدها از مخزن می‌توان از دستور زیر استفاده کرد:
    sn -d MyStrongNameKeys

    2. نام‌گذاری قوی یک اسمبلی
    نام‌گذاری قوی یک اسمبلی به دلایل زیادی انجام می‌شود:
    - برای اینکه اسمبلی شناسه‌ای منحصربه‌فرد داشته باشد، تا کاربران بتوانند مجوزهای ویژه‌ای را در حین تنظیم سیاست‌های امنیتی دسترسی به کد اعمال کنند.
    - تا اسمبلی را نتوان تغییر داده و سپس به عنوان اسمبلی اصلی توزیع نمود.
    - تا اسمبلی بتواند نسخه‌گذاری (Versioning) و سیاست‌های نسخه‌گذاری را پشتیبانی کند.
    - تا بتوان اسمبلی را در GAC (همان Global Assembly Cache که در مسیر %windir%\assembly قرار دارد) ذخیره کرده و آن را بین چند اپلیکیشن به اشتراک گذاشت.
    برای نام‌گذاری قوی اسمبلی با استفاده از خط فرمان کامپایلر #C باید از سوییچهای keyfile/ و یا keycontainer/ استفاده کنید.
     

    csc /keyfile:d:\mykeys.snk /out:"C:\Projects\ClassLibrary1\Class1.exe" "C:\Projects\ClassLibrary1\Class1.cs" 

    نکته: برای استفاده از این ویژگی در ویژوال استودیو، باید در تب Signing در تنظیمات پروژه گزینه Sign the Assembly را انتخاب کرد. سپس می‌توان فایل حاوی جفت کلیدهای تولیدشده را انتخاب یا فایل جدیدی تولید کرد. البته ویژوال استودیو تا نسخه 2010 امکانی جهت استفاده از مخازن CSP را ندارد.

    روش ساده دیگر استفاده از attributeهای سطح اسمبلی است:
    [assembly:AssemblyKeyFileAttribute("MyKeys.snk")]
    3. بررسی اینکه آیا یک اسمبلی قوی-نام‌گذاری‌شده تغییر یافته یا خیر
    زمانی‌که CLR در زمان اجرا یک اسمبلی قوی-نام‌گذاری‌شده را بارگذاری می‌کند:
    -ابتدا با استفاده از کلید عمومی (که در خود اسمبلی ذخیره شده است) هش‌کد اینکریپت‌شده که در زمان کامپایل محاسبه شده (یا همان امضای دیجیتال که این نیز درون خود اسمبلی ذخیره شده است) را دیکریپت می‌کند. (هش‌کد زمان کامپایل)
    -پس از آن هش‌کد اسمبلی را با استفاده از داده‌های مانیفست اسمبلی محاسبه می‌کند. (هش‌کد زمان اجرا)
    -سپس این دو مقدار بدست آمده (هش‌کد زمان کامپایل و هش‌کد زمان اجرا) را با یکدیگر مقایسه می‌کند. این عملیات مقایسه و تایید مشخص می‌کند که آیا اسمبلی پس از امضا دچار تغییر شده است یا خیر!
    اگر یک اسمبلی نتواند عملیات تایید نام قوی را پشت سر بگذارد، CLR پیغام خطایی به نمایش خواهد گذاشت. این خطا یک اکسپشن از نوع System.IO.FileLoadException با پیغام Strong name validation failed خواهد بود. با استفاده از ابزار sn نیز می‌توان یک اسمبلی قوی-نام‌گذاری شده را تایید کرد. برای مثال برای تایید اسمبلی MyAsm.exe می‌توان از دستور زیر استفاده کرد:
    sn –vf MyAsm.exe

    سوییچ v موجب تایید نام قوی اسمبلی شده و سوییچ f برنامه را مجبور به بررسی صحت نام قوی اسمبلی می‌کند، حتی اگر این امکان قبلا برای اسمبلی غیرفعال شده باشد. (با استفاده از سویج Vr مثل دستور sn –Vr MyAsm.exe می‌توان عملیات تایید نام قوی یک اسمبلی خاص را غیرفعال کرد). اگر اسمبلی تغییر کرده باشد و نتواند آزمون فوق را پشت سر بگذارد خطایی به شکل زیر نمایش داده می‌شود:
    Microsoft (R) .NET Framework Strong Name Utility Version 2.0.50727.42
    Copyright (C) Microsoft Corporation. All rights reserved.
    Failed to verify assembly --
    Strong name validation failed for assembly MyAsm.exe'.
    4. امضای تاخیری (Delay Sign) یک اسمبلی
    درصورتی‌که بخواهیم یک اسمبلی را امضا کنیم اما نخواهیم تمام اعضای تیم توسعه به کلید خصوصی مربوطه دسترسی داشته باشند باید از تکنیک امضای با تاخیر اسمبلی استفاده کنیم. ابتدا باید کلید عمومی تولیدشده برای اسمبلی را استخراج کرده و آنرا توزیع کنیم. با توجه به توضیحات داده شده در بخش اول، به اسمبلی خود یک نام قوی اختصاص دهید. هم‌چنین اسمبلی خود را با استفاده از سویج delaysign/ باید کامپایل کنید. سپس با استفاده از سوییچ Vr برنامه sn عملیات تایید اسمبلی خود را غیرفعال کنید.
    نکته: برای استفاده از این امکان در ویژوال استودیو باید گزینه Delay sign only را در تب Signing از پراپرتی پروژه انتخاب کرد.

     اسمبلی‌هایی که ریفرنسی به اسمبلی‌های نام‌گذاری قوی شده دارند، حاوی توکِن کلید عمومی آن اسمبلی‌ها نیز هستند. این بدین معنی است که این گونه اسمبلی‌ها بایستی قبل از ریفرنس داده شدن امضا شده باشند. در یک محیط توسعه که اسمبلی‌ها مرتبا کامپایل می‌شوند نیاز است تا تمام توسعه دهندگان و آزمایش‌کنندگان به جفت‌کلیدهای موجود دسترسی داشته باشند (یک ریسک امنیتی بزرگ). به جای توزیع کلید خصوصی، دات‌نت‌فریمورک مکانیزمی به نام امضای تاخیری (delay-signing) فراهم کرده است، که به شما اجازه می‌دهد تا یک اسمبلی را به‌صورت ناکامل (ناقص) امضا کنید. اسمبلی «ناقص-نام‌گذاریِ قوی شده»! حاوی کلید عمومی و توکِن کلید عمومی است که برای ریفرنس دادن اسمبلی نیاز است، اما تنها حاوی مکانِ خالیِ امضای دیجیتالی است که توسط کلید خصوصی تولید می‌شود. پس از کامل شدن توسعة برنامه، فرد مسئول امضای اسمبلی‌ها (signing authority - شخصی که مسئول امنیت و حفظ جفت‌کلیدهاست) اسمبلی‌‌های حاوی امضای تاخیری را دوباره امضا می‌کند، تا نام‌گذاریِ قوی آن اسمبلی کامل شود. برای امضای تاخیری یک اسمبلی تنها نیاز به کلید عمومی آن است، که هیچ ریسک امنیتی‌ای برای آن وجود ندارد. برای استخراج کلید عمومی یک جفت کلید همان‌طور که قبلا اشاره شده است، می‌توان از دستورات زیر استفاده کرد:
    sn –p d:\MyKeys.snk d:\MyPublicKey.snk
    sn –pc MyKeysContainer d:\MyPublicKey.snk
    با داشتن فایل حاوی کلید عمومی، و با استفاده از از دستور کامپایل زیر می‌توان اسمبلی را امضای تاخیری کرد:
    csc.exe /delaysign /keyfile:d:\MyPublicKey.snk /out:d:\MyAsm.exe d:\Class1.cs
    نکته: برای امضای اسمبلی‌های چندفایلی (multifile assembly) باید از Assembly Linker (نام فایل اجرایی آن al.exe است) استفاده کرد. این ابزار نیز مانند ابزار sn.exe در sdkهای ویندوز یافت می‌شود. دستوری که باید برای امضای این نوع اسمبلی‌های به‌کار برد به‌صورت زیر است:
    al /out:<assembly name> <module name> /keyfile:<file name>
    از آنجاکه درهنگام بارگذاری اسمبلی، CLR اسمبلی را به عنوان یک اسمبلی قوی نام‌گذاری شده درنظر می‌گیرد، همان‌طور که قبلا اشاره شده، سعی می‌کند تا صحت آن را بررسی و تایید کند. اما چون اسمبلی با امضای تاخیری هنوز امضا نشده است، باید CLR را جوری تنظیم کنید تا تایید اعتبار این اسمبلی را در کامپیوتر جاری انجام ندهد. این کار را همان‌طور که در بالا توضیح داده شد، می‌توان با دستور زیر انجام داد:
    sn –Vr d:\MyAsm.exe

    از لحاظ فنی این دستور اسمبلی موردنظر را در لیست «صرف‌نظر از تایید اسمبلی» ثبت (register) می‌کند. دقت کنید که دستور فوق را باید در تمام سیستم‌هایی که قرار است به نحوی با این اسمبلی سروکار داشته باشند اجرا کنید!
    نکته: تا زمانی‌که با استفاده از دستور فوق عملیات تایید اعتبار اسمبلی‌های امضای تاخیری شده را غیرفعال نکنید امکان اجرا یا بارگذاری آن اسمبلی‌ها و نیز دیباگ سورس‌کدهای آن را نخواهید داشت!
    پس از تکمیل فاز توسعه باید اسمبلی را دوباره امضا کنید تا نام‌گذاری قوی کامل شود. برنامه sn به شما این امکان را می‌دهد تا بدون تغییر سورس‌کد اسمبلی خود یا کامپایل دوباره آن عملیات امضای دوباره آنرا انجام دهید. اما برای این‌کار شما باید به کلید خصوصی آن (در واقع به فایل حاوی جفت‌کلید مربوطه) دسترسی داشته باشید. برای امضای دوباره می‌توان از دستورات زیر استفاده کرد:
    sn –R d:\MyAsm.exe MyKeys.snk
    sn –R d:\MyAsm.exe MyKeysContainer

    با استفاده از این دستور برنامه sn شروع به محاسبه هش‌کد زمان کامپایل می‌کند و درنهایت مقدار اینکریپت‌شده را درون اسمبلی ذخیره می‌کند.
    نکته: هنگام استفاده از اسمبلی‌های با امضای تاخیری، امکان مقایسه بیلدهای مختلف یک اسمبلی خاص برای اطمینان از اینکه تنها در امضای دیجیتال با هم فرق دارند، معمولا مفید است. این مقایسه تنها وقتی امکان‌پذیر است که اسمبلی موردنظر با استفاده از سوییچ R دوباره امضا شود. برای مقایسه دو اسمبلی می‌توان از سوییچ D استفاده کرد:
    sn –D assembly1 assembly2
    پس از امضای دوباره اسمبلی می‌توان عملیات تایید آنرا که قبلا غیرفعال شده است، با استفاده از دستور زیر دوباره فعال کرد:
    sn –Vu d:\MyAsm.exe

    دستور فوق اسمبلی موردنظر را از لیست «صرفنظر از تایید اسمبلی» حذف (Unregister) می‌کند.
    نکته: درصورتی‌که بخواهید یک اسمبلی را قبل از امضای دوباره (و یا در حالت کلی، قبل از اینکه اسمبلی دارای یک نام قوی کامل شده باشد) اجرا یا از آن به عنوان یک ریفرنس استفاده کنید، بدون اینکه آن را به لیست «صرفنظر از تایید اسمبلی» اضافی کنید،  با خطای زیر مواجه خواهید شد: 

    برای فعال‌سازی تایید اسمبلی برای تمامی اسمبلی‌هایی که این ویژگی برای آنان غیرفعال شده است، می‌توانید از دستور زیر استفاده کنید:
    sn –Vx
    برای لیست کردن اسمبلی‌هایی که تایید آنان غیرفعال شده است، می‌توانید از دستور زیر استفاده کنید:
    sn –Vl
    نکته: در دات‌نت 1.0 و 1.1 کامپایلر #C فاقد سوییچ delaysign/ است. برای استفاده از امکان امضای تاخیری اسمبلی می‌توان از attribute سطح اسمبلی System.Reflection.AssemblyDelaySignAttribute استفاده کرد. همچنین می‌شود از ابزار لینکر اسمبلی (al.exe) که از این سوییچ پشتیبانی می‌کند استفاده کرد.
    نکته: ابزارهای obfuscating که برای پیچیده‌کردن کد IL اسمبلی تولیدی به‌منظور جلوگیری از عملیات تولید دوباره کد (مثل کاری که برنامه Reflector انجام می‌دهد) به‌کار می‌روند، به دلیل تغییراتی که در محتوای اسمبلی ایجاد می‌کنند، درصورتیکه برای اسمبلی‌های دارای نام قوی استفاده شوند موجب ازکار افتادن آن‌ها می‌شوند. بنابراین یا باید آن‌ها را در سیستم‌هایی استفاده کرد که آن اسمبلی موردنظر در لیست صرفنظر از تایید اسمبلی ثبت شده باشد یا اینکه اسمبلی مربوطه را دوباره با استفاده از روش‌های توضیح داده‌شده (مثلا با استفاده از دستور sn –R myAsm.dll MyKeys.snk) برای تخصیص نام قوی جدید امضا کرد. الگوی معمولی که برای استفاده از obfuscating برای اسمبلی‌های دارای نام قوی استفاده می‌شود به‌صورت زیر است:
    - ساخت اسمبلی با امضای تاخیری
    - افزودن اسمبلی به لیست صرفنظر از تایید اسمبلی (sn -Vr)
    - دیباگ و تست اسمبلی
    - obfuscate کردن اسمبلی
    - دیباگ و تست اسمبلی obfuscate شده
    - امضای دوباره اسمبلی (sn -R)
    الگوی ساده‌تر دیگری نیز برای این منظور استفاده می‌شود که به‌صورت زیر است:
    - تولید اسمبلی بدون استفاده از تنظیمات امضای تاخیری
    - دیباگ و تست اسمبلی
    - obfuscate اسمبلی
    - امضای دوباره اسمبلی (sn -R)
    - دیباگ و تست دوباره نسخه obfuscate شده

    5. مدیریت کش عمومی اسمبلی‌ها (Global Assembly Cache)
    با استفاده از توضیحات این بخش می‌توان اسمبلی‌ها را به GAC اضافه و یا از درون آن حذف کرد. این کار با استفاده از برنامه gacutil.exe انجام می‌شود. مسیر نسخه 4 و 32 بیتی این برنامه به‌صورت زیر است:
    C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\gacutil.exe
    این برنامه به‌همراه SDK ویندوز و یا به‌همراه ویژوال استودیو در مسیری مشابه نشانی بالا نصب می‌شود. همانند توضیحات داده‌شده در مورد برنامه sn.exe، برای راحتی کار می‌توانید از خط فرمان ویژه‌ای که ویژوال استودیو در اختیار شما قرار می‌دهد استفاده کنید. البته قبل از اجرای هر دستوری مطمئن شوید که خط فرمان شما با استفاده از مجوز مدیریتی (Administrator) اجرا شده است! تنها اسمبلی‌های دارای نام قوی می‌توانند در GAC نصب شوند. بنابراین قبل افزودن یک اسمبلی به GAC باید طبق راهنمایی‌های موجود در قسمت‌های قبلی آن را به‌صورت قوی نام‌گذاری کرد. برای افزودن یک اسمبلی با نام MyAsm.dll می‌توان از دستور زیر استفاده کرد:
    gacutil /i c:\MyAsm.dll

    درصورتی‌که اسمبلی موردنظر دارای نام قوی نباشد، خطایی به صورت زیر نمایش داده خواهد شد:

    می‌توان نسخه‌های متفاوتی از یک اسمبلی (با نام یکسان) را با استفاده از این ابزار در GAC رجیستر کرد و آن‌ها را در کنار یکدیگر برای استفاده در نرم‌افزارهای گوناگون در اختیار داشت. برای حذف یک اسمبلی از GAC و یا به اصطلاح uninstall کردن آن می‌توان از دستور زیر استفاده کرد:
    gacutil /u MyAsm
    نکته: دقت کنید که در این دستور تنها از نام اسمبلی استفاده شده است و نه نام فایل حاوی آن!

    دستور فوق تمام نسخه‌های اسمبلی MyAsm موجود در GAC را حذف خواهد کرد. برای حذف نسخه‌ای خاص باید از دستوری مشابه زیر استفاده کرد:
    gacutil /u MyAsm,Version=1.3.0.5
    برای مشاهده تمام اسمبلی‌های نصب شده در GAC می‌توان از دستور زیر استفاده کرد:
    gacutil /l

    همان‌طور که مشاهده می‌کنید دستور فوق فهرستی بسیار طولانی از تمام اسمبلی‌های نصب‌شده در GAC را به‌همراه لیست اسمبلی‌هایی که در کش ngen به فرم باینری پیش‌کامپایل (Precompiled) شده‌اند، نمایش می‌دهد. برای تعیین اینکه آیا اسمبلی موردنظر در GAC نصب شده است می‌توان از دستور زیر استفاده کرد:
    gacutil /l MyAsm

    نکته: دات‌نت از GAC تنها در زمان اجرا استفاده می‌کند. بنابراین کامپایلر #C به‌صورت خودکار درون GAC را برای یافتن ریفرنس‌های یک اسمبلی جستجو نخواهد کرد. در زمان توسعه، کامپایلر #C به یک نسخه لوکال از ریفرنس‌های مذکور نیاز خواهد داشت. برای حل این مشکل می‌توان یک نسخه از این ریفرنس‌ها را به مسیر اسمبلی کپی کرد (در ویژوال استودیو می‌توان از خاصیت Copy Local ریفرنس‌ها استفاده کرد) یا با استفاده از سوییچ lib/ کامپایلر، مسیری را که می‌تواند این ریفرنس‌ها را در آن بیابد معرفی کرد (کاری که ویژوال استودیو به‌صورت خودکار انجام می‌دهد).
    نکته: نکته‌ای که در پایان باید اشاره کرد این است که تکنولوژی نام قوی برای بحث امنیت کد اسمبلی (مثلا برای جلوگیری از مهندسی معکوس IL و تغییر آن) بوجود نیامده است زیرا حذف این نام‌های قوی کار سختی نیست. بلکه هدف اصلی این تکنولوژی جلوگیری از تغییرات مخفی خرابکارانه و محرمانه اسمبلی توزیع شده و توزیع این نسخه‌های دستکاری شده به جای نسخه اصلی است. در زیر ابزارها و روش‌هایی که می‌توانند برای حذف کامل نام قوی یک اسمبلی به‌کار روند آورده شده است.
    البته باید به این نکته اشاره کرد که در صورت حذف نام قوی یک اسمبلی (یا همان حذف امضای دیجیتال درون آن) تمامی اسمبلی‌هایی که قبل از حذف نام قوی به آن ریفرنس داشتند از کار خواهند افتاد. یعنی درواقع تمامی آن اسمبلی‌ها برای ریفرنس دادن به این اسمبلی با نام جدید (نامی که دیگر قوی نیست) باید آپدیت شوند. هم‌چنین درصورتی‌که اسمبلی‌هایی که قبل از حذف نام قوی به اسمبلی موردنظر ما ریفرنس داشتند، خود نام قوی داشته باشند با حذف نام قوی، آنها از کار خواهند افتاد. چون اسمبلی‌های دارای نام قوی تنها می‌توانند از اسمبلی‌های دارای نام قوی ریفرنس داشته باشند. بنابراین برای کارکردن برنامه موردنظر باید نام قوی تمامی اسمبلی‌های درگیر را حذف کرد!
    منابع استفاده شده در تهیه این مطلب: