Hello! I work for the Angular core team on internationalization (i18n) and we are trying to get a better idea of the things that we need to improve/focus on in Angular regarding i18n. I created this survey: https://goo.gl/forms/0BIXXVP58RqbzzBM2 If you care about internationalization, please take 5mn to do it! Thanks!
مروری بر .net core توسط اسکات هانتر
There has never been a better time to be a .NET developer, you can now build Android, iOS, Linux, Mac, and Windows applications with .NET all in Open Source. In this session we will run through some of the new innovations including the .NET Framework updates, .NET Standard, Universal Windows Platform updates, .NET Core, managed languages and more. We will also review the updates to Visual Studio and Visual Studio Code to make you a better developer, come see some of the latest productivity features in these tools including managing code style, searching your source and more.
We finished week 2 of the 9-week boot camp. This week was AngularJS week. We covered building the front-end of a Single Page App with the AngularJS framework. In particular, we covered topics such as client-side routing, making Ajax calls using the $http service and the $route factory, building custom AngularJS services, working with Google Maps, using Angular UI Bootstrap, and uploading files to services such as FilePicker.io.
هدایت سراسری و خودکار کاربران اعتبارسنجی نشده به صفحهی لاگین
در برنامهی این سری، اگر کاربری که به سیستم وارد نشدهاست، بر روی دکمهی Book یک اتاق کلیک کند، فقط پیام «Not Authorized» را مشاهده خواهد کرد که تجربهی کاربری مطلوبی بهشمار نمیرود. بهتر است در یک چنین حالتی، کاربر را به صورت خودکار به صفحهی لاگین هدایت کرد و پس از لاگین موفق، مجددا او را به همین آدرس درخواستی پیش از نمایش صفحهی لاگین، هدایت کرد. برای مدیریت این مساله کامپوننت جدید RedirectToLogin را طراحی میکنیم که جایگزین پیام «Not Authorized» در کامپوننت ریشهای BlazorWasm.Client\App.razor خواهد شد. بنابراین ابتدا فایل جدید BlazorWasm.Client\Pages\Authentication\RedirectToLogin.razor را ایجاد میکنیم. چون این کامپوننت بدون مسیریابی خواهد بود و قرار است مستقیما داخل کامپوننت دیگری درج شود، نیاز است فضای نام آنرا نیز به فایل BlazorWasm.Client\_Imports.razor اضافه کرد:
@using BlazorWasm.Client.Pages.Authentication
@using System.Security.Claims @inject NavigationManager NavigationManager if(AuthState is not null) { <div class="alert alert-danger"> <p>You [@AuthState.User.Identity.Name] do not have access to the requested page</p> <div> Your roles: <ul> @foreach (var claim in AuthState.User.Claims.Where(c => c.Type == ClaimTypes.Role)) { <li>@claim.Value</li> } </ul> </div> </div> } @code { [CascadingParameter] private Task<AuthenticationState> AuthenticationState {set; get;} AuthenticationState AuthState; protected override async Task OnInitializedAsync() { AuthState = await AuthenticationState; if (!IsAuthenticated(AuthState)) { var returnUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); if (string.IsNullOrEmpty(returnUrl)) { NavigationManager.NavigateTo("login"); } else { NavigationManager.NavigateTo($"login?returnUrl={Uri.EscapeDataString(returnUrl)}"); } } } private bool IsAuthenticated(AuthenticationState authState) => authState?.User?.Identity is not null && authState.User.Identity.IsAuthenticated; }
در اینجا روش کار کردن با AuthenticationState را از طریق کدنویسی ملاحظه میکنید. در زمان بارگذاری اولیهی این کامپوننت، بررسی میشود که آیا کاربر جاری، به سیستم وارد شدهاست یا خیر؟ اگر خیر، او را به سمت صفحهی لاگین هدایت میکنیم. اما اگر کاربر پیشتر به سیستم وارد شده باشد، متن شما دسترسی ندارید، به همراه لیست نقشهای او در صفحه ظاهر میشوند که برای دیباگ برنامه مفید است و دیگر به سمت صفحهی لاگین هدایت نمیشود.
در ادامه برای استفاده از این کامپوننت، به کامپوننت ریشهای BlazorWasm.Client\App.razor مراجعه کرده و قسمت NotAuthorized آنرا به صورت زیر، با معرفی کامپوننت RedirectToLogin، جایگزین میکنیم:
<NotAuthorized> <RedirectToLogin></RedirectToLogin> </NotAuthorized>
چگونه دسترسی نقش ثابت Admin را به تمام صفحات محافظت شده برقرار کنیم؟
اگر خاطرتان باشد در زمان ثبت کاربر ادمین Identity، تنها نقشی را که برای او ثبت کردیم، Admin بود که در تصویر فوق هم مشخص است؛ اما ویژگی Authorize استفاده شده جهت محافظت از کامپوننت (attribute [Authorize(Roles = ConstantRoles.Customer)]@)، تنها نیاز به نقش Customer را دارد. به همین جهت است که کاربر وارد شدهی به سیستم، هرچند از دیدگاه ما ادمین است، اما به این صفحه دسترسی ندارد. بنابراین اکنون این سؤال مطرح است که چگونه میتوان به صورت خودکار دسترسی نقش Admin را به تمام صفحات محافظت شدهی با نقشهای مختلف، برقرار کرد؟
برای رفع این مشکل همانطور که پیشتر نیز ذکر شد، نیاز است تمام نقشهای مدنظر را با یک کاما از هم جدا کرد و به خاصیت Roles ویژگی Authorize انتساب داد؛ و یا میتوان این عملیات را به صورت زیر نیز خلاصه کرد:
using System; using BlazorServer.Common; using Microsoft.AspNetCore.Authorization; namespace BlazorWasm.Client.Utils { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public class RolesAttribute : AuthorizeAttribute { public RolesAttribute(params string[] roles) { Roles = $"{ConstantRoles.Admin},{string.Join(",", roles)}"; } } }
پس از این تعریف میتوان در کامپوننتها، ویژگی Authorize نقش دار را با ویژگی جدید Roles، جایگزین کرد که همواره دسترسی کاربر Admin را نیز برقرار میکند:
@attribute [Roles(ConstantRoles.Customer, ConstantRoles.Employee)]
مدیریت سراسری خطاهای حاصل از درخواستهای HttpClient
تا اینجا نتایج حاصل از شکست اعتبارسنجی سمت کلاینت را به صورت سراسری مدیریت کردیم. اما برنامههای سمت کلاینت، به کمک HttpClient خود نیز میتوانند درخواستهایی را به سمت سرور ارسال کرده و در پاسخ، برای مثال not authorized و یا forbidden را دریافت کنند و یا حتی internal server error ای را در صورت بروز استثنایی در سمت سرور.
فرض کنید Web API Endpoint جدید زیر را تعریف کردهایم که نقش ادیتور را میپذیرد. این نقش، جزو نقشهای تعریف شدهی در برنامه و سیستم Identity ما نیست. بنابراین هر درخواستی که به سمت آن ارسال شود، برگشت خواهد خورد و پردازش نمیشود:
namespace BlazorWasm.WebApi.Controllers { [Route("api/[controller]")] [Authorize(Roles = "Editor")] public class MyProtectedEditorsApiController : Controller { [HttpGet] public IActionResult Get() { return Ok(new ProtectedEditorsApiDTO { Id = 1, Title = "Hello from My Protected Editors Controller!", Username = this.User.Identity.Name }); } } }
namespace BlazorWasm.Client.Services { public class ClientHttpInterceptorService : DelegatingHandler { private readonly NavigationManager _navigationManager; private readonly ILocalStorageService _localStorage; private readonly IJSRuntime _jsRuntime; public ClientHttpInterceptorService( NavigationManager navigationManager, ILocalStorageService localStorage, IJSRuntime JsRuntime) { _navigationManager = navigationManager ?? throw new ArgumentNullException(nameof(navigationManager)); _localStorage = localStorage ?? throw new ArgumentNullException(nameof(localStorage)); _jsRuntime = JsRuntime ?? throw new ArgumentNullException(nameof(JsRuntime)); } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // How to add a JWT to all of the requests var token = await _localStorage.GetItemAsync<string>(ConstantKeys.LocalToken); if (token is not null) { request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token); } var response = await base.SendAsync(request, cancellationToken); if (!response.IsSuccessStatusCode) { await _jsRuntime.ToastrError($"Failed to call `{request.RequestUri}`. StatusCode: {response.StatusCode}."); switch (response.StatusCode) { case HttpStatusCode.NotFound: _navigationManager.NavigateTo("/404"); break; case HttpStatusCode.Forbidden: // 403 case HttpStatusCode.Unauthorized: // 401 _navigationManager.NavigateTo("/unauthorized"); break; default: _navigationManager.NavigateTo("/500"); break; } } return response; } } }
با ارثبری از کلاس پایهی DelegatingHandler میتوان متد SendAsync تمام درخواستهای ارسالی توسط برنامه را بازنویسی کرد و تحت نظر قرار داد. برای مثال در اینجا، پیش از فراخوانی await base.SendAsync کلاس پایه (یا همان درخواست اصلی که در قسمتی از برنامه صادر شدهاست)، یک توکن را به هدرهای درخواست، اضافه کردهایم و یا پس از این فراخوانی (که معادل فراخوانی اصل کد در حال اجرای برنامه است)، با بررسی StatusCode بازگشتی از سمت سرور، کاربر را به یکی از صفحات یافت نشد، خطایی رخ دادهاست و یا دسترسی ندارید، هدایت کردهایم. برای نمونه کامپوننت Unauthorized.razor را با محتوای زیر تعریف کردهایم:
@page "/unauthorized" <div class="alert alert-danger mt-3"> <p>You don't have access to the requested resource.</p> </div>
پس از تدارک این Interceptor سراسری، نوبت به معرفی آن به برنامهاست که ... در ابتدا نیاز به نصب بستهی نیوگت زیر را دارد:
dotnet add package Microsoft.Extensions.Http
namespace BlazorWasm.Client { public class Program { public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); //... // builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); /*builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.Configuration.GetValue<string>("BaseAPIUrl")) });*/ // dotnet add package Microsoft.Extensions.Http builder.Services.AddHttpClient( name: "ServerAPI", configureClient: client => { client.BaseAddress = new Uri(builder.Configuration.GetValue<string>("BaseAPIUrl")); client.DefaultRequestHeaders.Add("User-Agent", "BlazorWasm.Client 1.0"); } ) .AddHttpMessageHandler<ClientHttpInterceptorService>(); builder.Services.AddScoped<ClientHttpInterceptorService>(); builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("ServerAPI")); //... } } }
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-33.zip
You'll often hear the terms framework
and platform
used interchangeably. This can be very confusing. You'll hear that .NET Core is a platform. Then you'll read that .NET Core is cross-platform. Next, you'll learn that .NET Core is a framework. And it doesn't help that framework is part of the name of the original full .NET Framework.
In this post, I explain the difference between frameworks and platforms and explain why sometimes you'll see .NET being referred to as a framework and other times see it referred to as a platform.
Automapper به بنیاد NET. پیوست.
AutoMapper has been a popular library in the .NET open source community for a long time. As their site says:
AutoMapper is a simple little library built to solve a deceptively complex problem - getting rid of code that mapped one object to another. This type of code is rather dreary and boring to write, so why not invent a tool to do it for us?
کتاب کار با XML در SQL Server
Stairway to XML
XML has been part of the SQL Standard since 2003, and is essential for
any DBA because so many of the dynamic management views return XML data.
Now that the industry is more used to data defined by document markup,
it is becoming more important than ever for Database Developers and DBAs
to understand the technology and to know where it makes sense to use
XML. In this book, originally a series of articles on
SQLServerCentral.com, Robert Sheldon flexes his talent to make the
complicated seem simple.
1.3 TailWind CSS منتشر شد
EF Code First #14
The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value.
The statement has been terminated.