برای طراحی گزارش شما میتوانید به سه روش این کار را انجام دهید.
1- طراحی در برنامه طراح گزارش
2- طراحی از داخل ویژوال استودیو
3- طراحی گزارش در زمان اجرا
برای شروع شما میتوانید نسخه آزمایشی این گزارشساز را دریافت کنید. تنها محدودیت این نسخه نمایش عبارت Demo در چاپ میباشد.
برنامه Designer را اجرا کنید. در صورتی که برای اولین بار است این برنامه را اجرا میکنید ابتدا باید رابط کاربری خود را انتخاب نمایید. نوار ابزار سمت چپ تمامی ابزارهای پرکاربرد طراحی گزارش را در اختیارتان قرار میدهد. ابزارهایی که در این بخش درباره آنها توضیح داده خواهد شد عبارتند از:
Header, Footer, Data, Page Header, Page Footer, Report Title, Report Summery
*به ابزارهای بالا Band گفته میشود.
Header , Footer :
همانطور که از نامشان پیداست در قسمت بالا و پایین بخشی از گزارش قرار میگیرند که برای استفاده در بالا و پایین بند Data میباشد. به عنوان مثال بند Header مناسب طراحی سرستونهای یک جدول میباشد و بند Footer هم جهت نمایش اطلاعات انتهایی یک جدول. ولی شما میتوانید با تنظیم خصوصیات هر بند رفتار و نمایش آنها را به طور کل تغییر دهید. نکته مثبت این گزارشساز این است که شما میتوانید بیش از یک واحد از هر بند را بر روی صفحه طراح خود قرار دهید، به عنوان مثال شما میتوانید دو بند Header داشته باشید که یکی در صفحات زوج و دیگری در صفحات فرد نمایش داده شود.
Data :
این بند جهت نمایش اطلاعات از منبع دادهها میباشد. به این معنا که به ازای هر سطر از دادهها یک بار این بخش نمایش داده میشود. تعداد دفعات نمایش این بند محدود به تعداد سطرهای منبع داده و یا اندازه صفحه و همچنین خصوصیت محدوده نمایش سطرها در یک صفحه میباشد.
Page Header , Page Footer :
این دو بند با توجه به نامشان جهت نمایش در بالا و پایین هر صفحه از گزارش میباشد. البته باز هم یادآور میشوم که با تغییر در خصوصیاتشان میتوانید رفتار و نحوه نمایش آنها را تغییر دهید.
Report Title :
این بند فقط در ابتدای گزارش نمایش داده خواهد شد.
Report Summery :
این بند بلافاصله بعد از اتمام گزارش نمایش داده خواهد شد.
مثال :
برای شروع در Designer یک گزارش جدید از نوع Blank Report ایجاد نمایید. سپس در پنل Dictionary بر روی New Item کلیک کرده و گزینه XML Data را انتخاب نمایید. با توجه به محل نصب گزارشساز وارد مسیر …\Bin\Data شده و فایلهای Demo.xsd و Demo.xml را برای قسمتهای مربوطه انتخاب نمایید. یک بار دیگر بر رو New Item کلیک کرده و گزینه New Data Source را انتخاب نمایید، از لیست ظاهر شده کانکشنی را که ایجاد کردهاید را انتخاب نمایید؛ نتیجه کار تا اینجا باید به صورت زبر باشد.
جدول Product را دراگ کرده و بر روی صفحه طراحی گزارش رها کنید. فرم Data ظاهر میشود این فرم را مطابق تصویر زیر تنظیم نمایید.
حال بر روی صفحه طراحی گزارش بندهای Header, Data, Footer مشاهده میشود؛ حال شما میتوانید با کلیک بر روی سربرگ Preview خروجی گزارش را ببینید.
توابع :
این گزارشساز دارای توابع بسیاری است که اکثر نیازهای شما را برطرف میکند به عنوان مثال تابع تبدیل عدد به حروف به زبان فارسی. همچنین شما میتوانید توابع خاص خود را ساخته و به صورت رفرنس به گزارش اضافه نمایید.
در این بخش ما از توابع موجود در گزارش استفاده خواهیم کرد. برای شروع بر روی کامپوننت Text در بند Footer زیر ستون UnitPrice دابل کلیک کرده تا فرم TextEditor ظاهر شود. سربرگ Summery را انتخاب نمایید. مطابق اطلاعات زیر بخشها را تنظیم نمایید.
Summery Function: Sum
Data Band: DataProducts
Data Column: Products.UnitPrice
حال بر روی سربرگ Preview
کلیک نمایید تا خروجی گزارش را ببینید. جمع ستون UnitPrice
فقط در صفحه آخر نمایش داده خواهد شد. اگر بخواهید جمع ستون در پایین هر صفحه
نمایش داده شود ابتدا باید خصوصیت Print on All Pages بند Footer به True
ست شود. سپس بر روی کامپوننت Text در بند Footer،
دابل کلیک نمایید و در فرم TextEditor
سربرگ Summery
تیک Running Total
را به حالت انتخاب شده در بیاورید، حال خروجی گزارش را ببینید، جمع در انتهای هر
صفحه ظاهر میشود.
متغیرها :
در این گزارش ساز دو نوع متغیر وجود دارد؛ نرمال و سیستمی. نوع سیستمی شامل متغیرهایی میشود که کاربرد مشخصی در تهیه گزارش دارند، مثل شماره صفحه، شماره ردیف، عنوان گزارش و ...
برای مثال شما میتوانید متغیر سیستمی Line را برای روی صفحه طراحی دراگ کنید. دو کامپوننت Text بر روی صفحه ایجاد میشود. اولی با محتوای Line و دومی با محتوای {Line}. اولی را به بند Header و دومی را به بند Data منتقل کنید و سپس خروجی گزارش را مشاهده نمایید، حال گزارش شما دارای شماره ردیف است.
متغیرهای نرمال تقریبا همانند متغیرهایی هستند که همه روزه شما در برنامههای خود از آنها استفاده میکنید. با کلیک بر روی New Item گزینه New Variable را انتخاب نمایید و نوع متغیر را Decimal انتخاب نمایید، سپس متغیر ایجاد شده را دراگ کرده و بروی صفحه طراحی قرار دهید و مشابه متغیر Line عمل کرده و کامپوننتهای Text را در بندهای مناسب قرار دهید. سپس بند Data بر روی صفحه طراحی را انتخاب نمایید، در پنل Properties بر روی Eventes کلیک کرده سپس در رویداد Rendering کد زیر را وارد نمایید.
Variable1 += Products.UnitPrice
حال در خروجی گزارش میتوانید مقادیر محاسبه
شده را ببینید. توجه داشته باشید که شما میتوانید در رویدادهای این گزارشساز به
زبان VB
و C#
برنامه نویسی کنید و محدود به یک خط کد نمیباشید.
شما میتوانید گزارش ساخته شده را به صورتهای مختلف ذخیره کنید از جمله کد C# و یا یک اپلیکیشن قابل اجرا.
در این قسمت بیشتر یک سری از ماژولها را به شما در قالب جداول گروه بندی شده معرفی خواهیم کرد :
همانطور که در قسمتهای قبلی گفتیم سرور IIS آماده خصوصی سازی و کار بر اساس علائق شماست؛ ولی توجه داشته باشید حذف تمامی ماژولها ممکن است اثرات جانبی هم داشته باشد. در اینجا ما ماژول هایی را به شما معرفی میکنیم که بدانید کار هر ماژول چیست تا مثلا با حذف ماژولی، امنیت وب سایت خود را به خطر نیندازید :
ماژولهای سودمند یا utility
نام ماژول: | UriCacheModule |
توضیح: | این ماژول نوعی کش برای URLها به شمار میرود. موقعی که url درخواست میشود، اطلاعات در اولین درخواست خوانده شده و کش میشود و اگر دوباره همان url درخواست شود، بدون خواندن تنظیمات و بر اساس تنظیمات قبلی، کار url مربوطه را انجام میدهد تا اطلاعات پیکربندی تغییر کند و بر اساس اطلاعات جدید، خود را به روز کند. |
تگ قابل پیکربندی: | لازم ندارد |
وابستگی: | ندارد |
اثرات حذف آن: | کارایی سیستم کاهش مییابد و سیستم مجبور است برای هر درخواست فایل پیکربندی را بخواند. |
نام ماژول : | FileCacheModule |
توضیح : | فایل هندلِ فایلهایی که قبلا در سرور باز شدهاند را کش میکند تا در صورت نیاز در دفعات بعدی سریعتر عمل کند. |
تگ قابل پیکربندی : | لازم ندارد . |
وابستگی : | ندارد. |
اثرات حذف آن : | کارایی سیستم کاهش مییابد. سیستم در هر اجرای دستور مربوط به فایلها باید فایل هندل را به دست آورد. |
نام ماژول : | TokenCacheModule |
توضیح : | توکنهای امنیتی ویندوز که پسوردهایی بر اساس authentication schemes هستند را کش میکند (anonymous authentication, basic authentication, IIS client certificate authentication ) |
تگ قابل پیکربندی : | لازم ندارد |
وابستگی : | ندارد |
اثرات حذف آن : | کارایی سیستم به شدت پایین میآید. کاربر باید با هر درخواستی لاگین کند. یکی از اصلیترین ضربهها با حذف این ماژول این است که اگر مثلا یک پسورد از یک فایل html محافظت میکند و این صفحه به 50 تصویر ارجاع دارد، 51 بار باید درخواست لاگین اجرا گردد یا شاید هم بدتر |
MANAGED ENGINE: ASP.NET INTEGRATION
نام ماژول : | ManagedEngine |
توضیح : | مدیریت ماژولهای native و مدیریت شده |
تگ قابل پیکربندی : | |
وابستگی : | ندارد |
اثرات حذف آن : | مشخصا غیرفعال شدن asp.net integrated و غیر فعال شدن تمامی ماژولها و هندلرهای تگ وب کانفیگ یا داخل فایل کانفیگ IIS که در مقالات قبلی به تفصیل بیان کردهایم. |
IIS 7 NATIVE MODULES
نام ماژول : | HttpCacheModule |
توضیح : | مدیریت کش خروجی در htttp.sys بر اساس پیکربندی مثل تعریف سایز کش و ... |
تگ قابل پیکربندی : | System.webServer/caching |
وابستگی : | ندارد. |
اثرات حذف آن : | محتوا دیگر به صورت کرنل مد، کش نمیشود و کش پروفایل هم ندید گرفته میشود و احتمالا بر کارآیی و استفاده از منابع هم اثر میگذارد. |
نام ماژول : | DynamicCompressionModule |
توضیح : | پیاده سازی in-memory compression در محتوای پویا |
تگ قابل پیکربندی : | system.webServer/httpCompression and system.webServer/urlCompression. |
وابستگی : | وابستگی ندارد چرا که به طور پیش فرض غیرفعال است. |
نام ماژول : | StaticCompressionModule |
توضیح : | پیادسازی فشرده سازی در محتوای ایستا و برای فایلهای سیستمی از نوع in memory |
تگ قابل پیکربندی : | system.webServer/httpCompression and system.webServer/urlCompression |
وابستگی : | ندارد. |
اثرات حذف آن : | در صورت عدم فشرده سازی بر مصرف ترافیک تاثیر گذار است. |
نام ماژول : | DefaultDocumentModule |
توضیح : | پیاده سازی یک لیست سند پیش فرض. درخواستها مدام پشت سر هم میآیند و این درخواستهای پشت سرهم، به سند پیش فرض هدایت میشوند. همان پنجره ای که شما به ترتیب فایلهای index.htm,index.asp,default.aspx و... را تعیین میکنید. |
تگ قابل پیکربندی : | system.webServer/defaultDocument |
وابستگی : | ندارد. |
اثرات حذف آن : | درخواست را به ریشه هدایت میکند. مثلا برای localhost صفحه 404 باز میگرداند و اگر directoryBrowsing فعال باشد لیستی از دایرکتوری ریشه را باز میگرداند. |
نام ماژول : | DirectoryListingModule |
توضیح : | پیادی سازی لیستی از محتویات یک دایرکتوری |
تگ قابل پیکربندی : | system.webServer/directoryBrowse |
وابستگی : | ندارد. |
اثرات حذف آن : | اگر این ماژول و ماژول قبلی غیرفعال باشند response نهایی خالی است. |
نام ماژول : | ProtocolSupportModule |
توضیح : | پیاده سازی اختصاصی از response header پیاده سازی تنظیمات trace و HTTP verbs. پیاده سازی تنظیمات مربوطه به keep-alive بر اساس پیکربندی |
تگ قابل پیکربندی : | system.webServer/httpProtocol |
وابستگی : | ندارد. |
اثرات حذف آن : | بازگرداندن پیام خطای "405 Method not allowed". |
نام ماژول : | HttpRedirectionModule |
توضیح : | پیاده سازی عملیات انتقال یا redirect |
تگ قابل پیکربندی : | system.webServer/httpRedirect |
وابستگی : | ندارد. |
اثرات حذف آن : | خطر امنیتی: اگر منابعی با redirect کردن محافظت میشوند، از این پس در دسترسند. |
نام ماژول : | ServerSideIncludeModule |
توضیح : | حمایت از فایل shtm یا shtml و ... |
تگ قابل پیکربندی : | system.webServer/serverSideInclude |
وابستگی : | ندارد. |
اثرات حذف آن : | این فایلها به صورت متنی نمایش داده میشوند |
نام ماژول : | StaticFileModule |
توضیح : | فایلهای ایستا را به همراه پسوند ارسال میکند. مثل jpg,html و نوع محتوا را بر اساس staticContent/mimeMap پیکربندی میکند. |
تگ قابل پیکربندی : | system.webServer/staticContent |
وابستگی : | ندارد. |
اثرات حذف آن : | فایلهای ایستا دیگر ارائه نشده و به جای آن خطای 404 بازگشت داده میشود. |
نام ماژول : | AnonymousAuthenticationModule |
توضیح : | پیاده سازی سیستم شناسایی افراد ناشناس. همانطور که میدانید در یک وب سایت حداقل محتوایی برای افرادی بدون داشتن اکانت هم وجود دارد. برای اینکار یک شیء httpuser ایجاد میکند. |
تگ قابل پیکربندی : | system.webServer/security/authentication/anonymousAuthentication |
وابستگی : | ندارد. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS میباشد و در صورت نبودن هیچ سیستم شناسایی وجود نداشته و در نبود شیء httpuser سیستم خطای 401.2 را تولید میکند. |
نام ماژول : | CertificateMappingAuthenticationModule |
توضیح : | مجوز SSL را به Active Directory نگاشت میکند. |
تگ قابل پیکربندی : | system.webServer/security/authentication/clientCertificateMappingAuthentication |
وابستگی : | برای اینکه این ماژول وظیفه خود را انجام دهد باید تنظیمات SSL انجام شود و همچنین سیستم IIS جزئی از دامنه Active directory باشد |
اثرات حذف آن : | درخواستها، نرمال رسیدگی میشوند انگار SSL وجود ندارد. |
نام ماژول : | BasicAuthenticationModule |
توضیح : | پیاده سازی پایهای و روتین شناسایی کاربران بر اساس آن چیزی که در استانداد زیر آمده است |
تگ قابل پیکربندی : | system.webServer/security/authentication/basicAuthentication |
وابستگی : | None. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناساسایی یا authenticate وجود داشته باشد. httpuser یک ساختار دادهای در IIS میباشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید میکند. |
نام ماژول : | WindowsAuthenticationModule |
توضیح : | ((windows Authentication (NTLM or Negotiate (Kerberos |
تگ قابل پیکربندی : | system.webServer/security/authentication/windowsAuthentication |
وابستگی : | ندارد. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS میباشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید میکند. |
نام ماژول : | DigestAuthenticationModule |
توضیح : | پیاده سازی سیستم شناسایی دیاجست بر اساس RFC 2617 . |
تگ قابل پیکربندی : | system.webServer/security/authentication/digestAuthentication |
وابستگی : | IIS باید بخشی از دامنه Active Directory باشد. |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد.
httpuser یک ساختار داده ای در IIS میباشد و در صورت نبود، هیچ سیستم
شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید
میکند. |
نام ماژول : | IISCertificateMappingAuthenticationModule |
توضیح : | پیاده سازی نگاشت مجوزهای IIS، نگهداری و ذخیره اطلاعات همه نگاشتها و مجوزهای کاربری چون SSL client certificates |
تگ قابل پیکربندی : | system.webServer/iisClientCertificateMappingAuthentication |
وابستگی : | اطلاعات SSL به همراه دریافت client certificates جهت پیکربندی این ماژول |
اثرات حذف آن : | حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد.
httpuser یک ساختار داده ای در IIS میباشد و در صورت نبود، هیچ سیستم
شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید
میکند. |
نام ماژول : | UrlAuthorizationModule |
توضیح : | پیاده سازی authorization بر اساس قوانین پیکربندی شده |
تگ قابل پیکربندی : | system.webServer/security/authorization |
وابستگی : | ندارد. |
اثرات حذف آن : | محتواهای محافظت شده توسط authorization دیگر محافظت نمیشوند. |
نام ماژول : | IsapiModule |
توضیح : | پیاده سازی ISAPI Extension |
تگ قابل پیکربندی : | system.webServer/isapiCgiRestriction |
وابستگی : | ندارد. |
اثرات حذف آن : | هندلرهای معرفی شده در بخش IsapiModule و تگ handlers دیگر اجرا نمیشوند |
نام ماژول : | IsapiFilterModule |
توضیح : | پیاده سازی ISAPI filter |
تگ قابل پیکربندی : | system.webServer/isapiFilters |
وابستگی : | ندارد. |
اثرات حذف آن : | اگر برنامه ای از ISAPI filter استفاده میکند، در اجرا دچار مشکل خواهد شد. |
نام ماژول : | IpRestrictionModule |
توضیح : | یک سیستم تشخیص دسترسی بر اساس آی پیهای ورژن4 |
تگ قابل پیکربندی : | system.webServer/security/ipSecurity |
وابستگی : | IPv4 stack باید نصب شود. |
اثرات حذف آن : | کلاینت هایی که IP هایشان در IPsecurity لیست شدهاند ندید گرفته میشوند |
نام ماژول : | RequestFilteringModule |
توضیح : | پیاده سازی یک مجموعه قدرتمند از قوانین امنیتی که درخواستهای مشکوک را پس میزند. |
تگ قابل پیکربندی : | system.webServer/security/requestFiltering |
وابستگی : | ندارد. |
اثرات حذف آن : | دیگر قوانین امنیتی اجرا نخواهند شد و سبب وجود مشکلات امنیتی میشود. |
نام ماژول : | CustomLoggingModule |
توضیح : | پیاده سازی اینترفیس ILogPlugin در سمت IIS، به مشتریان اجازه میدهد تا لاگهای خود را توسعه دهند. هر چند این روش توصیه نمیشود و توصیه کارشناس مایکروسافت استفاده از یک ماژول دست نویس از نوع RQ_LOG_REQUEST می باشد. Implements the ILogPlugin interface on top of IIS. ILogPlugin is a previous COM implementation that allowed customers to extend IIS logging. We do not not recommend extending IIS using this interface. Instead, customers should write a module and subscribe to the RQ_LOG_REQUEST notification. |
تگ قابل پیکربندی : | system.webServer/httpLogging and system.applicationhost/sites/site/logFile/customLogPluginClsid |
وابستگی : | ندارد. |
اثرات حذف آن : | مسلما پلاگینهایهای این اینترفیس از کار میافتند که سیستم ODBC Logging هم جز آن است. |
نام ماژول : | CustomErrorModule |
توضیح : | پیاده سازی مدیریت خطاهای ویژه |
تگ قابل پیکبرندی : | system.webServer/httpErrors |
وابستگی : | None. |
اثرات حذف آن : | در صورتی که خطایی از هسته باشد، نتیجه یک صفحه، با توضیح مختصری از خطا خواهد بود. در غیر این صورت اگر خطا از برنامه یا کامپوننتی باشد جزئیات خطا فاش خواهد شد |
نام ماژول : | HttpLoggingModule |
توضیح : | پیاده سازی سیستم logging استاندارد http.sys |
تگ قابل پیکربندی : | system.applicationHost/log and system.webServer/httpLogging |
وابستگی : | ندارد. |
اثرات حذف آن : | از کار افتادن سیستم لاگ |
نام ماژول : | FailedRequestsTracingModule |
توضیح : | پیاده سازی سیستم ردیابی درخواستهای ناموفق و اجرای قوانین، طبق پیکربندی |
تگ قابل پیکربندی : | system.webServer/tracing and system.webServer/httpTracing |
وابستگی : | ندارد. |
اثرات حذف آن : | Tracing http requests will no longer work. |
نام ماژول : | RequestMonitorModule |
توضیح : | پیاده سازی IIS Run-time State and Control Interface یا به اختصار RSCA . به کاربران اجازه میدهد از اطلاعات، حین اجرا، کوئری بگیرند. مثل درخواست درحال اجرای جاری، آغاز به کار یا توقف وب سایت و دامنههای اپلیکیشن در حال اجرای جاری |
تگ قابل پیکربندی : | ندارد. |
وابستگی : | ندارد. |
اثرات حذف آن : | ابزارهای مرتبط با این موضوع از کار میافتند |
نام ماژول : | CgiModule |
توضیح : | پیاده سازی CGI در سمت IIS |
تگ قابل پیکبرندی : | system.webServer/cgi and system.webServer/isapiCgiRestriction |
وابستگی : | ندارد. |
اثرات حذف آن : | برنامههای CGI متوقف میشوند |
نام ماژول : | TracingModule |
توضیح : | پیاده سازی سیستم ردیابی ETW |
تگ قابل پیکربندی : | system.webServer/httpTracing |
وابستگی : | ندارد. |
اثرات حذف آن : | باعث از کار افتادن سیستم مربوطه میشود |
نام ماژول : | ConfigurationValidationModule |
توضیح : | اعتبارسنجی تنظیمات برنامه ASP.Net که به حالت integrate انتقال یافته است |
تگ قابل پیکربندی : | system.webServer/Validation |
وابستگی : | ندارد. |
اثرات حذف آن : | عدم اعتبارسنجی و در نتیجه عدم نمایش خطاها |
MANAGED MODULES:
نام ماژول : | OutputCache |
توضیح : | پیاده سازی output caching |
تگ قابل پیکربندی : | system.web/caching/outputCache |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | عدم اجرای output cache |
نام ماژول : | Session |
توضیح : | مدیریت سشن ها |
تگ قابل پیکربندی : | system.web/sessionState |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | سشنها از دسترس خارج میشوند. |
نام ماژول : | WindowsAuthentication |
توضیح : | |
تگ قابل پیکربندی : | system.web/authentication |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | این حالت قابل اجرا نخواهد بود |
نام ماژول : | FormsAuthentication |
توضیح : | |
تگ قابل پیکربندی : | system.web/authentication |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | این حالت قابل اجرا نیست و کاربران مجوز دار هم نمیتوانند به منابع محافظت شده دسترسی داشته باشند. |
نام ماژول : | DefaultAuthentication |
توضیح : | اطمینان از وجود شی Authentication در context مربوطه |
تگ قابل پیکربندی : | system.web/authentication |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | اگر مد Forms authentication انتخاب شده باشد بر روی بعضی از کاربران ناشناس کار نخواهد کرد و رویداد DefaultAuthentication.OnAuthenticate اجرا نخواهد شد. |
نام ماژول : | RoleManager |
توضیح : | |
تگ قابل پیکربندی : | |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | این قابلیت در دسترس نمیباشد |
نام ماژول : | UrlAuthorization |
توضیح : | |
تگ قابل پیکربندی : | system.web/authorization. |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | باعث از کار افتادن asp.net authorization و فاش شدن بعضی اطلاعات و همچنین دیگر تهدیدات امنیتی |
نام ماژول : | AnonymousIdentification |
توضیح : | |
تگ قابل پیکربندی : | |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | The anonymous identification feature used by the ASP.NET Profile will not work. |
نام ماژول : | Profile |
توضیح : | |
تگ قابل پیکربندی : | |
وابستگی : | ManagedEngine module must be installed. |
اثرات حذف آن : | ASP.Net Profile از کار خواهد افتاد |
نام ماژول : | UrlMappingsModule |
توضیح : | تبدیل یک Url واقعی به یک Url کاربرپسند |
تگ قابل پیکبرندی : | |
وابستگی : | نیاز به ManagedEngine . |
اثرات حذف آن : | نگاشت Urlها صورت نمیگیرد |
بعد از اینکه به کنسول آن وارد شدید، کلمه cfx را در آن تایپ کنید تا راهنمای دستورات و سوییچهای آنها نمایش داده شوند. از این ابزار میتوان برای راه اندازی فایرفاکس و اجرای افزونه بر روی آن، پکیج کردن افزونه، دیدن مستندات و آزمونهای واحد استفاده کرد.
از دستور زیر در مسیر دایرکتوری افزونه برای اجرا و تست افزونه استفاده میکنیم:
cfx run
انتهای مطلب قسمت دوم برای اجرا و بسته بندی افزونه این مورد رو توضیح دادیم.
در ادامه مطالب مربوط به برنامه نویسی تابعی، قصد دارم بیشتر وارد کد شویم و مباحث عنوان شده را در دنیای کد پیاده سازی کنیم. هدف این قسمت، refactor کردن کد موجود به یک معماری immutable هست. پیشتر درباره immutable ها صحبت کردیم. ابتدا برای یکسان سازی ادبیات مورد استفاده، چند کلمه را مجددا تعریف خواهیم کرد:
- Immutability: عدم توانایی تغییر داده
- State: دادههایی که در طول زمان تغییر میکنند
- Side Effect: تغییری که روی دادهها اتفاق میافتد
در قطعه کد زیر سعی شدهاست تفاوت یک کلاس Stateless و stateful را به سادگی نشان دهیم:
//Stateful public class UserProfile { private User _user; private string _address; public void UpdateUser(int userId, string name) { _user = new User(userId, name); } } //Stateless public class User { public User(int id, string name) { Id = id; Name = name; } public int Id { get; } public string Name { get; } }
چرا Immutable بودن مهم است؟
هر عمل mutable معادل کدی غیر شفاف است. در واقع وابستگی هر عملی که انجام میدهیم به state، باعث میشود که شرایط ناپایداری را در کد داشته باشیم. به طور مثال در یک عملیات چند نخی تصور کنید که چندین نخ به طور همزمان میتوانند state را تغییر دهند و مدیریت این قضیه باعث به وجود آمدن کدهایی ناخوانا و تحمیل پیچیدگی بیشتر به کد خواهد شد.
در واقع انتظار داریم که به ازای یک ورودی بر اساس بدنهی متد، یک خروجی داشته باشیم؛ ولی در واقعیت تاثیری که اجرای متد بر روی state کل کلاس خواهد گذاشت، از دید ما پنهان است و باعث به وجود آمدن مشکلات بعدی خواهد شد. برای مثال قطعه کد بالا را به صورت Honest بازنویسی میکنیم:
public class UserProfile { private readonly User _user; private readonly string _address; public UserProfile(User user,string address) { _user = user; _address = address; } public UserProfile UpdateUser(int userId, string name) { var newUser = new User(userId, name); return new UserProfile(newUser,_address); } } public class User { public User(int id, string name) { Id = id; Name = name; } public int Id { get; } public string Name { get; } }
در این مثال متد UpdateUser به جای void، یک شی از جنس کلاس UserProfile را بر میگرداند. کلاس UserProfile هم برای وهله سازی نیاز به یک شیء از جنس User و Address را دارد. بنابراین مطمئن هستیم که مقدار دهی شدهاند. نکته دیگر در قطعه کد بالا این است که به ازای هر بار فراخوانی متد، یک شیء جدید بدون وابستگی به وهله سازی اشیاء دیگر، برگردانده میشود.
Immutable
بودن باعث میشود:
- خوانایی کد افزایش پیدا کند
- جای واحدی برای Validate کردن داشته باشیم
- به صورت ذاتی Thread Safe باشیم
در مورد محدودیتهایی که در کار با اشیاء Immutable باید در نظر داشته باشیم، میتوان به مصرف بالای رم و سی پی یو، اشاره کرد. در واقع به نسبت حالت mutate، تعداد اشیاء بیشتری ساخته خواهند شد. در فریمورک دات نت برای کار با اشیا immutable امکاناتی در نظر گرفته شده که این هزینه را کاهش میدهند. به طور مثال میتوانیم از کلاس ImmutableList استفاده کنیم و از ایجاد اشیاء اضافهتر و تحمیل بار اضافی به GC جلوگیری کنیم. یک مثال:
//Create Immutable List ImmutableList<string> list = ImmutableList.Create<string>(); ImmutableList<string> list2 = list.Add("Salam"); //Builder ImmutableList<string>.Builder builder = ImmutableList.CreateBuilder<string>(); builder.Add("avali"); builder.Add("dovomi"); builder.Add("sevomi"); ImmutableList<string> immutableList = builder.ToImmutable();
چطور با side effect کنار بیایم؟
یکی از الگوهای رایج برای این کار، مفهوم جدا سازی Command/Query است. به طور ساده تمامی عملیاتی را که تاثیر گذار هستند، به صورت Command در نظر میگیریم. Command ها معمولا هیچ نوعی را بازگشت نمیدهند و همینطور بر عکس این قضیه برای Query ها صادق است. اشتباه رایج درباره این الگو، محدود کردن این الگو به معماریهای خاصی مانند Domain Driven میباشد؛ در صورتیکه الزامی برای رعایت این الگو در سایر معماریها وجود ندارد.
به مثال زیر دقت کنید. سعی کردم قسمتهای Command و Query را از هم جدا کنم:
در واقع هر برنامه میتواند شامل دو قسمت باشد:
قسمتی که در آن منطق تجاری برنامه پیاده سازی میشود و باید به صورت Immutable
باشد که یک خروجی را تولید میکند و قسمت دیگر برنامه که خروجی تولید شده را برای ذخیره
سازی وضعیت سیستم استفاده میکند.
در واقع یک هسته Immutable، ورودی را دریافت کرده و خروجیهای مورد نیاز را تولید میکند و همه اینها در دل یک پوستهMutable پیاده سازی میشوند که ما در اینجا به آن اصطلاحا Mutable Shell میگوییم.
برای مسائلی که در بالا صحبت شد، نمونهای را آماده کردهام. این نمونه به طور ساده یک سیستم مدیریت نوبت است که نوبتها را در فایلی ذخیره و بازیابی میکند ( mutate ) و منطق مربوط به نوبتها و زمان ویزیت آن میتواند به صورت immutable پیاده سازی شود. این کد در دو حالت functional و غیر functional پیاده سازی شده تا به خوبی تفاوت آن را در حالت قبل و بعد از برنامه نویسی تابعی بتوانیم درک کنیم. به جهت خوانایی بیشتر و دسترسی به کدها، آنها را روی گیتهاب قرار داده و شما میتوانید از اینجا سورس کد مورد نظر را بررسی کنید. سعی شده در این مثال تمامی مواردی که در این قسمت ذکر شد را پیاده سازی کنیم. امیدوارم که مطالب مربوط به برنامه نویسی تابعی یا functional programming توانسته باشد دیدگاه جدیدی را به کدهایی که مینویسیم بدهد. در قسمتهای بعدی به مواردی مانند مدیریت exception ها و کار با null ها و ... خواهیم پرداخت.
معرفی Xamarin و مزیتهای استفاده از آن
معرفی meteor
dotnet new -i FeatherHttp.Templates::0.1.67-alpha.g69b43bed72 --nuget-source https://f.feedz.io/featherhttp/framework/nuget/index.json
Templates Short Name Language Tags ---------------------------------------------------------------------------------------------------------------------------------- FeatherHttp feather [C#] Web/ASP.NET/FeatherHttp
dotnet new feather --name todoAPI
همانطور که مشاهده میکنید پروژهی فوق تنها شامل دو فایل .csproj و Program.cs است. درون Program.cs و متد Main کار initialize کردن سرور HTTP صورت گرفته است. WebApplication.Create دقیقا همانند Host.CreateDefaultBuilder پروژههای ASP.NET Core عمل میکند؛ یعنی پیکربندی pipeline از قبیل اضافه کردن متغیرهای محیطی، خواندن از فایل JSON و ... را انجام میدهد اما با کد boilerplate کمتر. بنابراین خروجی WebApplication.Create یک ASP.NET Core Pipeline با قابلیت اضافه کردن تنظیمات دلخواه است. در ادامه جهت بررسی بیشتر Feather HTTP، یک مدل را به همراه یک سری دیتای In-memory به پروژه اضافه خواهیم کرد:
using System.Collections.Generic; using System.Text.Json.Serialization; using System.Linq; namespace todoAPI.Models { public class Todo { [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("title")] public string Title { get; set; } [JsonPropertyName("completed")] public bool Completed { get; set; } } public class TodoData { private readonly IList<Todo> _db = new List<Todo> { new Todo { Id = 1, Title = "Read book" }, new Todo { Id = 2, Title = "Watch an episode of Dark" }, new Todo { Id = 3, Title = "Publish a post on dotnettips" }, new Todo { Id = 4, Title = "Skype with my friend" }, }; public IList<Todo> GetAllToDoItmes() { return _db; } public void AddTodo(Todo item) { _db.Add(item); } public void ToggleTodo(int id) { var todo = _db.FirstOrDefault(x => x.Id == id); todo.Completed = !todo.Completed; } public void DeleteTodo(int id) { var todo = _db.FirstOrDefault(x => x.Id == id); _db.Remove(todo); } } }
در مثال فوق برای نگاشت نام خواص، از System.Text.Json توکار NET Core 3.0. استفاده شدهاست. در ادامه نیز از یک کلاس برای شبیهسازی CRUD یک Todo استفاده شدهاست. سپس برای داشتن اندپوینتهای موردنظر به ازای هر کدام از متدهای فوق درون متد Main، از app.Map... استفاده کردهایم:
using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using todoAPI.Models; namespace todoAPI { class Program { private static readonly TodoData db = new TodoData(); static async Task Main(string[] args) { var app = WebApplication.Create(args); app.MapGet("/", GetTodos); app.MapPost("/api/todos", CreateTodo); app.MapPost("/api/todos/{id}", ToggleTodo); app.MapDelete("/api/todos/{id}", DeleteTodo); await app.RunAsync(); } static async Task GetTodos(HttpContext http) { var todos = db.GetAllToDoItmes(); await http.Response.WriteJsonAsync(todos); } static async Task CreateTodo(HttpContext http) { var todo = await http.Request.ReadJsonAsync<Todo>(); db.AddTodo(todo); http.Response.StatusCode = 204; } static async Task ToggleTodo(HttpContext http) { if (!http.Request.RouteValues.TryGet("id", out int id)) { http.Response.StatusCode = 400; return; } db.ToggleTodo(id); http.Response.StatusCode = 204; } static async Task DeleteTodo(HttpContext http) { if (!http.Request.RouteValues.TryGet("id", out int id)) { http.Response.StatusCode = 400; return; } db.DeleteTodo(id); http.Response.StatusCode = 204; } } }
هر کدام از اندپوینتهای فوق، یک ورودی HttpContext دریافت خواهند کرد. توسط این شیء میتوانیم به درخواست جاری و همچنین به پاسخ درخواست، دسترسی داشته باشیم.
استفاده از سیستم DI توکار NET Core.
همانطور که در ابتدای مطلب نیز عنوان شد، Feather HTTP یک wrapper بر روی APIهای موجود ASP.NET Core است، بنابراین میتوانیم از همان سرویس DI که درون پروژههای ASP.NET Core در اختیار داریم در اینجا نیز استفاده کنیم. در ادامه یک پوشهی جدید را به مثال قبل، با نام Controllers اضافه خواهیم کرد و درون آن یک فایل TodoController را با محتویات زیر ایجاد خواهیم کرد:
using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using todoAPI.Models; using todoAPI.Services; namespace todoAPI.Controllers { public class TodoController { private readonly ITodoService _todoService; public TodoController(ITodoService todoService) { _todoService = todoService; } public async Task GetTodos(HttpContext http) { var todos = _todoService.GetAllToDoItmes(); await http.Response.WriteJsonAsync(todos); } public async Task CreateTodo(HttpContext http) { var todo = await http.Request.ReadJsonAsync<Todo>(); _todoService.AddTodo(todo); http.Response.StatusCode = 204; } public async Task ToggleTodo(HttpContext http) { if (!http.Request.RouteValues.TryGet("id", out int id)) { http.Response.StatusCode = 400; return; } _todoService.ToggleTodo(id); http.Response.StatusCode = 204; } public async Task DeleteTodo(HttpContext http) { if (!http.Request.RouteValues.TryGet("id", out int id)) { http.Response.StatusCode = 400; return; } _todoService.DeleteTodo(id); http.Response.StatusCode = 204; } } }
کاری که انجام شده است، انتقال تمامی متدهای static به کلاس فوق و سپس جایگزین کردن کلمهی کلیدی static با public است. همچنین یه ارجاع به اینترفیس جدید با عنوان ITodoService اضافه شده است؛ درون پیادهسازی این اینترفیس همان متدهای کلاس TodoData را اضافه کردهایم:
using System.Collections.Generic; using todoAPI.Models; using System.Linq; namespace todoAPI.Services { public interface ITodoService { void AddTodo(Todo item); void DeleteTodo(int id); IList<Todo> GetAllToDoItmes(); void ToggleTodo(int id); } public class TodoService : ITodoService { private readonly IList<Todo> _db = new List<Todo> { new Todo { Id = 1, Title = "Read book" }, new Todo { Id = 2, Title = "Watch an episode of Dark" }, new Todo { Id = 3, Title = "Publish a post on dotnettips" }, new Todo { Id = 4, Title = "Skype with my friend" }, }; public IList<Todo> GetAllToDoItmes() { return _db; } public void AddTodo(Todo item) { _db.Add(item); } public void ToggleTodo(int id) { var todo = _db.FirstOrDefault(x => x.Id == id); todo.Completed = !todo.Completed; } public void DeleteTodo(int id) { var todo = _db.FirstOrDefault(x => x.Id == id); _db.Remove(todo); } } }
نکته: برای ایجاد اینترفیس از روی یک کلاس درون VS Code میتوانیم اینگونه عمل کنیم:
تغییرات فایل Program.cs
ابتدا باید using مربوط به DI را در ابتدای فایل اضافه کنیم:
using Microsoft.Extensions.DependencyInjection;
سپس توسط ServiceProvider یک وهله از کلاس موردنظر را ایجاد کردهایم و همچنین سرویسهای موردنظر را درون DI Container اضافه کردهایم:
using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using todoAPI.Controllers; using todoAPI.Services; namespace todoAPI { class Program { static async Task Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddTransient<TodoController>(); builder.Services.AddTransient<ITodoService, TodoService>(); var serviceProvider = builder.Services.BuildServiceProvider(); var todoController = serviceProvider.GetService<TodoController>(); var app = WebApplication.Create(args); app.MapGet("/", todoController.GetTodos); app.MapPost("/api/todos", todoController.CreateTodo); app.MapPost("/api/todos/{id}", todoController.ToggleTodo); app.MapDelete("/api/todos/{id}", todoController.DeleteTodo); await app.RunAsync(); } } }
Convention Over Configuration
در کد قبلی به صورت دستی TodoController را توسط Service Location از DI درخواست کردهایم. اینکار را در ادامه میتوانیم به Feather HTTP سپرده تا کار وهلهسازی را براساس قواعد توکار برایمان انجام دهد:
using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using todoAPI.Services; namespace todoAPI { class Program { static async Task Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); builder.Services.AddControllers(); builder.Services.AddSingleton<ITodoService, TodoService>(); var serviceProvider = builder.Services.BuildServiceProvider(); var app = builder.Build(); app.MapControllers(); await app.RunAsync(); } } }
سپس در ادامه برای دسترسی به HTTP Context درون TodoController از IHttpContextAccessor استفاده کردهایم:
using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using todoAPI.Models; using todoAPI.Services; namespace todoAPI.Controllers { public class TodoController { private readonly ITodoService _todoService; private readonly IHttpContextAccessor _accessor; public TodoController(ITodoService todoService, IHttpContextAccessor accessor) { _todoService = todoService; _accessor = accessor; } [HttpGet("/todos")] public async Task GetTodos() { var todos = _todoService.GetAllToDoItmes(); await _accessor.HttpContext.Response.WriteJsonAsync(todos); } [HttpPost("/todos")] public async Task CreateTodo() { var todo = await _accessor.HttpContext.Request.ReadJsonAsync<Todo>(); _todoService.AddTodo(todo); _accessor.HttpContext.Response.StatusCode = 204; } [HttpPost("/todos/{id}")] public async Task ToggleTodo(int id) { _todoService.ToggleTodo(id); _accessor.HttpContext.Response.StatusCode = 204; } [HttpDelete("/todos/{id}")] public async Task DeleteTodo(int id) { _todoService.DeleteTodo(id); _accessor.HttpContext.Response.StatusCode = 204; } } }
کدهای کامل مطلب را میتوانید از اینجا دریافت کنید.
معرفی Aspect oriented programming
AOP یکی از فناوریهای مرتبط با توسعه نرم افزار محسوب میشود که توسط آن میتوان اعمال مشترک و متداول موجود در برنامه را در یک یا چند ماژول مختلف قرار داد (که به آنها Aspects نیز گفته میشود) و سپس آنها را به مکانهای مختلفی در برنامه متصل ساخت. عموما Aspects، قابلیتهایی را که قسمت عمدهای از برنامه را تحت پوشش قرار میدهند، کپسوله میکنند. اصطلاحا به این نوع قابلیتهای مشترک، تکراری و پراکنده مورد نیاز در قسمتهای مختلف برنامه، Cross cutting concerns نیز گفته میشود؛ مانند اعمال ثبت وقایع سیستم، امنیت، مدیریت تراکنشها و امثال آن. با قرار دادن این نیازها در Aspects مجزا، میتوان برنامهای را تشکیل داد که از کدهای تکراری عاری است.
مثالی از کدهای تکراری پراکنده در برنامه
به برنامه ذیل و قسمتهای مختلف ثبت وقایع آن دقت کنید:
using System; namespace AOP00 { class Program { static void Main(string[] args) { Log.Debug("Program has started."); //..... try { } catch (Exception ex) { Log.Error(ex); throw; } finally { //..... Log.Debug("Program has ended."); } } } }
معرفی Aspects و مزایای استفاده از آنها
همانطور که عنوان شد اولین گام در AOP، کپسوله سازی کدهای تکراری است که اصطلاحا یک Aspect را تشکیل میدهند. بنابراین هر Aspect صرفا یک محصور کننده قابلیتی خاص و تکراری در برنامه است. این Aspect باید اصل SRP یا Single responsibility principle (تک مسئولیتی) را رعایت کند. برای اتصال یک Aspect به قطعههای مختلف کدهای برنامه از الگوی طراحی تزئین کننده یا Decorator pattern استفاده میشود. به این ترتیب که این Aspect خاص قرار است قسمتی از کدهای برنامه را تزئین کند. همچنین در این حالت، open closed principle نیز بهتر رعایت خواهد گردید. از این جهت که کدهای تکراری برنامه، به Aspects منتقل شدهاند و دیگر نیازی نیست برای تغییر آنها، کدهای قسمتهای مختلف را تغییر داد (کدهای برنامه باز خواهند بود برای توسعه و بسته برای تغییر). بنابراین با استفاده از Aspects، به یک طراحی شیءگرای بهتر نیز دست خواهیم یافت.
مراحل اجرای یک Aspect
هر Aspect برای تزئین یا اتصال به قسمتهای مختلف برنامه، یک طول عمر کاری مشخص را طی میکند:
الف) مرحله OnStart
public User GetUserById(int id) { if (Cache.ExistsFor(id)) { return Cache[id]; } else { var user = LoadFromDb(id); Cache.AddFor("User", id, user); return user; } }
برای مثال در متد GetUserById، پیش از اینکه کار به مراجعه به بانک اطلاعاتی برسد، ابتدا وضعیت کش سیستم بررسی میشود. بنابراین در این مثال میتوان قسمت بررسی کش را به یک Aspect مجزا منتقل ساخته و در صورتیکه اطلاعاتی موجود بود، بازگشت داده شود؛ در غیر اینصورت مجوز اجرای ادامه کدها صادر گردد.
ب) مرحله OnSuccess
مرحله OnSuccess زمانی اجرا میشود که اجرای یک متد بدون بروز استثنایی خاتمه یافته است.
ج) مرحله OnExit
مرحله OnExit همانند مرحله OnSuccess است؛ با این تفاوت که مرحله OnSuccess در صورت بروز استثنایی در کدها اجرا نخواهد شد اما مرحله OnExit همواره در پایان کار یک متد فراخوانی میگردد.
د) مرحله OnError
مرحله OnError در طول عمر یک Aspect، در زمان بروز استثنایی رخ میدهد. برای مثال به این ترتیب میتوان قسمت ثبت وقایع بروز استثناهای سیستم را کلا به یک Aspect مشخص انتقال داده و حجم کدهای تکراری را به این ترتیب به شدت کاهش داد.
انواع مختلف AOP
تا اینجا شاید این سؤال برای شما پیش آمده باشد که خوب! جالب است! اما چطور میخواهید در مراحلی که یاد شد، دخالت کرده و قطعه کدی را تزریق کنید؟
در AOP دو روش متداول کلی برای انجام اعمال تزریق کد وجود دارند:
1) استفاده از Interceptors
به کمک Interceptors، فرآیند فراخوانی متدها و خواص یک کلاس، تحت کنترل و نظارت قرار خواهند گرفت. برای انجام این امر، عموما از IOC Containers استفاده میشود (Inversion of control). احتمالا تا کنون از این کتابخانهها تنها برای تزریق وابستگیهای برنامه خود کمک گرفتهاید و از سایر توانمندیهای آنها آنچنان استفادهای نکردهاید. در این حالت، زمانیکه یک IOC Container کار وهله سازی کلاس خاصی را انجام میدهد، در همین حین میتواند مراحل یاد شده شروع، پایان و خطای متدها یا فراخوانیهای خواص را نیز تحت نظر قرار داده و به این ترتیب مصرف کننده امکان تزریق کدهایی را در این مکانها خواهد یافت.
مزیت مهم استفاده از Interceptors، عدم نیاز به کامپایل و یا تغییر ثانویه اسمبلیهای موجود برای تغییری در کدهای آنها است (برای تزریق نواحی تحت کنترل قرار دادن اعمال) و تمام کارها به صورت خودکار در زمان اجرای برنامه مدیریت میگردند.
2) بهره گیری از فناوری IL Code Weaving
در فناوی IL Code Weaving، ابتدا برنامه و ماژولهای آن به نحو متداولی کامپایل و تبدیل به dll یا exe خواهند شد. سپس این dllها و فایلهای اجرایی به پردازشگر ثانویه یک فریم ورک AOP برای تغییر و تزریق کدها سپرده خواهند شد. برای مثال در این حالت، کدهای سطح پایین IL مرتبط با مراحل مختلف اجرای یک Aspect، تولید و به اسمبلیهای نهایی برنامه تزریق میشوند. اکنون به dll یا فایل اجرایی جدیدی خواهیم رسید که علاوه بر کدهای اصلی برنامه، حاوی کدهای تزریق شده تمام Aspects تعریف شده نیز هستند.