今天,我们将使用SignalR + KnockoutJS + ASP.NET MVC实现一个实时HTML5的井字棋游戏。
首先,网络游戏平台一定要让用户登陆进来,所以需要一个登陆模块,然后就是游戏设计并且在游戏过程中保持用户连接有效性,假设用户玩着玩着突然掉线这肯定会使用户很不爽;因此,保持客户端和服务端通讯的稳定性变得至关重要了,这里我们将使用SignalR和Html5保持通讯实时和稳定。
近一、两年來HTML5的发展是沸沸扬扬,在这其中你也许听过HTML5的规划给浏览器与服务器之间进行全双工通讯的WebSocket的通讯协定,并提供了的WebSocket API,这一套完整的API设计,在规格的部分,WebSocket的通讯协定已经于2011年被IETF(国际网路工程研究团队)定为标准的RFC 6455,而的WebSocket API则被W3C定为标准。目前各平台的浏览器的主流版本皆已经支援HTML5的WebSocket / WebSocket API。
WebSocket / WebSocket API企图解决开发者长久以来实现服务器推送技术几乎都依赖于轮询的方式所造成的明显缺点,使得服务器接受到太多请求,导致服务器资源过度占用以及带宽的浪费。
那么,我们使用WebSocket / WebSocket API就可以确保客户端和服务器通讯的稳定性,但我们要面对一个事实是不是每个用户的浏览器都支持HTML5,我们必须提高旧的浏览器支持方案。
SignalR的出现让ASP.NET的开发者得到了救赎,兼容的通讯协议设计将Comet PRogramming概念和WebSocket技术都放在SignalR整个通讯架构中;SignalR会针对目前执行的浏览器进行判断,找到客户端(浏览器)与服务器最合适的建立链接方式。
SignalR会优先选用WebSocket技术与服务器沟通,开发人员就不需要针对浏览器而做出特殊的处理,所有的代码都通过ASP.NET SignalR高级的API进行信息传递。
图1 SignalR通讯的链接方式
首先,我们将使用ASP.NET MVC和SignalR实现服务端,客户端使用KnockoutJS和Html5获取和绑定数据到页面,具体设计如下图:
图2 井字棋游戏设计
我们使用SignalR提供一个简单的API用于创建服务器端到客户端的远程过程调用(RPC),以便从服务器端.NET代码中调用客户端浏览器(以及其他客户端平台)中的Javascript函数;客户端浏览器也可以通过SigalR来调用服务端.NET代码。
接下来,我们要实现.NET服务器端,由于我们游戏平台是让用户登陆后进行游戏的,所以我们将实现用户帐户管理的模块。
首先,我们创建一个ASP.NET MVC4 Web application。
图3 ASP.NET MVC4 Web Application
这里我们选择Empty模板就可以了。
图4 ASP.NET MVC4 Web Application
然后,我们在项目中使用以下Nuget包:
我们知道ASP.NET MVC自带的权限表的创建是在InitializeSimpleMembershipAttribute.cs中实现的,所以我们在程序中添加Filters文件夹,然后创建InitializeSimpleMembershipAttribute类,具体定义如下:
namespace OnlineTicTacTor.Filters{ /// <summary> /// Simple Membership initializer. /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute { private static SimpleMembershipInitializer _initializer; private static object _initializerLock = new object(); private static bool _isInitialized; public override void OnActionExecuting(ActionExecutingContext filterContext) { // Ensure ASP.NET Simple Membership is initialized only once per app start LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock); } private class SimpleMembershipInitializer { public SimpleMembershipInitializer() { Database.SetInitializer<UsersContext>(null); try { using (var context = new UsersContext()) { if (!context.Database.Exists()) { // Create the SimpleMembership database without Entity Framework migration schema ((IObjectContextAdapter)context).ObjectContext.CreateDatabase(); } } WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true); } catch (Exception ex) { throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized.", ex); } } } } }
上面,我们定义了Web.ConfigInitializeSimpleMembershipAttribute类,接着我们在Web.config中的配置数据库。
<connectionStrings> <add name="DefaultConnection" connectionString="Data Source=(LocalDb)/v11.0;Initial Catalog=GamesDB;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|/GamesDB.mdf" providerName="System.Data.SqlClient" /> </connectionStrings>
我们定义了数据库GamesDB,现在我们运行整个项目,看到localdb中生成了GamesDB数据库。
图5 GamesDB数据库
由于,我们使用ASP.NET MVC自带的权限表来管理用户账号,这里会使用到表UserProfile和webpages_Membership,当然,如果有更复杂的权限管理,我们可以使用表webpages_Roles和webpages_UsersInRoles等。
现在,我们已经创建了数据库GamesDB,接下来定义对应于数据表的DTO,首先,我们在Models文件夹中创建AccountModels.cs文件,然后定义类LoginModel具体定义如下:
/// <summary> /// The DTO for user account. /// </summary> public class LoginModel { [Required] [Display(Name = "User name")] public string UserName { get; set; } [Required] [DataType(DataType.PassWord)] [Display(Name = "Password")] public string Password { get; set; } [Display(Name = "Remember me?")] public bool RememberMe { get; set; } }
上面,我们定义了数据传输类LoginModel,它包含了UserName、Password和RememberMe等信息。
接下来,我们在Account文件中创建用户登陆页面Login.cshtml,由于时间的关系我们已经把页面设计好了,具体定下如下:
@model OnlineTicTacTor.Models.LoginModel@{ ViewBag.Title = "Login";}<section> @using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl })) { @Html.AntiForgeryToken(); @Html.ValidationSummary(); <div class="container"> <div class="content"> <div class="form-group"> @Html.LabelFor(m => m.UserName) @Html.TextBoxFor(m => m.UserName, new { @class = "form-control", @placeholder = "UserName" }) @Html.ValidationMessageFor(m => m.UserName) </div> <div class="form-group"> @Html.LabelFor(m => m.Password) @Html.PasswordFor(m => m.Password, new { @class = "form-control", @placeholder = "Password" }) @Html.ValidationMessageFor(m => m.Password) </div> <div class="checkbox"> @Html.CheckBoxFor(m => m.RememberMe) @Html.LabelFor(m =>
新闻热点
疑难解答