1. Введение
В этой статье будет представлена то, как применять AngularJS к реальным проектам. В этой статье будет использоваться AngularJS для создания простой системы управления разрешениями. Я не скажу многое ниже, просто перейдите к теме.
2. Введение в общий дизайн архитектуры
Во -первых, давайте посмотрим на схему архитектурного дизайна всего проекта:
Из приведенного выше рисунка мы можем увидеть общую структуру всего проекта. Далее я подробно расскажу об общей структуре проекта:
Используйте веб -API ASP.NET для реализации служб REST. Этот метод реализации достиг общественного использования, развертывания и лучшего расширения направленных услуг. Веб -уровень зависит от интерфейса службы приложений и использует Castle Windsor для внедрения инъекции зависимостей.
Дисплей слой (пользовательский пользовательский интерфейс)
Слой дисплеев использует AngularJS для реализации страниц спа -салонов. Все данные страниц загружаются асинхронно и обновляются локально, поэтому эта реализация будет иметь лучший пользовательский опыт.
Служба приложения
AngularJS запрашивает веб -API для получения данных через службу HTTP, а реализация веб -API - вызов уровня приложения для запроса данных.
Инфраструктура слой
Уровень инфраструктуры включает в себя реализацию склада и реализацию некоторых общих методов.
Реализация складского уровня сначала реализована в коде EF, а метод миграции EF используется для создания и обновления базы данных.
Слой LH.common реализует некоторые общие методы, такие как классы помощи в журнале, расширения дерева экспрессии и другие классы.
Домен слой
Доменное слой в основном реализует все доменные модели проекта, включая реализацию модели домена и определение интерфейса склада.
В дополнение к введению полной структуры, мы представим реализацию сервисного обслуживания и реализацию веб-фронта проекта соответственно.
3. Реализация сервисного обслуживания
Бэкэнд -сервисы в основном используют веб -API ASP.NET для внедрения сервисов бэкэнд, а Castle Windsor используется для завершения инъекции зависимостей.
Здесь мы используем управление пользователями в управлении разрешениями для представления реализации услуги REST Web API.
Внедрение службы REST, которая предоставляет пользовательские данные:
публичный класс USERCONTROLLER: APICONTROLLER {Private Readonly Iuserservice _userservice; public usercontroller (iuserservice userservice) {_userservice = userservice; } [Httpget] [route ("api/user/getUsers")] public outputbase getUsers ([fromuri] PageInput Input) {return _userservice.getUsers (input); } [Httpget] [route ("api/user/userinfo")] public outputbase getUserinfo (int id) {return _userservice.getUser (id); } [Httppost] [route ("api/user/adduser")] public outputbase createUser ([frombody] userdto userdto) {return _userservice.adduser (userdto); } [Httppost] [route ("api/user/updateUser")] public outputbase updateUser ([от cody] userdto userdto) {return _userservice.updateuser (userdto); } [Httppost] [route ("api/user/updateroles")] public outputbase updaterololes ([frombody] userdto userdto) {return _userservice.updateroles (userdto); } [Httppost] [route ("api/user/deleteuser/{id}")] public outputbase base deleteuser (int id) {return _userservice.deleteuser (id); } [Httppost] [route ("api/user/deleterole/{id}/{roleid}")] public outputbase deleterole (int id, int roleid) {return _userservice.deleterole (id, roleid); }}Из приведенной выше реализации кода видно, что служба отдыха пользователя зависит от интерфейса с iuserservice и не помещает всю бизнес -логику в реализацию веб -API традиционным способом, но вместо этого инкапсулирует некоторые конкретные бизнес -реализации в соответствующий уровень приложений. API REST отвечает только за вызов Сервисов на соответствующем уровне приложения. Эти преимущества дизайна включают в себя:
Отдел обслуживания REST зависит от интерфейса с уровнем приложения для разделения обязанностей и передачи экземпляра службы приложения уровня для отдельного контейнера для впрыска зависимостей для завершения. Служба REST отвечает только за вызов соответствующих методов службы приложения для получения данных. Использование интерфейсов зависимости вместо реализаций с конкретными классами делает низкую связь между классами. Служба REST не включает в себя конкретные реализации бизнес -логики. Этот дизайн может сделать услуги лучше отдельно. Если вы хотите использовать WCF для реализации служб REST на более поздних этапах, нет необходимости многократно писать логику в веб -API в классе службы REST в WCF. В настоящее время вы можете вызвать метод интерфейса службы приложений для реализации службы REST WCF. Таким образом, внедрение бизнес -логики извлечена на уровень услуг приложений для его реализации. Этот дизайн сделает обязанности по обслуживанию REST более единичными, а реализация услуг REST проще расширяется.
Внедрение услуг пользовательских приложений:
Общедоступный класс пользователей: BaseService, iUserService {Private Readonly iuserRepository _userRepository; Частный readonly iuserrolerePository _userrolerePository; public userservice (iuserRepository userRepository, iuserrolerePository userRolerePository) {_userRepository = userRepository; _USERROLEREPOSITIOR = USERROLEREPOSITORT; } public getResults <userDto> getUsers (pageInput input) {var result = getDefault <getResults <userDto >> (); var filterExp = buildExpression (input); var Query = _userRepository.find (filterExp, user => user.id, sortorder.descending, input.current, input.size); result.total = _userRepository.find (filterExp) .count (); result.data = Query.select (user => new userdto () {id = user.id, createTime = user.creationtime, email = user.email, state = user.state, name = user.name, realname = user.ralnam z.Role.id, name = z.role.rolename}). Tolist (), totalRole = user.userroles.count ()}). tolist (); результат возврата; } public UpdaterSult UpdateUser (userdto user) {var result = getDefault <UdentaterSult> (); var exactUser = _userRepository.findsingle (u => u.id == user.id); if (существующий размер == null) {result.message = "user_not_exist"; Result.StateCode = 0x00303; результат возврата; } if (ishassameName (ESIGNEUSER.NAME, ESIGNEUSER.ID)) {result.message = "user_name_has_exist"; result.StateCode = 0x00302; результат возврата; } ESIGNEUSER.REALNAME = user.RealName; ESIGNEUSER.NAME = user.name; ESIGNESER.State = user.state; ESIGNEUSER.EMAIL = user.email; _userRepository.update (существует); _userRepository.commit (); result.issaved = true; результат возврата; } public seateresult <int> adduser (userdto userdto) {var result = getDefault <createresult <int >> (); if (ishassameName (userdto.name, userdto.id)) {result.message = "user_name_has_exist"; result.StateCode = 0x00302; результат возврата; } var user = new user () {creationTime = datetime.now, password = ", email = userDto.email, state = userDto.state, realName = userDto.RealName, name = userDto.name}; _userRepository.add (пользователь); _userRepository.commit (); result.id = user.id; result.iscreated = true; результат возврата; } public deleterESult deleteUser (int userId) {var result = getDefault <deteterESult> (); var user = _userRepository.findsingle (x => x.id == userid); if (user! = null) {_userrepository.delete (user); _userRepository.commit (); } result.isdelet = true; результат возврата; } public UpdaterSult updatePwd (userDTO user) {var result = getDefault <UdentaterSult> (); var userentity = _userRepository.findsingle (x => x.id == user.id); if (userentity == null) {result.message = string.format («В настоящее время отредактированный пользователь» {0} «больше не существует», user.name); результат возврата; } userentity.password = user.password; _userRepository.commit (); result.issaved = true; результат возврата; } public getResult <userDto> getUser (int userId) {var result = getDefault <getResult <userDto >> (); var model = _userRepository.findsingle (x => x.id == userid); if (model == null) {result.message = "use_not_exist"; Result.StateCode = 0x00402; результат возврата; } result.data = new userdto () {createtime = model.creationtime, email = model.email, id = model.id, realName = model.realname, state = model.state, name = model.name, password = "******"}; результат возврата; } public UpdaterSult Updateroles (userDTO пользователь) {var result = getDefault <UdentaterSult> (); var model = _userRepository.findsingle (x => x.id == user.id); if (model == null) {result.message = "use_not_exist"; Result.StateCode = 0x00402; результат возврата; } var list = model.userroles.tolist (); if (user.roles! = null) {foreach (var in in user.roles) {if (! list.exists (x => x.role.id == item.id)) {_userRolerePository.Add (new UserRole {roleid = item.id, userid = model.id}); }} foreach (var in list) {if (! user.Roles.Exists (x => x.id == item.id)) {_userRolerePository.delete (item); }} _userRolerePository.commit (); _userRepository.commit (); } result.issaved = true; результат возврата; } public DeleTerESult DeLeterole (int userId, int roleid) {var result = getDefault <deteterESult> (); var model = _userrolerePository.findsingle (x => x.userid == userid && x.roleid == roleid); if (model! = null) {_userrolerePository.delete (model); _userRolerePository.commit (); } result.isdelet = true; результат возврата; } public bool существует (String username, String password) {return _userRepository.findsingle (u => u.name == username && u.password == password)! = null; } private bool iShassameName (string name, int userId) {return! String.IsnullorWhitestepace (name) && _userRepository.find (u => u.name == name && u.id! = userId). any (); } частное выражение <func <user, bool >> buildExpression (pageInput pageInput) {Expression <func <user, bool >> filterExp = user => true; if (string.isnullorwhitespace (pageinput.name)) return filterexp; Switch (pageInput.type) {case 0: filterExp = user => user.name.contains (pageInput.name) || user.email.contains (pageinput.name); перерыв; Case 1: filterExp = user => user.name.contains (pageInput.name); перерыв; Case 2: FilterExp = user => user.email.contains (pageInput.name); перерыв; } return filterExp; }}Здесь уровень службы приложений может быть фактически оптимизирован, реализовать разделение чтения и записи на уровне кода, определить интерфейс IradonlyService и интерфейс iwriteservie и абстрагировать операции записи в базовый сервис в форме общих методов. Такое дополнение, удаление и операции модификации являются общедоступными. Причина, по которой эта операция может быть опубликована, заключается в том, что эти операции очень похожи, и они являются не чем иным, как различными объектами операций. Фактически, эта реализация использовалась в другом проекте с открытым исходным кодом: Onlinestore. Вы можете ссылаться на это для реализации его самостоятельно.
Реализация уровня хранения:
Службы пользовательских приложений напрямую не полагаются на конкретные классы складов, но также полагаются на их интерфейсы. Соответствующий класс пользовательских складов реализован следующим образом:
открытый класс BASEREPOSITORION <TENTITY>: IREPOSITORITION <TENTITY> Где Tentity: Class, Ientity {Private Readonly Threadlocal <userManagerDbContext> _localCtx = new Threadlocal <SOMPERMAGERDBCONTEXT> () => new UserMAGERDBCONTEXT ()); public usermanagerdbcontext dbcontext {get {return _localctx.value; }} public teent findsingling (выражение <func <tentity, bool >> exp = null) {return dbcontext.set <tentity> (). asnotracking (). Firstordefault (exp); } public iqueryable <tentity> find (выражение <func <tentity, bool >> exp = null) {return filter (exp); } public Iqueryable <tentity> Найти (выражение <func <teentity, bool >> выражение, выражение <func <teantity, dynamic >> sortpredicate, sortorder sortorder, int pagenumber, int pageize) {if (pagenumber <= 0) бросает новый аргумент, что нужно, чем есть, -), чем или равный, чем -то, 1). if (pageSize <= 0) бросить новый ArgiryOutOfRangeException («PageSize», PageSize, «PageSize должен большой, чем или равен 1.»); var Query = dbcontext.set <tentity> (). где (выражение); var skip = (pageNumber - 1) * pageSize; var take = pagesize; if (sortpredicate == null) бросить новое InvalidoperationException («На основе запроса подкачки должен указать поля сортировки и порядок сортировки».); Switch (sortorder) {case sortorder.ascending: var pagegascending = Query.sortby (sortpredicate) .skip (skip) .take (take); вернуть PageDascending; case sortorder.descending: var pageddescending = Query.sortbydescending (sortpredicate) .skip (skip) .take (take); вернуть PagegedDescending; } бросить новое InvalidoperationException («На основе запроса под пейджингом должен указать поля сортировки и сортировку.»); } public int getCount (Expression <func <tentity, bool >> exp = null) {return filter (exp) .count (); } public void Add (tentity entity) {dbcontext.set <tentity> (). add (entity); } public void Update (tentity entity) {dbcontext.Entry (entity) .state = entitystate.modified; } public void delete (tentity entity) {dbcontext.Entry (entity) .state = entitystate.deleted; Dbcontext.set <tentity> (). Удалить (Entity); } public void Delete (icollection <tentity> EntityCollection) {if (entityCollection.count == 0) return; Dbcontext.set <tentity> (). Прикрепить (EntityCollection.first ()); Dbcontext.set <tentity> (). Removerange (EntityCollection); } private iqueryable <tentity> Filter (выражение <func <tentity, bool >> exp) {var dbset = dbcontext.set <tentity> (). asqueryable (); if (exp! = null) dbset = dbset.where (exp); вернуть dbset; } public void Commit () {dbContext.SaveChanges (); }} открытый класс userRepository: baserepository <user>, iuserRepository {}4. Angularjs Front-End реализация
Реализация веб-фронта-использовать AngularJS для его реализации и применения модульной модели разработки. Конкретная кодовая структура веб-интерфейса показана на рисунке ниже:
App / Images // Хранить ресурсы изображений, используемые в приложении Web Front-End app / styles // hore style files app / scripts // Файлы скриптов, используемые во всем Web Front-End / Controllers // Directory Directory Module Module Module Module Contipure // Filters Modure Modure Module Module Module Module Modure) Modure Modure Sporture Prograthoreing Programagure Prograthoreing Modure) Модуля. App/Modules // Библиотека зависимостей проекта, Angular, Bootstrap, JQUERY Library App/Views // AngularJS View Stemplate Directory
Уровень вызова и бэкэнд между кодами веб -приложений, разработанных с использованием AngularJS, в основном такие же, как и бэкэнд, и они также являются страницей просмотра - модуль контроллера - служба услуг Web API.
Кроме того, загрузка ресурсов CSS и JS в веб-интерфейс использует метод пакета, чтобы уменьшить количество запрошенных ресурсов, тем самым ускоряя время загрузки страницы. Конфигурация конкретного класса комплекта:
public class BundleConfig { // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 public static void RegisterBundles(BundleCollection bundles) { // Class library dependency file bundles.Add(new ScriptBundle("~/js/base/lib").Include( "~/app/modules/jquery-1.11.2.min.js", "~/app/modules/angular/angular.min.js", "~/app/modules/angular/angular-route.min.js", "~/app/modules/bootstrap/js/ui-bootstrap-tpls-0.13.0.min. "~/app/modules/bootstrap-notify/bootstrap-notify.min.js")); // AngularJs Project File Bundles.Add (New ScriptBundle ("~/js/angularjs/app"). include ("~/app/scripts/services/*. JS", "~/app/scripts/controllers/*. JS", "~/app/scripts/js/js", ~/app/applters/*. JS/*. JS/*. JS/*. JS/*.*. "~/app/scripts/app.js")); // style bundles.add (new Stylebundle ("~/js/base/style"). Include ("~/app/modules/bootstrap/css/bootstrap.min.css", "~/app/styles/dashboard.css", "~/app/styles/console.css")); }}Home Index.cshtml
<! Doctype html> <html ng-app = "lh"> <Head> <meta name = "viewport" content = "width = width"/> <title> Простая система управления разрешением демо </title> @styles.render ("~/js/base/style") @scripts.render ("~/js/base/lib") </lib ") </lib") </lib ") </lib") </lib ") </lib") </lib ") </base/base/style") @ ng-controller="navigation"> <nav> <div> <div> <button type="button" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span>Toggle navigation</span> <span></span> <span></span> <span></span> </button> <a href = "/"> простое управление разрешением SystemDemo </a> </div> <div> <ul> <li ng-repeat = "item In ls"> <a href = "#{{item.urls [0] .link}}"> {{item.name} </a> </li> </ul> href = "@url.action (" Unlogin "," Home ", null)"> {{lang.exit}} </a> </div> </div> </nav> <viv> <div> <ul> <li ng-repeat = "it in urls"> <a div> <ul> <li ng-repeat = " href = "#{{item.link}}"> {{item.title}} </a> </li> </ul> </div> <div> <div ng-view> </div> </div> </div> </div> </div> @scripts.render ("~/js/angularjs/app") </Hods> </Hodml> </hodsml>5. Эффект работы
После введения внедрения передних и задних концов, давайте посмотрим на операционный эффект всего проекта:
6. Резюме
На этом этапе все содержание этой статьи было введено, хотя в проекте приложения AngularJS в этой статье все еще есть много идеальных областей, таких как отсутствие поддержки буферизации, отсутствие разделения чтения и записи, никаких стрессовых испытаний на некоторых API и т. Д., Но применение AngularJ в реальных проектах в основном подобно этому. Если вам нужно использовать AngularJs в вашем проекте, а бэкэнд вашей компании - .NET, я считаю, что обмен этой статьей может быть хорошей ссылкой. Кроме того, вы также можете ссылаться на мой другой проект с открытым исходным кодом: Onlinestore и Fastworks для дизайна архитектуры.
Выше приведено метод использования AngularJS для создания системы управления разрешениями, введенной редактором. Я надеюсь, что это будет полезно для всех!