利用WCF服务实现Web 2.0用户界面和Web服务

随着互联网技术的发展,Web 2.0用户界面和Web服务的需求日益增长。本文将探讨如何利用WCF(Windows Communication Foundation)服务,结合HTML5、CSS3等前端技术,构建现代的Web应用程序。WCF服务不仅可以作为后端业务逻辑层,还可以通过自托管的方式,提供轻量级的Web服务,从而避免在客户端安装.NET Framework。

WCF最初仅支持SOAP消息。从.NET 3.5开始,通过WebHttpBinding等绑定,WCF开始支持直接从JavaScript的Ajax调用中消费Web服务。然而,JSON等数据格式的消费还不是开箱即用的功能,需要编写大量的DataContract。此外,XML等其他数据格式也无法直接利用JavaScript库,因为需要额外的步骤将XML转换为JSON。

本文介绍的方法将'Stream'作为UI交互操作的输入和输出类型,支持基本认证,并且可以扩展为更高级的用法。这种方法不涉及任何层的定制,完全基于.NET 3.5中WCF的开箱即用特性。此外,它也可以与.NET 4.0一起使用。但是,为了格式化JSON对象,使用了JSON.Net。

使用代码

首先,下载并构建源代码。可以使用Visual Studio 2010或VS命令行。(代码是为.NET 4.0构建的,但也可以与.NET 3.5一起使用。)启动WCFWebApp.exe。如果端口2011不空闲,请更改为不同的端口。并且需要管理员权限。

当服务器运行时,使用支持JavaScript的任何浏览器打开 "http:/<机器名>:<端口>/index.htm"。输入用户名# 'user' 和密码# 'pass' 并点击登录。将登录并加载关于页面。

点击“状态”链接。检查任何状态的访问选项,然后点击更新。更改页面到关于,然后返回到状态并观察上次选择是否已保留。点击右上角的“注销”。所有这些操作都是通过自托管的WCF服务运行的。这展示了诸如认证、获取静态文件、获取和设置数据等功能。以下部分将详细介绍代码。

服务器代码

主类只是使用WebHttpBinding和WebServiceHost启动WCF服务。服务合同定义了一个方法'Files'来服务所有静态HTML文件,另一个方法'Links'服务所有链接文件,如JavaScript、样式表和数据。其他资源如登录、注销、状态和服务操作。值得注意的是,输入和输出都使用'Stream'数据类型。

class Program { static void Main(string[] args) { string baseAddress = "http://" + Environment.MachineName + ":2011/"; using (WebServiceHost host = new WebServiceHost(typeof(WebApp), new Uri(baseAddress))) { WebHttpBinding binding = new WebHttpBinding(); host.AddServiceEndpoint(typeof(IWCFWebApp01), binding, "").Behaviors.Add(new WebHttpBehavior()); host.Open(); // 其他代码省略以简洁 } } }

服务实现。由于这种方法主要是为自托管的WCF服务设计的,因此使用单例实例和并发线程就足够了。考虑适用的会话。但与IIS托管的服务不同,自托管服务通常服务于有限的用户,因此默认的并发性就足够了。在功能线上,构造函数只是将数据加载到本地成员上。

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] public class WebApp : IWCFWebApp01 { JObject states; public WebApp() { if (states == null) states = JObject.Parse(File.ReadAllText("web\\data\\states.json")); // 其他代码省略以简洁 } }

当用户首次访问时,会提供多个HTM、CSS和JavaScript文件。这些由'Files'和'Links'方法处理。链接是在index.htm的head部分引用的文件,如JQuery。在'Files'方法中,根据不同的扩展名从不同的文件夹中获取不同类型的文件。

public Stream Links(string path, string resource, string extension) { // 其他代码省略以简洁 } public Stream Files(string resource, string extension) { switch (extension) { case "htm": // 其他代码省略以简洁 case "js": // 其他代码省略以简洁 } }

当用户发出登录请求时,会在标准头"Authorization"中发送基本认证令牌。这将在稍后描述的单独方法'Authenticate'中进行验证。此外,用户名作为JSON对象发送在请求流中,使用JSON.Net库将其解析为JSON对象。注销方法与登录类似。

public Stream Login(Stream request) { if (!Authenticate()) return null; // 其他代码省略以简洁 JObject o = JObject.Parse(data); }

当用户点击'States'时,请求到达以下方法。由于此资源没有任何扩展名,请求将不会通过'Files'方法。在这里,请求被认证,数据从成员变量发送。

public Stream States() { if (!Authenticate()) return null; WebOperationContext.Current.OutgoingResponse.ContentType = "application/json"; return new MemoryStream(Encoding.ASCII.GetBytes(states.ToString()), false); }

当用户进行修改并点击'Update'时,将调用以下方法。这将解析状态ID并更新类成员变量,并将更新后的列表返回给客户端。

public Stream State(Stream request) { // 其他代码省略以简洁 JObject data = JObject.Parse(new string(buffer)); int id = ((int)data["id"]) - 1; states["states"][id]["visited"] = true; return States(); }

需要授权的认证方法将调用以下方法:

public bool Authenticate() { string userName = "user"; string password = "pass"; string basicAuthCode = Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}: {1}", userName, password))); string token = WebOperationContext.Current.IncomingRequest.Headers["Authorization"]; if (token.Contains(basicAuthCode)) { return true; } else { WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized; return false; } }

客户端代码

客户端代码放置在名为'web'的单独文件夹中。在此文件夹的根目录下,放置了所有静态HTM文件。另外,包括用于图像、JavaScript和样式表的单独子文件夹。这些是从服务器代码中的'Files'方法根据扩展名引用的。

客户端遵循单页应用程序设计。因此,只有'index.htm'是一个完整的HTML页面。其他HTML文件通过Ajax调用填充到'content'部分,如下所示:

function StatesPage() { this.loadStatesPage = function(data) { content = undefined; $.each(data, function(index, value) { if (data[index]["id"] == "content") { content = data[index].innerHTML; $("#content")[0].innerHTML = content; $("#b_update")[0].onclick = updateStates; loadStatesTable(); } }); if (content == undefined) { alert("Failed to load page: Content missing"); return; } } // 其他代码省略以简洁 }

认证:客户端认证令牌在登录类中。登录后,此令牌在每个调用的'beforeSend'函数的头部分添加。其他客户端代码需要了解Jquery、JavaScript和Ajax概念,这些在Web上都有详细解释。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485