نظرات مطالب
دادن «حق فراموش شدن» به کاربران در ASP.NET Core Identity 2.1
سلام و تشکر
در مورد "قسمتی را هم در آن درنظر بگیرید که کاربر با فشردن یک کلیک، بتواند اکانت فعلی خودش را برای همیشه محو و نابود کند؛ بدون اینکه اثری از آن باقی بماند "
دو سوال داشتم.
ممکنه آی دی کاربر به صورت کلید خارجی در جداول دیگر استفاده شده باشه. در اینصورت وقتی بخواهیم اطلاعات کاربر را حذف کنیم چطور باید این مشکل فعالیت‌های کاربر که به صورت کلید خارجی در جداول دیگر داریم رو حذف نکنیم؟ مثلا در همین سایت اگر من مطالبی ثبت کرده باشم و بخواهم اکانتم رو حذف کنم باید اون مطالبی هم که قبلا در سایت ثبت کردم کاملا حذف بشه؟ اگر اینطوری باشه به نظرم یه ایرادت دیگری به وجود میاد.

همینطور در مورد "
با کلیک بر روی یک دکمه، کلیه اطلاعات شخصی خودش را دانلود و ذخیره کند."

این اطلاعات به صورت Json برای کاربر نمایش داده میشه تا دانلود کنه. خوب امکان برعکسش هم باید داشته باشیم؟ یعنی مثلا من در سایتی  اکانتم رو حذف کرده بودم ولی حالا به دلایلی میخوام اکانتم رو دوباره برگردانم [شبیه اینستاگرام] باید اون فایل Json رو دوباره روی سایت آپلود کنم تا همان اطلاعات کاربری قبلی ام را برگردان کند؟

نظرات مطالب
افزونه فارسی به پارسی برای word 2007
چند مورد رو می‌تونید بررسی کنید
- البته نیازی نیست آن 200 و خرده‌ای مگ را دریافت کنید. علت بالا بودن حجم آن این است که 32 بیتی و 64 بیتی و غیره، همه را با هم دارد. به آدرس زیر مراجعه کنید
http://msdn.microsoft.com/en-us/netframework/aa569263.aspx
روی دکمه نصب کلیک کنید تا یک برنامه 2 مگی در اختیار شما قرار دهد. این برنامه قسمت‌های مورد نیاز سیستم شما رو از سایت مایکروسافت دریافت و نصب خواهد کرد. بنابراین حجم کمتری دارد.
- آیا این افزونه به لیست add-in ها در word‌ اضافه شده؟ (شکل سوم در این صفحه)
- event viewer ویندوز را باز کنید. در قسمت run ویندوز تایپ کنید eventvwr.msc و سپس enter (و یا به قسمت administrative tools ویندوز مراجعه کنید این برنامه را مشاهده خواهید کرد). در صفحه باز شده به قسمت applications مراجعه کنید. آیا موردی با source مساوی FarsiToParsi از نوع خطا با آیکون قرمز مشاهده می‌شود؟ اگر بله، لطفا دوبار روی آن کلیک کنید و توضیحات صفحه باز شده را اینجا ارسال کنید. از روی این خطا می‌شود مشکل را بهتر بررسی کرد.

با تشکر
مطالب
Import و Export کردن Breakpointها در Visual Studio
ویژوال استدیو Breakpointها را در یک فایل XML ذخیره میکند.برای ذخیره Breakpointها فقط کافی است بر روی دکمه Export در پنجره Breakpoint که در شکل زیر نمایش داده شده است کلیک کنید.

Breakpoint_Window

شما می‌توانید فایل XML ذخیره شده را بعدا استفاده کنید و یا می‌توانید آن را به برنامه نویسان دیگر هم بدهید.
اجازه دهید نگاهی داشته باشیم بر محتویات داخل فایل XML . فایل XML کلکسیونی از تگ BreakPoints داخل BreakpointCollection است.هر تگ Breakpoint حاوی اطلاعاتی در مورد یک Breakpoint خاص است.

XML File

اگر شما هر زمانی همه Breakpointها را از کدتان حذف کردید به راحتی می‌توانید آن را تنها با کلیک بر روی Import وارد کدتان بکنید و تمام Breakpoint‌های ذخیره شده را بازآوری کنید.
نکته: Import کردن Breakpoint براساس شماره خط کد شما می‌باشد یعنی همان خطی که شما Breakpoint را گذاشته اید پس اگر شماره خط کد شما تغییر کند Breakpoint بروی خط قبلی گذاشته میشود.
 

اشتراک‌ها
کتابخانه UbaPlayer

The jQuery HTML5 Audio Player with Flash Fallback.  Demo

UbaPlayer is a simple jQuery plugin that plays audio natively in modern browsers and uses Flash where native playback is impossible. It is tested to work in the following browsers:

  • Mac (Chrome 10+, Safari 4+, Firefox 3.5+, Opera)
  • PC (Chrome 10+, Safari 4+, Firefox3.5+, Opera, IE6+)
  • iOS 3+ (Safari Mobile)
  • Android 2.2+ (Chrome, Firefox 4, Opera 11) 
کتابخانه UbaPlayer
مطالب
React 16x - قسمت 10 - ترکیب کامپوننت‌ها - بخش 4 - یک تمرین
در قسمت 6، تمرینی را جهت پیاده سازی نمایش لیست یک سری فیلم، انجام دادیم. در اینجا قصد داریم این تمرین را جهت دریافت امتیاز و Like از کاربر، به ازای هر ردیف نمایش داده شده، تکمیل کنیم.


بررسی ساختار کامپوننت Like

در پوشه‌ی components، ابتدا پوشه‌ی جدید common را ایجاد می‌کنید. در اینجا تمام کامپوننت‌های عمومی برنامه را که منحصر به دومین آن برنامه نیستند، قرار می‌دهیم. کامپوننت‌هایی را که اگر آن‌ها را به برنامه‌های دیگری نیز کپی کردیم، بدون هیچ مشکلی قابلیت استفاده‌ی مجدد را داشته باشند و متصل به سرویس‌ها و زیرساخت برنامه‌ی جاری نباشند. سپس در پوشه‌ی common، فایل جدید src\components\common\like.jsx را ایجاد می‌کنیم و داخل آن توسط میانبرهای imrc و cc در VSCode، ساختار ابتدایی کامپوننت Like را ایجاد می‌کنیم.
ساختار کلی این کامپوننت به صورت زیر است:
- ورودی این کامپوننت به این صورت است که در آن مشخص شده آیا یک فیلم، مورد علاقه واقع شده یا خیر؛ مانند خاصیت liked که یک boolean است. اگر true باشد، یک آیکن قلب توپر را نمایش می‌دهد و برعکس.
- خروجی این کامپوننت نیز به صورت یک رخ‌داد است. هر زمانیکه بر روی آیکن قلب آن کلیک می‌شود، این کامپوننت یک ر‌خ‌داد onClick را سبب خواهد شد. اکنون هر کامپوننت دیگری که در حال استفاده‌ی از آن است، مطلع شده و خاصیت liked شیء مرتبط را تغییر می‌دهد.

بنابراین این کامپوننت اطلاعی از ساختار یک شیء movie ندارد. تنها یک DOM کامپوننت ساده است که کارش نمایش یک آیکن قلب توپر یا خالی می‌باشد و اگر بر روی این آیکن قلب کلیک شد، به والد خود اطلاع رسانی می‌کند.

فعلا ساختار ابتدایی آن‌را به رندر یک قلب خالی که توسط قلم آیکن‌های font-awesome تامین می‌شود، تنظیم می‌کنیم:
import React, { Component } from "react";


class Like extends Component {
  render() {
    return <i className="fa fa-heart-o" aria-hidden="true"></i>;
  }
}

export default Like;


نمایش ابتدایی کامپوننت Like در جدول لیست فیلم‌ها

فعلا مهم نیست که این کامپوننت کار خاصی را انجام نمی‌دهد. فقط قصد داریم آن‌را در UI برنامه نمایش دهیم. به همین جهت ابتدا یک ستون جدید را مخصوص آن، در جدول فعلی نمایش لیست فیلم‌ها، ایجاد کرده و المان آن‌را درج می‌کنیم. برای این منظور به فایل movies.jsx مراجعه کرده و ابتدا این کامپوننت را import می‌کنیم:
import Like from "./common/like";

سپس در سرستون‌های جدول، یک th جدید را تعریف می‌کنیم تا ستونی برای درج آن ایجاد شود. همچنین در قسمت بدنه‌ی جدول، پیش از دکمه‌ی حذف، یک td مخصوص درج المان </Like> را اضافه می‌کنیم:


تا اینجا ستون جدید Like را مشاهده می‌کنید که کار رندر کامپوننت‌های Like در آن انجام شده‌است.


واکنش نشان دادن به ورودی‌ها، در کامپوننت Like

در ادامه باید این کامپوننت بر اساس مقدار Boolean ای که از والد خود دریافت می‌کند، یک آیکن قلب توپر و یا خالی را نمایش دهد. برای این منظور فعلا در کامپوننت movies، جائیکه المان کامپوننت Like درج شده‌است، ویژگی جدید liked را به مقدار ثابت true تنظیم می‌کنیم </Like liked={true}> تا بتوان قسمت props این کامپوننت را تکمیل کرد.
در کامپوننت Like، تفاوت بین آیکن قلب توپر و خالی در یک o- در انتهای کلاس‌های font-awesome است:
import React, { Component } from "react";

class Like extends Component {
  render() {
    let classes = "fa fa-heart";
    if (!this.props.liked) {
      classes += "-o";
    }
    return <i className={classes} aria-hidden="true"></i>;
  }
}

export default Like;
در اینجا اگر بر اساس مقدار ورودی this.props.liked، یک مقدار false را دریافت کردیم، به classes یک o- را اضافه می‌کنیم تا یک آیکن قلب خالی را رندر کند. سپس این classes را به خاصیت className انتساب داده‌ایم.
پس از این تغییرات اگر برنامه را ذخیره کرده و مجددا در مرورگر بارگذاری کنیم، با توجه به تنظیم liked={true} در کامپوننت movies، ستون like آن با آیکن‌های قلب توپر نمایش داده می‌شود که بیانگر واکنش نشان دادن صحیح به ورودی‌ها در کامپوننت Like است:



پویا سازی مقدار پیش‌فرض ویژگی liked در کامپوننت movies

برای پویاسازی نمایش مقدار liked در کامپوننت movies، از آنجائیکه هر ردیف بیانگر یک شیء movie است، می‌توان به این صورت عمل کرد:
<Like liked={movie.liked} />
البته اگر به فایل fakeMovieService.js مراجعه کنید، خاصیت liked در ساختار اشیاء فیلم‌ها وجود ندارد که فعلا آن‌را برای اولین شیء تعریف شده، اضافه می‌کنیم:
const movies = [
  {
    _id: "5b21ca3eeb7f6fbccd471815",
    title: "Terminator",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
    numberInStock: 6,
    dailyRentalRate: 2.5,
    publishDate: "2018-01-03T19:04:28.809Z",
    liked: true
  },
پس از این تغییرات، اکنون خروجی برنامه در مرورگر به صورت زیر تغییر کرده که اولین آیتم آن بر اساس مقدار تنظیم شده‌ی فوق، با آیکن قلب توپر نمایش داده شده‌است:



افزودن رخ‌داد کلیک به کامپوننت Like

برای اینکه کامپوننت Like، رویداد کلیک بر روی آیکن قلب را به والد خود گزارش دهد، ابتدا ویژگی جدید onClick را بر روی تعریف المان آن در کامپوننت movies اضافه می‌کنیم:
 <Like liked={movie.liked} onClick={() => this.handleLike(movie)} />
که به متد handleLike در همان کامپوننت متصل خواهد شد:
handleLike = movie => {
    console.log("handleLike", movie);
  };
سپس در کامپوننت Like، این ویژگی onClick را از طریق خاصیت props دریافت کرده و به رویداد onClick المان نمایش آیکن، متصل می‌کنیم:
    return (
      <i
        className={classes}
        onClick={this.props.onClick}
        aria-hidden="true"
        style={{ cursor: "pointer" }}
      ></i>
);
اینبار اگر بر روی المان نمایش آیکن کلیک شود، سبب فراخوانی متد handleLike والد متصل به آن خواهد شد.
در اینجا همچنین style این المان نیز جهت نمایش cursor با آیکن pointer، توسط یک شیء از نوع inline style تنظیم شده‌است.

یک نکته: کامپوننت Like تا اینجا یک controlled component است؛ دارای state نیست و همچنین تمام اطلاعات خودش را از طریق props تامین می‌کند و تنها دارای یک متد render است. بنابراین اگر علاقمند بودید می‌توان این کامپوننت را به یک «Stateless Functional Component» که در قسمت 8 معرفی شد نیز تبدیل کرد.


تغییر حالت کامپوننت Like جهت نمایش تغییرات

تا اینجا کامپوننت Like ما می‌تواند ورودی true/false را به آیکن‌های متناظری تبدیل کند. همچنین اگر بر روی این آیکن کلیک شود، آن‌را توسط رخ‌دادی به والد خود اطلاع رسانی می‌کند. اکنون می‌خواهیم با تکمیل متد handleLike، خاصیت like اشیاء انتخابی (آیکن‌هایی که بر روی آن‌ها کلیک شده‌اند) را از true به false و برعکس تبدیل کرده و سپس UI را نیز به روز رسانی کنیم:
  handleLike = movie => {
    console.log("handleLike", movie);
    const movies = [...this.state.movies]; // cloning an array
    const index = movies.indexOf(movie);
    movies[index] = { ...movies[index] }; // cloning an object
    movies[index].liked = !movies[index].liked;
    this.setState({ movies });
  };
با یک چنین مثالی که در آن cloning اشیاء و آرایه‌ها صورت می‌گیرد، پیشتر آشنا شده‌اید. هدف از cloning، قطع ارتباط شیء، یا آرایه‌ی ایجاد شده، از شیء، یا آرایه‌ی اصلی است تا با اعمال تغییرات بر روی شیء clone شده، تغییری در شیء اصلی صورت نگیرد؛ چون در React مجاز به تغییر مستقیم اشیاء state نیستیم.
پس از این تغییرات اگر برنامه را اجرا کنیم، با کلیک بر روی هر آیکن، عکس آن آیکن نمایش داده می‌شود؛ برای مثال آیکن قلب توپر، تبدیل به آیکن قلب توخالی خواهد شد.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-10.zip
مطالب
مروری بر کتابخانه ReactJS - قسمت ششم - اعتبارسنجی

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


اعتبارسنجی داده‌های ورودی 

برای مدیریت بهتر کامپوننت‌ها جهت استفاده مجدد از آنها بهتر است ورودی‌های کامپوننت را اعتبارسنجی کنیم. این ورودی‌ها چه برای استفاده داخلی کامپوننت، یا جهت مشخص کردن وضعیت آن، بر رفتار کامپوننت تاثیر زیادی دارند. React مجموعه‌ای از اعتبار سنجی‌ها را دارد که میشود به کامپوننت اضافه کرد. باید توجه داشته باشیم که پیام‌های خطای این اعتبارسنجی‌ها فقط در حالت Development Mode قابل استفاده هستند. به زبان ساده اگر از react.min.js استفاده کنید، پیام‌های خطا را نخواهید دید. باید فایل‌ها را به نوع react.js تبدیل کنید. اعتبارسنجی React در زمان توسعه و برای توسعه دهندگان استفاده میشود. 

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

const MenuItem = props => (
    <li className="list-group-item">
        <span className="badge">{props.price}</span>
        <p>{props.item}</p>
    </li>
)

MenuItem.propTypes = {
    price: React.PropTypes.number
};

شیء propTypes را به کامپوننت اضافه کرده‌ایم و در تنظیمات آن میتوانیم برای هر پارامتر ورودی یکی از  اعضای PropTypes از React را که مناسب حال پارامتر است، انتخاب کنیم. در مثال بالا مشخص کرده‌ایم که ورودی price باید عدد باشد و اگر مثلا رشته‌ای را بجای عدد ارسال کنیم، پیام خطای زیر را در Console خواهیم داشت. 

Warning: Failed prop type: Invalid prop `price` of type `string` supplied to `MenuItem`, expected `number`.
    in MenuItem (created by Menu)
    in Menu

یا میتوانستیم از React.PropTypes.number.isRequired استفاده کنیم تا درج مقداری برای این ورودی الزامی باشد. اگر اعتبارسنجی‌های React کافی نبودند میتوانیم اعتبارسنجی‌های سفارشی خودمان را ایجاد کنیم. در مثال زیر میخواهیم ورودی price بیشتر از 15000 نباشد.

MenuItem.propTypes = {
    price: (props, price)=>{
        if(props[price] > 15000){
            return new Error("Too expensive!");
        }
    }
};
اگر در ساخت  کامپوننت‌ها از React.creatClass یا Reac.Component استفاده کرده‌ایم، میتوانیم اعتبار سنجی را به عنوان یک عضو استاتیک در داخل کلاس معرفی کنیم. مانند مثال زیر.
let MenuItem = React.createClass({
    propTypes: {
        price: React.PropTypes.number
    }
});

class MenuItem extends React.Component{
    static propTypes = {
        price: React.PropTypes.number
    };
}

نوعهای دیگر برای اعتبارسنجی شامل موارد زیر هستند و  البته مرجع تمام اعتبارسنجی‌های React را میتوانید در اینجا بررسی کنید. 

  • React.PropTypes.array
  • React.PropTypes.bool
  • React.PropTypes.number
  • React.PropTypes.object
  • React.PropTypes.string


مقدار پیش‌فرض داده‌های ورودی

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

MenuItem.defaultProps = {
    price: 1000
};

همانطور که می‌بینید روش کار مشابه با اعتبارسنجی است و برای مشخص کردن مقدار پیش‌فرض برای React.creatClass از متد getDefaultProps که عضوی از React است، استفاده میکنیم. 

let MenuItem = React.createClass({
    getDefaultProps() {
        return { price: 200 }
    },
    render() {
        return (
            <li className="list-group-item">
                <span className="badge">{this.props.price}</span>
                <p>{this.props.item}</p>
            </li>
        );
    }
});
در قسمت بعد ورودی‌های کاربر را از UI به کامپوننت‌ها، بررسی میکنیم.
مطالب
PowerShell 7.x - قسمت دوم - آشنایی با Pipelineها
PowerShell برای نام‌گذاری Commandها، از ساختار verb-noun استفاده میکند. به عنوان مثال Get-Command, New-Service, Get-Help نمونه‌هایی از این Commandها در PowerShell هستند. لازم به ذکر است که در PowerShell، منظور از cmdlet یا Command let، همان Commandهای native در PowerShell هستند؛ نه Commandهای عمومی مانند dir, cd, ipconfig و غیره. به عنوان مثال از Get-Help برای نمایش مستندات یک cmdlet میتوان استفاده کرد و دقیقاً مشابه man page در لینوکس است.

Get-Help Get-Command
با فلگ Online میتوان مستندات cmdlet موردنظر را درون مرورگر مشاهده کرد:
Get-Help Get-Command -Online
برای بیشتر cmdletها میتوانیم فیلتر نیز اعمال کنیم. به عنوان مثال با دستور زیر میتوان لیست تمام processهای سیستم را که به واژه‌ی Process ختم میشوند، مشاهده کنیم:
Get-Command -Name '*Process'
خروجی دستور فوق، یک جدول به صورت زیر خواهد بود:
CommandType     Name                                               Version    Sour
                                                                              ce
-----------     ----                                               -------    ----
Cmdlet          Debug-Process                                      7.0.0.0    Mic…
Cmdlet          Enter-PSHostProcess                                7.2.6.500  Mic…
Cmdlet          Exit-PSHostProcess                                 7.2.6.500  Mic…
Cmdlet          Get-Process                                        7.0.0.0    Mic…
Cmdlet          Start-Process                                      7.0.0.0    Mic…
Cmdlet          Stop-Process                                       7.0.0.0    Mic…
Cmdlet          Wait-Process                                       7.0.0.0    Mic…
Application     mysqltest_safe_process                             0.0.0.0

Pipeline
توسط Pipeline میتوان خروجی یک command را به عنوان ورودی یک command دیگر ارسال کرد. در دیگر زبان‌های اسکریپتی مانند bash یا batch (در ویندوز) چیزی که به command بعدی ارسال میشود، در واقع یک text است:
ls -l | grep "\.pdf$"
در مثال فوق، خروجی برنامه ls -1 را به ورودی برنامه grep ارسال کرده‌ایم. در حالت عادی، خروجی دستورات به standard output یا به طور خلاصه stout ارسال میشوند. توسط pipe یا pipeline میتوانیم خروجی متنی را به اصطلاح redirect کنیم و به کامندهای بعدی به صورت یک زنجیره ارسال کنیم. اما در PowerShell این objectها هستند که ارسال (pipe) میشوند. به عنوان مثال میتوانیم با کمک Pipelineها، خروجی مثال قبل را محدود به نمایش ستون‌های دلخواهی کنیم. به عبارتی تنها ستون‌های Name و CommandType را در خروجی نمایش دهیم:
Get-Command -Name '*Process' | Select-Object Name,CommandType
همچنین میتوانیم خروجی را با کمک Sort-Object مرتب کنیم:
Get-Command -Name '*Process' | Select-Object Name,CommandType | Sort-Object Name -Descending
یا اینکه خروجی را محدود به نمایش ۳ آیتم کنیم:
PS /> Get-Command -Name '*Process' | Select-Object Name,CommandType -First 3 | Sort-Object Name -Descending

Name                CommandType
----                -----------
Exit-PSHostProcess       Cmdlet
Enter-PSHostProcess      Cmdlet
Debug-Process            Cmdlet
همچنین میتوانیم از Where-Object برای اعمال شرط نیز استفاده کنیم. به عنوان مثال، در ادامه لیست ۵ پروسس سیستم را که مقدار CPU بیشتر از 1.24، در اختیار دارند نمایش داده‌ایم:
PS /> Get-Process | Where-Object CPU -gt 1.24 | Sort-Object WorkingSet -Descending | Select-Object -First 5

Pipelineها چطور کار میکنند؟
در PowerShell در واقع stdinی وجود ندارد که shell از آن استفاده کند؛ در نتیجه PowerShell باید بداند خروجی cmdlet قبلی را به کدام پراپرتی از cmdlet بعدی در pipeline ارسال کند:


PowerShell از مکانیزمی تحت عنوان pipeline binding برای انجام این نگاشت استفاده میکند. دو روش برای انجام این binding وجود دارد:
  • ByValue
  • ByPropertyName 
در نظر داشته باشید که هر کدام از روش‌های فوق توسط کسی که cmdlet موردنظر را پیاده‌سازی خواهد کرد میتواند پشتیبانی شود. برای درک بهتر این مکانیزم دستور زیر را در نظر بگیرید:
Get-Process Slack | Stop-Process
قبل از هر چیزی باید بدانیم خروجی cmdlet اول یعنی Get-Process چه چیزی است. اینکار را میتوانیم توسط دستور زیر انجام دهیم:
Get-Process | Get-Member
دستور فوق یک لیست از خواص Get-Process خواهد بود و خط اول این خروجی دقیقاً تایپی است که Get-Process برمیگرداند:
TypeName: System.Diagnostics.Process
بنابراین این تایپی است که به عنوان ورودی، به Stop-Process درون pipeline ارسال میشود. در ادامه توسط دستور Get-Help Stop-Process -Full لیست پارامترهایی را که Stop-Process دریافت میکند، لیست خواهیم کرد:
PS /Users/sirwanafifi> Get-Help Stop-Process -Full

NAME
    Stop-Process

SYNTAX
    Stop-Process [-Id] <int[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>]

    Stop-Process -Name <string[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>]

    Stop-Process [-InputObject] <Process[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>]


PARAMETERS
    -Confirm

        Required?                    false
        Position?                    Named
        Accept pipeline input?       false
        Parameter set name           (All)
        Aliases                      cf
        Dynamic?                     false
        Accept wildcard characters?  false

    -Force

        Required?                    false
        Position?                    Named
        Accept pipeline input?       false
        Parameter set name           (All)
        Aliases                      None
        Dynamic?                     false
        Accept wildcard characters?  false

    -Id <int[]>

        Required?                    true
        Position?                    0
        Accept pipeline input?       true (ByPropertyName)
        Parameter set name           Id
        Aliases                      None
        Dynamic?                     false
        Accept wildcard characters?  false

    -InputObject <Process[]>

        Required?                    true
        Position?                    0
        Accept pipeline input?       true (ByValue)
        Parameter set name           InputObject
        Aliases                      None
        Dynamic?                     false
        Accept wildcard characters?  false

    -Name <string[]>

        Required?                    true
        Position?                    Named
        Accept pipeline input?       true (ByPropertyName)
        Parameter set name           Name
        Aliases                      ProcessName
        Dynamic?                     false
        Accept wildcard characters?  false

    -PassThru

        Required?                    false
        Position?                    Named
        Accept pipeline input?       false
        Parameter set name           (All)
        Aliases                      None
        Dynamic?                     false
        Accept wildcard characters?  false

    -WhatIf

        Required?                    false
        Position?                    Named
        Accept pipeline input?       false
        Parameter set name           (All)
        Aliases                      wi
        Dynamic?                     false
        Accept wildcard characters?  false

    <CommonParameters>
        This cmdlet supports the common parameters: Verbose, Debug,
        ErrorAction, ErrorVariable, WarningAction, WarningVariable,
        OutBuffer, PipelineVariable, and OutVariable. For more information, see
        about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216).


INPUTS
    System.Int32[]
    System.String[]
    System.Diagnostics.Process[]


OUTPUTS
    System.Diagnostics.Process


ALIASES
    spps


REMARKS
    Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help.
        -- To download and install Help files for the module that includes this cmdlet, use Update-Help.
        -- To view the Help topic for this cmdlet online, type: "Get-Help Stop-Process -Online" or
           go to https://go.microsoft.com/fwlink/?LinkID=2097058.
از پارامترهای فوق تنها Id, Name و InputObject هستند که خاصیت Accept pipeline inputشان به true تنظیم شده‌است. همانطور که مشاهده میکنید InputObject از نوع ByValue است و Id و Name نیز از نوع ByPropertyName هستند:
-Id <int[]>

    Required?                    true
    Position?                    0
    Accept pipeline input?       true (ByPropertyName)
    Parameter set name           Id
    Aliases                      None
    Dynamic?                     false
    Accept wildcard characters?  false

-InputObject <Process[]>

    Required?                    true
    Position?                    0
    Accept pipeline input?       true (ByValue)
    Parameter set name           InputObject
    Aliases                      None
    Dynamic?                     false
    Accept wildcard characters?  false

-Name <string[]>

    Required?                    true
    Position?                    Named
    Accept pipeline input?       true (ByPropertyName)
    Parameter set name           Name
    Aliases                      ProcessName
    Dynamic?                     false
    Accept wildcard characters?  false
نوع ورودی این پارامتر نیز یک آرایه از Processها میباشد. بنابراین در اینجا ByValue به این معنا است که اگر مقدار pipe شده از نوع Process بود، پراپرتی InputObject مقداردهی میشود. برای حالت ByPropertyName دستور زیر را در نظر بگیرید:
"Slack" | Stop-Process
با اجرای دستور فوق خطای زیر را دریافت خواهیم کرد:
Stop-Process: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
علت آن نیز مشخص است؛ چون هیچ پراپرتی از نوع ByValue که ورودی string یا آرایه‌ایی از stringها را دریافت کند برای Stop-Process وجود ندارد، بنابراین pipeline binding اتفاق نخواهد افتاد. برای درک بهتر موضوع، یک شیء تستی ایجاد خواهیم کرد که شامل یک پراپرتی Name با مقدار Slack است؛ سپس شیء جدید را به Stop-Process ارسال میکنیم:
PS /Users/sirwanafifi> $newObject = [pscustomobject]@{ Name = "Slack" }
PS /Users/sirwanafifi> $newObject | Stop-Process
با اجرای دستور فوق، پراسس موردنظر stop خواهد شد.
لازم به ذکر است که اگر یک پارامتر، هم ByValue و هم ByPropertyName باشد، PowerShell ابتدا سعی میکند ByValue را امتحان کند و اگر با شکست مواجه شد از ByPropertyName استفاده خواهد کرد.
بازخوردهای پروژه‌ها
ایراد در نمایش جزییات نمایش مطالب و TreeView Extension
زمانی که روی جزییات نمایش  مطلبی کلیک میکنیم خطای Helper مربوط به  TreeView  رو میگیره بعد از بررسی متوجه شدم کد TreeView ربطی به پروژه نداره و اصلا داخل پوشه  Helper  تعریف نشده.

خطای دریافتی بعد از زدن روی دکمه مشاهده
( به ازای کامنت هر مطلب  از TreeView  استفاده شده، خطا میدهد)


HttpCompileException: d:\IrisCms-master\Iris.Web\Views\Comment\_PostComments.cshtml(7): error CS1061: 'System.Web.Mvc.HtmlHelper<System.Collections.Generic.IEnumerable<Iris.DomainClasses.Entities.Comment>>' does not contain a definition for 'TreeView' and no extension method 'TreeView' accepting a first argument of type 'System.Web.Mvc.HtmlHelper<System.Collections.Generic.IEnumerable<Iris.DomainClasses.Entities.Comment>>' could be found (are you missing a using directive or an assembly reference?) 


کد TreeView
using System.Collections.Generic;
using System.Web.Mvc;
using Iris.Servicelayer.Interfaces;

namespace Iris.Web.Controllers
{
    public partial class TreeViewController : Controller
    {
        private readonly IPageService _pageService;

        public TreeViewController(IPageService pageService)
        {
            _pageService = pageService;
        }

        public virtual ActionResult Index()
        {
            List<TreeViewLocation> locations = GetLocations();

            return View(_pageService.GetNavBarData(x => x.Body.Equals("dsad")));
        }

        public static List<TreeViewLocation> GetLocations()
        {
            var locations = new List<TreeViewLocation>
            {
                new TreeViewLocation
                {
                    Name = "United States",
                    ChildLocations =
                    {
                        new TreeViewLocation
                        {
                            Name = "Chicago",
                            ChildLocations =
                            {
                                new TreeViewLocation {Name = "Rack 1"},
                                new TreeViewLocation {Name = "Rack 2"},
                                new TreeViewLocation {Name = "Rack 3"},
                                new TreeViewLocation {Name = "Rack 3"},
                            }
                        },
                        new TreeViewLocation
                        {
                            Name = "Dallas",
                            ChildLocations =
                            {
                                new TreeViewLocation
                                {
                                    Name = "Rack 1",
                                    ChildLocations =
                                    {
                                        new TreeViewLocation
                                        {
                                            Name = "Rack 1",
                                            ChildLocations =
                                            {
                                                new TreeViewLocation {Name = "Rack 1"},
                                                new TreeViewLocation {Name = "Rack 2"},
                                                new TreeViewLocation {Name = "Rack 3"},
                                                new TreeViewLocation {Name = "Rack 3"},
                                            }
                                        },
                                        new TreeViewLocation {Name = "Rack 2"},
                                        new TreeViewLocation {Name = "Rack 3"},
                                        new TreeViewLocation {Name = "Rack 3"},
                                    }
                                },
                                new TreeViewLocation {Name = "Rack 2"},
                                new TreeViewLocation {Name = "Rack 3"},
                                new TreeViewLocation {Name = "Rack 3"},
                            }
                        },
                        new TreeViewLocation {Name = "Dallas"},
                        new TreeViewLocation {Name = "Dallas"},
                        new TreeViewLocation {Name = "Dallas"},
                        new TreeViewLocation {Name = "Dallas"},
                        new TreeViewLocation {Name = "Dallas"},
                        new TreeViewLocation {Name = "Dallas"},
                    }
                },
                new TreeViewLocation
                {
                    Name = "Canada",
                    ChildLocations =
                    {
                        new TreeViewLocation {Name = "Ontario"},
                        new TreeViewLocation {Name = "Windsor"}
                    }
                }
            };
            return locations;
        }
    }

    public class TreeViewLocation
    {
        public TreeViewLocation()
        {
            ChildLocations = new HashSet<TreeViewLocation>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public ICollection<TreeViewLocation> ChildLocations { get; set; }
    }
}

مطالب
آموزش Prism #3
در پست‌های قبلی با Prism و روش استفاده از آن آشنا شدیم (قسمت اول) و (قسمت دوم). در این پست با استفاده از Mef قصد ایجاد یک پروژه Silverlight رو به صورت ماژولار داریم. مثال پیاده سازی شده در پست قبلی را در این پست به صورت دیگر پیاده سازی خواهیم کرد.
تفاوت‌های پیاده سازی مثال پست قبلی با این پست:
  • در مثال قبل پروژه به صورت Desktop و با WPF پیاده سازی شده بود ولی در این مثال با Silverlight می‌باشد؛
  • در مثال قبل از UnityBootstrapper استفاده شده بود ولی در این مثال از MefBootstrapper؛
  • در مثال قبل هر View در یک ماژول قرار داشت ولی در این مثال هر دو View را در یک ماژول قرار دادم؛
  • در مثال قبل از Prism Libary 2.x استفاده شده بود ولی در این مثال از PrismLibrary 4.x؛
  • و...

نکته : برای فهم بهتر مفاهیم، آشنایی اولیه با MEF و مفاهیمی نظیر Export و Import و AggregateCatalog و AssemblyCatalog نیاز است. در صورتی که با این مطالب آشنایی ندارید می‌توانید از (^) شروع کنید.


برای شروع یک پروژه Silverlight ایجاد کنید. بعد از اضافه شدن دو پروژه Silverlight و Web، یک Silverlight Class Library جدید بسازید.
ابتدا یک Page ایجاد کنید و کد‌های زیر را در آن کپی کنید.
<UserControl 
             x:Class="Module1.Module1View1"
             xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" FlowDirection="RightToLeft" FontFamily="Tahoma">
    <StackPanel>
        <sdk:DataGrid Height="100">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn Header="کد" Width="50"  />
                <sdk:DataGridTextColumn Header="عنوان" Width="200" />
                <sdk:DataGridTextColumn Header="نویسنده" Width="150"  />
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
        <Button x:Name="NextViewButton"
                Width="150"
                Height="25"
                Foreground="Red"
                Background="Blue"
                Content="لیست طبقه بندی ها" />
    </StackPanel>
</UserControl>
بر روی Page مربوطه راست کلیک کنید و گزینه ViewCode را انتخاب کنید و کد‌های زیر را در آن کپی کنید.
 [Export(typeof(Module1View1))]
    public partial class Module1View1 : UserControl
    {
        [Import]
        public IRegionManager TheRegionManager { private get; set; }

        public Module1View1()
        {
            InitializeComponent();

            NextViewButton.Click += NextViewButton_Click;
        }

        void NextViewButton_Click(object sender, RoutedEventArgs e)
        {
            TheRegionManager.RequestNavigate
            (
                "MyRegion1",
                new Uri("Module1View2", UriKind.Relative),
                a => { }
            );
        }
    }
ابتدا خود این View باید حتما Export شود. در رویداد کلیک با استفاده از متد RequestNavigate می‌توانیم به View مورد نظر برای نمایش در Shell اشاره کنیم و این View در Region نمایش داده می‌شود. به دلیل اینکه در این کلاس به RegionManager نیاز داریم از ImportAttribute استفاده کردیم. این بدین معنی است که کلاس Module1View1 وابستگی مستقیم به IRegionManager دارد.

حال یک Page دیگر برای طبقه بندی کتاب‌ها ایجاد کنید و کدهای زیر را در آن کپی کنید.
<UserControl 
             xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  x:Class="Module1.Module1View2"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" FlowDirection="RightToLeft" FontFamily="Tahoma">
    <StackPanel>
        <sdk:DataGrid Height="100">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn Header="کد" Width="150"/>
                <sdk:DataGridTextColumn Header="عنوان" Width="150"/>                
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
        <Button x:Name="NextViewButton"
                Width="150"
                Height="25"
                Foreground="Green"
                Background="Yellow"
                Content="لیست کتاب ها" />
    </StackPanel>
</UserControl>
در Code Behind این Page نیز کد‌های زیر را قرار دهید.
using Microsoft.Practices.Prism.Regions;
using System;
using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Controls;

namespace Module1
{
    [Export]
    public partial class Module1View2 : UserControl
    {
        IRegion _region1;

        [ImportingConstructor]
        public Module1View2( [Import] IRegionManager regionManager )
        {
            InitializeComponent();
         
            ViewModel viewModel = new ViewModel();
            DataContext = viewModel;

            viewModel.ShouldNavigateFromCurrentViewEvent += () => { return true; };

            _region1 = regionManager.Regions["MyRegion1"];

            NextViewButton.Click += NextViewButton_Click;
        }

        void NextViewButton_Click( object sender, RoutedEventArgs e )
        {
            _region1.RequestNavigate
            (
                new Uri( "Module1View1", UriKind.Relative ),
                a => { }
            );
        }
    }
}
در این ماژول برای اینکه بتوانیم حالت گردشی در فراخوانی ماژول‌ها را داشته باشیم ابتدا DataContext این کلاس را برابر با ViewModel ساخته شده قرار دادیم. با استفاده از رویداد ShoudlNavigateFromCurrentViewEvent که در کلاس ViewModel وجود دارد تعیین می‌کنیم که آیا باید از این View به View قبلی برگشت داشته باشیم یا نه. در صورتی که مقدار false برگشت داده شود خواهید دید که امکان فراخوانی View1 از View2 امکان پذیر نیست. در رویداد کلیک نیز همانند Page قبلی با استفاده از RegionManager و متد RequestNavigate به View مورد نظر راهبری کرده ایم.
نکته: اگر یک کلاس، سازنده با پارامتر داشته باشد باید با استفاده از ImportingConstructor حتما سازنده مورد نظر را هنگام وهله سازی مشخص کنیم در غیر این صورت با Exception مواجه خواهید شد.
حال قصد ایجاد کلاس ViewModel بالا را داریم:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using Microsoft.Practices.Prism.Regions;

namespace Module1
{
    public class ViewModel : IConfirmNavigationRequest
    {       
        public event Func<bool> ShouldNavigateFromCurrentViewEvent;      

        public bool IsNavigationTarget( NavigationContext navigationContext )
        {
            return true;
        }

        public void OnNavigatedTo( NavigationContext navigationContext )
        {

        }

        public void OnNavigatedFrom( NavigationContext navigationContext )
        {

        }         

        public void ConfirmNavigationRequest( NavigationContext navigationContext, Action<bool> continuationCallback )
        {
            bool shouldNavigateFromCurrentViewFlag = false;

            if ( ShouldNavigateFromCurrentViewEvent != null )
                shouldNavigateFromCurrentViewFlag = ShouldNavigateFromCurrentViewEvent();

            continuationCallback( shouldNavigateFromCurrentViewFlag );
        }    
    }
}
توضیح متد‌های بالا:
  • IsNavigateTarget : برای تعیین اینکه آیا کلاس پیاده سازی کننده اینترفیس، می‌تواند عملیات راهبری را مدیریت کند یا نه.
  • OnNavigateTo : زمانی عملیات راهبری وارد View شود(بهتره بگم View مورد نظر در Region صفحه لود شود) این متد فراخوانی می‌شود.
  • OnNavigateFrom : زمانی که راهبری از این View خارج می‌شود (View از حالت لود خارج می‌شود) این متد فراخوانی خواهد شد.
  • ConfirmNavigationRequest : برای تایید عملیات راهبری توسط کلاس پیاده سازی کننده اینترفیس استفاده می‌شود. 
حال یک کلاس برای پیاده سازی و مدیریت ماژول می‌سازیم.
using Microsoft.Practices.Prism.MefExtensions.Modularity;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using System.ComponentModel.Composition;

namespace Module1
{
    [ModuleExport(typeof(Module1Impl))]
    public class Module1Impl : IModule
    {       
        [Import]
        public IRegionManager TheRegionManager { private get; set; }     

        public void Initialize()
        {
            TheRegionManager.RegisterViewWithRegion("MyRegion1", typeof(Module1View1));

            TheRegionManager.RegisterViewWithRegion("MyRegion1", typeof(Module1View2));
        }
    }
}
همان طور که مشاهده می‌کنید از ModuleExportAttribute برای شناسایی ماژول توسط MefBootstrapper استفاده کردیم و نوع آن را Module1Imp1 قرار دادیم.  ImportAttribute استفاده شده در این کلاس و خاصیت TheRegionManager برای این است که در هنگام ساخت Instance از این کلاس IRegionManager موجود در Container باید در اختیار این کلاس قرار گیرد(نشان دهنده وابستگی مستقیم این کلاس با IRegionManager است). روش دیگر این است که در سازنده این کلاس هم این اینترفیس را تزریق کنیم.
در متد Initialize برای RegionManager دو View ساخته شده را رجیستر کردیم. این کار باید به تعداد View‌های موجود در ماژول انجام شود.
Shell
در پروژه اصلی بک Page به نام Shell ایجاد کنید و کد‌های زیر را در آن کپی کنید.
<UserControl x:Class="NavigationViaViewModel.Shell"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://www.codeplex.com/prism" FlowDirection="RightToLeft" FontFamily="Tahoma">

    <Grid x:Name="LayoutRoot"
          Background="White">
        <TextBlock Text="لیست کتاب‌ها به همراه طبقه بندی آن ها"
                   FontSize="19"
                   Foreground="Black"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Top" />
        <ContentControl HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        prism:RegionManager.RegionName="MyRegion1" />
    </Grid>
</UserControl>
همانند مثال قبلی یک ContentControl داریم و به وسیله RegionName که یک AttachedProperty است یک Region به نام MyRegion1 ایجاد کردیم. تمام ماژول‌های این مثال در این محدوده نمایش داده خواهند شد.
Bootstrapper
حال نیاز به یک Bootstrapper داریم. برای این کار یک کلاس به نام TheBootstrapper بسازید:
using Microsoft.Practices.Prism.MefExtensions;
using Microsoft.Practices.Prism.Modularity;
using System.ComponentModel.Composition.Hosting;
using System.Windows;

namespace NavigationViaViewModel
{
    public class TheBootstrapper : MefBootstrapper
    {
        protected override void InitializeShell()
        {
            base.InitializeShell();

            Application.Current.RootVisual = (UIElement)Shell;
        }

        protected override DependencyObject CreateShell()
        {
            return Container.GetExportedValue<Shell>();
        }

        protected override void ConfigureAggregateCatalog()
        {
            base.ConfigureAggregateCatalog();        
            AggregateCatalog.Catalogs.Add(new AssemblyCatalog(this.GetType().Assembly));
        }

        protected override IModuleCatalog CreateModuleCatalog()
        {
            ModuleCatalog moduleCatalog = new ModuleCatalog();
    
            moduleCatalog.AddModule
            (
                new ModuleInfo
                {
                    InitializationMode = InitializationMode.WhenAvailable,
                    Ref = "Module1.xap",
                    ModuleName = "Module1Impl",
                    ModuleType = "Module1.Module1Impl, Module1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                }
            );

            return moduleCatalog;
        }
    }
}
متد CreateShell اولین متد در این کلاس است که اجرا خواهد شد. بعد از متد CreateShell، متد InitializeShell اجرا خواهد شد. خاصیت Shell دقیقا به مقدار برگشتی متد CreateShell اشاره خواهد کرد. در متد InitializeShell  مقدار خاصیت Shell به RootVisual این پروژه اشاره می‌کند(مانند MainWindow در کلاس Application پروژه‌های WPF).
متد ConfigureAggregateCatalog برای مدیریت کاتالوگ‌ها و ماژول‌ها که هر کدام در یک اسمبلی جدا وجود خواهند شد استفاده می‌شود. در این متد من از AssemblyCatalog استفاده کردم. AssemblyCatalog  تمام کلاس هایی که ExportAttribute را به همراه دارند شناسایی می‌کند و آن‌ها را در Container نگهداری خواهد کرد(^). مانند یک ServiceLocator در Microsoft unity Service Locator(^) .
متد آخر به نام CreateModuleCatalog است و باید در آن تمام ماژول‌های برنامه را به کلاس ModuleCatalog اضافه کنیم. در مثال پست قبلی به دلیل استفاده از UnityBootstrapper باید این کار را از طریق BuildEvent ‌ها مدیریت می‌کردیم ولی در این جا Mef به راحتی این کار را انجام خواهد داد.
تغییرات زیر را در فایل App.Xaml قرار دهید و پروژه را اجرا کنید.
public partial class App : Application
 {
        public App()
        {
            this.Startup += this.Application_Startup;                 
            InitializeComponent();
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
           var bootstrapper = new TheBootstrapper();
            bootstrapper.Run(); 
        }
}
با کلیک بر روی ماژول عملیات راهبری برای ماژول انجام خواهد شد.

دریافت سورس پروژه
ادامه دارد..