博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Silverlight同步(Synchronous)调用WCF服务
阅读量:5752 次
发布时间:2019-06-18

本文共 5439 字,大约阅读时间需要 18 分钟。

  Silverlight的RIA应用中访问远端的WebService或WCF服务,都是通过异步线程模式调用的。在某些情况下我们的调用是需要同步进行,虽然Silverlight没有内置同步线程模式调用远端服务接口,但是我们可以通过多线程的处理来伪装出同步调用的实现。在.NET Framework的多线程编程中提供了丰富的线程接口,其中AutoResetEvent和ManualResetEvent在多线程编码中最为常用,本文将介绍如何通过AutoResetEvent的线程等待特性实现Silverlight同步调用远端WCF服务。

 

一、定义WCF服务

  为了演示同步调用WCF服务的实现,提供一个简单的WCF服务接口,完成返回一本图书基本信息,WCF服务接口定义如下:

[ServiceContract]
public
 
interface
 IDataService
{
    [OperationContract]
    Book GetBook();
}
public
 
class
 Book
{
    
public
 
int
 ID { 
get
set
; }
    
public
 
string
 Name { 
get
set
; }
    
public
 
string
 Author { 
get
set
; }
    
public
 
double
 Price { 
get
set
; }
}

 

  接口提供一个返回图书基本信息的方法,包括图书编好,图书名,图书作者以及图书价格。接口具体的实现如下代码:

public
 
class
 DataService : IDataService
{
    
public
 Book GetBook()
    {
        
return
 
new
 Book
        {
            ID 
=
 
1001
,
            Name 
=
 
"
《三国演义》
"
,
            Author 
=
 
"
罗贯中
"
,
            Price 
=
 
89.50
        };
    }
}

 

   如上提供可正常运行的WCF服务接口,在需要调用接口的地方通过WEB引用既可生成该服务的客户端代理对象。

 

二、基于MVVM模式的视图模型

  MVVM模式的核心为INotifyPropertyChanged接口,对于实体模型对象和UI控件元素间提供了完善的同步更新特性。为了方便界面元素同步更新,这里引入了MVVP模式的简单应用。

public
 
class
 ViewModelBase : INotifyPropertyChanged
{
    
public
 
event
 PropertyChangedEventHandler PropertyChanged;
    
protected
 
void
 RaisePropertyChangedEvent(
string
 propertyName)
    {
        var handler 
=
 PropertyChanged;
        
if
 (handler 
!=
 
null
)
            handler(
this
new
 PropertyChangedEventArgs(propertyName));
    }
}

 

  还需要对应于服务接口中的Book对象定义一个ViewModel对象,详细如下代码所示:

public
 
class
 BookViewModel : ViewModelBase
{
    
private
 
int
 iD;
    
///
 
<summary>
    
///
 图书ID
    
///
 
</summary>
    
public
 
int
 ID
    {
        
get
 { 
return
 iD; }
        
set
        {
            iD 
=
 value;
            RaisePropertyChangedEvent(
"
ID
"
);
        }
    }
    
private
 
string
 name;
    
///
 
<summary>
    
///
 图书名称
    
///
 
</summary>
    
public
 
string
 Name
    {
        
get
 { 
return
 name; }
        
set
        {
            name 
=
 value;
            RaisePropertyChangedEvent(
"
Name
"
);
        }
    }
    
private
 
string
 author;
    
///
 
<summary>
    
///
 图书作者
    
///
 
</summary>
    
public
 
string
 Author
    {
        
get
 { 
return
 author; }
        
set
        {
            author 
=
 value;
            RaisePropertyChangedEvent(
"
Author
"
);
        }
    }
    
private
 
double
 price;
    
///
 
<summary>
    
///
 图书价格
    
///
 
</summary>
    
public
 
double
 Price
    {
        
get
 { 
return
 price; }
        
set
        {
            price 
=
 value;
            RaisePropertyChangedEvent(
"
Price
"
);
        }
    }
}

 

三、基于AutoResetEvent的同步实现

   利用AutoResetEvent的线程等待特性,可以折中实现Silverlight同步调用远端WCF服务。其原理就是在Silverlight发起异步调用远端WCF的时候进行线程阻塞,比记录异步调用远端WCF服务接口的完成事件,当异步调用完成后就终止线程阻塞,从而获取状态事件对象中或得调用远程接口所返回的结果。由于视图模型对象实现了INotifyPropertyChanged接口能够及时的更新界面元素,以此间接的就实现了同步方式调用。

public
 
class
 AsyncCallStatus
<
T
>
{
    
public
 AsyncCallStatus()
    {
    }
    
public
 T CompletedEventArgs { 
get
set
; }
}

 

 

public
 
class
 BookFacade
{
    
private
 AutoResetEvent autoResetEvent 
=
 
new
 AutoResetEvent(
false
);
    
public
 
void
 GetBook(BookViewModel viewModel)
    {
        
if
 (viewModel 
==
 
null
)
        {
            
throw
 
new
 ArgumentNullException(
"
viewModel
"
"
参数不能为空。
"
);
        }
        DataService.DataServiceClient client 
=
 
new
 DataService.DataServiceClient();
        client.GetBookCompleted 
+=
 client_GetBookCompleted;
        var status 
=
 
new
 AsyncCallStatus
<
GetBookCompletedEventArgs
>
();
        client.GetBookAsync(status);
        
//
阻塞线程
        autoResetEvent.WaitOne();
        
if
 (status.CompletedEventArgs.Error 
!=
 
null
)
        {
            
throw
 status.CompletedEventArgs.Error;
        }
        var book 
=
 status.CompletedEventArgs.Result;
        viewModel.ID 
=
 book.ID;
        viewModel.Name 
=
 book.Name;
        viewModel.Author 
=
 book.Author;
        viewModel.Price 
=
 book.Price;
    }
    
private
 
void
 client_GetBookCompleted(
object
 sender, GetBookCompletedEventArgs e)
    {
        var status 
=
 e.UserState 
as
 AsyncCallStatus
<
GetBookCompletedEventArgs
>
;
        status.CompletedEventArgs 
=
 e;
        
//
终止线程阻塞
        autoResetEvent.Set();
    }
}

 

 

四、Silverlight前端调用

  Siverlight前端就简单布局一个表单作为数据呈现界面,其代码如下:

<
Grid 
x:Name
="LayoutRoot"
 Background
="White"
>
    
<
Grid 
HorizontalAlignment
="Left"
 Name
="grid1"
 VerticalAlignment
="Top"
 Width
="300"
 Margin
="20"
>
        
<
Grid.RowDefinitions
>
            
<
RowDefinition 
Height
="30"
></
RowDefinition
>
            
<
RowDefinition 
Height
="30"
></
RowDefinition
>
            
<
RowDefinition 
Height
="30"
></
RowDefinition
>
            
<
RowDefinition 
Height
="30"
></
RowDefinition
>
            
<
RowDefinition 
Height
="30"
></
RowDefinition
>
        
</
Grid.RowDefinitions
>
        
<
Grid.ColumnDefinitions
>
            
<
ColumnDefinition 
Width
="60"
></
ColumnDefinition
>
            
<
ColumnDefinition 
Width
="*"
></
ColumnDefinition
>
        
</
Grid.ColumnDefinitions
>
        
<
sdk:Label  
HorizontalAlignment
="Left"
 Content
="图书编号:"
 VerticalAlignment
="Center"
 Grid.Column
="0"
 Grid.Row
="0"
/>
        
<
TextBox 
Text
="
{Binding ID}
"
 Grid.Column
="1"
 Grid.Row
="0"
></
TextBox
>
        
<
sdk:Label  
HorizontalAlignment
="Left"
 Content
="图书名称:"
 VerticalAlignment
="Center"
 Grid.Column
="0"
 Grid.Row
="1"
/>
        
<
TextBox 
Text
="
{Binding Name}
"
 Grid.Column
="1"
 Grid.Row
="1"
></
TextBox
>
        
<
sdk:Label  
HorizontalAlignment
="Left"
 Content
="图书作者:"
 VerticalAlignment
="Center"
 Grid.Column
="0"
 Grid.Row
="2"
/>
        
<
TextBox 
Text
="
{Binding Author}
"
 Grid.Column
="1"
 Grid.Row
="2"
></
TextBox
>
        
<
sdk:Label  
HorizontalAlignment
="Left"
 Content
="图书价格:"
 VerticalAlignment
="Center"
 Grid.Column
="0"
 Grid.Row
="3"
/>
        
<
TextBox 
Text
="
{Binding Price}
"
 Grid.Column
="1"
 Grid.Row
="3"
></
TextBox
>
 
            
        
<
Button 
Content
="查询"
 Grid.Column
="1"
 Grid.Row
="4"
 Width
="60"
 Height
="23"
 Click
="Button_Click"
></
Button
>
    
</
Grid
>
</
Grid
>

 

   通过按钮执行调用WCF服务接口查询图书信息,按钮事件直接使用上面所写的图书门面类(BookFacade)的调用服务方法即可。

private
 
void
 Button_Click(
object
 sender, RoutedEventArgs e)
{
    
try
    {
        ThreadPool.QueueUserWorkItem(
delegate
(
object
 o)
        {
            BookViewModel viewModel 
=
 
new
 BookViewModel();
            
new
 BookFacade().GetBook(viewModel);
            Deployment.Current.Dispatcher.BeginInvoke(() 
=>
 
this
.DataContext 
=
 viewModel);
        });
    }
    
catch
 (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

 

   最终的运行如下图所示效果:

  

 

  

本文转自 beniao 51CTO博客,原文链接:http://blog.51cto.com/beniao/473971,如需转载请自行联系原作者
你可能感兴趣的文章
【M22】考虑以操作符复合形式(op=)取代其独身形式(op)
查看>>
yield 关键字
查看>>
[转】.Net开发人员可以拥抱Entity Framework 了
查看>>
电影集合
查看>>
c# 汉字转拼音
查看>>
Win7输入法消失和不能切换的办法了
查看>>
[转]通过继承ConfigurationSection,在web.config中增加自定义配置
查看>>
使用UIImagePickerController时3DTouch引起Crash
查看>>
实时 Django 终于来了 —— Django Channels 入门指南
查看>>
硬链接和软链接的区别
查看>>
XPage的使用示范例子
查看>>
【转】【MySQL】Mysql模糊查询like提速优化
查看>>
(原創) 微軟開發技術的大變革:WPF(Windows Presentation Foundation) (初級) (.NET)
查看>>
一步一步学Silverlight 2系列(19):如何在Silverlight中与HTML DOM交互(上)
查看>>
检测网页是否是伪静态
查看>>
c常用字符实战操作
查看>>
android开发_Button控件
查看>>
27个jQuery网页拖放操作的插件
查看>>
extjs 验证消息不显示
查看>>
Scanner方法 转
查看>>