• [.NET 三层架构(ADO.NET)+Web Service+多语言]WinForm三层架构重新实现TaskVision,外加WebService提供数据和多语言


    前言:                                                 

    关于不同框架实现同一个TaskVision:

    前面DebugLZQ先是用WPF(没有使用MVVM,因为前面使用MVVM实现过过点餐系统),因而这个关键点就放在了WPF的Binding上面;

    然后用普通的Winform,没有加入任何模式,实现了相同的功能。因此这个重点放在了DataGridView的总结,以及WinForm自定义控件实现类似WPF控件上面。

    本篇博文使用标准的三层架构,重新实现这个TaskVision。因而重点放在三层架构方面、为了体现三层的各层间低耦合的特点,博文下半部分会将DAL换成WebService,并实现多语言。数据库依然是原来的SQL Server 2008.

    标准的是这样的:                                         

    在软件体系设计中,分层式结构式最常见也是最重要的一种结构。MS推荐的分层结构一般分为三层,从上到下依次为UI、BLL、DAL。

    理解软件分层的概念有助于理解各种大量应用的模式结构,如MVC、MVVM等。以及GOF其他的一些等等。理解了三层,其他的理解起来会方便很多,因为其中贯通的都是:表现层的解耦。个人理解:模式间的区别是:根据具体的技术框架特点,决定表现层解耦方法的不同,由不断的最佳实践,总结出了各种不同的模式。即前面DebugLZQ也说的:表现层的持续解耦,带来的模式的转变!

    传统的三层式这样的:

    解释一下:UI层调用BLL层,传递的参数为UI层控件的属性值;BLL层调用DAL层,并加入相应的逻辑;DAL层则负责对数据库访问的封装(DAL层直接封装数据库访问,箭头所示)。

    我理解的规则

    1.UI层不包括任何BL;

    2.设计从BLL出发,而不是从UI出发,BLL实现所有的BL。

    3.DAL应该做到一定程度上与系统无关。即这一层可抽离。

    4.不可跨层调用;

    满足以上规则,就可以认为这个项目是三层了。

    (维基百科给出的)优点

      1、开发人员可以只关注整个结构中的其中某一层;
      2、可以很容易的用新的实现来替换原有层次的实现;
      3、可以降低层与层之间的依赖;
      4、有利于标准化;
      5、利于各层逻辑的复用。
      6、结构更加的明确
      7、在后期维护的时候,极大地降低了维护成本和维护时间
    (维基百科给出的)缺点
      1、降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。
      2、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码。
      3、增加了开发成本。
    关于引用百科的解释:确实是这样,不需要我去另外理解、解释。但是关于模式的理解是个人的。 

     实际是这样的                             

    实际使用中通常会
    1.加入Model。Model用来作为参数,在UI和BLL间传递。耦合度进一步降低!
    2.将DAL直接访问数据库改成调用其他数据库访问类库或服务,耦合度进一步降低!
    因此,针对DebugLZQ这个版本的TaskVison,你看到的所谓三层可能是这样的“5层”。如下:
    各层代码如下,以登陆为例:
    UI:Login.cs
    View Code
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using Models;
    
    namespace TaskVision_V2
    {
        public partial class Login : Form
        {
            public Login()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Models.UserLoginModel userLoginModel = new UserLoginModel() {  UserName=txtUserName.Text.Trim(), Password=txtPassword.Text, RememberPassword=checkBox1.Checked};
                if (BLL.UserService.Login(userLoginModel))
                {
                    //FormMain formMain = new FormMain();
                    //formMain.Show();
                    Global.userName = txtUserName.Text;
                    this.DialogResult = DialogResult.OK;
                }
                else
                {
                    MessageBox.Show("用户名或密码错误!");
                }            
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                this.Close();
            }
        }
    }

    Models:UserLoginModel.cs(叫UserModel更贴切,Model对应数据库表+判断逻辑控件value)

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Models
    {
        public class UserLoginModel
        {
            public string Id { get; set; }
            public string UserName { get; set; }
            public string Password { get; set; }
            public bool RememberPassword { get; set; }
        }
    }

    BLL:UserService.cs

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.SqlClient;
    using System.Data;
    
    namespace BLL
    {
        public class UserService
        {
            /// <summary>
            /// User Login
            /// </summary>
            private static string loginSQLText = "select * from tb_UserInfo where UserName=@UserName and Password=@Password";
            public static bool Login(Models.UserLoginModel userLoginModel)
            {
                if (userLoginModel.RememberPassword)
                {
                    //todo:
                }
                SqlParameter[] parameters = new SqlParameter[] { new SqlParameter("@UserName",userLoginModel.UserName),new SqlParameter("@Password",userLoginModel.Password)};
                return DAL.DataAccess.ExecuteReader(loginSQLText, parameters);
            }
            /// <summary>
            /// Get All User
            /// </summary>
            private static string getUserSQLText = "select distinct UserName from tb_UserInfo";
            public static DataTable GetUser()
            {
                return DAL.DataAccess.GetDataTable(getUserSQLText);
            }
        }
    }

    DAL:DataAccess.cs

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    using System.Data.SqlClient;
    
    namespace DAL
    {
        public static class DataAccess
        {
            public static DataTable GetDataTable(string sqlText, params SqlParameter[] parameters)
            {
                return AdoDotNetClassLibrary.SQLHelper.GetDataTable(sqlText, parameters);
            }
    
            public static int ExecuteNonQuery(string sqlText,params SqlParameter[] parameters)
            {
                return AdoDotNetClassLibrary.SQLHelper.ExecuteNonQuery(sqlText,parameters);
            }
    
            public static bool ExecuteReader(string sqlText, SqlParameter[] parameters)
            {
                return AdoDotNetClassLibrary.SQLHelper.ExecuteReader(sqlText, parameters);
            }       
        }
    }

    AdoDotNetClassLibrary:SQLHelper.cs

    using System.Data;
    using System.Data.SqlClient;
    
    namespace AdoDotNetClassLibrary
    {
        public static class SQLHelper
        {
            public const string connectionString = @"server=LocalHost;database=TaskVision;Trusted_Connection=SSPI";
    
            public static DataTable GetDataTable(string sqlText,params SqlParameter[] parameters)
            {
                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    SqlDataAdapter sda = new SqlDataAdapter(sqlText, conn);
                    foreach (SqlParameter parameter in parameters)
                    {
                        sda.SelectCommand.Parameters.Add(parameter);
                    }
                    DataTable dt = new DataTable();
                    sda.Fill(dt);
    
                    return dt;
                }
            }
    
            public static int ExecuteNonQuery(string sqlText,params SqlParameter[] parameters)
            {
                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    SqlCommand cmd = new SqlCommand(sqlText, conn);
                    foreach (SqlParameter parameter in parameters)
                    {
                        cmd.Parameters.Add(parameter);
                    }
                    conn.Open();
                    int temp = cmd.ExecuteNonQuery();
                    return temp;
                }
            }
    
            public static bool ExecuteReader(string sqlText, params SqlParameter[] parameters)
            {
                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    conn.Open();
                    SqlCommand cmd = new SqlCommand(sqlText, conn);
                    foreach (SqlParameter parameter in parameters)
                    {
                        cmd.Parameters.Add(parameter);
                    }
                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.Read())
                            return true;
                        return false;
                    }
                }
            }
    
        }
    }
    View Code

    数据由Webservice提供                   

    注意点:

    由于webservice序列化问题,SqlParameter不能直接传递,因此改用strng代替下;

    http://forums.asp.net/t/1335298.aspx!需要为DataTable设置名称,dt.TableName="myTable";

    需要将DAL引用webservice生成的config文件拷贝到UI工程中(注意:不是webservice项目的config)。否则会报告无法找到EndPoint运行时错误。

    由此只要:

    添加:AdoDotNetWebService--service1.asmx 

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Data;
    using System.Data.SqlClient;
    using System.Collections;
    
    namespace AdoDotNetWebService
    {
        /// <summary>
        /// Summary description for Service1
        /// </summary>
        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [System.ComponentModel.ToolboxItem(false)]
        // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
        // [System.Web.Script.Services.ScriptService]
        public class Service1 : System.Web.Services.WebService
        {
    
            [WebMethod]
            public string HelloWorld()
            {
                return "Hello World";
            }        
            public const string connectionString = @"server=LocalHost;database=TaskVision;Trusted_Connection=SSPI";
          
    
            [WebMethod]
            public DataTable GetDataTable(string sqlText, params string[] parameters)
            {
                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    SqlDataAdapter sda = new SqlDataAdapter(sqlText, conn);
                    for(int i=0;i<parameters.Length;i=i+2)
                    {
                        sda.SelectCommand.Parameters.Add(new SqlParameter(parameters[i],parameters[i+1]));
                    }
                    DataTable dt = new DataTable();
                    dt.TableName = "MyTable";//OMG!
                    sda.Fill(dt);
    
                    return dt;
                }
            }
    
            [WebMethod]
            public int ExecuteNonQuery(string sqlText, params string[] parameters)
            {
                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    SqlCommand cmd = new SqlCommand(sqlText, conn);
                    for (int i = 0; i < parameters.Length; i = i + 2)
                    {
                        cmd.Parameters.Add(new SqlParameter(parameters[i],parameters[i+1]));
                    }
                    conn.Open();
                    int temp = cmd.ExecuteNonQuery();
                    return temp;
                }
            }
    
    
    
            [WebMethod]
            public bool ExecuteReader(string sqlText, params string[] parameters)
            {
                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    conn.Open();
                    SqlCommand cmd = new SqlCommand(sqlText, conn);
                    for (int i = 0; i < parameters.Length; i = i + 2)
                    {
                        cmd.Parameters.Add(new SqlParameter(parameters[i], parameters[i + 1]));
                    }
                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.Read())
                            return true;
                        return false;
                    }
                }
            }
        }
    }

    修改DAL:

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    using System.Data.SqlClient;
    using System.Collections;
    
    namespace DAL
    {
        public static class DataAccess
        {
            //webserviceclient
            public static ServiceReference1.Service1SoapClient client = new ServiceReference1.Service1SoapClient();
    
            public static DataTable GetDataTable(string sqlText, params SqlParameter[] parameters)
            {
                //return AdoDotNetClassLibrary.SQLHelper.GetDataTable(sqlText, parameters);
                ArrayList ps = new ArrayList();
                for (int i = 0; i < parameters.Length; i++)
                {
                    ps.Add(parameters[i].ParameterName);
                    ps.Add(parameters[i].Value);
                }
                string[] ps1 = (string[])ps.ToArray(typeof(string));
                return client.GetDataTable(sqlText, ps1);
            }
    
            public static int ExecuteNonQuery(string sqlText, params SqlParameter[] parameters)
            {
                //return AdoDotNetClassLibrary.SQLHelper.ExecuteNonQuery(sqlText,parameters);
    
                ArrayList ps = new ArrayList();
                for (int i = 0; i < parameters.Length; i++)
                {
                    ps.Add(parameters[i].ParameterName);
                    ps.Add(parameters[i].Value);
                }
                string[] ps1 = (string[])ps.ToArray(typeof(string));
                return client.ExecuteNonQuery(sqlText, ps1);
            }
    
    
    
            public static bool ExecuteReader(string sqlText, params SqlParameter[] parameters)
            {
                //return AdoDotNetClassLibrary.SQLHelper.ExecuteReader(sqlText, parameters);
    
                ArrayList ps = new ArrayList();
                for (int i = 0; i < parameters.Length; i++)
                {
                    ps.Add(parameters[i].ParameterName);
                    ps.Add(parameters[i].Value);
                }
                string[] ps1 = (string[])ps.ToArray(typeof(string));
    
                return client.ExecuteReader(sqlText, ps1);
            }
        }
    }

    其他层保持不变!

     实现多语言                           

     非常简单。步骤如下:

    1.设置Form的Localizable属性为True。
    2.为每个Form添加对应的资源文件,命名有要求:以Login.cs窗体为例,资源名为Login.en.resx/Login.zh-CHS.resx(需要查阅具体语言的代码)。添加完成后VS自动将该资源文件添加到对应的窗体下。
    3.编辑添加的资源文件,注意:不同String类型资源文件的Name在不同的resx中必须相同。目的是为了保证编码方便。
    4.在Form_Load中根据CurrentUICulture为 Form的控件Text赋值(是用的是resx中string的Name,赋的是Value)

    以Login为例。

    1.设置Localizable属性为True。

    2.添加资源文件:

    添加代码:

    View Code
            private void Login_Load(object sender, EventArgs e)
            {
                Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");
                UpDataMainFormUILanguage();           
            }
    
            private void UpDataMainFormUILanguage()
            {
                ResourceManager rm = new ResourceManager(typeof(Login));
                UpdateLoginUILanguage(rm);
            }
    
            private void UpdateLoginUILanguage(ResourceManager rm)
            {
                this.Text = rm.GetString("Login");
                lblUserName.Text = rm.GetString("UserName");
                lblPassword.Text = rm.GetString("Password");
                checkBox1.Text = rm.GetString("RememberPassword");
                btnLogin.Text = rm.GetString("Login");
                btnCancel.Text = rm.GetString("Cancel");
            }

    效果如下:

    小结:     

    博文重点在于说明三层架构:UI层构建Model,传递给BLL层,BLL层利用UI层传过来的Model的属性作为参数调用DAL层,DAL层是对具体数据库访问方式的封装,真正的数据库访问则由具体的类库、服务等提供。关于三层架构也许很多人的理解都可能不够标准,我是这么认为的。附加介绍了WebService作为数据库提供程序的方法,需要注意的地方。以及实现多语言的一种参考方法。

     感触:  

    Baidu不靠谱!多问Google、多用英文问问题! 

  • 相关阅读:
    (4)ES6解构赋值-字符串篇
    (3)ES6解构赋值-对象篇
    (2)ES6解构赋值-数组篇
    (1)ES6中let,const,对象冻结,跨模块常量,新增的全局对象介绍
    MySQL中char与varchar区别,varchar最大长度是多少?
    集成学习实战——Boosting(GBDT,Adaboost,XGBoost)
    集成学习——Boosting(GBDT,Adaboost,XGBoost)
    集成学习(Random Forest)——实践
    集成学习——Bagging
    决策树实践
  • 原文地址:https://www.cnblogs.com/DebugLZQ/p/3050389.html
Copyright © 2020-2023  润新知