复用性登录组件

背景:

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

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

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

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

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

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

设计思想

复用性登录组件_第1张图片

设计步骤

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服务器中,测试如一下是否发布成功,出现如下页面表示已成功:

复用性登录组件_第2张图片

 

 

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>
复制代码

运行子系统,显示如下:

复用性登录组件_第3张图片

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

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

 
 
分类:  系统框架设计
标签:  系统框架设计

你可能感兴趣的:(系统框架设计)