تفاوت AngularJS با KnockoutJS
AngularJS #2
//_EntityFormLayout.cshtml @inherits EntityFormRazorPage<dynamic> @{ Layout = null; } <div class="modal-header"> <h4 class="modal-title" asp-if="IsNew">Create New @EntityDisplayName</h4> <h4 class="modal-title" asp-if="!IsNew">Edit @EntityDisplayName</h4> <button type="button" class="close" data-dismiss="modal">×</button> </div> <form asp-action="@(IsNew ? CreateActionName : EditActionName)" asp-modal-form="@FormId"> <div class="modal-body"> <input type="hidden" name="continue-editing" value="true" asp-permission="@EditPermission"/> <input asp-for="@Version" type="hidden"/> <input asp-for="@Id" type="hidden"/> @RenderBody() </div> <div class="modal-footer"> <a class="btn btn-light btn-circle" asp-modal-delete-link asp-model-id="@Id" asp-modal-toggle="false" asp-action="@DeleteActionName" asp-if="!IsNew" asp-permission="@DeletePermission" title="Delete Role"> <i class="fa fa-trash text-danger"></i> </a> <a class="btn btn-light btn-circle" title="Refresh Role" asp-if="!IsNew" asp-modal-link asp-modal-toggle="false" asp-action="@EditActionName" asp-route-id="@Id"> <i class="fa fa-repeat"></i> </a> <a class="btn btn-light btn-circle mr-auto" title="New Role" asp-modal-link asp-modal-toggle="false" asp-permission="@CreatePermission" asp-action="@CreateActionName"> <i class="fa fa-plus"></i> </a> <button type="button" class="btn btn-light" data-dismiss="modal"> <i class="fa fa-ban"></i> Cancel </button> <button type="submit" class="btn btn-outline-primary"> <i class="fa fa-save"></i> Save Changes </button> </div> </form>
public abstract class EntityFormRazorPage<T> : RazorPage<T> { protected string EntityName { get => ViewData[nameof(EntityName)].ToString(); set => ViewData[nameof(EntityName)] = value; } protected string EntityDisplayName { get => ViewData[nameof(EntityDisplayName)].ToString(); set => ViewData[nameof(EntityDisplayName)] = value; } protected string DeletePermission { get => ViewData[nameof(DeletePermission)].ToString(); set => ViewData[nameof(DeletePermission)] = value; } protected string CreatePermission { get => ViewData[nameof(CreatePermission)].ToString(); set => ViewData[nameof(CreatePermission)] = value; } protected string EditPermission { get => ViewData[nameof(EditPermission)].ToString(); set => ViewData[nameof(EditPermission)] = value; } protected string CreateActionName { get => ViewData.TryGetValue(nameof(CreateActionName), out var value) ? value.ToString() : "Create"; set => ViewData[nameof(CreateActionName)] = value; } protected string EditActionName { get => ViewData.TryGetValue(nameof(EditActionName), out var value) ? value.ToString() : "Edit"; set => ViewData[nameof(EditActionName)] = value; } protected string DeleteActionName { get => ViewData.TryGetValue(nameof(DeleteActionName), out var value) ? value.ToString() : "Delete"; set => ViewData[nameof(DeleteActionName)] = value; } protected string FormId => $"{EntityName}Form"; protected bool IsNew => (Model as dynamic).IsNew(); protected string Id => (Model as dynamic).Id.ToString(CultureInfo.InvariantCulture); protected byte[] Version => (Model as dynamic).Version; }
//_BlogPartial.cshtml @inherits EntityFormRazorPage<BlogModel> @{ Layout = "_EntityFormLayout"; EntityName = "Blog"; DeletePermission = PermissionNames.Blogs_Delete; CreatePermission = PermissionNames.Blogs_Create; EditPermission = PermissionNames.Blogs_Edit; EntityDisplayName = "Blog"; }
//_BlogPartial.cshtml @inherits EntityFormRazorPage<BlogModel> @{ Layout = "_EntityFormLayout"; ... } <div class="form-group row"> <div class="col col-md-8"> <label asp-for="Title" class="col-form-label text-md-left"></label> <input asp-for="Title" autocomplete="off" class="form-control"/> <span asp-validation-for="Title" class="text-danger"></span> </div> </div> <div class="form-group row"> <div class="col"> <label asp-for="Url" class="col-form-label text-md-left"></label> <input asp-for="Url" class="form-control" type="url"/> <span asp-validation-for="Url" class="text-danger"></span> </div> </div>
//_BlogPartial.cshtml @inherits EntityFormRazorPage<BlogModel> @{ Layout = "_EntityFormLayout"; EntityName = "Blog"; DeletePermission = PermissionNames.Blogs_Delete; CreatePermission = PermissionNames.Blogs_Create; EditPermission = PermissionNames.Blogs_Edit; EntityDisplayName = "Blog"; } @Html.EditorForModel()
روش جاری شباهت زیادی به استفاده از Context در React دارد:
Context provides a way to pass data through the component tree without having to pass props down manually at every level
// parent component providing 'foo' var Provider = { provide: { foo: 'bar' }, // ... }
// child component injecting 'foo' var Child = { inject: ['foo'], created () { console.log(this.foo) // => "bar" } // ... }
Using an injected value as the default for a prop //دریافت میکنیم props در قسمت child را در کامپوننت foo مقدار const Child = { inject: ['foo'], props: { bar: { default () { return this.foo } } } } Using an injected value as data entry //دریافت میکنیم data در قسمت child را در کامپوننت foo مقدار const Child = { inject: ['foo'], data () { return { bar: this.foo } } }
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <title>Dependency injection</title> </head> <body> <div id="app"> <button @click="counter++">Increment counter</button> <h2>Parent</h2> <p>{{counter}}</p> <div> <h3>Child</h3> <child></child> </div> </div> <script> const Child = { inject: ['counter_in_child'], template: `<div>Counter Child is:{{ counter_in_child }}</div>` }; new Vue ({ el: "#app", components: { Child }, provide() { return { counter_in_child: this.counter }; }, data() { return { counter: 0 }; } }); </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <title>Dependency injection</title> </head> <body> <div id="app"> <button @click="counter++">Increment counter</button> <h2>Parent</h2> <p>{{counter}}</p> <div> <h3>Child</h3> <child></child> </div> </div> <script> const Child = { inject: ['counter_in_child'], template: `<div>Counter Child is:{{ counter_in_child.counter }}</div>` }; new Vue ({ el: "#app", components: { Child }, provide() { const counter_in_child={}; Object.defineProperty(counter_in_child,'counter',{ enumerable:true, get:()=>this.counter }) return { counter_in_child }; }, data() { return { counter: 0 }; } }); </script> </body> </html>
provide
and inject
are primarily provided for advanced plugin / component library use cases. It is NOT recommended to use them in generic application code در قسمت مدل ابتدا یک کلاس پایه برای مدل ایجاد خواهیم کرد:
public abstract class Entity { public Guid Id { get; set; } }
public class Book : EntityBase { public string Name { get; set; } public decimal Author { get; set; } }
public class BookRepository { private readonly ConcurrentDictionary<Guid, Book> result = new ConcurrentDictionary<Guid, Book>(); public IQueryable<Book> GetAll() { return result.Values.AsQueryable(); } public Book Add(Book entity) { if (entity.Id == Guid.Empty) entity.Id = Guid.NewGuid(); if (result.ContainsKey(entity.Id)) return null; if (!result.TryAdd(entity.Id, entity)) return null; return entity; } }
نوبت به کلاس کنترلر میرسد. یک کنترلر Api به نام BooksController ایجاد کنید و سپس کدهای زیر را در آن کپی نمایید:
public class BooksController : ApiController { public static BookRepository repository = new BookRepository(); public BooksController() { repository.Add(new Book { Id=Guid.NewGuid(), Name="C#", Author="Masoud Pakdel" }); repository.Add(new Book { Id = Guid.NewGuid(), Name = "F#", Author = "Masoud Pakdel" }); repository.Add(new Book { Id = Guid.NewGuid(), Name = "TypeScript", Author = "Masoud Pakdel" }); } public IEnumerable<Book> Get() { return repository.GetAll().ToArray(); } }
در این کنترلر، اکشنی به نام Get داریم که در آن اطلاعات کتابها از Repository مربوطه برگشت داده خواهد شد. در سازنده این کنترلر ابتدا سه کتاب به صورت پیش فرض اضافه میشود و انتظار داریم که بعد از اجرای برنامه، لیست مورد نظر را مشاهده نماییم.
module Model { export class Book{ Id: string; Name: string; Author: string; } }
<div ng-controller="Books.Controller"> <table class="table table-striped table-hover" style="width: 500px;"> <thead> <tr> <th>Name</th> <th>Author</th> </tr> </thead> <tbody> <tr ng-repeat="book in books"> <td>{{book.Name}}</td> <td>{{book.Author}}</td> </tr> </tbody> </table> </div>
ابتدا یک کنترلری که به نام Controller که در ماژولی به نام Book تعریف شده است باید ایجاد شود. اطلاعات تمام کتب ثبت شده باید از سرویس مورد نظر دریافت و با یک ng-repeat در جدول نمایش داده خواهند شود.
در پوشه app یک فایل TypeScript دیگر برای تعریف برخی نیازمندیها به نام AngularModule ایجاد میکنیم که کد آن به صورت زیر خواهد بود:
declare module AngularModule { export interface HttpPromise { success(callback: Function) : HttpPromise; } export interface Http { get(url: string): HttpPromise; } }
در اینترفیس Http نیز تابعی به نام get تعریف شده است که برای دریافت اطلاعات از سرویس api، مورد استفاده قرار خواهد گرفت. از آن جا که تعریف توابع در اینترفیس فاقد بدنه است در نتیجه این جا فقط امضای توابع مشخص خواهد شد. پیاده سازی توابع به عهده کنترلرها خواهد بود:
مرحله بعد مربوط است به تعریف کنترلری به نام BookController تا اینترفیس بالا را پیاده سازی نماید. کدهای آن به صورت زیر خواهد بود:
/// <reference path='AngularModule.ts' /> /// <reference path='BookModel.ts' /> module Books { export interface Scope { books: Model.Book[]; } export class Controller { private httpService: any; constructor($scope: Scope, $http: any) { this.httpService = $http; this.getAllBooks(function (data) { $scope.books = data; }); var controller = this; } getAllBooks(successCallback: Function): void { this.httpService.get('/api/books').success(function (data, status) { successCallback(data); }); } } }
توضیح کدهای بالا:
برای دسترسی به تعاریف انجام شده در سایر ماژولها باید ارجاعی به فایل تعاریف ماژولهای مورد نظر داشته باشیم. در غیر این صورت هنگام استفاده از این ماژولها با خطای کامپایلری روبرو خواهیم شد. عملیات ارجاع به صورت زیر است:
/// <reference path='AngularModule.ts' /> /// <reference path='BookModel.ts' />
export interface Scope { books: Model.Book[]; }
در نهایت خروجی به صورت زیر خواهد بود:
سورس پیاده سازی مثال بالا در Visual Studio 2013
جلوگیری از deadlock در برنامههای async
public static DateTime GetLastActivity(this System.Security.Principal.IIdentity user) { var service = SmObjectFactory.Container.GetInstance<IApplicationUserManager>(); return service.FindByIdAsync(int.Parse(user.GetUserId())).Result.LastActivity; }
سلام
من کل دوره را مطالعه کردم خیلی جالب بود . تشکر میکنم
برنامه ILSPY فوق العاده بود و خیلی در یادگیری و درک عملکرد برنامهها کمکم کرد، اما این ابزار چیزی شبیه به برنامه Refox است و کلیه کدها را Decode میکنه. برای محافظت برنامه از Decode شدن و جلوگیری از دسترسی برنامه هایی مانند ILSPY چه باید کرد.
چرا که با این حساب برنامههای دات نه چیزی شبیه برنامههای Foxpro میشه که به راحتی میشه ReSource کرد.
با برنامه فوق حتی Assemblyهای خود Dotnet هم قابل Resource هست !
همچنین برنامه ILSPY تنها امکان نمایش سورس و دارد و اگر بخواهیم بخش از اسمبلی و تغییر بدیم و Dll یا Exe را Patch کنیم مثلا عنوان Butten تغییر بدیم و یا حتی خطی را اضافه و کم کنیم از چه برنامه ای استفاده کرد؟
خلاصه اشتراکهای روز پنج شنبه 3 آذر 1390
از طرفی به نظر من برای یه برنامه تجاری سازمانی، کاری که سیلورلایت انجام میده رو html نمی تونه به سادگی و راحتی انجام بده.