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


ایجاد فرم لاگین

فرم لاگینی را که به برنامه‌ی نمایش لیست فیلم‌های تکمیل شده‌ی تا قسمت 17، اضافه خواهیم کرد، یک فرم بوت استرپی است و می‌توانید جزئیات بیشتر مزین سازی المان‌های این نوع فرم‌ها را با کلاس‌های بوت استرپ، در مطلب «کار با شیوه‌نامه‌های فرم‌ها در بوت استرپ 4» مطالعه کنید.
در ابتدا فایل جدید src\components\loginForm.jsx را ایجاد کرده و سپس توسط میان‌برهای imrc و cc در VSCode، ساختار ابتدایی کامپوننت جدید LoginForm را ایجاد می‌کنیم:
import React, { Component } from "react";


class LoginForm extends Component {
  render() {
    return <h1>Login</h1>;
  }
}

export default LoginForm;
در ادامه یک Route جدید را در فایل app.js برای این فرم، با مسیر login/ و کامپوننت LoginForm، در ابتدای Switch موجود، تعریف می‌کنیم:
import LoginForm from "./components/loginForm";
//...

function App() {
  return (
    <React.Fragment>
      <NavBar />
      <main className="container">
        <Switch>
          <Route path="/login" component={LoginForm} />
          <Route path="/movies/:id" component={MovieForm} />
          // ...
        </Switch>
      </main>
    </React.Fragment>
  );
}
پس از تعریف این مسیریابی، نیاز است لینک آن‌را نیز به منوی راهبری سایت اضافه کنیم. به همین جهت در فایل navBar.jsx که آن‌را در قسمت قبل تکمیل کردیم، در انتهای لیست موجود و پس از Rentals، لینک لاگین را نیز قرار می‌دهیم:
<NavLink className="nav-item nav-link" to="/login">
   Login
</NavLink>
که در نهایت حاصل این تغییرات، به صورت زیر در مرورگر ظاهر می‌شود:


اکنون نوبت به افزودن فرم بوت استرپی لاگین به فایل loginForm.jsx رسیده‌است:
import React, { Component } from "react";


class LoginForm extends Component {
  render() {
    return (
      <form>
        <div className="form-group">
          <label htmlFor="username">Username</label>
          <input id="username" type="text" className="form-control" />
        </div>
        <div className="form-group">
          <label htmlFor="password">Password</label>
          <input id="password" type="password" className="form-control" />
        </div>
        <button className="btn btn-primary">Login</button>
      </form>
    );
  }
}

export default LoginForm;
توضیحات:
- ابتدا المان form به صفحه اضافه می‌شود.
- سپس هر ورودی، داخل یک div با کلاس form-group، محصور می‌شود. کار آن تبدیل یک برچسب و فیلد ورودی، به یک گروه از ورودی‌های بوت استرپ است.
- در اینجا هر برچسب دارای یک ویژگی for است. اما چون قرار است عبارات jsx، به معادل‌های جاوا اسکریپتی ترجمه شوند، نمی‌توان از واژه‌ی کلیدی for در اینجا استفاده کرد. به همین جهت از معادل react ای آن که htmlFor است، در کدهای فوق استفاده کرده‌ایم؛ شبیه به نکته‌ای که در مورد تبدیل ویژگی class به className وجود دارد. مقدار هر ویژگی htmlFor نیز به id فیلد ورودی متناظر با آن تنظیم می‌شود. به این ترتیب اگر کاربر بر روی این برچسب کلیک کرده و آن‌را انتخاب کند، فیلد متناظر با آن، دارای focus می‌شود.
- فیلدهای ورودی نیز دارای کلاس form-control هستند.

با این خروجی نهایی در مرورگر:



مدیریت ارسال فرم‌ها

به صورت پیش فرض و استاندارد، دکمه‌ی افزوده شده‌ی به المان form، سبب ارسال اطلاعات آن به سرور و سپس بارگذاری کامل صفحه می‌شود. این رفتاری نیست که در یک برنامه‌ی SPA مدنظر باشد. برای مدیریت این حالت، می‌توان از رخ‌داد onSubmit هر المان فرم، استفاده کرد:
class LoginForm extends Component {
  handleSubmit = e => {
    console.log("handleSubmit", e);
    e.preventDefault();

    // call the server
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
      //...
در اینجا یک متد رویدادگردان را برای رخ‌داد onSubmit تعریف کرده‌ایم که توسط آن رخ‌داد جاری، دریافت و متد preventDefault آن فراخوانی می‌شود تا دیگر پس از کلیک بر روی دکمه‌ی submit، حالت پیش‌فرض و استاندارد full page reload و post back به سمت سرور، رخ ندهد.


دسترسی مستقیم به المان‌های فرم‌ها

پس از فراخوانی متد preventDefault، کار مدیریت ارسال فرم به سرور را باید خودمان مدیریت کنیم و دیگر رخ‌داد full post back استاندارد به سمت سرور را نخواهیم داشت. در جاوا اسکریپت خالص برای دریافت مقادیر وارد شده‌ی توسط کاربر می‌توان نوشت:
const username = document.getElementById("username").value;
اما در React و کدهای یک کامپوننت، نباید ارجاع مستقیمی را به شیء document و DOM اصلی مرورگر داشته باشیم. در برنامه‌های React هیچگاه نباید با شیء document کار کرد؛ چون کل فلسفه‌ی آن ایجاد یک abstraction بر فراز DOM اصلی مرورگر است که به آن DOM مجازی گفته می‌شود. به این ترتیب مدیریت برنامه و همچنین آزمون نویسی برای آن نیز ساده‌تر می‌شود. اما اگر واقعا نیاز به دسترسی به یک المان DOM در React وجود داشت، چه باید کرد؟
برای دسترسی به یک المان DOM در React، باید یک reference را به آن نسبت داد. برای این منظور یک خاصیت جدید را در سطح کلاس کامپوننت، ایجاد کرده و آن‌را با React.RefObject، مقدار دهی اولیه می‌کنیم:
class LoginForm extends Component {
  username = React.createRef();
سپس ویژگی ref المان مدنظر را به این RefObject تنظیم می‌کنیم:
<input
  ref={this.username}
  id="username"
  type="text"
  className="form-control"
/>
اکنون زمان submit فرم، اگر نیاز به مقدار username وجود داشت، می‌توان توسط خاصیت ارجاعی username تعریف شده، به خاصیت current آن که DOM element مدنظر را بازگشت می‌دهد، دسترسی یافت و مانند مثال زیر، مقدار آن‌را مورد استفاده قرار داد:
  handleSubmit = e => {
    e.preventDefault();

    // call the server
    const username = this.username.current.value;
    console.log("handleSubmit", username);
  };

البته در حالت کلی باید استفاده‌ی از RefObjectها را به حداقل رساند (راه حل بهتری برای دریافت ورودی‌ها وجود دارد) و جاهائی از آن‌ها استفاده کرد که واقعا راه حل دیگری وجود ندارد؛ مانند تنظیم focus بر روی یک المان DOM. در این حالت حتما باید ارجاعی را از آن المان DOM در دسترس داشت و یا برای پویانمایی (animation) نیز مجبور به استفاده‌ی از RefObjectها هستیم.
برای نمونه روش تنظیم focus بر روی یک فیلد ورودی توسط RefObjectها به صورت زیر است:
class LoginForm extends Component {
  username = React.createRef();

  componentDidMount = () => {
    this.username.current.focus();
  };
در life-cycle hook ای به نام componentDidMount که پس از رندر کامپوننت در DOM فراخوانی می‌شود، می‌‌توان توسط RefObject تعریف شده، به شیء current که معادل DOM Element متناظر است، دسترسی یافت و سپس متد focus آن‌را فراخوانی کرد. در این حالت در اولین بار نمایش فرم، یک چنین تصویری حاصل می‌شود:


البته روش بهتری نیز برای انجام اینکار وجود دارد. المان‌های JSX دارای ویژگی autoFocus نیز هستند که دقیقا همین کار را انجام می‌دهد:
<input
  autoFocus
  ref={this.username}
  id="username"
  type="text"
  className="form-control"
/>
برای آزمایش آن، قطعه کد componentDidMount را کامنت کرده و برنامه را اجرا کنید.


تبدیل المان‌های فرم‌ها به Controlled elements

در بسیاری از اوقات، فرم‌های ما state خود را از سرور دریافت می‌کنند. فرض کنید که در حال ایجاد یک فرم ثبت اطلاعات فیلم‌ها هستیم. در این حالت باید بر اساس id فیلم، اطلاعات آن را از سرور دریافت و در state ذخیره کرد؛ سپس فیلدهای فرم را بر اساس آن مقدار دهی اولیه کرد. برای نمونه در فرم لاگین می‌توان state را با شیء account، به صورت زیر مقدار دهی اولیه کرد:
class LoginForm extends Component {
  state = {
    account: { username: "", password: "" }
  };
تا اینجا فیلدهای فرم لاگین، از این state مطلع نبوده و تغییرات داده‌های ورودی در آن‌ها، به شیء account منعکس نمی‌شوند. علت اصلی هم اینجا است که هر کدام از فیلدهای ورودی در React، دارای state خاص خود بوده و مستقل از state کامپوننت جاری هستند. برای رفع این مشکل باید آن‌ها را تبدیل به controlled element هایی کرد که دارای state خاص خود نبوده، تمام اطلاعات مورد نیاز خود را از طریق props دریافت می‌کنند و تغییرات در داده‌های خود را از طریق صدور رخ‌دادهایی اطلاع رسانی می‌کنند. برای اینکار باید مراحل زیر طی شوند:
ابتدا ویژگی value فیلد برای مثال username را به خاصیت username شیء account موجود در state متصل می‌کنیم:
<input 
  value={this.state.account.username}
به این ترتیب دیگر این المان، state خاص خود را نداشته و از طریق props، مقادیر خود را دریافت می‌کند. تا اینجا username، به رشته‌ی خالی دریافتی از شیء state و خاصیت account آن، به صورت یک طرفه متصل شده‌است. یعنی زمانیکه فرم نمایش داده می‌شود، دارای یک مقدار خالی است. برای اینکه تغییرات رخ‌داده‌ی در این المان را به state منعکس کرد، باید رخ‌داد change آن‌را مدیریت نمود. به این ترتیب زمانیکه کاربری اطلاعاتی را در اینجا وارد می‌کند، رخ‌داد change صادر شده و پس از آن می‌توان اطلاعات وارد شده را دریافت و state را به روز رسانی کرد. به روز رسانی state نیز سبب رندر مجدد فرم می‌شود. بنابراین فیلدهای ورودی، با اطلاعات state جدید، به روز رسانی و رندر می‌شوند. به همین جهت ابتدا رویداد onChange را به فیلد username اضافه کرده:
<input 
  value={this.state.account.username}
  onChange={this.handleChange}
و متد مدیریت کننده‌ی آن‌را به صورت زیر تعریف می‌کنیم:
  handleChange = e => {
    const account = { ...this.state.account }; //cloning an object
    account.username = e.currentTarget.value;
    this.setState({ account });
  };
در اینجا، هدف به روز رسانی this.state.account، بر اساس رخ‌داد رسیده (پارامتر e) است و چون نمی‌توان state را مستقیما به روز رسانی کرد، ابتدا یک clone از آن را تهیه می‌کنیم. سپس توسط e.currentTarget به المان در حال به روز رسانی دسترسی یافته و مقدار آن‌را به مقدار خاصیت username انتساب می‌دهیم. در آخر state را بر اساس این تغییرات، به روز رسانی می‌کنیم. این انعکاس در state را توسط افزونه‌ی react developer tools هم می‌توان مشاهده کرد:



مدیریت دریافت اطلاعات چندین فیلد ورودی

تا اینجا موفق شدیم اطلاعات state را به تغییرات فیلد username در فرم لاگین متصل کنیم؛ اما فیلد password را چگونه باید مدیریت کرد؟ برای اینکه تمام این مراحل را مجددا تکرار نکنیم، می‌توان از مقدار دهی پویای خواص در جاوا اسکریپت که توسط [] انجام می‌شود استفاده کرد:
  handleChange = e => {
    const account = { ...this.state.account }; //cloning an object
    account[e.currentTarget.name] = e.currentTarget.value;
    this.setState({ account });
  };
البته برای اینکه این قطعه کد کار کند، نیاز است ویژگی name فیلدهای ورودی را نیز تنظیم کرد تا e.currentTarget.name، به نام یکی از خواص شیء account تعریف شده‌ی در state اشاره کند. برای نمونه فیلد کلمه‌ی عبور، ابتدا دارای ویژگی value متصل به خاصیت password شیء account موجود در state می‌شود. سپس تغییرات آن توسط رویداد onChange، به متد handleChange منتقل شده و خاصیت name آن نیز مقدار دهی شده‌است تا مقدار دهی پویای خواص، در این متد میسر شود:
<input
  id="password"
  name="password"
  value={this.state.account.password}
  onChange={this.handleChange}
  type="password"
  className="form-control"
/>
که در نهایت سبب مقدار دهی صحیح state، با هر دو فیلد تغییر یافته می‌شود:


یک نکته: می‌توان توسط Object Destructuring، تکرار e.currentTarget را حذف کرد:
  handleChange = ({ currentTarget: input }) => {
    const account = { ...this.state.account }; //cloning an object
    account[input.name] = input.value;
    this.setState({ account });
  };
ما از شیء e دریافتی، تنها به خاصیت currentTarget آن نیاز داریم. بنابراین آن‌را از طریق Object Destructuring در همان پارامتر ورودی متد جاری دریافت کرده و سپس آن‌را به نام input، تغییر نام می‌دهیم.


آشنایی با خطاهای متداول دریافتی در حین کار با فرم‌ها

فرض کنید خاصیت username را از شیء account موجود در state حذف کرده‌ایم. در زمان نمایش ابتدایی فرم، خطایی را دریافت نخواهیم کرد، اما اگر اطلاعاتی را در آن وارد کنیم، بلافاصله در کنسول توسعه دهندگان مرورگر چنین اخطاری ظاهر می‌شود:
Warning: A component is changing an uncontrolled input of type text to be controlled.
Input elements should not switch from uncontrolled to controlled (or vice versa).
Decide between using a controlled or uncontrolled input element for the lifetime of the component.
More info: https://fb.me/react-controlled-components
چون خاصیت username را حذف کرده‌ایم، اینبار که در textbox مقداری را وارد می‌کنیم، سبب انتساب undefined و یا null به مقدار المان خواهد شد. در این حالت React چنین المانی را به صورت controlled element درنظر نمی‌گیرد و دارای state خاص خودش خواهد بود. به همین جهت عنوان می‌کند که بین یک المان کنترل شده و نشده، یکی را انتخاب کنید.
دقیقا چنین اخطاری را با ورود null/undefined بجای "" در حین مقدار دهی اولیه‌ی username در شیء account نیز دریافت خواهیم کرد:
Warning: `value` prop on `input` should not be null.
Consider using an empty string to clear the component or `undefined` for uncontrolled components.
بنابراین به عنوان یک قاعده در فرم‌های React، المان‌های یک فرم را باید توسط یک "" مقدار دهی اولیه کرد و یا با مقداری که از سمت سرور دریافت می‌شود.


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

هر چند در پیاده سازی فعلی سعی کردیم با بکارگیری مقداردهی پویای خواص اشیاء، تکرار کدها را کاهش دهیم، اما باز هم به ازای هر فیلد ورودی باید این مسایل تکرار شوند:
- ایجاد یک div با کلاس‌های بوت استرپی.
- ایجاد label و همچنین فیلد ورودی.
- در اینجا مقدار htmlFor باید با مقدار id فیلد ورودی یکی باشد.
- مقدار دهی ویژگی‌های value و onChange نیز باید تکرار شوند.

بنابراین بهتر است این تعاریف را استخراج و به یک کامپوننت با قابلیت استفاده‌ی مجدد منتقل کرد. به همین جهت فایل جدید src\components\common\input.jsx را در پوشه‌ی common ایجاد کرده و سپس توسط میانبرهای imrc و sfc، این کامپوننت تابعی بدون حالت را تکمیل می‌کنیم:
import React from "react";

const Input = ({ name, label, value, onChange }) => {
  return (
    <div className="form-group">
      <label htmlFor={name}>{label}</label>
      <input
        value={value}
        onChange={onChange}
        id={name}
        name={name}
        type="text"
        className="form-control"
      />
    </div>
  );
};

export default Input;
در اینجا کل تگ div مرتبط با username را از کامپوننت فرم لاگین cut کرده و در اینجا در قسمت return، قرار داده‌ایم. سپس شروع به تبدیل مقادیر قبلی به مقادیری که قرار است از props تامین شوند، کرده‌ایم. یا می‌توان props را به عنوان آرگومان این متد تعریف کرد و یا می‌توان توسط Object Destructuring، خواصی را که از props نیاز داریم، در پارامتر متد Input ذکر کنیم که این روش چون به نوعی اینترفیس کامپوننت را نیز مشخص می‌کند و همچنین کدهای تکراری دسترسی به props را به حداقل می‌رساند، تمیزتر و با قابلیت نگهداری بالاتری است. برای مثال هر جائیکه نام username استفاده شده بود، با خاصیت name جایگزین شده و بجای برچسب از label، بجای مقدار username از متغیر value و بجای رخ‌داد تعریف شده نیز onChange قرار گرفته‌است.

سپس به کامپوننت فرم لاگین بازگشته و ابتدا آن‌را import می‌کنیم:
import Input from "./common/input";
اکنون متد رندر ماژول src\components\loginForm.jsx، به صورت زیر با درج دو Input، خلاصه می‌شود که دیگر در آن خبری از تگ‌ها و کدهای تکراری نیست:
  render() {
    const { account } = this.state;
    return (
      <form onSubmit={this.handleSubmit}>
        <Input
          name="username"
          label="Username"
          value={account.username}
          onChange={this.handleChange}
        />
        <Input
          name="password"
          label="Password"
          value={account.password}
          onChange={this.handleChange}
        />
        <button className="btn btn-primary">Login</button>
      </form>
    );


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید:  sample-18.zip
نظرات مطالب
اجرای Stored Procedure با چند نوع مقدار برگشتی توسط EF CodeFirst
منظور من روش مشابه parameterAttribute‌ها در mapping  کردن ورودی‌های پروسیجرها در linq  می‌باشد.
نه اینکه صرفا از دستورات sql بصورت command استفاده شود.

مانند استفاده از پروسیجرها با چند ورودی و multiResult بودن آن در linq
  
مطالب
رمزنگاری کانکشن استرینگ در ASP.Net

ذخیره کردن رشته اتصالی به دیتابیس، به صورت یک رشته مشخص در کدهای برنامه، کاری است مزموم. زیرا پس از هر بار تغییر این مورد، نیاز خواهد بود تا تمامی سورس‌ها تغییر کنند و اگر از حالت web application استفاده کرده باشید، مجبور خواهید شد یکبار دیگر برنامه را کامپایل و دایرکتوری bin روی سرور را به روز کنید. به همین جهت، استاندارد برنامه‌های ASP.Net این است که این رشته اتصالی را در فایل web.config ذخیره کنیم تا با هر بار تغییر پارامترهای مختلف آن (مثلا تغییر نام سرور، یا تعویض ماهیانه پسوردها)، مجبور به کامپایل مجدد برنامه نشویم. شبیه به همین مورد در برنامه‌های PHP هم رایج است و عموما این مشخصات در فایل config.php و یا با اسامی شبیه به این صورت می‌گیرد.
در ASP.Net 1.x قسمت خاصی برای کانکشن استرینگ وجود نداشت اما از ASP.Net 2 به بعد ، قسمت ویژه‌ای مخصوص این کار در فایل web.config در نظر گرفته شده است.
خیلی هم خوب! اما این تجربه تلخ کاری را (که یکبار برای من رخ داد) هم همواره در نظر داشته باشید:
امکان خوانده شدن محتوای فایل کانفیگ، توسط همسایه شما در همان هاست اشتراکی که الان از آن دارید استفاده می‌کنید. عموما هاست‌های اینترنتی اشتراکی هستند و نه dedicated و نه فقط مختص به شما. از یک سرور برای سرویس دهی به 100 ها سایت استفاده می‌شود. یکبار در یکی از سایت‌ها دیدم که فایل machine.config سرور را هم محض نمونه خوانده بودند چه برسد به فایل متنی کانفیگ شما! یا تصور کنید که وب سرور هک شود. عموما اس کیوال سرور بر روی سرور دیگری قرار دارد. به همین جهت رمزنگاری این رشته باز هم ضریب امنیت بیشتری را به همراه خواهد داشت.
به همین منظور رمزنگاری قسمت کانکشن استرینگ فایل وب کانفیگ الزامی است، چون آن‌هایی که به دنبال اطلاعاتی اینگونه هستند دقیقا می‌دانند باید به کجا مراجعه کنند.

راه حل‌ها:

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

ب)استفاده از روش استاندارد رمزنگاری قسمت‌های مختلف کانکشن استرینگ فایل web.config
برای مشاهده نحوه انجام اینکار با برنامه نویسی به این مقاله مراجعه نمائید.
مزیت: نیازی به کد نویسی برای رمزگشایی و استفاده از آن نیست و اینکار به صورت خودکار توسط ASP.Net انجام می‌شود.
ایراد:فایل حاصل قابل انتقال نیست. چون رمزنگاری بر اساس کلیدهای منحصربفرد سرور شما ایجاد می‌شوند، این فایل از یک سرور به سرور دیگر قابل انتقال و استفاده نخواهد بود. یعنی اگر بر روی کامپیوتر برنامه نویسی شما این‌کار صورت گرفت، برنامه در سرور کار نخواهد کرد. البته شاید ایراد آنچنانی نباشد و فقط باید یکبار دیگر روی هاست نیز این کار را تکرار کرد. اما باید درنظر داشت که همسایه محترم شما نیز می‌تواند بر روی همان هاست به سادگی فایل شما را رمزگشایی کند! بنابراین نباید اصلا به این روش در هاست‌های اشتراکی دل خوش کرد.

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

د)اگر سرور dedicated است حتما از روش windows authentication استفاده کنید
برای مثال یک سرور dedicated مخصوص کار ویژه‌ای تهیه کرده اید یا در شبکه اینترانت یک شرکت برنامه شما نصب شده است.
روش اعتبار سنجی از نوع ویندوزی برای اتصال به اس کیوال سرور نسبت به حالت sql server authentication امن تر است، زیرا نیازی نیست تا در وب کانفیگ نام کاربری یا پسوردی را مشخص نمائید و همچنین در این حالت پسوردها در شبکه منتقل نمی‌شوند (در حالت sql server authentication اینطور نیست). اما عموما در هاست‌های اشتراکی برای ساده تر کردن کار ، از این روش استفاده نمی‌کنند.
بنابراین در اینجا حتی اگر شخصی به رشته اتصالی شما دسترسی پیدا کند، کار خاصی را نمی‌تواند انجام دهد چون هیچگونه نام کاربری یا پسوردی در آن لحاظ نشده است.
در این روش به صورت پیش فرض از اکانت ASP.Net استفاده می‌شود. یعنی تمام برنامه‌ها محدود به یک اکانت خواهند شد.
برای تغییر این مورد دو کار را می‌توان انجام داد : استفاده از impersonation یا مطالعه قسمت بعد (ه)
توصیه: از روش impersonation به دلیل اینکه باید نام کاربری و کلمه عبور را باز هم به صورت واضحی ذکر نمود اجتناب کنید.

ه)ایجاد application pool مجزا به ازای هر برنامه ASP.Net در ویندوزهای سرور
Application pool که برای اولین بار در ویندوز سرور 2003 معرفی شده جهت ایزوله کردن برنامه‌های ASP.Net بکار برده می‌شود. به این صورت می‌شود برای هر pool یک اکانت ویندوزی مجزا تعریف کرد. حال می‌توان به این اکانت در اس کیوال سرور دسترسی داد. به این صورت برنامه‌های مختلف تحت یک اکانت واحد (یوزر asp.net) کار نکرده (می‌توانند هم کار کنند، اما امکان تعریف identity جدید برای کاربر آن در IIS‌ وجود دارد) و ضریب امنیتی بالاتری را تجربه خواهید کرد (در تکمیل روش (د))


نظرات مطالب
بررسی معادل‌های LINQ to Objects در TypeScript
jQuery خودش به صورت توکار بسیاری از قابلیت‌های LINQ را دارد. برای مثال معادل Where در آن grep.$ است و یا معادل Select، متد map.$ آن است. برای مثال کد #C زیر:
var maleNames = people
.Where(p => p.Sex == "M")
.Select(p => p.Name)
به صورت زیر توسط jQuery ترجمه می‌شود:
var maleNames = $.grep(people, function (p) { return p.Sex == 'M'; })
            .map(function (p) { return p.Name; });
نظرات مطالب
EF Code First #1
من هم با مشکل شما مواجه شدم و پس از بررسی‌های زیاد مشکل رو در کانکشن پیدا کردم. کد زیر کانکشنی هست که من بصورت لوکال استفاده می‌کنم (حالت SQL Server Authentication). البته به یک Instance از SQL Server بر روی کامپیوتر خودم متصل می‌شم.
<connectionStrings>
<add name="X"
  connectionString="Data Source=Y;Initial Catalog=DataBaseName;User ID=sa; Password=1234;"
  providerName="System.Data.SqlClient" />
  </connectionStrings>
X نامی هست که از طریق سازنده کلاس Context در لایه  DataAccess مشخص کردم.
  public Context():base("X")
        {
            
        }
Y هم نام Instance ای هست که بصورت لوکال وصل می‌شوم .
نظرات مطالب
EF Code First #10
- شما می‌تونید با استفاده از fluent api کنترل کاملی بر روی نام‌های خودکار تولیدی داشته باشید. یک سری پیش فرض در ابتدای امر هست؛ اما تمام این‌ها با fluent api قابل بازنویسی است.
- اینکه چه نامی در بانک اطلاعاتی تولید شده در EF Code first اهمیتی ندارد. شما با اشیاء سروکار دارید. قرار نیست مستقیما از فیلدی کوئری بگیرید یا قرار نیست مستقیما SQL خام بنویسید. زمانیکه از LINQ استفاده می‌کنید تمام ترجمه‌ها خودکار است صرفنظر از اینکه نام‌ها در سمت دیتابیس الان چه چیزی هست.
- تمام navigation property‌‌ها به جداول مورد نظر مراجعه می‌کنند. lazy loading به معنای عدم بارگذاری اطلاعات اشیاء مرتبط در بار اول فراخوانی شیء پایه است و تنها بارگذاری اطلاعات اشیاء وابسته در زمان نیاز. دقیقا در زمانیکه خاصیتی از آن شیء مرتبط فراخوانی شود و نه قبل از آن.
- زمانیکه primary key یک جدول رو دارید بهتر است از متد Find استفاده کنید بجای کوئری LINQ فوق. به این ترتیب از سطح اول کش برخوردار خواهید شد (تعداد کمتر رفت و برگشت به بانک اطلاعاتی).
- شما بدون مشکل می‌تونید مستقیما از خواص اشیاء مرتبط استفاده کنید و اگر می‌خواهید lazy loading را متوقف کنید (خصوصا برای نمایش اطلاعات در یک گرید) فقط کافی است از متد Include یاد شده استفاده کنید.

مطالب
استفاده از Google Analytics API در دات نت فریم ورک

بالاخره گوگل کار تهیه API مخصوص ابزار Analytics خود را به پایان رساند و اکنون برنامه نویس‌ها می‌توانند همانند سایر سرویس‌های گوگل از این ابزار گزارشگیری نمایند.
خلاصه کاربردی این API ، دو صفحه تعاریف پروتکل (+) و ریز مواردی (+) است که می‌توان گزارشگیری نمود.
هنوز کتابخانه google-gdata جهت استفاده از این API به روز رسانی نشده است؛ بنابراین در این مقاله سعی خواهیم کرد نحوه کار با این API را از صفر بازنویسی کنیم.
مطابق صفحه تعاریف پروتکل، سه روش اعتبارسنجی جهت دریافت اطلاعات API معرفی شده است که در اینجا از روش ClientLogin که مرسوم‌تر است استفاده خواهیم کرد.
مطابق مثالی که در آن صفحه قرار دارد، اطلاعاتی شبیه به اطلاعات زیر را باید ارسال و دریافت کنیم:

POST /accounts/ClientLogin HTTP/1.1
User-Agent: curl/7.15.1 (i486-pc-linux-gnu) libcurl/7.15.1
OpenSSL/0.9.8a zlib/1.2.3 libidn/0.5.18
Host: www.google.com
Accept: */*
Content-Length: 103
Content-Type: application/x-www-form-urlencoded
accountType=GOOGLE&Email=userName@google.com&Passwd=myPasswrd&source=curl-tester-1.0&service=analytics

HTTP/1.1 200 OK
Content-Type: text/plain
Cache-control: no-cache
Pragma: no-cache
Date: Mon, 02 Jun 2008 22:08:51 GMT
Content-Length: 497
SID=DQ...
LSID=DQAA...
Auth=DQAAAG8...
در دات نت فریم ورک، این‌کار را به صورت زیر می‌توان انجام داد:
        string getSecurityToken()
{
if (string.IsNullOrEmpty(Email))
throw new NullReferenceException("Email is required!");

if (string.IsNullOrEmpty(Password))
throw new NullReferenceException("Password is required!");

WebRequest request = WebRequest.Create("https://www.google.com/accounts/ClientLogin");
request.Method = "POST";

string postData = "accountType=GOOGLE&Email=" + Email + "&Passwd=" + Password + "&service=analytics&source=vahid-testapp-1.0";
byte[] byteArray = Encoding.ASCII.GetBytes(postData);

request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;

using (Stream dataSt = request.GetRequestStream())
{
dataSt.Write(byteArray, 0, byteArray.Length);
}

string auth = string.Empty;
using (WebResponse response = request.GetResponse())
{
using (Stream dataStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(dataStream))
{
string responseFromServer = reader.ReadToEnd().Trim();
string[] tokens = responseFromServer.Split('\n');
foreach (string token in tokens)
{
if (token.StartsWith("SID="))
continue;

if (token.StartsWith("LSID="))
continue;

if (token.StartsWith("Auth="))
{
auth = token.Substring(5);
}
else
{
throw new AuthenticationException("Error authenticating Google user " + Email);
}
}
}
}
}

return auth;

}

همانطور که ملاحظه می‌کنید به آدرس https://www.google.com/accounts/ClientLogin ، اطلاعات postData با متد POST ارسال شده (دقیقا مطابق توضیحات گوگل) و سپس از پاسخ دریافتی، مقدار نشانه Auth را جدا نموده و در ادامه عملیات استفاده خواهیم کرد. وجود این نشانه در پاسخ دریافتی به معنای موفقیت آمیز بودن اعتبار سنجی ما است و مقدار آن در طول کل عملیات باید نگهداری شده و مورد استفاده مجدد قرار گیرد.
سپس مطابق ادامه توضیحات API گوگل باید لیست پروفایل‌هایی را که ایجاد کرده‌ایم پیدا نمائیم:

string getAvailableProfiles(string authToken)
{
return fetchPage("https://www.google.com/analytics/feeds/accounts/default", authToken);
}

متد fetchPage را از پیوست این مقاله می‌توانید دریافت نمائید. خروجی یک فایل xml است که با انواع و اقسام روش‌های موجود قابل آنالیز است، از کتابخانه‌های XML دات نت گرفته تا Linq to xml و یا روش serialization که من روش آخر را ترجیح می‌دهم.
مرحله بعد، ساخت URL زیر و دریافت مجدد اطلاعات مربوطه است:
            string url = string.Format("https://www.google.com/analytics/feeds/data?ids={0}&metrics=ga:pageviews&start-date={1}&end-date={2}", id, from, to);
return fetchPage(url, auth);
و سپس آنالیز اطلاعات xml دریافتی، جهت استخراج تعداد بار مشاهده صفحات یا pageviews استفاده شده در این مثال. لیست کامل مواردی که قابل گزارشگیری است، در صفحه Dimensions & Metrics Reference گوگل ذکر شده است.

فایل‌های کلاس‌های مورد استفاده را از اینجا دریافت نمائید.‌

مثالی در مورد نحوه استفاده از آن:
            CGoogleAnalytics cga = new CGoogleAnalytics
{
Email = "username@gmail.com",
Password = "password",
From = DateTime.Now.Subtract(TimeSpan.FromDays(1)),
To = DateTime.Now.Subtract(TimeSpan.FromDays(1))
};
List<CGoogleAnalytics.SitePagePreviews> pagePreviews =
cga.GetTotalNumberOfPageViews();

foreach (var list in pagePreviews)
{
//string site = list.Site;
//int pw = list.PagePreviews;
}

نظرات مطالب
مروری بر تاریخچه محدودیت حافظه مصرفی برنامه‌های ASP.NET در IIS
نه. این خوب نیست؛ چون کش اس کیوال سرور execution plan‌های زیادی داخل هست و خیلی مسایل دیگر (یعنی این مصرف صحیح حافظه هست نه نشتی حافظه).
در کل می‌شود برای اس کیوال سرور محدودیت حافظه گذاشت؛ در موردش قبلا مطلب نوشتم در سایت هست : (+)
ضمنا یک سری دستور برای خالی کردن این کش‌ها هم هست: (+) ؛ ولی باز هم توصیه نمی‌شود چون این‌ها نشتی حافظه نیست.
مطالب
راهنمای مدیریت دیتابیس‌های SharePoint

مایکروسافت اخیرا کتابچه‌ای را منتشر کرده است که در آن نحوه‌ی نگهداری و بهبود کارآیی دیتابیس‌های اس کیوال سرور 2008 مخصوص شیرپوینت 2007 را توضیح داده است. حتی اگر سر و کار شما با شیرپوینت نیست اما با دیتابیس‌های حجیم و غول پیکر اس کیوال سرور 2008 سر و کار دارید، خواندن نکات این مجموعه توصیه می‌شود.

دریافت این راهنما با فرمت pdf
دریافت این راهنما با فرمت docx