对于一款企业级的CRM系统在实际的使用过程中不与外界进行交换是不可能的。在博文《Dynamics CRM 2011编程系列(55):Dynamics CRM 集成开发简述 》中,我就Dynamics CRM的集成开发概念做了总结。本文将介绍如何使用BCS(Business Connectivity Service)来实现Dynamics CRM与Sharepoint 2010 的集成,Sharepoint 亦是款微软的重量级产品,它是企业门户,文档管理,协同办公,商务智能的一体化解决方案的产物。
本文将介绍如何通过BCS在Sharepoint站点上显示Dynamics CRM中的实体数据,并且Sharepoint的用户还可以对这些数据进行CRUD操作。先来看下程序的实现效果吧:
图1
图2
图3
图4
图5
实现流程
1. 创建一个能对Dynamics CRM 2011系统进行CRUD的WCF Service并把它部署在IIS上。
2. 在安装了Sharepoint的机器上新建BCS项目
3. 在BCS项目中引用之前创建的Service,并实现相应的CRUD逻辑。
4. 部署BCS项目
5. 配置Sharepoint的External List,让其引用我们部署成功的BCS项目
在步骤1)中,我们为什么不直接使用Dynamics CRM 2011的原生服务呢,原因:sharepoint 2010的BCS项目是基于.Net Frameworks 3.5,无法引用基于4.0框架开发的WCF Service。在步骤2)中,我们只能在安装了sharepoint的机器上创建BCS项目,至于具体原因不明。接下来我们就需要完成集成开发的第一步:实现一个基于CRUD的WCF Service,在本文中我会给出个小例子给大家,当然大家完全可以实现自己的CRUD小例子:
CRUD Service[ServiceContract] public interface ICURD { [OperationContract] IEnumerable<Account> GetAllAccount(); [OperationContract] Account GetAccount(string accNumber); [OperationContract] Account CreateAccount(Account acc); [OperationContract] void UpdateAccount(Account acc); [OperationContract] void DeleteAccount(Account acc); } [DataContract] public class Account { [DataMember] public string Number; [DataMember] public string Name; [DataMember] public string Email; [DataMember] public string PhoneNumber; [DataMember] public string Address; } public class CURD : ICURD { private IOrganizationService svc = CrmSvcHelper.CreateService(); public IEnumerable<Account> GetAllAccount() { List<Account> result = new List<Account>(); Account tmpAccount; QueryExpression query = new QueryExpression(); query.ColumnSet = new ColumnSet(true); query.EntityName = "account"; EntityCollection tmpResult = svc.RetrieveMultiple(query); foreach (var item in tmpResult.Entities) { tmpAccount = new Account(); tmpAccount.Number = item.GetAttributeValue<string>("accountnumber"); tmpAccount.Name = item.GetAttributeValue<string>("name"); tmpAccount.Address = item.GetAttributeValue<string>("address1_line1"); tmpAccount.Email = item.GetAttributeValue<string>("emailaddress1"); tmpAccount.PhoneNumber = item.GetAttributeValue<string>("telephone1"); result.Add(tmpAccount); } return result; } public Account GetAccount(string accNumber) { Account result = new Account(); QueryExpression query = new QueryExpression(); query.EntityName = "account"; query.ColumnSet = new ColumnSet(true); query.Criteria.AddCondition(new ConditionExpression("accountnumber", ConditionOperator.Equal, accNumber)); EntityCollection tmpResult = svc.RetrieveMultiple(query); if (tmpResult.Entities.Count > 0) { result.Number = tmpResult.Entities[0].GetAttributeValue<string>("accountnumber"); result.Name = tmpResult.Entities[0].GetAttributeValue<string>("name"); result.Address = tmpResult.Entities[0].GetAttributeValue<string>("address1_line1"); result.Email = tmpResult.Entities[0].GetAttributeValue<string>("emailaddress1"); result.PhoneNumber = tmpResult.Entities[0].GetAttributeValue<string>("telephone1"); } return result; } public Account CreateAccount(Account acc) { Entity account = new Entity("account"); account["accountnumber"] = acc.Number; account["name"] = acc.Name; account["address1_line1"] = acc.Address; account["emailaddress1"] = acc.Email; account["telephone1"] = acc.PhoneNumber; svc.Create(account); return acc; } public void UpdateAccount(Account acc) { QueryExpression query = new QueryExpression(); query.EntityName = "account"; query.ColumnSet = new ColumnSet(true); query.Criteria.AddCondition(new ConditionExpression("accountnumber", ConditionOperator.Equal, acc.Number)); EntityCollection tmpResult = svc.RetrieveMultiple(query); if (tmpResult.Entities.Count > 0) { Entity account = new Entity("account"); account["accountid"] = tmpResult.Entities[0].GetAttributeValue<Guid>("accountid"); account["accountnumber"] = acc.Number; account["name"] = acc.Name; account["address1_line1"] = acc.Address; account["emailaddress1"] = acc.Email; account["telephone1"] = acc.PhoneNumber; svc.Update(account); } } public void DeleteAccount(Account acc) { Account result = new Account(); QueryExpression query = new QueryExpression(); query.EntityName = "account"; query.ColumnSet = new ColumnSet(true); query.Criteria.AddCondition(new ConditionExpression("accountnumber", ConditionOperator.Equal, acc.Number)); EntityCollection tmpResult = svc.RetrieveMultiple(query); if (tmpResult.Entities.Count > 0) { svc.Delete("account", tmpResult.Entities[0].GetAttributeValue<Guid>("accountid")); } } }
小结
后续的博文会继续讨论这个话题,比如:BCS项目的创建,External List的配置。
这里仅提供简单的配置示例,关于比较详细的配置文件的信息,以后再做交流
实验环境:
系统:centos6.2 linux 2.6内核
php version: 5.4.14 (当前最新)
nginx version : 1.3.16 (当前最新)
1.配置框图配置的框架图如下:
可以看到有三台机器
连接代理:192.168.66.20 其它两台为后台服务器,IP与监听端口上面已标明
nginx 的安装比较简单了,详细内容请参照:http://blog.csdn.net/rao_warrior/article/details/8948063
对nginx的配置如下:
下面的配置文件中,为了理解方便,我把部分暂时不需要的东西都给删掉了
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream myproject {
server 192.168.66.11:9000 ;
server 192.168.66.10:9000 ;
}
server {
listen 80;
server_name 192.168.66.20;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://192.168.66.20;
#
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root html;
fastcgi_pass myproject ;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/php/$fastcgi_script_name; #指定后台server的php网站存放的目录
include fastcgi_params;
}
}
}
3.后台server的安装配置 3.1php的安装与配置
详细安装信息,请参考:http://blog.csdn.net/rao_warrior/article/details/8948063
配置/usr/local/etc/php-fpm.conf文件如下:
找到 listen = 127.0.0.1:9000 这一行,改成:
listen = 192.168.66.10:9000 #以server 192.168.66.10为例
启动php-fpm 就OK
本文讨论的是locale,内容和我的另一篇有一定关联:http://blog.csdn.net/sheismylife/article/details/7635767
今天远程登录到一台UBuntu12.04 server,用locale一看,出现警告信息:
root@s15438266:~# locale locale: Cannot set LC_CTYPE to default locale: No such file or directory locale: Cannot set LC_MESSAGES to default locale: No such file or directory locale: Cannot set LC_ALL to default locale: No such file or directory LANG=en_CA.UTF-8 LANGUAGE= LC_CTYPE="en_CA.UTF-8" LC_NUMERIC=zh_CN.UTF-8 LC_TIME=zh_CN.UTF-8 LC_COLLATE="en_CA.UTF-8" LC_MONETARY=zh_CN.UTF-8 LC_MESSAGES="en_CA.UTF-8" LC_PAPER=zh_CN.UTF-8 LC_NAME=zh_CN.UTF-8 LC_ADDRESS=zh_CN.UTF-8 LC_TELEPHONE=zh_CN.UTF-8 LC_MEASUREMENT=zh_CN.UTF-8 LC_IDENTIFICATION=zh_CN.UTF-8 LC_ALL=
这篇帖子解释的比较清楚,大意是ssh远程登录时想将我客户端的locale用在server上。结果server段没有en_US,就报了错。
http://askubuntu.com/questions/144235/locale-variables-have-no-effect-in-remote-shell-perl-warning-setting-locale-f
那就安装一下所有的en语言包:
root@s15438266:~# apt-get --reinstall install language-pack-en Reading package lists... Done Building dependency tree Reading state information... Done The following extra packages will be installed: firefox-locale-en language-pack-en-base The following NEW packages will be installed: firefox-locale-en language-pack-en language-pack-en-base 0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded. Need to get 1361 kB of archives. After this operation, 4956 kB of additional disk space will be used. Do you want to continue [Y/n]? y Get:1 http://mirror-us.oneandone.net/linux/distributions/ubuntu/ubuntu/ precise-updates/main language-pack-en-base all 1:12.04+20120801 [878 kB] Get:2 http://mirror-us.oneandone.net/linux/distributions/ubuntu/ubuntu/ precise-updates/main language-pack-en all 1:12.04+20120801 [1994 B] Get:3 http://mirror-us.oneandone.net/linux/distributions/ubuntu/ubuntu/ precise-updates/main firefox-locale-en amd64 16.0.1+build1-0ubuntu0.12.04.1 [480 kB] Fetched 1361 kB in 0s (4264 kB/s) perl: warning: Setting locale failed. perl: warning: Please check that your locale settings: LANGUAGE = (unset), LC_ALL = (unset), LC_TIME = "zh_CN.UTF-8", LC_MONETARY = "zh_CN.UTF-8", LC_ADDRESS = "zh_CN.UTF-8", LC_TELEPHONE = "zh_CN.UTF-8", LC_NAME = "zh_CN.UTF-8", LC_MEASUREMENT = "zh_CN.UTF-8", LC_IDENTIFICATION = "zh_CN.UTF-8", LC_NUMERIC = "zh_CN.UTF-8", LC_PAPER = "zh_CN.UTF-8", LANG = "en_CA.UTF-8" are supported and installed on your system. perl: warning: Falling back to the standard locale ("C"). locale: Cannot set LC_CTYPE to default locale: No such file or directory locale: Cannot set LC_MESSAGES to default locale: No such file or directory locale: Cannot set LC_ALL to default locale: No such file or directory Selecting previously unselected package language-pack-en-base. (Reading database ... 27043 files and directories currently installed.) Unpacking language-pack-en-base (from .../language-pack-en-base_1%3a12.04+20120801_all.deb) ... Selecting previously unselected package language-pack-en. Unpacking language-pack-en (from .../language-pack-en_1%3a12.04+20120801_all.deb) ... Selecting previously unselected package firefox-locale-en. Unpacking firefox-locale-en (from .../firefox-locale-en_16.0.1+build1-0ubuntu0.12.04.1_amd64.deb) ... Setting up firefox-locale-en (16.0.1+build1-0ubuntu0.12.04.1) ... Setting up language-pack-en (1:12.04+20120801) ... Setting up language-pack-en-base (1:12.04+20120801) ... Generating locales... en_AG.UTF-8... done en_AU.UTF-8... done en_BW.UTF-8... done en_CA.UTF-8... done en_DK.UTF-8... done en_GB.UTF-8... done en_HK.UTF-8... done en_IE.UTF-8... done en_IN.UTF-8... done en_NG.UTF-8... done en_NZ.UTF-8... done en_PH.UTF-8... done en_SG.UTF-8... done en_US.UTF-8... done en_ZA.UTF-8... done en_ZM.UTF-8... done en_ZW.UTF-8... done Generation complete.
推出后,再次登录,检查locale
root@s15438266:~# locale locale: Cannot set LC_ALL to default locale: No such file or directory LANG=en_CA.UTF-8 LANGUAGE= LC_CTYPE="en_CA.UTF-8" LC_NUMERIC=zh_CN.UTF-8 LC_TIME=zh_CN.UTF-8 LC_COLLATE="en_CA.UTF-8" LC_MONETARY=zh_CN.UTF-8 LC_MESSAGES="en_CA.UTF-8" LC_PAPER=zh_CN.UTF-8 LC_NAME=zh_CN.UTF-8 LC_ADDRESS=zh_CN.UTF-8 LC_TELEPHONE=zh_CN.UTF-8 LC_MEASUREMENT=zh_CN.UTF-8 LC_IDENTIFICATION=zh_CN.UTF-8 LC_ALL=
还有一个问题,就是LC_ALL没有正确设置。现在设置一下:
root@s15438266:~# update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 perl: warning: Setting locale failed. perl: warning: Please check that your locale settings: LANGUAGE = (unset), LC_ALL = (unset), LC_PAPER = "zh_CN.UTF-8", LC_ADDRESS = "zh_CN.UTF-8", LC_MONETARY = "zh_CN.UTF-8", LC_NUMERIC = "zh_CN.UTF-8", LC_TELEPHONE = "zh_CN.UTF-8", LC_IDENTIFICATION = "zh_CN.UTF-8", LC_MEASUREMENT = "zh_CN.UTF-8", LC_TIME = "zh_CN.UTF-8", LC_NAME = "zh_CN.UTF-8", LANG = "en_CA.UTF-8" are supported and installed on your system. perl: warning: Falling back to the standard locale ("C").
然后再次推出,重新登录,检查:
root@s15438266:~# locale LANG=en_US.UTF-8 LANGUAGE= LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_PAPER="en_US.UTF-8" LC_NAME="en_US.UTF-8" LC_ADDRESS="en_US.UTF-8" LC_TELEPHONE="en_US.UTF-8" LC_MEASUREMENT="en_US.UTF-8" LC_IDENTIFICATION="en_US.UTF-8" LC_ALL=en_US.UTF-8
总结,下面两个命令很重要:
apt-get --reinstall install language-pack-en update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8似乎比前一篇我的博客中修改/etc/environment的方法更简单。