فعلا برای ارتقاء به دات نت 4.6 عجله نکنید
<configuration> <runtime> <useLegacyJit enabled="1" /> </runtime> </configuration>
در مطلب قبلی (در مورد کتابخانه anti-xss مایکروسافت) از روش xml serialization برای خواندن فایل xml حملات استفاده کردیم.
ایجاد این کلاس و نگاشت اشیاء با توجه به ساختار ساده آن به صورت دستی و بهسادگی انجام شد. اکنون به مثال زیر دقت بفرمائید:
سرویس آب و هوای یاهو برای شهرهای مختلف ایران از طریق لینک زیر قابل استفاده است:
http://weather.yahoo.com/regional/IRXX.html
اگر به صفحات شهرهای مختلف مراجعه نمائید، یک فید rss هم مشاهده خواهید کرد، برای مثال در مورد تهران داریم:
http://weather.yahooapis.com/forecastrss?p=IRXX0018&u=c
ساختار این فایل xml تا حدودی با یک rss استاندارد تطابق دارد. اما اگر به سورس xml آن دقت کنیم تگهای دیگری را نیز مشاهده خواهیم کرد که برای مثال دما ، تاریخ و شرایط جوی را به صورت دقیقی و با استفاده از اصول xml ارائه میدهند.
<yweather:condition text="Partly Cloudy" code="29" temp="10" date="Tue, 11 Nov 2008 5:30 pm IRT" />
روش بالا هر چند مشکلی ندارد اما به زیبایی کار با خواص یک کلاس متناظر با آن فایل xml نیست. اما در اینجا برای استفاده از روش xml serialization یک مشکل وجود دارد! ایجاد دستی این کلاس که بیانگر عملکرد آن فایل xml است کار سادهای نیست.
خوشبختانه به همراه SDK دات نت فریم ورک 2، برنامهای به نام xsd.exe نیز همراه است که کار ایجاد یک کلاس cs یا vb را از یک فایل xml جهت این منظور انجام میدهد (این برنامه برای مثال در مسیر C:\Program Files\Microsoft.NET\SDK\v2.0\Bin قرار دارد).
برای ایجاد فایل کلاس به صورت خودکار از روی یک فایل xml موجود باید به ترتیب زیر عمل کرد:
الف) ایجاد فایل xsd متناظر (XML Schema Definition)
برای اینکار در خط فرمان تایپ کنید:
xsd.exe file.xml
روش دیگر انجام این کار : فایل xml را در VS.net باز کنید، از منوی بالای صفحه گزینه xml را انتخاب نموده و بر روی دکمه Create Schema کلیک کنید.
ب) ایجاد فایل cs یا vb از روی فایل(های) xsd ایجاد شده
در اینجا برای فید آب و هوای یاهو سه فایل xsd تولید خواهد شد. برای تبدیل آنها به کلاس cs باید دستور زیر را در خط فرمان اجرا کرد:
Xsd.exe file_1.xsd file_2.xsd file_3.xsd /c
نکته 2:
برای انتخاب زبان VB (با توجه به اینکه پیش فرض آن CS است) میتوان به صورت زیر عمل کرد:
xsd.exe file.xsd /c /l:vb
برای تولید فایل xsd ، از برنامه Infer.exe نیز میتوان استفاده کرد (خروجی نهایی دقیقتری را ارائه میدهد). این برنامه را از اینجا دریافت کنید.
تصاویر زیر مقایسه دو فایل کلاس نهایی تولید شده از xsd های این دو برنامه است:
پس از طی این مراحل فایل کلاس ما برای xml serialization آماده خواهد شد. مرحله بعد دریافت اطلاعات و نگاشت آن به این کلاس تولید شده است:
public static rss DeserializeFromXML()
{
XmlSerializer deserializer =
new XmlSerializer(typeof(rss));
using (XmlReader reader = XmlReader.Create("http://weather.yahooapis.com/forecastrss?p=IRXX0018&u=c"))
{
return (rss)deserializer.Deserialize(reader);
}
}
اکنون برای مثال خواندن وضعیت فعلی جوی از فید دریافتی به سادگی زیر است:
rss data = DeserializeFromXML();
MessageBox.Show(data.channel.item.condition.text);
ASP.NET MVC #23
اجرای برنامههای ASP.NET MVC توسط نگارشهای متفاوت IIS
تا اینجا برای اجرای برنامههای ASP.NET MVC از وب سرور توکار VS.NET استفاده شد که صرفا جهت آزمایش برنامهها طراحی شده است. تا این تاریخ سه رده از وب سرورهای مایکروسافت ارائه شدهاند که برای نصب ASP.NET MVC میتوانند مورد استفاده قرار گیرند و هر کدام هم نکتههای خاص خودشان را دارند که در ادامه به بررسی آنها خواهیم پرداخت.
اجرای برنامههای ASP.NET MVC بر روی IIS 5.x ویندوز XP
پس از ایجاد یک دایرکتوری مجازی بر روی پوشه یک برنامه ASP.NET MVC و سعی در اجرای برنامه، بلافاصله پیغام خطای HTTP 403 forbidden مشاهده میشود.
اولین کاری که برای رفع این مساله باید صورت گیرد، کلیک راست بر روی نام دایرکتوری مجازی در کنسول IIS، انتخاب گزینه خواص و سپس مراجعه به برگه «ASP.NET» آن است. در اینجا شماره نگارش دات نت فریم ورک مورد استفاده را به 4 تغییر دهید (برای نمونه ASP.NET MVC 3.0 مبتنی بر دات نت فریم ورک 4 است).
بعد از این تغییر، بازهم موفق به اجرای برنامههای ASP.NET MVC بر روی IIS 5.x نخواهیم شد؛ چون در آن زمان مفاهیم مسیریابی و Routing که اصل و پایه ASP.NET MVC هستند وجود خارجی نداشتند. این نگارش از IIS به صورت پیش فرض تنها قادر به پردازش درخواستهای رسیدهای که به یک فایل فیزیکی بر روی سرور اشاره میکند، میباشد (یعنی مشکلی با اجرای برنامههای ASP.NET Web forms ندارد).
برای رفع این مشکل، مجددا بر روی نام دایرکتوری مجازی برنامه در کنسول IIS کلیک راست کرده و گزینه خواص را انتخاب کنید. در صفحه ظاهر شده، در برگه «Virtual directory» آن، بر روی دکمه «Configuration» کلیک نمائید. در صفحه باز شده مجددا بر روی دکمه «Add» کلیک کنید.
در صفحه باز شده، مسیر Executable را C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll وارد کرده و Extension را به .* (دات هرچی) تنظیم کنید. همین مقدار تنظیم، برای اجرای برنامههای ASP.NET MVC بر روی IIS 5.x ویندوز XP کفایت میکند.
کاری که در اینجا انجام شده است، نگاشت تمام درخواستهای رسیده صرفنظر از پسوند فایلها، به موتور ASP.NET میباشد. به صورت پیش فرض در IIS 5.x درخواستها تنها بر اساس پسوند فایلها پردازش میشوند. مثلا اگر فایل درخواستی aspx است، درخواست رسیده به aspnet_isapi.dll یاد شده هدایت خواهد شد. اگر پسوند فایل php است به isapi مخصوص آن (در صورت نصب) هدایت میگردد و به همین ترتیب برای سایر سیستمهای دیگر. زمانیکه Extension به «دات هرچی» و Executable به aspnet_isapi.dll دات نت 4 تنظیم میشود، دایرکتوری مجازی تنظیم شده تنها جهت سرویس دهی به یک برنامه ASP.NET عمل خواهد کرد و تمام درخواستهای رسیده به آن، به موتور اجرایی ASP.NET هدایت میشوند.
بدیهی است تنظیمات فوق تنها به یک دایرکتوری مجازی اعمال شدند. اگر نیاز باشد تا بر روی تمام سایتها تاثیر گذار شود، اینبار در کنسول IIS 5.x بر روی «Default web site» کلیک راست کرده و گزینه خواص را انتخاب کنید. در صفحه باز شده به برگه «Home directory» مراجعه کرده و مراحل ذکر شده را تکرار کنید.
مشکل! این روش بهینه نیست.
روش فوق خوبه، کار میکنه، اما بهینه نیست؛ از این جهت که «نگاشت تمام درخواستها به موتور ASP.NET» یعنی پروسه پردازش درخواست یک فایل تصویری، js یا css هم باید از فیلتر موتور ASP.NET عبور کند که ضروری نیست.
برای رفع این مشکل، توصیه شده است که سیستم مسیریابی ASP.NET MVC را در IIS 5.x «پسوند دار» کنید. به این نحو که با مراجعه به فایل Global.asax.cs، تعاریف مسیریابی را به نحو زیر ویرایش کنید:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(
new Route("{controller}.aspx/{action}/{id}", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
})
});
اینبار برای مثال مسیر http://localhost/MyMvcApp/home.aspx/index به علت داشتن پسوند aspx وارد موتور پردازشی ASP.NET خواهد شد. البته در این حالت URL های تمیز ASP.NET MVC را از دست خواهیم داد و مدام باید دقت داشت که مسیرهای کنترلرها حتما باید به aspx ختم شوند. ضمنا با این تنظیم، دیگر نیازی به تغییر تعاریف نگاشتها در کنسول مدیریتی IIS، نخواهد بود.
اجرای برنامههای ASP.NET MVC بر روی IIS 6.x ویندوز سرور 2003
تمام نکات عنوان شده جهت IIS 5.x در IIS 6.x نیز صادق هستند. به علاوه برای اجرای برنامههای ASP.NET بر روی IIS 6.x باید به دو نکته مهم دیگر نیز دقت داشت:
الف) ASP.NET 4 به صورت پیش فرض در IIS 6.x غیرفعال است که باید با مراجعه به قسمت Web Services Extensions در کنسول مدیریتی IIS، آنرا از حالت prohibited خارج کرد.
ب) در هر Application pool تنها از یک نگارش دات نت فریم ورک میتوان استفاده کرد. برای مثال اگر هم اکنون AppPool1 مشغول سرویس دهی به یک سایت ASP.NET 3.5 است، از آن نمیتوانید جهت اجرای برنامههای ASP.NET MVC 3 به بعد استفاده کنید. زیرا برای مثال ASP.NET MVC 3 مبتنی بر دات نت فریم ورک 4 است. به همین جهت حتما نیاز است تا یک Application pool مجزا را برای برنامههای دات نت 4 در IIS 6 اضافه نمائید و سپس در تنظیمات سایت، از این Application pool جدید استفاده نمائید.
البته روش صحیح و اصولی کار با IIS از نگارش 6 به بعد هم مطابق شرحی است که عنوان شد. برای دستیابی به بهترین کارآیی و امنیت بیشتر، بهتر است به ازای هر سایت، از یک Application pool مجزا استفاده نمائید.
اطلاعات تکمیلی:
نکات نصب برنامههای ASP.NET 4.0 بر روی IIS 6
مروری بر تاریخچه محدودیت حافظه مصرفی برنامههای ASP.NET در IIS
اجرای برنامههای ASP.NET MVC بر روی IIS 7.x ویندوز 7 و ویندوز سرور 2008
اگر برنامه ASP.NET MVC در IIS 7.x در حالت یکپارچه (integrated mode) اجرا شود، بدون نیاز به هیچگونه تغییری در تنظیمات سرور یا برنامه، بدون مشکل قابل اجرا خواهد بود. بدیهی است در اینجا نیز بهتر است به ازای هر برنامه، یک Application pool مجزا را ایجاد کرد.
اما در حالت classic (که برای برنامههای جدید توصیه نمیشود) نیاز است همان مراحل IIS 5,x تکرار شود. البته اینبار مسیر زیر را باید طی کرد تا به صفحه افزودن نگاشتها رسید:
Right-click on a web site -> Properties -> Home Directory tab -> click on the Configuration button -> Mappings tab
نکتهای مهم در تمام نگارشهای IIS
ترتیب نصب دات نت فریم ورک 4 و IIS مهم است. اگر ابتدا IIS نصب شود و سپس دات نت فریم ورک 4، به صورت خودکار، کار نگاشت اطلاعات ASP.NET به IIS صورت خواهد گرفت.
اگر ابتدا دات نت فریم ورک 4 نصب شود و سپس IIS، برای مثال دیگر از برگه ASP.NET در IIS 6.x خبری نخواهد بود. برای رفع این مشکل دستور زیر را در خط فرمان اجرا کنید:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe /i
به این ترتیب، اطلاعات مرتبط با موتور ASP.NET مجددا به تنظیمات IIS اضافه خواهند شد.
بررسی بهبودهای پروسهی Build در داتنت 8
یک نکتهی تکمیلی: چگونه تاریخ Build را به اسمبلی برنامه اضافه کنیم؟
شاید علاقمند باشید که بجای نمایش شماره نگارش برنامه، تاریخ Build آنرا در قسمتی خاص، نمایش دهید. برای اینکار میتوان یک ویژگی جدید را به صورت زیر به اسمبلی برنامه اضافه کرد:
[AttributeUsage(AttributeTargets.Assembly)] public sealed class BuildDateAttribute : Attribute { public BuildDateAttribute(string buildDateTime) => BuildDateTime = buildDateTime; public string BuildDateTime { get; } }
تا در زمان کامپایل برنامه، فایل obj\Debug\net8.0\DntSite.Web.AssemblyInfo.cs را به این صورت تکمیل کند:
using System; using System.Reflection; [assembly: DNTCommon.Web.Core.BuildDateAttribute("1403.05.28.15.17")] [assembly: System.Reflection.AssemblyCompanyAttribute("DntSite.Web")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
مقدار دهی این این ویژگی جدید، در زمان Build و توسط تنظیمات زیر در فایل csproj. برنامه انجام میشود:
<Project> <ItemGroup> <AssemblyAttribute Include="DNTCommon.Web.Core.BuildDateAttribute"> <_Parameter1>$([System.DateTime]::Now.ToString("yyyy.MM.dd.HH.mm"))</_Parameter1> </AssemblyAttribute> </ItemGroup>
با استفاده از AssemblyAttribute میتوان پارامترهای دلخواهی را به ویژگی Include شده، ارسال کرد؛ برای مثال، تاریخ جاری سیستم را. اگر تعداد پارامترهای سازنده بیشتر بود، میتوان Parameter2_ و Parameter3_ و ... را هم تنظیم کرد.
همین اندازه تنظیم برای اضافه شدن خودکار این ویژگی جدید به اسمبلی نهایی برنامه کافی است (و همانطور که عنوان شد، محل درج خودکار اولیهی آن، در فایل AssemblyInfo.cs پوشهی obj برنامهاست). برای خواندن و نمایش آن هم میتوان به صورت زیر عمل کرد:
public static class BuildDateAttributeExtensions { public static string? GetBuildDateTime(this Assembly? assembly) => assembly?.GetCustomAttribute<BuildDateAttribute>()?.BuildDateTime ?? assembly?.GetName().Version?.ToString(); }
برای نمونه میتوان اطلاعات BuildDateAttribute اسمبلی جاری را به صورت زیر استخراج کرد:
private static string? GetVersionInfo() => Assembly.GetExecutingAssembly().GetBuildDateTime();
نگاهی به انواع Aspects موجود در کتابخانه PostSharp
یکی از مواردی که ممکن است در محیط کاری با آن برخورد داشت، تقاضای تولید فایل word یک گزارش با فرمتی مشخص از یک برنامه ASP.Net است. برای مثال یک قالب درست کردهاند که header و footer و کلا یک فرمت رسمی دارد. الان برنامه شما باید این فایل word رسمی را با گزارشی که تولید میکند پر کند. حالا اینجاست که گرفتاری برنامه نویس شروع میشود! روی سرور باید word نصب باشد تا توسط اشیاء COM آن بتوان یک چنین کارهایی را آنهم با ASP.Net که به صورت پیش فرض کمترین سطح دسترسی را روی سیستم دارد انجام داد. یا اینکه باید به سراغ کامپوننتهای تجاری رفت و حالا اینجا با این وضع تحریم و غیره چگونه بتوان آنها را خریداری کرد یا شاید احتمالا در سایتهای وارز بتوان نسخه تکه پاره شده آنها را یافت. مشکلی هم که این نوع کامپوننتها دارند این است که ممکن است سال دیگر اصلا ساپورت نشوند. محصولات مایکروسافت هم که مرتبا در حال به روز رسانی هستند. در این حالت برنامه متکی به این نوع کامپوننتهای تجاری سورس بسته در همان نگارش قبلی خود مجبور است باقی بماند.
خوشبختانه با ارائه آفیس 2007 و فرمت OpenXML فایلهای آن، این مشکل تقریبا مرتفع شده است. مایکروسافت نیز برای سهولت تولید این نوع اسناد، OpenXML SDK را ارائه داده است که از آدرس زیر قابل دریافت است:
Open XML Format SDK 1.0
البته پیش نمایش نگارش دو SDK آن نیز موجود است که در مطلب جاری به آن پرداخته نخواهد شد.
فایلهای office 2007 از یک فایلzip تشکیل شده از چند فایل xml داخل آن، ایجاد شدهاند. برای مثال یک فایل docx را با winrar یا امثال آن باز کنید (تصویر زیر):
برای کار با اینگونه اسناد باید با اصطلاحات زیر آشنا شد:
Package : فایل zip شما (همان فایل برای مثال docx) اینجا یک بسته نام دارد.
Parts : اجزای این بسته که همان فایلهای آن هستند، parts نامیده شده اند.
Relations : اگر به فایلهای موجود در یک بسته دقت کنید، فایلهایی با پسوند rels را خواهید دید که بیانگر نحوه ارتباط Parts با یکدیگر هستند.
Relations Ids: هر ارتباط با یک ID منحصربفرد تعریف میگردد.
اگر علاقمند باشید که پوستری را در این رابطه مشاهده نمائید میتوان به آدرس زیر مراجعه نمود.
Open XML Developer Map
نحوه استفاده از OpenXML SDK در دات نت:
ابتدا باید ارجاعی را به فایل DocumentFormat.OpenXml.dll که پس از نصب در مسیر OpenXMLSDK\1.0.1825\lib قرار گرفته است به پروژه افزود. سپس نیاز است تا ارجاعی به کتابخانه WindowsBase نیز به برنامه افزوده شود (تصویر زیر). افزودن ارجاعی به این کتابخانه جهت کامپایل برنامه ضروری است (شکل زیر).
تا اینجا ارجاعات برنامه به صورت زیر خواهند بود:
یک مثال ساده:
قصد داریم یک فایل docx ساده را با استفاده از OpenXML SDK ایجاد کنیم. در مثال زیر فرمت متغیر docXml را میتوان با ایجاد یک فایل docx ساده در word و سپس باز کردن بسته فشرده شده آن و مشاهده محتوای فایل word\document.xml بدست آورد.
using System.IO;
using System.Text;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
namespace OpenXMLTestApp
{
class CWord
{
public static void CreateDocument(string documentFileName, string text)
{
using (WordprocessingDocument wordDoc =
WordprocessingDocument.Create(documentFileName, WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = wordDoc.AddMainDocumentPart();
string docXml =
@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
<w:document xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
<w:body><w:p><w:r><w:t>#REPLACE#</w:t></w:r></w:p></w:body>
</w:document>";
docXml = docXml.Replace("#REPLACE#", text);
using (Stream stream = mainPart.GetStream())
{
byte[] buf = (new UTF8Encoding()).GetBytes(docXml);
stream.Write(buf, 0, buf.Length);
}
}
}
}
}
CWord.CreateDocument("test.docx", "سلام دنیا");
برای مطالعه بیشتر میتوان به منابع زیر مراجعه نمود:
یک ویدیوی آموزشی رایگان از مایکروسافت
دریافت
سؤالات متداول در MSDN
http://msdn.microsoft.com/en-us/library/bb491088.aspx
البته اگر پس از نصب SDK به پوشه doc آن مراجعه نمائید، این سؤال و جوابها را در فایل راهنمای chm آن نیز میتوان پیدا کرد.
مثال دیگری در مورد ایجاد یک گزارش از بانک اطلاعاتی و گرفتن خروجی docx از آن
http://openxmldeveloper.org/articles/GenerateWordTable.aspx
البته این مثال خیلی قدیمی است و قسمتهای کار با پکیج را با SDK ارائه شده میتوان به صورت خودکار انجام داد. اما حداقل نحوه تولید جداول استاندارد OpenXML را میتوان از آن ایده گرفت.
مثالی در مورد نحوه قرار دادن عکس در فایل docx تولیدی
همچنین مثالهای بیشتری را در وبلاگهای مربوطه میتوان یافت:
http://blogs.msdn.com/brian_jones/
http://blogs.msdn.com/ericwhite/default.aspx
نگاهی بر wyam
csc /t:module RUT.cs csc /t:module FUT.cs al /out: MultiFileLibrary.dll /t:library FUT.netmodule RUT.netmodule
این ابزار همچنین میتواند فایلهای CUI ,GUI و ... را با سوئیچهای زیر هم تولید کند:
/t[arget]:exe, /t[arget]:winexe, or /t[arget]:appcontainerexe
البته اینکار تا حدی غیر معمول است که یک فایل exe بخواهد کدهای IL ابتدایی را از ماژولهای جداگانه بخواند. در صورتیکه چنین قصدی را دارید، باید یکی از ماژولها را به عنوان مدخل ورودی Main تعریف کنید تا برنامه از آنجا آغاز به کار کند. نحوهی ساخت یک فایل اجرایی و معرفی ماژول Main به شکل زیر است:
csc /t:module /r:MultiFileLibrary.dll Program.cs al /out:Program.exe /t:exe /main:Program.Main Program.netmodule
.method privatescope static void __EntryPoint$PST06000001() cil managed { .entrypoint // Code size 8 (0x8) .maxstack 8 IL_0000: tail. IL_0002: call void [.module 'Program.netmodule']Program::Main() IL_0007: ret } // end of method 'Global Functions'::__EntryPoint
کد بالا یک کد ساده است که میگوید داخل فایل Program.netmodule در نوع Program متدی وجود دارد به نام Main که محل آغازین برنامه است. البته این روش ایجاد فایلهای EXE، بدین شکل توصیه چندانی نمیشود و ذکر این مطلب فقط اطلاع از وجود چنین قابلیتی بود.
[DllImport( "nativelib", EntryPoint = "to_lower", CharSet = CharSet.Unicode)] internal static extern string ToLower(string str); // string lower = ToLower("StringToConvert");
تولید کنندهی کد مخصوص P/Invoke در دات نت 7، به دنبال ویژگی جدید LibraryImportAttribute بر روی متدهای استاتیک و partial میگردد تا کدهای متناظر با آنها را تولید کند. به این ترتیب نیاز به تولید اینگونه کدها در زمان اجرای برنامه مرتفع میشود و همچنین میتوان این کدها را در IDE خود بررسی و حتی دیباگ کرد.
[LibraryImport( "nativelib", EntryPoint = "to_lower", StringMarshalling = StringMarshalling.Utf16)] internal static partial string ToLower(string str);
امکان تبدیل خودکار کدهای قدیمی مبتنی بر DllImportAttribute به نمونههای جدید
برای تبدیل خودکار کدهای قدیمی موجود، فقط کافی است یک سطر زیر را به فایل editorconfig. پروژهی خود اضافه کنید:
dotnet_diagnostic.SYSLIB1054.severity = suggestion
تغییرات صورت گرفته نسبت به DllImport قدیمی
نحوهی تعریف LibraryImportAttribute در اکثر موارد با DllImportAttribute تطابق دارد، منهای موارد زیر:
- در اینجا معادلی برای CallingConvention وجود ندارد. برای اینکار از UnmanagedCallConvAttribute استفاده میشود.
- CharSet با StringMarshalling تعویض شدهاست. ANSI حذف شدهاست و UTF-8 حالت پیشفرض است. برای مثال:
// Before public static class Native { [DllImport(nameof(Native), CharSet = CharSet.Unicode)] public extern static string ToLower(string str); } // After public static partial class Native { [LibraryImport(nameof(Native), StringMarshalling = StringMarshalling.Utf16)] public static partial string ToLower(string str); }