zoukankan      html  css  js  c++  java
  • 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)

    {

    
    										using (ChannelFactory<IIntercept> channelFactory = new
    										ChannelFactory<IIntercept>("calculateService"))

    {

    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对象。
    • OperationActionReplyAction*

    无论参数的个数,类型,次序是怎样的,但WCF的调用最终是基于Message的,也就是参数或返回值最终都会呈现为Message对象。

    Operation Selection的匹配规则是:Contract Namespacedefaulthttp://tempuri.org/Contract NamedefaultInterface name/Actiondefaultmethod name= action in SOAP header如果将Action设为"*",则意味着该服务的调用,无路SOAP Headeraction是什么,都将交付Intercept来处理。

    ChannelFactory构造函数的参数,是配置中,Client节点的endpoint的name值。

    AddressFilterMode = AddressFilterMode.Any:在上面我们提到过,ChannelDispatcher在选择EndpointDispacher的时候是基于两个Message FilterAddress FilterContract Filter。也就是说,ChannelDispatcher通过这两个Filter选择合适Endpoint。在默认的情况下,Address Filter是根据SOAPTo Message HeaderURI来进行栓选的,所以需要EndpointAddressTo Header中的Addres完全匹配。但是在我们CalculateService的例子中,由于Client最终是访问的时CalculateService,所以生成的SOAPTo Headler的地址是CalculateService的地址:http://127.0.0.1:9999/calculateservice,而我们需要是用InterceptService 来处理该请求,Address Filtering肯定是不能通过的。好在我们可以在ServiceBehavior设置AddressFilterMode 来改变Address Filtering的方式。AddressFilterMode = AddressFilterMode.Any意味着,Address Filtering会被忽略。

    CreateBufferedCopy:可能有人会奇怪,为什么不对request messageresponse message进行直接操作(将他们显示在TextBox上)?这是应为MessageWCF有一个特殊的处理机制:只有MessageStateCreated的时候,才能获取MessageBody的内容,否则会抛出异常。而我们在对Message进行相应操作的时候,会改变Message StateRead,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();

    }

    }

    }

    3Windows服务添加应用程序配置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的数据权限。

  • 相关阅读:
    安亦行
    [SCOI2010]连续攻击游戏 二分图匹配
    [USACO11JAN]Roads and Planes G
    CF796C Bank Hacking
    括号类问题总结 持续更新
    CF1216E Numerical Sequence Hard Version 数学
    POJ3613 Cow Relays 矩阵快速幂
    倍增法求lca(最近公共祖先)
    Codeforces C. Jzzhu and Cities(dijkstra最短路)
    Codeforces B. Mouse Hunt(强连通分解缩点)
  • 原文地址:https://www.cnblogs.com/msdynax/p/3778380.html
Copyright © 2011-2022 走看看