第一篇:java 調用webservice的各種方法總結
一、利用jdk web服務api實現,這里使用基于 SOAP message 的 Web 服務
1.首先建立一個Web services EndPoint:
Java代碼
package Hello;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.xml.ws.Endpoint;
@WebService
public class Hello {
@WebMethod
public String hello(String name){
return “Hello, ” + name + “n”;}
public static void main(String[] args){
// create and publish an endpoint
Hello hello = new Hello();
Endpoint endpoint Endpoint.publish(“http://localhost:8080/hello”, hello);
} }
=
2.使用 apt 編譯 Hello.java(例:apt-d [存放編譯后的文件目錄] Hello.java),會生成 jaws目錄
3.使用java Hello.Hello運行,然后將瀏覽器指向http://localhost:8080/hello?wsdl就會出現下列顯示
4.使用wsimport 生成客戶端
使用如下:wsimport-p.-keep http://localhost:8080/hello?wsdl
5.客戶端程序:
Java代碼
1.class HelloClient{ 2.3.public static void main(String args[]){ 4.5.HelloService service = new HelloService();6.7.Hello helloProxy = service.getHelloPort();8.9.String hello = helloProxy.hello(“你好”);10.11.System.out.println(hello);12.13.} 14.15.} 16.二、使用xfire,我這里使用的是myeclipse集成的xfire進行測試的
利用xfire開發WebService,可以有三種方法:
1一種是從javabean 中生成;
一種是從wsdl文件中生成;
還有一種是自己建立webservice
步驟如下:
用myeclipse建立webservice工程,目錄結構如下:
首先建立webservice接口,代碼如下:
Java代碼
1.package com.myeclipse.wsExample;2.3.//Generated by MyEclipse 4.5.6.7.public interface IHelloWorldService { 8.9.10.11.public String example(String message);12.13.14.15.} 16.Java代碼
1.package com.myeclipse.wsExample;2.3.//Generated by MyEclipse 4.5.6.7.public class HelloWorldServiceImpl implements IHelloWorldService { 8.9.10.11.public String example(String message){ 12.13.return message;14.15.} 16.17.18.19.} 20.修改service.xml 文件,加入以下代碼:
Xml代碼
1.2.3.
客戶端實現如下:
Java代碼
1.package com.myeclipse.wsExample.client;2.3.import java.net.MalformedURLException;4.5.import java.net.URL;6.7.8.9.import org.codehaus.xfire.XFireFactory;10.11.import org.codehaus.xfire.client.Client;12.13.import org.codehaus.xfire.client.XFireProxyFactory;14.15.import org.codehaus.xfire.service.Service;16.17.import org.codehaus.xfire.service.binding.ObjectServiceFactory;18.19.20.21.import com.myeclipse.wsExample.IHelloWorldService;22.23.24.25.public class HelloWorldClient { 26.27.public static void main(String[] args)throws MalformedURLException, Exception { 28.29.// TODO Auto-generated method stub 30.31.Service s=new ObjectServiceFactory().create(IHelloWorldService.class);32.33.XFireProxyFactory xf=new XFireProxyFactory(XFireFactory.newInstance().getXFire());34.35.String url=“http://localhost:8989/HelloWorld/services/HelloWorldService”;36.37.38.39.try 40.41.{ 42.43.44.45.IHelloWorldService hs=(IHelloWorldService)xf.create(s,url);46.47.String st=hs.example(“zhangjin”);48.49.System.out.print(st);50.51.} 52.53.catch(Exception e)54.55.{ 56.57.e.printStackTrace();58.59.} 60.61.} 62.63.64.65.} 66.這里再說點題外話,有時候我們知道一個wsdl地址,比如想用java客戶端引用.net 做得webservice,使用myeclipse引用,但是卻出現無法通過驗證的錯誤,這時我們可以直接在類中引用,步驟如下:
Java代碼
1.public static void main(String[] args)throws MalformedURLException, Exception { 2.3.// TODO Auto-generated method stub 4.5.Service s=new ObjectServiceFactory().create(IHelloWorldService.class);6.7.XFireProxyFactory xf=new XFireProxyFactory(XFireFactory.newInstance().getXFire());8.9.10.11.//遠程調用.net開發的webservice 12.13.Client c=new Client(new URL(“http://www.tmdps.cn/axis2/
同理,也需要將axis2復制到webapp目錄中
在axis2中部署webservice有兩種方法,第一種是pojo方式,這種方式比較簡單,但是有一些限制,例如部署的類不能加上包名
第二種方式是利用xml發布webservice,這種方法比較靈活,不需要限制類的聲明
下面分別說明使用方法:
1.pojo方式:在Axis2中不需要進行任何的配置,就可以直接將一個簡單的POJO發布成WebService。其中POJO中所有的public方法將被發布成WebService方法。先實現一個pojo類:
Java代碼
1.public class HelloWorld{ 2.3.public String getName(String name)4.5.{ 6.7.return ”你好 “ + name;8.9.} 10.11.public int add(int a,int b)12.13.{ 14.15.return a+b;16.17.} 18.19.} 20.由于這兩個方法都是public類型,所以都會發布成webservice。編譯HelloWorld類后,將HelloWorld.class文件放到%tomcat%webappsaxis2WEB-INFpojo目錄中(如果沒有pojo目錄,則建立該目錄),然后打開瀏覽器進行測試:
輸入一下url:
http://localhost:8080/axis2/services/listServices
會列出所有webservice
這是其中的兩個webservice列表,接著,在客戶端進行測試:
首先可以寫一個封裝類,減少編碼,代碼如下:
Java代碼
1.package MZ.GetWebService;2.3.import javax.xml.namespace.QName;4.5.6.7.import org.apache.axis2.AxisFault;8.9.import org.apache.axis2.addressing.EndpointReference;10.11.import org.apache.axis2.client.Options;12.13.import org.apache.axis2.rpc.client.RPCServiceClient;14.15.16.17.18.19.public class GetWSByAxis2 { 20.21.private static String EndPointUrl;22.23.private static String QUrl=”http://ws.apache.org/axis2“;
24.25.private QName opAddEntry;26.27.public String WSUrl;28.29.public RPCServiceClient setOption()throws AxisFault 30.31.{ 32.33.RPCServiceClient serviceClient = new RPCServiceClient();34.35.Options options = serviceClient.getOptions();36.37.EndpointReference targetEPR = new EndpointReference(WSUrl);38.39.options.setTo(targetEPR);40.41.return serviceClient;42.43.} 44.45.46.47.public QName getQname(String Option){ 48.49.50.51.return new QName(QUrl,Option);52.53.} 54.55.//返回String 56.57.public String getStr(String Option)throws AxisFault 58.59.{ 60.61.RPCServiceClient serviceClient =this.setOption();62.63.64.65.opAddEntry =this.getQname(Option);66.67.68.69.String str =(String)serviceClient.invokeBlocking(opAddEntry, 70.71.new Object[]{}, new Class[]{String.class })[0];72.73.return str;74.75.} 76.77.// 返回一維String數組 78.79.public String[] getArray(String Option)throws AxisFault
80.81.{ 82.83.RPCServiceClient serviceClient =this.setOption();84.85.86.87.opAddEntry =this.getQname(Option);88.89.90.91.String[] strArray =(String[])serviceClient.invokeBlocking(opAddEntry, 92.93.new Object[]{}, new Class[]{String[].class })[0];94.95.return strArray;96.97.} 98.99.//從WebService中返回一個對象的實例
100.101.public Object getObject(String Option,Object o)throws AxisFault 102.103.{ 104.105.RPCServiceClient serviceClient =this.setOption();106.107.QName qname=this.getQname(Option);108.109.Object object = serviceClient.invokeBlocking(qname, new Object[]{},new Class[]{o.getClass()})[0];110.111.return object;112.113.} 114.115.116.117.///////////////////////////////////////// 讀者可以自己封裝數據類型,如int,byte,float等數據類型
118.119.} 120.客戶端調用方法:
Java代碼
1.MZ.GetWebService.GetWSByAxis2 ws=new MZ.GetWebService.GetWSByAxis2();2.3.ws.WSUrl=”http://localhost:8989/axis2/services/HelloWorld“;4.5.HelloWorld hello=(HelloWorld)ws.getObject(”getName“, HelloWorld.class);6.7.8.9.10.11.System.out.println(hello.getName(”zhangjin“));12.2.使用service.xml發布webservice,這種方式和直接放在pojo目錄中的POJO類不同。要想將MyService類發布成Web Service,需要一個services.xml文件,這個文件需要放在META-INF目錄中,該文件的內容如下:
Xml代碼
1.
http://localhost:8080/axis2/services/myService?wsdl
除此之外,還有直接可以在其中制定webservice操作方法:可以這樣些service.xml文件
Java代碼
1. 10.11.service.HelloWorld 12.13. 14.15.
第二篇:個人對Java構造方法調用的總結(精選)
個人對Java構造方法調用的總結
1.構造方法必須與定義它的類有完全相同的名字。構造方法沒有返回類型,也沒有void。
2.類可以不聲明構造方法,這時類中隱含聲明了一個方法體為空的無參構造方法。但當類有明確聲明構造方法時,它就不會自動生成。
3.構造方法的調用:子類首先要調用父類的構造方法才能繼承父類的屬性和方法。如果子類的構造方法中沒有顯式地調用父類的構造方法,則系統默認調用父類無參數的構造方法。說說3種情況:
①父類和子類都沒有顯式定義構造方法或者只定義了無參構造方法,這種情況下沒有問題,Java 會順著繼承結構往上一直找到 Object,然后從 Object 開始往下依次執行構造函數。以下兩個例子效果一樣,只是Example2有相關輸出: Example1 public class test1 { public static void main(String[] args){
A example =new A();} }
class A extends B{ } class B{ }
Example2:
public class test { public static void main(String[] args){
A example =new A();} }
class A extends B{ public A(){
System.out.println(“A's constructor is invoked.”);} } class B{ public B(){ System.out.println(“B's constructor is invoked.”);} } 輸出:B's constructor is invoked
A's constructor is invoked
②父類只定義有參構造方法,那么無論子類如何定義,編譯都會報錯,因為父類缺少了默認無參構造方法,需要顯式定義。
public class test { public static void main(String[] args){
A example =new A(3);} }
class A extends B{ public A(int a){
System.out.println(“A's constructor is invoked.”+“a=”+a);} }
class B{ private int b=0;//public B(){ // System.out.println(“B's constructor is invoked.”);//}
public B(int b){
System.out.println(“B's constructor is invoked.”+“b=”+b);} } 把注釋符去掉就可以編譯,輸出:B's constructor is invoked.A's constructor is invoked.a=3
③在父類只有有參構造方法而沒有無參構造方法時,可以用super(參數)來調用父類構造方法,但super無參時需要父類的無參構造方法。public class test { public static void main(String[] args){
A example =new A(3);} }
class A extends B{ public A(int a){
super(a);
System.out.println(“A's constructor is invoked.”+“a=”+a);} } class B{ private int b=0;
public B(int b){
System.out.println(“B's constructor is invoked”+“b=”+b);} } 輸出:B's constructor is invoked.b=3 A's constructor is invoked.a=3 此處指定用super(3)調用public B(int b),所以就有如下輸出: B's constructor is invoked.b=3 A's constructor is invoked.a=3
第三篇:用java調用oracle存儲過程總結
用java調用oracle存儲過程總結
分類: PL/SQL系列 2009-09-24 15:08 253人閱讀 評論(0)收藏 舉報
聲明:
以下的例子不一定正確,只是為了演示大概的流程。
一:無返回值的存儲過程 存儲過程為:
CREATE OR REPLACE PROCEDURE TESTA(PARA1 IN VARCHAR2,PARA2 IN VARCHAR2)AS BEGIN
INSERT INTO HYQ.B_ID(I_ID,I_NAME)VALUES(PARA1, PARA2);END TESTA;
然后呢,在java里調用時就用下面的代碼: package com.hyq.src;
import java.sql.*;import java.sql.ResultSet;
public class TestProcedureOne {
public TestProcedureOne(){
}
public static void main(String[] args){
String driver = “oracle.jdbc.driver.OracleDriver”;
String strUrl = “jdbc:oracle:thin:@127.0.0.1:1521: hyq ”;
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
CallableStatement cstmt = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(strUrl, “ hyq ”, “ hyq ”);
CallableStatement proc = null;
proc = conn.prepareCall(“{ call HYQ.TESTA(?,?)}”);
proc.setString(1, “100”);
proc.setString(2, “TestOne”);
proc.execute();
}
catch(SQLException ex2){
ex2.printStackTrace();
}
catch(Exception ex2){
ex2.printStackTrace();
}
finally{
try {
if(rs!= null){
rs.close();
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
}
}
catch(SQLException ex1){
}
}
} }
二:有返回值的存儲過程(非列表)
當然了,這就先要求要建張表TESTTB,里面兩個字段(I_ID,I_NAME)。
存儲過程為: CREATE OR REPLACE PROCEDURE TESTB(PARA1 IN VARCHAR2,PARA2 OUT VARCHAR2)AS BEGIN
SELECT INTO PARA2 FROM TESTTB WHERE I_ID= PARA1;END TESTB;
在java里調用時就用下面的代碼: package com.hyq.src;
public class TestProcedureTWO {
public TestProcedureTWO(){
}
public static void main(String[] args){
String driver = “oracle.jdbc.driver.OracleDriver”;
String strUrl = “jdbc:oracle:thin:@127.0.0.1:1521:hyq”;
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(strUrl, “ hyq ”, “ hyq ”);
CallableStatement proc = null;
proc = conn.prepareCall(“{ call HYQ.TESTB(?,?)}”);
proc.setString(1, “100”);
proc.registerOutParameter(2, Types.VARCHAR);
proc.execute();
String testPrint = proc.getString(2);
System.out.println(“=testPrint=is=”+testPrint);
}
catch(SQLException ex2){
ex2.printStackTrace();
}
catch(Exception ex2){
ex2.printStackTrace();
}
finally{
try {
if(rs!= null){
rs.close();
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
}
}
catch(SQLException ex1){
}
}
} }
}
注意,這里的proc.getString(2)中的數值2并非任意的,而是和存儲過程中的out列對應的,如果out是在第一個位置,那就是proc.getString(1),如果是第三個位置,就是proc.getString(3),當然也可以同時有多個返回值,那就是再多加幾個out參數了。
三:返回列表
由于oracle存儲過程沒有返回值,它的所有返回值都是通過out參數來替代的,列表同樣也不例外,但由于是集合,所以不能用一般的參數,必須要用pagkage了.所以要分兩部分,1,建一個程序包。如下:
CREATE OR REPLACE PACKAGE TESTPACKAGE AS
TYPE Test_CURSOR IS REF CURSOR;end TESTPACKAGE;
2,建立存儲過程,存儲過程為:
CREATE OR REPLACE PROCEDURE TESTC(p_CURSOR out TESTPACKAGE.Test_CURSOR)IS BEGIN
OPEN p_CURSOR FOR SELECT * FROM HYQ.TESTTB;END TESTC;
可以看到,它是把游標(可以理解為一個指針),作為一個out 參數來返回值的。在java里調用時就用下面的代碼: package com.hyq.src;import java.sql.*;
import java.io.OutputStream;import java.io.Writer;
import java.sql.PreparedStatement;import java.sql.ResultSet;import oracle.jdbc.driver.*;
public class TestProcedureTHREE {
public TestProcedureTHREE(){
}
public static void main(String[] args){
String driver = “oracle.jdbc.driver.OracleDriver”;
String strUrl = “jdbc:oracle:thin:@127.0.0.1:1521:hyq”;
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(strUrl, “hyq”, “hyq”);
CallableStatement proc = null;
proc = conn.prepareCall(“{ call hyq.testc(?)}”);
proc.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);
proc.execute();
rs =(ResultSet)proc.getObject(1);
while(rs.next())
{
System.out.println(“
}
}
catch(SQLException ex2){
ex2.printStackTrace();
}
catch(Exception ex2){
ex2.printStackTrace();
}
finally{
try {
if(rs!= null){
rs.close();
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
}
}
catch(SQLException ex1){
}
}
} }
四。Hibernate調用存儲過程
Connection con = session.connect();
CallableStatement proc = null;
con = connectionPool.getConnection();
proc = con.prepareCall(“{ call set_death_age(?, ?)}”);proc.setString(1, XXX);
proc.setInt(2, XXx);...proc.execute();
session.close();
在Hibernate中調用存儲過程的示范代碼--
如果底層數據庫(如Oracle)支持存儲過程,也可以通過存儲過程來執行批量更新。存儲過程直接在數據庫中運行,速度更加快。在Oracle數據庫中可以定義一個名為batchUpdateStudent()的存儲過程,代碼如下:
create or replace procedure batchUpdateStudent(p_age in number)as begin update STUDENT set AGE=AGE+1 where AGE>p_age;end;以上存儲過程有一個參數p_age,代表學生的年齡,應用程序可按照以下方式調用存儲過程: tx = session.beginTransaction();Connection con=session.connection();String procedure = “{call batchUpdateStudent(?)}”;CallableStatement cstmt = con.prepareCall(procedure);cstmt.setInt(1,0);//把年齡參數設為0 cstmt.executeUpdate();tx.commit();在以上代碼中,我用的是Hibernate的 Transaction接口來聲明事務,而不是采用JDBC API來聲明事務。
存儲過程中有一個參數p_age,代表客戶的年齡,應用程序可按照以下方式調用存儲過程:
代碼內容
tx = session.beginTransaction();Connection con=session.connection();
String procedure = “{call batchUpdateCustomer(?)}”;
CallableStatement cstmt = con.prepareCall(procedure);
cstmt.setInt(1,0);//把年齡參數設為0
cstmt.executeUpdate();
tx.commit();
CREATE procedure selectAllUsers DYNAMIC RESULT SETS 1 BEGIN
DECLARE temp_cursor1 CURSOR WITH RETURN TO CLIENT FOR
SELECT * FROM test;
OPEN temp_cursor1;END;
映射文件中關于存儲過程內容如下
............
{ ? = call selectAllUsers()}
{ ? = call selectAllUsers()} 也可以寫成{ call selectAllUsers()},如果有參數就寫成
{ ? = call selectAllUsers(?,?,?)}
代碼中對query設置相應位置上的值就OK Java調用關鍵代碼如下
Session session = HibernateUtil.currentSession();
Query query = session.getNamedQuery(“selectAllUsers”);
List list = query.list();
System.out.println(list);
要求你的存儲過程必須能返回記錄集,否則要出錯
如果你的存儲過程是完成非查詢任務就應該在配置文件用以下三個標簽
setFirstResult(int)和setMaxResults(int)方法來分頁
第四篇:webService基礎總結
? WebService是一種跨編程語言和跨操作系統平臺的遠程調用技術
? 所謂跨編程語言和跨操作平臺,就是說服務端程序采用java編寫,客戶端程序則可以采用其他編程語言編寫,反之亦然!跨操作系統平臺則是指服務端程序和客戶端程序可以在不同的操作系統上運行。? 除了WebService外,常見的遠程調用技術還有RMI(Remote method invoke)和CORBA,由于WebService的跨平臺和跨編程語言特點,因此比其他兩種技術應用更為廣泛,但性能略低。
? WebService使用SOAP協議實現跨編程語言和跨操作系統平臺
? WebService采用HTTP協議傳輸數據,采用XML格式封裝數據(即XML中說明調用遠程服務對象的哪個方法,傳遞的參數是什么,以及服務對象的返回結果是什么)。WebService通過HTTP協議發送請求和接收結果時,發送的請求內容和結果內容都采用XML格式封裝,并增加了一些特定的HTTP消息頭,以說明HTTP消息的內容格式,這些特定的HTTP消息頭和XML內容格式就是SOAP協議(simple object access protocol,簡單對象訪問協議)。
? SOAP協議 = HTTP協議 + XML數據格式
? HTTP協議和XML是被廣泛使用的通用技術,各種編程語言對HTTP協議和XML這兩種技術都提供了很好的支持,WebService客戶端與服務器端使用什么編程語言都可以完成SOAP的功能,所以,WebService很容易實現跨編程語言,跨編程語言自然也就跨了操作系統
? WebService客戶端要調用一個WebService服務,首先要有知道這個服務的地址在哪,以及這個服務里有什么方法可以調用,所以,WebService務器端首先要通過一個WSDL文件來說明自己家里有啥服務可以對外調用,服務是什么(服務中有哪些方法,方法接受的參數是什么,返回值是什么),服務的網絡地址用哪個url地址表示,服務通過什么方式來調用。? WSDL(webservice description language)是基于XML格式的,它是WebService客戶端和服務器端都能理解的標準格式,其中描述的信息可以分為what,where,how等部分!? WSDL文件保存在Web服務器上,通過一個url地址就可以訪問到它。客戶端要調用一個WebService服務之前,要知道該服務的WSDL文件的地址。WebService服務提供商可以通過兩種方式來暴露它的WSDL文件地址:
? 注冊到UDDI服務器,以便被人查找 ? 直接告訴給客戶端調用者,例如,在自己網站給出信息或郵件告訴。
第五篇:調用外部方法及工作流
調用外部方法及工作流
公開一個對象,來從執行的工作流中傳給宿主應用程序,或者從宿主應用程序傳給工作流不就行了嗎?其實,使用現有的串行化技術,如.NET Remoting或者XML Web服務,就可完成這些事。串行化,也叫序列化,它可把數據從原有的形式轉換成合適的形式,以在不同進程甚至不同計算機之間進行傳輸。
學習完本章,你將掌握:
1.創建并調用你的工作流外部的本地數據服務
2.理解怎樣使用接口來為宿主進程和你的工作流之間進行通信。
3.使用設計的外部方法在你的工作流和宿主應用程序之間傳輸數據。
4.在一個正執行的工作流中調用其它工作流
在寫前面的章節時,我自己不斷地思考,“我不能再等了,我要弄清楚在哪里可把(工作流中的)真實數據返回到宿主應用程序中!”為什么?做了這么多的活動和工作流的演示,但都沒有實際返回某些感興趣的東西給宿主應用程序。我不知寫過多少我們感興趣的工作流的實例和演示,但至多只是僅僅處理過數據的初始化(就像第一章-WF簡介中你看過的郵政編碼的例子)。但事情變得更加有趣,坦率地說,當我們啟動工作流,然后從外部源中尋找并處理數據、返回處理后的數據給我們的主應用程序要更加接近現實。
為什么不這樣呢?公開一個對象,來從執行的工作流中傳給宿主應用程序,或者從宿主應用程序傳給工作流不就行了嗎?其實,使用現有的串行化技術,如.NET Remoting或者XML Web服務,就可完成這些事。串行化,也叫序列化,它可把數據從原有的形式轉換成合適的形式,以在不同進程甚至不同計算機之間進行傳輸。
為什么談到序列化呢?因為你的工作流是在你的宿主進程中的不同線程上執行,不同線程之間傳送數據,如不進行適當的序列化,將會引發災難,具體原因超出了本書的討論范圍。其實,你的工作流能在一個持久化的狀態下發送它的數據。這并沒有在不同線程上,甚至它不在執行中。
但我們想在我們的工作流和正控制該工作流的宿主進程間傳送數據時,使用.NET Remoting或者XML Web服務這樣的技術為什么并沒有認為是多余的呢?其實這絕對有必要!我們將創建local通信,本章將以此出發。我們將搭建必須的體系來滿足線程數據序列化,以進行計算機之間或進程之間的數據傳輸。
創建ExternalDataService服務
當工作流和它的宿主進行通信時,在它發送和接收數據的時候,工作流要使用隊列和消息。WF為我們做的越多,我們就可把重點更多的放到應用中特定任務的解決上。
工作流內部進程通信
對于簡單的通信任務,WF使用“abstraction layer”來在工作流和宿主之間進行緩沖。抽象層像一個黑盒,你為它提供輸入,它會執行一些神奇的任務,然后信息流出到另一邊。但我們不用知道它是如何工作的。
在這種情形下,該黑盒就是一個知名的“local communication”服務。和WF術語中的任何一種服務一樣,它也是另一種可插拔服務。區別是它不像WF中的那些已預先創建好的服務,你需要寫出這個服務的一部分。為什么呢?因為你在宿主應用程序和你的工作流之間傳遞的數據有一定的特殊性。更進一步說,你可創建各種各樣的數據傳輸方法,你可使用你設計的各種方法從宿主應用程序發送數據,然后在工作流中接收數據。
備注:這里有些事情你需要進行關注,那就是對象或集合的共享問題。因為宿主應用程序和工作流運行時在同一個應用程序域執行,因此引用類型的對象和集合就是通過引用而不是值進行傳遞。這意味著宿主應用程序和工作流實例在同一時間會訪問和使用同一個對象,多線程環境下這會產生bug,出現數據并發訪問錯誤。因此,對于可能要進行并發訪問的對象或集合,你可考慮傳遞一個對象或集合的副本,或許這可通過實現ICloneable接口,或者考慮親自序列化該對象或集合并傳遞序列化后的版本。
你可寫這種local service,把它插進工作流,然后打開連接,發送數據。這些數據可以是字符串,DataSet對象,甚至可以是你設計的任何可被序列化的自定義對象。通信可以是雙向的,盡管在本章我沒有演示它。(這里,我僅僅是把數據從工作流中傳回給宿主應用程序。)從工作流的角度來說,我們使用工具生成活動的目的是發送和接收數據。從宿主應用程序的角度來說,接收數據等同于一個事件,而發送數據就是在一個服務對象上的方法的簡單調用。
備注:我們在后面幾章看到更多的活動后還會重溫該雙向數據傳輸的概念。工作流活動從宿主應用程序中接收數據基于一個HandleExternalEvent活動,我們將在第10章“Event活動”中看到。我們也需要更深入地了解這些概念間的相互關系,這在第17章“宿主通信”中將進行介紹。對于當前,我們只是在工作流實例完成它的任務后,簡單地返回復合數據給宿主。
我們需要做的還不僅僅是這一點,我們最終需要添加ExternalDataService服務到我們的工作流運行時中。ExternalDataService是一個可插拔的服務,它方便了工作流實例和宿主應用程序之間進行序列化數據的傳輸。在緊接下來的一節我們將寫出的該服務的代碼將做很多事(包括序列化數據的傳輸)。讓我們來看看大體的開發過程。