LaxCraft - 示例 MVC3 网站






4.74/5 (9投票s)
一个很好的示例应用程序,它利用了 MVC3、Castle Windsor 和 Fluent-NHibernate。
引言
LaxCraft 是一个 ASP.NET MVC3 站点,允许一支青年队跟踪他们在场上和场下的努力。它目前仅设计用于支持一支球队,并且是为长曲棍球(因此得名)设计的,但它可以轻松发展为支持多支球队甚至多个联赛和运动项目。在我赛季结束后,我没有直接放弃这个网站,而是决定拆解这个应用程序并突出一些很酷的功能,以便其他人可以从中学习,因为它可能比典型的 Twitter Feed 或 Hello World 应用程序更有趣。
背景
该网站利用了以下技术
- Castle Windsor 用于依赖注入(Ninject 或其他 IoC 产品也可以)
- Fluent NHibernate,一个建立在 NHibernate 之上的优秀层,它允许无 XML 配置,并且支持真正的 DDD,因为它会为您构建数据库表
- Razor 视图用于呈现,我觉得它比标准的 ASP.NET 视图引擎更简洁
- Telerik MVC UI 扩展,在编辑或创建新闻项目时提供所见即所得编辑器
使用代码
您可以在 http://laxcraft.codeplex.com/ 下载代码和数据库备份,因为代码量太大无法在此 CodeProject 上容纳。
如果您有 SQL Server 实例,您可以还原数据库,或者通过更改 web.config 中 ApplicationServices
项的连接字符串并将 SchemaUpdate
设置为 "Build
",让 Fluent-NHibernate 构建您的数据库。
总体设计/概述
概述
我构建并使用了 LaxCraft 来激励我的队员们自己练习。他们可以花费数小时玩 XBox,但如今,孩子们不像我们以前那样多出门玩耍。该网站模仿了孩子们玩的某些电子游戏,他们可以在其中获得经验值(XP)并在特定类别中升级。该网站允许玩家登录,然后记录他们为某个特定统计数据付出的努力。统计数据会将这些努力转化为获得的 XP,并相应地调整他们的该统计数据的等级。玩家在某个统计数据中获得的 XP 越多,升级的速度就越慢。该应用程序显示所有玩家的团队视图,以及每个玩家在每个统计数据中的等级,以及玩家视图,详细显示玩家在每个统计数据中的位置,并附有详细的统计数据描述以及他们还需要多少 XP 才能进入下一个级别。
领域设计
一个用户可以是一个玩家或一个管理员。玩家可以为某些统计数据输入努力并获得 XP,而管理员可以管理所有玩家的所有统计数据。这是一个相当通用的设计,可以灵活地处理任何类型的进度跟踪,而不仅仅是长曲棍球或体育运动。
关注点
依赖注入
Global.asax.cs 的 Application_Start
方法将调用 BootstrapContainer()
方法,该方法将设置将用于特定接口的具体类。Install
方法将查找当前程序集中所有继承自 IWindsorInstaller
的类,并调用它们的 Install
方法。我认为我更喜欢 Ninject 的依赖注入方式,因为它更简洁易懂,但 Castle 的 Windsor 是我在此项目中使用的。
private static void BootstrapContainer()
{
container = new WindsorContainer()
.Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<persistencefacility>();
}
PersistenceFacility
将告知应用程序它将如何存储数据,并告诉 Fluent 应该与哪个数据库进行数据持久化交互。
protected override void Init()
{
var config = BuildDatabaseConfiguration();
Kernel.Register(
Component.For<isessionfactory>()
.UsingFactoryMethod(config.BuildSessionFactory),
Component.For<isession>()
.UsingFactoryMethod(k => k.Resolve<isessionfactory>().OpenSession())
.LifeStyle.PerWebRequest);
}
private Configuration BuildDatabaseConfiguration()
{
return Fluently.Configure()
.Database(SetupDatabase)
.Mappings(m => m.AutoMappings.Add(CreateMappingModel()))
.ExposeConfiguration(ConfigurePersistence)
.BuildConfiguration();
}
DotNetOpenAuth 身份验证
该项目利用了 Visual Studio 中构建新的 MVC3 Web 应用程序时添加的标准 DotNetOpenAuth 身份验证,但经过了调整:成功身份验证后,系统会检查数据库中是否已存在该电子邮件,如果存在,则将用户映射到特定玩家。如果电子邮件不存在,则会引导用户到一个屏幕,在那里他们可以选择他们是哪个玩家,然后创建关联。如果这是一个生产级别的应用程序,这一点需要稍作调整,但对于该应用程序的用途来说,已经足够了。
[HttpPost]
public ActionResult MapPlayer(FormCollection collection)
{
var user = new User
{
Username = HttpContext.User.Identity.Name,
Email = collection["Email"],
Player = team.GetPlayer(int.Parse(collection["PlayerId"]))
};
users.SaveUser(user);
NHibernateUtil.Initialize(user.Player);
Session["CurrentUser"] = user;
return RedirectToAction("Index", "Team");
}
团队视图
控制器 (Controller)
TeamController
会注入一个 ITeamRepository
,这使得它能够获取所有团队成员和统计数据。
public class TeamController : Controller
{
private readonly ITeamRepository team;
public TeamController(ITeamRepository team)
{
this.team = team;
}
public ActionResult Index()
{
ViewBag.Players = team.GetPlayers().OrderBy(p => p.Name).ToList();
ViewBag.Stats = team.GetStats().OrderBy(s => s.Order).ToList();
return View(ViewBag);
}
视图
视图使用 Razor 语法构建一个表,通过遍历 ViewBag 中的统计数据以及团队中的每个玩家。由于 XP 和等级的计算方式,这里可能有一些性能优化或更好的缓存空间。PlayerStat
上的 GetLevel
方法中有一些工作,该方法对每个玩家的每个统计数据都会被调用。所以在团队页面上,如果您有 10 个玩家和 10 个统计数据,该方法将被调用 100 次。
可能有些前端开发者看到那些 Table
标签会皱眉,但我相信如果您的内容确实是数据并且应该放在表格中,那么使用表格而不是 div
标签是可以接受的。
利用了一个名为 TableSorter 的 jQuery 插件,允许用户按特定统计数据排序表格。利用了一个名为 jQueryTools 的 jQuery 插件用于工具提示,在玩家详情页面上,动画进度条利用了 Twits jQuery Progress Bar。
<table id="teamTable" class="tablesorter">
<thead>
<tr>
<th>
Name
</th>
@foreach (var stat in ViewBag.Stats) {
<th>
<span class="abbreviation">@stat.Abreviation</span>
<div class="tooltip">
@stat.Name - @stat.Description
</div>
</th>
}
</tr>
</thead>
<tbody>
@foreach (var player in ViewBag.Players) {
<tr>
<td class="playerName">
@(Html.ActionLink((string)player.Name, "Player",
"Team", new { id = player.Id }, null))
</td>
@foreach (var stat in player.GetCompletePlayerStats(ViewBag.Stats)) {
<td>
@{var level = stat.GetLevel();}
@{var title = string.Format("level {0}: {1}",
level, LaxCraftSession.LevelTitles[level]);}
@{var src = Url.Content("~/content/images/" + level + ".png");}
<img src="@src" alt="@title" title="@title" />
</td>
}
</tr>
}
</tbody>
新闻发布
控制器 (Controller)
Post Controller 非常直接,它会注入一个 IPostRepository
,并使用该存储库获取所有帖子进行显示。
private readonly IPostRepository blog;
public PostController(IPostRepository blog)
{
this.blog = blog;
}
public ActionResult Index()
{
ViewBag.Posts = blog.GetPosts().OrderByDescending(p => p.CreatedOn);
ViewBag.Admin = LaxCraftSession.CurrentUser.IsAdministrator;
return View(ViewBag);
}
视图
Post 视图将遍历每个帖子,显示 HTML 和元数据,包括标签和作者,并显示编辑、删除或创建(如果用户是管理员)的链接。
@foreach (var post in ViewBag.Posts) {
<div class="postTitle">@post.Title</div>
<div class="postBody">
@post.GetHtml()
</div>
<div class="postFooter">
@string.Format("Posted by {0} on {1:g}", post.CreatedBy, post.CreatedOn);
<br />
@if (!string.IsNullOrEmpty(post.Tags)) {
foreach (var tag in post.Tags.Split(",".ToCharArray())) {
<span class="tag">@tag</span>
}
}
</div>
if (ViewBag.Admin) {
<div class="adminAction">
@Html.ActionLink("Edit", "Edit", new { id = post.Id })
@Html.ActionLink("Delete", "Delete",
new { id = post.Id }, new { rel = "nofollow" })
</div>
}
}
所见即所得编辑
Post 的创建和编辑视图使用了 Telerik 的 MVC3 扩展,提供了一个漂亮的富文本编辑器。
@Html.ValidationSummary(true)
<fieldset>
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Body)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Body)
@Html.ValidationMessageFor(model => model.Body)
@{ Html.Telerik().Editor()
.Name("editor")
.HtmlAttributes(new { style = "height:400px" })
.Encode(false)
.Value(@<text>
<p>
<img src="@Url.Content("~/Content/Images/33.png")"
alt="Editor for ASP.NET MVC logo"
style="display:block;margin-left:auto;margin-right:auto;" />
Telerik Editor for ASP.NET MVC allows your users
to edit HTML in a familiar, user-friendly way.
<br />In this version, the Editor provides
the core HTML editing engine, which includes
</p>
</text>).Render();
}
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Tags)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Tags)
@Html.ValidationMessageFor(model => model.Tags)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.CreatedBy)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.CreatedBy)
@Html.ValidationMessageFor(model => model.CreatedBy)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
这是 Controller 中处理表单提交并将新帖子保存到数据库的方法
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(Post post)
{
if (ModelState.IsValid)
{
var newPost = new Post { Body = post.Body, Tags = post.Tags,
Title = post.Title, CreatedBy = post.CreatedBy,
CreatedOn = DateTime.Now };
blog.Save(newPost);
return RedirectToAction("Index");
}
return View(post);
}
历史
- 文章提交日期:2011 年 8 月 1 日。