1.為什么要使用三層應用?
客戶的應用要求在廣域網上運行,資料庫不在廣域網上暴露,有兩個途徑實作:1.建議客戶購買遠程桌面管理軟體,CS程式無需做任何更改,即可實作廣域網應用;2.使用三層架構,客戶端與中間服務器打交道,中間服務器與資料庫打交道。
第一種方式,這個遠程桌面管理軟體也不算貴也不算便宜,關鍵是它大部分是賣站點數的,小型企業一般不愿意額外開支這部分費用。那么,就用PB自身來實作三層架構吧。
2.選webform,還是webservice?
webform的本質是把pb代碼生成html代碼,再發布到IIS服務器上。好處是:很容易轉換;壞處是:想美化一下界面,需要更多的網頁知識。我試玩了幾下,放棄了這個。
webservice才是PB三層應用的核心。它的最大好處是:通過soap協議,將資料視窗物件進行傳送。PB開發員需要做的只是轉換一下開發思想,就可以使用純PB script做出非常好的三層應用。
3.PB開發webservice的一些準備
(1)網路連接管理的問題:CS下,連接是不會斷開的,有利于身份認證完成后就無需再關心這個事件。而BS時,連接是斷開的。那么,身份認證的問題需要貫穿整個開發。
我的做法:登錄后,確認身份成功,分配一個guid值做為令牌,當客戶端需要做業務處理時,引數里都帶著這個令牌,解決了連接的問題。
(2)資料連接管理的問題:CS下,資料庫連接是不會中斷的。而在BS時,網路連接是無狀態的,所以,資料庫連接也是斷開的。
我的做法:在服務器端,每一個業務邏輯,都重新connect一次,邏輯完成后,disconnect掉。查過相關貼子,據說這樣使用,IIS會自動管理資料庫連接。因為沒有相關工具的使用經驗,無從查究。
(3)多表提交的問題:以往的CS程式下,多表提交是在客戶端通過設定autocommit=false,手動來控制多表提交,如果有一個事情失敗,就整個事務回滾。
我的做法:做一個多表提交的函式,一般是主子表結構,那么傳入引數里就有兩個blob,分別是主子表的dw語法,然后在服務端做多表提交控制
(4)資料存取效率問題:目前單機運行,還是很滿意的。除了第一次使用時慢一點。以后如果有效率問題出現,先考慮使用壓縮演算法,把dw語法進行壓縮,以減少對網路的依賴
(5)可以接受多少個客戶端?這個問題目前未知。不過一般情況,我想三五百個客戶端應該是沒有太大壓力的,如果客戶端再多,可以建議客戶購買更專業的可以放置pb物件的中間層服務器,比如sybase自己的easerver
4.如何開發第一個webservice
其實,用pb開發webservice是很簡單的事情。第一個大前提就是:環境一定要做好。在安裝pb時,會有提示說用到什么功能時需要什么樣的環境。要開發webservice,就得安裝.net framework sdk 2.0。要注意,是sdk,不是普通的那個。
其次,建一個webservice專案,然后建一些不可視的物件,將各種業務函式封裝在這些物件里。網上所能找到的資料,已經足夠你用來學習了。之所以資料不多,是因為它真的不復雜。建議去臺灣的一個資訊網站去下載資料,我看好些資料是從它那里出來的http://www.mpinfo.com.tw/
照著這些資料,發布你的第一個webservice吧。
服務端的物件是,是不存在可視物件的,象視窗啦,資料視窗啦。資料視窗不在服務端,那么,如何使用資料視窗技術呢?不要忘了,資料視窗的不可視版本:datastore。在服務端的腳本里,定義一個datastore,然后與資料庫連接,然后檢索,然后使用getfullstate()得到blob,把blob物件通過soap傳給客戶端,客戶端的dw.setfullstate()一下,哈哈,怎么樣,看到通過webservice生成資料了吧。
5.客戶端如何使用webservice
呼叫webservice時,PB是通過一個project來生成服務端物件的代理。這個代理的本質其實就是一些遠程函式的定義。
6.常用的幾個函式
不用說,首當其沖的就是getfullstate(),setfullstate()這一對寶貝函式。它是整個資料物件的語法包括資料,狀態,都集中成一個blob中。
其次,dw.create()。這個函式也很有用。你可以從服務端取得dw object的syntax,然后在客戶端接收這個syntax,再create()一下,哈哈,資料視窗就出現欄位了,而且是在客戶端代碼里沒有dw object的前提下。
總結:pb的webservice大大地拓寬了pb的應用,而且非常的簡單易用,希望更多的pb開發員加入到這個行列。不要以為其它的工具如何如何的先進,在快速應用方面,目前還是pb是首選。也不要以為這webservice有多復雜,我本身對這是很弱的,通過學習,一周之內,就把它理解并能應用了,想念聰明的你們更是得力。
我寫這些的初衷,就是鼓勵大家使用新技術,完成客戶需求,這才是最重要的事情。
sybase繼續加油,讓pb的代碼除了可以發布在iis,easerver,以后支持更多的中間件服務器,而且能跨平臺,將是我們所有PB開發人員的福音
uj5u.com熱心網友回復:
呵呵,樓主辛苦了
uj5u.com熱心網友回復:
有沒有例子呢?uj5u.com熱心網友回復:
謝謝分享uj5u.com熱心網友回復:
最好提供些例子出來uj5u.com熱心網友回復:
大力支持樓主放實體。。。。
uj5u.com熱心網友回復:
1.先從這個地址下載pb11開發webservice的檔案,仔細學習http://www.mpinfo.com.tw/FileDownload.php?rt=x1&dir=ActivityFiles&file=20071101_PB11%20.NET%20Seminar%2F1101_Sec2_Web.pdf
2.服務端的設計
先建一個application,再在這個application上建一個web service的project,當運行這個web service的project時,就是向iis發布的程序。
在這個target中,建一個custom class(它是一個不可視的類),我把它命令為n_ws_dwservice(意思是提供dw的服務),在這個類里,定義一個函式,uf_getsyn,函式的任務是取得服務端里的dw object的語法。具體函式腳本如下:
//獲得資料視窗的語法
//引數:string as_do 資料視窗物件的名稱
string ls_syn
datastore lds_tmp
lds_tmp = create t_datastore
lds_tmp.dataobject = as_do
lds_tmp.settransobject(sqlca)
ls_syn = lds_tmp.describe("datawindow.syntax")
destroy lds_tmp
return ls_syn
3.服務端的發布
參照下載的資料
4.客戶端的呼叫
先建一個web service的代理工程,讓pb生成代理物件類。我這里生成的類名是:n_ws_dwservicesoap
在使用時,先建一個easysoap的連接(我把這個連接初始化成全域變數,就象sqlca一樣,全域可用),再使用這個連接進行代理的實體化。可以這么想象,easysoap是一個連接,服務端代理就依付在這個連接之上,進行遠程呼叫服務器的函式。所以,我又把代理物件也做成全域變數,到處可以使用嘛
連接的實體化與代理的實體化,都安排在客戶端application的open事件中
-------------------
//取出webservice地址
gs_wssvr = ProfileString(gs_appdir+"\init", "服務器", "地址", "127.0.0.1")
//初始化soap連接與代理
string ls_urldw
soapcon = create SoapConnection
ls_urldw = "http://"+gs_wssvr+"/bdlws/n_ws_dwservice.asmx?WSDL"
soapcon.CreateInstance(gp_dw, "n_ws_dwservicesoap",ls_urldw)
然后,在某個視窗里,先布置一個資料視窗控制元件,例如叫dw_1
在dw_1的open事件里,把dw object的語法獲得,相當于CS下的dw_1.dataobject='d_xxxx'的效果,此時的腳本是:
string ls_syn
ls_syn = gp_dw.uf_getsyn('d_xxxx')
dw_1.create(ls_syn)
注意了,注意了,這時你發現了什么情況?在客戶端里,沒有定義d_xxxx這個資料視窗物件,它只是存在于服務端的pbl中,但是,你仍然在客戶端這里生成了這個d_xxxx的界面,而且,使用起來,和cs下一點區別都沒有。
哈哈,恭喜你,已經學會使用web service進行遠程呼叫了。
剩下來要干點什么活呢?當然是把客戶端的dw_1里的資料向資料庫提交了。這時,getfullstate()和setfullstate()就派上用場了。
兄弟們,好好享受這一刻
uj5u.com熱心網友回復:
重要更下:(因為沒有修改的權限,沒辦法修改上面的回復)在dw_1的open事件里,把dw object的語法獲得,相當于CS下的dw_1.dataobject='d_xxxx'的效果,此時的腳本是
更正為:
在dw_1的所在視窗的open事件里,把dw object的語法獲得,相當于CS下的dw_1.dataobject='d_xxxx'的效果,此時的腳本是
uj5u.com熱心網友回復:
再告訴一個用pb做的智能下載的途徑:因為pb自身是偽編譯的,所以,從本質上說,只要把程式的pbd檔案更新了,客戶端的業務代碼也就更新了。一直以來,我都是把通過一個版本識別方法,來判斷當前的pbd是否是最新的。版本高,則updateblob到資料庫的一個表里保存著,版本低,則從資料庫的表里selectblob下來
這樣,只要有一個客戶端的pbd被更新過,所有的客戶端都會被自動更新。
這個功能也被我改成web service下可用了。
所以說,除了客戶端不是IE,三層能干的事情,PB都可以干。
uj5u.com熱心網友回復:
感謝樓主,還沒用過pb3層的,學習了。。uj5u.com熱心網友回復:
呵呵,樓主辛苦,下次一定請教uj5u.com熱心網友回復:
感謝分享,學習下uj5u.com熱心網友回復:
謝謝樓主,很有啟發.uj5u.com熱心網友回復:
提供一個例子給我們下載吧uj5u.com熱心網友回復:
示例代碼(其實就是我正在為客戶做的應用的框架,除掉了業務部分)已經上傳到我的資源里,有興趣的兄弟試試看能下載不uj5u.com熱心網友回復:
好的我們看看uj5u.com熱心網友回復:
能不能不要分不,有沒有9的版本呢?uj5u.com熱心網友回復:
pb11.5+oracle10 ,3G記憶體。提取十條左右的資料,正常情況下等待3、4秒鐘,有點慢吧 , 不知道樓主的運行速度如何?uj5u.com熱心網友回復:
是比純cs慢,檢索幾行資料也要幾秒,檢索數千行時近十幾秒。我都是在筆記本上跑的,在真實環境不知道情況怎么樣。uj5u.com熱心網友回復:
可以,蠻好的uj5u.com熱心網友回復:
臺灣的網站訪問不了 。。。。。。。。。。。請版主給共享下吧uj5u.com熱心網友回復:
樓上的兄弟,我也不知道在CSDN如何共享一個檔案下載。想在資源里修改不要資源分,好象也沒地方修改了。uj5u.com熱心網友回復:
使用webservice已經差不多一個月了,又有一些心得共享:1.關于webservice的除錯。
因為自己的作業系統已經有一年沒重裝過了,時不時有些病毒,查查殺殺的,不知道是不是這個原因,webservice的除錯有時很正常,有時不正常。
正常的表現:運行除錯后,output刷刷的出現一大堆資訊,大致是與.net通信吧。這時,只要呼叫了webservice,pb的ide就會跳到斷點,就可以看往常一樣除錯webservice的代碼了。
不正常的表現:彈出一個計時框,大意是等待.net,幾十秒后,視窗關閉,output提示fail to 啥啥的。
除錯時的我的做法(不知道對與不對,反正可以有效的除錯):
(1).project勾上debug,不勾enable debug symbol(目前不知道有什么用,也不知道勾與不勾有什么區別,我是一般不勾,畢竟只是用了easysoap,沒有使用.net的資料型別,跟.net關系不大),deploy一下。
個人猜想:讓這個動作是讓發布的代碼含有debug標記
(2).然后進行debug。當看到output區有刷刷的資訊時,就基本上可以抓住斷點了。
2.如果之前可用,忽然間就出現呼叫出錯,基本都是與檔案的權限有關。而且,客戶端呼叫出錯并不是很容易理解的。我遇到的錯誤有:
(1)Unexpected return Content-Type: text/html;charset=utf
遇到這個錯誤時,從google上查到的資訊很少,看到一個點子說是要進行連接設定。我查完了soapconnect物件的函式(它沒有屬性),沒有任何一個函式是可以設定content的。
然后,在客戶端進行代碼除錯,發現一呼叫webservice的函式就出這提示。
然后,對IIS進行各個設定檢查,發現有地方可以選charset的,改了之后沒有效果。
然后,對webservice的project的objects頁的view wsdl進行測驗,發現提示wsdl無效。
然后,做一個簡單的index.htm在iis上,發現可以訪問,說明iis網站是正常的
然后,對webservice進行跟蹤,跟蹤時有一個ie頁跳出來,大意說是:network service無法對windows\temp目錄進行讀寫。一檢查,果然是該目錄沒有netservice的權限。將權限設定好(我給netservice全控制,權限問題以后再慢慢研究),問題就解決了。
之前也遇到另一個問題,也是由于network service對C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files沒有權限導致的。
綜上所述,大部分所謂的環境問題,歸根結底就是檔案系統的訪問權限問題,特別是network service這個用戶。而且,許多問題所出的提示,不會明確。主要是要抓住這樣一個思路,才會有效地解決:
1.確保iis是正常的。其實iis以及soapconnect這兩樣東西,沒什么可設定的。
2.檢查wdsl是否能正常訪問
3.跟蹤webservice
之所以發現這個問題的問題所在,是因為用得好好的,來了個病毒后,就出錯了,所以,查啊查的,不想重裝系統呀。
3.getfullstate()和setfullstate()的缺點
使用setfullstate()時,如果dw object是多表連接的,那么,在服務端進行update()操作時,會導致update()<>1,而且,根本就沒有辦法查到為什么會這樣。
我就在那想呀想,忽然想到好象有一個地方可以保存。為什么會這樣呢?能保存的dw object是單表的,不能保存的是多表的。于是,在webservice的uf_save()函式時,用代碼檢查一下datawindow.table.updatetable的值,發現沒有值。真相大白:多表的dw object在fullstate時,datawindow.table.updatetable會丟失。
怎么辦?怎么辦?
仔細地研究一下setfullstate,在幫助里有一個see also,一看,哈哈,還有一對寶貝函式:getchangesblob(),setchangesbolb()。這幾天好好研究一下怎么利用這一對寶貝。
uj5u.com熱心網友回復:
最近又遇到除錯ws端代碼時,出現等待asp回應的視窗。檢查了network service在兩個目錄的權限,正常。于是,在deploy里,重新view wsdl一下,就可以了。uj5u.com熱心網友回復:
感謝樓主分享,堅持哦uj5u.com熱心網友回復:
要收藏一下。遠程終端好像購買ms的就行,價格多少不知道。但是如果是cs程式還是值得的。uj5u.com熱心網友回復:
樓上的各位兄弟們,不要迷戀于CS了,pb的webservice一樣好用:三層的應用模式,兩層的界面檢驗.所有的代碼都是基于我已經在csdn公開的代碼源上修修改改.基本的思路就是:涉及到資料庫操作的,就設計一個webservice來執行,就OK了.比如,我設計了一個uf_retrieve()函式,用來回傳指定dw object的blob,就完成了普通dw的retrieve()作業
目前幾十用戶的使用效果很好.上百用戶時的情況有待實踐
不過話又說回來,用戶超多時,使用專門的中間服務器才是王道,比如sybase自有的中間件,可以做為webservice的容器,就足夠好了
uj5u.com熱心網友回復:
三層的應用模式,兩層的界面體驗uj5u.com熱心網友回復:
最近用上了win7 ,iis7.5的功能好象復雜了很多找到一篇文章http://yangactive.iteye.com/blog/1552014,關于webservice在iis7.5上的分布的,依樣畫葫蘆,在pb的project中訪問wsdl成功了
看來,pb的webservice是依托于asp.net的,我還以為是直接.net應用程式來實作呢
uj5u.com熱心網友回復:
昨日用電信3g流量卡試了一下應用,小資料量時(一百行記錄的報表),反應速度還不錯但大報表時,十幾分鐘沒有回傳.查看了一下網路統計,網速為20k/s左右,接收的資料已經達到7M了,還沒有完成.自己粗略地估算一下,如果一行記錄1k,一千行記錄時就會達到2000k,還是比較占帶寬的
下一步計算是研究一下壓縮解壓縮的演算法了,每個blob的傳遞,都進行壓縮運算
最近需要頻頻更新服務端的代碼,因為dwo都放在服務器上,每當dwo更新時,就需要做一次服務器的代碼布署,有點繁.計劃把dwo放在客戶機上,把dwo的模板做為引數,讓服務代碼發生檢索,再把結果回傳.這樣,服務端就變成了純粹的檢索橋梁,減少更新的次數.
uj5u.com熱心網友回復:
再說一說webservice的從測驗環境轉移到正式環境的步驟.1.在正式機器上建一個網站
2.在正式機器上安裝pb的runtime庫.這個可以使用runtime packager來生成,因為是使用easysoap,所以選擇powerbuilder .net compenents選項.安裝時,建議直接安裝到windows/system32目錄下
3.把測驗環境下的網站目錄,復制到正式環境的網站目錄下.關于這點,需要一點點網站知識了,至少,得了解網站的目錄結構的概念.直接復制過去時,會發現有一個目錄沒有變成虛擬目錄.沒關系,是否是虛擬目錄,是由目錄的執行權限決定的.當把執行權限更改成純腳本時,它就變成了虛擬目錄
4.檢查正式機器的網站,是否使用asp.net 2.0,當然,更高的版本也許更好.這樣,代碼就被設定成asp.net進行托管了
5.訪問一下wdsl檔案,看看有正常的回傳沒?
當看到正常的回傳時,恭喜你,webservice已經布署成功.當服務端的代碼需要更新時,只需要簡單的把網站目錄更新就可以了(也就是把測驗機器的網站目錄復制到正式機器就行了).
在第5步,如果沒有正常的回傳,那么,研究一下網站回傳相應的錯誤資訊,就折騰iis就行了
客戶端也可以做成綠色的.其實就是把runtime packager所包含的檔案,都整到一個客戶端代碼目錄內,就OK了.如何確認packager包含了哪些內容?很簡單,檢查一下安裝目錄的檔案變化,就知道了
uj5u.com熱心網友回復:
學習了!3層結構話,會丟失了資料視窗一部分的功能吧!uj5u.com熱心網友回復:
目前沒發現有功能丟失:變了個方式與資料庫互動使用而已.換句話說,cs的資料互動代碼是寫在客戶端,現在呢,是寫在服務器端
昨天加了zlib壓縮功能,剛才用3g流量卡試用了一下,十幾秒鐘,接近一萬行的資料就出來了,下載流量不到400k
很滿意
uj5u.com熱心網友回復:
學習了謝謝uj5u.com熱心網友回復:
有完整的教程嗎uj5u.com熱心網友回復:
完整的步驟我都在這個貼子里寫了,特別是在這個貼子里提到的臺灣網站下載的教程,已經是比較明晰的了.
在我的資源里有代碼框架下載,可以參考一下
如果有什么問題,在這里共同探討一下
uj5u.com熱心網友回復:
求PowerBuilder 9.0 web 開發篇 光碟 教程!求PowerBuilder 9.0 案例開發篇 光碟 教程!
求PowerBuilder 9.0 與系統開發篇 光碟 教程!
uj5u.com熱心網友回復:
PB呼叫java寫的webservice,呼叫成功,但服務器端接收的引數為null值,而用java呼叫則正常,引數型別為String,呼叫代碼如下,請問要如何解決?long ll_ret , ll_row
string str_proxy_name = "test_isendstatussoap11port_http"
string err
soapconnection lsc_conn
test_isendstatussoap11port_http test_ws
try
lsc_conn = create soapconnection
catch (RUNtimeerror e11)
err = '創建soapconnection 出現錯誤,錯誤訊息是: ' + e11.getMessage()
messagebox('',err)
return
end try
try
lsc_conn.SetOptions("SoapLog=~"C:\soaplog.txt~"")
catch (RUNtimeerror e12)
err = 'soapconnection 呼叫函式SetOptions 出現錯誤,錯誤訊息是: ' + e12.getMessage()
messagebox('',err)
return
end try
try
ll_ret = lsc_conn.createInstance(test_ws,str_proxy_name,"http://10.10.0.4:9080/uapws/service/ldxy")
catch (RUNtimeerror e13)
err = 'soapconnection 創建實體(函式createInstance)失敗,錯誤訊息是: ' + e13.getMessage()
messagebox('',err)
return
end try
if ll_ret <> 0 then
err = '創建實體失敗,請檢查代理物件是否正確,錯誤代碼'
messagebox('',err)
return
end if
String ls_1,ls_2
ls_1 = "2012-08-20 11:01:30"
ls_2 = "2012-08-20 11:07:30"
String ls_rtn
ls_rtn = test_ws.sendStatus(ls_1,ls_2)
messagebox("2",ls_rtn)
uj5u.com熱心網友回復:
把客戶端生成的物件刪掉,重新deploy一下客戶端的webservice代理,檢查一下生成的引數結構是不是string
uj5u.com熱心網友回復:
看了你的系統說明,系統升級為什么不使用智能客戶端自動完成呢?uj5u.com熱心網友回復:
還有請問壓縮功能是如何實作的?能給個詳細的說明嗎?uj5u.com熱心網友回復:
請問 PB9.0 做樓主webservice 的這個OK不uj5u.com熱心網友回復:
感謝樓主的分享,學習下uj5u.com熱心網友回復:
dw_1.dataobject='d_xxxx',引數怎么傳遞?uj5u.com熱心網友回復:
升級到12吧,如果一定要用9,那就根據教程找找那些建project的圖示在不在.主要是我的代碼是12了,再倒回9去測驗挺麻煩的
uj5u.com熱心網友回復:
你可以把datawindow的sql里,where條件統一為where 1=1,然后,在web service里的函式,把條件做為引數傳進來,然后用getsqlselect()取出datawindow的sql,然后,把1=1替換成傳進來的條件,再setsqlselect()回去,再來個retrieve(),就OK啦
uj5u.com熱心網友回復:
這些天遇到在生產機器上布署時,訪問testwebservice.htm(也就是pb幫生成的測驗html頁),在呼叫函式時,出現錯誤提示:System.Web.Services.Protocols.SoapException: Could not load file or assembly
在對檔案權限,iis設定等一一檢查之后,無果.google了一下,找到一點靈感,再與自己開發環境"添加洗掉程式"里進行比對,最后的結論是:生產機器沒有安裝visual c++ 2008 redistribute包.要注意,visual c++ 2005 redistribue都不行.
安裝后重啟,問題解決.
因為我自身是做cs出身,對bs下的服務器環境問題很不敏感,一有問題就總以為是pb發布的問題.其實大部分原因都錯怪了sybase.
總結一下服務器能正常運行的環境(僅說明這個環境能運行,版本更高可能更好,呵呵):
1. .net framework 2.0 sp1
2. sybase powerbuilder 12.0,這是由pb自帶的打包工具生成,安裝在windows\system32目錄下
3. visual c++ 2008 redistribute
uj5u.com熱心網友回復:
多謝樓主分享經驗,很有幫助,另外想請教下,程式自動更新,如何比較PBD的版本?謝謝uj5u.com熱心網友回復:
因為我都是用同一個版本開發,所以目前沒考慮過pbd會因為pb的版本而變化.如果要實作這一點,那就設計一個pbd的版本號表,而在客戶端定義一個當前所使用的版本號,然后客戶端根據當前版本號而從資料庫里selectblob相應的pbd下來
uj5u.com熱心網友回復:
目前我的開發環境,試用了win 7 64位,和win 2008 64位,說一下心得:1.在win 2003 x86,win 7 64位,win 2008 64位下,pb 12.0的webservice開發都沒有任何例外,除了iis從6到7,iis自已的界面變化很大之外,無差別.iis 7也是不用做任何特別的設定,新建網站,然后用pb 12進行發布,都成功
2.所用的zlib.dll這個壓縮dll,在win 7 64位下,不被執行.在win 2008 64位,就沒有問題.對于生產服務器而言,我想也沒有那個企業會采用win 7
現在我的開發環境已經移到win 2008 64位,很穩定.我的開發特征就是:幾乎不使用第三方控制元件.一,我不需要很花哨的界面,對于一個企業應用而言,安全,可靠,穩定,是首要設計目標;二,目前僅使用到條碼列印這個第三方控制元件,各個windows版本下都沒有例外
uj5u.com熱心網友回復:
頂樓主,另外,建議樓主整理下可以收錄到你的博客中uj5u.com熱心網友回復:
http://www.mpinfo.com.tw/報告樓主,這個站 點不能訪問了。
uj5u.com熱心網友回復:
謝謝樓主。。uj5u.com熱心網友回復:
樓主你好,能否詳細說一下,多表資料視窗修改后進行保存時,是如何處理的?getfullstate()與setfullstate()這2個函式不起作用。uj5u.com熱心網友回復:
http://v.youku.com/v_show/id_XMzA3MzU0NjQw.html黃國酬-PB Webservice多層架構開發-演講視頻
這個視頻不錯
uj5u.com熱心網友回復:
http://wenku.baidu.com/view/39c3d9bbc77da26925c5b00c.html視頻上用的ppt
uj5u.com熱心網友回復:
抱歉,挺久沒上來,看及時看到你的疑問
你注意到我在26樓的內容嗎?多表的資料視窗之所以通過blob回傳到客戶機后不能更新,是因為dw物件的update屬性全部丟失了,所以,在回傳blob時,把dw object的update屬性恢復回去就可以了
我的代碼是這么寫的.先說一下思路,因為客戶機大部分的情況是先檢索資料,然后修改,然后再保存,所以,對update屬性的恢復,我是寫在服務端的uf_retrieve()函式里.恢復的代碼如下:
uf_retrieve()的引數:
string as_dataobject 指定dw的名稱,dw是存放于服務端的,由客戶機呼叫時指定
string as_db 指定檢索的資料庫名稱
string as_where 指定dw的檢索條件,也就是在客戶端自行拼接where條件,然后對dw中的1=1這個條件進行替換處理
blob rn 回傳值
----------------
......
......
datastore lds_tmp,lds_info
//為什么要定義兩個datastore呢,lds_tmp是用來根據as_where進行檢索,lds_info用來做模板
lds_tmp = create datastore
lds_tmp.dataobject = as_dataobject
lds_info = create t_datastore
lds_info.dataobject = as_dataobject
//進行資料庫連接.f_connect_db()是自已寫的連接函式,無非就是connnect using sqlca
f_connect_db(as_db)
//檢索資料
lds_tmp.settransobject(sqlca)
ls_sqlold = lds_tmp.object.datawindow.table.select
ls_sqlnew = f_replace(ls_sqlold,'1=1',as_where) //f_replace是自己寫的替換函式,實作sql里的replace()的功能
lds_tmp.setsqlselect(ls_sqlnew)
lds_tmp.retrieve()
//多表連接時,getfullstate()會丟失update資訊,需要用代碼重新設定,將lds_info的屬性復制給lds_tmp
//恢復update屬性
string ls_des,ls_colname
long i,ll_rccol
ll_rccol = long(lds_tmp.describe("DataWindow.Column.Count"))
//UpdateKey InPlace
lds_tmp.modify("datawindow.table.UpdateKeyInPlace="+lds_info.describe("datawindow.table.UpdateKeyInPlace"))
//UpdateTable
lds_tmp.modify("datawindow.table.UpdateTable='"+lds_info.describe("datawindow.table.UpdateTable")+"'")
//UpdateWhere
lds_tmp.modify("datawindow.table.UpdateWhere="+lds_info.describe("datawindow.table.UpdateWhere"))
for i = 1 to ll_rccol
ls_colname = lds_info.describe("#" + string(i) + ".name")
//key
lds_tmp.modify(ls_colname + ".key=" + lds_info.describe(ls_colname + ".key"))
//update
lds_tmp.modify(ls_colname + ".update=" + lds_info.describe(ls_colname + ".update"))
next
//獲得blob
lds_tmp.getfullstate(rn)
destroy lds_tmp
destroy lds_info
//斷開資料庫
f_disconnect()
//壓縮blob.壓縮函式也是自定義的
f_compress(rn)
//回傳blob
return rn
uj5u.com熱心網友回復:
看七樓的鏈接,我剛試了一下,還可以下載.一樓的鏈接太簡單了,也找不到
uj5u.com熱心網友回復:
今天系統重裝了一下,發布webservice上去,在desploy中view wdsl,總是出錯誤提示,大意是該檔案或目錄不存在.自行寫了個最簡單的index.html,放在各個目錄下都可以訪問,偏偏asmx檔案就提示不存在.照以往的思路,network service的目錄訪問權限全打開了,仍然出錯.百思不得其解.后來查詢所生成的虛擬目錄的應用程式設定,發現asmx的映射是由aspnet_isapi.dll來完成的.原來是IIS沒允許isapi擴展導致.將該設定打開,終于可用了.
uj5u.com熱心網友回復:
呵呵 不錯的文章 學習了uj5u.com熱心網友回復:
樓主好人一生平安
uj5u.com熱心網友回復:
<例外的解決>今天布置一個webservice到新的一個服務器,遇到了service unavailable的提示,處理方式如下:
網站設定成:純腳本,運行,記錄訪問,索引資源
虛擬目錄設定成:純腳本,運行,記錄訪問,索引資源
新建一個應用程式緩沖池,并把緩沖池分配給網站與虛擬目錄
解決問題
uj5u.com熱心網友回復:
http://bbs.csdn.net/topics/390390741大蝦們,幫忙看下這個貼....
uj5u.com熱心網友回復:
最近客戶給我提了一個難題:因為客戶建了一個新的資料庫,做同樣的業務,希望在客戶端可以選擇登錄到哪一個資料庫最簡單的辦法就是:把服務端的代碼復制到另一個IIS埠去,這樣,客戶端在登錄不同的埠時,就會使用不同的資料庫
怎么樣讓服務端的代碼能連接到不同的資料庫上呢?想來想去,有這幾招:
1.呼叫系統函式,知道埠所映射的絕對路徑,然后讀取絕對路徑里的ini檔案
結果:失敗.短時間內學不來如何呼叫系統api
2.讀注冊表
結果:失敗.服務端代碼無法對自身進行識別,也就無法讀取相應的注冊表內容.
3.讀取組態檔
剛開始時,是失敗的.我把組態檔放在系統目錄下,webservice是訪問不了的,因為它是屬于托管代碼,涉及到運行權限問題,不可以隨意讀取服務器目錄檔案的.
終于,找到了pb的webservice的project里,可以定義該webservice用到的檔案,而且,發布時是依照指定目錄來生成.所以,在服務端的代碼里,可以用一個固定的路徑來讀取組態檔
比如,在project中,定義了d:\ini\config.ini檔案
那么,在發布時,iis該網站的目錄,有這么一個檔案是被服務端代碼所訪問
C:\inetpub\網站目錄\ws服務名稱_root\file\common\D\ini\config.ini
只要在服務端代碼里,ProfileString ( 'D:\ini\config.ini', '資料庫', '名稱', '' ),就可以獲得配置資訊了.
我描述得不是很通暢,各位pber自行消化一下了.結論就是:實作了在服務端代碼里讀取組態檔,以實作服務端代碼的可定制.
uj5u.com熱心網友回復:
經典!樓主威武!學習!uj5u.com熱心網友回復:
向lz學習。。。uj5u.com熱心網友回復:
最近又接到一個需求:要求外部系統的用戶名與口令,盡可能地與通達OA一致通達OA經過研究,該OA是呼叫了php內置的crypt()函式來進行md5加密.在判斷口令是否正確時,需要同樣地呼叫php的crypt()函式,加salt值來進行核對.在google和baidu上花了很多時間找可以指定salt的md5的dll,都找不到.
路到這里就中止了嗎?
電石火光之間,想到了把php的crypt()做成web service,那么,我就可以通過webserver來呼叫crypt()函式了.
自此,踏入了長達一周的對php的webservice的研究當中.
php的代碼相當的簡短,但由于從沒用過php腳本,也不會使用php的debug,所以,一直沒能制作成功.直至今天,終于完美地實作了設計目標:將crypt()做成web service函式
步驟如下:
1.修改php.ini檔案,打開php的web service功能.該內容請參考網路教程.
2.書寫php的服務端代碼,檔案名叫pw.php,代碼如下
-------------------------
<?php
/*
建立一個webservice,以便于獲到crypt()呼叫
*/
$soap = new SoapServer('./pw.wsdl');
$soap->setClass("sysmng");
$soap->handle();
class sysmng
{
function uf_login($as_pw,$as_salt)
{
$a=crypt($as_pw,$as_salt);
if ($a==$as_salt) {
$rn='y';
} else {
$rn='n';
}
return $rn;
}
}
?>
--------------------
3.定義wdsl檔案,使web service可以被暴露在網站上.因為wdsl檔案對初學者來說相當的繁雜,所以,借助了zend studio 9的wdsl support功能,可以圖形化的生成該檔案.當然,其間要學習wsdl的格式與內容,因為,完全由工具生成的wdsl檔案是不可用的,生成后,還得自行修修改改.
最終的wdsl檔案如下,我把它命名為pw.wsdl
--------------------
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://127.0.0.1:8080/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="bdlpw" targetNamespace="http://127.0.0.1:8080/">
<wsdl:types>
<xsd:schema targetNamespace="http://127.0.0.1:8080/">
<xsd:element name="uf_login">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="in" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="uf_loginResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="out" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="uf_loginRequest">
<wsdl:part name="as_pw" type="xsd:string"></wsdl:part>
<wsdl:part name="as_salt" type="xsd:string"></wsdl:part>
</wsdl:message>
<wsdl:message name="uf_loginResponse">
<wsdl:part name="outparm" type="xsd:string"></wsdl:part>
</wsdl:message>
<wsdl:portType name="bdlpw">
<wsdl:operation name="uf_login">
<wsdl:input message="tns:uf_loginRequest"/>
<wsdl:output message="tns:uf_loginResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="bdlpwSOAP" type="tns:bdlpw">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="uf_login">
<soap:operation soapAction="http://127.0.0.1:8080/uf_login"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="bdlpw">
<wsdl:port binding="tns:bdlpwSOAP" name="bdlpwSOAP">
<soap:address location="http://127.0.0.1:8080/pw.php"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
------------------
看到這里,初學者一定會很頭暈,怎么有這么多url在里面.呵呵,其實看到的這些url,它的作用僅僅是個命名空間,只不過約定俗成地,命名空間的名稱非常多人喜歡用url的形式來書寫.記得,它只是個名稱,和a,b,c,d這種名稱的意義是一樣的,沒有真正的意義
wdsl有兩部分內容,一部分是抽象層,用來把函式展現給外部系統;另一部分是實作層,它非常重要.<binding>元素里書寫的就是實作層的內容,一個內部是soap:address location,這個定義了函式的真正的實作代碼在什么地方,所以,你看到我指向了http://127.0.0.1:8080/pw.php,也就是服務端的php代碼.另一個soap:operation soapAction,通知webservice,抽象層的uf_login,對應到真正的php的什么函式
其實,wdsl檔案每一個元素都很重要.認真地理解完wdsl的結構,對你查錯一定有幫助.因為我也不知道wdsl檔案應該如何debug,只有自己理解,邊理解邊改,邊試效果.
一旦wdsl檔案完成.如果抽象層沒有錯誤,那么,用pb的webservice proxy就可以找到該函式.如果實作層沒有錯誤,那么pb呼叫時就會有正確的結果
4.剛才說到在檢驗wdsl時,實作層正確才會有正確的結果.事實上,通過pb根本無法debug,而且我也不會用zend進行debug.好在有另一種辦法進行除錯,那就是書寫一個php的客戶端代碼,進行測驗.如果不成功,至少有那么一點error回傳
除錯用的php客戶端代碼如下,我把它命名為soapclient.php
--------------
<?php
ini_set("soap.wsdl_cache_enabled","0");
$client = new SoapClient("http://127.0.0.1:8899/pw.php?wsdl");
echo $client->uf_login('aaa','$1$HE1.EN0.$Szfs2J76idSsOOWFvi9aR/');
?>
---------------------------
5.當通過ie,訪問http://127.0.0.1:8080/soapclient.php時,有你想看到的結果出現,恭喜你,你的php的web service成功了.放心地用pb去訪問吧
6.總結:如果你需要寫一點php的web service,那么,你需要的是:少量的php知識,一個示例代碼,一個wdsl生成工具(除了zend,還有xml spy也可以幫到你),大量的耐心
uj5u.com熱心網友回復:
沒得修改了,只好在這補充一下,在pb中,訪問該webservice的地址書寫成:http://127.0.0.1:8080/pw.php?wdsl
或者
http://127.0.0.1:8080/pw.wdsl
都可以.
我總共寫了這三個檔案:一個服務端的php,一個服務端的wdsl,再加上一個測驗用的php
uj5u.com熱心網友回復:
又發現一個錯誤,soapcliet.php里$client = new SoapClient("http://127.0.0.1:8899/pw.php?wsdl");
應該是
$client = new SoapClient("http://127.0.0.1:8080/pw.php?wsdl");
埠號填錯了,呵呵.因為客戶的通達OA的埠號是8080,所以要特別指定
也許所粘的代碼里還有其它錯誤,因為在粘上去時,我把客戶真正的IP地址與埠號給改了,但有些地方的name沒完全更正,所以,這些,僅僅做個參考好了
uj5u.com熱心網友回復:
不知道樓主用過pb12.5開發webservice嗎,最近測驗發現似乎如果裝了.net framework 4.5,除錯webservice時就會出現非法操作,如果是 4.0就不存在這個問題,pb版本號是最新的12.5.2 5555, 由于win8自帶的就是4.5,沒辦法裝4.0 ,被這個問題搞得很郁悶,不知道有沒有辦法解決(win8不想換)uj5u.com熱心網友回復:
回復樓上:我用的是12.0,一切都很正常我覺得你的可能是環境的問題,剛看了一下,12.5做web service要求sdk .net framework 4.0,那就用4.0好了。win 8 帶的應該是runtime庫,和sdk不沖突的吧
uj5u.com熱心網友回復:
話說完成了php的webservice,興高采烈的在pb的webservice里再呼叫php的webservice象平時的客戶端代碼一樣,加入pbsoapclient120.pbd,初始化soapconnection物件,保存時也沒什么語法錯誤,進行發布時,麻煩來了:總是提示illegal data type :soapconnection
奇了怪了,是不是編譯時不認得pbsoapclient120.pbd?于是,把該檔案后綴改成pbl,也不行
難道pbsoapclient120.pbd要做為外部檔案? 在project中試來試去,仍然報錯
好吧,我的php ws proxy改用.net engine,變成了無法發現php的ws服務
好吧,我去找easysoap.dll,不用pbsoapclient120.pbd,這回可以了吧?找到easysoap.dll了,又沒有它的api使用指南之類的東西.
郁悶啊郁悶,那我找pbsoapclint120.pbl源檔案可以嗎?通過"pbsoapclient pbl"這對關鍵詞的組合,找到了一篇非常關鍵的文章:<PB11.5 WebService中使用的PBSoapClient115.PBD和PBWSClient115> (http://wenku.baidu.com/view/5e14febcc77da26925c5b0d2.html)
終于明白了其中的玄機,順利地在pb的webservice服務中,再呼叫其它的webservice得到實作
方法是:1.生成一個空的pbwsclient120.pbl;2.使用pb的import pb extention功能,把pbwsclient120.pbx匯入.終于在pbl檔案里看到熟悉的soapconnection物件了
------------------------------
在此,非常感謝該檔案的作者(雖然沒具名),感謝他的研究精神與分享精神,祝他好人一生平安!
uj5u.com熱心網友回復:
感謝樓主共享學習。uj5u.com熱心網友回復:
好文章,留個爪
uj5u.com熱心網友回復:
關于webservice的實戰文章,留念學習uj5u.com熱心網友回復:
謝謝樓主的整理和分享,最近正想用PB開發一些web查詢急需資料。樓主整理的東西太有用了!uj5u.com熱心網友回復:
樓主的分享精神值的學習uj5u.com熱心網友回復:
好文章,謝謝分享!! 收藏了。uj5u.com熱心網友回復:
感謝各位pber們的支持,最近使用到pb的兩個功能,覺得挺有用的,分享一下1.許多人都詬病PB的界面,我也一樣.在pb12里帶有一個advance gui示例,挺漂亮的,因為帶有原始碼,就想著拿來改進自己的主界面,發現左側的文字如果換成中文,就只能顯示幾個漢字而已,被截短了,而英文就沒問題.于是仔細地追蹤代碼,最后發現是在最底層的物件n_cst_xpheader_gradient.of_drawtext()函式在呼叫drawtext()函式時,有一個引數是字串的長度,應該是取漢字的長度與取英文的長度不一樣導到.原代碼如下:
Drawtext(ll_DC, as_text, LEN(as_text), l_Rect, al_align)
把它改成:
Drawtext(ll_DC, as_text, LEN(as_text)*2, l_Rect, al_align)
漢字正確了,但英文的字串又不正常.應該是len()取漢字與取英文時回傳的長度不合適.也曾換成lena(),未能解決.因為對呼叫winapi的drawtext()機理不是很明白,所以只能到此為止,沒有一個解決方案
2.現在小團隊里一起拿PB去維護資料庫,需要一個簡單的版本控制方案,使用ms的vcc是不錯,但要裝服務器與客客戶端,不是很方便,就直接使用了pb native的控制方案,也就是PB自帶的源代碼控制方案,對于一個小型團隊而言,挺好用的,在這分享一個心得
uj5u.com熱心網友回復:
首先,是要了解pb native的運行機制.它可以認為是一個對服務器上的源檔案進行版本控制的小工具.也就是說,它會核對服務器上的版本情況與本機的版本情況進行一個處理.據我觀察,版本情況應該是寫在pbg檔案里那么,開始使用pb native時,
首先,各個程式員的電腦都有一套源pbl,
其次,在workspace里設定好源代碼的在服務器的位置以及本機的代碼位置
設定完成后,因為與服務器的源代碼的訪問是與windows自身的共享檔案訪問是一致的,所以,需要先行在window系統里訪問一次服務器的檔案路徑,最方便的方法就是將共享路徑映射成盤符,并讓windows記憶訪問憑據
進行一次add to source control,此時,pb native會自動將pbl檔案上傳至服務器,服務器上會擁有客戶機一樣的目錄結構,并自動生成一堆pbg,sra,sru等檔案
看到workspace里的圖示發生變化了,恭喜你,成功地應用了pb的scc.
當你遇到明明是沒有人check out,而你的機器上卻總是一個紅叉叉告訴你有人已經check out了,怎么辦?我的辦法就是,把服務器的目錄刪了,把客戶機上的除了pbl,pbr之外的全部檔案刪了,從頭再來一次add to source control,一切問題都解決了.
其實,只要保證你的pbl沒問題,隨便你試,呵呵
再講一下get lastversion的功能:程式員A撰寫了一個新視窗,并check in到服務器了,那么,程式員B需要get lastversion,找到這個新視窗并勾上,那么程式員B的計算機上就會擁有了該新視窗的代碼.
至于pb的scc更多的幫助,請在pb的help的索引里,鍵入"source code",會看到一個條目"source code control(scc)",點擊它,會看到提示,更多幫助請參考using a source control system,再點擊它,你就會看到pb scc的手冊.英文不明白的,查一下詞典(我用的是www.iciba.com),相信你會明白的
結論就是:pb的scc很好用,前提是你需要理解一下它的作業機理,以及遇到問題時,只要你擁有pbl,啥都不用擔心.不用羨慕m$那個大型的版本控制軟體,PB的scc已經做得很不錯了。
現在,PB對我這個團隊而言,只有一樣東西挺麻煩的,就是pb沒辦法在手機端做程式。也了解過有appeon這個公司的產品,但現在沒有精力去研究,再說了,不是pb原生的東西,也擔心不好維護。最好最好最好,就是sybase提供pb在手機端的開發平臺了,那真是廣大pber的福音
uj5u.com熱心網友回復:
想糾錯一下,發現csdn的編輯功能不知道為啥用不了就寫在這里吧:把客戶機上的除了pbl,pbr之外的全部檔案刪了,改為:把客戶機上除了pbl,pbt之外的檔案刪了
其實,這樣描述還是有問題的,我不知道你的目錄下還有什么其它的檔案。我想表達的意思就是,把版本控制生成的檔案給刪掉,比如pbg檔案。其實你應該懂的,象pbl,pbt這些單機用到的檔案,版本控制是不會涉及到它們的
uj5u.com熱心網友回復:
樓主好厲害啊!~我也在也是用12.5在做的三層結構,不夠發現穩定性不夠強,不知道是不是我自己代碼沒規劃好。uj5u.com熱心網友回復:
TO #86這樣改是不對的
Drawtext(ll_DC, as_text, LEN(as_text), l_Rect, al_align)
把它改成:
Drawtext(ll_DC, as_text, LEN(as_text)*2, l_Rect, al_align)
建議將定義:
FUNCTION ulong DrawText(ulong hdc,ref string lpStr,ulong nCount,ref RECT lpRect,ulong wFormat) LIBRARY "user32.dll" ALIAS FOR "DrawTextA;Ansi"
改為
FUNCTION ulong DrawText(ulong hdc,ref string lpStr,ulong nCount,ref RECT lpRect,ulong wFormat) LIBRARY "user32.dll" ALIAS FOR "DrawTextW"
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/40018.html
標籤:Web 應用
上一篇:MySQL查詢重復資料
