欢迎光临
我们一直在努力

COM+ Web 服务:通过复选框路由到 XML Web Services(2) (微软中国)-.NET教程,Web Service开发

建站超值云服务器,限时71元/月

事务性组件示例

简单的计算器远算不上工作量繁重的业务应用程序,因此我们现在考虑带有对象池的适于 com+ 事务性组件的应用程序。
最容易管理和配置的组件是由 servicedcomponent 导出的托管代码组件,如以下 c# 示例所示:

using system;using system.reflection;using system.runtime.interopservices;using system.enterpriseservices;using system.data;using system.data.sqlclient;[assembly: applicationname("sctrans")][assembly: applicationactivation(activationoption.server,    soapvroot="sctrans")][assembly: assemblykeyfile("sctrans.snk")]namespace sctrans{  public interface isctrans  {   string countup (string key);  }  [objectpooling(minpoolsize=0, maxpoolsize=25)]  [justintimeactivation(true)]  [classinterface(classinterfacetype.autodual)]  [transactionattribute(transactionoption.requiresnew)]  public class sctranssqlnc : servicedcomponent, isctrans  {   [autocomplete]   public string countup (string key)   {      _command = new sqlcommand("", _connection);      _command.commandtype = commandtype.text;      _command.connection.open();     _command.commandtext = "update callcount with (rowlock) set       callcount = callcount + 1 where machine=" + key + "";     _command.executenonquery();      _command.connection.close();     _numcalls++;     return (_numcalls + " nc " + _guid);   }    protected override bool canbepooled()   {     return true;    }   private int _numcalls = 0;   private string _guid = guid.newguid().tostring();   private sqlconnection _connection =    new sqlconnection("user id=myuser;password=my!password;   database=soaptest;server=myserver");   private sqlcommand _command;      }}

要建立并运行此 c# 组件,在完成编辑连接值以连接到 microsoft sql server™ 数据库之后,需要使用 sn.exe 生成 sctrans.snk 加强名称关键字文件,然后在 using 语句中使用程序集引用对其进行编译。如果您在服务器上进行部署,应使用 gacutil.exe(如果正在使用 sdk)或通过 .net 框架用户界面将程序集放入 gac,然后运行 regsvcs.exe,注册 com+ 托管组件。regsvcs.exe 将使用以下属性,将组件发布为服务器上的 soap 端点和服务器(进程外)激活:

[assembly: applicationactivation(activationoption.server,    soapvroot="cssoapsql")]

此组件在每种方法调用中使用不同的事务,具有一个自动完成方法,并被配置为进行缓冲。使用托管和非托管 com+ 组件时,对象池和事务将如所预期的那样通过 soap 运行。例如,如果使用下列 vbscript 通过 soap 访问以下 servicedcomponent

mon = "soap:wsdl=http://jnoss3/sctrans/sctrans.sctranssqlnc.soap?wsdl"wscript.echo(mon)for i = 1 to 2 set c = getobject(mon) for j = 1 to 10  wscript.echo i & " " & j & " " & c.countup("scwkonc")  nextnext

将显示以下输出内容:

c:\moniker>actscwkomicrosoft (r) windows script host version 5.6copyright (c) microsoft corporation 1996-2001. all rights reserved.soap:wsdl=http://jnoss3/sctrans/sctrans.sctranssqlnc.soap?wsdl1 1 486 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 1 2 487 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 1 3 488 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 1 4 489 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 1 5 490 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 1 6  8 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 1 7  9 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 1 8 10 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 1 9 494 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 1 10 495 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 2 1 13 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 2 2 14 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 2 3 15 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 2 4 499 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 2 5 17 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 2 6 501 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 2 7 502 nc 6e41f32f-74be-45f0-94c0-989e7e1c5672 2 8 19 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 2 9 20 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 2 10 21 nc af26b53b-4a1f-48c8-8880-518c2b55a7ce 

这就是所预期的缓冲的组件:从缓冲池中拖出对象并重新使用。使用客户端激活的缓冲组件的行为都是相同的。
非托管组件的对象池和事务也如所预期的那样运行(虽然 visual basic 6.0 组件不支持对象池)。需要为大多数非托管应用程序通过 com+ 管理工具设置缓冲和事务属性。

传递引用

wko 与 cao 模型的一个关键区别在于它们向有状态的对象传递引用的能力。以下是 c# servicedcomponent 示例,显示了此操作的基本步骤:

using system;using system.reflection;using system.enterpriseservices;using system.runtime.interopservices;[assembly: applicationname("refpass")][assembly: applicationactivation(activationoption.server,    soapvroot="refpass")][assembly: assemblykeyfile("refpass.snk")]namespace refpass{  public interface iparent  {    string setref(object inkid);    object getref();    string countup(object obj);   }  public interface ichild  {    string getvalue ();    string countup();    void setname(string key);  }  [classinterface(classinterfacetype.autodual)]  public class parent: servicedcomponent, iparent  {    protected child _kid = null;    public string setref(object inkid)    {      _kid = (child)inkid;      return _kid.getvalue();    }    public object getref()    {      return (object)_kid;    }    public string countup(object obj)    {      child kid = (child)obj;      if (kid == null) return _kid.countup();      else return kid.countup();    } }  [classinterface(classinterfacetype.autodual)]  public class child : servicedcomponent, ichild  {    private int _counter = 0;    private string _name = "none";    public string countup() { _counter++; return getvalue(); }    public string getvalue() { return (_name + " "    +_counter.tostring()); }    public void setname(string key) { _name = key; }  }}

此 c# 程序有两个类:childparent。如果运行以下 vbscript 示例,wko 与 cao 模型的区别会更加明显:

set c1 = getobject   ("soap:wsdl=http://jnoss4/refpass/refpass.child.soap?wsdl")set c2 = getobject   ("soap:wsdl=http://jnoss4/refpass/refpass.child.soap?wsdl")c1.setname("c1")wscript.echo c1.countup()wscript.echo c1.countup()wscript.echo c1.countup()wscript.echo c1.countup()wscript.echo c1.countup()c2.setname("c2")wscript.echo c2.countup()wscript.echo c2.countup()wscript.echo c2.countup()wscript.echo c2.countup()wscript.echo c2.countup()

运行时将显示以下输出内容:

c:\moniker>refpasswkomicrosoft (r) windows script host version 5.6copyright (c) microsoft corporation 1996-2001. all rights reserved.none 1none 1none 1none 1none 1none 1none 1none 1none 1none 1

名称和值说明了单一调用已知对象的无状态性质,因为组件是使用不同的方法调用创建的,所以方法调用之间不保留名称或值。
如果导出客户端代理,然后导入到另一台客户端计算机上,并且运行了下面的 vbscript,则 soap 激活将是 cao 而不是 wko:

直接创建两个对象set c1=createobject("refpass.child")set c2=createobject("refpass.child")设置第一个对象的名称,并调用数次以递增对象内部计数器c1.setname("c1")wscript.echo c1.countup()wscript.echo c1.countup()wscript.echo c1.countup()wscript.echo c1.countup()wscript.echo c1.countup()设置第一个对象的名称,并调用数次以递增对象内部计数器c2.setname("c2")wscript.echo c2.countup()wscript.echo c2.countup()wscript.echo c2.countup()wscript.echo c2.countup()wscript.echo c2.countup()创建父对象set p=createobject("refpass.parent")将子对象传递到父对象,并从父对象调用子对象wscript.echo p.setref(c1)wscript.echo p.countup(c2)wscript.echo p.countup(c2)wscript.echo p.countup(c2)wscript.echo p.countup(c2)现在调用存储在父对象内部的子对象dim c9wscript.echo p.countup(c9)从父对象获取该对象并直接调用set c3 = p.getref()wscript.echo c3.countup()

从命令行运行时,将显示以下输出内容:

c:\moniker>refpassclmicrosoft (r) windows script host version 5.6copyright (c) microsoft corporation 1996-2001. all rights reserved.c1 1c1 2c1 3c1 4c1 5c2 1c2 2c2 3c2 4c2 5c1 5c2 6c2 7c2 8c2 9c1 6c1 7

即使在通过 soap 调用时,cao 激活也会保留状态,并且允许通过 soap 来回传递对象引用。名称和值都保留在服务器上的类实例中,并且引用可以正确工作。这两种脚本都调用相同的编译 c# 组件,只是 .net remoting 激活模型不同。
除了使用 createobject 调用 cao 激活外,还可以使用带有 com+ 的名字对象,它可以提供 cao 激活来替代 wko(类型名称和程序集名字对象)。以下脚本:

直接创建两个对象set c1=getobject("soap:typename=refpass.child,assembly=refpass")set c2=getobject("soap:typename=refpass.child,assembly=refpass")设置第一个对象的名称,并调用数次以递增对象内部计数器c1.setname("c1")wscript.echo c1.countup()wscript.echo c1.countup()wscript.echo c1.countup()wscript.echo c1.countup()wscript.echo c1.countup()设置第二个对象的名称,并调用数次以递增对象内部计数器c2.setname("c2")wscript.echo c2.countup()wscript.echo c2.countup()wscript.echo c2.countup()wscript.echo c2.countup()wscript.echo c2.countup()创建父对象set p=getobject("soap:typename=refpass.parent,assembly=refpass")将子对象传递到父对象,并从父对象调用子对象wscript.echo p.setref(c1)wscript.echo p.countup(c2)wscript.echo p.countup(c2)wscript.echo p.countup(c2)wscript.echo p.countup(c2)现在调用存储在父对象内部的子对象dim c9wscript.echo p.countup(c9)从父对象获取该对象并直接调用set c3 = p.getref()wscript.echo c3.countup()

将显示以下输出内容:

c:\moniker>refpasscamicrosoft (r) windows script host version 5.6copyright (c) microsoft corporation 1996-2001. all rights reserved.c1 1c1 2c1 3c1 4c1 5c2 1c2 2c2 3c2 4c2 5c1 5c2 6c2 7c2 8c2 9c1 6c1 7

这与上面的 vbscript createobject(progid) 示例的输出内容相同。因为常规 com+ 激活路径被 soap 代理应用程序截获,所以可以使用 cocreateinstancecreateinstance 以及其他传统的 com+ 激活方法来调用使用 com+ web 服务的客户端激活的对象。
程序集和类型名称名字对象,对于从托管代码客户端远程获取预先配置的客户端激活也很有用,如下例所示:

imports systemimports system.runtime.interopservicesmodule refpassclsub main()    dim childmoniker = "soap:assembly=refpass,typename=refpass.child"    dim parentmoniker = "soap:assembly=refpass,typename=refpass.parent"    dim c1,c2,p as object    c1 = marshal.bindtomoniker(childmoniker)    console.writeline(c1.setname("c1"))    console.writeline(c1.countup())    console.writeline(c1.countup())    console.writeline(c1.countup())    console.writeline(c1.countup())    console.writeline(c1.countup())    c2 = marshal.bindtomoniker(childmoniker)    console.writeline(c2.setname("c2"))    console.writeline(c2.countup())    console.writeline(c2.countup())    console.writeline(c2.countup())    console.writeline(c2.countup())    console.writeline(c2.countup())    p = marshal.bindtomoniker(parentmoniker)    console.writeline(p.setref(c1))    console.writeline(p.countup(c2))    console.writeline(p.countup(c2))    console.writeline(p.countup(c2))    console.writeline(p.countup(c2))    dim c9    console.writeline(p.countup(c9))    dim c3 = p.getref()    console.writeline(c3.countup()) end subend module

编译并运行此 visual basic .net 应用程序,将产生与前面两个 vbscript cao 示例相同的输出内容。
因为服务器应用程序将组件发布为 cao 和 wko 两种形式,所以由远程客户端选择激活方法。虽然可能只对学术研究有意义,但是单一客户端计算机确实可以使用同一组件的两种远程激活方法,访问远程服务器上同一个 soap 发布的虚拟根。

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » COM+ Web 服务:通过复选框路由到 XML Web Services(2) (微软中国)-.NET教程,Web Service开发
分享到: 更多 (0)