مطالب
آشنایی با ساختار یک Pull Request خوب
در مطلب «نحوه‌ی مشارکت در پروژه‌های GitHub به کمک Visual Studio» با مفهوم pull request آشنا شدیم. اما ... یک pull request خوب چه خصوصیاتی دارد و فرهنگ ارسال یک PR خوب چیست؟

اخلاق مشارکت در یک پروژه‌ی سورس باز

بعضی از توسعه دهنده‌ها در حین مشارکت در یک پروژه‌ی سورس باز، برای مثال جهت افزودن قابلیتی جدید و یا رفع مشکلی، ابتدا سعی می‌کنند تا کدهای فعلی را برای خودشان «قابل فهم‌تر» کنند. این قابل فهم‌تر کردن پروژه، شامل تغییر نام متغیرها و متدهای فعلی، انتقال کدهای موجود به فایل‌هایی دیگر یا حتی یکی کردن چندین فایل با هم، مرتب سازی متدهای یک کلاس بر اساس حروف الفباء و امثال آن می‌شود.
این کارها را نباید در حین مشارکت و توسعه‌ی پروژه‌های سورس باز دیگران انجام دهید! اگر هدفتان رفع مشکلی است یا افزودن قابلیتی جدید، باید نحوه‌ی کدنویسی فعلی را حفظ کنید. از این جهت که نگهدارنده‌ی اصلی پروژه، پیش از شما این‌کار را شروع کرده‌است و زمانیکه شما به پروژه‌ای دیگر رجوع خواهید کرد، باز نیز باید همین کار را ادامه دهد.
اگر refactoring گسترده‌ی شما به هر نحوی سبب بهبود پروژه‌ی اصلی می‌شود، ابتدا این مورد را با مسئول اصلی پروژه مطرح کنید. اگر او قبول کرد، سپس اقدام به چنین کاری نمائید.


بحث در مورد تغییرات پیش از ارسال PR

قبل از اینکه PR ایی را ارسال کنید، بهتر است یک issue یا ticket جدید را باز کرده و در مورد آن بحث کنید یا توضیح دهید. در این حالت ممکن است توضیحات بهتری را در مورد سازگار سازی تغییرات خود با کدهای فعلی دریافت کنید.


Pull requestها را کوچک نگه‌دارید

برای اینکه شانس قبول شدن PR خود را بالا ببرید، حجم و تمرکز آن‌را کوچک نگه دارید. بسیاری از توسعه دهنده‌های سورس باز اگر با یک PR حجیم روبرو شوند، آن‌را رد می‌کنند چون مشکل اصلی، مدت زمان بالایی است که باید جهت بررسی این PR اختصاص داد. هرچقدر حجم آن بیشتر باشد، زمان بیشتری را خواهد برد.


فقط یک کار را انجام دهید

شبیه به اصل تک مسئولیتی کلاس‌ها، یک PR نیز باید تنها یک کار را انجام دهد و بر روی یک موضوع خاص تمرکز داشته باشد. فرض کنید PR ایی را ارسال کرده‌اید که سه مشکل A، B و C را برطرف می‌کند. از دیدگاه مسئول اصلی پروژه، موارد A و C قابل قبول هستند؛ اما نه مورد C مطرح شده. در این حالت کل PR شما برگشت خواهد خورد. به همین جهت بهتر است بجای یک PR، سه PR مختلف و مجزا را جهت رفع مشکلات A، B و C ارسال کنید.


سازگاری تغییرات ارسالی را بررسی کنید

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


PR ایی را بر روی شاخه‌ی master ارسال نکنید

پس از اینکه یک fork از پروژه‌ای سورس باز را ایجاد کردید و سپس آن‌را clone نمودید تا به صورت Local بتوانید با آن کار کنید، فراموش نکنید که در همینجا باید یک branch و انشعاب جدید را جهت کار بر روی ویژگی مدنظر خود ایجاد کنید (برای مثال feature-X, fix-Y). بسیاری از پروژه‌های سورس باز به هیچ عنوان PRهای کار شده‌ی بر روی انشعاب master را قبول نمی‌کنند.


برای مطالعه بیشتر
Open Source Contribution Etiquette  
ten tips for better Pull Requests 
Getting a Pull Request Accepted 
Optimize Your Pull-request 

نظرات مطالب
ساخت بسته‌های نیوگت مخصوص NET Core.
یک نکته‌ی تکمیلی: تولید خودکار بسته‌ی نیوگت پس از Build

در فایل‌‌های csproj بجای ذکر post build event زیر:
<Target Name="PostcompileScript" AfterTargets="Build">
    <Exec Command="dotnet pack --no-build --configuration $(Configuration)" />
</Target>
می‌توان خاصیت GeneratePackageOnBuild را true کرد:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <Version>1.1.1</Version>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
  </PropertyGroup>
</Project>
و یا اگر ترجیح می‌دهید آن‌را توسط NET Core CLI. به صورت مجزا و در زمان مناسبی انجام دهید، دستور نهایی آن به صورت ذیل است:
dotnet pack -c release
نظرات مطالب
EF Code First #1
سلام 
با توجه به خطایی که گذاشته شده به نظر مشکل از ConnectionString  هست و اگر مثال این قسمت رو انجام دادی و instance شما به غیر از (local) است هنگام نوشتن نام DataSource بایستی پرانتز‌ها رو برداری 
<add name="Context"
         connectionString="Data Source=.\sql2012;Initial Catalog=testdb2012;Integrated Security = true"
          providerName="System.Data.SqlClient"
           />

موفق باشید 
پاسخ به بازخورد‌های پروژه‌ها
عدم اجرای پروژه در VS 2012
خطایی که گرفتید عنوان کرده server was not found. یعنی SQL Server رو پیدا نمی‌کنه مطابق کانکشن استرینگ زیر (بررسی کنید آیا سرویس SQL در حال اجرا هست روی سیستم شما؟)
  <add name="IrisDbContext" providerName="System.Data.SqlClient" 
connectionString="Data Source=(local);Integrated Security=true;Initial Catalog=IrisDB" />
اشتراک‌ها
انتشار ویژوال استدیو ۲۰۲۲ نگارش 17.5

For .NET and cloud developers, we’ve focused on improving the inner-loop dev experience. New .http/.rest files make it easier to test and iterate on your APIs directly in Visual Studio, while improved Dev Tunnels help streamline the configuration and management of your webhooks. We’ve also made it easier than ever to deploy your ASP.NET apps to containers.

Game developers can now view properties from base classes modified in an Unreal Blueprint asset without leaving the IDE. Visual Studio has improved the cross-platform development experience with a new remote file explorer, Linux Console output to the Integrated Terminal window, dev container improvements, and more.

Beyond individuals, Visual Studio also has new features to better support dev teams at scale, with exportable configuration files and a persistent update toggle helping ensure everyone on your team is working from the latest version of the tool.

This blog covers several of the top new features in Visual Studio 17.5—to see some in action, watch the Visual Studio 17.5 release video. As always lot of these features come straight from your feedback and suggestions. Your feedback is critical to help us make Visual Studio the best tool it can be! 

انتشار ویژوال استدیو ۲۰۲۲ نگارش 17.5
مطالب دوره‌ها
بررسی Select For XML
تعدادی افزونه‌ی T-SQL، از نگارش‌های پیشین SQL Server، جهت تولید خروجی XML از یک بانک اطلاعاتی رابطه‌ای، به همراه آن بوده‌اند که در این قسمت آن‌ها را بررسی خواهیم کرد.

پیشنیاز بحث

در ادامه، از بانک اطلاعاتی معروف northwind برای تهیه کوئری‌ها استفاده خواهیم کرد. بنابراین فرض بر این است که این بانک اطلاعاتی را پیشتر به وهله‌ی جاری SQL Server خود افزوده‌اید.


بررسی FOR XML RAW

از نگارش 2005 به بعد، Select for XML علاوه بر خروجی متنی XML، توانایی تولید خروجی از نوع XML را نیز یافته است. در ادامه 4 حالت مختلف خروجی آن‌را بررسی خواهیم کرد.
 SELECT Customers.CustomerID, Orders.OrderID
FROM Customers, Orders
WHERE  Customers.CustomerID = Orders.CustomerID
ORDER BY Customers.CustomerID
FOR XML RAW
خروجی For XML Raw کوئری فوق به نحو ذیل است:
 <row CustomerID="ALFKI" OrderID="10643" />
<row CustomerID="ALFKI" OrderID="10692" />
Select for XML در اینجا به صورت خودکار، هر ردیف کوئری را تبدیل به یک المان row نموده و همچنین هر ستون کوئری را تبدیل به ویژگی‌های این المان (attributes) کرده‌است. همچنین باید دقت داشت که خروجی آن یک fragment است و دارای یک root element  مشخص نیست.

برای تغییر حالت خروجی آن می‌توان از حالت ELEMENTS استفاده کرد:
 SELECT Customers.CustomerID, Orders.OrderID
FROM Customers, Orders
WHERE  Customers.CustomerID = Orders.CustomerID
ORDER BY Customers.CustomerID
FOR XML RAW, ELEMENTS
اینبار مقادیر هر ردیف خروجی، بجای ظاهر شدن در ویژگی‌ها، به صورت یک المان نمایش داده می‌شود:
 <row>
  <CustomerID>ALFKI</CustomerID>
  <OrderID>10643</OrderID>
</row>

حالت پیشرفته‌تر FOR XML RAW را در ادامه ملاحظه می‌کنید:
 SELECT Customers.CustomerID,
Orders.OrderID
FROM Customers,
Orders
WHERE  Customers.CustomerID = Orders.CustomerID
ORDER BY
Customers.CustomerID
FOR XML RAW('Customer'), ELEMENTS XSINIL, ROOT('Customers'), XMLSCHEMA('http://MyCustomers')
با استفاده از Root می‌توان Fragment حاصل را تبدیل به Document با یک Root element مشخص کرد. در قسمت Raw نیز می‌توان مقدار پیش فرض row را مقدار دهی کرد.
 <Customers>
  <Customer xmlns="http://MyCustomers">
     <CustomerID>ALFKI</CustomerID>
     <OrderID>10643</OrderID>
  </Customer>
از XSINIL برای مشخص سازی المان‌های نال استفاده می‌شود. اگر XSINIL ذکر نشود، المان‌های نال در خروجی وجود نخواهند داشت.
ذکر XMLSCHEMA، سبب می‌شود تا SQL Server به صورت خودکار XML Schema را بر اساس اطلاعات ستون‌های رابطه‌ای مورد استفاده تولید کند.
این نکات را برای FOR XML AUTO نیز می‌توان بکار برد.


بررسی FOR XML AUTO

حالت دوم بکارگیری Select for XML به همراه عبارت Auto است:
 SELECT Customers.CustomerID, Orders.OrderID
FROM Customers, Orders
WHERE  Customers.CustomerID = Orders.CustomerID
ORDER BY Customers.CustomerID
FOR XML AUTO, ELEMENTS
با خروجی ذیل:
 <Customers>
  <CustomerID>ALFKI</CustomerID>
  <Orders>
     <OrderID>10643</OrderID>
  </Orders>
  <Orders>
     <OrderID>10692</OrderID>
  </Orders>
</Customers>
در اینجا ابتدا شماره مشتری و سپس اطلاعات تمام خریدهای او ذکر می‌شوند.


بررسی For XML Explicit

اگر بخواهیم خروجی را تبدیل به ترکیبی از المان‌ها و ویژگی‌ها کنیم، می‌توان از For XML Explicit استفاده کرد:
 SELECT 1 AS Tag,
NULL AS Parent,
Customers.CustomerID AS [Customers!1!CustomerID],
NULL AS [Order!2!OrderId]
FROM Customers
UNION ALL
SELECT 2,
1,
Customers.CustomerID,
Orders.OrderID
FROM Customers,
Orders
WHERE  Customers.CustomerID = Orders.CustomerID
ORDER BY
[Customers!1!CustomerID]
FOR XML EXPLICIT
با خروجی:
 <Customers CustomerID="ALFKI">
  <Order OrderId="10643" />
  <Order OrderId="10692" />
  <Order OrderId="10702" />
  <Order OrderId="10835" />
  <Order OrderId="10952" />
  <Order OrderId="11011" />
</Customers>
برای استفاده از FOR XML EXPLICIT، باید به ازای هر سطح از سلسله مراتب مورد نظر، یک عبارت select را تهیه کرد که این‌ها نهایتا باید با هم UNION ALL شوند.
به علاوه دو ستون اضافی Tag و Parent نیز باید ذکر شوند. از این دو برای مشخص سازی سلسه مراتب استفاده می‌شوند.
!1! سبب تولید یک ویژگی در سطح اول می‌شود و !2! سبب تولید ویژگی دیگری در سطح دوم.


بررسی  FOR XML PATH

همانطور که مشاهده می‌کنید، نوشتن FOR XML EXPLICIT نسبتا طولانی و پیچیده‌است. برای ساده سازی آن از نگارش 2005 به بعد، روش For XML Path معرفی شده‌است:
 WITH XMLNAMESPACES('http://somens' AS au)
SELECT
  CustomerID AS [@au:CustomerID],
  CompanyName AS [Company/Name],
  ContactName AS [Contact/Name]  
FROM Customers
 FOR XML PATH('Customer')
با خروجی:
 <Customer xmlns:au="http://somens" au:CustomerID="ALFKI">
  <Company>
       <Name>Alfreds Futterkiste</Name>
  </Company>
  <Contact>
      <Name>Maria Anders</Name>
  </Contact>
</Customer>
در اینجا با استفاده از WITH XMLNAMESPACES یک فضای نام جدید را تعریف کرده و سپس نحوه‌ی استفاده از آن‌را توسط یک Alias مشاهده می‌کنید. در اینجا همچنین توسط Aliasها می‌توان یک مسیر مشخص را نیز تعریف کرد. رشته‌ای که در قسمت Path مشخص می‌شود، بیانگر نام المان‌های خروجی است.

یک نکته: اگر کوئری FOR XML PATH را اجرا کنید، نام ستون خروجی به صورت خودکار به XML_F5..6B  تنظیم می‌شود. علت اینجا است که در حالت پیش فرض، نوع خروجی این افزونه، استریم است و نه XML. برای تبدیل آن به نوع XML باید یک Type را اضافه کرد:
 FOR XML PATH('Customer'), Type
در این حالت خروجی FOR XML PATH قابل انتساب به یک متغیر T-SQL از نوع XML خواهد بود.
مطالب
بهینه سازی برنامه‌های وب ASP.NET برای موتورهای جستجو (SEO)
می‌دانیم بهینه‌سازی موتورهای جستجو (به انگلیسی: ‎Search engine optimization (SEO)‎)‏ که گاهی در فارسی به آن سئو نیز گفته می‌شود، عملیاتی است برای بهبود دید یک وب‌گاه یا یک صفحهٔ وب، در صفحه نتایج موتورهای جستجو که می‌تواند طبیعی و یا الگوریتمی باشد. این عملیات برای وبمسترها یکی از عوامل مهم و حیاتی بدست آوردن کاربران جدید از موتورهای جستجو است.

اگر چک لیست‌های SEO وب سایت ها را مشاهده کنیم، می‌توانیم آن‌ها را در دو دسته‌ی کلی بهینه سازی درونی و برونی وب سایت در نظر بگیریم:
Off-Page Optimization
یا برونی ، که بیشتر بر دوش مشاوران سئو و خود مدیران وب سایت است.(link building ، فعالیت در شبکه اجتماعی و ...)
و اما در حوزه On-Page Optimization یا درونی که بخش‌های مهمی از آن وظیفه‌ی مابرنامه نویس‌ها است.(H1 Tag ، URL Naming ، Meta Tags ، عنوان صفحه و ...)
[البته عامل درونی بهینه سازی محتوا (Content Optimization)  که مهمترین عامل در الگوریتم‌های نسل جدید موتورهای جستجو و همچنین الگوریتم جدید گوگل+) به حساب می‌آید بر عهده مشاوران سئو و خود مدیران وب سایت می‌باشد]


در ادامه به ارائه چند راهکار جهت بهینه سازی برنامه‌های وب ASP.NET مان برای موتورهای جستجو می‌پردازیم:


1.متدی برای ایجاد عنوان سایت
    private const string SeparatorTitle = " - ";
    private const int MaxLenghtTitle = 60;
    public static string GeneratePageTitle(params string[] crumbs)
    {
        var title = "";

        for (int i = 0; i < crumbs.Length; i++)
        {
            title += string.Format
                        (
                            "{0}{1}",
                            crumbs[i],
                            (i < crumbs.Length - 1) ? SeparatorTitle : string.Empty
                        );
        }

        title = title.Substring(0, title.Length <= MaxLenghtTitle ? title.Length : MaxLenghtTitle).Trim();

        return title;
    }
نکته :
  • MaxLenghtTitle پیشنهادی برای عنوان سایت 60 می‌باشد.

2.متدی برای ایجاد متاتگ صفحات سایت
public enum CacheControlType
{
    [Description("public")]
    _public,
    [Description("private")]
    _private,
    [Description("no-cache")]
    _nocache,
    [Description("no-store")]
    _nostore
}  
private const int MaxLenghtTitle = 60; private const int MaxLenghtDescription = 170; private const string FaviconPath = "~/cdn/ui/favicon.ico"; public static string GenerateMetaTag(string title, string description, bool allowIndexPage, bool allowFollowLinks, string author = "", string lastmodified = "", string expires = "never", string language = "fa", CacheControlType cacheControlType = CacheControlType._private) { title = title.Substring(0, title.Length <= MaxLenghtTitle ? title.Length : MaxLenghtTitle).Trim(); description = description.Substring(0, description.Length <= MaxLenghtDescription ? description.Length : MaxLenghtDescription).Trim(); var meta = ""; meta += string.Format("<title>{0}</title>\n", title); meta += string.Format("<link rel=\"shortcut icon\" href=\"{0}\"/>\n", FaviconPath); meta += string.Format("<meta http-equiv=\"content-language\" content=\"{0}\"/>\n", language); meta += string.Format("<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/>\n"); meta += string.Format("<meta charset=\"utf-8\"/>\n"); meta += string.Format("<meta name=\"description\" content=\"{0}\"/>\n", description); meta += string.Format("<meta http-equiv=\"Cache-control\" content=\"{0}\"/>\n", EnumExtensions.EnumHelper<CacheControlType>.GetEnumDescription(cacheControlType.ToString())); meta += string.Format("<meta name=\"robots\" content=\"{0}, {1}\" />\n", allowIndexPage ? "index" : "noindex", allowFollowLinks ? "follow" : "nofollow"); meta += string.Format("<meta name=\"expires\" content=\"{0}\"/>\n", expires); if (!string.IsNullOrEmpty(lastmodified)) meta += string.Format("<meta name=\"last-modified\" content=\"{0}\"/>\n", lastmodified); if (!string.IsNullOrEmpty(author)) meta += string.Format("<meta name=\"author\" content=\"{0}\"/>\n", author); //------------------------------------Google & Bing Doesn't Use Meta Keywords ... //meta += string.Format("<meta name=\"keywords\" content=\"{0}\"/>\n", keywords); return meta; }
چند نکته :

3.متدی برای ایجاد Slug ( اسلاگ آدرسی با مفهوم برای بکار بردن در URL ها است که دوست‌دار موتورهای جستجو می‌باشد)
private const int MaxLenghtSlug = 45;
public static string GenerateSlug(string title)
{
        var slug = RemoveAccent(title).ToLower();
        slug = Regex.Replace(slug, @"[^a-z0-9-\u0600-\u06FF]", "-");
        slug = Regex.Replace(slug, @"\s+", "-").Trim();
        slug = Regex.Replace(slug, @"-+", "-");
        slug = slug.Substring(0, slug.Length <= MaxLenghtSlug ? slug.Length : MaxLenghtSlug).Trim();

        return slug;
}
    
private static string RemoveAccent(string text)
{
        var bytes = Encoding.GetEncoding("UTF-8").GetBytes(text);
        return Encoding.UTF8.GetString(bytes);
}
نکته :
  • MaxLenghtSlug پیشنهادی برای عنوان سایت 45 می‌باشد. 

نمونه ای از کاربرد توابع :
   Head.InnerHtml = SEO.GenerateMetaTag
                            (
                                title: SEO.GeneratePageTitle(".NET Tips", "آرشیو مطالب", "ASP.NET MVC #1"),
                                description: "چرا ASP.NET MVC با وجود فریم ورک پخته‌ای به نام ASP.NET web forms، اولین سؤالی که حین سوئیچ به ASP.NET MVC مطرح می‌شود این است: «برای چی؟». بنابراین تا به این سؤال پاسخ داده نشود، هر نوع بحث فنی در این مورد بی فایده است.",
                                allowIndexPage: true,
                                allowFollowLinks: true,
                                author: "وحید نصیری",
                                cacheControlType: SEO.CacheControlType._private
                            );
و خروجی در Page Source :
<title>.NET Tips - آرشیو مطالب - ASP.NET MVC #1</title>
<link rel="shortcut icon" href="../../cdn/images/ui/favicon.ico"/>
<meta http-equiv="content-language" content="fa"/>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta charset="utf-8"/>
<meta name="description" content="چرا ASP.NET MVC ؟با وجود فریم ورک پخته‌ای به نام ASP.NET web forms، اولین سؤالی که حین سوئیچ به ASP.NET MVC مطرح می‌شود این است: &#171;برای چی؟&#187;. بن ..."/>
<meta http-equiv="Cache-control" content="private"/>
<meta name="robots" content="index, follow" />
<meta name="expires" content="never"/>
<meta name="author" content="وحید نصیری"/>
موفق باشید
اشتراک‌ها
مایکروسافت و ارائه‌ی یک Build سفارشی از OpenJDK

Today we are excited to announce the preview of the Microsoft Build of OpenJDK, a new no-cost Long-Term Support (LTS) distribution of OpenJDK that is open source and available for free for anyone to deploy anywhere. It includes binaries for Java 11, based on OpenJDK 11.0.10+9, on x64 server and desktop environments on macOS, Linux, and Windows. We are also publishing a new Early Access binary for Java 16 for Windows on ARM, based on the latest OpenJDK 16+36 release. 

مایکروسافت و ارائه‌ی یک Build سفارشی از OpenJDK
نظرات مطالب
روش‌هایی برای بهبود قابلیت دیباگ بسته‌های NuGet
یک نکته‌ی تکمیلی
مایکروسافت توصیه کرده که از روش قرار دادن اطلاعات دیباگ در بسته‌ی نیوگت نهایی استفاده کنید:
<!-- Embed source files that are not tracked by the source control manager in the PDB -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>

<!-- Recommended: Embed symbols containing Source Link in the main file (exe/dll) -->
<DebugType>embedded</DebugType>