1. Pendahuluan
Artikel ini akan memperkenalkan cara menerapkan angularjs ke proyek aktual. Artikel ini akan menggunakan AngularJS untuk membuat sistem manajemen izin sederhana. Saya tidak akan mengatakan banyak hal di bawah, pergi saja ke topik.
2. Pengantar Desain Arsitektur Secara Keseluruhan
Pertama, mari kita lihat diagram desain arsitektur dari seluruh proyek:
Dari gambar di atas, kita dapat melihat struktur keseluruhan dari seluruh proyek. Selanjutnya, saya akan memperkenalkan keseluruhan struktur proyek secara rinci:
Gunakan ASP.NET Web API untuk mengimplementasikan layanan REST. Metode implementasi ini telah mencapai penggunaan publik, penyebaran, dan perluasan layanan back-end yang lebih baik. Lapisan web tergantung pada antarmuka layanan aplikasi dan menggunakan Castle Windsor untuk mengimplementasikan injeksi ketergantungan.
Tampilan Lapisan (USER UI)
Lapisan tampilan menggunakan AngularJS untuk mengimplementasikan halaman spa. Semua data halaman dimuat secara tidak sinkron dan disegarkan secara lokal, sehingga implementasi ini akan memiliki pengalaman pengguna yang lebih baik.
Layanan Aplikasi
AngularJS meminta API Web untuk mendapatkan data melalui Layanan HTTP, dan implementasi API Web adalah menghubungi lapisan aplikasi untuk meminta data.
Lapisan infrastruktur
Lapisan infrastruktur mencakup implementasi pergudangan dan implementasi beberapa metode umum.
Implementasi lapisan pergudangan diimplementasikan dalam kode EF terlebih dahulu, dan metode migrasi EF digunakan untuk membuat dan memperbarui database.
LH.Common Layer mengimplementasikan beberapa metode umum, seperti kelas Bantuan Log, Ekspresi Ekstensi Pohon dan Kelas Lainnya.
Lapisan domain
Lapisan domain terutama mengimplementasikan semua model domain proyek, termasuk implementasi model domain dan definisi antarmuka pergudangan.
Selain memperkenalkan struktur lengkap, kami akan memperkenalkan implementasi layanan back-end dan implementasi front-end web masing-masing.
3. Implementasi Layanan Back-End
Layanan backend terutama menggunakan ASP.NET Web API untuk mengimplementasikan layanan backend, dan Castle Windsor digunakan untuk menyelesaikan injeksi ketergantungan.
Di sini kami menggunakan manajemen pengguna dalam manajemen izin untuk memperkenalkan implementasi layanan API Web REST.
Implementasi Layanan REST yang menyediakan data pengguna:
UserController kelas publik: apicontroller {private readonly iuserservice _userservice; UserController publik (iUserservice Userservice) {_Userservice = Userservice; } [Httpget] [route ("API/USER/GETUSERS")] OutputBase publik getUsers ([fromuri] pageInput input) {return _userservice.getUsers (input); } [Httpget] [route ("API/USER/USERInfo")] OutputBase publik getUserInfo (int id) {return _Userservice.getUser (id); } [Httppost] [route ("API/USER/ADDUSER")] OutputBase Publik CreateUser ([frombody] userdto userdto) {return _userservice.adduser (userdto); } [Httppost] [route ("API/User/UpdateAser")] Public OutputBase UpdateAser ([frombody] userdto userdto) {return _Userservice.updateUser (userdto); } [Httppost] [route ("API/User/Updateroles")] Updateroles OutputBase Publik ([Frombody] userdto userdto) {return _userservice.updateroles (userdto); } [Httppost] [route ("API/user/deleteUser/{id}")] Public OutputBase DeleteUser (int id) {return _userservice.deleteUser (id); } [Httppost] [route ("API/user/deleterole/{id}/{roleId}")] deleterole outputbase publik (int id, int roleID) {return _userservice.deleterole (id, roleID); }}Dari implementasi kode di atas, dapat dilihat bahwa layanan Pengguna REST tergantung pada antarmuka dengan iUserservice, dan tidak menempatkan semua logika bisnis dalam implementasi API Web dengan cara tradisional, tetapi sebaliknya merangkum beberapa implementasi bisnis tertentu ke dalam lapisan aplikasi yang sesuai. API REST hanya bertanggung jawab untuk memanggil Layanan di lapisan aplikasi yang sesuai. Manfaat desain ini meliputi:
Departemen Layanan REST bergantung pada antarmuka dengan lapisan aplikasi untuk memisahkan tanggung jawab dan menyerahkan instantiasi layanan lapisan aplikasi ke wadah injeksi ketergantungan yang terpisah untuk penyelesaian. Layanan REST hanya bertanggung jawab untuk memanggil metode layanan aplikasi yang sesuai untuk mendapatkan data. Menggunakan antarmuka ketergantungan alih -alih implementasi dengan kelas spesifik membuat kopling rendah antar kelas. Layanan istirahat tidak termasuk implementasi logika bisnis tertentu. Desain ini dapat membuat layanan lebih terpisah. Jika Anda ingin menggunakan WCF untuk mengimplementasikan layanan REST di tahap selanjutnya, tidak perlu berulang kali menulis logika di API Web di kelas layanan REST WCF. Saat ini, Anda dapat menghubungi metode antarmuka layanan aplikasi untuk mengimplementasikan layanan WCF REST. Oleh karena itu, implementasi logika bisnis diekstraksi ke lapisan layanan aplikasi untuk mengimplementasikannya. Desain ini akan membuat tanggung jawab layanan istirahat lebih lajang dan implementasi layanan REST lebih mudah diperluas.
Implementasi Layanan Aplikasi Pengguna:
Public Class UserService: Baseservice, iuserservice {private readonly iuserrepository _userrepository; private readonly iuserrolerepository _userrolerEpository; UserServer Public (iuserrepository userrepository, iuserrolerepository userRoleRepository) {_userrepository = userrepository; _UserRolerEpository = userRoleRepository; } getResult publik <UserDTO> getUsers (input PageInput) {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.Realname, kata sandi = "*****", roles = user.userroles. z.role.id, name = z.role.rolename}). Tolist (), totalRole = user.userroles.count ()}). Tolist (); hasil pengembalian; } UpdateReSult PublateSult UpdateUser (userDTO user) {var result = getDefault <PlovateResult> (); var eksistuser = _userrepository.findsingle (u => u.id == user.id); if (existUser == null) {result.message = "user_not_exist"; result.statecode = 0x00303; hasil pengembalian; } if (isHassamename (eksistuser.name, eksistuser.id)) {result.message = "user_name_has_exist"; result.statecode = 0x00302; hasil pengembalian; } existUser.RealName = user.RealName; eksistuser.name = user.name; eksistuser.state = user.state; eksistuser.email = user.email; _userrepository.update (eksistuser); _userrepository.Commit (); result.issaved = true; hasil pengembalian; } public createresult <Itt> addUser (userdto userdto) {var result = getDefault <createresult <int>> (); if (isHassamename (userdto.name, userdto.id)) {result.message = "user_name_has_exist"; result.statecode = 0x00302; hasil pengembalian; } var user = User baru () {creationTime = datetime.now, password = "", email = userdto.email, state = userdto.state, realname = userdto.realname, name = userdto.name}; _userrepository.add (pengguna); _userrepository.Commit (); result.id = user.id; result.iscreated = true; hasil pengembalian; } DeleteUser DeleteUser (int userId) {var result = getDefault <Deleteresult> (); var user = _userrepository.findsingle (x => x.id == userId); if (user! = null) {_userrepository.delete (user); _userrepository.Commit (); } result.isdeleted = true; hasil pengembalian; } Public UpdateResult updatePWD (userdto user) {var result = getDefault <PlovateResult> (); var userentity = _userrepository.findsingle (x => x.id == user.id); if (userEntity == null) {result.message = string.format ("pengguna yang saat ini diedit" {0} "tidak ada lagi", user.name); hasil pengembalian; } userentity.password = user.password; _userrepository.Commit (); result.issaved = true; hasil pengembalian; } 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; hasil pengembalian; } result.data = UserDTO baru () {createTime = model.creationTime, email = model.email, id = model.id, realname = model.RealName, state = model.state, name = model.name, password = "******"}; hasil pengembalian; } Updateresult Public Updateroles (userDTO user) {var result = getDefault <PlovateResult> (); var model = _userrepository.findsingle (x => x.id == user.id); if (model == null) {result.message = "use_not_exist"; result.statecode = 0x00402; hasil pengembalian; } var list = model.userroles.tolist (); if (user.Roles! = null) {foreach (item var di user.roses) {if (! list.exists (x => x.role.id == item.id)) {_userrolerEpository.add (UserRole {roleId = retem.id, userid = model.id}); }} foreach (item var dalam daftar) {if (! User.Roles.exists (x => x.id == item.id)) {_userroleRepository.delete (item); }} _UserRolerEpository.Commit (); _userrepository.Commit (); } result.issaved = true; hasil pengembalian; } deleterole deleteresult publik (int userid, int roleId) {var result = getDefault <deleteresult> (); var model = _UserRolerEpository.findsingle (x => x.userid == userid && x.roleid == roleId); if (model! = null) {_userrolerEpository.delete (model); _userrolerepository.Commit (); } result.isdeleted = true; hasil pengembalian; } public bool ada (string username, string password) {return _userrepository.findsingle (u => u.name == username && u.password == kata sandi)! = null; } private bool ishassamename (nama string, int userid) {return! string.isnullorwhitespace (name) && _userrepository.find (u => u.name == Nama && u.id! = UserId) .Any (); } ekspresi pribadi <func <user, bool>> buildExpression (pageInput pageInput) {ekspresi <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); merusak; case 1: filterexp = user => user.name.contains (pageInput.name); merusak; case 2: filterexp = user => user.email.contains (pageInput.name); merusak; } return filterexp; }}Di sini, lapisan layanan aplikasi sebenarnya dapat dioptimalkan lebih lanjut, mengimplementasikan pemisahan membaca dan menulis tingkat kode, mendefinisikan antarmuka IREADONLYService dan antarmuka IWriteservie, dan abstrak operasi tulis ke Baseservice dalam bentuk metode generik. Penambahan, operasi penghapusan dan modifikasi seperti itu bersifat publik. Alasan mengapa operasi ini dapat dipublikasikan adalah karena operasi ini sangat mirip, dan mereka tidak lebih dari entitas operasi yang berbeda. Bahkan, implementasi ini telah digunakan dalam proyek open source lain: Onlinestore. Anda dapat merujuk ini untuk mengimplementasikannya sendiri.
Implementasi lapisan penyimpanan:
Layanan aplikasi pengguna tidak secara langsung bergantung pada kelas pergudangan tertentu, tetapi juga mengandalkan antarmuka mereka. Kelas pergudangan pengguna yang sesuai diimplementasikan sebagai berikut:
Kelas publik Baserepository <Tentity>: Irepository <Tentity> di mana tentitas: kelas, ientity {private readonly threadLocal <UserManagerDbContext> _localctx = ThreadLocal baru <UserManagEndBContext> () => new UserManagerDbContext ()); UserManagerDbContext dbContext {get {return _localctx.value; }} tentitas publik Findsingle (ekspresi <func <tentity, bool >> exp = null) {return dbcontext.set <Tentity> (). asnotracking (). firstordefault (exp); } public iqueryable <Tentity> find (ekspresi <func <tentity, bool >> exp = null) {return filter (exp); } public iqueryable <Tentity> temukan (ekspresi <func <tentity, bool >> ekspresi, ekspresi <func <tentity, dinamis >> sortpredicate, sortorder sortorder, int pagenumber, int int pageSize) {if "pagenumber", pagenumber ", pagenumber", pagenumber ", pagenumber", pagenumber ", pagenumber", pagenumber ", pagenumber", pagenumber ", pagenumber; jika (halaman <= 0) melempar argumentoutofrangeException ("halaman", halaman, "halaman harus bagus atau sama dengan 1."); var query = dbcontext.set <Tentity> (). Where (Expression); var skip = (pagenumber - 1) * halaman; var take = pageSize; if (sortPredicate == null) Lempar InvalidOperationException baru ("berdasarkan kueri paging harus menentukan bidang penyortiran dan mengurutkan urutan."); switch (sortorder) {case sortOrder.ascending: var pagedascending = query.sortby (sortpredicate) .skip (lewati) .take (ambil); Kembali Pagredascending; case sortorder.descending: var pageddescending = query.sortbydescending (sortpredicate) .skip (lewati) .take (ambil); kembali pageddescending; } lempar InvalidOperationException baru ("Berdasarkan kueri paging harus menentukan bidang penyortiran dan mengurutkan urutan."); } public int getCount (ekspresi <func <tentity, bool >> exp = null) {return filter (exp) .count (); } public void add (entitas tentitas) {dbcontext.set <Tentity> (). add (entitas); } Pembaruan public void (entitas Tentitas) {dbcontext.entry (entitas) .state = entitystate.modified; } public void delete (entitas tentitas) {dbcontext.entry (entitas) .state = entitystate.deleted; Dbcontext.set <Tentity> (). Remove (entitas); } public void delete (icollection <Tentity> EntityCollection) {if (EntityCollection.count == 0) return; Dbcontext.set <Tentity> (). Lampirkan (EntityCollection.first ()); Dbcontext.set <Tentity> (). Removerange (EntityCollection); } private iQueryable <Tentity> filter (ekspresi <func <tentity, bool >> exp) {var dbset = dbcontext.set <dentity> (). asQueryable (); if (exp! = null) dbset = dbset.where (exp); mengembalikan dbset; } public void commit () {dbcontext.savechanges (); }} kelas publik USErrepository: BaseRepository <User>, iuserrepository {}4. Implementasi front-end AngularJS
Implementasi front-end web adalah menggunakan AngularJS untuk mengimplementasikannya dan mengadopsi model pengembangan modular. Struktur kode spesifik dari front-end web ditunjukkan pada gambar di bawah ini:
Aplikasi / Gambar // Store Sumber Daya Gambar yang Digunakan oleh Web Front-Enend App / Styles // Store Style Files App / Scripts // File Script yang Digunakan di Seluruh Web Front-End / Controllers // AngularJS Controller Direktori Penyimpanan / Arahan // Module Module Direktori Penyimpanan Modul / Filter / / Modul Filter / Modul Penyimpanan / Layanan Layanan // Service Module Direktori Penyimpanan / Filter / Modul Penyimpanan Modul / Layanan Layanan Modul Layanan. Aplikasi/Modul // Perpustakaan Dependensi Proyek, Angular, Bootstrap, Perpustakaan JQuery Aplikasi/Views // AngularJS Lihat Template Storage Directory
Level panggilan dan backend antara kode aplikasi web yang dikembangkan menggunakan AngularJS pada dasarnya sama dengan backend, dan mereka juga halaman tampilan - modul pengontrol - modul layanan - layanan API web.
Selain itu, pemuatan sumber daya CSS dan JS di web front-end mengadopsi metode bundel untuk mengurangi jumlah sumber daya yang diminta, sehingga mempercepat waktu pemuatan halaman. Konfigurasi kelas bundel spesifik:
Kelas Publik Bundleconfig {// Untuk informasi lebih lanjut tentang bundling, kunjungi http://go.microsoft.com/fwlink/?linkid=301862 public static void registerbundles (bundlecollection bundles) {// class library File bundles. "~/App/Modul/jQuery-1.11.2.min.js", "~/app/modul/angular/angular.min.js", "~/app/modul/angular/angular-route.min.js", "~/app/modul/bootstrap/js/js/ui-bottaps. "~/app/modules/bootstrap-notify/bootstrap-notify.min.js")); // AngularJS file proyek bundles.add (new scriptBundle ("~/js/angularjs/app"). Sertakan ("~/app/skrip/layanan/*. Js", "~/app/skrip/pengontrol/*. "~/app/scripts/app.js")); // bundles style.add (styleBundle baru ("~/js/base/style"). Sertakan ("~/app/modul/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 = device-width"/> <itement> Demo Sistem Manajemen Izin Sederhana </title> @styles.render ("~/js/base/style") @skrip ("~ ~/JS/JS/basis/js/js/js/gaya") @s. <Av> <div> <div> <tombol type = "tombol" data-koggle = "collapse" data-target = "#navbar" aria-expanded = "false" aria-controls = "navbar"> <span> navigasi sakelar </span> <pan> <pan> <span> </span> </span> <pan> </span> </span> <span> <span> </span> </span> <span> </span> SystemDemo </a> </div> <div> <ul> <li ng-repeat = "item in ls"> <a href = "#{{item.urls [0] .link}}"> {{item.name}} </a> </li> </ul> <v div> "non-href ="@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a href = </ul. {{lang.exit}} </a> </div> </div> </bav> <div> <vet> <verv> <ul> <li ng-repeat = "item dalam urls"> <a href = "#{{{item.link}}"> {{item.title} {{{{link} "> ng-view> </div> </div> </div> </div> </div> @scripts.render ("~/js/angularjs/app") </body> </html>5. Efek Operasi
Setelah memperkenalkan implementasi ujung depan dan belakang, mari kita lihat efek operasi dari seluruh proyek:
6. Ringkasan
Pada titik ini, semua isi artikel ini telah diperkenalkan, meskipun proyek aplikasi AngularJS dalam artikel ini masih memiliki banyak area yang sempurna, seperti tidak ada dukungan buffering, tidak ada pemisahan baca dan tulis, tidak ada tes stres pada beberapa API, dll. Tetapi penerapan AngularJS dalam proyek aktual pada dasarnya seperti ini. Jika Anda perlu menggunakan AngularJS dalam proyek Anda, dan backend perusahaan Anda adalah .NET, saya percaya bahwa berbagi artikel ini dapat menjadi referensi yang baik. Selain itu, Anda juga dapat merujuk pada proyek open source saya yang lain: Onlinestore dan Fastworks untuk desain arsitektur.
Di atas adalah metode menggunakan AngularJS untuk membuat sistem manajemen izin yang diperkenalkan oleh editor. Saya harap ini akan membantu semua orang!