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的数据权限。

  • 相关阅读:
    Java Output流写入包装问题
    SpringBoot项目单元测试不经过过滤器问题
    SpringSecurity集成启动报 In the composition of all global method configuration, no annotation support was actually activated 异常
    JWT jti和kid属性的说明
    Maven 排除依赖
    第五章 基因概念的发现
    第三章 孟德尔遗传的拓展
    第二章 孟德尔遗传
    第一章 引言
    GWAS全基因组关联分析
  • 原文地址:https://www.cnblogs.com/msdynax/p/3778380.html
Copyright © 2011-2022 走看看