Dynamics AX 2012 R2 Service Middle Tier WCF WCF转发
参考了蒋金楠老师08年的文章。好吧,那时候我才大二、大三,大神果然是大神。 http://www.cnblogs.com/artech/archive/2008/09/01/1280939.html
在使用AX2012 AIF服务的时候,有一个问题一直困扰着我,那就是访问权限的认证。
众所周知AX2012的权限认证是基于AD的,但有些客户端机器的AD账户,并没有AX2012的访问权限,甚至没有加入AD中(如PDA客户端)。
按照微软的最佳实践,应该使用声明账户和可信中介这样两样技术,来实现客户端-》WCF中间层(可信中介)-》AIF服务。这样做好处,是客户端不用加入AD中,并且可以将客户端登陆账户权限的管理,纳入到AX中。
如果使用AX2012的自定义服务,会在AOS中有多个数据契约和服务操作,如果一个一个再在WCF中间层去重复造轮子,有些麻烦。能不能将中间层进行简化成,只是将客户端请求转发给AIF,将AIF的响应返回给客户端呢?
答案肯定是可以的咯,不然我也不会写这篇文章。具体可以参考上面蒋金楠老师博文的链接。
1新建一个WCF类库程序,代码如下:
|
namespace MessageInterceptor { [ServiceContract] public interface IIntercept { [OperationContract(Action ="*", ReplyAction="*")] Message Intercept(Message request); } [ServiceBehavior(UseSynchronizationContext = false, AddressFilterMode = AddressFilterMode.Any)] public class InterceptService : IIntercept { public System.ServiceModel.Channels.Message Intercept(System.ServiceModel.Channels.Message request) {
{ IIntercept interceptor = channelFactory.CreateChannel(); using (interceptor as IDisposable) { MessageBuffer requstBuffer = request.CreateBufferedCopy(int.MaxValue); Message response = interceptor.Intercept(requstBuffer.CreateMessage()); MessageBuffer responseBuffer = response.CreateBufferedCopy(int.MaxValue); Console.WriteLine(string.Format("Request:{0}{1}{0}", Environment.NewLine, request)); Console.WriteLine(string.Format("Response:{0}{1}{0}", Environment.NewLine, response)); return responseBuffer.CreateMessage(); } } } } } |
该数据契约有以下两个特点:
- Intercept的参数和返回值都是Message对象。
- Operation的Action和ReplyAction为*。
无论参数的个数,类型,次序是怎样的,但WCF的调用最终是基于Message的,也就是参数或返回值最终都会呈现为Message对象。
Operation Selection的匹配规则是:Contract Namespace(default:http://tempuri.org)/Contract Name(default:Interface name)/Action(default:method name)= action in SOAP header。如果将Action设为"*",则意味着该服务的调用,无路SOAP Header中action是什么,都将交付Intercept来处理。
ChannelFactory构造函数的参数,是配置中,Client节点的endpoint的name值。
AddressFilterMode = AddressFilterMode.Any:在上面我们提到过,ChannelDispatcher在选择EndpointDispacher的时候是基于两个Message Filter:Address Filter和Contract Filter。也就是说,ChannelDispatcher通过这两个Filter选择合适Endpoint。在默认的情况下,Address Filter是根据SOAP的To Message Header的URI来进行栓选的,所以需要Endpoint的Address和To Header中的Addres完全匹配。但是在我们CalculateService的例子中,由于Client最终是访问的时CalculateService,所以生成的SOAP的To Headler的地址是CalculateService的地址:http://127.0.0.1:9999/calculateservice,而我们需要是用InterceptService 来处理该请求,Address Filtering肯定是不能通过的。好在我们可以在ServiceBehavior设置AddressFilterMode 来改变Address Filtering的方式。AddressFilterMode = AddressFilterMode.Any意味着,Address Filtering会被忽略。
CreateBufferedCopy:可能有人会奇怪,为什么不对request message和response message进行直接操作(将他们显示在TextBox上)?这是应为Message在WCF有一个特殊的处理机制:只有Message的State为Created的时候,才能获取MessageBody的内容,否则会抛出异常。而我们在对Message进行相应操作的时候,会改变Message 的State(Read,Written,Copied,Closed)。所以对response message来讲,对message的显示实际上将Sate改为Read,如何将response message直接返回到client,对该message的读取操作将是不允许的,所以先调用CreateBufferedCopy创建该message的一个memory buffer,最有返回的时通过该buffer重新创建的Message。
2新建Windows服务,作为上面WCF服务的宿主程序。
代码如下:
|
namespace MiddleTierWcfWindowsService { public partial class Service : ServiceBase { ServiceHost host; public Service() { InitializeComponent(); } protected override void OnStart(string[] args) { host = new ServiceHost(typeof(MessageInterceptor.InterceptService)); host.Open(); } protected override void OnStop() { host.Close(); } } } |
3为Windows服务添加应用程序配置App.config
|
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <netTcpBinding> <binding name="aaaaaaaaa" /> </netTcpBinding> </bindings> <client> <endpoint address="net.tcp://bbbbbbbbb" binding="netTcpBinding" bindingConfiguration="aaaaaaaaa" contract="eeeeeeeee" name="ccccccccc"> </endpoint> </client> <services> <service name="HHHHHHHHH"> <endpoint binding="netTcpBinding" bindingConfiguration="aaaaaaaaa" contract="eeeeeeeee" address="net.tcp://ddddddddd"/> </service> </services> </system.serviceModel> </configuration> |
AAAAAAAAA:这里我使用了NetTcpBinding,作为客户端-》WCF中间层(可信中介)-》AIF服务端的终结点的binding,你也可以选择适合自己的。
BBBBBBBBB:这里是AIF中,服务的URI。
CCCCCCCCC:这里是上面WCF中间层类库接口的实现中,ChannelFactory构造函数的参数,本例中是calculateService。
DDDDDDDDD:这里是WCF中间层的终结点地址。
EEEEEEEEE:是client和service的contract契约,都使用的是WCF中间层类库中的接口的"命名空间+接口名"。本例子中是MessageInterceptor.IIntercept。
HHHHHHHHH:是接口的实现。本例中是MessageInterceptor.InterceptService 。
4设置Windows服务的Service设计视图的ServiceName,用于在日志中显示。
5在Windows服务的Service设计视图上点右键,添加安装程序。
6在新添加的安装程序中,将serviceProcessInstaller1的Account设为LocalService。即,启动时,以本地服务方式登录。
7将serviceInstaller1的Description,DisplayName,ServiceName,都设置下,用于在系统服务中显示。
8安装生成的服务。
9在系统服务中,找到该服务,右键,属性,登录,登录为AX中的系统服务账户,如BC账户,密码为BC账户的密码。
10客户端的配置文件里,新增一个终结点行为。
|
<system.serviceModel> <behaviors> <endpointBehaviors> <behavior name="FFFFFFFFF"> <clientVia viaUri="net.tcp://DDDDDDDDD" /> </behavior> </endpointBehaviors> </behaviors> <bindings> <netTcpBinding> <binding name="AAAAAAAAA" /> </netTcpBinding> </bindings> <client> <endpoint address="net.tcp://BBBBBBBBB" behaviorConfiguration="FFFFFFFFF" binding="netTcpBinding" bindingConfiguration="AAAAAAAAA" contract="GGGGGGGGG" name="CCCCCCCCC"> </endpoint> </client> </system.serviceModel> |
A、B、C、D、如上面所述。
FFFFFFFFF:终结点行为的名称。
GGGGGGGGG:AIF服务中,"命名空间+数据契约"的名字。本例为,MessageInterceptor.ICalculate
11结束
至此,WCF中间层的转发,已经设置好了。
在客户端,可以以context.LogonAsUser=aaa@bbb.com;的方法,用AX中的账户进行操作,系统会检查该账户的数据权限。在表中,记录的createdBy等系统字段,会显示为该AD用户的别名。
如果使用客户端的人员为一线工人,可能没有AX账户,所以此处建议不设置。表中的createdBy等系统字段,记录是BC账户的别名,使用的是BC的数据权限。
Dynamics AX 2012 R2 Service Middle Tier WCF WCF转发的更多相关文章
- Dynamics AX 2012 R2 电子邮件广播错误 0x80040213
Dynamics AX 2012 R2 电子邮件广播错误 0x80040213 今天Reinhard在新环境做邮件广播测试时,发现无法发送邮件,并报以下错误: 类"CDO.Message&q ...
- Dynamics AX 2012 R2 安装Reporting Services 扩展
今天Reinhard在VS中部署SSRS报表时,接到以下错误: 部署因错误而被取消.在报表服务器上,验证:-SQL Server Reporting Services 服务是否正在运行. 接着,Rei ...
- Dynamics AX 2012 R2 如何处理运行时间较长的报表
当处理的数据量较多,逻辑比较复杂时,报表可能会超时.为了解决这个问题,Reinhard一直使用SrsReportDataProviderPreProcess来做预处理报表.它会在调用SSRS前,在AX ...
- Dynamics AX 2012 R2 安装额外的AOS
众所周知,AX系统分为三层:Client,Application Server,Database Server. 我们添加额外的Application Server主要是出于以下两个原因: 使用多台服 ...
- Dynamics AX 2012 R2 业务系列-销售业务流程
在博文Dynamics AX R2 业务系列中,Reinhard对这个系列做了一个规划,下面我们就按照规划开始说业务吧. 1.销售的主要职责 其实这里说的职责主要是针对销售文员,并非整天外面满世界跑业 ...
- Dynamics AX 2012 R2 业务系列-采购业务流程
在博文Dynamics AX R2 业务系列中,Reinhard对这个系列做了一个规划,下面我们就按照规划开始说业务吧. 国际惯例,从采购开始. 1.采购的主要职责 简单点说,采购的主要职责,是从供应 ...
- Dynamics AX 2012 R2 安装 AIF IIS上的Web服务
1.为什么使用IIS上的WEB服务 组件? 如果你要在Dynamics AX Service中使用HTTP Adapter,那么你就要安装IIS上的WEB服务 组件.HTTP Adapter会在IIS ...
- Dynamics AX 2012 R2 业务系列
在之前的一系列博文里,Reinhard介绍了Dynamics AX Demo的安装与配置.相信同学们看完后,都已经成功拥有了一个测试环境. 众所周知的是,ERP作为一个特殊的软件系统,他有着背后的业务 ...
- [译]Dynamics AX 2012 R2 BI系列-规划分析的注意事项
https://msdn.microsoft.com/en-us/library/gg731898.aspx 在开始实施AX的分析特性前,有很多事情要考虑.本文描述了你必须考虑的事情,和在 ...
随机推荐
- 为什么玩VR眼镜会头晕?
为什么玩VR眼镜会头晕?看完本文你就懂了 很多用户都体验过各式各样的VR眼镜或者说头盔,但是不管哪一款,都很容易出现头晕的情况.相信大家都纳闷过,为什么玩VR眼镜会头晕?实际上这是和设备本身的技术 ...
- [转帖]Speed-BI数据分析案例:2016年8月汽车销量排行榜
[转帖]Speed-BI数据分析案例:2016年8月汽车销量排行榜 据中国汽车工业协会统计分析,2016年8月,乘用车市场表现较好,当月销量环比和同比均呈较快增长.1-8月,乘用车销量总体呈稳定增长, ...
- python_字符串
1. 字符串的格式化 格式: 说明: (1)转换说明符 (2)格式化操作符右操作数可以是任何东西,如果是元组的话,每一个元素都会被单独格式化. 2. 字符串常用的方法 (1)find int = fi ...
- span和div的区别
<span> 在CSS定义中属于一个行内元素,在行内定义一个区域,也就是一行内可以被 <span> 划分成好几个区域,从而实现某种特定效果. <span> 本身没有 ...
- Java中几种日志方案
.本文记录Java中几种常用的日志解决方案 0x01 Log4j .这应该是一个比较老牌的日志方案了,配置也比较简单,步骤如下 1)添加对应依赖,比如 Gradle 中 dependencies { ...
- 写了个pager, 可供参考
/* Author: Calos Description: patv2 pager !import: this pager goes with the time, we just temporaril ...
- csuoj 1111: 三家人
acm.csu.edu.cn/OnlineJudge/problem.php?id=1111 1111: 三家人 Time Limit: 1 Sec Memory Limit: 128 MBSubm ...
- [原创]java WEB学习笔记50:文件上传案例
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
- URAL 1001 Reverse Root(水题?)
The problem is so easy, that the authors were lazy to write a statement for it! Input The input stre ...
- 2.session与cookie的区别?
session:储存用户访问的全局唯一变量,存储在服务器上的php指定的目录中的(session_dir)的位置进行的存放 cookie:用来存储连续訪問一个頁面时所使用,是存储在客户端,对于Cook ...