背景

    到TL有整整一年了,在这一年中公司从无到有,完成了两个自动化系统整合项目,老板一直强调模块化设计这个理念,可是由于团队基础实在是薄弱,很多规范没办法执行起来,以致于这两个项目的源码惨不忍睹,代码写得很乱,可以重复利用的模块实在是太少。所以今年我主要的精力投在软件开发规范化这一块,以系统可扩展,模块化,可复用性为原则。

    虽然自已技术还是个小菜,但只要有思想就应该是简单的问题,那么我从一个“用户登录模块”设计开始,把这个模块抽离出来,让所有子系统都能够复用这个登录组件,并且降低模块与主框架之间耦合。

    在制造业的系统架构中,一般分为好几个工作站,每个工作站都有一个子系统,每个子系统都有需要有用户登录权限控制,所以这就意味着每个子系统都要开发这个模块,如果子系统比较多,这样开发成本就比较高,重复代码也很多,我分析了一下,这个用户登录模块有如下特点:

      • 有统一的界面风格
      • 模块根据用户权限不同加载对应的系统子系统
      • 模块标题不一样

    我们如何设计达到组件可以重复利用?

    1. 复用性:让所有子系统都能够重复利用这个用户登录
    2. 易用性:通过配置文件根据不同的子系统设置不一样的系统标题,子系统主框架调用组件简单化
    3. 我后台做一个WCF服务作为用户权限逻辑处理,登录组件直接调这个服务,把用户登录逻辑处理层从系统框架主分离出来成一个独立模块,子模块只需要引入这个组 件,做相应的配置,调用用户验证接口,当登录成功时,组件内部会消息通知主框架(订阅消息)进行启动加载主界面,从而达到成功登录的目的。

    设计思想

    image

    设计步骤

    1.设计WCF Service作后台用户登录验证处理

    using System.ServiceModel;
    using Xiaocai.Security.IDAL;
    
    namespace Xiaocai.Commons
    {
        // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IUserService" in both code and config file together.
        [ServiceContract]
        public interface ILoginService
        {
            [OperationContract]
            AuthUser CheckUser(string userId, string password);
        }
    }

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    using Xiaocai.Commons;
    using Xiaocai.Security.Core.Admin;
    using Xiaocai.Security.Core.Helpers;
    using Xiaocai.Security.IDAL;
    
    namespace Xiaocai.SystemHelper.Services
    {
        // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "UserService" in code, svc and config file together.
        public class LoginService : ILoginService
        {
            private AuthController _controller;
            public LoginService()
            {
                _controller=new AuthController();
            }
            public AuthUser CheckUser(string userId, string password)
            {
                AuthUser authUser=null;
                bool result=_controller.Login(userId, password);
                if (result)
                {
                    authUser = _controller.AuthUser;
                }
                return authUser;
            }
        }
    }

    我主要总结原理,很多细节就不多写了,所以服务中的验证我封装在另一组件中,此处省略。

    2.发布这个WCF服务到IIS服务器中,测试如一下是否发布成功,出现如下页面表示已成功:

    image

     

     

    3.调用服务客户端

    using System;
    using System.ServiceModel;
    using Xiaocai.Commons;
    using Xiaocai.Security.IDAL;
    
    namespace Xiaocai.SystemHelper.Proxy
    {
        public class LoginHelper
        {
            public static AuthUser OnLogin(string userId,string password)
            {
                AuthUser authUser = null;
                using (ChannelFactory<ILoginService> channelFactory = new ChannelFactory<ILoginService>("userService"))
                {
                    ILoginService proxy = channelFactory.CreateChannel();
                    using (proxy as IDisposable)
                    {
                        authUser = proxy.CheckUser(userId, password);
                        return authUser;
                    }
                }
            }
        }
    }

     

    4.新建一Winform项目作为登录组件,命名为Xiaocai.SecurityControlLibaray,把项目输出类型改为类库,以便子系统主框引入调用。

    /******************************************************************************
    * This document is the property of ShangHai TLian Agent Technology Co., Ltd. (TLAgent).
    * No exploitation or transfer of any information contained herein is permitted 
    * in the absence of an agreement with Xiaocai
    * and neither the document nor any such information
    * may be released without the written consent of Xiaocai
    *  
    * All right reserved by Xiaocai  
    *******************************************************************************
    * Owner: Agan
    * Version: 1.0.0.0
    * Component:for login function
    * Function Description:*
    * Revision / History
    *------------------------------------------------------------------------------
    * Flag     Date     Who             Changes Description
    * -------- -------- --------------- -------------------------------------------
    *   1       20130715 Agan           File created
    
    *------------------------------------------------------------------------------
    */
    
    using System;
    using System.Configuration;
    using System.Windows.Forms;
    using Xiaocai.Commons;
    using Xiaocai.Security.IDAL;
    using Xiaocai.SystemHelper.Proxy;
    namespace Xiaocai.SecurityControlLibaray
    {
        public partial class LoginForm : Form
        {
            public LoginForm()
            {
                InitializeComponent();
            }
    
            public virtual string Title { get; set; }
    
            private void LoginForm_Load(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(ConfigurationManager.AppSettings["Title"]))
                {
                    prgTitle.Text = string.Format("{0}", Title);
                }
                else
                {
                    prgTitle.Text = string.Format("{0}", ConfigurationManager.AppSettings["Title"]);
                }
             
                txtUserId.Select();
            }
    
            private void OnLogin(object sender, EventArgs e)
            {
                string userId = txtUserId.Text.Trim();
                string password = txtPassWord.Text.Trim();
                if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(password))
                {
                    if (string.IsNullOrEmpty(userId))
                    {
                        MessageHelper.ShowError("用户名不能为空!");
                        txtUserId.Focus();
                        txtUserId.SelectAll();
                        return;
                    }
                    if (string.IsNullOrEmpty(password))
                    {
                        MessageHelper.ShowError(@"密码不能为空!");
                        txtUserId.Focus();
                        txtUserId.SelectAll();
                        return;
                    }
                   
                    txtUserId.Focus();
                    txtUserId.SelectAll();
                    return;
                }
    
                AuthUser authUser = LoginHelper.OnLogin(userId, password);
                if (authUser!=null)
                {
                    this.Hide();
                    EventService.Publish(authUser);//用户验证成功,发布消息,把登录用户传送出去
                    Application.ThreadException += Application_ThreadException;
                }
                else
                {
                    MessageHelper.ShowError("用户名或密码不正确,请联系管理员!");
                    txtUserId.Focus();
                    txtUserId.SelectAll();
                }
            }
    
            private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs ex)
            {
                string message = string.Format("{0}\r\n操作发生错误,您需要退出系统么?", ex.Exception.Message);
                MessageBox.Show(message);
                Application.Exit();
            }
    
            private void OnCancel(object sender, EventArgs e)
            {
                Application.Exit();
            }
    
    
            private void txtPassWord_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Enter)
                {
                    OnLogin(sender,e);
                }
            }
    
            private void txtUserId_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Enter)
                {
                    txtPassWord.Focus();
                }
            }
        }
    }

     

    6.系统子框架调用

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Forms;
    using TLAgent.Commons;
    using TLAgent.Security.Core;
    using TLAgent.Security.IDAL;
    using TLAgent.SecurityControlLibaray;
    
    namespace TLAgent.Assembling.SecurityManager
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                AppCore.Startup();
                //Application.Run(new LoginForm());
                OnLonin();
            }
    
            private static void OnLonin()
            {
                //订阅消息
                EventAggregatorRepository.EventAggregator
          .GetEvent<ReceiveObjectEvent>()
          .Subscribe(SuccessLogin);
                Application.Run(new LoginForm());
            }
            /// <summary>
            /// 登录成功加载主窗体
            /// </summary>
            /// <param name="objParam">用户实体对象</param>
            private static void SuccessLogin(object objParam)
            {
                SecurityControlLibaray.SplashScreen.Splasher.Show(typeof(SplasherForm));
                MainForm form = new MainForm();
                var user = objParam as AuthUser;
                if (user != null)
                {
                    form.AuthUser = user;
                }
                form.StartPosition = FormStartPosition.CenterScreen;
                form.ShowDialog();
            }
        }
    }

     

    7.配置文件中设置,如下:

    <?xml version="1.0"?>
    <configuration>
      <!--WCF服务配置文件-->
      <system.serviceModel>
        <client>
          <endpoint address="http://localhost/SystemServices/LoginService.svc" binding="basicHttpBinding" contract="Xiaocai.Commons.ILoginService" name="userService"/>
        </client>
      </system.serviceModel>
      
      <appSettings>
        <add key="Title" value="用户权限管理系统"/><!--系统标题设置-->
        <add key="Copyright" value=" 版权所有:小菜成長記"/><!--系统版权设置-->
          <!-- Database with WebService -->
        <add key="IsRemote" value="N"/>
        <add key="GlobalSessionFactory" value="Xiaocai.Security.DAL.Global.SQLServerSessionFactory,Xiaocai.Security.DAL.Global"/>
    
        <!-- Database without WCFService -->
    
        <add key="Database.SqlServerConn" value="Data Source=localhost,1433;Network Library=DBMSSOCN;Initial Catalog=SecurityDB;User ID=root;Password=12345;"/>
      </appSettings>
    </configuration>

    运行子系统,显示如下:

    image

    这个标题可以根据不同子系统功能在配置文件中作对应设置,到此基本完成这个登录组件的设计,这个组件可以用于所有子系统的登录界面,多次重复利用,减少开发成本。

    附:因本人技术有限,也许会有更好的方法做这个模块化设计,希望高人指点,在不断学习中进步。

    posted on 2013-09-20 02:01  aganqin  阅读(3092)  评论(2编辑  收藏  举报