惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Azure Blog
Microsoft Azure Blog
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
V
V2EX
PCI Perspectives
PCI Perspectives
Latest news
Latest news
博客园 - 三生石上(FineUI控件)
C
CERT Recently Published Vulnerability Notes
W
WeLiveSecurity
Last Week in AI
Last Week in AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Palo Alto Networks Blog
T
The Exploit Database - CXSecurity.com
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
WordPress大学
WordPress大学
V
Vulnerabilities – Threatpost
H
Heimdal Security Blog
Attack and Defense Labs
Attack and Defense Labs
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Hacker News: Ask HN
Hacker News: Ask HN
博客园 - 叶小钗
V
Visual Studio Blog
Jina AI
Jina AI
P
Proofpoint News Feed
罗磊的独立博客
SecWiki News
SecWiki News
J
Java Code Geeks
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LINUX DO - 热门话题
Security Archives - TechRepublic
Security Archives - TechRepublic
The Hacker News
The Hacker News
Hugging Face - Blog
Hugging Face - Blog
N
News and Events Feed by Topic
NISL@THU
NISL@THU
T
Tailwind CSS Blog
T
Tenable Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Recent Announcements
Recent Announcements
H
Hacker News: Front Page
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Tor Project blog
宝玉的分享
宝玉的分享
Help Net Security
Help Net Security
S
Security Affairs
Microsoft Security Blog
Microsoft Security Blog
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
G
GRAHAM CLULEY

博客园 - 眼里进了砂

Unity Application Block 1.2 学习笔记 [转] Unity Application Block 與 ASP.NET MVC 學習資源整理 [转] 线程之间的通讯---SynchronizationContext [转] .NET2.0中WinForm自定义的程序配置[转] 使用BackgroundWorker组件进行异步操作编程[转] .NET页面事件执行顺序[转] 不用设置iis .net 实现urlrewrite[转] 利用XPath读取Xml文件 javascript中replace与正则表达式 c# BackgroundWorker组件介绍(属性、方法、事件) .net 2.0 BackgroundWorker类详细用法 .Net的线程同步方法一:ManualResetEvent [转][javascript] Google谷歌首页点点效果 AJAX 中Sys.WebForms.PageRequestManager的事件激发顺序 AJAX 中Sys.Net.WebRequestManager的事件激发顺序 Summary review about Problem.Design.Solution 2 Summary review about Problem.Design.Solution [转发]深入理解 __doPostBack CSS Tips
.NET应用程序中异步调用Web Service的几种方法 come from: veryhappy(wx.net)
眼里进了砂 · 2008-07-07 · via 博客园 - 眼里进了砂

测试程序界面

图一,调用前界面

图二,调用后界面

详细代码实现

闲言少叙,直接进入主题吧。首先一个声明一个类(将来在客户端与服务器间传递):

其次,声明一个Web方法:

// 省略系统生成的Web Service声明代码,采用默认的

public class Service1 : System.Web.Services.WebService

{

//省略系统生成的Web Service声明代码,采用默认的

[WebMethod]
public Class1 GetClass1 ( int p_TimeSpan )

        {

            System.Threading.Thread.Sleep( p_TimeSpan ); 

// 线程停止一段执行,假设一段处理的时间

            Class1 r 
= new Class1();

            r.Name 

= "Async Call";

            r.ID 

= p_TimeSpan;return r;

     }

}

客户端调用代码,设计一个Windows Form窗体来测试,放入3个按钮控件(分别代表3种异步调用方法),一个进度条控件(表示调用Web Service后,客户端继续进行某些操作)。先把3种方法介绍一下:

1.       利用Backgroundworker对象,所在命名空间System.ComponentModelMSDN原文解释:BackgroundWorker 类允许您在单独的专用线程上运行操作。耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态。如果您需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用 BackgroundWorker 类方便地解决问题。

2.       利用wsdl.exe生成Web Service的客户端代理类,调用其中WebMethodAsync方法。

3.       利用wsdl.exe生成Web Service的客户端代理类,分别调用其中WebMethodBeginEnd方法。

先用wsdl.exe把上面的Web Service生成客户端代理类并把他编译成类库引入Windows应用项目(这里我没有编译类库,而是直接把代理类.cs文件加入到了Windows应用项目中)。

进入Visual Studio命令行模式,运行

wsdl /out:MyService.cs http://localhost:2732/Service1.asmx

参数说明:第二个参数是Web ServiceURL,这个是我机器的本地环境,其他人需要根据情况修改!

注:第一种方式的调用,不采用手动生成Web Service客户端代理类也可以(项目中直接添加Web引用)。后面两种方法都是通过Web Service代理类中提供的方法实现,因此必须生成这个代理类。

看一下处理进度条控件值的代码,几种调用方法都会用到,

private void ChangeProcessBar ( )

        {

for ( int i = 0; i < 10; i++ )

            {

                progressBar1.Value 

= i;// 不知道用多少时间,慢慢走吧:)

                System.Threading.Thread.Sleep( 
500 );

            }

        }

第一种方式调用,

private void button1_Click ( object sender, EventArgs e )

        {

            AsyncCall_In_Backgroundworker();

        }

#region AsyncCall_In_Backgroundworkerprivate void AsyncCall_In_Backgroundworker ( )

        {

            BackgroundWorker backgroundworker 

= new BackgroundWorker();

            backgroundworker.DoWork 

+= new DoWorkEventHandler( back_DoWork );// 注册具体异步处理的方法

            backgroundworker.RunWorkerCompleted 
+= new RunWorkerCompletedEventHandler( back_RunWorkerCompleted );// 注册调用完成后的回调方法

            backgroundworker.RunWorkerAsync();
// 这里开始异步调用

            ChangeProcessBar(); 
// 调用同时客户端处理不停止

        }
void back_RunWorkerCompleted ( object sender, RunWorkerCompletedEventArgs e )

        {

if ( e.Error != null )throw e.Error;

            progressBar1.Value 

= progressBar1.Maximum; // 调用完成了,把客户端进度条填充满

            Class1 result 
= e.Result as Class1; // 结果转化为Class1对象

            MessageBox.Show( 
"ID is " + ( result.ID.ToString() + ",Name is " + result.Name.ToString() ) ); //显示从服务器获取的对象值

        }
void back_DoWork ( object sender, DoWorkEventArgs e )

        {

            Service1 service1 

= new Service1(); // Web Service代理类

            e.Result 
= service1.GetClass1( 2500 ); // 调用Web方法GetClass1,结果赋值给DoWorkEventArgs的Result对象

        }
#endregion

第二种方式调用,

private void button2_Click ( object sender, EventArgs e )

        {

            AsynCall_In_WebServiceProxy();

        }

#region AsynCall_In_WebServiceProxyprivate void AsynCall_In_WebServiceProxy ( )

        {

            Service1 service1 

= new Service1(); // Web Service代理类

            service1.GetClass1Async( 
3000 ); // 这里开始异步调用

            service1.GetClass1Completed 
+= new GetClass1CompletedEventHandler( s_GetClass1Completed ); // 注册调用完成后的回调方法

            ChangeProcessBar();
// 调用同时客户端处理不停止

        }
void s_GetClass1Completed ( object sender, GetClass1CompletedEventArgs e )

        {

if ( e.Error != null )throw e.Error;

            progressBar1.Value 

= progressBar1.Maximum; // 调用完成了,把客户端进度条填充满

            Class1 result 
= e.Result as Class1; // 结果转化为Class1对象

            MessageBox.Show( 
"ID is " + ( result.ID.ToString() + ",Name is " + result.Name.ToString() ) ); // 显示从服务器获取的对象值

        }
#endregion

第三种调用,

private void button3_Click ( object sender, EventArgs e )

        {

            AsynCall_In_WebServiceProxyOther();

        }

#region AsynCall_In_WebServiceProxyOtherprivate void AsynCall_In_WebServiceProxyOther ( )

        {

            Service1 service1 

= new Service1(); // Web Service代理类

            service1.BeginGetClass1( 
3000, OnWebMethodCompleted, null ); // 这里开始异步调用

            ChangeProcessBar();
// 调用同时客户端处理不停止

        }
private void OnWebMethodCompleted ( IAsyncResult p_AsyncResult )

        { 

// 方法声明必须带有IAsyncResult类型对象

            Service1 service1 
= new Service1();// Web Service代理类

            Class1 result 
= service1.EndGetClass1( p_AsyncResult ); // 结束调用时结果返回

            MessageBox.Show( 
"ID is " + ( result.ID.ToString() + ",Name is " + result.Name.ToString() ) ); // 显示从服务器获取的对象值

        }
#endregion

细心的读者可能发现第三种方法并没有在调用完成后把客户端的进度条填满,的确在OnWebMethodCompleted中调用progressBar1.Value = progressBar1.Maximum时会出现InvalidOperationException异常,线程间操作无效: 从不是创建控件“progressBar1”的线程访问它。这个异常恐怕在.net下写过多线程操作的人都看到过:)。可以声明一个委托,把处理进度条的代码放到一个方法中,用窗体的Invoke去安全的调用它。好下面把修改的代码写出来,注意加粗的部分

private delegate void MaxProcessBarEventHandle ( ); // 声明最大化客户端进度条控件方法的委托

        
private void OnWebMethodCompleted ( IAsyncResult p_AsyncResult )

        {

            Service1 service1 

= new Service1();

            Class1 result 

= service1.EndGetClass1( p_AsyncResult );

            MessageBox.Show( 

"ID is " + ( result.ID.ToString() + ",Name is " + result.Name.ToString() ) );this.Invoke( new MaxProcessBarEventHandle( MaxProcessBar ) ); // 从进度条创建的线程安全调用MaxProcessBar方法

        }
private void MaxProcessBar ( )

        {

// 客户端进度条最大化方法


            progressBar1.Value 
= progressBar1.Maximum;

        }