As discussed in dotnet/runtime#33331 we're adding an analyzer to detect usage of platform-specific APIs. This analyzer requires a custom attribute applied to method, containing type, or assembly.
- Automatic ANSI .rc file conversion to UTF8 !!!! (not wanted !!!!)
- Fixed an inaccurate error message when developers try publishing .NET Core 3.0 apps to Azure.
- Stability improvement in msbuild/dotnet restore when plugins are used to restore against authenticated feeds.
Null propagation برای قبل از C#6
C#6 will support null propagation (https://github.com/dotnet/roslyn/wiki/Languages-features-in-C%23-6-and-VB-14). Result.OrDefault is simple null propagation for pre-C#6.
Port 5000 is already in use. Use '--port' to specify a different port.
پیرو مطلب قلمهایی حاوی آیکون که خصوصا در برنامههای مترو بیشتر مرسوم شدهاند، شاید بد نباشد کار برنامه Character Map ویندوز را با WPF شبیه سازی کنیم.
ابتدا Model و ViewModel این برنامه را درنظر بگیرید:
namespace CrMap.Models { public class Symbol { public char Character { set; get; } public string CharacterCode { set; get; } } }
using System; using System.Collections.Generic; using System.Windows.Media; using CrMap.Models; namespace CrMap.ViewModels { public class CrMapViewModel { public IList<Symbol> Symbols { set; get; } public int GridRows { set; get; } public int GridCols { set; get; } public CrMapViewModel() { fillDataSource(); } private void fillDataSource() { Symbols = new List<Symbol>(); GridCols = 15; var fontFamily = new FontFamily(new Uri("pack://application:,,,/"), "/Fonts/#whhglyphs"); GlyphTypeface glyph = null; foreach (var typeface in fontFamily.GetTypefaces()) { if (typeface.TryGetGlyphTypeface(out glyph) && (glyph != null)) break; } if (glyph == null) throw new InvalidOperationException("Couldn't find a GlyphTypeface."); GridRows = (glyph.CharacterToGlyphMap.Count / GridCols) + 1; foreach (var item in glyph.CharacterToGlyphMap) { var index = item.Key; Symbols.Add(new Symbol { Character = Convert.ToChar(index), CharacterCode = string.Format("&#x{0:X}", index) }); } } } }
یک سری قابلیت جالب در WPF برای استخراج اطلاعات قلمها وجود دارند که در فضای نام System.Windows.Media اسمبلی PresentationCore.dll قرار گرفتهاند. برای نمونه پس از وهله سازی FontFamily بر اساس یک قلم مدفون شده در برنامه، امکان استخراج تعداد گلیفهای موجود در این قلم وجود دارد که نحوه انجام آنرا در متد fillDataSource ملاحظه میکنید.
این اطلاعات استخراج شده و لیست Symbols برنامه را تشکیل میدهند. در نهایت برای نمایش این اطلاعات، از ترکیب ItemsControl و UniformGrid استفاده خواهیم کرد:
<Window x:Class="CrMap.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:CrMap.ViewModels" Title="MainWindow" WindowStartupLocation="CenterScreen" WindowState="Maximized" Height="350" Width="525"> <Window.Resources> <vm:CrMapViewModel x:Key="vmCrMapViewModel" /> </Window.Resources> <ScrollViewer VerticalScrollBarVisibility="Visible"> <ItemsControl DataContext="{StaticResource vmCrMapViewModel}" ItemsSource="{Binding Symbols}" Name="MainItemsControl" VerticalAlignment="Top" HorizontalAlignment="Center" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="4"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid HorizontalAlignment="Center" VerticalAlignment="Center" Columns="{Binding GridCols}" Rows="{Binding GridRows}"> </UniformGrid> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <ContentControl> <Border BorderBrush="SlateGray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="1" CornerRadius="3" Margin="3"> <StackPanel Margin="3" Orientation="Vertical"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Fonts/#whhglyphs" Foreground="DarkRed" FontSize="17" Text="{Binding Character}" /> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding CharacterCode}" /> </StackPanel> </Border> </ContentControl> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> </Window>
دریافت مثال این مطلب
CrMap.zip
همیشه با نزدیک شدن آخر سال، به روز کردن مناسبتهای تقویم سال بعد ضروری میشود. دوستان لینوکسی ما هم در این مورد زحمت کشیده و برنامهای را تهیه کردهاند که از آدرس زیر قابل دریافت است:
http://download.gna.org/jalali-calendar/
پس از دریافت برنامه، مناسبتهای سال 1388 در فایل 1388.xml قابل مشاهده است (با تقدیر و تشکر از زحمات این عزیزان). فرض کنید میخواهیم این اطلاعات را به اس کیوال سرور منتقل کنیم.
فرمت این فایل به شکل زیر است:
<?xml version="1.0" encoding="UTF-8"?>
<cal1388>
<day>
<num>1/1</num>
<desc>عید نوروز، لحظه تحویل سال:ساعت 15 و 13 دقیقه و 39 ثانیه </desc>
</day>
</cal1388>
حداقل سه راه حل برای انجام اینکار (خواندن فایل xml توسط اس کیوال سرور) موجود است:
راه اول:
SELECT '1388' saal,
X.day.query('num').value('.', 'nVARCHAR(50)') rooz_maah,
X.day.query('desc').value('.', 'nVARCHAR(max)') tozih
FROM (
SELECT CAST(x AS XML)
FROM OPENROWSET(
BULK
'c:\1388.xml',
SINGLE_BLOB
) AS T(x)
) AS T(x)
CROSS APPLY x.nodes('cal1388/day') AS X(day);
راه دوم:
DECLARE @MyXML XML
SELECT @MyXML = CAST(x AS XML)
FROM OPENROWSET(
BULK
'c:\1388.xml',
SINGLE_BLOB
) AS T(x)
SELECT 1388 saal,
nref.value('num[1]', 'nvarchar(50)') rooz_maah,
nref.value('desc[1]', 'nvarchar(max)') tozih
FROM @MyXML.nodes('//day') AS R(nref)
راه سوم:
DECLARE @MyXML XML
DECLARE @handle INT
SELECT @MyXML = CAST(x AS XML)
FROM OPENROWSET(
BULK
'c:\1388.xml',
SINGLE_BLOB
) AS T(x)
EXEC sp_xml_preparedocument @handle OUTPUT,
@MyXML
SELECT 1388 saal,
*
FROM OPENXML(@handle, '/cal1388/day', 2) WITH
(num VARCHAR(20), [desc] NVARCHAR(MAX))
EXEC sp_xml_removedocument @handle
اکنون که میتوانیم اطلاعات این فایل را select کنیم، Insert آن ساده است . برای مثال:
INSERT INTO tblMonasebat
(
saal,
rooz_mah,
tozih
)
SELECT '1388' saal,
nref.value('num[1]', 'nvarchar(50)') rooz_maah,
nref.value('desc[1]', 'nvarchar(max)') tozih
FROM @MyXML.nodes('//day') AS R(nref)
بدیهی است امکان مقدار دهی @MyXML به صورت یک رشته که حاوی محتویات فایل است نیز مهیا میباشد (بجای خواندن از فایل).
برای مطالعهی بیشتر
XML Support in Microsoft SQL Server 2005
Beginning SQL Server 2005 XML Programming
کامپوننت jumbotron
از Jumbotron برای نمایش متنی مشخص در بالای یک صفحه، استفاده میشود. دو روش استفادهی از آن در بوت استرپ 4 وجود دارند:
- داخل container:
<div class="container"> <header class="jumbotron mt-4"> <div class="display-2 mb-4">Our Mission</div> <p class="lead">Wisdom Pet Medicine strives to blend the best in traditional and alternative medicine in the diagnosis and treatment of companion animals including dogs, cats, birds, reptiles, rodents, and fish. We apply the wisdom garnered in the centuries old tradition of veterinary medicine, to find the safest treatments and cures.</p> </header>
در اینجا با اعمال کلاس jumbotron، متن header، داخل یک قاب با گوشههای گرد قرار میگیرد و مشخصتر نمایش داده خواهد شد. همچنین با mt-4، فاصلهای را بین آن و بالای صفحه ایجاد کردهایم.
- خارج از container:
<header class="jumbotron jumbotron-fluid"> <div class="container"> <div class="display-2 mb-4">Our Mission</div> <p class="lead">Wisdom Pet Medicine strives to blend the best in traditional and alternative medicine in the diagnosis and treatment of companion animals including dogs, cats, birds, reptiles, rodents, and fish. We apply the wisdom garnered in the centuries old tradition of veterinary medicine, to find the safest treatments and cures.</p> </div> </header>
اگر میخواهیم این قاب، تمام عرض صفحه را پر کند و همچمنین لبههای گرد آن نیز حذف شوند، میتوان از کلاس jumbotron-fluid استفاده کرد و آنرا خارج از container قرار داد. سپس برای اینکه متن داخل آن با container زیر آن تراز شود، میتوان یک container را در اینجا داخل jumbotron تعریف کرد.
کنترل ظاهر جداول، در بوت استرپ 4
بوت استرپ 4 به همراه تعدادی کلاس ویژه است که برای بهبود ظاهر المان استاندارد جدول، ارائه شدهاند. آنها را در طی مثالهایی بررسی خواهیم کرد.
برای رسیدن به چنین تصویری، تغییرات زیر را بر روی یک جدول استاندارد HTML اعمال کردهایم:
<table class="table table-striped table-hover table-bordered table-responsive"> <thead class="thead-light">
- کلاس table-striped سبب میشود تا ردیفها، یک در میان با رنگی متمایز نمایش داده شوند.
- با افزودن table-hover، رنگ ردیفهای جدول با عبور اشارهگر ماوس از روی آنها تغییر میکند.
- کلاس table-bordered کار نمایش قاب جدول را انجام میدهد.
- کلاس table-responsive سبب میشود تا در اندازههای کوچک صفحه، یک اسکرول بار افقی برای نمایش آیتمهای جدول ظاهر شود و یا میتوان از کلاس table-sm نیز استفاده کرد تا padding تعریف شدهی در جدول، کاهش یابند. این کلاس، قابلیت پذیرش break-pointها را نیز دارد؛ مانند table-responsive-md.
- کلاسهای thead-light و یا thead-dark که بر روی تگ thead قرار میگیرند، رنگ پس زمینهی هدر جدول را مشخص میکنند.
- برای تغییر رنگ پس زمینه و متن یک ردیف میتوان از کلاسهای bg-color و text-color استفاده کرد:
<tr class="bg-danger text-light">
<td class="table-success">$100.00 </td>
کامپوننت جدید card در بوت استرپ 4
پنلهای بوت استرپ 3 حذف و بجای آن کامپوننت جدیدی به نام card در نگارش 4 آن ارائه شدهاست که با افزودن کلاس آن به یک div، بلافاصله قابی با گوشههای گرد به آن اضافه میشود.
<section class="card mb-5" id="drwinthrop"> <div class="card-body"> <img class="card-img img-fluid" src="images/testimonial-mcphersons.jpg" alt="Doctor Winthrop Photo"> <h2 class="card-title">Dr. Stanley Winthrop</h2> <h5 class="card-subtitle">Behaviorist</h5> <p class="card-text">Dr. Winthrop is the guardian of Missy, a three-year old Llaso mix, who he adopted at the shelter. Dr. Winthrop is passionate about spay and neuter and pet adoption, and works tireless hours outside the clinic, performing free spay and neuter surgeries for the shelter.</p> <a class="card-link" href="#">About Me</a> <a class="card-link" href="#">My Pets</a> <a class="card-link" href="#">Client Slideshow</a> </div> </section>
- سپس یک card میتواند دارای تصویری واکنشگرا باشد که عرض card را پوشش میدهد. این تصویر با کلاس card-img مشخص میشود.
در اینجا امکان تعریف card-img-top و card-img-bottom نیز وجود دارند. این موارد تصویر card را در بالا و یا پایین آن، بدون padding، نمایش میدهند. اگر میخواهید متنی را بر روی این تصویر نمایش دهید، از کلاس card-img-overlay استفاده کنید. در این حالتها باید تصویر را خارج از card-body قرار دهید.
- عنوان و زیرعنوان یک card، توسط کلاسهای card-title و card-subtitle تعیین میشوند.
- متن داخل آنرا با کلاس card-text مشخص میکنیم.
- لینکهای ذیل آن نیز توسط کلاس card-link در طی یک ردیف نمایش داده میشوند.
امکان تعیین رنگ پس زمینه، حاشیه و متن یک card نیز وجود دارند:
<section class="card mb-5 bg-primary text-light border-warning" id="drchase">
و فرمول کلی رنگهای آن نیز به صورت زیر میباشد:
میتوان برای یک card، هدر و فوتر نیز تعریف کرد:
<section class="card mb-5" id="drsanders"> <div class="card-header"> <h2 class="card-title">Dr. Kenneth Sanders</h2> <h5 class="card-subtitle">Nutritionist</h5> </div> <div class="card-body"> <img class="card-img img-fluid" src="images/testimonial-mcphersons.jpg" alt="Doctor Sanders Photo"> <p class="card-text">Leroy walked into Dr. Sanders front door when she was moving into a new house. After searching for weeks for Leroy's guardians, she decided to make Leroy a part of her pet family, and now has three cats.</p> </div> <div class="card-footer"> <a class="card-link" href="#">About Me</a> <a class="card-link" href="#">My Pets</a> <a class="card-link" href="#">Client Slideshow</a> </div> </section>
برای تعریف یک list-group در داخل یک card، به صورت زیر عمل میکنیم:
<section class="card mb-5" id="drwong"> <div class="card-body"> <img class="card-img img-fluid" src="images/testimonial-mcphersons.jpg" alt="Doctor Wong Photo"> <h2 class="card-title">Dr. Olivia Wong</h2> <h5 class="card-subtitle">Preventive Care</h5> <p class="card-text">Dr. Wong is a cancer survivor who was fortunate enough to get to spend time with a therapy dog during her recovery. She became passionate about therapy animals, and has started her own foundation to train and provide education to patients in recovery. Now she gets her own dose of daily therapy from her husky, Lilla.</p> </div> <div class="list-group list-group-flush"> <a class="list-group-item" href="#">About Me</a> <a class="list-group-item" href="#">My Pets</a> <a class="list-group-item" href="#"> Client Slideshow </a> </div> </section>
تعیین نحوهی چیدمان cards در بوت استرپ 4
اگر چندین card در یک صفحه تعریف شدهاند، برای تعیین نحوهی قرارگیری آنها در کنار یکدیگر میتوان یا از سیستم طرحبندی متداول بوت استرپ استفاده کرده و یا امکان تعریف گروهی از آنها نیز وجود دارد. برای اینکار کافی است یک div با کلاس card-group را تعریف و سپس تمام cards را داخل آن قرار دهیم:
<div class="container"> <div class="card-group">
اگر از کلاس card-columns استفاده کنیم، تمام cards را به صورت خودکار در ستونها و ردیفها، قرار میدهد که بعضی از آنها بلندتر و بعضی دیگر کوتاهتر هستند (نوعی نمایش کاشیکاری شدهاست):
ولی در کل اگر نیاز به کنترل بیشتری دارید، از همان روش متداول تعریف ردیفها و ستونهای سیستم طرحبندی بوت استرپ استفاده کنید.
المان media در بوت استرپ 4
برای نمایش متداول متن و تصویر که قرار است تصویر، در یک ستون و متن، در ستونی دیگر باشد، بوت استرپ 4 به همراه کلاس media است که بر اساس Flexbox بازنویسی شدهاست.
<body> <div class="container"> <section class="media mb-5" id="drwinthrop"> <img class="d-flex align-self-center img-fluid rounded mr-3" style="width:30%" src="images/testimonial-mcphersons.jpg" alt="Doctor Winthrop Photo"> <div class="media-body"> <h2>Dr. Stanley Winthrop</h2> <h5>Behaviorist</h5> <p>Dr. Winthrop is the guardian of Missy, a three-year old Llaso mix, who he adopted at the shelter. Dr. Winthrop is passionate about spay and neuter and pet adoption, and works tireless hours outside the clinic, performing free spay and neuter surgeries for the shelter.</p> </section> </div> </body>
ابتدا توسط کلاس media یک container را تعریف میکنیم. سپس تصویر، یک ستون و media-body ستون دیگر را تشکیل میدهد.
با استفاده از d-flex، المان تصویر را به یک Flexbox container تبدیل کرده و با استفاده از کلاس align-self-center، آنرا در میانهی ستون قرار میدهیم. همچنین در اینجا توسط mr-3، فاصلهی آنرا با متن ستون کناری تنظیم کردهایم.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: Bootstrap4_09.zip
بر روی ماشینهای ویندوزی و ویندوزهای سرور، استفادهی از IIS به عنوان پروکسی درخواستها و ارسال آنها به Kestrel، روش توصیه شدهاست؛ از این جهت که حداقل قابلیتهایی مانند «port 80/443 forwarding»، مدیریت طول عمر برنامه، مدیریت مجوزهای SLL آن و خیلی از موارد دیگر توسط Kestrel پشتیبانی نمیشود.
معماری پردازش نگارشهای پیشین ASP.NET در IIS
در نگارشهای پیشین ASP.NET، همه چیز داخل پروسهای به نام w3wp.exe و یا IIS Worker Process پردازش میشود که در اصل چیزی نیست بجز همان IIS Application Pool. این AppPoolها، برنامههای ASP.NET شما را هاست میکنند و همچنین سبب وهله سازی و اجرای آنها نیز خواهند شد.
در اینجا درایور http.sys ویندوز، درخواستهای رسیده را دریافت کرده و سپس آنها را به سمت سایتهایی نگاشت شدهی به AppPoolهای مشخص، هدایت میکند.
معماری پردازش برنامههای ASP.NET Core در IIS
روش اجرای برنامههای ASP.NET Core با نگارشهای پیشین آنها کاملا متفاوت هستند؛ از این جهت که داخل پروسهی w3wp.exe اجرا نمیشوند. این برنامهها در یک پروسهی مجزای کنسول خارج از پروسهی w3wp.exe اجرا میشوند و حاوی وب سرور توکاری به نام کسترل (Kestrel) هستند.
این وب سرور، وب سروری است تماما دات نتی و به شدت برای پردازش تعداد بالای درخواستها بهینه سازی شدهاست؛ تا جایی که کارآیی آن در این یک مورد چند 10 برابر IIS است. هرچند این وب سرور فوق العاده سریع است، اما «تنها» یک وب سرور خام است و به همراه سرویسهای مدیریت وب، مانند IIS نیست.
در تصویر فوق مفهوم «پروکسی» بودن IIS را در حین پردازش برنامههای ASP.NET Core بهتر میتوان درک کرد. ابتدا درخواستهای رسیده به IIS میرسند و سپس IIS آنها را به طرف Kestrel هدایت میکند.
برنامههای ASP.NET Core، برنامههای کنسول متکی به خودی هستند که توسط دستور خط فرمان dotnet اجرا میشوند. این اجرا توسط ماژولی ویژه به نام AspNetCoreModule در IIS انجام میشود.
همانطور که در تصویر نیز مشخص است، AspNetCoreModule یک ماژول بومی IIS است و هنوز برای اجرا نیاز به IIS Application Pool دارد؛ با این تفاوت که در تنظیم AppPoolهای برنامههای ASP.NET Core، باید NET CLR Version. را به No managed code تنظیم کرد.
اینکار از این جهت صورت میگیرد که IIS در اینجا تنها نقش یک پروکسی هدایت درخواستها را به پروسهی برنامهی حاوی وب سرور Kestrel، دارد و کار آن وهله سازی NET Runtime. نیست. کار AspNetCoreModule این است که با اولین درخواست رسیدهی به برنامهی شما، آنرا بارگذاری کند. سپس درخواستهای رسیده را دریافت و به سمت برنامهی ASP.NET Core شما هدایت میکند (به این عملیات reverse proxy هم میگویند).
اگر دقت کرده باشید، برنامههای ASP.NET Core، هنوز دارای فایل web.config ایی با محتوای ذیل هستند:
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/> </handlers> <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/> </system.webServer> </configuration>
یک نکته: در زمان publish برنامه، تنظیم و تبدیل مقادیر LAUNCHER_PATH و LAUNCHER_ARGS به معادلهای اصلی آنها صورت میگیرد (در ادامه مطلب بحث خواهد شد).
آیا واقعا هنوز نیازی به استفادهی از IIS وجود دارد؟
هرچند میتوان Kestrel را توسط یک IP و پورت مشخص، عمومی کرد و استفاده نمود، اما حداقل در ویندوز چنین توصیهای نمیشود و بهتر است از IIS به عنوان یک front end proxy استفاده کرد؛ به این دلایل:
- اگر میخواهید چندین برنامه را بر روی یک وب سرور که از طریق پورتهای 80 و 443 ارائه میشوند داشته باشید، نمیتوانید از Kestrel به صورت مستقیم استفاده کنید؛ زیرا از مفهوم host header routing که قابلیت ارائهی چندین برنامه را از طریق پورت 80 و توسط یک IP میسر میکند، پشتیبانی نمیکند. برای اینکار نیاز به IIS و یا در حقیقت درایور http.sys ویندوز است.
- IIS خدمات قابل توجهی را به برنامهی شما ارائه میکند. برای مثال با اولین درخواست رسیده، به صورت خودکار آنرا اجرا و بارگذاری میکند؛ به همراه تمام مدیریتهای پروسهای که در اختیار برنامههای ASP.NET در طی سالیان سال قرار داشتهاست. برای مثال اگر پروسهی برنامهی شما در اثر استثنایی کرش کرد، دوباره با درخواست بعدی رسیده، حتما برنامه را بارگذاری و آمادهی خدمات دهی مجدد میکند.
- در اینجا میتوان تنظیمات SSL را بر روی IIS انجام داد و سپس درخواستهای معمولی را به Kestrel ارسال کرد. به این ترتیب با یک مجوز میتوان چندین برنامهی Kestrel را مدیریت کرد.
- IISهای جدید به همراه ماژولهای بومی بسیار بهینه و کم مصرفی برای مواردی مانند gzip compression of static content, static file caching, Url Rewriting هستند که با فعال سازی آنها میتوان از این قابلیتها، در برنامههای ASP.NET Core نیز استفاده کرد.
نحوهی توزیع برنامههای ASP.NET Core به IIS
روش اول: استفاده از دستور خط فرمان dotnet publish
برای این منظور به ریشهی پروژهی خود وارد شده و دستور dotnet publish را با توجه به پارامترهای ذیل اجرا کنید:
dotnet publish --framework netcoreapp1.0 --output "c:\temp\mysite" --configuration Release
{ "publishOptions": { "include": [ "wwwroot", "Features", "appsettings.json", "web.config" ] }, "scripts": { "precompile": [ "dotnet bundle" ], "prepublish": [ //"bower install" ], "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] } }
پس از انتقال این فایلها به سرور، مابقی مراحل آن مانند قبل است. یک Application جدید تعریف شده و سپس ابتدا مسیر آن مشخص میشود و نکتهی اصلی، انتخاب AppPool ایی است که پیشتر شرح داده شد:
برنامههای ASP.NET Core باید به AppPool ایی تنظیم شوند که NET CLR Version. آنها No Managed Code است. همچنین بهتر است به ازای هر برنامهی جدید یک AppPool مجزا را ایجاد کنید تا کرش یک برنامه تاثیر منفی را بر روی برنامهی دیگری نگذارد.
روش دوم: استفاده از ابزار Publish خود ویژوال استودیو
اگر علاقمند هستید که روش خط فرمان فوق را توسط ابزار publish ویژوال استودیو انجام دهید، بر روی پروژه در solution explorer کلیک راست کرده و گزینهی publish را انتخاب کنید. در صفحهای که باز میشود، بر روی گزینهی custom کلیک کرده و نامی را وارد کنید. از این نام پروفایل، جهت ساده سازی مراحل publish، در دفعات آتی فراخوانی آن استفاده میشود.
در صفحهی بعدی اگر گزینهی file system را انتخاب کنید، دقیقا همان مراحل روش اول تکرار میشوند:
سپس میتوانید فریم ورک برنامه و نوع ارائه را مشخص کنید:
و در آخر کار، Publish به این پوشهی مشخص شده که به صورت پیش فرض در ذیل پوشهی bin برنامهاست، صورت میگیرد.
روش عیب یابی راه اندازی اولیهی برنامههای ASP.NET Core
در اولین سعی در اجرای برنامهی ASP.NET Core بر روی IIS به این خطا رسیدم:
در event viewer ویندوز چیزی ثبت نشده بود. اولین کاری را که در این موارد میتوان انجام داد به این صورت است. از طریق خط فرمان به پوشهی publish برنامه وارد شوید (همان پوشهای که توسط IIS عمومی شدهاست). سپس دستور dotnet prog.dll را صادر کنید. در اینجا prog.dll نام dll اصلی برنامه یا همان نام پروژه است:
همانطور که مشاهده میکنید، برنامه به دنبال پوشهی bower_components ایی میگردد که کار publish آن انجام نشدهاست (این پوشه در تنظیمات آغازین برنامه عمومی شدهاست و در لیست include قسمت publishOptions فایل project.json فراموش شدهاست).
روش دوم، فعال سازی stdoutLogEnabled موجود در فایل وب کانفیگ، به true است. در اینجا web.config نهایی تولیدی توسط عملیات publish را مشاهده میکنید که در آن پارامترهای processPath و arguments مقدار دهی شدهاند (همان قسمت postpublish فایل project.json). در اینجا مقدار stdoutLogEnabled به صورت پیش فرض false است. اگر true شود، همان خروجی تصویر فوق را در پوشهی logs خواهید یافت:
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" /> </handlers> <aspNetCore processPath="dotnet" arguments=".\Core1RtmEmptyTest.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" /> </system.webServer> </configuration>
Warning: Could not create stdoutLogFile \\?\D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest\bin\Release\PublishOutput\logs\stdout_10064_201672893654.log, ErrorCode = -2147024893.
حداقلهای یک هاست ویندوزی که میخواهد برنامههای ASP.NET Core را ارائه دهد
پس از نصب IIS، نیاز است ASP.NET Core Module نیز نصب گردد. برای اینکار اگر بستهی NET Core Windows Server Hosting. را نصب کنید، کافی است:
https://go.microsoft.com/fwlink/?LinkId=817246
این بسته به همراه NET Core Runtime, .NET Core Library. و ASP.NET Core Module است. همچنین همانطور که عنوان شد، برنامههای ASP.NET Core باید به AppPool ایی تنظیم شوند که NET CLR Version. آنها No Managed Code است. اینها حداقلهای راه اندازی یک برنامهی ASP.NET Core بر روی سرورهای ویندوزی هستند.
هنوز فایل app_offline.htm نیز در اینجا معتبر است
یکی از خواص ASP.NET Core Module، پردازش فایل خاصی است به نام app_offline.htm. اگر این فایل را در ریشهی سایت قرار دهید، برنامه پردازش تمام درخواستهای رسیده را قطع خواهد کرد و سپس پروسهی برنامه خاتمه مییابد. هر زمانیکه این فایل حذف شد، مجددا با درخواست بعدی رسیده، برنامه آمادهی پاسخگویی میشود.
npm install -D jsHint jsHint-loader
module.exports = { entry:['./shared.js','./main.ts'] ,output:{ filename:'bundle.js' } ,watch :true ,module:{ preLoaders:[ { test:/\.js$/ ,exclude:/node_modules/ ,loader:'jshint-loader' } ], loaders:[ { test:/\.ts$/ ,exclude:/node_modules/ ,loader:'ts-loader' } ] } }
همچنین برای تکمیل قابل ذکر است که وبپک دارای postLoaders نیز میباشد که پس از Loaderهای اصلی اجرا میشوند.
// در حالتی که به صورت محلی وبپک نصب شده است npm run webpack -- -p // درحالتی که وبپک به صورت سراسری اجرا میشود webpack -p
npm install -D strip-loader
// webpack.prod.config.js //تنظیمات قبلی را میخوانیم var devConfig = require("./webpack.config.js"); // لودری که وظیفهی حذف کردن دارد را وارد میکنیم var stripLoader = require("strip-loader"); // مانند قبل یک آبجکت با موارد مورد نظر برای لودر میسازیم var stripLoaderConfig = { test:[/\.js$/,/\.ts$/], exclude :/node_modules/ ,loader:stripLoader.loader("console.log") } // اضافه کردن به لیست لودرهای قبلی devConfig.module.loaders.push(stripLoaderConfig); // و در آخر اکسپورت کردن تنظیمات جدید وقبلی module.exports = devConfig;
loader:stripLoader.loader("console.log")
// در حالتی که وبپک به صورت محلی نصب شده است npm run webpack -- --config webpack.prod.config.js -p // در حالتی که وبپک به صورت سراسری نصب شده باشد webpack --config webpack.prod.config.js -p
// زمانی که وبپک به صورت محلی در پروژه نصب شده است npm run webpackserver -- --config webpack.prod.config.js -p //در حالتی که وبپک به صورت گلوبال ( سراسری ) نصب میباشد webpack-dev-server --config webpack.prod.config.js -p
// new webpack.config.js file //ماژول توکار نود جی اس var path = require("path"); module.exports = { // مشخص کردن زمینه برای فایلهای ورودی context:path.resolve("js"), entry:['./shared.js','./main.ts'] ,output:{ // مشخص کردن محل قرارگیری باندل ساخته شده path:path.resolve("build/js"), // درخواست از سمت چه مسیری برای باندل خواهد آمد ؟ publicPath:"assets/js", filename:'bundle.js' } , devServer:{ //راهنمایی برای وب سرور جهت اینکه فایلها را از چه محلی سرو کند contentBase:"assets" } ,watch :true ,module:{ loaders:[ { test:/\.ts$/ ,exclude:/node_modules/ ,loader:'ts-loader' } ] } }
context:path.resolve("js")
// تغییرات در شی output // این کلید جدید مسیر قرار گیری جدید باندل را به وبپک اطلاع میدهد path:path.resolve("build/js"), // راهنما برای وب سرور وبپک جهت میزبانی مسیر زیر از کلید بالا publicPath:"assets/js",
//index.html <html> <head> first part of webpack tut! </head> <body> <h1>webpack is awesome !</h1> <script src="assets/js/bundle.js"></script> </body> </html>
حال با اجرا کردن وب سرور وبپک میتوان مشاهده کرد که مسیرهای جدید، بدون مشکل توسط وبپک پیدا شده و فایلها سرو میشوند. قابل توجه است که این نوع چینش پروژه قابل تغییر و شخصی سازی برای پروژههای گوناگون میباشد.
ساخت فایلهای سورس مپ (source map)
سادهترین راه جهت ساخت فایلهای سورس مپ با استفاده از یک پرچم در هنگام فراخوانی وبپک به صورت زیر میباشد.
// فعال کردن ساخت سورس مپها npm run webpack -- -d // یا در هنگام نصب گلوبال webpack -d // جهت استفاده به همراه وب سرور npm run webpackserver -- -d // یا به صورت نصب گلوبال webpack-dev-server -d
// webpack.config.js // کلید جدید اضافه شده در فایل پیکربندی devtool:"#source-map"
با اجرای وب سرور وبپک خواهید دید که سورس مپها در منوی توسعه دهندهی مرورگر قابل دستیابی میباشند.
ساخت چندین باندل گوناگون
قصد داریم به پروژه، دو صفحهی دیگر را نیز با نامهای aboutme و contact اضافه کنیم. هر یک از این صفحات اسکریپت مخصوص به خود را خواهد داشت و باندل نهایی نیز شامل تمامی آنها خواهد شد. در صورتی که این خروجی مطلوب ما نباشد و به طور مثال بخواهیم مکانیزمی شبیه به lazy loading اسکریپتها را داشته باشیم و فقط زمانی اسکریپتها بارگذاری شوند که به آنها احتیاج باشد، برای انجام این کار با وبپک به صورت زیر عمل خواهیم کرد.
دو صفحهی html جدید را با عناوین ذکر شدهی بالا به پوشهی assets اضافه میکنیم و برای هریک نیز اسکریپتی با همان نام خواهیم ساخت و در پوشهی js قرار میدهیم.
محتوای صفحات بدین شکل میباشد.
// index.html file <html> <head> <title> third part of webpack tut! </title> </head> <body> <nav> <a href="aboutme.html">about me</a> <a href="contact.html">contact</a> </nav> <h1>webpack is awesome !</h1> <script src="assets/js/shared.js"></script> <script src="assets/js/index.js"></script> </body> </html> // aboutme.html file <html> <head> <title> about me page ! </title> </head> <body> <nav> <a href="index.html">index</a> <a href="contact.html">contact</a> </nav> <h1>webpack is awesome !</h1> <script src="assets/js/shared.js"></script> <script src="assets/js/aboutme.js"></script> </body> </html> // contact.html file <html> <head> <title> contact me page ! </title> </head> <body> <nav> <a href="index.html">index</a> <a href="aboutme.html">about me</a> </nav> <h1>webpack is awesome !</h1> <script src="assets/js/shared.js"></script> <script src="assets/js/contact.js"></script> </body> </html>
var path = require("path"); var webpack = require("webpack"); // وارد کردن پلاگینی از وب پک برای ساخت تکههای مختلف اسکریپتها // معرفی اسکریپت shared.js var commonChunkPlugin = new webpack.optimize.CommonsChunkPlugin("shared.js"); module.exports = { context:path.resolve("js"), //entry:['./shared.js','./main.ts'] // معرفی اسکریپتهای جدید به وبپک entry:{ index:"./main.js", aboutme:"./aboutme.js", contact:"./contact.js" } ,output:{ path:path.resolve("build/js"), publicPath:"assets/js", // filename:'bundle.js' // به جای یک باندل کلی از وبپک میخاهیم برای هر ورودی باندلی جدید بسازد filename:"[name].js" } // رجیستر کردن پلاگین ,plugins:[commonChunkPlugin] , devServer:{ contentBase:"assets" } //,devtool:"#source-map" ,watch :true ,module:{... } }
حال با اجرای وبپک میتوان دید که سه باندل ساخته شده که همگی به اسکریپت shared.js وابستگی دارند و اگر این اسکریپت را از صفحات HTML حذف کنید، با خطا رو به رو خواهید شد. این پلاگین قدرت ساخت باندلهایی با خاصیت مشخص کردن وابستگیها و همچنین تو در توییها خاص را نیز دارد. برای مطالعهی بیشتر میتوانید به اینجا مراجعه کنید: پلاگین commonsChunk
در قسمت بعدی با استفاده از وبپک فایلهای css، فونتها و تصاویر را نیز باندل خواهیم کرد.
فایلهای مطلب:
سورس تا قبل از قسمت ایجاد تغییرات در ساختار فایلهای پروژه :dntwebpack-part3-beforeFileAndFolderManagment.zip
سورس برای بعد از ایجاد تغییرات در ساختار فایلهای پروژه : dntwebpack-part3AfterFileOrganization.zip