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的同步通知。
文件内容如下: 

View Code
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添加此应用,具体怎么填的图片如下:

Asp.net 与 UCenter 用户同步之实施过程


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

 我成功的图片:

Asp.net 与 UCenter 用户同步之实施过程

最新提醒:

有不少读者反映为什么引用我的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

你可能感兴趣的:(asp.net)