1. مقدمة
ستقدم هذه المقالة كيفية تطبيق AngularJS على المشاريع الفعلية. ستستخدم هذه المقالة AngularJS لإنشاء نظام إدارة إذن بسيط. لن أقول الكثير أدناه ، فقط اذهب إلى الموضوع.
2. مقدمة لتصميم العمارة الشاملة
أولاً ، دعونا نلقي نظرة على مخطط التصميم المعماري للمشروع بأكمله:
من الشكل أعلاه ، يمكننا أن نرى الهيكل العام للمشروع بأكمله. بعد ذلك ، سأقدم الهيكل العام للمشروع بالتفصيل:
استخدم ASP.NET Web API لتنفيذ خدمات REST. حققت طريقة التنفيذ هذه الاستخدام العام والنشر وتوسيع أفضل للخدمات الخلفية. تعتمد طبقة الويب على واجهة خدمة التطبيق وتستخدم Castle Windsor لتنفيذ حقن التبعية.
عرض طبقة (واجهة المستخدم المستخدم)
تستخدم طبقة العرض AngularJs لتنفيذ صفحات السبا. يتم تحميل جميع بيانات الصفحات بشكل غير متزامن وتحديثها محليًا ، لذلك سيكون لهذا التنفيذ تجربة مستخدم أفضل.
خدمة التطبيق
يطلب AngularJS واجهة برمجة تطبيقات الويب للحصول على البيانات من خلال خدمة HTTP ، وتنفيذ واجهة برمجة تطبيقات الويب هو استدعاء طبقة التطبيق لطلب البيانات.
طبقة البنية التحتية
تتضمن طبقة البنية التحتية تنفيذ التخزين وتنفيذ بعض الأساليب الشائعة.
يتم تنفيذ تطبيق طبقة التخزين في رمز EF أولاً ، ويتم استخدام طريقة ترحيل EF لإنشاء قاعدة البيانات وتحديثها.
تنفذ طبقة LH.Common بعض الطرق الشائعة ، مثل فئات مساعدة السجل ، وملحقات شجرة التعبير والفئات الأخرى.
طبقة المجال
تقوم طبقة المجال بتنفيذ جميع نماذج المجال للمشروع بشكل أساسي ، بما في ذلك تنفيذ نموذج المجال وتعريف واجهة التخزين.
بالإضافة إلى إدخال الهيكل الكامل ، سنقدم تنفيذ الخدمة الخلفية وتنفيذ الواجهة الأمامية لمشروع الويب على التوالي.
3. تنفيذ الخدمة الخلفية
تستخدم خدمات الواجهة الخلفية بشكل أساسي ASP.NET Web API لتنفيذ خدمات الواجهة الخلفية ، ويتم استخدام Castle Windsor لإكمال حقن التبعية.
هنا نستخدم إدارة المستخدم في إدارة الإذن لتقديم تنفيذ خدمة REST Web API.
تنفيذ خدمة REST التي توفر بيانات المستخدم:
الطبقة العامة USERCONTROLLER: apicontroller {private readonly iuserservice _userservice ؛ userController العام (iuserservice userviceRevice) {_userservice = userService ؛ } [httpget] [route ("API/user/getUsers")] GetUsers Public OutputBase ([Fromuri] PageInput INPUT) {return _userservice.getusers (input) ؛ } [httpget] [route ("api/user/userinfo")] الإخراج العام getUserInfo (int id) {return _userservice.getuser (id) ؛ } [httppost] [route ("API/user/adduser")] OutputBase public CreateUser ([frombody] userdto userdto) {return _userservice.adduser (userdto) ؛ } [httppost] [route ("API/user/updateUser")] uptordedbase upturdyuser ([frombody] userdto userdto) {return _userservice.updateuser (userdto) ؛ } [httppost] [route ("API/user/updateroles")] updaterbase public outpratebase ([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}/{robeId}")] deleterole publictbase (int id ، int rob) {return _userservice.deleterole (id ، roboid) ؛ }}من تطبيق الرمز أعلاه ، يمكن ملاحظة أن خدمة REST للمستخدم تعتمد على الواجهة مع iuserservice ، ولا تضع جميع منطق العمل في تطبيق واجهة برمجة تطبيقات الويب بالطريقة التقليدية ، ولكن بدلاً من ذلك تغلف بعض تطبيقات الأعمال المحددة في طبقة التطبيق المقابلة. يعد API REST مسؤولاً فقط عن استدعاء الخدمات في طبقة التطبيق المقابلة. تشمل مزايا التصميم هذه:
يعتمد قسم خدمة REST على الواجهة مع طبقة التطبيق لفصل المسؤوليات وتسليم استئصال خدمة طبقة التطبيق إلى حاوية حقن تبعية منفصلة لإكمالها. خدمة REST مسؤولة فقط عن استدعاء أساليب خدمة التطبيق المقابلة للحصول على البيانات. إن استخدام واجهات التبعية بدلاً من التطبيقات مع فئات محددة يجعل الاقتران المنخفض بين الفئات. لا تتضمن خدمة REST تطبيقات منطق أعمال محددة. هذا التصميم يمكن أن يجعل الخدمات منفصلة بشكل أفضل. إذا كنت ترغب في استخدام WCF لتنفيذ خدمات REST في المرحلة اللاحقة ، فليست هناك حاجة إلى كتابة منطق متكرر في واجهة برمجة تطبيقات الويب في فئة خدمة REST في WCF. في هذا الوقت ، يمكنك الاتصال بطريقة واجهة خدمة التطبيق لتطبيق خدمة REST WCF. لذلك ، يتم استخراج تنفيذ منطق الأعمال إلى طبقة خدمة التطبيق لتنفيذها. سيجعل هذا التصميم مسؤوليات خدمة REST أكثر وحيدة وتنفيذ خدمة REST أسهل في التوسع.
تنفيذ خدمات تطبيق المستخدم:
ustervice public class: baseservice ، iuserservice {private readonly iuserrepository _userRepository ؛ private readonly iuserrolerepository _userrolerepository ؛ userService public (iuserrepository userrepository ، iuserrolerepository userrolerepository) {_userrepository = userRepository ؛ _userrolerepository = userrolerepository ؛ } getResults public <SerdDTo> 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 () {eD = user.id ، createTime = user.CreationTime ، email = user.email ، state = user.state ، name = user.name ، RealName = user.realName ، " z.role.id ، name = z.role.rolename}). tolist () ، totalRole = user.userRoles.count ()}). tolist () ؛ نتيجة العودة } updateustult updateUser (userdto user) {var result = getDefault <UpdateResult> () ؛ var expensuser = _userRepository.findsingle (u => U.ID == user.id) ؛ if (expensuser == null) {result.message = "user_not_exist" ؛ result.StateCode = 0x00303 ؛ نتيجة العودة } if (ishassamename (expensuser.name ، expenuser.id)) {result.message = "user_name_has_exist" ؛ result.StateCode = 0x00302 ؛ نتيجة العودة } expensuser.realName = user.realName ؛ ExpressUser.name = user.name ؛ expensuser.state = user.state ؛ expensuser.email = user.email ؛ _USERREPOSTORY.UPDATE (الوجود) ؛ _USERREPOSTORY.COMMIT () ؛ النتيجة. نتيجة العودة } createresult public <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 () {createTime = dateTime.now ، password = "" ، email = userdto.email ، state = userDto.state ، realName = userDto.realName ، name = ers ersdto.name} ؛ _userRepository.add (المستخدم) ؛ _USERREPOSTORY.COMMIT () ؛ result.id = user.id ؛ النتيجة. نتيجة العودة } deleteresult deleteuser (int userId) {var result = getDefault <deleteresult> () ؛ var user = _userRepository.findsingle (x => x.id == userId) ؛ if (user! = null) {_userRepository.delete (user) ؛ _USERREPOSTORY.COMMIT () ؛ } result.isdeleted = true ؛ نتيجة العودة } updateustult updatepwd (userdto user) {var result = getDefault <UpdateResult> () ؛ var userentity = _userRepository.findsingle (x => x.id == user.id) ؛ if (userentity == null) {result.message = string.format ("المستخدم المعدل حاليًا" {0} "لم يعد موجودًا" ، user.name) ؛ نتيجة العودة } userentity.password = user.password ؛ _USERREPOSTORY.COMMIT () ؛ النتيجة. نتيجة العودة } getResult public <SerdDto> 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 = "******"} ؛ نتيجة العودة } تحديثات التحديثات العامة (المستخدم المستخدم) {var result = getDefault <UpdateResult> () ؛ 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 item في user.roles) {if (! list.exists (x => x.role.id == item.id)) {_userrolerepository.add (new userrole {initid.id ، userid = model.id}) ؛ }} foreach (var item في القائمة) {if (! user.roles.exists (x => x.id == item.id)) {_userrolerepository.delete (item) ؛ }} _userrolerepository.commit () ؛ _USERREPOSTORY.COMMIT () ؛ } result.issaved = true ؛ نتيجة العودة } deleteroled deleterole (int userId ، int rob) {var result = getDefault <deleteresult> () ؛ var model = _userrolerepository.findsingle (x => x.userId == userId && x.roleid == robleId) ؛ if (model! = null) {_userrolerepository.delete (model) ؛ _userrolerepository.commit () ؛ } result.isdeleted = true ؛ نتيجة العودة } BOLOL Public Bool (اسم مستخدم السلسلة ، كلمة مرور السلسلة) {return _userrepository.findsingle (u => U.Name == username && U.Password == password)! = null ؛ } bool private ishassamename (اسم السلسلة ، int userId) {return! string.isnullorwhitespace (name) && _userrepository.find (u => uthename == 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) ؛ استراحة؛ الحالة 1: FilterExp = user => user.name.contains (pageinput.name) ؛ استراحة؛ الحالة 2: FilterExp = user => user.email.contains (pageinput.name) ؛ استراحة؛ } return filterexp ؛ }}هنا ، يمكن في الواقع تحسين طبقة خدمة التطبيق ، وتنفيذ فصل القراءة والكتابة على مستوى الرمز ، وتحديد واجهة الخدمات الخاصة بـ iReadOnlyService وواجهة IWERITESERVIE ، وتجريد عمليات الكتابة في خدمة قواعد في شكل طرق عامة. مثل هذه الإضافة ، عمليات الحذف والتعديل هي عامة. السبب في أن هذه العملية يمكن نشرها هو أن هذه العمليات متشابهة للغاية ، وأنها ليست أكثر من الكيانات المختلفة للعمليات. في الواقع ، تم استخدام هذا التنفيذ في مشروع مفتوح المصدر آخر: Onlinestore. يمكنك الرجوع إلى هذا لتنفيذها بنفسك.
تنفيذ طبقة التخزين:
لا تعتمد خدمات تطبيقات المستخدم بشكل مباشر على فئات مستودعات محددة ، ولكنها تعتمد أيضًا على واجهاتهم. يتم تنفيذ فئة تخزين المستخدم المقابلة على النحو التالي:
Public Class BaseRepository <tentity>: iRepository <tentity> حيث الخيمة: الفصل ، ientity {private readonly threadlocal <SeRmanagerDbContext> _localctx = new threadlocal <EserManagerDbContex Public UserManagerDbContext dbContext {get {return _localctx.value ؛ }} tentity public findsingle (التعبير <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> find (expression <func <tentity ، bool >> التعبير ، التعبير <func <tentity ، dynamic >> sortpredicate ، sortorder sortorder ، int pagenumber ، int pagesize) {if (pagenumber <= 0) رمي الوسيطة الجديدة rrangeException ("pagenumber". إذا كان (pagesize <= 0) رمي ingumentOutoFrangeException ("pagesize" ، pagesize ، "يجب أن تكون pagesize كبيرة من أو تساوي 1.") ؛ var query = dbContext.set <tentity> (). حيث (التعبير) ؛ var skip = (pagenumber - 1) * pagesize ؛ var take = pagesize ؛ إذا كان (sortpredicate == null) رمي جديد invalidoperationException ("" بناءً على استعلام الترحيل ، يجب أن يحدد حقول الفرز وترتيب الفرز. ") ؛ Switch (sortorder) {case sortorder.ascending: var pagedascending = query.sortby (sortpredicate) .Skip (skip) .take (take) ؛ العودة pagedascending. case sortorder.descending: var pageddescending = query.sortbydescending (sortpredicate) .Skip (skip) .take (take) ؛ إرجاع pageddescing. } رمي جديد invalidoperationException ("بناءً على استعلام الترحيل يجب تحديد حقول الفرز وترتيب الفرز.") ؛ } public int getCount (التعبير <func <tentity ، bool >> exp = null) {return filter (exp) .count () ؛ } public void add (tentity unitity) {dbContext.set <tentity> (). add (intity) ؛ } تحديث الفراغ العام (كيان tentity) {dbContext.Entry (Entity) .State = entityState.modified ؛ } public void delete (tentity ictity) {dbContext.entry (intity) .State = entityState.Deleted ؛ dbContext.set <tentity> (). إزالة (الكيان) ؛ } حذف الفراغ العام (icollection <tentity> entityCollection) {if (entityCollection.count == 0) return ؛ dbContext.set <tentity> (). include (entityCollection.first ()) ؛ dbContext.set <tentity> (). Removerange (entityCollection) ؛ } filter iqueryable <tentity> خاص (التعبير <func <tentity ، bool >> exp) {var dbset = dbContext.set <tractity> (). asqueryable () ؛ if (exp! = null) dbset = dbset.where (exp) ؛ إرجاع DBSET ؛ } public void commun () {dbContext.Savechanges () ؛ }} الفئة العامة userrepository: baseRepository <Ser> ، iuserrepository {}4. تنفيذ الواجهة الأمامية AngularJS
إن تنفيذ الواجهة الأمامية على شبكة الإنترنت هو استخدام AngularJS لتنفيذها واعتماد نموذج تطوير وحدات. يوضح الشكل أدناه بنية التعليمات البرمجية المحددة للواجهة الأمامية على الويب:
تطبيق / صور // تخزين موارد الصورة المستخدمة من قبل تطبيق / أنماط / أنماط styles // المتجر ، التطبيق // ملفات البرامج النصية المستخدمة في نظام تخزين / وحدة تخزين وحدة تخزين وحدة تخزين / مرشحات وحدة تخزين وحدة تخزين وحدة تخزين / مرشحات module / apponge module / appression module / appression. التكوين) تطبيق/وحدات // مكتبة تبعية المشروع ، الزاوي ، bootstrap ، تطبيق مكتبة jQuery/views // AngularJS دليل تخزين القالب
إن مستوى الاتصال والواجهة الخلفية بين رموز تطبيقات الويب التي تم تطويرها باستخدام AngularJS هي في الأساس نفس الواجهة الخلفية ، وهي أيضًا صفحة العرض - وحدة التحكم - وحدة الخدمة - خدمة واجهة برمجة تطبيقات الويب.
بالإضافة إلى ذلك ، يعتمد تحميل موارد CSS و JS في شبكة الويب الأمامية طريقة الحزمة لتقليل عدد الموارد المطلوبة ، وبالتالي تسريع وقت تحميل الصفحة. تكوين فئة حزمة محددة:
الفئة العامة bundleconfig {// لمزيد من المعلومات حول bundling ، تفضل بزيارة http://go.microsoft.com/fwlink/؟linkid=301862 public static void regindbundles (bundleCollect "~/app/modules/jQuery-1.11.2.min.js" ، "~/app/modules/Angular/Angular.min.js" ، "~/app/modules/Angular/Angular-Route.min.js" ، "~/modules/bootstrap/js/uboottrap-tpls-0.1.3 "~/app/modules/bootstrap-notify/bootstrap-notify.min.js") ؛ // angularjs project project bundles.add (scriptbundle new ("~/JS/AngularJS/App"). "~/app/scripts/app.js") ؛ // bundles.add (new StyleBundle ("~/js/base/style"). }}الصفحة الرئيسية index.cshtml
<! doctype html> <html ng-app = "lh"> <head> <meta name = "viewport" content = "width = width device"/> <title> Simple System Management System Demo </title> @styles.render ("~/js/base/style") @scripts.render ( ng-controller = "sevigation"> <viv> <viv> <viv> <button type = "button" data-toggle = "collapse" data-arget = "#navbar" aria-expanded = "false" controls = "/a" </a span> </span> HREF = "/"> Simple SystemDemo SystemDemo </a> </viv> <viv> <ul> <li ng-repeat = "item in ls"> <a href = "#{item.urls [0] .link}}"> {{item.name}}} </a> href = "@url.action (" Unlogin "،" home "، null)"> {{lang.exit}} </a> </viv> </viv> </vic> <viv> <viv> <viv> <ul> <li ng-repeat = "item في urls"> <a href = "#{{item.link}}"> {{item.title}} </a> </li> </ul> </viv> <viv> <div ng-view5. تأثير التشغيل
بعد إدخال تنفيذ النهايات الأمامية والخلفية ، دعونا نلقي نظرة على تأثير تشغيل المشروع بأكمله:
6. ملخص
في هذه المرحلة ، تم تقديم جميع محتويات هذه المقالة ، على الرغم من أن مشروع تطبيق AngularJS في هذه المقالة لا يزال يحتوي على العديد من المجالات المثالية ، مثل عدم وجود دعم التخزين المؤقت ، ولا يوجد فصل القراءة والكتابة ، ولا اختبارات الإجهاد على بعض واجهات برمجة التطبيقات ، وما إلى ذلك. إذا كنت بحاجة إلى استخدام AngularJS في مشروعك ، وكانت الواجهة الخلفية لشركتك هي .NET ، أعتقد أن مشاركة هذه المقالة يمكن أن تكون مرجعًا جيدًا. بالإضافة إلى ذلك ، يمكنك أيضًا الرجوع إلى مشروعي المفتوح المصدر الآخر: Onlinestore و FastWorks لتصميم الهندسة المعمارية.
ما سبق هو طريقة استخدام AngularJS لإنشاء نظام إدارة إذن أدخله المحرر. آمل أن يكون ذلك مفيدًا للجميع!