Query: Regression in EF 6.1.2: OUTER APPLY introduced and more compex queries for 1:1 relationships and "let" clauseTPT problem with hiding base class property in inherited classDbMigration.Sql fails when the word 'go' is contained in the textCreate compatibility flag for UnionAll and Intersect flattening supportQuery with multiple Includes does not work in 6.1.2 (working in 6.1.1)"You have an error in your SQL syntax" after upgrading from EF 6.1.1 to 6.1.2
مبانی TypeScript؛ اینترفیسها
- Typewriter
Using Typewriter to Strongly-Type Your Client-Side Models and Services
- NSwag
- TypeLITE
- gulp-typescript-cs-poco
This post shows how to import and export .xls or .xlsx (Excel files) in ASP.NET Core. And when thinking about dealing with excel with .NET, we always look for third-party libraries or component. And one of the most popular .net library that reads and writes Excel 2007/2010 files using the Open Office Xml format (xlsx) is EPPlus. However, at the time of writing this post, this library is not updated to support .NET Core. But there exists an unofficial version of this library EPPlus.Core which can do the job of import and export xlsx in ASP.NET Core. This works on Windows, Linux and Mac.
Blazor 5x - قسمت 25 - تهیه API مخصوص Blazor WASM - بخش 2 - تامین پایهی اعتبارسنجی و احراز هویت
- «معرفی JSON Web Token»
توسعهی IdentityUser
در قسمتهای 21 تا 23، روش نصب و یکپارچگی ASP.NET Core Identity را با یک برنامهی Blazor Server بررسی کردیم. در پروژهی Web API جاری هم از قصد داریم از ASP.NET Core Identity استفاده کنیم؛ البته بدون نصب UI پیشفرض آن. به همین جهت فقط از ApplicationDbContext آن برنامه که از IdentityDbContext مشتق شده و همچنین قسمتی از تنظیمات سرویسهای ابتدایی آن که در قسمت قبل بررسی کردیم، در اینجا استفاده خواهیم کرد.
IdentityUser پیشفرض که معرف موجودیت کاربران یک سیستم مبتنی بر ASP.NET Core Identity است، برای ثبت نام یک کاربر، فقط به ایمیل و کلمهی عبور او نیاز دارد که نمونهای از آنرا در حین معرفی «ثبت کاربر ادمین Identity» بررسی کردیم. اکنون میخواهیم این موجودیت پیشفرض را توسعه داده و برای مثال نام کاربر را نیز به آن اضافه کنیم. برای اینکار فایل جدید BlazorServer\BlazorServer.Entities\ApplicationUser .cs را به پروژهی Entities با محتوای زیر اضافه میکنیم:
using Microsoft.AspNetCore.Identity; namespace BlazorServer.Entities { public class ApplicationUser : IdentityUser { public string Name { get; set; } } }
اکنون که یک ApplicationUser سفارشی را ایجاد کردیم، نیازی نیست تا DbSet خاص آنرا به ApplicationDbContext برنامه اضافه کنیم. برای معرفی آن به برنامه ابتدا باید به فایل BlazorServer\BlazorServer.DataAccess\ApplicationDbContext.cs مراجعه کرده و نوع IdentityUser را به IdentityDbContext، از طریق آرگومان جنریکی که میپذیرد، معرفی کنیم:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
پس از این تغییر، در فایل BlazorWasm\BlazorWasm.WebApi\Startup.cs نیز باید ApplicationUser را به عنوان نوع جدید کاربران، معرفی کرد:
namespace BlazorWasm.WebApi { public class Startup { // ... public void ConfigureServices(IServiceCollection services) { services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); // ...
پس از این تغییرات، باید از طریق خط فرمان به پوشهی BlazorServer.DataAccess وارد شد و دستورات زیر را جهت ایجاد و اعمال Migrations متناظر با تغییرات فوق، اجرا کرد. چون در این دستورات اینبار پروژهی آغازین، به پروژهی Web API اشاره میکند، باید بستهی نیوگت Microsoft.EntityFrameworkCore.Design را نیز به پروژهی آغازین اضافه کرد، تا بتوان آنها را با موفقیت به پایان رساند:
dotnet tool update --global dotnet-ef --version 5.0.4 dotnet build dotnet ef migrations --startup-project ../../BlazorWasm/BlazorWasm.WebApi/ add AddNameToAppUser --context ApplicationDbContext dotnet ef --startup-project ../../BlazorWasm/BlazorWasm.WebApi/ database update --context ApplicationDbContext
ایجاد مدلهای ثبت نام
در ادامه میخواهیم کنترلری را ایجاد کنیم که کار ثبت نام و لاگین را مدیریت میکند. برای این منظور باید بتوان از کاربر، اطلاعاتی مانند نام کاربری و کلمهی عبور او را دریافت کرد و پس از پایان عملیات نیز نتیجهی آنرا بازگشت داد. به همین جهت دو مدل زیر را جهت مدیریت قسمت ثبت نام، به پروژهی BlazorServer.Models اضافه میکنیم:
using System.ComponentModel.DataAnnotations; namespace BlazorServer.Models { public class UserRequestDTO { [Required(ErrorMessage = "Name is required")] public string Name { get; set; } [Required(ErrorMessage = "Email is required")] [RegularExpression("^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$", ErrorMessage = "Invalid email address")] public string Email { get; set; } public string PhoneNo { get; set; } [Required(ErrorMessage = "Password is required.")] [DataType(DataType.Password)] public string Password { get; set; } [Required(ErrorMessage = "Confirm password is required")] [DataType(DataType.Password)] [Compare("Password", ErrorMessage = "Password and confirm password is not matched")] public string ConfirmPassword { get; set; } } }
public class RegistrationResponseDTO { public bool IsRegistrationSuccessful { get; set; } public IEnumerable<string> Errors { get; set; } }
ایجاد و تکمیل کنترلر Account، جهت ثبت نام کاربران
در ادامه نیاز داریم تا جهت ارائهی امکانات اعتبارسنجی و احراز هویت کاربران، کنترلر جدید Account را به پروژهی Web API اضافه کنیم:
using System; using BlazorServer.Entities; using BlazorServer.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using System.Linq; using BlazorServer.Common; namespace BlazorWasm.WebApi.Controllers { [Route("api/[controller]/[action]")] [ApiController] [Authorize] public class AccountController : ControllerBase { private readonly SignInManager<ApplicationUser> _signInManager; private readonly UserManager<ApplicationUser> _userManager; private readonly RoleManager<IdentityRole> _roleManager; public AccountController(SignInManager<ApplicationUser> signInManager, UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager) { _roleManager = roleManager ?? throw new ArgumentNullException(nameof(roleManager)); _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); _signInManager = signInManager ?? throw new ArgumentNullException(nameof(signInManager)); } [HttpPost] [AllowAnonymous] public async Task<IActionResult> SignUp([FromBody] UserRequestDTO userRequestDTO) { var user = new ApplicationUser { UserName = userRequestDTO.Email, Email = userRequestDTO.Email, Name = userRequestDTO.Name, PhoneNumber = userRequestDTO.PhoneNo, EmailConfirmed = true }; var result = await _userManager.CreateAsync(user, userRequestDTO.Password); if (!result.Succeeded) { var errors = result.Errors.Select(e => e.Description); return BadRequest(new RegistationResponseDTO { Errors = errors, IsRegistrationSuccessful = false }); } var roleResult = await _userManager.AddToRoleAsync(user, ConstantRoles.Customer); if (!roleResult.Succeeded) { var errors = result.Errors.Select(e => e.Description); return BadRequest(new RegistationResponseDTO { Errors = errors, IsRegistrationSuccessful = false }); } return StatusCode(201); // Created } } }
- در تعریف ابتدایی این کنترلر، ویژگیهای زیر ذکر شدهاند:
[Route("api/[controller]/[action]")] [ApiController] [Authorize]
تا اینجا اگر برنامه را اجرا کنیم، میتوان با استفاده از Swagger UI، آنرا آزمایش کرد:
که با اجرای آن، برای نمونه به خروجی زیر میرسیم:
که عنوان میکند کلمهی عبور باید حداقل دارای یک عدد و یک حرف بزرگ باشد. پس از اصلاح آن، status-code=201 را دریافت خواهیم کرد.
و اگر سعی کنیم همین کاربر را مجددا ثبت نام کنیم، با خطای زیر مواجه خواهیم شد:
ایجاد مدلهای ورود به سیستم
در پروژهی Web API، از UI پیشفرض ASP.NET Core Identity استفاده نمیکنیم. به همین جهت نیاز است مدلهای قسمت لاگین را به صورت زیر تعریف کنیم:
using System.ComponentModel.DataAnnotations; namespace BlazorServer.Models { public class AuthenticationDTO { [Required(ErrorMessage = "UserName is required")] [RegularExpression("^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$", ErrorMessage = "Invalid email address")] public string UserName { get; set; } [Required(ErrorMessage = "Password is required.")] [DataType(DataType.Password)] public string Password { get; set; } } }
using System.Collections.Generic; namespace BlazorServer.Models { public class AuthenticationResponseDTO { public bool IsAuthSuccessful { get; set; } public string ErrorMessage { get; set; } public string Token { get; set; } public UserDTO UserDTO { get; set; } } public class UserDTO { public string Id { get; set; } public string Name { get; set; } public string Email { get; set; } public string PhoneNo { get; set; } } }
ایجاد مدل مشخصات تولید JSON Web Token
پس از لاگین موفق، نیاز است یک JWT را تولید کرد و در اختیار کلاینت قرار داد. مشخصات ابتدایی تولید این توکن، توسط مدل زیر تعریف میشود:
namespace BlazorServer.Models { public class BearerTokensOptions { public string Key { set; get; } public string Issuer { set; get; } public string Audience { set; get; } public int AccessTokenExpirationMinutes { set; get; } } }
{ "BearerTokens": { "Key": "This is my shared key, not so secret, secret!", "Issuer": "https://localhost:5001/", "Audience": "Any", "AccessTokenExpirationMinutes": 20 } }
namespace BlazorWasm.WebApi { public class Startup { // ... public void ConfigureServices(IServiceCollection services) { services.AddOptions<BearerTokensOptions>().Bind(Configuration.GetSection("BearerTokens")); // ...
ایجاد سرویسی برای تولید JSON Web Token
سرویس زیر به کمک سرویس توکار UserManager مخصوص Identity و مشخصات ابتدایی توکنی که معرفی کردیم، کار تولید یک JWT را انجام میدهد:
using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using System.Threading.Tasks; using BlazorServer.Entities; using BlazorServer.Models; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; namespace BlazorServer.Services { public interface ITokenFactoryService { Task<string> CreateJwtTokensAsync(ApplicationUser user); } public class TokenFactoryService : ITokenFactoryService { private readonly UserManager<ApplicationUser> _userManager; private readonly BearerTokensOptions _configuration; public TokenFactoryService( UserManager<ApplicationUser> userManager, IOptionsSnapshot<BearerTokensOptions> bearerTokensOptions) { _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); if (bearerTokensOptions is null) { throw new ArgumentNullException(nameof(bearerTokensOptions)); } _configuration = bearerTokensOptions.Value; } public async Task<string> CreateJwtTokensAsync(ApplicationUser user) { var signingCredentials = new SigningCredentials( new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration.Key)), SecurityAlgorithms.HmacSha256); var claims = await getClaimsAsync(user); var now = DateTime.UtcNow; var tokenOptions = new JwtSecurityToken( issuer: _configuration.Issuer, audience: _configuration.Audience, claims: claims, notBefore: now, expires: now.AddMinutes(_configuration.AccessTokenExpirationMinutes), signingCredentials: signingCredentials); return new JwtSecurityTokenHandler().WriteToken(tokenOptions); } private async Task<List<Claim>> getClaimsAsync(ApplicationUser user) { string issuer = _configuration.Issuer; var claims = new List<Claim> { // Issuer new Claim(JwtRegisteredClaimNames.Iss, issuer, ClaimValueTypes.String, issuer), // Issued at new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64, issuer), new Claim(ClaimTypes.Name, user.Email, ClaimValueTypes.String, issuer), new Claim(ClaimTypes.Email, user.Email, ClaimValueTypes.String, issuer), new Claim("Id", user.Id, ClaimValueTypes.String, issuer), new Claim("DisplayName", user.Name, ClaimValueTypes.String, issuer), }; var roles = await _userManager.GetRolesAsync(user); foreach (var role in roles) { claims.Add(new Claim(ClaimTypes.Role, role, ClaimValueTypes.String, issuer)); } return claims; } } }
در آخر، این سرویس را به صورت زیر به لیست سرویسهای ثبت شدهی پروژهی Web API، اضافه میکنیم:
namespace BlazorWasm.WebApi { public class Startup { // ... public void ConfigureServices(IServiceCollection services) { services.AddScoped<ITokenFactoryService, TokenFactoryService>(); // ...
تکمیل کنترلر Account جهت لاگین کاربران
پس از ثبت نام کاربران، اکنون میخواهیم امکان لاگین آنها را نیز فراهم کنیم:
namespace BlazorWasm.WebApi.Controllers { [Route("api/[controller]/[action]")] [ApiController] [Authorize] public class AccountController : ControllerBase { private readonly SignInManager<ApplicationUser> _signInManager; private readonly UserManager<ApplicationUser> _userManager; private readonly ITokenFactoryService _tokenFactoryService; public AccountController( SignInManager<ApplicationUser> signInManager, UserManager<ApplicationUser> userManager, ITokenFactoryService tokenFactoryService) { _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); _signInManager = signInManager ?? throw new ArgumentNullException(nameof(signInManager)); _tokenFactoryService = tokenFactoryService; } [HttpPost] [AllowAnonymous] public async Task<IActionResult> SignIn([FromBody] AuthenticationDTO authenticationDTO) { var result = await _signInManager.PasswordSignInAsync( authenticationDTO.UserName, authenticationDTO.Password, isPersistent: false, lockoutOnFailure: false); if (!result.Succeeded) { return Unauthorized(new AuthenticationResponseDTO { IsAuthSuccessful = false, ErrorMessage = "Invalid Authentication" }); } var user = await _userManager.FindByNameAsync(authenticationDTO.UserName); if (user == null) { return Unauthorized(new AuthenticationResponseDTO { IsAuthSuccessful = false, ErrorMessage = "Invalid Authentication" }); } var token = await _tokenFactoryService.CreateJwtTokensAsync(user); return Ok(new AuthenticationResponseDTO { IsAuthSuccessful = true, Token = token, UserDTO = new UserDTO { Name = user.Name, Id = user.Id, Email = user.Email, PhoneNo = user.PhoneNumber } }); } } }
تا اینجا اگر برنامه را اجرا کنیم، میتوان در قسمت ورود به سیستم، برای نمونه مشخصات کاربر ادمین را وارد کرد:
و پس از اجرای درخواست، به خروجی زیر میرسیم:
که در اینجا JWT تولید شدهی به همراه قسمتی از مشخصات کاربر، در خروجی نهایی مشخص است. میتوان محتوای این توکن را در سایت jwt.io مورد بررسی قرار داد که به این خروجی میرسیم و حاوی claims تعریف شدهاست:
{ "iss": "https://localhost:5001/", "iat": 1616396383, "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "vahid@dntips.ir", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "vahid@dntips.ir", "Id": "582855fb-e95b-45ab-b349-5e9f7de40c0c", "DisplayName": "vahid@dntips.ir", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Admin", "nbf": 1616396383, "exp": 1616397583, "aud": "Any" }
تنظیم Web API برای پذیرش و پردازش JWT ها
تا اینجا پس از لاگین، یک JWT را در اختیار کلاینت قرار میدهیم. اما اگر کلاینت این JWT را به سمت سرور ارسال کند، اتفاق خاصی رخ نخواهد داد و توسط آن، شیء User قابل دسترسی در یک اکشن متد، به صورت خودکار تشکیل نمیشود. برای رفع این مشکل، ابتدا بستهی جدید نیوگت Microsoft.AspNetCore.Authentication.JwtBearer را به پروژهی Web API اضافه میکنیم، سپس به کلاس آغازین پروژهی Web API مراجعه کرده و آنرا به صورت زیر تکمیل میکنیم:
namespace BlazorWasm.WebApi { public class Startup { // ... public void ConfigureServices(IServiceCollection services) { var bearerTokensSection = Configuration.GetSection("BearerTokens"); services.AddOptions<BearerTokensOptions>().Bind(bearerTokensSection); // ... var apiSettings = bearerTokensSection.Get<BearerTokensOptions>(); var key = Encoding.UTF8.GetBytes(apiSettings.Key); services.AddAuthentication(opt => { opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; opt.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(cfg => { cfg.RequireHttpsMetadata = false; cfg.SaveToken = true; cfg.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateAudience = true, ValidateIssuer = true, ValidAudience = apiSettings.Audience, ValidIssuer = apiSettings.Issuer, ClockSkew = TimeSpan.Zero, ValidateLifetime = true }; }); // ...
افزودن JWT به تنظیمات Swagger
هر کدام از اکشن متدهای کنترلرهای Web API برنامه که مزین به فیلتر Authorize باشد، در Swagger UI با یک قفل نمایش داده میشود. در این حالت میتوان این UI را به نحو زیر سفارشی سازی کرد تا بتواند JWT را دریافت و به سمت سرور ارسال کند:
namespace BlazorWasm.WebApi { public class Startup { // ... public void ConfigureServices(IServiceCollection services) { // ... services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "BlazorWasm.WebApi", Version = "v1" }); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { In = ParameterLocation.Header, Description = "Please enter the token in the field", Name = "Authorization", Type = SecuritySchemeType.ApiKey }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); }); } // ...
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-25.zip
دستور مورد نظر در Nuget :
Install failed. Rolling back... install-package : Could not install package 'AsyncAwaitCTP 1.0'. You are trying to install this package into a project that targets '.NETPortable,Version=v4.0,Profile=Profile3', but the package does not contain any assembly references that are compatible with that framework. For more information, contact the package author. At line:1 char:1
خلاصه بعد از یکم جستجو متوجه شدم که باید از دستور زیر برای نصب TPL توی Portable Class Library تحت دات نت 4 استفاده کنم.
Install failed. Rolling back... install-package : Could not install package 'Microsoft.Bcl 1.0.16-rc'. You are trying to install this package into a project that targets '.NETPortable,Version=v4.0,Profile=Profile3', but the package does not contain any assembly references that are compatible with that framework. For more information, contact the package author. At line:1 char:1 + install-package Microsoft.BCL.Async -Pre + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Install-Package], InvalidOperationException + FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PowerShell.Commands.InstallPackageCommand
Nuget نصب شده روی سیستم من Update نیست. برای همین به روش زیر عمل کردم .
از منوی Tools گزینه Extension And Updates رو انتخاب کردم. بعد از صفحه مورد نظر گزینه Updates روز از منوی سمت چپ انتخاب کردم و درنهایت گزینه Nuget Package Manager. مثل شکل زیر:
بعد از اتمام عملیات Update دوباره دستورات مورد نظر رو وارد کردم که به خوبی عملیات نصب CTP به اتمام رسید.
هرچند بسیاری از قابلیتهای C# 8.0 در خود کامپایلر #C پیاده سازی شدهاند، اما برای مثال قابلیتی مانند «پیاده سازی پیشفرض اینترفیسها» نیاز به یک runtime جدید دارد که به همراه NET Core 3.0. ارائه میشود. بنابراین NET Full 4x. شاهد پیاده سازی C# 8.0 نخواهد بود. همچنین یک سری از قابلیتهای C# 8.0 وابستهی به NET Standard 2.1. و netcoreapp3.0 هستند؛ مانند نوعهای جدید System.IAsyncDisposable و یا System.Range. به همین جهت است که برای کار با C# 8.0، حتما نیاز به نصب NET Core 3.0. نیز میباشد و به روز رسانی کامپایلر #C کافی نیست.
چه نگارشهایی از Visual Studio از NET Core 3.0. پشتیبانی میکنند؟
مطابق مستندات رسمی موجود، یک چنین جدولی در مورد نگارشهای مختلف NET Core. و نگارشهای ویژوال استودیوهایی از که از آنها پشتیبانی میکنند، وجود دارد:
.NET Core SDK | .NET Core Runtime | Compatible Visual Studio | MSBuild | Notes |
---|---|---|---|---|
2.1.5nn | 2.1 | 2017 | 15 | Installed as part of VS 2017 version 15.9 |
2.1.6nn | 2.1 | 2019 | 16 | Installed as part of VS 2019 |
2.2.1nn | 2.2 | 2017 | 15 | Installed manually |
2.2.2nn | 2.2 | 2019 | 16 | Installed as part of VS 2019 |
3.0.1nn | 3.0 (Preview) | 2019 | 16 | Installed manually |
بنابراین فقط VS 2019 است که قابلیت پشتیبانی از NET Core 3.0. را دارد. به همین جهت اگر قصد دارید با ویژوال استودیو کار کنید، نصب VS 2019 برای کار با C# 8.0 الزامی است.
فعالسازی C# 8.0 در ویژوال استودیو 2019
در زمان نگارش این مطلب، NET Core 3.0. در حالت پیشنمایش، ارائه شدهاست. به همین جهت جزء یکپارچهی VS 2019 محسوب نشده و باید جداگانه نصب شود:
- برای این منظور ابتدا نیاز است آخرین نگارش NET Core 3.0 SDK. را دریافت و نصب کنید.
- سپس از منوی Tools | Options، گزینهی Projects and Solutions را انتخاب و در ادامه گزینهی Use previews of the .NET Core SDK را انتخاب کنید.
- پس از آن، این SDK جدید NET Core. به صورت زیر قابل انتخاب خواهد بود:
البته انتخاب شماره SDK صحیح به تنهایی برای کار با C# 8.0 کافی نیست؛ بلکه باید شمارهی زبان مورد استفاده را نیز صریحا انتخاب کرد:
برای اینکار بر روی پروژه کلیک راست کرده و گزینهی Properties آنرا انتخاب کنید. سپس در اینجا در برگهی Build، بر روی دکمهی Advanced کلیک کنید تا بتوان شماره نگارش زبان را مطابق تصویر فوق انتخاب کرد. در اینجا بجای C# 8.0 (beta)، گزینهی unsupported preview را نیز میتوانید انتخاب کنید.
یک نکته: خلاصهی تمام این مراحل، منوها و تصاویر، همان تنظیمات فایل csproj است که در ادامه بررسی میکنیم.
فعالسازی C# 8.0 در VSCode
مدتها است که برای کار با NET Core. نیازی به استفادهی از نگارش کامل ویژوال استودیو نیست. همینقدر که VSCode را به همراه افزونهی #C آن نصب کرده باشید، میتوانید برنامههای مبتنی بر NET Core. را بر روی سیستم عاملهای مختلفی که NET Core SDK. بر روی آنها نصب شدهاست، توسعه دهید.
پشتیبانی ابتدایی از C# 8.0، با نگارش v1.18.0 افزونهی #C مخصوص VSCode ارائه شد. بنابراین هم اکنون اگر آخرین نگارش آنرا نصب کرده باشید، امکان کار با پروژههای NET Core 3.0 و C# 8.0 را نیز دارید.
بنابراین در اینجا به صورت خلاصه:
- ابتدا باید NET Core 3.0 SDK. را به صورت جداگانهای دریافت و نصب کنید.
- سپس آخرین نگارش افزونهی #C مخصوص VSCode را نیز نصب کنید.
- در آخر، یک پوشهی جدید را ایجاد کرده و در خط فرمان دستور dotnet new console را صادر کنید. این دستور بر اساس آخرین شماره نگارش SDK نصب شده، یک پروژهی جدید کنسول را ایجاد میکند که ساختار فایل csproj آن به صورت زیر است:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> </PropertyGroup> </Project>
- یا معادل همان گزینهی unsupported preview در تصویر سوم این مطلب:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> <LangVersion>preview</LangVersion> </PropertyGroup> </Project>
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.0</TargetFramework> <LangVersion>8.0</LangVersion> </PropertyGroup> </Project>
یک نکته: در اینجا نمیتوان LangVersion را به latest تنظیم کرد؛ چون C# 8.0 هنوز در مرحلهی بتا است. زمانیکه از مرحلهی بتا خارج شد، مقدار پیشفرض آن دقیقا latest خواهد بود و ذکر صریح آن غیر ضروری است. انتخاب latest در اینجا به latest minor version یا همان نگارش C# 7.3 فعلی (آخرین نگارش پایدار زبان #C در زمان نگارش این مطلب) اشاره میکند.
Rider و پشتیبانی از C# 8.0
Rider 2019.1 نیز به همراه پشتیبانی از C# 8.0 ارائه شدهاست و میتواند گزینهی مطلوب دیگری برای توسعهی برنامههای مبتنی بر NET Core. باشد.
نصب NET Core 3.0 SDK. و عدم اجرای برنامههای پیشین
یکی از مزایای کار با NET Core.، امکان نصب چندین نوع مختلف SDK آن، به موازت هم است؛ بدون اینکه بر روی یکدیگر تاثیری بگذارند. البته این نکته را باید درنظر داشت که برنامههای NET Core. بدون وجود فایل مخصوص global.json در پوشهی ریشهی آنها، همواره از آخرین نگارش SDK نصب شده، برای اجرا استفاده خواهند کرد. اگر این مورد بر روی کار شما تاثیرگذار است، میتوانید شماره SDK مورد استفادهی برنامهی خود را قفل کنید، تا SDKهای جدید نصب شده، به عنوان SDK پیشفرض برنامههای پیشین، انتخاب نشوند. بنابراین ابتدا لیست SDKهای نصب شده را با دستور زیر پیدا کنید:
> dotnet --list-sdks
> dotnet new globaljson --sdk-version 2.2.300 > type global.json
سوالات مصاحبه ای در مورد #C و دات نت
Performance of your ASP.NET web application is important. There is a lot of evidence to suggest that slow loading times and clunky interaction, will drive customers elsewhere. Even in the case of internal applications where the users have no option but to use the application, their satisfaction is tightly coupled to speed.
There are a ton of ways to improve the performance of a website, let's look at fifteen of them.
سه آرزو برای Office 365 در سال 2016
5.Visual Studio 2017 15.9 منتشر شد
These are the customer-reported issues addressed in 15.9.5:
- VSX1000: No enough information has been provided to MSBuild in order to establish a connection to a Remote Server.
- Visual C++ 2017 Redistributable for ARM64 is not available via visualstudio.com.
- VC Runtime Redistributable Update for VS 15.9 deletes Registry Key. This fix may have an increased chance of requiring a reboot of the machine in order to install an updated VC++ Redistributable package.
- Incorrect codegen in managed c++ with List to List assignment.
- Can't connect to mac build host after Visual Studio 15.9.4 update.
- Resource directories missed in incremental builds with
AndroidAarLibrary
items. - Lots of external assembly references - JNI ERROR (app bug): local reference table overflow (max=512).
- The Unity Editor has been updated to 2018.3. For more information, please visit the Unity website.
- SSDT: We enabled SQL projects to build schemas that have non-clustered columnstore indexes on an indexed views.
- SSDT: We fixed a significant performance issue in the schema compare tool when generating a script.
- SSDT: We fixed the schema drift detection logic in the schema compare tool which forced a new comparison to reenable scripting and publishing actions.