Silverlight+WCF 新手实例 象棋 回归WCF通讯应用-登陆(十八)

前四节,我们讲了通讯基础,从这节起,我们回归到项目中来,要将前面的WCF通讯知识应用进来。

之前的项目大伙没丢把,重新发下载地址:之前第3阶段代码:点此下载

 

我们为Chess项目的解决方案里,再添加WCF应用服务程序

由于Silverlight+WCF 新手实例 象棋 WCF通讯跨域(十五)已截图,所以这里不截图了。

步骤:

1。对着解决方案-》右键-》添加新建项目-》选择WCF应用服务程序-》输入:GameService

2。删除默认的IService1.cs和IService1.svc

3。新建WCF服务,起名为IService

4。把跨域文件clientaccesspolicy.xml复制到项目中去.

5。设置GameService项目属性的特定启动端口为:8686

6。添加引用PollingDuplex.dll

7。修改配置文件,参考十五小节

上面步骤完成了后

我们接下来要添加几个新文件:

1.新添加一个回调接口:ICallBack

对着GameService项目右键-》添加-》新建项->选择接口->输入:ICallBack.cs

2.添加文件夹,用于存放通讯实体[契约数据]

对着GameService项目右键-》添加-》新建文件夹-》输入:DataContract

3.在通讯实体文件夹下,我们添加一个玩家Player实体用于通讯传递。

对着DataContract文件夹右键-》添加-》类-》输入:Player.cs

目前的项目结构图如下:



我们去掉Player的名称空间[.DataContract],其实就是去掉文件夹的名称:

using System.Runtime.Serialization;
namespace GameService
{
    /// <summary>
    /// 游戏玩家 by 路过秋天
    /// </summary>
    [DataContract]
    public class Player
    {
       
    }
}

 

接着,我们为Player增加基本属性[以后随着应用会增加]:
ID:用户标识
NickName:昵称
CallBack:玩家的回调,我们把回调放到玩家里。

RoomID:玩家所在房间,没有的话默认为0;
下面我们实现属性代码:

 


namespace GameService
{
    /// <summary>
    /// 游戏玩家 by 路过秋天
    /// </summary>
    [DataContract]
    public class Player
    {
        /// <summary>
        /// 玩家ID
        /// </summary>
        [DataMember]
        public Guid ID
        {
            get;
            set;
        }
        /// <summary>
        /// 玩家昵称
        /// </summary>
        [DataMember]
        public string NickName
        {
            get;
            set;
        }
        /// <summary>
        /// 玩家的回调
        /// </summary>
        [DataMember]
        internal ICallBack CallBack
        {
            get;
            set;
        }

       /// <summary>
       /// 玩家所在房间号
       /// </summary>
       [DataMember]
       public int RoomID
       {
           get;
           set;
       }
    }

 

用于传递的player完成了,现在我们写一下WCF通讯方法,我们为IService接口添加登陆和退出事件:


namespace GameService
{
    [ServiceContract(CallbackContract = typeof(ICallBack))]//头顶上这里写明了回调是ICallBack
    public interface IService
    {
        [OperationContract(IsOneWay = true)]
        void Login(Player player);//登陆

        [OperationContract(IsOneWay = true)]
        void Logout(Player player);//退出
        
    }
}

 

就是说,客户端直接传递一个Player实体过来了,我们接着实现这个接口:


namespace GameService
{
    public class Service : IService
    {
        /// <summary>
        /// 玩家集合
        /// </summary>
        static Dictionary<int, Dictionary<Guid, Player>> playerList = new Dictionary<int, Dictionary<Guid, Player>>();
        #region IService 成员
        public void Login(Player player)
        {
            //待实现
        }

        public void Logout(Player player)
        {
            //待实现
        }

        #endregion
    }
}

 

我这在里用了一个静态的全局变量,来保存所有的用户,简单解释一下这个双重的泛型字典集合

Dictionary<int, Dictionary<Guid, Player>> 翻译一下就变成----》Dictionary<房间号, 玩家列表>

看到翻译明白了吧,所有的玩家都被分到房间里去了。然后所有的房间的玩家才构成一个大集合。

 

看明白了,现在来实现Login登陆了。

根据以前我们注册一样,先判断用户在不在,在就删除,然后再添加用户。


 public void Login(Player player)
        {
            //待实现
            Player oldPlayer = FindPlayer(player.ID);
            if (oldPlayer != null)//用户已存在了
            {
                RemovePlayer(player);//删除用户
            }
            AddPlayer(player, 0);//添加用户
        }

 

所以这里我们还要补上三个方法:

FindPlayer:从全局里找用户

RemovePlayer:从全局里移除用户

AddPlayer:从全局里添加一个用户


static Player FindPlayer(Guid playerID)
        {
            foreach (KeyValuePair<int, Dictionary<Guid, Player>> item in playerList)
            {
                if (item.Value.ContainsKey(playerID))
                {
                    return item.Value[playerID];
                }
            }
            return null;
        }
        static void RemovePlayer(Player player)
        {
            playerList[player.RoomID].Remove(player.ID);
        }
        static void AddPlayer(Player player, int roomID)
        {
            player.RoomID = roomID;
            //注册回调
            player.CallBack = OperationContext.Current.GetCallbackChannel<ICallBack>();
            Dictionary<Guid, Player> players;
            if (playerList.ContainsKey(roomID))//房间已存在
            {
                players = playerList[roomID];//房间所有用户

                if (!players.ContainsKey(player.ID))
                {
                    players.Add(player.ID, player);
                }
            }
            else
            {
                players = new Dictionary<Guid, Player>();
                players.Add(player.ID, player);
                playerList.Add(roomID, players);
            }
        }

 

全面两个函数都短一点,后面添加就长一点了。

要判断房间是否存在,然后还要判断房间里是不是已有用户了,最后才添加。

用户登陆就到此了,那退出呢?

退出就一行代码搞完了:

 public void Logout(Player player)
        {
            //待实现
            RemovePlayer(player);//删除用户
        }

 

OK,WCF的服务端就写完了,写完就要编绎下服务端代码,确保是正常通过的。

 

接着是客户端要调用开始了,这里先:

1。当然是添加服务引用了,并起名为GameService。

接着我们回到App.xaml.cs里,我们把GameService做成一个全局变量,在应用程序开始时实例化一次,以后调用就不用到New了:


Grid root = new Grid();
        public static GameService.ServiceClient client;//回调的客户端
        public static GameService.Player player;//当前玩家
        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
            InitiallizeGlobalVar();
        }
        private void InitiallizeGlobalVar()
        {
            PollingDuplexHttpBinding binding = new PollingDuplexHttpBinding()
            {
                InactivityTimeout = TimeSpan.FromMinutes(20)
            };
            EndpointAddress endPoint = new EndpointAddress("http://localhost:8686/Service.svc");
            client = new GameService.ServiceClient(binding, endPoint);
            player = new GameService.Player();
        }

 

这里有一点提一下:

本人机子装了VS2005+VS2010

新建的项目Silverlight是2.0的库,WCF服务应用程序是4.0的库。所以在引用DLL方面,有点小插曲。

这不,WCF引用的轮询是4.0的,到Silverlight里,就只能引用2.0的。好在也能用着。

顺便提一下,之所以不用wsDualHttpBinding双工通讯方式,就是因为Silverlight是2.0的,

因此引用不了4.0的wsDualHttpBinding库,所以没用它了。

 

现回到Login页面,简单修改下以前的代码:


 private void btnLogin_Click(object sender, RoutedEventArgs e)
        {
            nickName = txtNickName.Text.Trim();
            if (nickName == "")
            {
                MessageBox.Show("请输入昵称!");
                return;
            }
            if (nickName.Contains(","))
            {
                MessageBox.Show("昵称不能包含非法字符!");
                return;
            }
            btnLogin.IsEnabled = false;
            //下面这几句代码变了一下:
            App.player.ID = userID;
            App.player.NickName = nickName;
            App.client.LoginCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_LoginCompleted);
            App.client.LoginAsync(App.player);
           
        }
        void client_LoginCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {//设置Cookie
            System.Windows.Browser.HtmlPage.Document.Cookies = userID + "," + nickName;
            ((App)(Application.Current)).RedirectTo(new Room());
        }

 

好了按F5运行,



点击登陆,正常转向房间

版权声明:本文原创发表于博客园,作者为路过秋天,原文链接:

http://www.cnblogs.com/cyq1162/archive/2010/07/14/1777307.html

时间: 2024-09-20 00:20:50

Silverlight+WCF 新手实例 象棋 回归WCF通讯应用-登陆(十八)的相关文章

Silverlight+WCF 新手实例 象棋 回归WCF通讯应用-进入房间(十九)

上一节我们讲到登陆时通过WCF,把用户信息传递到远程服务器,并用一个全局泛型字典变量来保存用户列表. 登陆后我们转向了房间页面.这节,我们要通过点击房间上的座位进入主页面(Index.xaml). 既然要点击房间座位才能进入,我们就得为那房间的座位添加鼠标点击事件了. 我们回到GameRoom.cs找到创建房间的代码,找到Draw函数里,创建红蓝黑三个房间座位的代码,其实就是那三个矩形框Rectangle. 我们在它们被添加到房间之前,添加几个事件:    //添加三个房间点击事件       

Silverlight+WCF 新手实例 象棋 主界面-在线用户区(二十四)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 演示已更新到此节介绍:Silverlight+WCF 新手实例 象棋 介绍III(二十三)   这节我们来实现在线用户区的显示,把上两节介绍那张图再弄来,看在线用户区是哪块:   一眼扫过看到了,是第四区,现在开始了,还是上次下棋区域一样的逻辑,往Index.xaml里拉一个Board控件,然后后台写两行代码代码一下. 当然了,得新建一个用户控件:就叫:OnlineUser.xaml,好,空白的在线用户建完了,下面还是两步实

Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放(三十九)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   本节完后,同时会更新Silverlight+WCF 新手实例 象棋 专题索引,并顺路提供第八阶段源码   在Silverlight+WCF 新手实例 象棋 主界面-棋谱-布局写谱(三十六)节中,我们完成了下棋双方的棋谱传递 在Silverlight+WCF 新手实例 象棋 主界面-棋谱-获取列表(三十八)节中,我们完成了观棋者获取棋谱列表 在本节中,我们要进行最一步了,棋谱回放: 首先,当用户进入列表后,获取完棋谱信息之

Silverlight+WCF 新手实例 象棋 主界面-棋盘区(二十二)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   这节我们要布局Index.xaml界面. 首先,我们定义一下全局的宽和高:1000*620[数字差不多就行了] 一堆代码,都是自动生成的,只是改了两个数字,不说大伙也知道改啥数字了. <UserControl x:Class="NewChessProject.Index"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen

Silverlight+WCF 新手实例 象棋 主界面-状态重置(三十四)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   正如我们在:Silverlight+WCF 新手实例 象棋 主界面-事件区-求和认输(三十二)里面提到的一样: "游戏结束了,要干点什么呢?当然就是棋盘复位了,按钮重置了,如果还有棋谱之类的,全都得重置.这些,我们留下到另一节优化处理吧."   所以,本节就做这些手尾工作了. 由于游戏结束,我们复位的工作很多,至少有N个控件需要复位,因此,Silverlight+WCF 新手实例 象棋 主界面-控件消息传递(二

Silverlight+WCF 新手实例 象棋 主界面-事件区-游戏开始(二十七)

本专题出产简单原由: 一开始的初衷,只是想写个简单的单机BS人机对战版的,开始还下了点AI算法看看的: 但是写到最后,都写成了通讯版本的对战了,只因中间不小心看到了WCF的相关内容,顺便加了进来; 最后就定局了,反正新手实例,能加多点内容就加多点了. 关于原始初衷,后期再补上了.       好了,先上几个附加索引: 1:Silverlight+WCF 新手实例 象棋 在线演示 2:Silverlight+WCF 简单部署问题集 3:Silverlight4 ListBox bug 4:Silv

Silverlight+WCF 新手实例 象棋 房间状态更新(二十)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示   这节开始,标题里就去掉"回归WCF通讯应用"几字了.   上节我们成功实现了进入房间,服务端也收到用户进入房间的请求了,这节,我们服务端收到进入房间请求后,通知在房间大门外的人更新房间状态. 我们要增加一个回调方法,ICallBack接口那,忘记的人回去看看WCF通讯那几篇(十四到十七节). 方法如下,以前说过了,回调的方法是给客户端实现的,服务端只管调就行了: using System.ServiceMode

Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放-结局(四十)

查看本系列其他相关文章请点击:Silverlight+WCF 新手实例象棋专题索引 在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 在Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放(三十九)中,我们实现了用户的棋谱回放,在文章的下面,我们曾留下了两个问题: 下棋者在下棋过程,要不要开放"回放"功能,如果开放,需要注意什么? 观众在回放过程中,突然又传来一个棋步,需要注意什么? 在解答这两个问题之前,我们先来解答上一篇的截图中发现的问题: 不知

Silverlight+WCF 新手实例 象棋 主界面-实时聊天区(二十五)

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 演示已更新到此节介绍:Silverlight+WCF 新手实例 象棋 介绍III(二十三)   本节连着Silverlight+WCF 新手实例 象棋 主界面-在线用户区(二十四) 发,主界面就不截图了,这节我们实现"实时聊天区": 这节内容几乎和上节一个样的逻辑 1:新建一个用户控件:就叫:Chat.xaml,用来在线聊天 2: 界面拖一个Border到Index.xaml,现在界面上有三个Border了,第三个