public class FingerPrint { private static string fingerPrint = string.Empty; public static string Value() { if (string.IsNullOrEmpty(fingerPrint)) { fingerPrint = GetHash("CPU >> " + cpuId() + "\nBIOS >> " + biosId() + "\nBASE >> " + baseId() +"\nDISK >> "+ diskId() + "\nVIDEO >> " + videoId() +"\nMAC >> "+ macId()); } return fingerPrint; } private static string GetHash(string s) { MD5 sec = new MD5CryptoServiceProvider(); ASCIIEncoding enc = new ASCIIEncoding(); byte[] bt = enc.GetBytes(s); return GetHexString(sec.ComputeHash(bt)); } private static string GetHexString(byte[] bt) { string s = string.Empty; for (int i = 0; i < bt.Length; i++) { byte b = bt[i]; int n, n1, n2; n = (int)b; n1 = n & 15; n2 = (n >> 4) & 15; if (n2 > 9) s += ((char)(n2 - 10 + (int)'A')).ToString(); else s += n2.ToString(); if (n1 > 9) s += ((char)(n1 - 10 + (int)'A')).ToString(); else s += n1.ToString(); if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-"; } return s; } #region Original Device ID Getting Code //Return a hardware identifier private static string identifier (string wmiClass, string wmiProperty, string wmiMustBeTrue) { string result = ""; System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass); System.Management.ManagementObjectCollection moc = mc.GetInstances(); foreach (System.Management.ManagementObject mo in moc) { if (mo[wmiMustBeTrue].ToString() == "True") { //Only get the first one if (result == "") { try { result = mo[wmiProperty].ToString(); break; } catch { } } } } return result; } //Return a hardware identifier private static string identifier(string wmiClass, string wmiProperty) { string result = ""; System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass); System.Management.ManagementObjectCollection moc = mc.GetInstances(); foreach (System.Management.ManagementObject mo in moc) { //Only get the first one if (result == "") { try { result = mo[wmiProperty].ToString(); break; } catch { } } } return result; } private static string cpuId() { //Uses first CPU identifier available in order of preference //Don't get all identifiers, as it is very time consuming string retVal = identifier("Win32_Processor", "UniqueId"); if (retVal == "") //If no UniqueID, use ProcessorID { retVal = identifier("Win32_Processor", "ProcessorId"); if (retVal == "") //If no ProcessorId, use Name { retVal = identifier("Win32_Processor", "Name"); if (retVal == "") //If no Name, use Manufacturer { retVal = identifier("Win32_Processor", "Manufacturer"); } //Add clock speed for extra security retVal += identifier("Win32_Processor", "MaxClockSpeed"); } } return retVal; } //BIOS Identifier private static string biosId() { return identifier("Win32_BIOS", "Manufacturer") + identifier("Win32_BIOS", "SMBIOSBIOSVersion") + identifier("Win32_BIOS", "IdentificationCode") + identifier("Win32_BIOS", "SerialNumber") + identifier("Win32_BIOS", "ReleaseDate") + identifier("Win32_BIOS", "Version"); } //Main physical hard drive ID private static string diskId() { return identifier("Win32_DiskDrive", "Model") + identifier("Win32_DiskDrive", "Manufacturer") + identifier("Win32_DiskDrive", "Signature") + identifier("Win32_DiskDrive", "TotalHeads"); } //Motherboard ID private static string baseId() { return identifier("Win32_BaseBoard", "Model") + identifier("Win32_BaseBoard", "Manufacturer") + identifier("Win32_BaseBoard", "Name") + identifier("Win32_BaseBoard", "SerialNumber"); } //Primary video controller ID private static string videoId() { return identifier("Win32_VideoController", "DriverVersion") + identifier("Win32_VideoController", "Name"); } //First enabled network card ID private static string macId() { return identifier("Win32_NetworkAdapterConfiguration", "MACAddress", "IPEnabled"); } #endregion }
/// Generates a 16 byte Unique Identification code of a computer /// Example: 4876-8DB5-EE85-69D3-FE52-8CF7-395D-2EA9 var computerId = FingerPrint.Value();
در این سیستم، کلیه اتصالاتی که Mode آنها به OneTime تنظیم نشده است، به صورت اجباری دارای یک valueChangedHandlers متصل توسط سیستم PropertyDescriptor خواهند بود و در حافظه زنده نگه داشته میشوند؛ تا بتوان در صورت نیاز، توسط سیستم binding اطلاعات آنها را به روز کرد.
همین مساله سبب میشود تا اگر قرار نیست خاصیتی برای نمونه توسط مکانیزم INotifyPropertyChanged اطلاعات UI را به روز کند (یک خاصیت معمولی دات نتی است) و همچنین حالت اتصال آن به OneTime نیز تنظیم نشده، سبب مصرف حافظه بیش از حد برنامه شود.
اطلاعات بیشتر
A memory leak may occur when you use data binding in Windows Presentation Foundation
راه حل آن هم ساده است. برای اینکه valueChangedHandler ایی به خاصیت سادهای که قرار نیست بعدها UI را به روز کند، متصل نشود، حالت اتصال آنرا باید به OneTime تنظیم کرد.
سؤال: در یک برنامه بزرگ که هم اکنون مشغول به کار است، چطور میتوان این مسایل را ردیابی کرد؟
برای دستیابی به اطلاعات کش Binding در WPF، باید به Reflection متوسل شد. به این ترتیب در برنامه جاری، در کلاس PropertyDescriptor به دنبال یک کلاس خصوصی تو در توی دیگری به نام ReflectTypeDescriptionProvider خواهیم گشت (این اطلاعات از طریق مراجعه به سورس دات نت و یا حتی برنامههای ILSpy و Reflector قابل استخراج است) و سپس در این کلاس خصوصی داخلی، فیلد خصوصی propertyCache آنرا که از نوع HashTable است استخراج میکنیم:
var reflectTypeDescriptionProvider = typeof(PropertyDescriptor).Module.GetType("System.ComponentModel.ReflectTypeDescriptionProvider"); var propertyCacheField = reflectTypeDescriptionProvider.GetField("_propertyCache", BindingFlags.Static | BindingFlags.NonPublic);
اکنون به لیست داخلی Binding نگهداری شونده توسط WPF دسترسی پیدا کردهایم. در این لیست به دنبال مواردی خواهیم گشت که فیلد valueChangedHandlers به آنها متصل شده است و در حال گوش فرا دادن به سیستم binding هستند (سورس کامل و طولانی این مبحث را در پروژه پیوست شده میتوانید ملاحظه کنید).
یک مثال: تعریف یک کلاس ساده، اتصال آن و سپس بررسی اطلاعات درونی سیستم Binding
فرض کنید یک کلاس مدل ساده به نحو ذیل تعریف شده است:
namespace WpfOneTime.Models { public class User { public string Name { set; get; } } }
using WpfOneTime.Models; using System.Collections.Generic; namespace WpfOneTime.ViewModels { public class MainWindowViewModel { public IList<User> Users { set; get; } public MainWindowViewModel() { Users = new List<User>(); for (int i = 0; i < 1000; i++) { Users.Add(new User { Name = "name " + i }); } } } }
<Window x:Class="WpfOneTime.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ViewModels="clr-namespace:WpfOneTime.ViewModels" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <ViewModels:MainWindowViewModel x:Key="vmMainWindowViewModel" /> </Window.Resources> <Grid DataContext="{Binding Source={StaticResource vmMainWindowViewModel}}"> <ListBox ItemsSource="{Binding Users}"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Window>
خوب؛ اکنون اگر اطلاعات HashTable داخلی سیستم Binding را در مورد View فوق بررسی کنیم به شکل زیر خواهیم رسید:
بله. تعداد زیادی خاصیت Name زنده و موجود در حافظه باقی هستند که تحت ردیابی سیستم Binding میباشند.
در ادامه، نکتهی ابتدای بحث را جهت تعیین حالت Binding به OneTime، به View فوق اعمال میکنیم (یک سطر ذیل باید تغییر کند):
<TextBlock Text="{Binding Name, Mode=OneTime}" />
به این ترتیب میتوان در لیستهای طولانی، به مصرف حافظه کمتری در برنامه WPF خود رسید.
بدیهی است این نکته را تنها در مواردی میتوان اعمال کرد که نیاز به بهروز رسانیهای ثانویه اطلاعات UI در کدهای برنامه وجود ندارند.
چطور از این نکته برای پروفایل یک برنامه موجود استفاده کنیم؟
کدهای برنامه را از انتهای بحث دریافت کنید. سپس دو فایل ReflectPropertyDescriptorWindow.xaml و ReflectPropertyDescriptorWindow.xaml.cs آنرا به پروژه خود اضافه نمائید و در سازنده پنجره اصلی برنامه، کد ذیل را فراخوانی نمائید:
new ReflectPropertyDescriptorWindow().Show();
دریافت کدهای کامل پروژه این مطلب
WpfOneTime.zip
- با نصب و اجرای Visual Studio 2013 Express for Web یا Visual Studio 2013 شروع کنید.
- یک پروژه جدید بسازید (از صفحه شروع یا منوی فایل)
- گزینه #Visual C و سپس ASP.NET Web Application را انتخاب کنید. نام پروژه را به "WebFormsIdentity" تغییر داده و OK کنید.
- در دیالوگ جدید ASP.NET گزینه Empty را انتخاب کنید.
دقت کنید که دکمه Change Authentication غیرفعال است و هیچ پشتیبانی ای برای احراز هویت در این قالب پروژه وجود ندارد.
افزودن پکیجهای ASP.NET Identity به پروژه
دقت کنید که نصب کردن این پکیج وابستگیها را نیز بصورت خودکار نصب میکند: Entity Framework و ASP.NET Idenity Core.
افزودن فرمهای وب لازم برای ثبت نام کاربران
در دیالوگ باز شده نام فرم را به Register تغییر داده و تایید کنید.
فایل ایجاد شده جدید را باز کرده و کد Markup آن را با قطعه کد زیر جایگزین کنید.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Register.aspx.cs" Inherits="WebFormsIdentity.Register" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body style=" <form id="form1" runat="server"> <div> <h4 style="Register a new user</h4> <hr /> <p> <asp:Literal runat="server" ID="StatusMessage" /> </p> <div style="margin-bottom:10px"> <asp:Label runat="server" AssociatedControlID="UserName">User name</asp:Label> <div> <asp:TextBox runat="server" ID="UserName" /> </div> </div> <div style="margin-bottom:10px"> <asp:Label runat="server" AssociatedControlID="Password">Password</asp:Label> <div> <asp:TextBox runat="server" ID="Password" TextMode="Password" /> </div> </div> <div style="margin-bottom:10px"> <asp:Label runat="server" AssociatedControlID="ConfirmPassword">Confirm password</asp:Label> <div> <asp:TextBox runat="server" ID="ConfirmPassword" TextMode="Password" /> </div> </div> <div> <div> <asp:Button runat="server" OnClick="CreateUser_Click" Text="Register" /> </div> </div> </div> </form> </body> </html>
این تنها یک نسخه ساده شده Register.aspx است که از چند فیلد فرم و دکمه ای برای ارسال آنها به سرور استفاده میکند.
فایل کد این فرم را باز کرده و محتویات آن را با قطعه کد زیر جایگزین کنید.
using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; using System; using System.Linq; namespace WebFormsIdentity { public partial class Register : System.Web.UI.Page { protected void CreateUser_Click(object sender, EventArgs e) { // Default UserStore constructor uses the default connection string named: DefaultConnection var userStore = new UserStore<IdentityUser>(); var manager = new UserManager<IdentityUser>(userStore); var user = new IdentityUser() { UserName = UserName.Text }; IdentityResult result = manager.Create(user, Password.Text); if (result.Succeeded) { StatusMessage.Text = string.Format("User {0} was created successfully!", user.UserName); } else { StatusMessage.Text = result.Errors.FirstOrDefault(); } } } }
کد این فرم نیز نسخه ای ساده شده است. فایلی که بصورت خودکار توسط VS برای شما ایجاد میشود متفاوت است.
کلاس IdentityUser پیاده سازی پیش فرض EntityFramework از قرارداد IUser است. قرارداد IUser تعریفات حداقلی یک کاربر در ASP.NET Identity Core را در بر میگیرد.
کلاس UserStore پیاده سازی پیش فرض EF از یک فروشگاه کاربر (user store) است. این کلاس چند قرارداد اساسی ASP.NET Identity Core را پیاده سازی میکند: IUserStore, IUserLoginStore, IUserClaimStore و IUserRoleStore.
کلاس UserManager دسترسی به APIهای مربوط به کاربران را فراهم میکند. این کلاس تمامی تغییرات را بصورت خودکار در UserStore ذخیره میکند.
کلاس IdentityResult نتیجه یک عملیات هویتی را معرفی میکند (identity operations).
پوشه App_Data را به پروژه خود اضافه کنید.
فایل Web.config پروژه را باز کنید و رشته اتصال جدیدی برای دیتابیس اطلاعات کاربران اضافه کنید. این دیتابیس در زمان اجرا (runtime) بصورت خودکار توسط EF ساخته میشود. این رشته اتصال شبیه به رشته اتصالی است که هنگام ایجاد پروژه بصورت خودکار برای شما تنظیم میشود.
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <connectionStrings> <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\WebFormsIdentity.mdf;Initial Catalog=WebFormsIdentity;Integrated Security=True" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> </system.web> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="v11.0" /> </parameters> </defaultConnectionFactory> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> </providers> </entityFramework> </configuration>
همانطور که مشاهده میکنید نام این رشته اتصال DefaultConnection است.
روی فایل Register.aspx کلیک راست کنید و گزینه Set As Start Page را انتخاب کنید. اپلیکیشن خود را با کلیدهای ترکیبی Ctrl + F5 اجرا کنید که تمام پروژه را کامپایل نیز خواهد کرد. یک نام کاربری و کلمه عبور وارد کنید و روی Register کلیک کنید.
ASP.NET Identity از اعتبارسنجی نیز پشتیبانی میکند، مثلا در این مرحله میتوانید از اعتبارسنج هایی که توسط ASP.NET Identity Core عرضه میشوند برای کنترل رفتار فیلدهای نام کاربری و کلمه عبور استفاده کنید. اعتبارسنج پیش فرض کاربران (User) که UserValidator نام دارد خاصیتی با نام AllowOnlyAlphanumericUserNames دارد که مقدار پیش فرضش هم true است. اعتبارسنج پیش فرض کلمه عبور (MinimumLengthValidator) اطمینان حاصل میکند که کلمه عبور حداقل 6 کاراکتر باشد. این اعتبارسنجها بصورت propertyها در کلاس UserManager تعریف شده اند و میتوانید آنها را overwrite کنید و اعتبارسنجی سفارشی خود را پیاده کنید. از آنجا که الگوی دیتابیس سیستم عضویت توسط Entity Framework مدیریت میشود، روی الگوی دیتابیس کنترل کامل دارید، پس از Data Annotations نیز میتوانید استفاده کنید.
تایید دیتابیس LocalDbIdentity که توسط EF ساخته میشود
گره (DefaultConnection (WebFormsIdentity و سپس Tables را باز کنید. روی جدول AspNetUsers کلیک راست کرده و Show Table Data را انتخاب کنید.
پیکربندی اپلیکیشن برای استفاده از احراز هویت OWIN
نصب پکیجهای احراز هویت روی پروژه
به دنبال پکیجی با نام Microsoft.Owin.Host.SystemWeb بگردید و آن را نیز نصب کنید.
پکیج Microsoft.Aspnet.Identity.Owin حاوی یک سری کلاس Owin Extension است و امکان مدیریت و پیکربندی OWIN Authentication در پکیجهای ASP.NET Identity Core را فراهم میکند.
پکیج Microsoft.Owin.Host.SystemWeb حاوی یک سرور OWIN است که اجرای اپلیکیشنهای مبتنی بر OWIN را روی IIS و با استفاده از ASP.NET Request Pipeline ممکن میسازد. برای اطلاعات بیشتر به OWIN Middleware in the IIS integrated pipeline مراجعه کنید.
افزودن کلاسهای پیکربندی Startup و Authentication
فایل Startup.cs را باز کنید و قطعه کد زیر را با محتویات آن جایگزین کنید تا احراز هویت OWIN Cookie Authentication پیکربندی شود.
using Microsoft.AspNet.Identity; using Microsoft.Owin; using Microsoft.Owin.Security.Cookies; using Owin; [assembly: OwinStartup(typeof(WebFormsIdentity.Startup))] namespace WebFormsIdentity { public class Startup { public void Configuration(IAppBuilder app) { // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888 app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Login") }); } } }
این کلاس حاوی خاصیت OwinAttribute است که کلاس راه انداز OWIN را نشانه گذاری میکند. هر اپلیکیشن OWIN یک کلاس راه انداز (startup) دارد که توسط آن میتوانید کامپوننتهای application pipeline را مشخص کنید. برای اطلاعات بیشتر درباره این مدل، به OWIN Startup Class Detection مراجعه فرمایید.
افزودن فرمهای وب برای ثبت نام و ورود کاربران
using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.Owin.Security; using System; using System.Linq; using System.Web; namespace WebFormsIdentity { public partial class Register : System.Web.UI.Page { protected void CreateUser_Click(object sender, EventArgs e) { // Default UserStore constructor uses the default connection string named: DefaultConnection var userStore = new UserStore<IdentityUser>(); var manager = new UserManager<IdentityUser>(userStore); var user = new IdentityUser() { UserName = UserName.Text }; IdentityResult result = manager.Create(user, Password.Text); if (result.Succeeded) { var authenticationManager = HttpContext.Current.GetOwinContext().Authentication; var userIdentity = manager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie); authenticationManager.SignIn(new AuthenticationProperties() { }, userIdentity); Response.Redirect("~/Login.aspx"); } else { StatusMessage.Text = result.Errors.FirstOrDefault(); } } } }
فایل Login.aspx را باز کنید و کد Markup آن را مانند قطعه کد زیر تغییر دهید.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="WebFormsIdentity.Login" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body style="font-family: Arial, Helvetica, sans-serif; font-size: small"> <form id="form1" runat="server"> <div> <h4 style="font-size: medium">Log In</h4> <hr /> <asp:PlaceHolder runat="server" ID="LoginStatus" Visible="false"> <p> <asp:Literal runat="server" ID="StatusText" /> </p> </asp:PlaceHolder> <asp:PlaceHolder runat="server" ID="LoginForm" Visible="false"> <div style="margin-bottom: 10px"> <asp:Label runat="server" AssociatedControlID="UserName">User name</asp:Label> <div> <asp:TextBox runat="server" ID="UserName" /> </div> </div> <div style="margin-bottom: 10px"> <asp:Label runat="server" AssociatedControlID="Password">Password</asp:Label> <div> <asp:TextBox runat="server" ID="Password" TextMode="Password" /> </div> </div> <div style="margin-bottom: 10px"> <div> <asp:Button runat="server" OnClick="SignIn" Text="Log in" /> </div> </div> </asp:PlaceHolder> <asp:PlaceHolder runat="server" ID="LogoutButton" Visible="false"> <div> <div> <asp:Button runat="server" OnClick="SignOut" Text="Log out" /> </div> </div> </asp:PlaceHolder> </div> </form> </body> </html>
محتوای فایل Login.aspx.cs را نیز مانند لیست زیر تغییر دهید.
using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.Owin.Security; using System; using System.Web; using System.Web.UI.WebControls; namespace WebFormsIdentity { public partial class Login : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { if (User.Identity.IsAuthenticated) { StatusText.Text = string.Format("Hello {0}!", User.Identity.GetUserName()); LoginStatus.Visible = true; LogoutButton.Visible = true; } else { LoginForm.Visible = true; } } } protected void SignIn(object sender, EventArgs e) { var userStore = new UserStore<IdentityUser>(); var userManager = new UserManager<IdentityUser>(userStore); var user = userManager.Find(UserName.Text, Password.Text); if (user != null) { var authenticationManager = HttpContext.Current.GetOwinContext().Authentication; var userIdentity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie); authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = false }, userIdentity); Response.Redirect("~/Login.aspx"); } else { StatusText.Text = "Invalid username or password."; LoginStatus.Visible = true; } } protected void SignOut(object sender, EventArgs e) { var authenticationManager = HttpContext.Current.GetOwinContext().Authentication; authenticationManager.SignOut(); Response.Redirect("~/Login.aspx"); } } }
- متد Page_Load حالا وضعیت کاربر جاری را بررسی میکند و بر اساس وضعیت Context.User.Identity.IsAuthenticated تصمیم گیری میکند.
- متد SignIn
- پروژه را با Ctrl + F5 اجرا کنید و کاربر جدیدی بسازید. پس از وارد کردن نام کاربری و کلمه عبور و کلیک کردن دکمه Register باید بصورت خودکار به سایت وارد شوید و نام خود را مشاهده کنید.
- همانطور که مشاهده میکنید در این مرحله حساب کاربری جدید ایجاد شده و به سایت وارد شده اید. روی Log out کلیک کنید تا از سایت خارج شوید. پس از آن باید به صفحه ورود هدایت شوید.
- حالا یک نام کاربری یا کلمه عبور نامعتبر وارد کنید و روی Log in کلیک کنید.
زمان ریلیز نسخه .net core
Null Coalescing در TypeScript 3.7
Windows Live Writer سورس باز شد
Visual Studio 2017 15.6 منتشر شد
- We improved solution load performance by optimizing design time build.
- We've added installation progress details on Visual Studio Installer.
- You can pause your installation and resume at a later time.
- We streamlined the update process so the notification takes you directly to the Installer.
- Non-administrators can create a VS layout.
- We added a new shortcut for Edit.Duplicate in the keyboard mapping.
- We made significant improvements to the F# language and tools, particularly for .NET Core SDK projects.
- The C++ compiler optimizes your code to run faster through improved optimizations.
- C++ Mapfile generation overhead is reduced in full linking scenarios.
- Debug options are available for Embedded ARM GCC support.
- We added strong name signing on CoreCLR for the C# compiler.
- Visual Studio Tools for Xamarin has lots of new productivity updates for iOS and Android developers.
- Python no longer requires a completion DB, and Anaconda users have support for conda.
- The Performance Profiler's CPU Usage Tool can display logical call stacks for asynchronous code.
- The CPU Usage tool displays source line highlighting and async/await code with logical 'Call Stack Stitching'.
- The debugger supports thread names set via SetThreadDescription APIs in dump debugging.
- Snapshot Debugging can be started from the Debug Target dropdown for ASP.NET applications.
- We've launched the initial implementation of Navigate to decompiled sources for .NET code navigation.
- New enhancements for Configure Continuous Delivery include support for TFVC, Git authentication over SSH, and containerized projects.
- You can now click on the Continuous Delivery tile in Team Explorer to configure automated build and deployments for your application.
- Team Explorer supports Git tags and checking out pull request branches.
- Service Fabric Tooling for the 6.1 Service Fabric release is now available.
- The Windows 10 Insider Preview SDK can be installed as an optional component.
- File versions for a number of Visual Studio executables now reflect the minor release.
- Test Explorer has a hierarchy view and real time test discovery is now on by default.
- We have added support for testing Win10 IoT Core applications.
- Visual Studio Build Tools supports TypeScript and Node.js.
- ClickOnce Tools support signing application and deployment manifests with CNG certificate.
- You can access Azure resources such as Key Vault using your Visual Studio accounts.