- استفاده از WebHost.CreateDefaultBuilder: این روش جهت تنظیم شروع به کار یک برنامهی ASP.NET Core 2x مورد استفاده قرار میگرفت.
- استفاده از Host.CreateDefaultBuilder: روش پیشفرض آغاز برنامههای وب NET Core 3x. و NET 5x. که با معرفی generic host، امکان تهیهی Worker services را میسر کردند.
- استفاده از WebApplication.CreateBuilder: روش جدید شروع به کار با برنامههای وب مبتنی بر NET 6.
استفاده از WebHost.CreateDefaultBuilder در ASP.NET Core 2.x
در نگارش اول ASP.NET Core، مفهومی به نام هاست پیشفرض (default host) وجود نداشت. یکی از مهمترین نکات درنظر گرفته شده در طراحی ASP.NET Core، مفهوم «هزینه کردن به ازای احتیاج» است. یعنی اگر نیاز به قابلیتی نیست، نباید وجود داشته باشد. به این ترتیب یک قالب آغازین نباید به همراه تعداد زیادی بستههای NuGet و مقدار زیادی کد برای تنظیم باشد؛ زمانیکه واقعا قرار نیست از تمام آنها استفاده شود. به همین جهت از نگارش 2، شروع به سادهکردن این قالب اولیه کردند و در این زمان، WebHost.CreateDefaultBuilder ارائه شد. این تنظیم به ظاهر ساده، کدهای پیشفرض مورد نیاز قابل توجهی را جهت ساخت سادهی IWebHostBuilder و IWebHost به همراه دارد. در قالب به همراه آن، بین مفاهیم تنظیمات application و host تفاوت قائل شدهاند؛ یعنی دو فایل Program.cs را برای تنظیمات application و فایل Startup.cs را برای ارائهی تنظیمات هاست، تدارک دیدند.
در این طراحی، بین میدان دید Program و Startup تفاوت وجود دارد. هدف از Program، ارائهی تنظیمات زیرساختی برنامه، مانند تنظیمات HTTP Server، یکپارچگی با IIS و امثال آن شد و عموما در طول عمر برنامه ثابت است. اما برای تغییر رفتار برنامه، بیشتر تغییرات و تنظیمات، به Startup محول شدند؛ مانند تنظیمات تزریق وابستگیها، تنظیمات میانافزارها، مسیریابیها و غیره.
public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .Build(); }
معرفی Generic Host در ASP.NET Core 3.x/5
ASP.NET Core 3.x به همراه تغییرات بزرگی در کدهای آغازین برنامههای ASP.NET Core بود. تا پیش از آن، امکانات پایهی ASP.NET Core تنها برای مقاصد وب قابل استفاده بود. اما در نگارشهای 3x، با ارائهی یک هاست عمومی، امکان پشتیبانی از سایر برنامهها، مانند worker services را نیز میسر کرد؛ برای مثال پیشتیبانی از کارهای طولانی پس زمینه، هاست سرویسهای gRPC، هاست سرویسهای ویندوز و غیره. هدف اصلی از این تغییرات، به اشتراک گذاری فریمورک پایهی ASP.NET Core که تنها برای برنامههای وب ساخته شده بود و به همراه امکاناتی مانند تنظیمات، ثبت وقایع، تزریق وابستگیها و غیره بود، با سایر انواع برنامههای یاد شده است. برای رسیدن به این هدف، Web Host نگارش 2x، به Generic Host نگارش 3x تغییر کرد و سپس ASP.NET Core برفراز آن بنا شد. اینبار بجای IWebHostBuilder، نمونهی جدید IHostBuilder را داریم:
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }; } }
ASP.NET Core 5 به همراه تغییرات مهمی در این زمینه نبود و تنها با تغییر target framework در فایل csproj و به روز رسانی بستههای نیوگت مرتبط، کار ارتقاء به نگارش جدید در آن صورت میگرفت.
معرفی WebApplicationBuilder در ASP.NET Core 6x
در دات نت 6، روش آغاز برنامههای وب بطور کامل تغییر کردهاست. در تمام نگارشهای پیشین ASP.NET Core، همواره شاهد دو فایل Program.cs و Startup.cs بودیم؛ اما در اینجا فقط یک فایل Program.cs بیشتر وجود ندارد. هر چند همانطور که در مطلب «ارتقاء فایلهای آغازین برنامههای ASP.NET Core 5x به 6x» نیز عنوان شد، میتوان همان سبک و سیاق پیشین را نیز برگرداند و از این لحاظ محدودیتی وجود ندارد.
var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorPages(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.MapGet("/", () => "Hello World!"); app.MapRazorPages(); app.Run();
- استفاده از top level statements
- استفاده از usingهای سراسری و سایر قابلیتهای C# 10.0
- حذف کامل کلاس Startup؛ اینبار همه چیز فقط یک فایل است.
دیدگاهی را که در اینجا بکار گرفتهاند شامل این موارد است و بیشتر تازهواردان را مدنظر دارند:
- برای شروع به کار، using statements اضافی هستند؛ پس حذف شدهاند!
- برای شروع به کار، namespaces اضافی هستند؛ پس حذف شدهاند!
- برای شروع به کار، Program.Main ... هم اضافی است!
- تنظیمات بین دو فایل Program.cs و Startup.cs تقیسم نشدهاند و همهچیز یکجا است و این هم نیازی به توضیح اضافی به تازهواردان، ندارد.
- همچنین همانطور که عنوان شد، « ... متد UseStartup به صورت خودکار به دنبال متدهای ویژهی ConfigureServices و Configure در کلاس آغازین برنامه گشته و آنها را فراخوانی میکند تا تنظیمات تزریق وابستگیها، مسیریابیها و میانافزارها صورت گیرند ...»
نکتهی مهم این توضیح، این است که کلاس Startup، هیچ اینترفیسی را پیاده سازی نمیکند. یعنی نام این متدها، دقیقا باید به همین صورت باشند (بدون اینکه قرار دادی توسط یک اینترفیس برای آنها وضع شده باشد) و ... چرا واقعا باید به این صورت باشد؟! به همین جهت اینها هم حذف شدهاند!
- در اینجا WebApplication هم مشاهده میشود؛ اما آیا واقعا نیازی به آن است؟
پاسخ: خیر! WebApplication.CreateBuilder ای که در اینجا ملاحظه میکنید در حقیقت ساده شدهی قطعه کد زیر از کدهای ASP.NET Core 3x/5x است:
var hostBuilder = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddRazorPages(); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.Configure((ctx, app) => { if (ctx.HostingEnvironment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet("/", () => "Hello World!"); endpoints.MapRazorPages(); }); }); }); hostBuilder.Build().Run();
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages(); builder.Services.AddSingleton<MyThingy>();
builder.Logging.AddFile();
var app = builder.Build();
app.UseStaticFiles(); app.MapRazorPages();
CoffeeScript #3
Syntax
Object & Array
برای تعریف Object در CoffeeScript میتوان دقیقا مانند جاوااسکریپت عمل کرد؛ با یک جفت براکت و ساختار کلید / مقدار. البته همانند تابع، نوشتن براکت اختیاری است. در واقع، شما میتوانید از تورفتگی و هر کلید/مقدار، در خط جدید به جای کاما استفاده کنید:
object1 = {one: 1, two: 2} # Without braces object2 = one: 1, two: 2 # Using new lines instead of commas object3 = one: 1 two: 2 User.create(name: "Vahid Mohammad Taheri")
array1 = [1, 2, 3] array2 = [ 1 2 3 ] array3 = [1,2,3,]
Flow control
طبق قاعدهای که برای نوشتن پرانتز در قبل گفته شد (پرانتز اختیاری است)، در دستورات if و else نیز چنین است:
if true == true "We're ok" if true != true then "Vahid" # برابر است با: # (1 > 0) ? "Yes" : "No!" if 1 > 0 then "Yes" else "No!"
CoffeeScript از اپراتورهای شرطی (:?) پشتیبانی نمی کند و به جای آن از if / else استفاده کنید.
CoffeeScript نیز همانند Ruby امکان نوشتن بدنه شرط را به صورت پسوندی ایجاد کرده است.
alert "It's cold!" if 1 < 5
if not true then "Vahid"
unless true "Vahid"
if true is 1 "OK!"
if true isnt true alert "OK!"
الحاق رشته ها
CoffeeScript امکان الحاق رشتهها را با استفاده از روش الحاق رشتهها در Ruby فراهم کرده است. برای انجام این عمل از {}# در داخل " " استفاده کنید که در داخل براکت میتوانید از دستورات مختلف استفاده کنید. برای مثال:favorite_color = "Blue. No, yel..." question = "Sam: What... is your favorite color? Ben: #{favorite_color} Sam: Wrong! "
var favorite_color, question; favorite_color = "Blue. No, yel..."; question = "Sam: What... is your favorite color? Ben: " + favorite_color + " Sam: Wrong!";
using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { using (var session = store.OpenSession()) { store.DatabaseCommands.PutAttachment(key: "file/1", etag: null, data: System.IO.File.OpenRead(@"D:\Prog\packages.config"), metadata: new RavenJObject { { "Description", "توضیحات فایل" } }); var question = new Question { By = "users/Vahid", Title = "Raven Intro", Content = "Test....", FileId = "file/1" }; session.Store(question); session.SaveChanges(); } }
RavenFS یک فایل سیستم مجازی توزیع شدهاست و برای فایلهای بزرگ چند گیگابایتی به طور بهینهای طراحی گردیدهاست تا کارآیی بانک اطلاعاتی را بالا ببرد و وجود فایلهای تکراری، از بین برود. این سیستم جدید شامل سیستم پیش فرض ایندکس گذاری میباشد و به شما این اجازه را میدهد تا بر روی متادیتاهای یک فایل از قبیل حجم، تاریخ آخرین نگارش و حتی متادیتاهای اختصاصی که شما در حین ذخیره سازی به آن اضافه میکنید، به جستوجو بپردازد. این سیستم جدید همچنین این امکان را به شما میدهد تا این اطلاعات را بین Nodeها، با کمترین میزان انتقالات جابجا کنید و دسترسی سریعتری را بین نودهای مختلف داشته باشید.
برای ذخیره سازی یک فایل ابتدا باید یک FileStore را همانند آنچه که برای DocumentStore داشتید تعریف کنید. Url که شامل همان رشته اتصالی بوده و DefaultFileSystem هم همانند DefaultDatabase که نام دیتابیس در آن ذکر میشد، در اینجا نام فایل سیستم ذکر میگردد:
var fileStore = new FilesStore() { Url = "http://localhost:8080", DefaultFileSystem = "SampleFs" }; fileStore.Initialize();
بعد از آن باید از طریق Store جدید یک سشن ایجاد شود و فایل مورد نظر را در قالب یک استریم بخوانیم:
var session = fileStore.OpenAsyncSession(); var stream = File.OpenRead("D:\\Apocalypse.Now.Redux.1979.BDRip.YIFY.mkv");
توجه داشته باشید که برای کار با فایل سیستم، همه متدهای session به صورت غیرهمزمان بوده و متد همزمانی وجود ندارد. سپس در مرحله بعد میخواهم متادیتاهای شخصی نیز به آن اضافه کنیم:
var metadata = new RavenJObject { {"User", "users/1345"}, {"Director","Francis Ford Coppola" }, {"Year","1979" } };
با استفاده از شیء RavenObject میتوانیم در قالب کلید و مقدار، مقادیر خود را ذخیره کنیم و بعد از آن همه موارد بالا که شامل فایل هدر، استریم و متادیتای اختصاصی است را رجیستر کنیم. اگر هم چندین فایل داریم میتوانید آنها را هم در همینجا رجیستر کنید:
session.RegisterUpload("mkv/sample.mkv", stream, metadata);
در مرحله بعدی تغییرات را تایید و عملیات آپلود آغاز میگردد:
await session.SaveChangesAsync();
همانطور که میبینید تمامی متدهای کاربردی این سشن به طور غیرهمزمان طراحی شدهاند.
کلیه عملیاتی که در بالا انجام شد:
var fileStore = new FilesStore() { Url = "http://localhost:8080", DefaultFileSystem = "SampleFs" }; fileStore.Initialize(); var session = fileStore.OpenAsyncSession(); var stream = File.OpenRead("D:\\Apocalypse.Now.Redux.1979.BDRip.YIFY.mkv"); var metadata = new RavenJObject { {"User", "users/1345"}, {"Director","Francis Ford Coppola" }, {"Year","1979" } }; session.RegisterUpload("Mkv/sample.mkv", stream, metadata); await session.SaveChangesAsync();
حالا اگر به نسخه سرور ravenDb مراجعه کنید میبینید که فایل طبق فایل هدر داده شده قرار گرفته است و اطلاعات مربوط به آن ذخیره شده است:
{ "User": "users/1345", "Country": "Iran", "City": "Kashan", "Raven-Synchronization-History": [ { "Version": 4, "ServerId": "42d0cccb-103d-4bf0-9f3d-6f635b1c8ba4" }, { "Version": 5, "ServerId": "42d0cccb-103d-4bf0-9f3d-6f635b1c8ba4" } ], "Raven-Synchronization-Version": "6", "Raven-Synchronization-Source": "42d0cccb-103d-4bf0-9f3d-6f635b1c8ba4" }
برای خواندن هم به شیوه زیر عمل میکنیم:
از طریق Store ایجاد شده، یک سشن جدید را باز میکنیم و فایل مورد نظر را از طریق یکی از متادیتاهای تعریف شده بازیابی میکنیم:
var fileStore = new FilesStore() { Url = "http://localhost:8080", DefaultFileSystem = "SampleFs" }; fileStore.Initialize(); var session = fileStore.OpenAsyncSession(); var file = await session.Query() .WhereEquals("Year", "1979") .FirstOrDefaultAsync();
var stream = await session.DownloadAsync("mkv/"+file.Name);
سپس استریم را روی دیسک سخت دخیره یا به هر مکانی که مد نظر است ارسال میکنیم:
var fs = File.Create("D:\\file2.mkv"); stream.CopyTo(fs); fs.Flush(); fs.Close();
await stream.CopyToAsync(fs);
سپس کل کد بازیابی را به شکل زیر مینویسیم:
var fileStore = new FilesStore() { Url = "http://localhost:8080", DefaultFileSystem = "SampleFs" }; fileStore.Initialize(); var session = fileStore.OpenAsyncSession(); var file = await session.Query() .WhereEquals("Year", "1979") .FirstOrDefaultAsync(); var stream = await session.DownloadAsync("mkv/"+file.Name); var fs = File.Create("D:\\file2.mkv"); await stream.CopyToAsync(fs);
We kindly ask you for your valuable input on the priorities for modernizing investments that the WPF team should focus on, as outlined in the roadmap document for 2023.
Please use thumbs up (no other emoji responses will be considered to avoid duplication) on options below which you would like us to prioritize.
نرم افزاری جهت مدیریت زمان پروژه ها
برخی مواقع مدت زمانی که روی یک پروژه کار کردید را به طور دقیق نمیتوانید اندازی گیری کنید تا بر اساس آن سود و هزینههای خود را محاسبه نمایید این نرم افزار که به صورت رایگان میباشد و تمامی این موارد را در اختیار شما قرار میدهد.
HourGuard Timesheet Software
Time tracking software to log time on customer projects
HourGuard makes it easy to track work hours with its simple-to-use interface. Click Start when you begin work, and Stop when you finish—the time tracking software does the rest for you, generating time sheets and even creating invoices for you.
فقط اگر از NET 5x. به عنوان Target Framework استفاده کنید، زبان تنظیم شدهی پیشفرض آن سیشارپ 9 است. اما اگر برای مثال بخواهید این زبان را در پروژههای مبتنی بر net standard 2.1 که زبان پیشفرض آنها C# 8.0 است نیز فعال کنید، اینکار با بازنویسی صریح شماره نگارش زبان آن در فایل csproj ممکن است:
<LangVersion>9.0</LangVersion>
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; namespace System.Runtime.CompilerServices { /// <summary> /// Reserved to be used by the compiler for tracking metadata. /// This class should not be used by developers in source code. /// </summary> [EditorBrowsable(EditorBrowsableState.Never)] internal static class IsExternalInit { } }