How to Use AngularJs to create a permission management system [simple] And angularjs Management System
I. Introduction
This article describes how to apply AngularJs to a real project. This article uses AngularJS to create a simple permission management system. Let's not talk about it below. Go directly to the topic.
II. Introduction to the overall architecture design
First, let's take a look at the architectural design of the entire project:
We can see the overall structure of the entire project. Next, I will introduce the overall architecture of the project in detail:
Use Asp.net Web APIs to implement REST services. This implementation method has reached the public, separately deployed, and better extended backend services. The Web layer depends on the Application Service Interface and uses Castle Windsor to implement dependency injection.
Display layer (User UI)
The display layer uses AngularJS to implement SPA pages. All page data is asynchronously loaded and refreshed locally. This will provide a better user experience.
Application Service)
AngularJS uses the Http service to request Web APIs to obtain data, while the Web API is implemented by calling the application layer to request data.
Infrastructure Layer
The infrastructure layer includes the implementation of warehousing and some public methods.
The implementation of the warehousing layer is implemented by EF Code First, and EF Migration is used to create and update databases.
The LH. Common layer implements some Common methods, such as log help classes and Expression Tree extensions.
Domain Layer
The domain layer mainly implements all the Domain Models of the project, including the implementation of the domain model and the definition of the warehousing interface.
In addition to the complete body structure, we will introduce the backend service implementation and Web Front-end Implementation of the project respectively.
Iii. backend service implementation
Backend services mainly use Asp.net Web APIs to implement backend services and use Castle Windsor to complete dependency injection.
Here, we use user management in permission management to introduce the implementation of Rest Web API service.
Implement the REST service that provides user data:
public class 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([FromBody] UserDto userDto) { return _userService.UpdateUser(userDto); } [HttpPost] [Route("api/user/UpdateRoles")] public OutputBase UpdateRoles([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}")] public OutputBase DeleteRole(int id, int roleId) { return _userService.DeleteRole(id, roleId); } }
The code above shows that the User REST service depends on the IUserService interface, and does not put all the business logic in the Web API implementation in the traditional way, instead, it encapsulates specific business implementations into the corresponding application layer. Rest APIs are only responsible for calling services in the corresponding application layer. The benefits of this design are:
The REST Service Department depends on the application-layer interface to separate responsibilities. The instantiation of the application-layer service is handed over to a separate dependency injection container. The REST service is only responsible for calling the method of the corresponding application service to obtain data. This method relies on interfaces and does not rely on the implementation of specific classes, so that classes and classes are low-coupling. The REST service does not include specific business logic implementations. This design can enable better separation of services. If you want to use WCF to implement REST services in the future, in this way, you do not need to repeat the logic of a Web API in the wcf rest service class. At this time, you can call the interface method of the Application Service to implement the wcf rest service. Therefore, the implementation of business logic is implemented at the application service layer. This design makes the REST service more uniform, and the REST service implementation is easier to expand.
Implementation of user application services:
Public class UserService: BaseService, IUserService {private readonly metadata _ userRepository; private readonly metadata _ metadata; public UserService (metadata userRepository, role userRoleRepository) {_ userRepository = userRepository; _ userRoleRepository = userRoleRepository;} 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, Re AlName = user. realName, Password = "*******", Roles = user. userRoles. take (4 ). select (z => new BaseEntityDto () {Id = z. role. id, Name = z. role. roleName }). toList (), TotalRole = user. userRoles. count ()}). toList (); return result;} public UpdateResult UpdateUser (UserDto user) {var result = GetDefault <UpdateResult> (); var existUser = _ userRepository. findSingle (u => u. id = user. id); if (existUser = n Ull) {result. message = "USER_NOT_EXIST"; result. stateCode = 0x00303; return result;} if (IsHasSameName (existUser. name, existUser. id) {result. message = "USER_NAME_HAS_EXIST"; result. stateCode = 0x00302; return result;} existUser. realName = user. realName; existUser. name = user. name; existUser. state = user. state; existUser. email = user. email; _ userRepository. update (existUser); _ userRepository. co Mmit (); result. isSaved = true; return result;} public CreateResult <int> AddUser (UserDto userDto) {var result = GetDefault <CreateResult <int> (); if (IsHasSameName (userDto. name, userDto. id) {result. message = "USER_NAME_HAS_EXIST"; result. stateCode = 0x00302; return result;} var user = new User () {CreationTime = DateTime. now, Password = "", Email = userDto. email, State = userDto. state, RealName = UserDto. realName, Name = userDto. name}; _ userRepository. add (user); _ userRepository. commit (); result. id = user. id; result. isCreated = true; return result;} public DeleteResult 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; return result;} public UpdateResult UpdatePwd (UserDto user) {var result = GetDefault <UpdateResult> (); var userEntity = _ userRepository. findSingle (x => x. id = user. id); if (userEntity = null) {result. message = string. format ("the currently edited user" {0} "does not exist", user. name); return result;} userEntity. password = user. pass Word; _ userRepository. commit (); result. isSaved = true; return result;} 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; return result;} result. data = new UserDto () {CreateTime = model. creationTime, Email = m Odel. email, Id = model. id, RealName = model. realName, State = model. state, Name = model. name, Password = "********"}; return result;} public UpdateResult UpdateRoles (UserDto user) {var result = GetDefault <UpdateResult> (); var model = _ userRepository. findSingle (x => x. id = user. id); if (model = null) {result. message = "USE_NOT_EXIST"; result. stateCode = 0x00402; return result;} var list = mod El. UserRoles. ToList (); if (user. Roles! = Null) {foreach (var item in user. Roles) {if (! List. exists (x => x. role. id = item. id) {_ userRoleRepository. add (new UserRole {RoleId = item. id, UserId = model. id}) ;}} foreach (var item in list) {if (! User. roles. exists (x => x. id = item. id) {_ userRoleRepository. delete (item) ;}}_ userRoleRepository. commit (); _ userRepository. commit ();} result. isSaved = true; return result;} public DeleteResult DeleteRole (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; return result;} public bool Exist (string username, string password) {return _ userRepository. findSingle (u => u. name = username & u. password = password )! = Null;} private bool IsHasSameName (string name, int userId) {return! String. IsNullOrWhiteSpace (name) & _ userRepository. Find (u => u. Name = name & u. Id! = UserId ). any ();} private Expression <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); break; case 1: filterExp = user => user. name. contains (pageInput. name); break; case 2: filterExp = user => user. email. contains (pageInput. name); break;} return filterExp ;}}
Here, the application service layer can be further optimized to implement code-level read/write splitting and define the IReadOnlyService interface and IWriteServie interface, in addition, write operations can be abstracted into BaseService using the generic method. In this way, some add, delete, modify, and delete operations can be shared because these operations are very similar, except that the Operation Entities are different. In fact, this implementation has already been used in another open-source project: OnlineStore. You can refer to this for your own implementation.
Implementation of the warehousing layer:
The user's application service does not directly depend on the specific storage class, but also depends on its interface. The implementation of the corresponding user storage class is as follows:
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity :class , IEntity { private readonly ThreadLocal<UserManagerDBContext> _localCtx = new ThreadLocal<UserManagerDBContext>(() => new UserManagerDBContext()); public UserManagerDBContext DbContext { get { return _localCtx.Value; } } public TEntity FindSingle(Expression<Func<TEntity, bool>> exp = null) { return DbContext.Set<TEntity>().AsNoTracking().FirstOrDefault(exp); } public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> exp = null) { return Filter(exp); } public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize) { if (pageNumber <= 0) throw new ArgumentOutOfRangeException("pageNumber", pageNumber, "pageNumber must great than or equal to 1."); if (pageSize <= 0) throw new ArgumentOutOfRangeException("pageSize", pageSize, "pageSize must great than or equal to 1."); var query = DbContext.Set<TEntity>().Where(expression); var skip = (pageNumber - 1) * pageSize; var take = pageSize; if (sortPredicate == null) throw new InvalidOperationException("Based on the paging query must specify sorting fields and sort order."); switch (sortOrder) { case SortOrder.Ascending: var pagedAscending = query.SortBy(sortPredicate).Skip(skip).Take(take); return pagedAscending; case SortOrder.Descending: var pagedDescending = query.SortByDescending(sortPredicate).Skip(skip).Take(take); return pagedDescending; } throw new InvalidOperationException("Based on the paging query must specify sorting fields and sort order."); } 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>().Remove(entity); } public void Delete(ICollection<TEntity> entityCollection) { if(entityCollection.Count ==0) return; DbContext.Set<TEntity>().Attach(entityCollection.First()); DbContext.Set<TEntity>().RemoveRange(entityCollection); } private IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> exp) { var dbSet = DbContext.Set<TEntity>().AsQueryable(); if (exp != null) dbSet = dbSet.Where(exp); return dbSet; } public void Commit() { DbContext.SaveChanges(); } }public class UserRepository :BaseRepository<User>, IUserRepository { }
Iv. AngularJS front-end implementation
The implementation of Web Front-end is implemented using AngularJS and modular development mode. Shows the code structure of the Web Front-end:
App/images // store the image resources used by the Web Front-end App/Styles // store the Style File App/scripts // store the script file used by the Web Front-end/Controllers // angularJS Controller Module directory/directives // angularJs Command Module Directory/filters // Filter Module Directory/services // Service Module Directory/app. js // Web Front-End program configuration module (route configuration) App/Modules // project dependency library, directory for storing angular, Bootstrap, and Jquery library App/Views // AngularJs view templates
The Calling levels of Web application code developed using AngularJS are basically the same as those of the backend. It is also the view page, controller module, service module, and Web API service.
In addition, the Web Front-end CSS and JS resources are loaded in Bundle mode to reduce the number of requests for resources, thus accelerating the page loading time. Configuration of Bundle classes:
Public class BundleConfig {// For more information on bundling, visit http://go.microsoft.com/fwlink? LinkId = 301862 public static void RegisterBundles (BundleCollection bundles) {// library dependency file bundles. Add (new ScriptBundle ("~ /Js/base/lib "). Include ("~ /App/modules/jquery-1.11.2.min.js ","~ /App/modules/angular. min. js ","~ /App/modules/angular/angular-route.min.js ","~ /App/modules/bootstrap/js/ui-bootstrap-tpls-0.13.0.min.js ","~ /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/directives/*. js ","~ /App/scripts/filters/*. 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>
V. Running Effect
After introducing the implementation of the front and back ends, let's take a look at the running effect of the entire project:
Vi. Summary
At this point, all the content in this article has been introduced. Although AngularJS application projects in this article still have many improvements, such as no buffer support or read/write splitting, no stress tests were performed on Some APIs. However, the application of AngularJS in actual projects is basically like this. If you need AngularJS in the project, your company's background is exactly the same. NET, I believe this article can be a good reference. In addition, for architecture design, refer to another open-source project: OnlineStore and FastWorks.
The above section describes how to use AngularJs to create a permission management system. I hope it will help you!