WCF的登录服务+WPF登录窗体实现


现将一个基于WCF的分布式程序的登录实现( 源码下载)描述如下:

1.部署需求

  • 数据库部署在一台专用服务器上,要实现数据和服务的远程调用.
  • 客户端与服务器不属于同一计算机.
    基于以上要求,考虑到以后便于扩展,考虑使用 WCF 技术实现程序的分布式开发.

2.登录界面

在这里插入图片描述

3.服务搭建

在这里插入图片描述
解决方案目前考虑6个项目.其中和服务相关的3个项目.

3.1 JIS.IService 项目

主要定义各种服务契约.该项目主要是一些接口.通过定义 [ServiceContract] [OperationContract]特性,指定服务契约和契约方法.

如:登录服务中,需要首先为界面用户提供用户数据,和进行登录方法

namespace JIS.IService
{
    [ServiceContract]
    public interface ILoginService
    {
        [OperationContract]
        bool Login(string loginName, string pwd);
        [OperationContract]
        List<User> GetUsers();
    }
}

3.2 JIS.Service 项目

该项目为服务契约提供服务实现

using JIS.IService;
using JIS.Utilities.DBComm;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JIS.Model;
using System.Configuration;

namespace JIS.Service
{
    /// <summary>
    /// 登陆服务
    /// </summary>
    public class LoginService : System.MarshalByRefObject, ILoginService
    {
        public LoginService()
        {
            //从配置文件中读取数据库连接字符串
            Database.SqlConStr = ConfigurationManager.ConnectionStrings["SqlConStr"].ConnectionString;
        }

        public List<User> GetUsers()
        {
            string sql = "select * from UserTb";
            DataTable table = Database.ExecSqlReturnDataTable(sql);
            List<User> userList = new List<User>();
            foreach (DataRow row in table.Rows)
            {
                var user = new User();
                user.LoginName = row["LoginName"].ToString();
                user.UserName = row["UserName"].ToString();
                user.PassWord = row["PassWord"].ToString();
                userList.Add(user);
            }
            return userList;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="loginName"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public bool Login(string loginName, string pwd)
        {
            string sql = "select * from UserTb where LoginName=@user and Password=@pwd";
            SqlParameter[] ps = {
                new SqlParameter("@user",loginName),
                new SqlParameter("@pwd",pwd)
            };

            DataTable table = Database.ExecSqlReturnDataTable(sql, ps);
            return table.Rows.Count>0;
        }
    }
}

3.3 JIS.Host 项目

主要是为服务提供主机服务,是服务的宿主程序.这里用控制台简单实现.

step 1:配置服务

App.config配置最顺手配置如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>

<
  <connectionStrings>
    <add name="SqlConStr" connectionString=".\DY;uid=sa;pwd=888;database=RMSDb"/>
  </connectionStrings>

  <system.serviceModel>
    <services>
      <service name="JIS.Service.LoginService" behaviorConfiguration="MyTypeBehaviors">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8001/LoginService"/>
          </baseAddresses>
        </host>
        <!-- 终结点 -->
        <endpoint address="" binding="basicHttpBinding" contract="JIS.IService.ILoginService" ></endpoint>
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="MyTypeBehaviors" >
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>

</configuration>

具体对应关系见下图
在这里插入图片描述

step 2:宿主程序

详见Main方法

using System;
using System.Collections.Generic;
using System.ServiceModel;

namespace JISHost
{
    class Program
    {
        static void Main(string[] args)
        {
            //创建提供服务的主机
            ServiceHost host = new ServiceHost(typeof(JIS.Service.LoginService));
            host.Open();

            //读取服务基地址
            IReadOnlyCollection<Uri> uris = host.BaseAddresses;
            foreach (var u in uris)
            {
                Console.WriteLine($"{u.AbsoluteUri}  服务已经启动....");
            }
            Console.Read();
        }
    }
}

step 3:运行服务

生成Hosts项目,将生成如下文件,以管理员身份运行JISHost.exe,将启动服务
在这里插入图片描述

在这里插入图片描述

这时,如果在浏览器地址栏中输入http://localhost:8001/LoginService ,将显示如下信息,这里也给出了客户端调用服务的方法.
在这里插入图片描述

4. 客户端Client实现

在这里插入图片描述
基本框架流程就如上述所现.

6.WPF客户端登录实现

建立JIS.Client项目,主要代码如下:

6.1 App.xaml.cs

 public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            // base.OnStartup(e);
            WLogin wLogin = new WLogin();
            var s = wLogin.ShowDialog();
        }
    }

6.1 登录窗体WLogin.xaml

//WLogin.xaml
<local:BaseWindow x:Class="JIS.Views.WLogin"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:JIS.Views"
        xmlns:vm="clr-namespace:JIS.ViewModels"
        mc:Ignorable="d"
        Title="登录" Height="300" Width="400" WindowStyle="ToolWindow" 
                  WindowStartupLocation="CenterScreen"  Background="#FFF6F6F6"   ResizeMode="NoResize">

    
    <StackPanel Margin="5">
        <Image Grid.Row="0" Grid.ColumnSpan="4" Source="/JIS;component/Resources/Images/Login_Top.png" Margin="20 5 20 0"></Image>
        <GroupBox Margin="20 5 20 5" Header="登录"
                  BorderBrush="OliveDrab" BorderThickness="1" 
                  FocusManager.FocusedElement="{Binding ElementName=pwd}"     >
            <Grid Width="200">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <Label Grid.Row="0"    >用户(U):</Label>
                <Label Grid.Row="1"    >密码(P):</Label>
                <ComboBox  Grid.Row="0" Grid.Column="1" Margin="4"  
                           ItemsSource="{Binding UserList}" 
                           DisplayMemberPath="UserName"
                           SelectedValuePath="LoginName"
                           SelectedIndex="0"
                           SelectedItem="{Binding SelectedUserItem,Mode=OneWayToSource}"
                           
                           HorizontalContentAlignment="Center"
                           VerticalContentAlignment="Center" />

                <PasswordBox x:Name="pwd"  Grid.Row="1" Grid.Column="1" Margin="4"
                             local:PasswordBoxHelper.Attach="True"
                             local:PasswordBoxHelper.Password="{Binding PassWord, Mode=TwoWay}" 
                             HorizontalContentAlignment="Center" />
            </Grid>
        </GroupBox>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="5 5 20 5">
            <Button x:Name="btnReister" Margin="2 2 65 2">申请账号</Button>
            <Button x:Name="btnLogin" Margin="2" Command="{Binding LoginCommand}" >登录(_L)</Button>
            <Button x:Name="btnExit"  Margin="2"  Click="BtnExit_Click">退出(_E)</Button>
        </StackPanel>

    </StackPanel>
</local:BaseWindow>

6.2 WLoginViewModel

using JIS.Model;
using JIS.Views;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace JIS.ViewModels
{
    public class WLoginViewModel : NotificationObject
    {
       
        //加载登陆服务
        LoginService.LoginServiceClient serviceClient = new LoginService.LoginServiceClient();
       
        #region 委托事件
        public event EventHandler<LoginTipsEventArgs> LoginHandler;
        protected virtual void OnLoginHandler(LoginTipsEventArgs e)
        {
            this.LoginHandler?.Invoke(this, e);
        }
        #endregion

        #region 构造函数
        public WLoginViewModel()
        {
            _UserList = serviceClient.GetUsers();
        }

        #endregion

        #region 封装字段

        private List<User> _UserList;
        public List<User> UserList
        {
            get { return this._UserList; }
            set
            {
                this._UserList = value;
                RaisePropertyChanged(() => UserList);
            }
        }
        private string _PassWord;
        public string PassWord
        {
            get { return this._PassWord; }
            set
            {
                this._PassWord = value;
                RaisePropertyChanged(() => PassWord);
            }
        }

        private User _SelectedUserItem;
        public User SelectedUserItem
        {
            get { return this._SelectedUserItem; }
            set
            {
                this._SelectedUserItem = value;
                RaisePropertyChanged(() => SelectedUserItem);
            }
        }



        private bool? _DialogResult;
        public bool? DialogResult
        {
            get { return this._DialogResult; }
            set
            {
                this._DialogResult = value;
                RaisePropertyChanged(() => DialogResult);
            }
        }
        #endregion

        #region 封装命令
        private ICommand _LoginCommand;
        public ICommand LoginCommand
        {
            get
            {
                if (this._LoginCommand == null)
                    this._LoginCommand = new RelayCommandBase(LoginAction);
                return this._LoginCommand;
            }
        }
        #endregion

        #region 命令实现
        private void LoginAction(object obj)
        {
            if (serviceClient.Login(SelectedUserItem.LoginName, _PassWord))
                OnLoginHandler(new LoginTipsEventArgs(LoginState.Success, "登陆成功!"));
            else
                OnLoginHandler(new LoginTipsEventArgs(LoginState.Success, "登陆失败!"));
        }

        #endregion
    }
}

6.3 WLogin.xaml.cs

WLoginViewModel 绑定,并实现LoginHandler

using JIS.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace JIS.Views
{
    /// <summary>
    /// WLogin.xaml 的交互逻辑
    /// </summary>
    public partial class WLogin : BaseWindow
    {
        public WLogin()
        {
            InitializeComponent();
            WLoginViewModel login = new WLoginViewModel();

            login.LoginHandler += Login_LoginHandler;
            this.DataContext = login;
        }

        private void Login_LoginHandler(object sender, LoginTipsEventArgs e)
        {
            if (e.loginState == LoginState.Fail)
            {
                MessageBox.Show(e.Tips);
                return;
            }
            else
            {
                MainWindow mainWindow = new MainWindow();
                this.Close();
                mainWindow.Show();
            }
        }

        private void BtnExit_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }
    }
}

6.4 PasswordBoxHelper

WPF的PasswordBox控件的Password属性不是依赖属性,无法直接进行数据绑定,为使其在MVVM模式中正常使用,增加附加属性

using System.Windows;
using System.Windows.Controls;

namespace JIS.Views
{

    //WPF的PasswordBox控件的Password属性不是依赖属性,无法直接进行数据绑定,为使其在MVVM模式中正常使用,可以为PasswordBox增加一个助手类
    public static class PasswordBoxHelper
    {
        public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached(
            "Password",
            typeof(string),
            typeof(PasswordBoxHelper),
            new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));



        public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached(
            "Attach",
            typeof(bool),
            typeof(PasswordBoxHelper),
            new PropertyMetadata(false, Attach));


        private static readonly DependencyProperty IsUpdatingProperty = DependencyProperty.RegisterAttached(
            "IsUpdating",
            typeof(bool),
            typeof(PasswordBoxHelper));

        public static void SetAttach(DependencyObject dp, bool value)
        {
            dp.SetValue(AttachProperty, value);
        }
        public static bool GetAttach(DependencyObject dp)
        {
            return (bool)dp.GetValue(AttachProperty);
        }
        public static string GetPassword(DependencyObject dp)
        {
            return (string)dp.GetValue(PasswordProperty);
        }
        public static void SetPassword(DependencyObject dp, string value)
        {
            dp.SetValue(PasswordProperty, value);
        }
        private static bool GetIsUpdating(DependencyObject dp)
        {
            return (bool)dp.GetValue(IsUpdatingProperty);
        }
        private static void SetIsUpdating(DependencyObject dp, bool value)
        {
            dp.SetValue(IsUpdatingProperty, value);
        }

        private static void OnPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            PasswordBox passwordBox = sender as PasswordBox;
            passwordBox.PasswordChanged -= PasswordChanged;
            if (!(bool)GetIsUpdating(passwordBox))
            {
                passwordBox.Password = (string)e.NewValue;
            }
            passwordBox.PasswordChanged += PasswordChanged;
        }

        private static void Attach(
            DependencyObject sender,
            DependencyPropertyChangedEventArgs e)
        {
            PasswordBox passwordBox = sender as PasswordBox;
            if (passwordBox == null)
                return;
            if ((bool)e.OldValue)
            {
                passwordBox.PasswordChanged -= PasswordChanged;
            }
            if ((bool)e.NewValue)
            {
                passwordBox.PasswordChanged += PasswordChanged;
            }
        }

        private static void PasswordChanged(object sender, RoutedEventArgs e)
        {
            PasswordBox passwordBox = sender as PasswordBox;
            SetIsUpdating(passwordBox, true);
            SetPassword(passwordBox, passwordBox.Password);
            SetIsUpdating(passwordBox, false);
        }
    }
}


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值