مطالب
React 16x - قسمت 21 - کار با فرم‌ها - بخش 4 - چند تمرین
پس از فراگیری اصول کار کردن با فرم‌ها در React، اکنون می‌خواهیم چند فرم جدید را برای تمرین بیشتر، به برنامه‌ی نمایش لیست فیلم‌ها اضافه کنیم؛ مانند فرم ثبت نام، فرمی برای ثبت و یا ویرایش فیلم‌ها و یک فرم جستجوی سریع در لیست فیلم‌های موجود.

تمرین 1 - ایجاد فرم ثبت نام


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

برای حل این تمرین، فایل جدید registerForm.jsx را در پوشه‌ی components ایجاد می‌کنیم و سپس توسط میانبرهای imrc و cc در VSCode، ساختار ابتدایی کامپوننت RegisterForm را ایجاد کرده و سپس آن‌را به صورت زیر تکمیل می‌کنیم:
- ابتدا در فایل app.js، پس از import ماژول آن:
import RegisterForm from "./components/registerForm";
در ابتدای سوئیچ تعریف شده، مسیریابی آن‌را تعریف می‌کنیم:
<Route path="/register" component={RegisterForm} />
- سپس در فایل src\components\navBar.jsx، لینک به آن‌را، در انتهای لیست اضافه می‌کنیم، تا در منوی راهبری ظاهر شود:
<NavLink className="nav-item nav-link" to="/register">
   Register
</NavLink>
- در ادامه کدهای کامل کامپوننت ثبت نام را ملاحظه می‌کنید:
import Joi from "@hapi/joi";
import React from "react";

import Form from "./common/form";

class RegisterForm extends Form {
  state = {
    data: { username: "", password: "", name: "" },
    errors: {}
  };

  schema = {
    username: Joi.string()
      .required()
      .email({ minDomainSegments: 2, tlds: { allow: ["com", "net"] } })
      .label("Username"),
    password: Joi.string()
      .required()
      .min(5)
      .label("Password"),
    name: Joi.string()
      .required()
      .label("Name")
  };

  doSubmit = () => {
    // Call the server
    console.log("Submitted");
  };

  render() {
    return (
      <div>
        <h1>Register</h1>
        <form onSubmit={this.handleSubmit}>
          {this.renderInput("username", "Username")}
          {this.renderInput("password", "Password", "password")}
          {this.renderInput("name", "Name")}
          {this.renderButton("Register")}
        </form>
      </div>
    );
  }
}

export default RegisterForm;
- ابتدا این کامپوننت را بجای ارث بری از Component خود React، از کامپوننت Form که در قسمت قبل ایجاد کردیم، ارث بری می‌کنیم تا به تمام امکانات آن مانند اعتبارسنجی، مدیریت حالت و متدهای کمکی تعریف فیلدها و دکمه‌ها بهره‌مند شویم.
- سپس state این کامپوننت را با شیءای حاوی دو خاصیت data و error، مقدار دهی اولیه می‌کنیم. خواص متناظر با المان‌های فرم را نیز به صورت یک شیء، به خاصیت data انتساب داده‌ایم.
- پس از آن، خاصیت schema تعریف شده‌است؛ تا قواعد اعتبارسنجی تک تک فیلدهای فرم را به کمک کتابخانه‌ی Joi، مطابق نیازمندی‌هایی که در ابتدای تعریف این تمرین مشخص کردیم، ایجاد کند.
- در ادامه، متد doSubmit را ملاحظه می‌کنید. این متد پس از کلیک بر روی دکمه‌ی Register و پس از اعتبارسنجی موفقیت آمیز فرم، به صورت خودکار فراخوانی می‌شود.
- در آخر، تعریف فرم ثبت‌نام را مشاهده می‌کنید که نکات آن‌را در قسمت قبل، با معرفی کامپوننت Form و افزودن متدهای کمکی رندر input و button به آن، بررسی کردیم و در کل با نکات بررسی شده‌ی در فرم لاگینی که تا به اینجا ایجاد کردیم، تفاوتی ندارد.


تمرین 2- ایجاد فرم ثبت و یا ویرایش یک فیلم


فرم جدید ثبت و ویرایش یک فیلم، نکات بیشتری را به همراه دارد. در اینجا می‌خواهیم در بالای لیست نمایش فیلم‌ها، یک دکمه‌ی new movie را اضافه کنیم تا با کلیک بر روی آن، به فرم ثبت و ویرایش فیلم‌ها هدایت شویم. این فرم، از فیلدهای یک عنوان متنی، انتخاب ژانر از یک drop down list، تعداد موجود (بین 1 و 100) و امتیاز (بین صفر تا 10) تشکیل شده‌است. همچنین تا زمانیکه اعتبارسنجی فرم تکمیل نشده‌است، دکمه‌ی submit فرم باید غیرفعال باقی بماند. پس از ذخیره شدن این فیلم (در لیست درون حافظه‌ای برنامه)، با مراجعه‌ی به لیست فیلم‌ها و انتخاب آن از لیست (با کلیک بر روی لینک آن)، باید مجددا به همین فرم، در حالت ویرایش این رکورد هدایت شویم. به علاوه اگر در بالای صفحه یک id اشتباه وارد شد، باید صفحه‌ی «پیدا نشد» نمایش داده شود.

کامپوننت MovieForm و مسیریابی آن‌را در قسمت 17، تعریف و اضافه کردیم. برای تعریف لینکی به آن، به کامپوننت movies مراجعه کرده و بالای متنی که تعداد کل آیتم‌های موجود در بانک اطلاعاتی را نمایش می‌دهد، المان زیر را اضافه می‌کنیم:
import { Link } from "react-router-dom";
// ...


<div className="col">
  <Link
    to="/movies/new"
    className="btn btn-primary"
    style={{ marginBottom: 20 }}
  >
    New Movie
  </Link>
  <p>Showing {totalCount} movies in the database.</p>
این Link را هم با کلاس btn مزین کرده‌ایم تا شبیه به یک دکمه، به نظر برسد. با کلیک بر روی آن، به آدرس movies/new هدایت خواهیم شد؛ یعنی id جدید این مسیریابی را به "new" تنظیم کرده‌ایم که در ادامه بر اساس آن، تفاوت بین حالت ویرایش و حالت ثبت اطلاعات، مشخص می‌شود.


سپس به کامپوننت src\components\movieForm.jsx که پیشتر آن‌را اضافه کرده بودیم، مراجعه کرده و به صورت زیر آن‌را تکمیل می‌کنیم:
import Joi from "@hapi/joi";
import React from "react";

import { getGenres } from "../services/fakeGenreService";
import { getMovie, saveMovie } from "../services/fakeMovieService";
import Form from "./common/form";

class MovieForm extends Form {
  state = {
    data: {
      title: "",
      genreId: "",
      numberInStock: "",
      dailyRentalRate: ""
    },
    genres: [],
    errors: {}
  };
- ابتدا importهای مورد نیاز به Joi، React و همچنین سرویس‌های لیست فیلم‌ها و لیست ژانرهای سینمایی، به همراه کامپوننت فرم، تعریف شده‌اند.
- سپس این کامپوننت نیز از کامپوننت Form ارث بری می‌کند تا به امکانات ویژه‌ی آن دسترسی پیدا کند.
- در ادامه در خاصیت state، طبق روالی که در کامپوننت فرم درنظر گرفته‌ایم، دو خاصیت data و errors باید حضور داشته باشند. در خاصیت data، شیءای که نام خاصیت‌های آن با فیلدهای فرم تطابق دارد، ذکر شده‌اند. در اینجا برای ذخیره سازی اطلاعات انتخاب شده‌ی از drop down list مرتبط با ژانرهای سینمایی، از خاصیت genreId استفاده می‌شود؛ این تنها اطلاعاتی است که از کل آیتم‌های یک drop down list نیاز داریم. آرایه‌ی genres که آیتم‌های این drop down list را مقدار دهی می‌کند، در روال componentDidMount، از سرویس مرتبطی دریافت و مقدار دهی خواهد شد.

در ادامه‌ی کدهای کامپوننت MovieForm، کدهای schema اعتبارسنجی شیء data را ملاحظه می‌کنید:
  schema = {
    _id: Joi.string(),
    title: Joi.string()
      .required()
      .label("Title"),
    genreId: Joi.string()
      .required()
      .label("Genre"),
    numberInStock: Joi.number()
      .required()
      .min(0)
      .max(100)
      .label("Number in Stock"),
    dailyRentalRate: Joi.number()
      .required()
      .min(0)
      .max(10)
      .label("Daily Rental Rate")
  };
در اینجا، id به required تنظیم نشده‌است؛ چون زمانیکه قرار است یک شیء movie جدید را  ایجاد کنیم، هنوز این id نامشخص است. سایر موارد خاصیت schema، به لطف fluent api کتابخانه‌ی Joi، بسیار خوانا بوده و نیاز به توضیحات خاصی ندارند. برای مثال هر دو خاصیت numberInStock و  dailyRentalRate باید عددی وارد شده و بین بازه‌ی مشخصی قرار گیرند.

اکنون به مرحله‌ی componentDidMount می‌رسیم:
  componentDidMount() {
    const genres = getGenres();
    this.setState({ genres });

    const movieId = this.props.match.params.id;
    if (movieId === "new") return;

    const movie = getMovie(movieId);
    if (!movie) return this.props.history.replace("/not-found");

    this.setState({ data: this.mapToViewModel(movie) });
  }
- در اینجا لیست ژانرهای سینمایی از متد getGenres فایل src\services\fakeGenreService.js دریافت شده و پس از آن کار به روز رسانی خاصیت genres در state را انجام می‌دهیم. این به روز رسانی state، سبب می‌شود تا این خاصیت که آرایه‌ای است، در رندر بعدی این کامپوننت، به لیست options مربوط به drop down list درج شده‌ی در فرم، ارسال شده و در فرم رندر شود.
- پس از آن، نحوه‌ی دریافت پارامتر id مسیریابی رسیده را ملاحظه می‌کنید. این id اگر به "new" تنظیم شده بود، یعنی قرار است، اطلاعات جدیدی ثبت شوند. بنابراین متد جاری را خاتمه می‌دهیم (چون کار ادامه‌ی این متد، مقدار دهی اولیه‌ی تمام فیلدهای فرم، بر اساس اطلاعات شیء دریافت شد‌ه‌ی از سرویس فیلم‌ها است). در غیراینصورت (و با مشخص بودن id)، با استفاده از این id و متد getMovie سرویس src\services\fakeMovieService.js، سعی خواهیم کرد تا اطلاعات شیء movie متناظری را دریافت کنیم. اگر خروجی این متد null بود، یعنی id وارد شده معتبر نیست. به همین جهت کاربر را به صفحه‌ی not-found هدایت می‌کنیم. اگر دقت کنید در اینجا بجای متد push، از متد replace استفاده کرده‌ایم. چون اگر از متد push استفاده می‌کردیم و کاربر بر روی دکمه‌ی back مرورگر کلیک می‌کرد، دوباره به همین صفحه، با id غیرمعتبر قبلی وارد می‌شد و یک حلقه‌ی بی‌پایان رخ می‌داد. همچنین به return ای هم که به همراه متد replace استفاده شده، دقت کنید. کار redirect به یک صفحه‌ی دیگر، به معنای عدم اجرای کدهای پس از آن نیست. بنابراین اگر می‌خواهیم کار این متد با redirect، به پایان برسد، ذکر return الزامی است.
- در پایان این متد، خاصیت data موجود در state را به روز رسانی می‌کنیم؛ تا سبب رندر فرم، با اطلاعات شیء movie یافت شده گردد و چون ساختار شیء movie دریافت شده‌ی از سرویس، با ساختار data تعریف شده‌ی در state یکی نیست، نیاز به نگاشت این دو به هم، توسط متد سفارشی mapToViewModel زیر است:
  mapToViewModel(movie) {
    return {
      _id: movie._id,
      title: movie.title,
      genreId: movie.genre._id,
      numberInStock: movie.numberInStock,
      dailyRentalRate: movie.dailyRentalRate
    };
  }
این سناریو بسیار متداول است و اکثر داده‌های دریافت شده‌ی از سرور، الزاما با ساختار داده‌هایی که در فرم‌های خود تعریف می‌کنیم (که در اینجا view-model نام گرفته)، یکی نیستند و نیاز به نگاشت بین آن‌ها وجود دارد. برای مثال genreId موجود در view-model این فرم (همان شیء منتسب به data در state)، دقیقا به همین نام، در شیء movie تعریف نشده‌است و نیاز به نگاشت این دو به هم است.

در ادامه‌ی کدهای کامپوننت فرم فیلم‌ها، به متد doSubmit می‌رسیم:
  doSubmit = () => {
    saveMovie(this.state.data);

    this.props.history.push("/movies");
  };
این متد پس از کلیک کاربر بر روی دکمه‌ی submit و اعتبارسنجی کامل فرم، فراخوانی می‌شود. در این مرحله می‌توان اطلاعات موجود در شیء data را به متد saveMovie سرویس src\services\fakeMovieService.js ارسال کرد، تا آن‌را به لیست خودش اضافه کند. سپس کاربر را به لیست به روز شده‌ی فیلم‌ها هدایت می‌کنیم.

در انتهای این کامپوننت نیز به متد رندر آن می‌رسیم:
  render() {
    return (
      <div>
        <h1>Movie Form</h1>
        <form onSubmit={this.handleSubmit}>
          {this.renderInput("title", "Title")}
          {this.renderSelect("genreId", "Genre", this.state.genres)}
          {this.renderInput("numberInStock", "Number in Stock", "number")}
          {this.renderInput("dailyRentalRate", "Rate")}
          {this.renderButton("Save")}
        </form>
      </div>
    );
  }
تمام قسمت‌های این فرم را منهای متد جدید renderSelect آن، پیشتر در قسمت قبل، مرور کرده‌ایم و نکته‌ی جدیدی ندارند.
برای تعریف متد جدید renderSelect به این صورت عمل می‌کنیم:
- ابتدا فایل جدید src\components\common\select.jsx را ایجاد کرده و سپس آن‌را جهت نمایش یک drop down list، ویرایش می‌کنیم:
import React from "react";

const Select = ({ name, label, options, error, ...rest }) => {
  return (
    <div className="form-group">
      <label htmlFor={name}>{label}</label>
      <select name={name} id={name} {...rest} className="form-control">
        <option value="" />
        {options.map(option => (
          <option key={option._id} value={option._id}>
            {option.name}
          </option>
        ))}
      </select>
      {error && <div className="alert alert-danger">{error}</div>}
    </div>
  );
};

export default Select;
شبیه به یک چنین کامپوننتی را در قسمت قبل، در فایل src\components\common\input.jsx ایجاد کردیم و ساختار کلی آن‌ها با هم یکی است. ابتدا تمام تگ‌ها و کلاس‌های بوت استرپی مورد نیاز، در این کامپوننت محصور می‌شوند. سپس آرایه‌ای بر روی لیست options رسیده، ایجاد شده و به صورت پویا، لیست نمایش داده شده‌ی توسط drop down آن‌را تشکیل می‌دهد. در پایان آن هم کار نمایش اخطار اعتبارسنجی متناظری، در صورت وجود خطایی، قرار گرفته‌است.

- پس از آن به کامپوننت src\components\common\form.jsx مراجعه کرده و متد رندر آن‌را اضافه می‌کنیم:
import Select from "./select";
// ...

class Form extends Component {

  // ...

  renderSelect(name, label, options) {
    const { data, errors } = this.state;

    return (
      <Select
        name={name}
        value={data[name]}
        label={label}
        options={options}
        onChange={this.handleChange}
        error={errors[name]}
      />
    );
  }
}
کار این متد، مقدار دهی ویژگی‌های مورد نیاز کامپوننت Select، بر اساس نام فیلد، یک برچسب و آیتم‌های ارسالی به آن است. مزیت وجود یک چنین متد کمکی، کم شدن کدهای تکراری Selectهای مورد نیاز و همچنین عدم فراموشی قسمتی از این اتصالات و در نهایت یک‌دست شدن کدهای کل برنامه‌است. این متد در نهایت سبب رندر یک drop down list، بر اساس اطلاعات خاصیت genres موجود در state می‌شود:



تمرین 3- جستجوی در لیست فیلم‌ها


می‌خواهیم در بالای لیست نمایش فیلم‌ها، یک search box را قرار دهیم تا توسط آن بتوان بر اساس عنوان وارد شده، در فیلم‌های موجود جستجو کرد. همچنین این جستجو قرار است کلی بوده و حتی در صورت انتخاب ژانر خاصی از منوی کنار صفحه، باید در کل اطلاعات موجود جستجو کند. به علاوه اگر کاربر ژانری را انتخاب کرد، این text box باید خالی شود.

برای اینکار ابتدا فایل جدید src\components\searchBox.jsx را ایجاد کرده و به صورت زیر آن‌را تکمیل می‌کنیم:
import React from "react";

const SearchBox = ({ value, onChange }) => {
  return (
    <input
      type="text"
      name="query"
      className="form-control my-3"
      placeholder="Search..."
      value={value}
      onChange={e => onChange(e.currentTarget.value)}
    />
  );
};

export default SearchBox;
این SeachBox، یک controlled component است و دارای state خاص خودش نیست. تمام اطلاعات مورد نیاز خود را از طریق props دریافت کرده و خروجی خود را (اطلاعات تایپ شده‌ی در input box را) از طریق صدور رخ‌دادها، اطلاع رسانی می‌کند.

سپس به کامپوننت movies مراجعه کرده و آن‌را ذیل متن نمایش تعداد رکوردها، درج می‌کنیم:
<p>Showing {totalCount} movies in the database.</p>
<SearchBox value={searchQuery} onChange={this.handleSearch} />
که البته نیاز به import کامپوننت مربوطه، تعریف واژه‌ی جستجو شده در state و مدیریت رخ‌داد onChange را نیز دارد:
import SearchBox from "./searchBox";
//...

class Movies extends Component {
  state = {
    //...
    selectedGenre: {},
    searchQuery: ""
  };


  handleSearch = query => {
    this.setState({ searchQuery: query, selectedGenre: null, currentPage: 1 });
  };

  handleGenreSelect = genre => {
    console.log("handleGenreSelect", genre);
    this.setState({ selectedGenre: genre, searchQuery: "", currentPage: 1 });
  };
در متد handleSearch، اطلاعات وارد شده‌ی توسط کاربر دریافت شده و توسط آن سه خاصیت state به روز رسانی می‌شوند تا توسط آن‌ها در حین رندر مجدد کامپوننت، کار فیلتر صحیح اطلاعات صورت گیرد. همچنین selectedGenre نیز به حالت اول بازگشت داده می‌شود. به علاوه اگر کاربر در حین مشاهده‌ی صفحه‌ی 3 بود، نیاز است currentPage صحیحی را به او نمایش  داد.
متد handleGenreSelect را نیز اندکی تغییر داده‌ایم تا اگر گروهی انتخاب شد، مقدار searchQuery را خالی کند. اگر در اینجا searchQuery را به نال تنظیم می‌کردیم، controlled component جعبه‌ی جستجو، تبدیل به کامپوننت کنترل نشده‌ای می‌شد و در این حالت، React، اخطار تبدیل بین این دو را صادر می‌کرد.

در آخر، ابتدای متد getPageData هم جهت اعمال searchQuery، به صورت زیر تغییر می‌کند:
  getPagedData() {
    const {
      pageSize,
      currentPage,
      selectedGenre,
      movies: allMovies,
      sortColumn,
      searchQuery
    } = this.state;

    let filteredMovies = allMovies;
    if (searchQuery) {
      filteredMovies = allMovies.filter(m =>
        m.title.toLowerCase().startsWith(searchQuery.toLowerCase())
      );
    } else if (selectedGenre && selectedGenre._id) {
      filteredMovies = allMovies.filter(m => m.genre._id === selectedGenre._id);
    }
در اینجا اگر searchQuery مقداری داشته باشد، یک جستجوی غیرحساس به کوچکی و بزرگی حروف، بر روی خاصیت title اشیاء فیلم، انجام می‌شود.



کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-21.zip
مطالب
چک لیست تهیه یک هاست خوب برای تازه کاران
برای بسیاری از تازه کاران که پا به عرصه‌ی برنامه‌های تحت وب می‌گذارند، اینکه چگونه، از کجا و چطور باید هاستی را انتخاب کنند، دچار سردرگمی هستند. دیدن پلن‌های مختلف با قیمت‌های مختلف، باعث افزایش سردرگمی آن‌ها می‌شود. در این مقاله به بررسی اینکه چطور باید هاستی خریداری شود و اینکه اصلا خود برنامه‌ی نوشته شده نیازش چقدر هست، صحبت می‌کنیم.

قبل از اینکه صحبت را آغاز کنیم باید این نکته اشاره کنیم که انواع هاست چیست؟

انواع هاست
هاست‌ها بر سه نوع تقسیم می‌شوند:
  1. هاست اشتراکی
  2. سرورهای مجازی
  3. سرور اختصاصی

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

سرورهای مجازی VPS یا Virtual Private Server
این‌ها هم تقریبا مثل هاست‌های اشتراکی هستند با این تفاوت که منابع بیشتر و دسترسی بیشتری به شما داده می‌شوند؛ به طوری که احساس می‌کنید به شما یک سرور واقعی را داده‌اند و عموما تعداد سایت هایی که روی آن سرویس می‌گیرند، به مراتب کمتر از هاست اشتراکی است. اکثر وب سایت‌هایی که توانایی استفاده از هاست‌های اشتراکی را ندارند، از این نوع هاستینگ بهره می‌برند. قیمتش بالا‌تر از یک هاست اشتراکی است ولی به مراتب پایین‌تر از یک سرور اختصاصی است. پرداخت این نوع هاست عموما به دو صورت ماهیانه و یا سالانه است که احتمال زیادی دارد پرداخت سالیانه تخفیف خوبی را شامل شود. در صورت رسیدن به حد نهایت منابع همانند هاست اشتراکی با شما رفتار خواهد شد. این سرورهای مجازی در ایران عموما از مبلغ ماهیانه 20 هزار تومان به بالا آغاز می‌شوند.


سروهای اختصاصی یا Dedicate
این‌ها دیگر سروهای واقعی هستند و صاحب اول و آخرشان شمایید و دسترسی کامل به همه اجزا و منابع آن را دارید. این سرورهای عموما برای فعالیت‌های بزرگ تجاری و بازدیدهای همزمان به شدت بالا استفاده می‌شوند. قیمت، بسته به مشخصات آن متفاوت است و ممکن است یکی ماهیانه 200 هزار تومان، یکی ماهیانه 500 هزار تومان و .. آغاز شود.
نکته ای در مورد سرورهای اختصاصی و حتی گاها VPSها هست اینکه عموما پشتیبانی این‌ها توسط شما تامین می‌شود و  یا باید یک مدیر سرور با حق ماهیانه اختیار کنید یا در صورت بروز مشکل به صورت ساعتی حق حل مشکل را بدهید. بهتر هست این مورد را از قبل توسط میزبان جویا شوید.

سرورهای ابری
اگر قصد انجام عملیات رایانش برای را دارید بهتر هست که دنبال چنین سرورهایی باشید که مورد بحث این مقاله نیست و صرفا جهت تکمیل معرفی انواع هاست‌ها آمده است.


چک لیست


موقعی که شما نوع هاست خود را انتخاب می‌کنید به یک سری پلن یا پکیج‌های مختلفی می‌رسید که مشخصات مختلفی دارند و هر شرکت مبلغ و پیکربندی مختلفی را در نظر  می‌گیرد. نگاهی به چک لیست پایین و بررسی گام به گام آن  می‌تواند شما را در رسیدن به انتخاب بهتر یاری کند.


فضای دیسک و پهنای باند (ترافیک)
اولین نکاتی که همیشه توسط میزبان‌ها و خریداران مورد توجه قرار می‌گیرند، این دو مورد هست. در صورتیکه سایت شما اجازه آپلودی به کاربران نمی‌دهد، یا خودتان هم آپلود چندانی ندارید، می‌توانید فضای دیسک سخت پایین‌تری را انتخاب کنید. مثلا اگر شما تعدادی تصویر دارید و مقدار زیادی فایل متنی و ... به نظر یک گیگ کفایت می‌کند و در صورتیکه بعدها دیدید این فضا رو به اتمام است، می‌توانید به میزبان درخواست افزایش و ارتقاء آن را بدهید؛ اما برای بار اول یک گیگ به خوبی کفایت می‌کند. ولی اگر چنانچه با فایل‌های حجیم سرو کله میزنید و یا تعداد فایل‌هایی چون تصاویر، صوت و ویدیو در آن زیاد دیده می‌شود، بهتر است به فکر فضایی بیشتر و حتی گاها unlimited باشید. برای سایت‌هایی که حجم به شدت بالایی دارند و یا مثلا نیاز به راه اندازی بخش دانلود دارند، بهتر هست از یک هاستینگ به نام هاست دانلود استفاده کنند. این نوع هاست‌ها به شما اجازه میزبانی فایل‌های وب سایت‌هایی چون aspx,mvc,php را نمی‌دهند و بیشتر پهنای باند و فضای دیسک سخت آن مدنظر است. در این حالت سایت خود را روی یک هاست معمولی به اشتراک می‌گذارید و فایل‌های خود را روی هاست دانلود قرار می‌دهید و ارتباط آن‌ها را لینک می‌کنید.

در مورد پهنای باند باید تعداد کاربر و همچنین نوع اطلاعاتی که جابجا می‌شوند را مورد بررسی قرار دهید. اگر تعداد کاربران پایین است عموما این مقدار کم است و یا اگر اطلاعات متنی فقط جابجا می‌شود این مقدار کمتر هم می‌شود.

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

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

سرعت Speed و توان سرویس دهی(Uptime)
بعد از ارزیابی موارد بالا نوبت به این دو مورد می‌رسد. اینکه هاست شما به قولی چقدر دوام و ایستادگی دارد، بسیار مهم است و در صورتیکه این امر محقق نگردد، می‌تواند موجب از دست دادن و شنیدن اعتراض کاربرها باشید. uptime به معنی این است که در یک دوره‌ی زمانی چقدر وب سایت شما در دسترس بوده است؛ درست  شنیدید!  حتما پیش خودتان میگویید خوب، یک وب سایت همیشه در دسترس است. ولی واقعیت را بخواهید خیر، اینگونه نیست. اگر سرویس دهنده‌ی خوبی را انتخاب نکنید، ممکن است در روز یا هفته یا در هرمقطع زمانی، با در دسترس نبودن وب سایت روبرو شوید؛ تقریبا مشابه زمانیکه adsl شما قطع می‌شود، چند لحظه‌ای (طولانی‌تر از زمان عادی) مرورگر شما سعی کرده و می‌بیند که زورش نمی‌رسد و یک پیام عدم دسترسی را به شما نمایش می‌دهد.

به خوبی به یاد دارم که یک میزبان، هاست‌های ارزان قیمتی را ارائه می‌کرد، ولی گاها در روز دو الی سه بار پنج دقیقه‌ای سرور از دسترس خارج می‌شد و می‌گفتیم این هاست برای کسانی است که پول کافی ندارند و یا خیلی نمی‌خواهند خرج کنند و حالا پنج دقیقه‌ای هم در روز در دسترس نباشد اهمیتی ندارد. در سایت‌ها بیشتر این مورد را با اعدادی شبیه 99.9% مشخص می‌کنند و پیشنهاد می‌کنم هاستی را بخرید که این عدد را به شما نشان می‌دهد، یا حداقل دیگر 99.5% کمتر نباشد. البته تمامی هاست‌ها همین را می‌نویسند، ولی واقعیت چیز دیگری است و بهتر از از دوستان و آشنایان و جستجوی در اینترنت و انجمنها به این مورد برسید.

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

برای اینکه بدانیم که سرعت یک هاست چگونه باید ارزیابی شود باید سه مورد را بررسی کنیم :
  1. دیتاسنتر
  2. سرور
  3. نزدیکی سرور به محل زندگی کاربران هدف
دو مورد اول تا حدی فنی هستند و اصلا ممکن هست به چنین اطلاعاتی دسترسی هم نداشته باشید؛ هر چند میزبان - در صورتی که قصد خرید سروری را دارید - در صورت پرسش شما باید این اطلاعات را در اختیار شما بگذارد. عموما چیزی که پیشنهاد می‌شود دیتاسنترهای SAS70 Type 2 هستند و سرورهای DELL، امروزه خوب مورد استقبال قرار گرفته‌اند. در رده‌های بعدی میتوان HP را هم مثال زد.
مورد سوم نزدیکی سرور به کاربران هدف است. هر چقدر traceroute و پینگ زمانی کمتری به سرور داشته باشید، دسترسی به اطلاعات آن سریعتر می‌شود. در ایران عموما از کشورهایی چون آمریکا، کانادا ، انگلیس ، آلمان و استرالیا سرور خریده می‌شود و به مدت چندسالی است که در ایران هم این امکان فراهم شده است ولی خب مسائلی که این سرورها در ایران دارند باعث می‌شوند عده‌ی زیادی دور آن‌ها را که هیچ روی آن‌ها را هم خط بکشند.

مشکلاتی که این سرورها دارند بیشتر به سه مورد زیر بر میگردد:

هزینه‌ی سنگین ترافیک : این مورد آن قدر به وضوح پیداست که شما را به کل برای هر نوع خریدی پشیمان می‌کند؛ مگر اینکه پولتان از جایی تامین میشود. ادارات دولتی عموما این نوع هاست را بر میدارند و یا سایت‌های اشتراکی که منابع زیادی را مصرف نمی‌کنند و یا شرکت‌ها یا اشخاصی که پول تامین را دارند.

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

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

امنیت
این مورد شامل دو بخش می‌شود یکی امنیت دسترسی به سرور و دیگر امنیت نگهداری اطلاعات. نصب فایروال‌ها روی سرور و نظارت 24 ساعته روی سرورهای شرکت (که شامل بخش پشتیبانی می‌شود) می‌تواند این موردها را پوشش دهد. هر چند این مورد را زیاد نمی‌توانید محک بزنید، ولی اگر اخباری چون «همکاری با یک شرکت امنیتی جهت تست سرور و همکاری با تعدادی هکر جهت تست سرور» و ... را شنیدید، می‌توانید این اطمینان را کسب کنید که آن‌ها به این مورد اهمیت میدهند.

امنیت اطلاعات چون پشتیبان‌های روزانه و نگهداری اطلاعات تا مدتی معین پس از اتمام قرارداد و موارد این چنینی، می‌تواند شما را مطمئن سازد. در مورد یکی از مشتریانم به خاطر دارم که فراموش کرده بود هاست را تمدید کند و یک روز بعد از انقضاء ما درخواست دیتابیس را داشتیم که برای ما ارسال کنند و به گفته‌ی خودشان ما مسئولیتی در قبال نگه داری اطلاعات نداریم، ولی تا 5 روز نگه میداریم که البته گفتند هر چه به دنبال دیتابیس گشتند، چیزی پیدا نکردند که البته این مشکل را از راهکار دیگری حل کردیم و ماجرا به خوشی تمام شد. ولی جالب این بود که اینقدر که من حرص خوردم، چطوری به مدیر این‌ها بگوئیم که اطلاعات تیمشان پریده و این‌ها حرص نخوردند و بی خیال.

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

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

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

پشتیبانی هر نوع سرور را مطلع شوید. بعضی‌ها واقعا پشتیبانی دارند!؟ ولی وقتی زنگ می‌زنید می‌گویند این پشتیبانی مربوط به لینوکس است و بچه‌های ویندوز فقط ساعات اداری هستند. خلاصه حواستان را جمع کنید که بچه‌های آن بخش همیشه باشند.
بنابراین مطمئن شوید که یک پشتیبانی 24/7 واقعی داشته باشند.

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

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

کل مطالب گفته شده در چک لیست به طور خلاصه : اول از همه بررسی فضای ذخیره سازی و پهنای باند، بعد از آن بررسی توانایی سرویس دهی و سرعت سرورها، داشتن محیط امن و پشتیبانی مناسب بود. 

هاستینگ در قرارداد

هنگام عقد قرارداد با مشتری، در قرارداد در مورد هاستینگ که خودش تهیه می‌کند، این نکته ذکر شود که شما در مورد مسائلی که مربوط به هاست و دامنه می‌شود هیچ مسئولیتی ندارید و باید مشکلات را با مسئولان آن در میان بگذارد.
همچنین این نکته هم ذکر شود در مورد مسائلی چون عدم پشتیبانی مناسب هاست، از محصول یا سرویس شما، شما هیچگونه مسئولیتی در قبال آن ندارید و یا باید این مورد توسط شما دنبال شود یا خرید ایشان با مشاوره و تایید شما از هاست مربوطه باشد.

در صورتی که مشتری نمیتواند شخصا خرید هاستینگ را انجام دهد یا در شرکت مسئولین IT ندارند که این کار را انجام دهند و این مورد به شما محول میشود، در قرارداد ذکر شود که شما هیچ گونه مسئولیتی در قبال مشکلاتی که برای هاست و دامنه رخ میدهد ندارید و تنها میتوانید به عنوان یک واسط یا وکیل در ازای مبلغ توافق شده‌ای مشکل را با مسئولین هاست و دامنه در میان گذاشته و ماجرا را برای حل مشکل ایجاد شده دنبال کنید یا این کار را به عنوان هدیه ای از طرف خدمات طلایی شما به مشتریان به صورت رایگان انجام دهید.
نظرات اشتراک‌ها
دریافت ویدیوهای کنفرانس Build به کمک پاورشل
کافیست آدرس زیر را در Internet Explorer یا در یک RSS Reader کپی کنید
 http://channel9.msdn.com/Events/Build/2012/RSS/wmvhigh 
هم عنوان، هم توضیحات، هم Comment‌ها و هم لینک مستقیم را می‌توانید یک جا مشاهده کنید، و آنهایی را که می‌خواهید را دانلود کنید
لینک دانلود مستقیم رو هم به Download Manager دهید، تا به بهترین نحو آنرا دریافت کند.
موفق باشید
نظرات مطالب
تهیه خروجی RSS در برنامه‌های ASP.NET MVC
خیلی متشکر، کدها بسیار کار امد بود و بدون دردسر در پروژه جواب داد 
فقط این که مثلا باید ادرس http://localhost:40252/feed/rss  را وارد کرد ، حال این شکل rss  (مربع نارنجی قرمز بالا چپ ادرس بار در گوگل کروم)که در نوار ابزار نمایش داده میشود رو چه تغییراتی باید انجام بدهم تا در ادرس بار نمایش داده شود ؟
مطالب دوره‌ها
استفاده از async و await در برنامه‌های ASP.NET Web forms 4.5
سؤال: چه زمانی از متدهای async و چه زمانی از متدهای همزمان بهتر است استفاده شود؟

از متدهای همزمان متداول برای انجام امور ذیل استفاده نمائید:
- جهت پردازش اعمالی ساده و سریع
- اعمال مدنظر بیشتر قرار است بر روی CPU اجرا شوند و از مرزهای IO سیستم عبور نمی‌کنند.

و از متدهای غیرهمزمان برای پردازش موارد زیر کمک بگیرید:
- از وب سرویس‌هایی استفاده می‌کنید که متدهای نگارش async را نیز ارائه داده‌اند.
- عمل مدنظر network-bound و یا I/O-bound است بجای CPU-bound. یعنی از مرزهای IO سیستم عبور می‌کند.
- نیاز است چندین عملیات را به موازات هم اجرا کرد.
- نیاز است مکانیزمی را جهت لغو یک عملیات طولانی ارائه دهید.


مزایای استفاده از متدهای async در ASP.NET

استفاده از await در ASP.NET، ساختار ذاتی پروتکل HTTP را که اساسا یک synchronous protocol، تغییر نمی‌دهد. کلاینت، درخواستی را ارسال می‌کند و باید تا زمان آماده شدن نتیجه و بازگشت آن از طرف سرور، صبر کند. نحوه‌ی تهیه‌ی این نتیجه، خواه async باشد و یا حتی همزمان، از دید مصرف کننده کاملا مخفی است. اکنون سؤال اینجا است که چرا باید از متدهای async استفاده کرد؟
- پردازش موازی: می‌توان چند Task را مثلا توسط Task.WhenAll به صورت موازی با هم پردازش کرده و در نهایت نتیجه را سریعتر به مصرف کننده بازگشت داد. اما باید دقت داشت که این Taskها اگر I/O bound باشند، ارزش پردازش موازی را دارند و اگر compute bound باشند (اعمال محاسباتی)، صرفا یک سری ترد را ایجاد و مصرف کرده‌اید که می‌توانسته‌اند به سایر درخواست‌های رسیده پاسخ دهند.
- خالی کردن تردهای در حال انتظار: در اعمالی که disk I/O و یا network I/O دارند، پردازش موازی و اعمال async به شدت مقیاس پذیری سیستم را بالا می‌برند. به این ترتیب worker thread جاری (که تعداد آن‌ها محدود است)، سریعتر آزاد شده و به worker pool بازگشت داده می‌شود تا بتواند به یک درخواست دیگر رسیده سرویس دهد. در این حالت می‌توان با منابع کمتری، درخواست‌های بیشتری را پردازش کرد.


ایجاد Asynchronous HTTP Handlers در ASP.Net 4.5

در نگارش‌های پیش از دات نت 4.5، برای نوشتن فایل‌های ashx غیرهمزمان می‌بایستی اینترفیس IHttpAsynchHandler پیاده سازی می‌شد که نحوه‌ی کار با آن از مدل APM پیروی می‌کرد؛ نیاز به استفاده از یک سری callback داشت و این عملیات باید طی دو متد پردازش می‌شد. اما در دات نت 4.5 و با معرفی امکانات async و await، نگارش سازگاری با پیاده سازی کلاس پایه HttpTaskAsyncHandler فراهم شده است.
برای آزمایش آن، یک برنامه‌ی جدید ASP.NET Web forms نگارش 4.5 یا بالاتر را ایجاد کنید. سپس از منوی پروژه، گزینه‌ی Add new item یک Generic handler به نام LogRequestHandler.ashx را به پروژه اضافه نمائید.
زمانیکه این فایل به پروژه اضافه می‌شود، یک چنین امضایی را دارد:
 public class LogRequestHandler : IHttpHandler
IHttpHandler آن‌را اکنون به HttpTaskAsyncHandler تغییر دهید. سپس پیاده سازی ابتدایی آن به شکل زیر خواهد بود:
using System;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace Async14
{
    public class LogRequestHandler : HttpTaskAsyncHandler
    {
        public override async Task ProcessRequestAsync(HttpContext context)
        {
            string url = context.Request.QueryString["rssfeedURL"];
            if (string.IsNullOrWhiteSpace(url))
            {
                context.Response.Write("Rss feed URL is not provided");
            }

            using (var webClient = new WebClient {Encoding = Encoding.UTF8})
            {
                webClient.Headers.Add("User-Agent", "LogRequestHandler 1.0");
                var rssfeed = await webClient.DownloadStringTaskAsync(url);
                context.Response.Write(rssfeed);
            }
        }

        public override bool IsReusable
        {
            get { return true; }
        }

        public override void ProcessRequest(HttpContext context)
        {
            throw new Exception("The ProcessRequest method has no implementation.");
        }
    }
}
واژه‌ی کلیدی async را نیز جهت استفاده از await به نسخه‌ی غیرهمزمان آن اضافه کرده‌ایم.
در این مثال آدرس یک فید RSS از طریق کوئری استرینگ rssfeedURL دریافت شده و سپس محتوای آن به کمک متد DownloadStringTaskAsync دریافت و بازگشت داده می‌شود.
برای آزمایش آن، مسیر ذیل را درخواست دهید:
 http://localhost:4207/LogRequestHandler.ashx?rssfeedURL=https://www.dntips.ir/feed/latestchanges
کاربردهای فایل‌های ashx برای مثال ارائه فید‌های XML ایی یک سایت، ارائه منبع نمایش تصاویر پویا از بانک اطلاعاتی، ارائه JSON برای افزونه‌های auto complete جی‌کوئری و امثال آن است. مزیت آن‌ها سربار بسیار کم است؛ زیرا وارد چرخه‌ی طول عمر یک صفحه‌ی aspx معمولی نمی‌شوند.


صفحات async در ASP.NET 4.5

در قسمت‌های قبل مشاهده کردیم که در برنامه‌های دسکتاپ، به سادگی می‌توان امضای روال‌های رخداد گردان را به async تغییر داد و ... برنامه کار می‌کند. به علاوه از مزیت استفاده از واژه کلیدی await نیز در آن‌ها برخوردار خواهیم شد. اما ... هرچند این روش در وب فرم‌ها نیز صادق است (مثلا public void Page_Load را به  public async void Page_Load می‌توان تبدیل کرد) اما اعضای تیم ASP.NET آن‌را در مورد برنامه‌های وب فرم توصیه نمی‌کنند:
Async void event handlers تنها در مورد تعداد کمی از روال‌های رخدادگردان ASP.NET Web forms کار می‌کنند و از آن‌ها تنها برای تدارک پردازش‌های ساده می‌توان استفاده کرد. اگر کار در حال انجام اندکی پیچیدگی دارد، «باید» از PageAsyncTask استفاده نمائید. علت اینجا است که Async void یعنی fire and forget (کاری را شروع کرده و فراموشش کنید). این روش در برنامه‌های دسکتاپ کار می‌کند، زیرا این برنامه‌ها مدل طول عمر متفاوتی داشته و تا زمانیکه برنامه از طرف OS خاتمه نیابد، مشکلی نخواهند داشت. اما برنامه‌های بدون حالت وب متفاوتند. اگر عملیات async پس از خاتمه‌ی طول عمر صفحه پایان یابد، دیگر نمی‌توان اطلاعات صحیحی را به کاربر ارائه داد. بنابراین تا حد ممکن از تعاریف async void در برنامه‌های وب خودداری کنید.

تبدیل روال‌های رخدادگردان متداول وب فرم‌ها به نسخه‌ی async شامل دو مرحله است:
الف) از متد جدید RegisterAsyncTask که در کلاس پایه Page قرار دارد برای تعریف یک PageAsyncTask استفاده کنید:
using System;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web.UI;

namespace Async14
{
    public partial class _default : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
        }

        public async Task LoadSomeData()
        {
            using (var webClient = new WebClient { Encoding = Encoding.UTF8 })
            {
                webClient.Headers.Add("User-Agent", "LogRequest 1.0");
                var rssfeed = await webClient.DownloadStringTaskAsync("url");

                //listcontacts.DataSource = rssfeed;
            }
        }
    }
}
با استفاده از System.Web.UI.PageAsyncTask می‌توان یک async Task را در روال‌های رخدادگردان ASP.NET مورد استفاده قرار داد.

ب) سپس در کدهای فایل aspx، نیاز است خاصیت async را نیز true نمائید:
 <%@ Page Language="C#" AutoEventWireup="true"
Async="true"
  CodeBehind="default.aspx.cs" Inherits="Async14._default" %>


تغییر تنظیمات IIS برای بهره بردن از پردازش‌های Async

اگر از ویندوزهای 7، ویستا و یا 8 استفاده می‌کنید، IIS آن‌ها به صورت پیش فرض به 10 درخواست همزمان محدود است.
بنابراین تنظیمات ذیل مرتبط است به یک ویندوز سرور و نه یک work station :
به IIS manager مراجعه کنید. سپس برگه‌ی Application Pools آن‌را باز کرده و بر روی Application pool برنامه خود کلیک راست نمائید. در اینجا گزینه‌ی Advanced Settings را انتخاب کنید. در آن Queue Length را به مثلا عدد 5000 تغییر دهید. همچنین در دات نت 4.5 عدد 5000 برای MaxConcurrentRequestsPerCPU نیز مناسب است. به علاوه عدد connectionManagement/maxconnection را نیز به 12 برابر تعداد هسته‌های موجود تغییر دهید.
مطالب
روش‌هایی برای بهبود قابلیت دیباگ بسته‌های NuGet
عموما بسته‌های نیوگت تولید شده، قابلیت دیباگ ضعیفی را دارند. برای بالابردن بهبود تجربه‌ی کاربری آن‌ها می‌توان توزیع فایل‌های PDB و فعالسازی قابلیت Source Link را به آن‌ها اضافه کرد.


فعالسازی توزیع فایل‌های PDB به همراه بسته‌های NuGet

وجود فایل‌های PDB، برای اجرای برنامه‌ها ضرورتی ندارند؛ اما اگر ارائه شوند، به کمک آن‌ها می‌توان گزارش‌های استثناءهای بسیار کاملتری را به همراه نام فایل و شماره سطرهای مرتبط موجود در Exception.StackTrace، مشاهده کرد.
پیشتر توسعه دهندگان بسته‌های NuGet، فایل‌های PDB را خودشان با تعریف یک سری include در فایل مشخصات بسته، به فایل نهایی تولیدی اضافه می‌کردند. اما این روزها با ارائه‌ی «NuGet.org Symbol Server»، دیگر افزودن فایل‌های PDB به بسته‌های nupkg توصیه نمی‌شود. چون حجم نهایی و زمان بازیابی بسته‌ها را بیش از اندازه افزایش می‌دهند؛ خصوصا اگر مصرف کننده‌ای قصد دیباگ آن‌ها را نداشته باشد.
راه حل جدید توصیه شده، ارائه‌ی فایل‌های ویژه‌ی snupkg. در کنار بسته‌های nupkg. معمولی است که حاوی فایل‌های PDB متناظر با بسته‌ی اصلی NuGet هستند.

برای فعالسازی آن‌ها در پروژه‌های NET Core. بسته‌های نیوگت خود تنها کافی است دو تنظیم زیر را به فایل csproj اضافه کنید:
<PropertyGroup>
  <IncludeSymbols>true</IncludeSymbols>
  <SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
در این حالت پس از ساخت بسته‌ی نیوگت توسط دستور «dotnet pack -c release»، دو فایل با پسوندهای snupkg و nupkg تولید می‌شوند که باید هر دو را به سایت NuGet ارسال کرد.

در سمت مصرف کننده، IDE شما باید برای کار با این Symbol Server تنظیم شده باشد.


فعالسازی تولید Source Link

وجود PDBها جهت دیباگ بسته‌های ارائه شده بسیار مفیدند؛ اما اگر بر روی کدهای نهایی بهینه سازی صورت گرفته باشد، ممکن است اطلاعات دیباگ آن‌ها با کد اصلی تطابق پیدا نکنند. برای بهبود این وضعیت و ارتقاء آن به یک سطح بالاتر، مفهوم source link ارائه شده‌است که مستقل است از نوع زبان و همچنین سورس کنترل.
کار سورس‌لینک، افزودن متادیتای سورس کنترل انتخابی، به بسته‌ی نهایی تولید شده‌است. به این صورت می‌توان سورس کامل و متناظر با قطعه کد بسته و کتابخانه‌ی ثالث در حال دیباگ را در IDE خود داشت و با آن به نحو متداولی کار کرد. یعنی سورس لینک، قابلیت «Step Into" the source code"» را مهیا می‌کند. متادیتای اضافه شده، دقیقا مشخص می‌کند که بسته‌ی تولیدی نهایی، متناظر با کدام commit سورس کنترل است. به این ترتیب دقیقا می‌توان به کدهای همان commit ای که بسته بر اساس آن کامپایل شده‌است، در IDE خود دسترسی یافت.
این قابلیت از Visual Studio 15.3 به بعد در اختیار کاربران آن است (گزینه‌ی Enable Source Server Support، در قسمت Debug/General آن باید فعال شود). همچنین Rider و VSCode نیز از آن پشتیبانی می‌کنند. برای Rider باید در قسمت Tools/External symbols، گزینه‌های Use sources from symbol files when available و Allow downloading symbols from remote locations را فعال کنید.
همچنین برای فعالسازی آن در فایل csproj بسته‌ی نیوگت خود می‌توانید تنظیمات زیر را اضافه کنید:
<PropertyGroup>
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
البته در اینجا پروایدر مخصوص GitHub را مشاهده می‌کنید (اگر مخزن کد بسته‌ی شما بر روی آن قرار دارد) و همچنین سایر پروایدرهای مخصوص سورس کنترل‌های دیگر مانند Azure DevOps/VSTS نیز برای آن تهیه شده‌اند.


روش فعالسازی Source Link در پروژه‌ی VSCode

اگر از VSCode استفاده می‌کنید، نیاز است تنظیمات زیر را به قسمت configurations فایل launch.json خود اضافه کنید تا قابلیت «Step Into" the source code"» بسته‌های نیوگتی که از SourceLink پشتیبانی می‌کنند، با فشردن دکمه‌ی F11 در حین دیباگ، فعال شود:
"justMyCode": false,
"symbolOptions": {
   "searchMicrosoftSymbolServer": true
},
"suppressJITOptimizations": true,
"env": {
   "COMPlus_ZapDisable": "1"
}
نظرات مطالب
KnockoutJs #5
با سلام و تشکر از مطالب مفیدی که تو سایت قرار میدید
من یه پروژه case study رو چند روزی هست که شروع کردم و بدون مشکل کارم رو ادامه میدادم تااینکه به ویو ویرایش مشخصات افراد رسیدم.
سه تا از فیلدهای مربوط به افراد شامل کشور، استان و شهر میشه که تو View مربوط به افراد جدید این سه تا DropDownList با استفاده از Knockout پر میشن. بطوری که DropDownList‌های مربوط به استان و شهر خالی هستند و با انتخاب کشور، استان پر میشه و با انتخاب استان، شهر پر میشه.
مشکل اینجاست که تو View ویرایش DropDownList‌های استان و شهر در بارگذاری اولیه فرم پر نمیشن ولی با تغییر مقادیر کشور، استانها در DropDownList خودش پر میشه و این کار برای شهر هم به خوبی انجام میشه.
حالا میخام ببینم که چطور میشه این مشکل رو حل کرد