اشتراک‌ها
ویژوال استودیو کد: آموزش نحوه غیرفعال سازی ماژول AutoReveal در VS Code

اگر از نرم‌افزار ویژوال استودیو کد(Visual Studio Code) به عنوان ویرایشگر متن استفاده می‌کنید یحتمل با ماژول Auto Reveal آشنایی دارید. ماژول Auto Reveal به صورت پیشفرض فعال می‌باشد و اگر بر روی یکی از پنجره فایل باز شده کلیک کنید اتماتیک در بخش Explorer Panel فایل انتخابی فوکوس می‌شود...

ویژوال استودیو کد: آموزش نحوه غیرفعال سازی ماژول AutoReveal در VS Code
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 2 - بررسی ساختار جدید Solution
به روز رسانی
در VS 2017 و ساختار MSBuild ایی آن، فایل‌های project.lock.json, project.json, global.json از پروژه‌های ASP.NET Core حذف شده‌اند.
- معادل فایل global.json اکنون قسمت خواص پروژه و انتخاب فریم ورک مدنظر است:


- معادل فایل project.json، همان فایل csproj برنامه است که اینبار بجای ساختار JSON ایی قبلی، XML ایی شده‌است و اگر بر روی آن کلیک راست کنید، گزینه‌ی Edit آن‌را مشاهده خواهید کرد:


 سایر موارد مانند نصب بسته‌های نیوگت، از طریق رابط کاربری آن تفاوتی نکرده‌اند و یکی است. فقط اینبار بسته‌های نیوگت
به صورت یک ItemGroup، به فایل csproj اضافه می‌شوند:
<ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.1" />
مطالب
پیاده سازی یک سیستم دسترسی Role Based در Web API و AngularJs - بخش اول
در این مجموعه مقالات قصد دارم یک روش را برای پیاده سازی سیستم Role Based سفارشی شده، به صورت پروژه محور، در اختیار شما دوستان قرار دهم. این مجموعه مقالات در هر دو بخش سرور و کلاینت، در قالب یک پروژه‌ی واقعی ارائه خواهد شد. در سمت سرور از Web API و سیستم Identity 2.1 و در سوی کلاینت از تکنولوژی قدرتمند AngularJs کمک گرفته شده‌است. در این مجموعه قصد دارم تا مراحل کلی و اصلی این سیستم دسترسی را تشریح کنم.

مقدمه ای بر سیستم مبتنی بر نقش کاربران

شاید برای شما هم پیش آمده باشد که برای وب سایت یا وب اپلیکیشن خود، به دنبال یک سیستم دسترسی بوده‌اید که بتوانید در آن نقش‌های گوناگونی را تعریف کنید و هر نقش شامل یک سری دسترسی خاص باشد و همچنین با اضافه شدن هر کاربر به این سیستم، بتوانید آنها را به یک نقش خاص انتساب دهید. برای اجرای این امر، روش‌های گوناگونی وجود دارد. یکی از این روش‌ها در سایت CodeProject توسط آقای Stefan Wloch تشریح شده است. در این مقاله کلیت و هدف یک سیستم Role Based، ساختار نقش‌ها و کاربران و دسترسی‌های آنها به خوبی بیان شده است.
 
و اما کمی درباره روشهای موجود حول توسعه یک سیستم مبتنی بر نقش (Role Based) صحبت کنیم. در ابتدا لازم است یک تعریف کلی از یک سیستم Role Based داشته باشیم:
یک سیستم مدیریت کاربر مبتنی بر نقش، سیستمی است که در آن نقش‌های گوناگونی تعریف می‌گردد. به گونه‌ای که هر نقش شامل یک سری دسترسی هایی است که به کاربر اجازه می‌دهد تا به بخشی از سیستم دسترسی داشته باشد. هر کاربر در این سیستم می‌تواند یک و یا چند نقش متفاوت داشته باشد و بر اساس آن نقش‌ها و دسترسی‌های تعریف شده، درون هر نقش به قسمتی از سیستم دسترسی داشته باشد.
بر اساس این تعریف ما در نهایت سه موجودیت نقش (Role)، دسترسی (Permission) و کاربر (User) را خواهیم داشت. در این سیستم دسترسی را اینگونه تعریف میکنیم:
دسترسی در یک سیستم، مجموعه‌ای از حوزه‌ها و یا ناحیه‌هایی است که در سیستم تعریف می‌شود. این حوزه‌ها می‌توانند شامل یک متد یا مجموعه‌ای از متدهای نوشته شده و یا فراتر از آن، شامل مجموعه‌ای از کنترلرها باشد که کاربر اجازه‌ی فراخوانی آنها را دارد.

بدیهی است کاربر برای ما موجودیتی مشخص است. یک کاربر ویژگی‌هایی مانند نام، نام کاربری، سن، رمز عبور و ... خاص خود را داراست که به واسطه این ویژگی‌ها از کاربری دیگر تمییز داده میشود. کاربر در سیستم طی دو مرحله جداگانه Authentication و Authorization مجاز است تا از بخش‌هایی از سیستم استفاده کند. مرحله Authentication به طور خلاصه شامل مرحله‌ای است که هویت کاربر (به عنوان مثال نام کاربری و رمز عبور) تایید صلاحیت میشود. این مرحله در واقع تایید کننده کاربر است و اما بخش بعدی که ما قصد داریم تا در این مورد راهکاری را ارائه دهیم بخش Authorization است. در این بخش به کاربر بر اساس نقش وی دسترسی‌هایی اعطا می‌گردد و کاربر را به استفاده از بخش‌هایی از سیستم مجاز میدارد.

دیاگرام زیر نمود سه موجودیت کاربر، نقش و دسترسی میباشد.

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

ارائه یک سیستم مبتنی بر نقش کاربران با استفاده از تکنولوژی Web API و AngularJs

حال که از محتوا و عملکرد یک سیستم مبتنی بر نقش (Role Based) دانش کافی را کسب کردیم، قصد داریم تا به پیاده سازی کامل این سیستم بپردازیم. شاید برای شما سوال باشد که چرا ما قصد داریم تا این معماری را در Web API و AngularJs پیاده سازی کنیم. در جواب به این سوال باید بگوییم که پیاده سازی این روشها در تکنولوژی‌هایی مانند ASP.NET MVC و تکنولوژی‌ةای مشابه آن که صفحه را در سمت سرور می‌سازند، در بسیاری از منابع و مقالات اینترنتی موجود است. ما قصد داریم تا آنچه را که در یک Single Page Application پیاده سازی کرده‌ایم، به اشتراک بگذاریم. بنابراین قصد داریم تا علاوه بر تشریح کامل این سیستم که قسمت اعظم آن در سمت سرور انجام میشود، به تشریح نحوه تبادل اطلاعات و مدیریت دسترسی‌ها در سمت کلاینت نیز بپردازیم.
همانطور که میدانید ما در یک سیستم بر پایه SPA، برای ساخت یک صفحه ممکن است چندین API را فراخوانی کنیم. بنابراین APIهای نوشته شده به تعداد زیاد ولی با عملکرد اتمیک خواهند بود. به عنوان مثال در یک سیستم فروشگاه اینترنتی، برای ویرایش یک محصول، ممکن است دو یا چند متد API (فراخوانی آن محصول برای قرار دادن در فیلدهای ویرایش، ارسال اطلاعات پس از ویرایش به سرور و ...) فراخوانی گردند. با این حساب ما در تعریف و ایجاد دسترسی‌ها دو راه را خواهیم داشت.
  1. تعریف هر یک از متدهای اتمیک به عنوان یک مجوز دسترسی: در این روش نام کنترلر و نام متد به عنوان یک دسترسی تعریف خواهد شد. در این روش به ازای هر متد ما یک آیتم جدید را باید به جدول Permissions، اضافه نماییم و در نهایت برای تعریف یک نقش و انتساب دسترسی‌ها به یک کاربر، بایستی یک مجموعه چک باکس را که در نهایت به یک متد API ختم میشود، فعال یا غیر فعال کنیم.
  2. تعریف ناحیه‌های مختلف و کنترل‌های قابل انجام در آن ناحیه: در این روش ما قصد داریم تا مجموعه‌ای از متد‌ها را که هدف مشترکی را انجام خواهند داد، در یک ناحیه و یک کنترل بگنجانیم و از به وجود آمدن تعداد زیادی مجوز دسترسی جلوگیری نماییم. به عنوان مثال فرض کنید میخواهیم یک سطح دسترسی را با نام ویرایش کاربران تعریف کنیم. همانگونه که گفتیم ممکن است برای یک عملیات، دو و یا چندین متد درون یک کنترلر تعریف شوند. حال ما این متد‌ها را درون یک ناحیه دسترسی قرار خواهیم داد و آن را در یک حوزه و یک کنترل (Area & Control) میگنجانیم.
در بخش بعدی سعی میکنیم تا این مبحث را بازتر کنیم و به صورت عملی مراحل توسعه این مدل را تشریح نماییم.
مطالب
9# آموزش سیستم مدیریت کد Git : کار به صورت remote
تا اینجا هر آنچه درباره git آموختیم در رابطه با عملکرد git به صورت محلی بود. اما یکی از ویژگی‌های سیستم‌های توزیع شده، امکان استفاده از آن‌ها به صورت remote می‌باشد.
در مورد git تفاوت چندانی بین سرور‌ها و کلاینت‌ها وجود ندارد. تنها تفاوت، نحوه‌ی پیکربندی سرور است که این امکان را می‌دهد تا چندین کلاینت به صورت همزمان به آن متصل شده و با repository آن کار کنند. اما عملا تفاوتی بین repository موجود در کلاینت و سرور نیست.
تذکر ۱: در این مقاله از وب سایت github برای توضیح مثال‌ها استفاده شده است. github قدیمی‌ترین و قدرتمندترین وب سایت برای مدیریت repository‌های git است. اما اجباری در انتخاب آن نیست؛ زیرا انتخاب‌های فراوانی از جمله bitbucket   نیز وجود دارد.
تذکر ۲: نام مستعار origin اجباری نیست؛ اما از آن جهت که نام پیش فرض است، در اکثر مثال‌ها و توضیحات استفاده شده است.
قبل از شروع مبحث بهتر است کمی درباره‌ی پروتکل‌های ارتباطی پشتیبانی شده توسط git صحبت کنیم:
git از ۴ نوع پروتکل پشتیبانی می‌کند:
۱) (http(s: پروتکل http با پورت ۸۰ و https با پورت ۴۴۳ کار می‌کند و معمولا فایروال‌ها مشکلی با این پروتکل‌ها ندارند. از هر دوی آن‌ها می‌توان برای عملیات نوشتن و یا خواندن استفاده نمود و می‌توان آن‌ها را به گونه‌ای تنظیم کرد که برای برقراری ارتباط نیاز به تائید هویت داشته باشند.
۲) git: پروتکلی فقط خواندنی است که به صورت  anonymous و بر روی پورت ۹۴۱۸ کار می‌کند. شکل استفاده از آن به صورت زیر است و معمولا در github کاربرد فراوانی دارد:
git://github.com/[username]/[repositoryname].git
۳) ssh: همان پروتکل استفاده شده در یونیکس است که بر اساس مقادیر کلیدهای عمومی و خصوصی تعیین هویت را انجام می‌دهد. شکل استفاده از آن به صورت زیر است و بر روی پورت ۲۲ کار می‌کند و امکان نوشتن و خواندن را می‌دهد:
git@github.com:[username]/[repositoryname].git
۴) file: تنها استفاده محلی دارد و امکان نوشتن و خواندن را می‌دهد.

نحوه‌ی عملکرد git به صورت remote:
به طور کلی هر برنامه‌نویس نیاز به دو نوع از دستورات دارد تا همواره repository محلی با remote هماهنگ باشد:
۱) بتواند به طریقی داده‌های موجود در repository محلی خود را به سمت سرور بفرستد.
۲) این امکان را داشته باشد تا repository محلی خود را با استفاده از repository در سمت سرور آپدیت نماید تا از آخرین تغییراتی که توسط بقیه اعضای گروه صورت گرفته است آگاهی یابد.

طریقه رفتار git برای کار با repository‌های remote به صورت زیر است:
هنگامی‌که کاربر قصد دارد تا repository یا شاخه‌ای از آن را به سمت سرور بفرستد، git ابتدا یک شاخه با نام همان شاخه به اضافه /origin ایجاد می‌کند. مثلا برای شاخه master، آن نام به صورت زیر می‌شود:
origin/master
عملکرد این شاخه دقیقا مانند دیگر شاخه‌های git است؛ با این تفاوت که امکان check-in یا out برای این نوع شاخه‌ها وجود ندارد. زیرا git باید این شاخه‌ها را با شاخه‌ها متناظرشان در remote هماهنگ نگه دارد.
از این پس این شاخه‌ی ایجاد شده، به عنوان واسطی بین شاخه محلی و شاخه راه دور عمل می‌کند.

cloning:
با استفاده از دستور clone می‌توان یک repository در سمت سرور را به طور کامل در سمت کلاینت کپی کرد. به عنوان مثال repository مربوط به کتابخانه jquery از وب سایت github به صورت زیر است:
git clone https://github.com/jquery/jquery.git
همچنین می‌توان با استفاده از دستور زیر پوشه‌ای با نامی متفاوت را برای repository محلی انتخاب نمود:
git clone [URL][directory name]

اضافه کردن یک remote repository:
برای آن‌که بتوان تغییرات یک remote repository را به repository محلی منتقل نمود، ابتدا باید آن را به لیست repository‌های ریموت که در فایل config. ذخیره می‌شود به شکل زیر اضافه نمود:
git remote add [alias][URL]
در دستور فوق، برای repository باید یک نام مستعار تعریف کرد و در بخش URL باید آدرسی که سرور به وسیله آن امکان دریافت اطلاعات را به ما می‌دهد، نوشت. البته این بستگی به نوع پروتکل انتخابی دارد. به عنوان مثال:
git remote add origin https://github.com/jquery/jquery.git
اگر بخواهیم لیست repository‌هایی که به صورت remote اضافه شده‌اند را مشاهده کنیم، از دستور زیر استفاده می‌کنیم:
git remote
در صورتی‌که دستور فوق را با v- تایپ کنید اطلاعات کامل‌تری در رابطه با repository‌ها مشاهده خواهید کرد.
همچنین برای حذف یک remote repository از دستور زیر استفاده می‌‌کنیم:
git remote [alias] -rm
در صورتی‌که بخواهید لیستی از شاخه‌های remote را مشاهده کنید کافیست از دستور زیر استفاده کنید:
git branch -r
همچنین می‌توان از دستور زیر برای نمایش تمامی شاخه‌ها استفاده کرد:
git branch -a

fetch:
برای دریافت اطلاعات از دستور زیر استفاده می‌کنیم:
git fetch [alias][alias/branch name]
در صورتی‌که تنها یک repository باشد می‌توان از نوشتن نام مستعار صرفنظر نمود. همچنین اگر شاخه یا شاخه‌های مورد نظر به صورت track شده باشند، می‌توان قسمت دوم دستور فوق را نیز ننوشت.
اگر بعد از اجرای دستور فوق، بر روی یک شاخه log بگیرید، خواهید دید که تغییرات در شاخه محلی اعمال نشده است زیرا دستور فوق تنها داده‌ها را بر روی شاخه [origin/[branchname ذخیره کرده است. برای آپدیت شدن شاخه اصلی باید با استفاده از دستور merge آن را در شاخه مورد نظر ادغام کرد.

pulling:
چون کاربرد دو دستور fetch و merge به صورت پشت سر هم زیاد است git دو دستور فوق را با استفاده از pull انجام می‌دهد:
pull [alias][remote branch name ]
اگر دو مقدار فوق را برای دستور pull تعیین نکنید، ممکن است در هنگام اجرای دستور فوق با خطایی مواجه شوید مبنی بر اینکه git نمی‌داند دقیقا شاخه ریموت را با کدام شاخه محلی باید ادغام کند. این مشکل زمانی پیش می‌آید که برای شاخه ریموت یک شاخه محلی متناظر وجود نداشته باشد. برای ایجاد تناظر بین دو شاخه ریموت و لوکال درگذشته باید فایل config. را تغییر می‌دادیم، اما نسخه جدید git دستوری را برای آن دارد:
git branch --set-upstream [local brnach][alias/branch name]
با اجرای این دستور از این پس شاخه محلی تغییرات شاخه remote را دنبال می‌کند.

pushing:
با استفاده از push می‌توان تغییرات ایجاد شده را به remote repository انتقال داد:
git push -u [alias][branch name ]
وجود u- در اینجا بدین معنا است که ما میخواهیم تغییرات repository در سمت سرور دنبال شود. در صورت استفاده نکردن از u- بایستی برای push هر بار مقادیر داخل کروشه‌ها را بنویسیم. در صورتی‌که بعدا بخواهیم، می‌توان توسط همان دستوری که در قسمت pull گفته شد دو شاخه را به هم وابسته کنیم.
tag:
همانطور که قبلا گفته شد تگ‌ها برای نشانه‌گذاری و دسترسی راحت‌تر به به commitها هستند. برای ایجاد یک تگ از دستور زیر استفاده می‌شود:
git tag [tag name]
همچنین می‌توان با a- برای تگ پیامی نوشت و یا با s- آن را امضا کرد. برای مشاهده تگ‌ها از دستور زیر استفاده می‌شود:
git tag
در حالت پیشفرض git تگ‌ها را push نمی‌کند. برای push کردن تگ‌ها باید دستور push را با اصلاح‌کننده tages-- به کارببرید.
نظرات مطالب
شروع به کار با بوت استرپ 4
یک نکته‌ی تکمیلی: چگونه کلاس‌های CSS استفاده نشده را تشخیص دهیم؟

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


در developer tools آن، برگه‌ی Sources و سپس در اینجا، قسمت Snippets را انتخاب کنید. در همین ناحیه کلیک راست کرده و گزینه‌ی new را انتخاب نمائید. سپس قطعه کد «List all undefined CSS classes» را در باکس خالی جلوی آن paste کنید و ctrl+s را بفشارید.

اکنون بر روی این مدخل جدید کلیک راست کرده و گزینه‌ی Run را انتخاب کنید:


بلافاصله در برگه‌ی Console، چنین خروجی را مشاهده خواهید کرد:


این‌ها کلاس‌هایی هستند که در صفحه‌ی جاری استفاده شده‌اند، اما از بوت استرپ 4 (جمع تمام CSSهایی که به صفحه الحاق شده‌اند) حذف شده‌اند و دیگر حضور ندارند.
نظرات مطالب
نمایش فرم‌های مودال Ajax ایی در ASP.NET MVC به کمک Twitter Bootstrap
با css قابل تنظیم است. برای تنظیم عرض و سایر مشخصات تمام صفحات مودال:
body .modal {
    width: 560px;
    margin-left: -280px;
}
و یا در مثال فوق برای یک صفحه خاص:
$('#dialogDiv').modal({
                        backdrop: 'static', //با کلیک کاربر روی صفحه، صفحه مودال بسته نمی‌شود
                        keyboard: true
                    }, 'show').css({
                               'width': '100px',
                               'max-width': '1000px',
                               'margin-left': '10px' });
نظرات مطالب
تاریخ شمسی برای blogger !
- در قالب شما ابتدای صفحه یک سطر طولانی هست ... اون همون کل فایل jQuery است که به این صورت لحاظ شده و علت آن‌را هم نمی‌دانم و لزومی هم نداشته و صفحه را بی‌خود سنگین کرده.
- شما می‌تونید اسکریپت‌ها را قبل از بسته شدن تگ body قرار بدید.
- ضمنا کار ارائه شده در این مقاله، با قالب‌های جدید تهیه شده سازگار نیست. خبری از date-header و غیره در آن نیست و منصف باشید که فرصت این وجود ندارد که به ازای تک تک قالب‌ها یا تک تک افراد بلاگر این موارد بخواهند اصلاح شوند یا تغییر کنند.
در کل تهیه کنندگان قالب‌ها می‌تونند این مورد را لحاظ کنند یا خیر.
مطالب
درست کردن فایل راهنمای CHM از توضیحات XML یک پروژه

تا حالا هیچ وقت برای شما این سؤال پیش اومده که این فایل‌های CHM راهنمای زیبایی که برای مثال به‌عنوان مستندات یک کتابخانه در دات نت ارائه می‌شوند با چه نرم‌افزار یا نرم‌افزارهایی تولید می‌شوند؟ یا اینکه به نظر یک یا چند نفر ساعت‌ها وقت می‌گذارند، صفحات HTML مربوطه را تولید می‌کنند و در آخر با استفاده از ابزارهای تولید فایل CHM ، فایل راهنما را نهایی می‌کنند؟
این فایل‌ها به صورت خودکار بر اساس XML code comments ارائه شده برای یک متد ، کلاس و امثال آن تولید می‌شوند. برای مثال به توضیحات زیر دقت بفرمائید:

/// <summary>
/// استخراج ایمیل‌های یک فایل متنی و ذخیره آن در فایلی جدید
/// </summary>
/// <param name="inFilePath">فایل ورودی</param>
/// <param name="outFilePath">فایل خروجی</param>
public static void ExtractEmails(string inFilePath, string outFilePath)

هر چند VS.Net‌ در ایجاد خوکار قالب اولیه این نوع کامنت‌ها بسیار خوب عمل می‌کند اما نکات پیشرفته‌تری نیز در این‌باره موجود هستند که در کیفیت فایل راهنمای تولید شده بر اساس این توضیحات بسیار مؤثرند. راهنمای کاملی در این‌باره را از اینجا می‌توانید دریافت کنید.
در ادامه نحوه تولید خودکار این نوع راهنماها را بررسی خواهیم کرد.

الف) نصب برنامه‌های مورد نیاز
برای ایجاد فایل chm از توضیحات xml ایی ارائه شده، ابتدا دو برنامه سورس باز زیر را دریافت و نصب کنید:
سپس نیاز به HTML Help 2.0 compiler خواهد بود. این کامپایلر به همراه SDK ویژوال استودیو ارائه می‌شود. بسته به نگارش VS مورد استفاده، نیاز است تا یکی از موارد زیر را دریافت و نصب کنید:
برنامه hxcomp.exe ذکر شده، عموما در مسیر زیر نصب خواهد شد:
%Program Files%\Common Files\Microsoft Shared\Help 2.0 Compiler\
ب) تنظیمات VS.Net
مرحله بعد به تنظیمات VS.Net مربوط می‌شود. به صفحه خواص پروژه مراجعه کنید و در برگه Build ، گزینه تولید XML documentation file را انتخاب کنید. سپس مجددا پروژه خود را کامپایل کنید.

ج) تنظیمات Sandcastle Help File Builder
یک پروژه جدید را در این برنامه آغاز کرده و سپس فایل اسمبلی و xml تولید شده آنرا انتخاب کنید. (بر روی دکمه add کلیک کرده و هر دو فایل exe یا dll مورد نظر را به همراه فایل xml آن که در قسمت ب تولید کردیم، انتخاب کنید. در صورت عدم انتخاب یکی از موارد فایل راهنما تولید نخواهد شد)
اکنون نوبت به تنظیمات پروژه می‌رسد.
در قسمت Build:
گزینه Help File Format را انتخاب کرده و سپس html help 2x را نیز تیک بزنید. (در صورت تمایل به تولید این نوع فرمت)
در قسمت Dependencies ، تمام اسمبلی‌هایی را که پروژه شما به آن وابسته است، اضافه کنید.
توسط گزینه Framework Version ، نگارشی از دات نت فریم ورک که اسمبلی شما بر اساس آن کامپایل شده است را انتخاب کنید.
در قسمت Help File:
Presentation Style را بر روی VS2005 قرار دهید. این‌کار اجباری نیست اما راهنمای حاصل زیباتر خواهد بود.
در قسمت Paths :
مسیرهای کامپایلرهای راهنما را مشخص کنید. بر روی سیستم من این مسیرها مطابق شکل زیر هستند:


اگر HTML Help Workshop بر روی سیستم شما نصب نبود، آنرا از این آدرس دریافت نمائید.

د) ساخت فایل راهنما
بر روی آیکون build در نوار ابزار برنامه کلیک کنید (و یا انتخاب گزینه documentation->build)

تا اینجا اگر هر دو نوع Help1xAndHelp2x را در قسمت build انتخاب کرده باشید، دو نوع راهنمای مستقل و همچنین قابل یکپارچه شدن با سیستم راهنمای VS.net را تولید کرده‌اید.



ه) یکپارچه سازی Help2x تولید شده با سیستم راهنمای VS.Net
پروژه جدیدی را در VS.Net از نوع Other Project Types > Extensibility > Help Integration Wizard ایجاد کنید. در مرحله اول، ایجاد setup و نوع VS را انتخاب کرده و در صفحه بعد فایل‌های Help2x خود را اضافه کنید (فایلهایی با پسوند hxs). دو مرحله آخر را مطابق نیازهای کاری خود تنظیم نموده و پروژه را در آخر build کنید. نصاب تولید شده فایل‌های راهنمای شما را با سیستم راهنمای VS.Net یکپارچه خواهد ساخت.

چند نکته:
1- جهت سفارشی سازی بیشتر راهنمای تولید شده می‌توان از ابزار سورس باز زیر نیز کمک گرفت:
http://www.codeplex.com/DocProject
2- افزونه‌ای رایگان برای VS.Net جهت سهولت تولید توضیحات XML در آدرس زیر قابل دریافت است:
http://www.roland-weigelt.de/ghostdoc

مطالب
PowerShell 7.x - قسمت سیزدهم - ساخت یک Static Site Generator ساده توسط PowerShell و GitHub Actions
در این مطلب میخواهیم یک مثال دیگر از PowerShell را به همراه GitHub Actions را بررسی کنیم. هدف ایجاد یک Static Site Generator و در نهایت پابلیش خروجی استاتیک بر روی GitHub Pages است. روالی که در ادامه بررسی میکنیم صرفاً یک مثال از ترکیب این تکنولوژی‌ها است و قاعدتاً روش‌های ساده‌تر و سرراست‌تری نیز برای اینکار وجود دارد. به عنوان مثال میتوانید از Jekyll که یک SSG مبتنی بر Ruby است نیز استفاده کنید که GitHub Pages، به صورت پیش‌فرض از آن پشتیبانی میکند. در اینحالت به محض پوش کردن سایت بر روی ریپوزیتوری (با فرض اینکه این امکان را فعال کرده باشید) به صورت خودکار سایت بیلد شده و خروجی بر روی یک برنچ دیگر قرار خواهد گرفت و در نهایت برنچ بیلد شده توسط GitHub Pages میزبانی خواهد شد (البته امکان تغییر برنچ پیش‌فرض را نیز دارید). اما اگر بخواهیم کل فرآیند بیلد را به صورت سفارشی انجام دهیم، میتوانیم از GitHub Actions استفاده کنیم؛ یعنی مشابه کاری که Jekyll انجام میدهد. به محض پوش کردن محتوا، یک اسکریپت PowerShell برای اینکار فراخوانی شود و خروجی نهایی بر روی یک برنچ دیگر منتشر شود. خروجی نهایی این چنین قالبی خواهد داشت:

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

ساختار پروژه
ساختاری که برای پروژه در نظر گرفته‌ام به صورت زیر است:
├── _layout
│   ├── _footer.html
│   ├── _header.html
│   ├── _nav.html
│   └── main.html
├── build
├── img
├── posts
└── set-posts.ps1
  • دایرکتوری layout_: درون این دایرکتوری، ساختار اصلی بلاگ را قرار داده‌ایم. در ادامه محتویات هر فایل را مشاهده خواهید کرد: 
<!--main.html-->
<!DOCTYPE html>
<html dir="rtl">

{{header}}

<body>
    {{nav}}
    <main>
        {{content}}
    </main>
    {{footer}}
</body>



<!--_header.html-->
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{title}}</title>
    <link href="https://cdn.jsdelivr.net/gh/rastikerdar/samim-font@v4.0.5/dist/font-face.css" rel="stylesheet"
        type="text/css" />
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.16/dist/tailwind.min.css" rel="stylesheet">
    <style>
        * {
        }
    </style>
</head>

<!--_nav.html-->
<header>
    <nav>
        <div>
            <div>
                <a href="#">بلاگ من</a>
            </div>
            <div>
                <ul>
                    {{nav}}
                </ul>
            </div>
        </div>
    </nav>
</header>


<!--_footer.html-->
<footer>
    <div>
        <div>
            <p>
                تمامی حقوق محفوظ است
            </p>
        </div>
    </div>
</footer>
  • دایرکتوری build: درون این دایرکتوری، خروجی‌های HTML که قرار است توسط اسکریپت PowerShell جنریت شوند، قرار خواهند گرفت. این پوشه در واقع قرار است توسط GitHub Pages میزبانی شود.
  • دایرکتوری img: درون این دایرکتوری، تصاویر مربوط به هر بلاگ‌پست را قرار خواهیم داد.
  • دایرکتوری posts: درون این دایرکتوری، مطالب‌مان را با فرمت Markdown، قرار خواهیم داد. به عنوان مثال در ادامه یک نمونه از آن را مشاهده خواهید کرد (در کد زیر از Front Matter برای اضافه کردن یکسری متادیتای موردنیاز که حین بیلد شدن ضروری هستند استفاده شده‌است) 
---
title: اولین پست من
slug: hello
date: 2023-04-26
author: سیروان عفیفی
tags: [tag1, tag2, tag3]
excerpt: این یک پست تستی است در مورد اینکه چطور میتوانیم از این قالب استفاده کنیم
---

# اولین پست من

## اولین پست من

### اولین پست من

#### اولین پست من

##### اولین پست من

###### اولین پست من

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

<img src="/img/graphql.jpg"/>
همانطور که مشاهده میکنید، مسیر تصویر استفاده شده در بلاگ‌پست، از دایرکتوری img خوانده شده‌است.
  • فایل set_post.ps1: موتور اصلی جنریت کردن صفحات HTML این فایل میباشد. در ادامه محتویات آن را مشاهده خواهید کرد. سپس هر کدام از توابع استفاده شده را یکی‌یکی توضیح خواهیم داد: 
Function Get-Layouts {
    $headerLayout = Get-Content -Path ./_layout/_header.html -Raw
    $homeLayout = Get-Content -Path ./_layout/main.html -Raw
    $footerLayout = Get-Content -Path ./_layout/_footer.html -Raw

    Return @{
        Header = $headerLayout
        Home   = $homeLayout
        Footer = $footerLayout
    }
}

Function Get-PostFrontMatter($postContent) {
    $frontMatter = [regex]::Match($postContent, "(---(?:\r?\n(?!--|\s*$).*)*)\s*((?:\r?\n(?!---).*)*\r?\n---)")
    Return $frontMatter
}

Function Set-Headings($postHtml) {
    Return $postHtml -Replace '<h(\d) id="(.*)">', {
        $level = $_.Groups[1].Value
        $id = $_.Groups[2].Value
        $class = Switch ($level) {
            '1' { 'text-4xl font-bold mb-2' }
            '2' { 'text-3xl font-bold mb-2' }
            '3' { 'text-2xl font-bold mb-2' }
            '4' { 'text-xl font-bold mb-2' }
            '5' { 'text-lg font-bold mb-2' }
            '6' { 'text-base font-bold mb-2' }
        }
        "<h$level class='$class' id='$id'>"
    }
}

Function ConvertTo-Slug {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string]$String
    )
    process {
        $slug = $String -replace '[^\w\s-]', '' # remove non-word characters except hyphens
        $slug = $slug -replace '\s+', '-' # replace whitespace with a single hyphen
        $slug = $slug -replace '^-+|-+$', '' # remove leading/trailing hyphens
        $slug = $slug.ToLower() # convert to lowercase
        Write-Output $slug
    }
}

Function Get-Posts {
    $markdownPosts = Get-ChildItem -Path ./posts -Filter *.md
    $posts = @()
    Foreach ($post in $markdownPosts) {
        $postContent = Get-Content -Path $post.FullName -Raw
        $frontMatter = Get-PostFrontMatter $postContent
        $frontMatterObject = $frontMatter | ConvertFrom-Yaml

        $slug = $frontMatterObject.slug ?? (ConvertTo-Slug "$($frontMatterObject.date)-$($frontMatterObject.title)")
        $body = $postContent.Replace($frontMatter.Value, "") | ConvertFrom-Markdown
        $postHtml = $layouts.Home -replace '{{header}}', $layouts.Header `
            -replace '{{title}}', $frontMatterObject.title `
            -replace '{{nav}}', (Set-Navs) `
            -replace '{{content}}', $body.Html `
            -replace '{{footer}}', $layouts.Footer

        $postHtml = Set-Headings $postHtml
        $postHtml | Out-File -FilePath ./build/$slug.html

        $posts += @{
            title   = $frontMatterObject.title
            slug    = $slug
            excerpt = $frontMatterObject.excerpt
            date    = $frontMatterObject.date
            author  = $frontMatterObject.author
            body    = $body.Html
        }
    }
    Return $posts
}

Function Set-Archive {
    $posts = Get-Posts
    $archive = @()
    $archive = @"
        <ul>
            $($posts | ForEach-Object { "<li><a href='$($_.slug).html'>$($_.title)</a></li>" })
        </ul>
"@
    Return $archive -join "`r`n"
}

Function Copy-ToBuild {
    $layouts = Get-Layouts
    $latestPosts = Get-Posts | ForEach-Object { @"
    <div>
        <img src="https://via.placeholder.com/300x200" alt="$($_.title)">
        <h2>$($_.title)</h2>
        <p>$($_.excerpt)</p>
            <a href="$($_.slug).html">ادامه مطلب</a>
        </div>
"@
    }

    $homeLayout = $layouts.Home -replace '{{header}}', $layouts.Header `
        -replace '{{nav}}', (Set-Navs) `
        -replace '{{title}}', 'بلاگ من' `
        -replace '{{content}}', ('<div>' + $latestPosts + '</div>') `
        -replace '{{footer}}', $layouts.Footer

    $homeLayout | Out-File -FilePath ./build/index.html

    Copy-Item -Path ./img -Destination ./build -Recurse -Force

}

Function Set-Navs {
    $navs = @(
        @{
            title = "صفحه اصلی"
            url   = "/sample"
        },
        @{
            title = "درباره ما"
            url   = "/sample/about.html"
        },
        @{
            title = "تماس با ما"
            url   = "/sample/contact.html"
        }
    )
    $navLayout = Get-Content -Path ./_layout/_nav.html -Raw
    $navLayout -replace '{{nav}}', ($navs | ForEach-Object { "<li><a href=""$($_.url)""text-gray-700 hover:text-gray-800 m-2"">$($_.title)</a></li>" })
}


Copy-ToBuild
همانطور که در کد فوق مشاهده میکنید، تابع Copy-ToBuild فراخوانی شده است. درون این تابع، ابتدا لی‌اوت‌های موردنیاز برای تولید صفحات HTML را درون یک متغییر با نام layouts قرار داده‌ایم. درون لی‌اوت‌ها یکسری placeholder برای قرارگیری قسمت‌های مختلف سایت تعریف کرده‌ایم که قرار است توسط تابع عنوان شده، جایگزین شوند. در ادامه توسط تابع Get-Posts، تمامی مطالب درون دایرکتوری posts را واکشی کرده و برای هر کدام، صفحه‌ی HTML معادل آن را تولید کرده‌ایم. برای پارز کردن قسمت Front Matter هر بلاگ‌پست نیز از پکیج powershell-yaml استفاده شده‌است. درون تابع Get-Posts باید هر مطلب را همراه با لی‌اوت اصلی سایت، به HTML تبدیل کنیم. بنابراین یکسری عملیات string replacement درون تابع عنوان شده انجام گرفته است. در نهایت، مطالب همراه با لی‌اوت مناسبی درون دایرکتوری build ذخیره خواهند شد و سپس یک لیست از مطالب پارز شده به عنوان خروجی تابع برگردانده خواهد شد. در نهایت درون تابع Copy-ToBuild، یکسری card برای نمایش آخرین مطالب بلاگ تهیه شده، سپس خروجی نهایی درون فایل index.html همراه با قالب اصلی ذخیره خواهد شد.

ایجاد GitHub Actions Workflow
در ادامه برای ساختن workflow نهایی باید با کمک GitHub Actions، اسکریپت PowerShellی را که ساختیم، اجرا کنیم. این اسکریپت ابتدا پروژه را clone کرده، سپس وابستگی موردنیاز را نصب کرده و در نهایت اسکریپت را اجرا خواهد کرد: 
name: Deploy static content to Pages

on:
  push:
    branches:
      - main
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2

      - name: Install powershell-yaml module
        shell: pwsh
        run: |
          Set-PSRepository PSGallery -InstallationPolicy Trusted
          Install-Module powershell-yaml -ErrorAction Stop

      - name: Setup Pages
        uses: actions/configure-pages@v3

      - name: Build Static Site
        shell: pwsh
        run: |
          . ./set-posts.ps1

      - name: Upload Static Site Artifact
        uses: actions/upload-pages-artifact@v1
        with:
          path: build

      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2

نحوه انتشار یک مطلب جدید
  • درون دایرکتوری posts، مطلب موردنظر را به همراه Front Matter زیر ایجاد کرده و سپس محتویات مطلب را بعد از آن وارد کنید:
---
title: اولین پست من
slug: hello
date: 2023-04-26
author: سیروان عفیفی
tags: [tag1, tag2, tag3]
excerpt: این یک پست تستی است در مورد اینکه چطور میتوانیم از این قالب استفاده کنیم
---

content
  • تغییرات ایجاد شده را کامیت و سپس پوش کنید. به محض پوش کردن تغییرات، GitHub Actions پروسه بیلد را انجام خواهد داد و بلافاصله میتوانید تغییرات را مشاهده نمائید.
نکته: قابلیت GitHub Pages به صورت پیش‌فرض فعال نیست. برای فعال کردن آن ابتدا باید به قسمت تنظیمات ریپوزیتوری GitHubتان مراجعه کرده و سپس از تب Pages، فیلد Source را بر روی GitHub Actions قرار دهید:


بنابراین بعد از پوش کردن تغییرات workflowایی که ایجاد کردیم توسط Source شناسایی خواهد شد و سپس وب‌سایت از طریق آدرس https://<username>.github.io/<repository> در دسترس قرار خواهد گرفت:

کدهای این مطلب را میتوانید از اینجا دریافت کنید.

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

برای تهیه فایل PDF، به غیر از کتابخانه‌های گزارش گیری تجاری، می‌توان از کتابخانه‌ی iTextSharp که گزینه‌ای سورس باز، با کیفیت و محبوب است، استفاده کرد. متاسفانه این کتابخانه دارای محیط گرافیکی طراحی گزارش نیست و کار با آن فقط از طریق کدنویسی میسر است که صد البته انعطاف پذیری و پویایی قابل توجهی را برای تهیه‌ی گزارش نسبت به ابزار‌های طراحی گرافیکی، در اختیار برنامه نویس قرار می‌دهد. البته می‌توان از برنامه‌ی Open Office برای طراحی قالب گزارش نیز استفاده کرد، اما من پس از استفاده، به کیفیت و انعطاف پذیری و امکانات مورد نظرم نتوانستم دست یابم و تصمیم گرفتم برای تهیه‌ی کارت، مستقیما با iTextSharp کد نویسی انجام دهم.

در این مقاله به نحوه‌ی تهیه یک کارت به فرمت PDF با استفاده از کتابخانه iTextSharp خواهیم پرداخت که این کتابخانه به فناوری خاصی گره نخورده است و در تمامی برنامه‌های ASP.NET ، WPF، Windows Form و در کل هر کجا که دات نت فریمورک در دسترس است، قابل استفاده می‌باشد.

فرض کنید کارتی به شکل زیر می‌خواهیم بسازیم (تمامی تصاویر از سطح اینترنت جمع آوری شده‌اند):


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

 فرقی نمی‌کند که تکنولوژی مورد استفاده شما چیست، برای سادگی کار این مثال را با یک Console Application آغاز کنید. برای نصب iTextSharp نیز فرمان زیر را در کنسول NuGet وارد کنید:
Install-Package iTextSharp


شروع کار با iTextSharp

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

            var fileStream = new FileStream("card.pdf", FileMode.Create, FileAccess.Write, FileShare.None);

            var docFont = GetFont();

            var pageSize = PageSize.A6.Rotate(); // سایز کارت را اینجا باید مشخص کرد

            var doc = new Document(pageSize);

            doc.SetMargins(18f, 18f, 15f, 2f);

            var pdfWriter = PdfWriter.GetInstance(doc, fileStream);

            doc.Open();
-  در اینجا سایز کارت، بر روی کاغذ A6 در حالت افقی قرار داده شده است. بدیهی است که مطابق نیاز خودتان می‌توانید این سایز را تغییر دهید.
-  تابع GetFont یک تابع کمکی است که در سورس نهایی ارائه شده است و نکته تعریف فونت در iTextSharp  در آن رعایت شده است.
 - بقیه موارد نیز جزء الزامات کار با این کتابخانه است.


برای درج عکس به صورت شفاف در پس زمینه کارت باید از کد زیر استفاده کرد:

            //  درج لوگوی مسابقات به صورت شفاف در پس زمینه
            var canvas = pdfWriter.DirectContentUnder;
            var logoImg = Image.GetInstance(competitionImagePath);
            logoImg.SetAbsolutePosition(0, 0);
            logoImg.ScaleAbsolute(pageSize);
            var graphicsState = new PdfGState { FillOpacity = 0.2F };
            canvas.SetGState(graphicsState);
            canvas.AddImage(logoImg);
 

چیدمان و طرح بندی بندی عناصر در iTextSharp

برای طراحی کارت یا کلا کار طراحی، باید با نحوه‌ی قرار دادن و طرح بندی عناصر مثل تصاویر و نوشته‌ها و ابزارهای مورد نیاز برای این کار، آشنا شوید. خوشبختانه در iText برای این کار ابزارهای خوبی وجود دارد.

حتما با تگ Table در HTML آشنایی دارید. در سال‌های دور، حتی کل صفحه‌ی وب را به وسیله‌ی Table ساختار دهی می‌کردند. در iTextSharp نیز کلاسی به نام PdfPTable در دسترس است که می‌توان از آن به عنوان قالبی برای قرار دادن عناصر، در صفحه استفاده کرد. این Table همانند هر جدولی دارای یک سری سطر و ستون است که می‌توانیم عناصر مورد نظرمان مثل تصویر و نوشته و... را در آن قرار دهیم. 

همانطور که از تگ Table در HTML می‌توان برای رسم جدول و قرار دادن عناصر در سطر و ستون‌های آن استفاده کرد، در iText نیز می‌توان از کلاس PdfPTable برای ترسیم جدول و از متد AddCell آن برای افزودن سلول به آن استفاده کرد. کار با کلاس PdfPTable نیز ساده است. کافی هست به هنگام ساخت نمونه‌ای از آن، در سازنده‌اش تعداد ستون‌های جدول را ذکر کنید. سپس با استفاده از متد AddCell آن، پارامتری از جنس PdfPCell برای آن ارسال کنید تا به جدول، سلول جدیدی اضافه شود و در صورتیکه تعداد سلول‌های جدید، از تعداد ستون‌های تعریف شده بیشتر شود، iText به صورت خودکار سلول‌های اضافی را به ردیف جدیدی منتقل می‌کند. البته برای افزودن سطر و ستون، روش‌های دیگری نیز هست؛ ولی گویا  روش مرجح همین روش است.  کلاس PdfPCell که نقش سلول‌های جدول را بازی می‌کند، نیز می‌تواند شامل متن، تصویر و یا حتی یک جدول تودرتو باشد.
  
در ادامه کدهای جدول بالایی کارت شامل لوگوی دانشگاه، عنوان مسابقات و عکس فرد را مشاهده می‌کنید:
            // جدولی که برای چیدمان عناصر ارم دانشگاه و عنوان و عکس شخص استفاده می‌شود
            var topTable = new PdfPTable(3)
            {
                WidthPercentage = 100,
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                ExtendLastRow = false,
            };

            var universityLogoImage = Image.GetInstance(universityLogoPath);

            universityLogoImage.ScaleAbsolute(70, 100);

            topTable.AddCell(new PdfPCell(universityLogoImage)
            {
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            topTable.AddCell(new PdfPCell(new Phrase("کارت مسابقات دانشگاه آزاد اسلامی", docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_CENTER,
                Border = 0,
            });

            var userImage = Image.GetInstance(userModel.ImagePath);
            userImage.Border = Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.BOTTOM_BORDER | Rectangle.LEFT_BORDER;
            userImage.BorderWidth = 1f;
            userImage.BorderColor = new BaseColor(204, 204, 204); // gray color
            userImage.ScaleAbsolute(70, 100);

            topTable.AddCell(new PdfPCell(userImage)
            {
                HorizontalAlignment = 2,
                Border = 0
            });

            int[] topTableColumnsWidth = { 10, 25, 10 };

            topTable.SetWidths(topTableColumnsWidth);

            doc.Add(topTable);
-  در ابتدا یک جدول سه ستونه تعریف شده است. تعداد ستون‌ها در هنگام نمونه سازی از کلاس PdfPTable، در سازنده‌ی آن ذکر شده است.
-  در iText برای کار با تصاویر، باید از کلاس Image و متد GetInstance فراهم شده توسط خود کتابخانه استفاده کرد. سپس این تصویر را باید به عنوان پارامتر به سلول جدول ارسال کرد.
-  به کمک متد AddCell، می‌توان به جدول، سلول اضافه کرد و به صورت خودکار سلول‌های جدیدی که از تعداد ستون‌ها بیشتر می‌شوند، به سطر جدید منتقل می‌شوند.
-  اگر می‌خواهید در سلولی متنی نمایش دهید، از کلاس Phrase و تعیین صریح فونت آن استفاده کنید؛ چرا که در غیر این صورت ممکن است متون فارسی نمایش داده نشود.
-  در انتها هم جدول مورد نظر را باید به شی doc از جنس کلاس Document تعریف شده اضافه کرد.
 
بدیهی هست که اطلاعات شخص مثل نام، نام خانوادگی و ... را نیز باید در یک جدول چهار ستونه قرار داد و نکته‌ی خاص اضافه‌تری ندارد. 

حال اگر بیاییم این تکه کدها را کنار هم قرار بدهیم به کدی قابل اجرا خواهیم رسید.
ابتدا کلاسی را که در برگیرنده‌ی اطلاعات فرد است، تعریف می‌کنیم:
    public class UserModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string StudentNumber { get; set; }
        public string NationalCode { get; set; }
        public string UniversityName { get; set; }
        public string ImagePath { get; set; }
    }
 
- سپس کلاس CardReport را که اصل و اساس بحث ما بود، تعریف می‌کنیم.
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Font = iTextSharp.text.Font;
using Image = iTextSharp.text.Image;
using Rectangle = iTextSharp.text.Rectangle;

namespace ITextSharpCardSample
{
    public class CardReport
    {
        public static void Generate(UserModel userModel, string competitionImagePath, string universityLogoPath)
        {
            var fileStream = new FileStream("card.pdf", FileMode.Create, FileAccess.Write, FileShare.None);

            var docFont = GetFont();

            var pageSize = PageSize.A6.Rotate(); // سایز کارت را اینجا باید مشخص کرد

            var doc = new Document(pageSize);

            doc.SetMargins(18f, 18f, 15f, 2f);

            var pdfWriter = PdfWriter.GetInstance(doc, fileStream);

            doc.Open();

            //  درج لوگوی مسابقات به صورت شفاف در پس زمینه
            var canvas = pdfWriter.DirectContentUnder;
            var logoImg = Image.GetInstance(competitionImagePath);
            logoImg.SetAbsolutePosition(0, 0);
            logoImg.ScaleAbsolute(pageSize);
            var graphicsState = new PdfGState { FillOpacity = 0.2F };
            canvas.SetGState(graphicsState);
            canvas.AddImage(logoImg);


            // جدولی که برای چیدمان عناصر ارم دانشگاه و عنوان و عکس شخص استفاده می‌شود
            var topTable = new PdfPTable(3)
            {
                WidthPercentage = 100,
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                ExtendLastRow = false,
            };

            var universityLogoImage = Image.GetInstance(universityLogoPath);

            universityLogoImage.ScaleAbsolute(70, 100);

            topTable.AddCell(new PdfPCell(universityLogoImage)
            {
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            topTable.AddCell(new PdfPCell(new Phrase("کارت مسابقات دانشگاه آزاد اسلامی", docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_CENTER,
                Border = 0,
            });

            var userImage = Image.GetInstance(userModel.ImagePath);
            userImage.Border = Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.BOTTOM_BORDER | Rectangle.LEFT_BORDER;
            userImage.BorderWidth = 1f;
            userImage.BorderColor = new BaseColor(204, 204, 204); // gray color
            userImage.ScaleAbsolute(70, 100);

            topTable.AddCell(new PdfPCell(userImage)
            {
                HorizontalAlignment = 2,
                Border = 0
            });

            int[] topTableColumnsWidth = { 10, 25, 10 };

            topTable.SetWidths(topTableColumnsWidth);

            doc.Add(topTable);


            // جدول مشخصات شرکت کننده مثل نام و نام خانوادگی
            var infoTable = new PdfPTable(4)
            {
                WidthPercentage = 100,
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                ExtendLastRow = false,
                SpacingBefore = 15,
            };

            infoTable.AddCell(new PdfPCell(new Phrase("نام:", docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0,
                PaddingBottom = 15
            });

            infoTable.AddCell(new PdfPCell(new Phrase(userModel.FirstName, docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            infoTable.AddCell(new PdfPCell(new Phrase("نام خانوادگی:", docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            infoTable.AddCell(new PdfPCell(new Phrase(userModel.LastName, docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            infoTable.AddCell(new PdfPCell(new Phrase("شماره\nدانشجویی:", docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0,
                PaddingBottom = 15
            });

            infoTable.AddCell(new PdfPCell(new Phrase(userModel.StudentNumber, docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            infoTable.AddCell(new PdfPCell(new Phrase("کد ملی:", docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            infoTable.AddCell(new PdfPCell(new Phrase(userModel.NationalCode, docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            infoTable.AddCell(new PdfPCell(new Phrase("واحد دانشگاهی:", docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            infoTable.AddCell(new PdfPCell(new Phrase(userModel.UniversityName, docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });


            // دو سلول بعدی صرفا جهت تکمیل شدن یک ردیف است تا عملکرد صحیح خود را داشته باشد
            infoTable.AddCell(new PdfPCell(new Phrase("", docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });

            infoTable.AddCell(new PdfPCell(new Phrase("", docFont))
            {
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_LEFT,
                Border = 0
            });


            int[] infoTableColumnsWidth = { 20, 15, 20, 15 };

            infoTable.SetWidths(infoTableColumnsWidth);

            doc.Add(infoTable);

            doc.Close();
        }

        private static Font GetFont()
        {
            const string fontName = "Iranian Sans";

            if (FontFactory.IsRegistered(fontName))
                return FontFactory.GetFont(fontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

            var fontPath = "Fonts/irsans.ttf"; // مسیر فونت

            FontFactory.Register(fontPath);

            return FontFactory.GetFont(fontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        }

    }

}
نکته: حتما به تعریف فونت در پوشه‌ی Fonts و عکس‌ها در پوشه Images توجه فرمایید.

و در انتها نحوه‌ی استفاده از کلاس CardReport در یک برنامه‌ی Console: 
    class Program
    {
        static void Main(string[] args)
        {
            var userModel = new UserModel
            {
                FirstName = "علی",
                LastName = "احمدی",
                NationalCode = "1234567890",
                StudentNumber = "23242342",
                UniversityName = "آزاد",
                ImagePath = "Images/avatar.jpg"
            };

            CardReport.Generate(userModel, "Images/competition_logo.jpg", "Images/university_logo.png");

            System.Diagnostics.Process.Start("card.pdf");

        }
    }