65.9K
CodeProject 正在变化。 阅读更多。
Home

Silverlight 中的同步 WCF 服务调用

starIconstarIconstarIconstarIconstarIcon

5.00/5 (11投票s)

2010年3月16日

CPOL

2分钟阅读

viewsIcon

73623

downloadIcon

971

如何在 Silverlight 中进行真正的同步调用

点击一个按钮会冻结 Silverlight UI 线程,但不会冻结浏览器。

引言

这篇文章献给 Daniel Vaughan,他是 CodeProject 上最优秀的作者之一。昨天,我看到他的一篇文章关于 Silverlight 中的同步调用。我不同意他的方法,最终在异步线程上进行同步调用。大多数同步问题都无法用它解决。

我需要在自己的应用程序中进行同步调用,以在我的 Silverlight 应用程序和 LMS 服务器(暴露 WCF 服务)之间创建通信管道。

我的解决方案

我的解决方案非常简单,我只是使用 JavaScript,Silverlight 的兄弟,通过 XmlHttpRequest 对象来调用我的 WCF 服务。我创建了一个通用的 JS 函数,它将调用 WCF 前端的指定方法并添加指定的参数。

我创建了一个管理器,它调用这个 JS 函数并格式化一个简单的 JSON 消息。

这个示例非常基础,因为我没有太多时间来改进它。它只使用 string 参数和 string 返回值。如果您想使用其他对象类型的 WCF OperationContract ,只需使用真正的 JSON 序列化器即可。:)

JavaScript 部分

该函数读取管理器通过 arguments 数组传递的参数

function SyncWCFServiceCaller() 
{
var client = null;

if (window.XMLHttpRequest)
client = new XMLHttpRequest();
else if (window.ActiveXObject)
client = new ActiveXObject("Microsoft.XMLHTTP");
var data = arguments[1];
client.open('POST', arguments[0], false);
client.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
client.setRequestHeader('Content-Length', data.length + '');
client.send(data);
var response = eval('(' + client.responseText + ')').d;
return response;
}

arguments[0] 包含 WCF 端点和方法名称(例如 "localhost/service.svc/method")。

arguments[1] 包含序列化的参数(以 JSON 格式),例如 "{"name" : "daniel"}"

这里没有什么复杂的。XmlHttpRequest 创建一个同步调用,因此如果从 Silverlight 调用,它不会在服务返回之前返回给调用者。

我的工作只使用 string 对象类型,所以我只是返回默认的 'd' JSON 对象,其中包含结果。

Silverlight 部分

C# 管理器也很简单

public class ContractToJavascriptCaller<T>
{
public string ServiceEndPointUri
{
get;
private set;
}
public ContractToJavascriptCaller(string serviceEndPointUri)
{
this.ServiceEndPointUri = serviceEndPointUri;
}
public object CallMethod(string methodName, params string[] arguments)
{
StringBuilder builder = new StringBuilder();
builder.Append("{");
MethodInfo methodInfo = typeof(T).GetMethod(methodName);
ParameterInfo[] parameters = methodInfo.GetParameters();
int parameterIndex = 0;
foreach (ParameterInfo parameter in parameters)
{
builder.Append("\"");
builder.Append(parameter.Name);
builder.Append("\"");
builder.Append(":\"");
builder.Append(arguments[parameterIndex++]);
builder.Append("\",");
}

string jsonSerializedParameters = builder.ToString().TrimEnd(',');
jsonSerializedParameters = string.Concat(jsonSerializedParameters, "}");

return HtmlPage.Window.Invoke("SyncWCFServiceCaller", 
	string.Concat(this.ServiceEndPointUri, "/", methodName), 
	jsonSerializedParameters);
}
}

这个管理器只有一个方法,CallMethod,它将使用服务的端点和方法名称以及序列化为 JSON 的参数来调用 JS 函数。HtmlPage.Window.Invoke 不会在 WCF 服务调用完成之前返回。

CallMethod 接收要调用的 WCF MethodName 。它使用反射来获取参数并将其名称和值序列化为 JSON。

就这样!如果您以这种方式调用 WCF 服务,您将冻结 UI 线程,但不会冻结浏览器。

调用 WCF 服务

我的 WCF 服务包含两个方法

string DoWork(string name);
string DoWorkWithTwoParams(string name, string name2); 

我在它们的指令块中放置了一个 Thread.Sleep 指令,以模拟大量的计算指令。WCF 服务的接口链接到 Silverlight 项目中。因此,要调用 WCF 方法,我只需要执行

ContractToJavascriptCaller<IDanielService> caller = 
new ContractToJavascriptCaller<IDanielService>(https://:23770/DanielService.svc);
string response = caller.CallMethod("DoWork", this.firstMathodTextBlock.Text).ToString();
this.ResultTextBlock.Text = response; 

抱歉

  1. 我的英语不好
  2. 代码质量不高,我真的没有时间:我目前正在收听 Mix 2010 会议关于 WP7 的内容。

历史

  • 2010 年 3 月 15 日:初始发布
© . All rights reserved.