Now, with this required hardware-enforced containerization and virtualization tech, Windows 11 will isolate applications and processes much more easily. It will be much more difficult for malware in an errantly running application to access resources it isn't supposed to. It will only access the resources in that specific application task that it infects, such as a particular browser tab.
- TLS 1.0: The request was aborted: Could not create SSL/TLS secure channel.
- Task List with filter set to Entire Solution doesnt display tasks/todos when the file is closed.
- Fatal error C1001: An internal error has occurred in the compiler.
- VS 2019 Preview 1 - EF6 edmx file cannot be saved.
- vcruntime140.dll should be made available on Microsoft Symbol Server.
- Static Analyser, Custom Rule Set (C++) does not execute included default sets.
- VS2019 Preview: Azure Function publishing does not work.
- References window does not remember its position.
- Missing formatting option for pointers and references.
- Microsoft.TeamFoundation.Client, Version=15.0.0.0 assembly not found when create a new web project.
private Document oDoc; public void createdoc1() { var realpath="~/template"; var filePath = Path.Combine(HttpContext.Current.Server.MapPath("~/template"), Lcourseid.Text + ".doc"); var oWordApplication = new Application(); DirectoryInfo dir = new DirectoryInfo(Server.MapPath(realpath)); foreach (FileInfo files in dir.GetFiles()) { files.Delete(); } // To invoke MyMethod with the default argument value, pass // Missing.Value for the optional parameter. object missing = System.Reflection.Missing.Value; //object fileName = ConfigurationManager.AppSettings["DocxPath"];@"C:\DocXExample.docx"; string fileName = @"D:\template1.dot"; //string fileName1 = @"D:\sss.doc"; object newTemplate = false; object docType = 0; object isVisible = true; //System.Reflection.Missing.Value is used here for telling that method to use default parameter values when method execution oDoc = oWordApplication.Documents.Open(fileName, newTemplate, docType, isVisible, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing); // usable in earlier versions of Microsoft Word v2003 v11 // if(Convert.ToInt16(oWordApplication.Version) >=11) { //Sets or returns a Boolean that represents whether a document is being viewed in reading layout view. oDoc.ActiveWindow.View.ReadingLayout = false; } //The active window is the window that currently has focus.If there are no windows open, an exception is thrown. //microsoft.office.tools.word. oDoc.Activate(); if (oDoc.Bookmarks.Exists("Title")) { oDoc.Bookmarks["Title"].Range.Text = "Test Field Entry from webform"; oDoc.Bookmarks["Address"].Range.Text = "Address Field Entry from webform"; } oDoc.SaveAs(filePath, ref missing); oWordApplication.Documents.Close(ref missing, ref missing, ref missing); //oWordApplication.Quit(ref SaveChanges, ref missing, ref missing, ref missing); ProcessRequest(filePath, Lcourseid.Text);
#C به عنوان یک زبان سیستمی
When you think about C#, you'll usually think about a high-level language, one that is utilized to build websites, APIs, and desktop applications. However, from its inception, C# had the foundation to be used as a system language, with facilities that allow you direct memory access and fine-grained control over memory and execution.
افزودن و اعتبارسنجی خودکار Anti-Forgery Tokens در برنامههای Angular مبتنی بر ASP.NET Core
میانافزار طراحی شدهی در این مطلب، پیش از لاگین و با اولین درخواست تک صفحهی برنامه، کوکیهای antiforgery را دریافت میکند. اما ... سیستم antiforgery طوری طراحی شدهاست که پیش از تولید کوکی، مشخصات دقیق this.HttpContext.User را دریافت و هش میکند (لیست Claims آنرا به صورت رشته در میآورد و هش SHA256 آن را محاسبه میکند). از این هش هم جهت تولید محتوای کوکی نهایی خود استفاده میکند. بنابراین در بار اولی که صفحه درخواست شدهاست، یک کوکی antiforgery مخصوص کاربر null و اعتبارسنجی نشده، تولید خواهد شد. بعد از آن پس از لاگین، اگر میانافزار یاد شده مجددا نیز فراخوانی شود، هیچ اتفاق خاصی رخ نخواهد داد. از این جهت که در طراحی متد GetAndStoreTokens آن، به ازای یک صفحه، فقط یکبار این کوکی تولید میشود و اگر هزار بار دیگر هم این متد را جهت برنامهی تک صفحهای خود فراخوانی کنیم، به این معنا نخواهد بود که مشخصات this.HttpContext.User را به کوکی جدیدی اضافه میکند؛ چون اصلا کوکی جدیدی را تولید نمیکند!
بنابراین راه حل نهایی به این صورت است:
الف) میان افزار AngularAntiforgeryTokenMiddleware فوق را حذف کنید. این میانافزار عملا کاربردی برای برنامههای SPA دارای اعتبارسنجی ندارد.
ب) امضای متد Login را به این صورت تغییر دهید که شامل IgnoreAntiforgeryToken باشد:
[AllowAnonymous] [IgnoreAntiforgeryToken] [HttpPost("[action]")] public async Task<IActionResult> Login([FromBody] User loginUser)
ج) در متد لاگین، پس از تولید توکنها، اکنون کار تولید کوکی را به صورت زیر انجام میدهیم:
private void regenerateAntiForgeryCookie(IEnumerable<Claim> claims) { this.HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity(claims, JwtBearerDefaults.AuthenticationScheme)); var tokens = _antiforgery.GetAndStoreTokens(this.HttpContext); this.HttpContext.Response.Cookies.Append( key: "XSRF-TOKEN", value: tokens.RequestToken, options: new CookieOptions { HttpOnly = false // Now JavaScript is able to read the cookie }); }
نکتهی مهم! جائیکه Claimهای برنامه را تولید میکنید، باید حتما Issuer را هم ذکر کنید:
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString(), ClaimValueTypes.String, _configuration.Value.Issuer),
خلاصه این تغییرات به پروژهی ASPNETCore2JwtAuthentication اعمال شدهاند.
When Ruby on Rails, a web application framework written in the Ruby programming language, was first released as open source back in July 2004, it stumbled to rise in the rankings as one of the top programming languages. But in 2006, Apple announced that it would be shipping Ruby on Rails with their Mac OS X v10.5 “Leopard” and Ruby soon became known and used by many. So much so, that the TIOBE index, a measure of the popularity of programming languages, named Ruby the “Programming Language of 2006.” However, due to some scalability issues and the release of other exciting new tools, such as Node.js and AngularJS, Ruby started to lose its popularity and by 2008 it seemed as if it was on its way out.
تکمیل فرم ثبت نام کاربران
در ادامه کدهای کامل کامپوننت فرم ثبت نام کاربران را مشاهده میکنید:
@page "/registration" @inject IClientAuthenticationService AuthenticationService @inject NavigationManager NavigationManager <EditForm Model="UserForRegistration" OnValidSubmit="RegisterUser" class="pt-4"> <DataAnnotationsValidator /> <div class="py-4"> <div class=" row form-group "> <div class="col-6 offset-3 "> <div class="card border"> <div class="card-body px-lg-5 pt-4"> <h3 class="col-12 text-success text-center py-2"> <strong>Sign Up</strong> </h3> @if (ShowRegistrationErrors) { <div> @foreach (var error in Errors) { <p class="text-danger text-center">@error</p> } </div> } <hr style="background-color:aliceblue" /> <div class="py-2"> <InputText @bind-Value="UserForRegistration.Name" class="form-control" placeholder="Name..." /> <ValidationMessage For="(()=>UserForRegistration.Name)" /> </div> <div class="py-2"> <InputText @bind-Value="UserForRegistration.Email" class="form-control" placeholder="Email..." /> <ValidationMessage For="(()=>UserForRegistration.Email)" /> </div> <div class="py-2 input-group"> <div class="input-group-prepend"> <span class="input-group-text"> +1</span> </div> <InputText @bind-Value="UserForRegistration.PhoneNo" class="form-control" placeholder="Phone number..." /> <ValidationMessage For="(()=>UserForRegistration.PhoneNo)" /> </div> <div class="form-row py-2"> <div class="col"> <InputText @bind-Value="UserForRegistration.Password" type="password" id="password" placeholder="Password..." class="form-control" /> <ValidationMessage For="(()=>UserForRegistration.Password)" /> </div> <div class="col"> <InputText @bind-Value="UserForRegistration.ConfirmPassword" type="password" id="confirm" class="form-control" placeholder="Confirm Password..." /> <ValidationMessage For="(()=>UserForRegistration.ConfirmPassword)" /> </div> </div> <hr style="background-color:aliceblue" /> <div class="py-2"> @if (IsProcessing) { <button type="submit" class="btn btn-success btn-block disabled"><i class="fas fa-sign-in-alt"></i> Please Wait...</button> } else { <button type="submit" class="btn btn-success btn-block"><i class="fas fa-sign-in-alt"></i> Register</button> } </div> </div> </div> </div> </div> </div> </EditForm> @code{ UserRequestDTO UserForRegistration = new UserRequestDTO(); bool IsProcessing; bool ShowRegistrationErrors; IEnumerable<string> Errors; private async Task RegisterUser() { ShowRegistrationErrors = false; IsProcessing = true; var result = await AuthenticationService.RegisterUserAsync(UserForRegistration); if (result.IsRegistrationSuccessful) { IsProcessing = false; NavigationManager.NavigateTo("/login"); } else { IsProcessing = false; Errors = result.Errors; ShowRegistrationErrors = true; } } }
- مدل این فرم بر اساس UserRequestDTO تشکیل شدهاست که همان شیءای است که اکشن متد ثبت نام سمت Web API انتظار دارد.
- در این کامپوننت به کمک سرویس IClientAuthenticationService که آنرا در قسمت قبل تهیه کردیم، شیء نهایی متصل به فرم، به سمت Web API Endpoint ثبت نام ارسال میشود.
- در اینجا روشی را جهت غیرفعال کردن یک دکمه، پس از کلیک بر روی آن مشاهده میکنید. میتوان پس از کلیک بر روی دکمهی ثبت نام، با true کردن یک فیلد مانند IsProcessing، بلافاصله دکمهی جاری را برای مثال با ویژگی disabled در صفحه درج کرد و یا حتی آنرا از صفحه حذف کرد. این روش، یکی از روشهای جلوگیری از کلیک چندبارهی کاربر، بر روی یک دکمهاست.
- فرم جاری، خطاهای اعتبارسنجی مخصوص Identity سمت سرور را نیز نمایش میدهد که حاصل از ارسال آنها توسط اکشن متد ثبت نام است:
- پس از پایان موفقیت آمیز ثبت نام، کاربر را به سمت فرم لاگین هدایت میکنیم.
تکمیل فرم ورود به سیستم کاربران
در ادامه کدهای کامل کامپوننت فرم ثبت نام کاربران را مشاهده میکنید:
@page "/login" @inject IClientAuthenticationService AuthenticationService @inject NavigationManager NavigationManager <div id="logreg-forms"> <h1 class="h3 mb-3 pt-3 font-weight-normal text-primary" style="text-align:center;">Sign In</h1> <EditForm Model="UserForAuthentication" OnValidSubmit="LoginUser"> <DataAnnotationsValidator /> @if (ShowAuthenticationErrors) { <p class="text-center text-danger">@Errors</p> } <InputText @bind-Value="UserForAuthentication.UserName" id="email" placeholder="Email..." class="form-control mb-2" /> <ValidationMessage For="(()=>UserForAuthentication.UserName)"></ValidationMessage> <InputText @bind-Value="UserForAuthentication.Password" type="password" placeholder="Password..." id="password" class="form-control mb-2" /> <ValidationMessage For="(()=>UserForAuthentication.Password)"></ValidationMessage> @if (IsProcessing) { <button type="submit" class="btn btn-success btn-block disabled"><i class="fas fa-sign-in-alt"></i> Please Wait...</button> } else { <button type="submit" class="btn btn-success btn-block"><i class="fas fa-sign-in-alt"></i> Sign in</button> } <a href="/registration" class="btn btn-primary text-white mt-3"><i class="fas fa-user-plus"></i> Register as a new user</a> </EditForm> </div> @code { AuthenticationDTO UserForAuthentication = new AuthenticationDTO(); bool IsProcessing = false; bool ShowAuthenticationErrors; string Errors; string ReturnUrl; private async Task LoginUser() { ShowAuthenticationErrors = false; IsProcessing = true; var result = await AuthenticationService.LoginAsync(UserForAuthentication); if (result.IsAuthSuccessful) { IsProcessing = false; var absoluteUri = new Uri(NavigationManager.Uri); var queryParam = HttpUtility.ParseQueryString(absoluteUri.Query); ReturnUrl = queryParam["returnUrl"]; if (string.IsNullOrEmpty(ReturnUrl)) { NavigationManager.NavigateTo("/"); } else { NavigationManager.NavigateTo("/" + ReturnUrl); } } else { IsProcessing = false; Errors = result.ErrorMessage; ShowAuthenticationErrors = true; } } }
- مدل این فرم بر اساس AuthenticationDTO تشکیل شدهاست که همان شیءای است که اکشن متد لاگین سمت Web API انتظار دارد.
- در این کامپوننت به کمک سرویس IClientAuthenticationService که آنرا در قسمت قبل تهیه کردیم، شیء نهایی متصل به فرم، به سمت Web API Endpoint ثبت نام ارسال میشود.
- در اینجا نیز همانند فرم ثبت نام، پس از کلیک بر روی دکمهی ورود به سیستم، با true کردن یک فیلد مانند IsProcessing، بلافاصله دکمهی جاری را با ویژگی disabled در صفحه درج کردهایم تا از کلیک چندبارهی کاربر، جلوگیری شود.
- این فرم، خطاهای اعتبارسنجی مخصوص Identity سمت سرور را نیز نمایش میدهد که حاصل از ارسال آنها توسط اکشن متد لاگین است:
همانطور که مشاهده میکنید، مقدار JWT تولید شدهی پس از لاگین و همچنین مشخصات کاربر دریافتی از Web Api، جهت استفادههای بعدی، در Local Storage مرورگر درج شدهاند.
تغییر منوی راهبری سایت، بر اساس وضعیت لاگین شخص
تا اینجا قسمتهای ثبت نام و ورود به سیستم را تکمیل کردیم. در ادامه نیاز داریم تا منوی سایت را هم بر اساس وضعیت اعتبارسنجی شخص، تغییر دهیم. برای مثال اگر شخصی به سیستم وارد شدهاست، باید در منوی سایت، لینک خروج و نام خودش را مشاهده کند و نه مجددا لینکهای ثبتنام و لاگین را. جهت تغییر منوی راهبری سایت، کامپوننت Shared\NavMenu.razor را گشوده و لینکهای قبلی ثبتنام و لاگین را با محتوای زیر جایگزین میکنیم:
<AuthorizeView> <Authorized> <li class="nav-item p-0"> <NavLink class="nav-link" href="#"> <span class="p-2"> Hello, @context.User.Identity.Name! </span> </NavLink> </li> <li class="nav-item p-0"> <NavLink class="nav-link" href="logout"> <span class="p-2"> Logout </span> </NavLink> </li> </Authorized> <NotAuthorized> <li class="nav-item p-0"> <NavLink class="nav-link" href="registration"> <span class="p-2"> Register </span> </NavLink> </li> <li class="nav-item p-0"> <NavLink class="nav-link" href="login"> <span class="p-2"> Login </span> </NavLink> </li> </NotAuthorized> </AuthorizeView>
تکمیل قسمت خروج از سیستم
اکنون که لینک logout را در منوی سایت، پس از ورود به سیستم نمایش میدهیم، میتوان کدهای کامپوننت آنرا (Pages\Authentication\Logout.razor) به صورت زیر تکمیل کرد:
@page "/logout" @inject IClientAuthenticationService AuthenticationService @inject NavigationManager NavigationManager @code { protected async override Task OnInitializedAsync() { await AuthenticationService.LogoutAsync(); NavigationManager.NavigateTo("/"); } }
مشکل! پس از کلیک بر روی logout، هرچند میتوان مشاهده کرد که اطلاعات Local Storage به درستی حذف شدهاند، اما ... پس از هدایت به صفحهی اصلی برنامه، هنوز هم لینک logout و نام کاربری شخص نمایان هستند و به نظر هیچ اتفاقی رخ ندادهاست!
علت اینجا است که AuthenticationStateProvider سفارشی را که تهیه کردیم، فاقد اطلاع رسانی تغییر وضعیت است:
namespace BlazorWasm.Client.Services { public class AuthStateProvider : AuthenticationStateProvider { // ... public void NotifyUserLoggedIn(string token) { var authenticatedUser = new ClaimsPrincipal( new ClaimsIdentity(JwtParser.ParseClaimsFromJwt(token), "jwtAuthType") ); var authState = Task.FromResult(new AuthenticationState(authenticatedUser)); base.NotifyAuthenticationStateChanged(authState); } public void NotifyUserLogout() { var authState = Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()))); base.NotifyAuthenticationStateChanged(authState); } } }
namespace BlazorWasm.Client.Services { public class ClientAuthenticationService : IClientAuthenticationService { private readonly HttpClient _client; private readonly ILocalStorageService _localStorage; private readonly AuthenticationStateProvider _authStateProvider; public ClientAuthenticationService( HttpClient client, ILocalStorageService localStorage, AuthenticationStateProvider authStateProvider) { _client = client; _localStorage = localStorage; _authStateProvider = authStateProvider; } public async Task<AuthenticationResponseDTO> LoginAsync(AuthenticationDTO userFromAuthentication) { // ... if (response.IsSuccessStatusCode) { //... ((AuthStateProvider)_authStateProvider).NotifyUserLoggedIn(result.Token); return new AuthenticationResponseDTO { IsAuthSuccessful = true }; } //... } public async Task LogoutAsync() { //... ((AuthStateProvider)_authStateProvider).NotifyUserLogout(); } } }
- ابتدا AuthenticationStateProvider به سازندهی کلاس تزریق شدهاست.
- سپس در حین لاگین موفق، متد NotifyUserLoggedIn آن فراخوانی شدهاست.
- در آخر پس از خروج از سیستم، متد NotifyUserLogout فراخوانی شدهاست.
پس از این تغییرات اگر بر روی لینک logout کلیک کنیم، این گزینه به درستی عمل کرده و اینبار شاهد نمایش مجدد لینکهای لاگین و ثبت نام خواهیم بود.
محدود کردن دسترسی به صفحات برنامه بر اساس نقشهای کاربران
پس از ورود کاربر به سیستم و تامین AuthenticationState، اکنون میخواهیم تنها این نوع کاربران اعتبارسنجی شده بتوانند جزئیات اتاقها (برای شروع رزرو) و یا صفحهی نمایش نتیجهی پرداخت را مشاهده کنند. البته نمیخواهیم صفحهی نمایش لیست اتاقها را محدود کنیم. برای این منظور ویژگی Authorize را به ابتدای تعاریف کامپوننتهای PaymentResult.razor و RoomDetails.razor، اضافه میکنیم:
@attribute [Authorize(Roles = ConstantRoles.Customer)]
@using Microsoft.AspNetCore.Authorization
تکمیل مشخصات هویتی شخصی که قرار است اتاقی را رزرو کند
پیشتر در فرم RoomDetails.razor، اطلاعات ابتدایی کاربر را مانند نام او، دریافت میکردیم. اکنون با توجه به محدود شدن این کامپوننت به کاربران لاگین کرده، میتوان اطلاعات کاربر وارد شدهی به سیستم را نیز به صورت خودکار بارگذاری و تکمیل کرد:
@page "/hotel-room-details/{Id:int}" // ... @code { // ... protected override async Task OnInitializedAsync() { try { HotelBooking.OrderDetails = new RoomOrderDetailsDTO(); if (Id != null) { // ... if (await LocalStorage.GetItemAsync<UserDTO>(ConstantKeys.LocalUserDetails) != null) { var userInfo = await LocalStorage.GetItemAsync<UserDTO>(ConstantKeys.LocalUserDetails); HotelBooking.OrderDetails.UserId = userInfo.Id; HotelBooking.OrderDetails.Name = userInfo.Name; HotelBooking.OrderDetails.Email = userInfo.Email; HotelBooking.OrderDetails.Phone = userInfo.PhoneNo; } } } catch (Exception e) { await JsRuntime.ToastrError(e.Message); } }
public async Task<RoomOrderDetailsDTO> SaveRoomOrderDetailsAsync(RoomOrderDetailsDTO details) { // details.UserId = "unknown user!";
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-32.zip
Welcome to The Xamarin Show Snack Pack Edition. A Snack Pack is bite sized episode that is focused on a specific topic and covered in just a few minutes. Today, we take a look at how to manage and upgrade your Xamarin and Xamarin.Forms based applications to target .NET Standard. We also see how to install existing PCL based NuGets into that library.