مطالب
React 16x - قسمت 8 - ترکیب کامپوننت‌ها - بخش 2 - مدیریت state
در ادامه‌ی بحث ترکیب کامپوننت‌ها، پس از نمایش لیستی از کامپوننت‌های شمارشگر و مقدار دهی عدد آغازین آن‌ها، به همراه مدیریت حذف هر ردیف در قسمت قبل، اکنون می‌خواهیم دکمه‌ای را اضافه کنیم تا تمام شمارشگرها را به حالت اول خودشان بازگرداند. برای این منظور دکمه‌ی Reset را به ابتدای المان‌های کامپوننت Counters اضافه می‌کنیم:
<button
  onClick={this.handleReset}
  className="btn btn-primary btn-sm m-2"
>
  Reset
</button>
سپس متد رویدادگردان handleReset آن‌را به صورت زیر با تنظیم مقدار value هر counter به صفر و بازگشت آن و در نهایت به روز رسانی state کامپوننت با این آرایه‌ی جدید، پیاده سازی می‌کنیم:
  handleReset = () => {
    const counters = this.state.counters.map(counter => {
      counter.value = 0;
      return counter;
    });
    this.setState({ counters }); // = this.setState({ counters: counters });
  };


اکنون پس از ذخیره سازی فایل counters.jsx و بارگذاری مجدد برنامه در مرورگر، هرچقدر بر روی دکمه‌ی Reset کلیک کنیم ... اتفاقی رخ نمی‌دهد! حتی اگر به افزونه‌ی React developer tools نیز مراجعه کنیم، مشاهده خواهیم کرد که عمل تنظیم value به صفر، در تک تک کامپوننت‌های شمارشگر، به درستی صورت گرفته‌است؛ اما تغییرات به DOM اصلی منعکس نشده‌اند:


البته اگر به همین تصویر دقت کنید، هنوز مقدار count، در state آن 4 است. علت اینجا است که هر کدام از Counterها دارای local state خاص خودشان هستند و در آن‌ها، مقدار count به صورت زیر مقدار دهی شده‌است که در آن تغییرات بعدی این this.props.value، متصل به count نیست و count، فقط یکبار مقدار دهی می‌شود:
class Counter extends Component {
  state = {
    count: this.props.counter.value
  };
این قطعه‌ی از کد، تنها زمانی اجرا می‌شود که یک وهله از کلاس کامپوننت Counter، در حال ایجاد است. به همین جهت زمانیکه صفحه برای بار اول بارگذاری می‌شود، مقدار آغازین count به درستی دریافت می‌شود. اما با کلیک بر روی دکمه‌ی Reset، هرچند مقدار value هر شیء counter تعریف شده‌ی در کامپوننت والد تغییر می‌کند، اما local state کامپوننت‌های فرزند به روز رسانی نمی‌شوند و مقدار جدید value را دریافت نمی‌کنند. برای رفع یک چنین مشکلی نیاز است یک مرجع مشخص را برای مقدار دهی stateهای کامپوننت‌های فرزند ایجاد کنیم.


حذف Local state

اکنون می‌خواهیم در کامپوننت Counter، قسمت local state آن‌را به طور کامل حذف کرده و تنها از this.props جهت دریافت اطلاعاتی که نیاز دارد، استفاده کنیم. به این نوع کامپوننت‌ها، «‍Controlled component» نیز می‌گویند. یک کامپوننت کنترل شده دارای local state خاص خودش نیست و تمام داده‌های دریافتی را از طریق this.props دریافت می‌کند و هر زمانیکه قرار است داده‌ای تغییر کند، رخ‌دادی را به والد خود صادر می‌کند. بنابراین این کامپوننت به طور کامل توسط والد آن کنترل می‌شود.
برای پیاده سازی این مفهوم، ابتدا خاصیت state کامپوننت Counter را حذف می‌کنیم. سپس تمام ارجاعات به this.state را در این کامپوننت یافته و آن‌ها را تغییر می‌دهیم. اولین ارجاع، در متد handleIncrement به صورت this.state.count تعریف شده‌است:
  handleIncrement = () => {
    this.setState({ count: this.state.count + 1 });
  };
 از این جهت که دیگر دارای local state نیستیم، داشتن متد this.setState در اینجا بی‌مفهوم است. در یک کامپوننت کنترل شده، هر زمانیکه قرار است داده‌ای ویرایش شود، این کامپوننت باید رخ‌دادی را صادر کرده و از والد خود درخواست تغییر اطلاعات را ارائه دهد؛ شبیه به this.props.onDelete ای که در قسمت قبل کامل کردیم. بنابراین کل متد handleIncrement را نیز حذف می‌کنیم. اینبار رخ‌داد onClick، سبب بروز رخداد onIncrement در والد خود خواهد شد:
<button
  onClick={() => this.props.onIncrement(this.props.counter)}
  className="btn btn-secondary btn-sm"
>
  Increment
</button>
همچنین دو متد دیگری که ارجاعی را به this.state داشتند، به صورت زیر جهت استفاده‌ی از this.props.counter.value، به روز رسانی می‌شوند:
  getBadgeClasses() {
    let classes = "badge m-2 badge-";
    classes += this.props.counter.value === 0 ? "warning" : "primary";
    return classes;
  }

  formatCount() {
    const { value } = this.props.counter; // Object Destructuring
    return value === 0 ? "Zero" : value;
  }
تا اینجا به صورت کامل local state این کامپوننت حذف و با this.props جایگزین شده و در نتیجه تحت کنترل کامپوننت والد آن قرار می‌گیرد.

در ادامه به کامپوننت Counters مراجعه کرده و متد رویدادگردانی را جهت پاسخگویی به رخ‌داد onIncrement رسیده‌ی از کامپوننت‌های فرزند، تعریف می‌کنیم:
  handleIncrement = counter => {
    console.log("handleIncrement", counter);
  };
سپس ارجاعی از این متد را به ویژگی onIncrement تعریف شده‌ی در المان Counter، متصل می‌کنیم:
  <Counter
    key={counter.id}
    counter={counter}
    onDelete={this.handleDelete}
    onIncrement={this.handleIncrement}
  />
اکنون هر زمانیکه بر روی دکمه‌ی Increment کلیک شود، this.props.onIncrement آن، سبب فراخوانی متد handleIncrement والد خود خواهد شد.

پیاده سازی کامل متد handleIncrement اینبار به صورت زیر است:
  handleIncrement = counter => {
    console.log("handleIncrement", counter);
    const counters = [...this.state.counters]; // cloning an array
    const index = counters.indexOf(counter);
    counters[index] = { ...counter }; // cloning an object
    counters[index].value++;
    console.log("this.state.counters", this.state.counters[index]);
    this.setState({ counters });
  };
همانطور که در قسمت‌های قبل نیز عنوان شد، در React نباید مقدار state را به صورت مستقیم ویرایش کرد؛ مانند مراجعه‌ی مستقیم به this.state.counters[index] و سپس تغییر خاصیت value آن‌. بنابراین باید یک clone از آرایه‌ی counters و سپس یک clone از شیء counter رسیده‌ی از کامپوننت فرزند را ایجاد کنیم تا این cloneها دیگر ارجاعی را به اشیاء اصلی ساخته شده‌ی از روی آن‌ها نداشته باشند (مهم‌ترین خاصیت یک clone) تا اگر خاصیت و مقداری را در آن‌ها تغییر دادیم، دیگر به شیء اصلی که از روی آن‌ها clone شده‌اند، منعکس نشوند. در اینجا از spread operator برای ایجاد این cloneها استفاده شده‌است. اکنون مقادیر خواص این cloneها را تغییر می‌دهیم و درنهایت این counters جدید را که خودش نیز یک clone است، به متد this.setState جهت به روز رسانی UI و همچنین state کامپوننت، ارسال می‌کنیم.

تا اینجا اگر برنامه را ذخیره کرده و منتظر به روز رسانی آن در مرورگر شویم، با کلیک بر روی Reset، تمام کامپوننت‌ها با هر وضعیتی که پیشتر داشته باشند، به حالت اول خود باز می‌گردند:



همگام سازی چندین کامپوننت با هم زمانیکه رابطه‌ی والد و فرزندی بین آن‌ها وجود ندارد


در ادامه می‌خواهیم یک منوی راهبری (یا همان NavBar در بوت استرپ) را به بالای صفحه اضافه کنیم و در آن جمع کل تعداد Counterهای رندر شده را نمایش دهیم؛ مانند نمایش تعداد آیتم‌های انتخاب شده‌ی توسط یک کاربر، در یک سبد خرید. برای پیاده سازی آن، درخت کامپوننت‌های React را مطابق شکل فوق تغییر می‌دهیم. یعنی مجددا کامپوننت App را در به عنوان کامپوننت ریشه‌ای انتخاب کرده که سایر کامپوننت‌ها از آن مشتق می‌شوند و همچنین کامپوننت مجزای NavBar را نیز اضافه خواهیم کرد.
برای این منظور به index.js مراجعه کرده و مجددا کامپوننت App را که غیرفعال کرده بودیم و بجای آن Counters را نمایش می‌دادیم، اضافه می‌کنیم:
import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));

سپس کامپوننت جدید NavBar را توسط فایل جدید src\components\navbar.jsx اضافه می‌کنیم تا منوی راهبری سایت را نمایش دهد:
import React, { Component } from "react";

class NavBar extends Component {
  render() {
    return (
      <nav className="navbar navbar-light bg-light">
        <a className="navbar-brand" href="#">
          Navbar
        </a>
      </nav>
    );
  }
}

export default NavBar;

اکنون به App.js مراجعه کرده و متد render آن‌را جهت نمایش درخت کامپوننت‌هایی که مشاهده کردید، تکمیل می‌کنیم:
import "./App.css";

import React from "react";

import Counters from "./components/counters";
import NavBar from "./components/navbar";

function App() {
  return (
    <React.Fragment>
      <NavBar />
      <main className="container">
        <Counters />
      </main>
    </React.Fragment>
  );
}

export default App;
ابتدا کامپوننت NavBar در بالای صفحه رندر می‌شود و سپس کامپوننت Counters در میانه‌ی صفحه. چون در اینجا چندین المان قرار است رندر شوند، از React.Fragment برای محصور کردن آن‌ها استفاده کرده‌ایم.
تا اینجا اگر برنامه را ذخیره کنیم تا در مرورگر بارگذاری مجدد شود، چنین شکلی حاصل شده‌است:


اکنون می‌خواهیم تعداد کامپوننت‌های شمارشگر را در navbar نمایش دهیم. پیشتر state کامپوننت Counters را توسط props، به کامپوننت‌های Counter رندر شده‌ی توسط آن انتقال دادیم. استفاده‌ی از این ویژگی به دلیل وجود رابطه‌ی والد و فرزندی بین این کامپوننت‌ها میسر شد. اما همانطور که در تصویر درخت کامپوننت‌های جدید تشکیل شده مشاهده می‌کنید، رابطه‌ی والد و فرزندی بین دو کامپوننت Counters و NavBar وجود ندارد. بنابراین اکنون این سؤال مطرح می‌شود که چگونه باید تعداد کل شمارشگرهای کامپوننت Counters را به کامپوننت NavBar، برای نمایش آن‌ها انتقال داد؟ در یک چنین حالت‌هایی که رابطه‌ی والد و فرزندی بین کامپوننت‌ها وجود ندارد و می‌خواهیم آن‌ها را همگام سازی کنیم و داده‌هایی را بین آن‌ها به اشتراک بگذاریم، باید state را به یک سطح بالاتر انتقال داد. یعنی در این مثال باید state کامپوننت Counters را به والد آن که اکنون کامپوننت App است، منتقل کرد. پس از آن چون هر دو کامپوننت NavBar و Counters، از کامپوننت App مشتق می‌شوند، اکنون می‌توان این state را به تمام فرزندان App توسط props منتقل کرد و به اشتراک گذاشت.


انتقال state به یک سطح بالاتر

برای انتقال state به یک سطح بالاتر، به کامپوننت Counters مراجعه کرده و خاصیت state آن‌را به همراه تمامی متدهایی که آن‌را تغییر می‌دهند و از آن استفاده می‌کنند، انتخاب و cut می‌کنیم. سپس به کامپوننت App مراجعه کرده و آن‌ها را در اینجا paste می‌کنیم. یعنی خاصیت state و متدهای handleDelete، handleReset و handleIncrement را از کامپوننت Counters به کامپوننت App منتقل می‌کنیم. این مرحله‌ی اول است. سپس نیاز است به کامپوننت Counters مراجعه کرده و ارجاعات به state و متدهای یاد شده را توسط props اصلاح می‌کنیم. برای این منظور ابتدا باید این props را در کامپوننت App مقدار دهی کنیم تا بتوانیم آن‌ها را در کامپوننت Counters بخوانیم؛ یعنی متد render کامپوننت App، تمام این خواص و متدها را باید به صورت ویژگی‌هایی به تعریف المان Counters اضافه کند تا خاصیت props آن بتواند به آن‌ها دسترسی داشته باشد:
  render() {
    return (
      <React.Fragment>
        <NavBar />
        <main className="container">
          <Counters
            counters={this.state.counters}
            onReset={this.handleReset}
            onIncrement={this.handleIncrement}
            onDelete={this.handleDelete}
          />
        </main>
      </React.Fragment>
    );
  }

پس از این تعاریف می‌توانیم به کامپوننت Counters بازگشته و ارجاعات فوق را توسط خاصیت props، در متد render آن اصلاح کنیم:
  render() {
    return (
      <div>
        <button
          onClick={this.props.onReset}
          className="btn btn-primary btn-sm m-2"
        >
          Reset
        </button>
        {this.props.counters.map(counter => (
          <Counter
            key={counter.id}
            counter={counter}
            onDelete={this.props.onDelete}
            onIncrement={this.props.onIncrement}
          />
        ))}
      </div>
    );
  }
در اینجا سه رویدادگردان و یک خاصیت counters، از طریق خاصیت props والد کامپوننت Counter که اکنون کامپوننت App است، خوانده می‌شوند.

پس از این نقل و انتقالات، اکنون می‌توانیم تعداد counters را در NavBar نمایش دهیم. برای این منظور ابتدا در کامپوننت App، به همان روشی که ویژگی counters={this.state.counters} را به تعریف المان Counters اضافه کردیم، شبیه به همین کار را برای کامپوننت NavBar نیز می‌توانیم انجام دهیم تا از طریق خاصیت props آن قابل دسترسی شود و یا حتی می‌توان به صورت زیر، تنها جمع کل را به آن کامپوننت ارسال کرد:
<NavBar
    totalCounters={this.state.counters.filter(c => c.value > 0).length}
/>

سپس در کامپوننت NavBar، عدد totalCounters فوق را که به تعداد کامپوننت‌هایی که مقدار value آن‌ها بیشتر از صفر است، اشاره می‌کند، از طریق خاصیت props خوانده و نمایش می‌دهیم:
class NavBar extends Component {
  render() {
    return (
      <nav className="navbar navbar-light bg-light">
        <a className="navbar-brand" href="#">
          Navbar{" "}
          <span className="badge badge-pill badge-secondary">
            {this.props.totalCounters}
          </span>
        </a>
      </nav>
    );
  }
}
که با ذخیره کردن این فایل و بارگذاری مجدد برنامه در مرورگر، به خروجی زیر خواهیم رسید:



کامپوننت‌های بدون حالت تابعی

اگر به کدهای کامپوننت NavBar دقت کنیم، تنها یک تک متد render در آن ذکر شده‌است و تمام اطلاعات مورد نیاز آن نیز از طریق props تامین می‌شود و دارای state و یا هیچ رویدادگردانی نیست. یک چنین کامپوننتی را می‌توان به یک «Stateless Functional Component» تبدیل کرد؛ کامپوننت‌های بدون حالت تابعی. در اینجا بجای اینکه از یک کلاس برای تعریف کامپوننت استفاده شود، می‌توان از یک function استفاده کرد (به همین جهت به آن functional می‌گویند). احتمالا نمونه‌ی آن‌را با کامپوننت App پیش‌فرض قالب create-react-app نیز مشاهده کرده‌اید که در آن فقط یک ()function App وجود دارد. البته در کدهای فوق چون نیاز به ذکر state، در کامپوننت App وجود داشت، آن‌را از حالت تابعی، به حالت کلاس استاندارد کامپوننت، تبدیل کردیم.
اگر بخواهیم کامپوننت بدون حالت NavBar را نیز تابعی کنیم، می‌توان به صورت زیر عمل کرد:
import React from "react";

// Stateless Functional Component
const NavBar = props => {
  return (
    <nav className="navbar navbar-light bg-light">
      <a className="navbar-brand" href="#">
        Navbar{" "}
        <span className="badge badge-pill badge-secondary">
          {props.totalCounters}
        </span>
      </a>
    </nav>
  );
};

export default NavBar;
برای اینکار قسمت return متد render کامپوننت را cut کرده و به داخل تابع NavBar منتقل می‌کنیم. بدنه‌ی این تابع را هم می‌توان توسط میان‌بر sfc که مخفف Stateless Functional Component است، در VSCode تولید کرد.
پیشتر در کامپوننت NavBar از شیء this استفاده شده بود. این روش تنها با کلاس‌های استاندارد کامپوننت کار می‌کند. در اینجا باید props را به عنوان پارامتر متد دریافت (همانند مثال فوق) و سپس از آن استفاده کرد.

البته لازم به ذکر است که انتخاب بین «کامپوننت‌های بدون حالت تابعی» و یک کامپوننت معمولی تعریف شده‌ی توسط کلاس‌ها، صرفا یک انتخاب شخصی است.

یک نکته: امکان Destructuring Arguments نیز در اینجا وجود دارد. یعنی بجای اینکه یکبار props را به عنوان پارامتر دریافت کرد و سپس توسط آن به خاصیت totalCounters دسترسی یافت، می‌توان نوشت:
const NavBar = ({ totalCounters }) => {
در این حالت شیء props دریافت شده توسط ویژگی Objects Destructuring، به totalCounters تجزیه می‌شود و سپس می‌توان تنها از همین متغیر دریافتی، به صورت {totalCounters} در کدها استفاده کرد.



کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-08.zip
نظرات مطالب
تبدیل برنامه‌های کنسول ویندوز به سرویس ویندوز ان تی
من برای شرکتی چندسال قبل یک چنین برنامه‌ای رو تهیه کردم:
یک سرویس ویندوز ان تی که روزهای اول به پورت سریال دستگاه کارتخوان متصل می‌شد و بعدها این پورت تبدیل شد به پورت شبکه و ریموت هم می‌شد به آن وصل شد؛ اما باز هم این پورت شبکه تبدیلگری بود برفراز سیستم اصلی RS232 آن دستگاه. کار این سرویس که نیاز به دسترسی بالایی برای اتصال به پورت‌های سیستم داشت و همچنین همیشه در حال اجرا بود و راه اندازی آن نیازی به لاگین شخصی و اجرای دستی برنامه نداشت (مزیت سرویس‌های ویندوز ان تی)، اتصال هر 5 دقیقه یکبار به دستگاه کارتخوان، تخلیه اطلاعات آن و ثبت آن‌ها در بانک اطلاعاتی یک برنامه ASP.NET بود. به این ترتیب کارکنان آن سازمان می‌توانستند از ورود و خروج خودشان با یک برنامه تحت وب (در شبکه داخلی شرکت) گزارشگیری کنند.
مطالب
لیست تازه‌های IIS 7.5

IIS 7.5 که به همراه ویندوز سرور 2008 R2 ارائه می‌شود شامل تازه‌های زیر است:

  • بیش از 50 مورد cmdlet جدید مخصوص Powershell جهت مدیریت IIS
  • افزونه‌های جدید مدیریتی: Database Manager (مدیریت اس کیوال سرور از درون IIS و کنسول آن)، Configuration Editor (تولید خودکار اسکریپت‌های مدیریتی جهت اتوماسیون امور مرتبط)، IIS Reports و Request Filtering .
  • پشتیبانی از One-click publishing موجود در Visual Studio 10
  • Web Deployment Tool یا همان MS Deploy سابق جهت مدیریت بهتر برنامه‌های وب.
  • امکان ردیابی تغییرات در کانفیگ وب سرور
  • گزارشگیری بهتر از وضعیت کارآیی سرور
  • ساپورت دات نت جهت Server Core معرفی شده در ویندوز سرور 2008
  • WebDav که پیشتر به صورت یک افزونه‌ی آن معرفی شده بود، اکنون جزئی از IIS 7.5 است.
  • یکپارچگی با URLScan 3.0 جهت بالا بردن امنیت وب سرور.
  • FTP server services : با کنسول مدیریتی IIS یکپارچه شده است با بهبودهایی در نحوه‌ی تنظیم کردن و ردیابی آن.

جهت مطالعه بیشتر در مورد تازه‌های ویندوز سرور 2008 نگارش R2 می‌توان به مقالات زیر رجوع کرد:
Windows Server 2008 R2 new features - the complete list - Part 1: Virtualization
Windows Server 2008 R2 new features - the complete list - Part 2: Active Directory
Windows Server 2008 R2 new features - the complete list - Part 3: IIS 7.5 and Performance
Windows Server 2008 R2 new features - the complete list - Part 4: Administration

مطالب
راه اندازی سرور Git با استفاده از Bonobo Git Server و انتقال از ساب ورژن به گیت
تا چندی پیش شاید برای استفاده‌ی از گیت و راه اندازی سرور عملیاتی آن در ویندوز، مشکلاتی مانند سبک راه اندازی آن که لینوکسی و کامندی بود، مانعی برای استفاده بود. ولی با استفاده از Bonobo Git Server که با ASP.NET MVC نوشته شده‌است و بصورت مدفون شده (embedded) از گیت استفاده می‌کند، راه انداختن سرور گیت خیلی آسان و با مراحلی خیلی کمتر و پسندیده‌تر، قابل انجام است. من تا مدتی قبل، برای استفاده‌ی شخصی به مدتی طولانی از Subversion برای نگهداری تاریخچه‌ی پروژه‌ها استفاده و حتی مثالهایی را که می‌نوشتم در این سرور ذخیره می‌کردم. ولی با توجه به سرعت فوق العاده‌ای که گیت داشت و نیز یکپارچگی که با آن در داخل ویژوال استودیو به‌وجود آمده، شاید بد نباشد حتی برای استفاده‌ی شخصی و بصورت تیم تک نفره هم این سورس کنترلر قوی را انتخاب کرد.
برای این منظور ابتدا آخرین نسخه‌ی  Bonobo Git Server را از آدرس مخرن آن دریافت می‌کنید و با توجه ویندوز، پیشنیاز‌های آن را نصب می‌کنیم:
- نصب و راه اندازی IIS
- نصب دات نت فریمورک 4.5
- نصب ASP.NET MVC نسخه 4.0
مانند هاست کردن یه برنامه وب ASP.NET محتوای آن را هاست میکنیم:
 همانطور که در تصویر زیر می‌بینید، این برنامه از فولدر App_Data بصورت پیش فرض برای نگهداری گیت و مخازن آن استفاده کرده است :

این سرور در فایل config.xml قرار گرفته در فولدر App_Data، تنظیمات مربوط به فراخوانی‌هایی را که در داخل برنامه‌ی وب به گیت می‌دهد، ذخیره می‌کند؛ از جمله در آن مشخص می‌شود که فولدر نگهداری مخازن کجا قرار گرفته‌است. من برای استفاده، این آدرس را به درایوی غیر از درایو ویندوز تغییر دادم:
<?xml version="1.0"?>
<Configuration xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <AllowAnonymousPush>false</AllowAnonymousPush>
  <Repositories>D:\GitRepo</Repositories>
  <AllowUserRepositoryCreation>true</AllowUserRepositoryCreation>
  <AllowAnonymousRegistration>false</AllowAnonymousRegistration>
  <DefaultLanguage>en-US</DefaultLanguage>
  <IsCommitAuthorAvatarVisible>true</IsCommitAuthorAvatarVisible>
</Configuration>
و در ادامه باید در این فولدر، به کاربر IIS دسترسی خواندن و نوشتن داد:

حالا آدرس مربوط به سرور وب آن را در مرورگر وارد می‌کنیم و با کاربر admin و کلمه‌ی عبور admin وارد سیستم می‌شویم.

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

البته نصب گیت برای ویندوز برای صدور فرمان انتقال به گیت الزامی است که می‌توانید از این آدرس آن‌را دانلود و نصب کنید.

پس از آن در 2 مرحله مخرن ساب ورژن را به گیت انتقال می‌دهیم:

1- استخراج آن در یک مخزن لوکال

2- افزودن به سرور گیت (که راه اندازی شده)

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

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


پس از اتمام کار با توجه به مقاله‌ی «مراحل ارسال یک پروژه‌ی Visual Studio به GitHub» برای کار با گیت در ویژوال استودیو، می‌توان به کار با گیت بصورت ریموت ادامه دهید.

و اما نکته‌ی آخر: من برای استفاده از این سرور مجبور بودم که نام localhost را با نام mehdi-pc جابجا کنم تا بتوانم از طریق یک کامپیوتر دیگر با سورس کنترل کار کنم و طی جستجوهایی که در اینترنت کردم، این کار بصورت کامند و فرمان‌های شبه لینوکسی انجام پذیر بود. ولی راهی را همچون این مقاله «مشکل در جابجایی پروژه‌های svn» پیدا کردم که بنظرم آن‌را مرتبط با موضوع می‌دانم و گفتن آن را خالی از لطف نمی‌بینم.

فایل config در واقع فایل کانفیگ داخل مخزن لوکال است؛ یعنی داخل فولدر .git و بصورت متنی ذخیره شده است:

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

[remote "origin"]
url = http://mehdi-pc:8551/NewsService.git
fetch = +refs/heads/*:refs/remotes/origin/*

البته باید بسیار با دقت این تغییر را ایجاد کنید و مطمئن باشید که آدرس را بطور صحیح و به یک مخزن درست گیت تغییر می‌دهید.

اشتراک‌ها
CShell یک IDE سورس باز سی شارپ
CShell is an interactive C# scripting environment. It allows you to use C# without any fluff right in a console like environment called a read-eval-print-loop (REPL). 
CShell یک IDE سورس باز سی شارپ
نظرات مطالب
روش کار با فایل‌های پویای ارائه شده‌ی توسط یک برنامه‌ی ASP.NET Core در برنامه‌های React
 مدتی هست که دنبال روشی هستم تا بتوان فایل PDF را بصورت پویا دریافت کرده و در browser توسط یک برنامه ASP.NET Core نمایش داد. مثل استفاده از
Response.AddHeader("content-disposition", "inline;filename=sample.pdf");
ولی چیزی که من میخواهم عدم امکان save کردن فایل توسط کاربر هست. یعنی قابلیتهای paging و search وجود داشته باشند ولی print و save نه.
برای این کار کامپوننتهای آماده ای توسط Telerik و Syncfusion ارائه شده اند ولی من به دنبال راه حلهای غیر تجاری هستم. آیا چیزی وجود دارد در این زمینه؟
مطالب
بررسی الگوی Command در جاوا اسکریپت
الگوی command، اجازه‌ی کپسوله سازی درخواست‌ها و عملیات را در شیء‌های جداگانه‌ای میدهد. این الگو، شیء‌هایی که درخواست‌ها را ارسال می‌کنند، از شیء‌هایی که مسئول اجرا کردن درخواست‌ها هستند، جدا می‌کند.
یک مثال را در نظر بگیرید؛ جائیکه یک کلاینت قرار است، دسترسی به متد‌های یک API را به صورت مستقیم داشته باشد. چه اتفاقی خواهد افتاد اگر پیاده سازی آن API‌ها تغییر کند؟ هر جائیکه API، در حال استفاده شدن است، باید تغییرات صورت گیرد. برای اجتناب از این کار، ما از abstraction بهره خواهیم برد و سپس شیء‌های درخواست کننده را از پیاده سازی درخواست‌ها، جدا می‌کنیم .


دیاگرام بالا، ماهیت این الگو را نمایش میدهد:

  • Invoker: از Command می‌خواهد که درخواست را اجرا کند. 
  • Command: اطلاعاتی را در رابطه با action، به همراه دارد و هم چنین bind کردن آن به receiver؛ همراه با فراخوانی کردن عملیات مربوطه بر روی command. 
  • Reciever: می‌داند که چگونه عملیات مرتبط با command مورد نظر را انجام دهد.
  •  Client: یک command  را ایجاد می‌کند و receiver را مشخص می‌کند؛ چه کسی قرار است این command را دریافت کند. 

اجازه بدهید یک مثال واقعی، بر اساس دیاگرام بالا جهت درک بهتر داشته باشیم: 

مثال: 
 
class Command {
  execute() {};
}

//TurnOnPrinter command
class TurnOnPrinter extends Command {
    
    constructor(printingMachine) {
        super();
        this.printingMachine = printingMachine;
        this.commandName = "turn on" 
    }
    
    execute() {
        this.printingMachine.turnOn();
    }
}

//TurnOffPrinter command
class TurnOffPrinter extends Command {

  constructor(printingMachine) {
    super();
    this.printingMachine = printingMachine;
    this.commandName = "turn off" 
  }
  
  execute() {
    this.printingMachine.turnOff();
  }
  
}

//Print command
class Print extends Command {

  constructor(printingMachine) {
    super();
    this.printingMachine = printingMachine;
    this.commandName = "print" 
  }
  
  execute() {
    this.printingMachine.print();
  }
  
}

//Invoker
class PrinterControlPanel {
    pressButton(command) {
        console.log(`Pressing ${command.commandName} button`);
        command.execute();
    }
}

//Reciever: 
class PrintingMachine {

  turnOn() {
    console.log('Printing machine has been turned on');
  }
  
  turnOff() {
    console.log('Printing machine has been turned off');
  }

  print(){
      console.log('The printer is printing your document')
  }
}


const printingMachine = new PrintingMachine();
const turnOnCommand = new TurnOnPrinter(printingMachine);
const turnOffCommand = new TurnOffPrinter(printingMachine);
const printCommand = new Print(printingMachine)
const controlPanel = new PrinterControlPanel();
controlPanel.pressButton(turnOnCommand);
controlPanel.pressButton(turnOffCommand);
controlPanel.pressButton(printCommand);

در مثال بالا، یک کلاس به نام PrintingMachine داریم: 
class PrintingMachine {

  turnOn() {
    console.log('Printing machine has been turned on');
  }
  
  turnOff() {
    console.log('Printing machine has been turned off');
  }

  print(){
      console.log('The printer is printing your document')
  }
}

در اینجا میتوانیم یکی از عملیات زیر را با استفاده از printingMachine انجام دهیم:

  • turnOn: روشن کردن ماشین (printer) 
  • turnOff: خاموش کردن ماشین (printer) 
  • print: چاپ کردن صفحه با استفاده از ماشین (printer) 

هر زمانکه ماشین چاپ (printing machine)، یک command را برای هر یک از این عملیات دریافت می‌کند، آن را اجرا می‌کند. اکنون می‌توانیم متوجه شویم که 3 نوع command که یک کاربر می‌تواند به printer ارسال کند، وجود دارند: 

class TurnOnPrinter extends Command {/*code*/}

class TurnOffPrinter extends Command {/*code*/}

class Print extends Command {/*code*/}

هر 3 کلاس بالا، یک abstract  کلاس به نام Command را extend می‌کنند:
class Command {
  execute() {};
}

کلاس‌های فرزند‌، تابع execute را ارث بری می‌کنند و در نتیجه، آن را تعریف می‌کنند. اجازه دهید که در ادامه، نگاهی به هر کدام از command‌ها داشته باشیم. 
class TurnOnPrinter extends Command {
    
    constructor(printingMachine) {
        super();
        this.printingMachine = printingMachine;
        this.commandName = "turn on" 
    }
    
    execute() {
        this.printingMachine.turnOn();
    }
}

در اینجا سازنده‌ی کلاس،  printingMachine را به عنوان پارامتر دریافت می‌کند و همچنین متغیر commandName را مقدار دهی اولیه می‌کند که در اینجا به "turn on" تنظیم شده‌است.
سپس تابع execute را تعریف می‌کند که کار روشن کردن ماشین را وقتی که فراخوانی شود، انجام خواهد داد. 

command‌های TurnOffPrinter و Print، تعاریفی مشابه به TurnOnPrinter  دارند که در بالا توضیح داده شد.  برای TurnOffPrinter ، command متغیر commandName  به مقدار "turn off" و برای Print ، command  به مقدار print تنظیم شده‌است. 
 
class TurnOffPrinter extends Command {
   //code...
   this.commandName = "turn off" 
   //code..
}

class Print extends Command {
   //code...
   this.commandName = "print" 
   //code..
}

به طور مشابه آنها تابع execute را تعریف می‌کنند که عملیات خاموش کردن ماشین، وقتی که TurnOffPrinter ، command  اجرا شود، انجام میشود و عملیات چاپ زمانیکه 
Print ، command اجرا شود، انجام میشود.
class TurnOffPrinter extends Command {
   //code...
   execute() {
     this.printingMachine.turnOff();
   }
}

class Print extends Command {
   //code...
   execute() {
     this.printingMachine.print();
   }
}

چگونه این command‌ها فراخوانی می‌شوند؟

invoker، صفحه کنترل (control panel) برای printer است که دکمه‌های turn on، turn off و print  را دارد و کاربر یک دکمه را برای ارسال یک command فشار خواهد داد.
class PrinterControlPanel {
    pressButton(command) {
        console.log(`Pressing ${command.commandName} button`);
        command.execute();
    }
}

 نگاهی به مثال زیر داشته باشید: 
controlPanel.pressButton(turnOnCommand);

در اینجا کاربر دکمه را برای روشن کردن printer فشار میدهد. بعد از فشردن دکمه، تابع execute برای این command اجرا خواهد شد و در ادامه شما پیام زیر را خواهید دید: 
Printing machine has been turned on


چه زمانی از الگوی command استفاده کنیم:

  1. اگر می‌خواهید یک صف درست کنید و درخواست‌ها را در زمان‌های متفاوتی اجرا کنید. 
  2. اگر می‌خواهید عملیاتی از قبیل reset و undo را انجام بدهید. 
  3. اگر می‌خواهید تاریخچه‌ای از درخواست‌های ایجاد شده را داشته باشید. 

 
نظرات مطالب
Entity Framework و آینده
EF 5 به بعد بر مبنای دات نت 4 و نیم است.
ویندوز 8 دات نت 4 و نیم سر خود است.
از دیدگاه تیم BCL، دات نت 4 و نیم یک به روز رسانی درجای دات نت 4 است و صد در صد با آن سازگاری دارد.
دات نت 4 و نیم فقط بر روی ویندوزهای ویستا سرویس پک 2 به بعد قابل نصب است (روی XP یا ویندوز سرور 2003 نصب نمی‌شود).

نظرات مطالب
چرا در سازمان‌ها برنامه‌های وب جایگزین برنامه‌های دسکتاپ شده‌اند (یا می‌شوند)؟
سلام مهندس . جالب بود و در اکثر کشور ها با توجه به افزایش سرعت اینترنت به این سمت گرایش داشتند . در آلمان در ایستگاه قطار یا آژانس هواپیمایی و ... به همین شکل هست و یا حداقل از یک وب سرویس بهره میبرند حتی اگر برنامه ویندوز داشته باشند . در آمریکا هم تا اونجا که میدونم silverlight و wpf به این منظور ( جهت همسان سازی محیط اینترنت و ویندوز ) استفادش رو به رشد هست . راستی آقای نصیری شما رو silverlight مانور نمیدید . یه مدتی هست که از Jquery چیزی نمیگید . منتظر مطالب جدیدتون هستم . موفق باشید .