zoukankan      html  css  js  c++  java
  • Asp.net 与 UCenter 用户同步之实施过程

    在写这篇文章的时候,我还在想,这篇文章也许能给你带来一些收获,但或许会令你更加的迷茫,为什么会这样?
    因为:
    1、UCenter虽然足够强大,但正为它的强大,它的不少暗箱操作使得我们望而生畏,我们不害怕出错,我们害怕出错时抓不到出错点。
    2、同步登录经常会跨平台,跨服务器,跨域,跨数据库等。环境要求比较高,这使得我们需要更多地了解它。

    最近公司弄了个团购项目,要求团购的用户和论坛的会员同步起来,以期实现优质会员享受更低折扣等功能。这个项目正是以asp.net开发,当然,在这里要非常感谢同步API的原作者dozer,其原理在其主页文章http://www.dozer.cc/2011/01/ucenter-api-in-depth-1st/
    有详细介绍,我这里只简单介绍一下:
    UCenter是所有子项目的核心,任何其中某一子应用(包括Discuz论坛)通过向它发送登录,注册,删除,退出等消息,再由UCenter转发到其它的子应用。
    ,另外我只介绍一下需要重点步骤及需要注意的地方。

    第一步,你要得到和UCenter进行通信的类库,作者的主页有原始类库http://www.dozer.cc/2011/05/ucenter-api-for-net-on-codeplex/,是asp.net 4.0版的。我的环境是3.5所以将类库作了一些修改,修改之后的版本在这里/Files/CoreCaiNiao/DS.Web.UCenter.rar
    第二步,你在你的asp.net项目中引用该类库,引用类库的时候,Browse到dll就行,没有必要把整个项目原代码添加到你的解决方案中。
    这个类库有两个重点的文件夹需要注意:DS.Web.UCenter.Api与DS.Web.UCenter.Client,
    其中DS.Web.UCenter.Api用于响应由UCenter中心发出的通知消息;
    然后DS.Web.UCenter.Client用于本地向UCenter发送消息;
    第三步,你的asp.net项目需要一个专门向MySql数据库提供操作的类,为了使用本类,还需要安装mysql-connector-net-6.4.3.msi,这个文件可以到官网去下载(上谷歌搜一下),之后,建立用于连接MySql的类。
    有人要问和MySql数据库通信的必要性,我得解释一下,UCenter向你的应用发出的通知里,只有UID,要想得到更多的用户信息,唯有和MySql通信。
    我这里有一个临时写的,如果你不介意,可以拿去用,代码如下:

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using MySql.Data;
    using MySql.Data.MySqlClient;
    using System.Data;

    namespace UCenterDB
    {
        public class MySqlHelper
        {
            private string connString;
            private MySqlConnection conn;

            public string ConnString {
                set
                {
                    connString = value;
                    conn = new MySqlConnection(this.connString);
                }
            }

            public MySqlHelper(string connString) {
                this.connString = connString;
                conn = new MySqlConnection(this.connString);
            }

            public int ExecuteNonQuery(string query) {
                MySqlCommand cmd = createTxtCommand(query);
                int result = -1;
                try
                {
                    conn.Open();
                    result = cmd.ExecuteNonQuery();
                    conn.Close();
                }
                catch (Exception ex)
                {
                    //错误处理过程
                }
                return result;
            }

            public string ExecuteScalar(string query)
            {
                MySqlCommand cmd = createTxtCommand(query);
                string result = string.Empty;
                try
                {
                    conn.Open();
                    result = cmd.ExecuteScalar().ToString();
                    conn.Close();
                }
                catch (Exception ex)
                {
                    //错误处理过程
                }
                return result;
            }

            public DataTable GetDataTable(string query) {          
                DataSet ds = new DataSet();
                MySqlDataAdapter msda = new MySqlDataAdapter();
                msda.SelectCommand = createTxtCommand(query);
                msda.Fill(ds);
                return ds != null && ds.Tables.Count > 0 ? ds.Tables[0] : null;          
            }

            private MySqlCommand createTxtCommand(string query) {
                return new MySqlCommand
                {
                    Connection = conn,
                    CommandText = query,
                    CommandType = CommandType.Text                
                };
            }  
        }
    }
    复制代码

    不过我要提醒一下,为了安全,在主服务器开放MySql对外的帐户权限的时候,仅需要开放select权限就可以了。
    第四步,你需要一个响应通知的页面了,这里为了尊重原作者,我在WEB根目录下建立了API文件夹,并在里面建立了一个名为uc.ashx的响应文件。这个页面用于响应UCenter的同步通知。
    文件内容如下: 

    复制代码
    using System;
    using System.Collections;
    using System.Data;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using System.Web.Services.Protocols;
    using System.Xml.Linq;
    using DS.Web.UCenter; 
    using DS.Web.UCenter.Api;
    using System.Collections.Generic;
    using UCenterDB;

    namespace CoreCaiNiao.Web.API
    {
        /// <summary>
        /// Summary description for $codebehindclassname$
        /// </summary>
        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        public class uc : UcApiBase
        {
            SiteMemberManager users = TuanGouManager.siteMemberManager;
            MySqlHelper msh = new MySqlHelper(DBConfig.ConnStringMySql);
            public override ApiReturn DeleteUser(IEnumerable<int> ids)
            {
                throw new NotImplementedException();
            }
            public override ApiReturn RenameUser(int uid, string oldUserName, string newUserName)
            {
                throw new NotImplementedException();
            }
            public override UcTagReturns GetTag(string tagName)
            {
                throw new NotImplementedException();
            }
            public override ApiReturn SynLogin(int uid)
            {
                SiteMember loginMember = users.GetInfoByUid(uid);
                DataTable dt = msh.GetDataTable("select uid,username,password,email,groupid from pre_common_member where uid=" + uid + " limit 0,1");
                if (dt == null || dt.Rows.Count < 1)
                {
                    return ApiReturn.Failed;//无法从远端找到,则此用户不存在
                }
                DataRow dr = dt.Rows[0];
                if (loginMember != null) {//从本地库找到,则更新库             
                    loginMember.ULevel = dr[4].ToString().ToNumber();
                    users.EditInfo();
                    //以下代码保存会话到浏览器进程
                    TuanGouManager.userSessionManager.Login(loginMember, UserLoginExpire.NoSave);               
                    return ApiReturn.Success;
                }
              
                //本地库没有,则添加到本地库
                loginMember = new SiteMember
                {
                    CreateTime = DateTime.Now,
                    Address = "",
                    BadAppCount = 0,
                    CumulateMoney = "",
                    EditTime = DateTime.Now,
                    Email = dr[3].ToString(),
                    GoodAppCount = 0,
                    Intro = "",
                    IpAddress = HttpContext.Current.Request.UserHostAddress,
                    IsLock = 0,
                    NickName = "",
                    NormalAppCount = 0,
                    PickedMoney = "",
                    RemainMoney = "",
                    SiteAuthoritys = "",
                    SiteRole = "",
                    TrueName = "",
                    UID = uid,
                    ULevel = dr[4].ToString().ToNumber(),
                    UserName = dr[1].ToString(),
                    UserPass = dr[2].ToString(),
                    UserQQ = "",
                    UserSex = "保密",
                    UserTel = "",
                    UserType = ",1,"
                };
                int userId = users.AddNewInfo(loginMember);
                loginMember.ID = userId;
                //以下代码保存会话到浏览器进程            
                TuanGouManager.userSessionManager.Login(loginMember, UserLoginExpire.NoSave);          
                return ApiReturn.Success;
            }
            public override ApiReturn SynLogout()
            {
                TuanGouManager.userSessionManager.Logout();
                return ApiReturn.Success;
            }
            public override ApiReturn UpdatePw(string userName, string passWord)
            {
                throw new NotImplementedException();
            }
            public override ApiReturn UpdateBadWords(UcBadWords badWords) { throw new NotImplementedException(); } 
            public override ApiReturn UpdateHosts(UcHosts hosts) { throw new NotImplementedException(); } 
            public override ApiReturn UpdateApps(UcApps apps) { throw new NotImplementedException(); }
            public override ApiReturn UpdateClient(UcClientSetting client) { throw new NotImplementedException(); }
            public override ApiReturn UpdateCredit(int uid, int credit, int amount) { throw new NotImplementedException(); } 
            public override UcCreditSettingReturns GetCreditSettings() { throw new NotImplementedException(); } 
            public override ApiReturn GetCredit(int uid, int credit) { throw new NotImplementedException(); }
            public override ApiReturn UpdateCreditSettings(UcCreditSettings creditSettings) { throw new NotImplementedException(); }
           
        } 
    }
    复制代码

    我的示例代码中,只对同步登录和退出消息作出响应,具体过程中,您可以根据需要作更多的响应.


    第五步,这步是写配置信息,因为原始类库的配置信息都写到它自己的App.config中去了,我们需要复制过来到Web.config
    在<appSettings>节中,加入以下行:
        <!--DZ1.5用户同步-->
        <!--客户端版本-->
        <add key="UC_CLIENT_VERSION" value="1.5.2"/>
        <!--发行时间-->
        <add key="UC_CLIENT_RELEASE" value="20101001"/>
        <!--API 开关(value类型:True False 默认值:True)-->
        <!--是否允许删除用户-->
        <add key="API_DELETEUSER" value="True"/>
        <!--是否允许重命名用户-->
        <add key="API_RENAMEUSER" value="True"/>
        <!--是否允许得到标签-->
        <add key="API_GETTAG" value="True"/>
        <!--是否允许同步登录-->
        <add key="API_SYNLOGIN" value="True"/>
        <!--是否允许同步登出-->
        <add key="API_SYNLOGOUT" value="True"/>
        <!--是否允许更改密码-->
        <add key="API_UPDATEPW" value="True"/>
        <!--是否允许更新关键字-->
        <add key="API_UPDATEBADWORDS" value="True"/>
        <!--是否允许更新域名解析缓存-->
        <add key="API_UPDATEHOSTS" value="True"/>
        <!--是否允许更新应用列表-->
        <add key="API_UPDATEAPPS" value="True"/>
        <!--是否允许更新客户端缓存-->
        <add key="API_UPDATECLIENT" value="True"/>
        <!--是否允许更新用户积分-->
        <add key="API_UPDATECREDIT" value="True"/>
        <!--是否允许向UCenter提供积分设置-->
        <add key="API_GETCREDITSETTINGS" value="True"/>
        <!--是否允许获取用户的某项积分-->
        <add key="API_GETCREDIT" value="True"/>
        <!--是否允许更新应用积分设置-->
        <add key="API_UPDATECREDITSETTINGS" value="True"/>
        <!--API 开关结束-->
        <!--返回值设置-->
        <!--返回成功(默认:1)-->
        <add key="API_RETURN_SUCCEED" value="1"/>
        <!--返回失败(默认:-1)-->
        <add key="API_RETURN_FAILED" value="-1"/>
        <!--返回禁用(默认:-2)-->
        <add key="API_RETURN_FORBIDDEN" value="-2"/>
        <!--返回值设置结束-->
        <!--[必填]通信密钥-->
        <add key="UC_KEY" value="FD144298AF7E4797A66ACC0C18CXXEA3"/>
        <!--[必填]UCenter地址,这个要根据需要变化,例如,http://你的论坛UCENTER地址-->
        <add key="UC_API" value="http://bbs.XXX.XXX.com/ucenter" />
        <!--[必填]默认编码-->
        <add key="UC_CHARSET" value="utf-8"/>
        <!--[非必填]UCenter IP-->
        <add key="UC_IP" value=""/>
        <!--[必填]应用ID-->
        <add key="UC_APPID" value="4"/>
    这里有三行要改:
    倒数第1行:应用ID:UC_APPID
    倒数第4行:UCenter地址:UC_API
    倒数第5行:通信密钥:UC_KEY
    另外,再加上MySqlProviderFactories节
         <!--MySql使用-->
         <system.data>
             <DbProviderFactories>
                 <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.4.3.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />  
             </DbProviderFactories> 
         </system.data>
    第六步,检查本地服务器和UCenter服务器是否能正常通信(两台服务器互相telnet IP地址 80)
    第七步,去UCenter添加此应用,具体怎么填的图片如下:


    最后,我祈祷你能通信成功并同步成功。建议先在本地进行DEBUG模式,在uc.ashx文件的SynLogin(int uid)方法及UpdateApps(UcApps apps)处下断点,这样可以查看是否有通知过来,之后再确定问题的根源。

     我成功的图片:

    最新提醒:

    有不少读者反映为什么引用我的UC.ashx后不能直接被编译?这是因为你直接把我的业务逻辑代码也照搬了,实际上

    public override ApiReturn SynLogin(int uid)

    这个函数是用来做你自己的业务处理的,做完处理后,返回给接口一个成功的信号就行了,形式如同这样:

    复制代码
     1 public override ApiReturn SynLogin(int uid)
     2         {
     3             SiteMember loginMember = users.GetInfoByUid(uid);
     4             DataTable dt = msh.GetDataTable("select uid,username,password,email,groupid from pre_common_member where uid=" + uid + " limit 0,1");
     5             if (dt == null || dt.Rows.Count < 1)
     6             {
     7                 return ApiReturn.Failed;//无法从远端找到,则此用户不存在
     8             }
     9             DataRow dr = dt.Rows[0];
    10             if (loginMember != null) {//从本地库找到,则更新库             
    11                 loginMember.ULevel = dr[4].ToString().ToNumber();
    12                 users.EditInfo();
    13                 TuanGouManager.userSessionManager.Login(loginMember, UserLoginExpire.NoSave);               
    14                 return ApiReturn.Success;
    15             }
    16           
    17             //本地库没有,则添加到本地库
    18             loginMember = new SiteMember
    19             {
    20                 CreateTime = DateTime.Now,
    21                 Address = "",
    22                 BadAppCount = 0,
    23                 CumulateMoney = "",
    24                 EditTime = DateTime.Now,
    25                 Email = dr[3].ToString(),
    26                 GoodAppCount = 0,
    27                 Intro = "",
    28                 IpAddress = HttpContext.Current.Request.UserHostAddress,
    29                 IsLock = 0,
    30                 NickName = "",
    31                 NormalAppCount = 0,
    32                 PickedMoney = "",
    33                 RemainMoney = "",
    34                 SiteAuthoritys = "",
    35                 SiteRole = "",
    36                 TrueName = "",
    37                 UID = uid,
    38                 ULevel = dr[4].ToString().ToNumber(),
    39                 UserName = dr[1].ToString(),
    40                 UserPass = dr[2].ToString(),
    41                 UserQQ = "",
    42                 UserSex = "保密",
    43                 UserTel = "",
    44                 UserType = ",1,"
    45             };
    46             int userId = users.AddNewInfo(loginMember);
    47             loginMember.ID = userId;
    48             TuanGouManager.userSessionManager.Login(loginMember, UserLoginExpire.NoSave);          
    49             return ApiReturn.Success;
    50         }
    复制代码

    其中,灰色的部分千万别抄,只是示意代码,绿色的部分是必须要的,作用是向接口表明你已经成功处理登录业务啦。

     应朋友要求,特制作DEMO一份,已测试同步成功!用户需要自行安装UCenter及论坛等.UC_Demo.rar

          DEMO说明:

          1、子应用登录入口:default.aspx

          2、注意web.config中的几处不要填错了,通信密钥,应用ID,UCenter地址(最好用域名或映射域名而不要用IP,有时直接用IP无法连接),编码(中文用户名时会用到)

          3、该DEMO请在调试状态下进行,方便知道问题所在。在UCenter配置此Demo的新应用时,应该带上端口号,例如http://localhost:28457/

     您可以转载本文,但请标明出处:http://www.cnblogs.com/CoreCaiNiao/archive/2011/08/25/2153434.html

     
     
  • 相关阅读:
    SG函数
    贪心:zoj3953 Intervals
    山东省第四届省赛 E-Mountain Subsequences
    山东省第四届ACM程序设计竞赛A题:Rescue The Princess
    前缀和:CodeForces 932B Recursive Queries
    常用头文件和一些简单的函数
    codeforce 429D. Tricky Function (思维暴力过)
    HDU-5754 Life Winner Bo (博弈论)
    线程池的原理与实现
    运行停止一个线程
  • 原文地址:https://www.cnblogs.com/webenh/p/8087443.html
Copyright © 2011-2022 走看看