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

ASP.NET MVC:构建您的自定义博客引擎 - 第 2 部分,共 2 部分(工作引擎)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (11投票s)

2016 年 1 月 23 日

CPOL

22分钟阅读

viewsIcon

49435

downloadIcon

1757

阅读完本文后,您将掌握一种轻松发布新博客文章的新颖方法,该方法将自动更新您网站上的内容,并且您将学习到实现此功能的 C# ASP.NET MVC 代码。

引言

这是两部分系列文章的第二部分。

您可以在此处阅读第一部分:https://codeproject.org.cn/Articles/1072781/ASP-NET-MVC-Build-Your-Custom-Blog-Engine-CMS-Part (在新标签页/窗口中打开)

第一部分介绍了如何将 Visual Studio MVC 模板项目操作成您可能实际想要使用的东西。在此过程中,您将很好地了解 MVC 开发。

为什么要阅读本文?

本文将引导您完成创建**组件**的设计和代码,该组件

  1. 您可以将其放到您的 ASP.NET MVC 网站中
  2. 提供一种简单的方法来创建博客页面——它将迭代文档,因此当您添加新文档时,它将显示为当前文章并置于您的文章列表顶部

此组件/文章不包含什么

如果您正在寻找一个完整的博客/CMS(内容管理系统)(Joomla、Drupal、WordPress),您会感到失望。这个组件还有很多需要添加的地方。这是一个“快速完成”的组件。但是,我相信您会从研究设计中学到很多东西,并且您会发现您可以在我创建的设计基础上进行构建。

功能摘要

我希望能够轻松地向我的网站发布新文章,并让它们作为最新内容显示在页面顶部,并自动添加到我的所有文章的链接列表中。

它将如下图所示

blog engine complete

  1. 将鼠标悬停在左侧的项目上会改变样式,以提供用户反馈,表明这是一个可点击的链接到另一篇文章。 
  2. 当用户点击其中一个文章项时,内容会异步加载到右侧的 div 中。
  3. 文章列表是动态加载的,可以随时更新以向用户提供新内容。

然而,肯定还有改进的空间。 

您可能(应该)质疑的设计方面

随着您接触代码,您会发现设计中可以改进的地方。

一个明显的问题是,我使用一个平面文件作为我的博客文章的条目表。这仅仅是因为我不想花时间教授所有的数据库连接、存储过程等繁琐的东西。那是以后要做的事情。但是,您会注意到,您可以轻松地扩展代码,使其从数据库而不是平面文件读取。

如果您对这一点没问题,并且仍然感兴趣——我希望您是——那么让我们开始吧。

背景(与第 1 部分相关)

我曾经想过,我希望博客引擎是一个可即插即用的程序集 (dll),您可以将其放置在 bin 目录中并立即受益。该 dll 的名称将是 UnRio.dll (One River),它将与您的网站(和我的)默认名称分开。  

然而,在第一篇文章中,我将整个项目命名为 UnRio。对于这个项目,您会看到我已将其重命名为 BasicMVC,以便我能够详细研究 UnRio 博客引擎如何在任何站点中工作。

获取 BasicMVC 基础项目

如果您想一步一步地跟着我们构建应用程序,请下载 **BasicMVC_begin.zip** 文件,解压缩并在 Visual Studio 中打开项目(我使用的是 Community Edition)。

该代码与第一篇文章中的代码完全相同,只是重命名为新的 BasicMVC 项目。

旁注:Community 2013 Edition 与 Community 2015

我发现(通过艰难的方式)当我在一台安装了 2013 版的旧电脑上尝试打开项目时,2013 版的 ASP.NET 项目与 2015 版的项目之间存在一个细微的差异。只有在运行后,我才收到导致应用程序崩溃的错误。它看起来像这样

compilation error

这很奇怪,因为错误提示是:[无相关源代码行]

错误消息的重要部分是

编译器错误消息: CS1617: /langversion 的无效选项 '6';必须是 ISO-1、ISO-2、3、4、5 或 Default

您可能知道 Community 2015 使用较新的编译器来构建代码。我对 `web.config` 做了一个更改,使项目在 2015 和 2013 两个版本下都能编译。

我更改的行如下所示(重点关注加粗部分)

<system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" warningLevel="4" compilerOptions="/langversion:5 /nowarn:1659;1699;1701">

我将 /langversion:6(用于 Community 2015)更改为 5,如上所示,它在 Community 2013 中正常工作。

旁注:NuGet

此外,如果您从这个项目获取源代码并在 Visual Studio 中打开它,那么您第一次构建项目时会看到 NuGet 检索 MVC 依赖项程序集 (DLL)。它通过查看项目中找到的 `packages.config` 文件并下载这些 DLL 的相应版本来完成此操作。 

当这种情况发生时,您会看到一个如下所示的窗口

nuget

这允许您获取项目中包含的 DLL 的精确版本,而无需我将它们包含在项目中(使项目下载大小大大减小)。

现在,回到我们定期更新的文章。

设置项目

我们首先需要做的是在 Visual Studio 2015 Community 版中加载 BasicMVC 项目

接下来,让我们向解决方案添加一个名为 UnRio 的新项目。 

该项目应该是一个类库(如下图所示),而不是类库(可移植)。

add new project

添加新项目后,您可以将其作为引用添加到 BasicMVC 项目中,因为 BasicMVC 将依赖它来显示您的博客文章。

右键单击 BasicMVC 项目中的“引用”项,然后单击出现的“添加引用...”菜单项。

add reference

选择左侧的“项目”项,然后勾选 UnRio 复选框,再点击“确定”按钮。

select project

现在我们准备添加一些代码了。 

我们首先需要一些东西来表示(建模)我们的博客文章。我将创建一个简单的 `BlogArticle` 类并将其添加到 UnRio 项目中。它将看起来像这样

namespace UnRio.Models
{
    public class BlogArticle
    {
        private int id;

        public int Id
        {
            get { return id; }
            set { id = value; }
        }
        private string category;

        public string Category
        {
            get { return category; }
            set { category = value; }
        }
        private string title;

        public string Title
        {
            get { return title; }
            set { title = value; }
        }
        private string relativeFilePath;

        public string RelativeFilePath
        {
            get { return relativeFilePath; }
            set { relativeFilePath = value; }
        }
        private DateTime created;

        public DateTime Created
        {
            get { return created; }
            set { created = value; }
        }
    }
}

转换设计:查看步骤

 您可以看到这个类非常简单。它只不过是一堆构成我的 BlogArticle 的属性。我将其保持非常简单,以便您可以看到我所走的每个设计步骤。此时,我只是尝试让 `BlogArticle` 成为一个 `read` 项。我不担心将 BlogArticle 写入任何数据库或文件。

设计可以更好

设计可以做得更好。请不要过分纠结于我们可以做得更好这一事实。我首先尝试实现我想要的功能,然后我再进行重构。我仍然在基于基本的 OOP 原则和 SOLID(维基百科文章在新标签页中打开)原则进行构建,但现在我只想让它工作并向您解释。

继续,我知道我将需要一个博客文章集合,以便我可以通过某种方式迭代它们并在视图中显示给用户,这促使我创建 `BlogArticleRepository` 类。

该类将如下所示

using System;
using System.Collections.Generic;
using System.IO;

namespace UnRio.Models
{
    class BlogArticleRepository : List<BlogArticle>
    {
        private string rootPath;
        private string blogFile;

        public BlogArticleRepository(string rootPath, string blogFile)
        {
            this.rootPath = rootPath;
            this.blogFile = blogFile;
            GetAllBlogArticles(false);
        }

        public void GetAllBlogArticles(bool? forceReload)
        {
            if (this.Count == 0 || (forceReload == true))
            {
                this.Clear();
                LoadBlogArticlesFromDataStore();
            }
        }
        
        private void LoadBlogArticlesFromDataStore()
        {
            string[] allLines = File.ReadAllLines(Path.Combine(rootPath,blogFile)); 
            foreach (string line in allLines)
            {
                try
                {
                    string[] allItems = line.Split('|');

                    BlogArticle ba = new BlogArticle();
                    ba.Id = Convert.ToInt32(allItems[0]); //id 1; newest first (top of file)
                    ba.Title = allItems[1]; // "Biggest Tech Article Ever";
                    ba.Category = allItems[2]; //"Tech";
                    ba.RelativeFilePath = allItems[3];// "TechBlog1.htm";
                    ba.Created = DateTime.Parse(allItems[4]); // 2015-03-31
                    this.Add(ba);
                }
                finally
                {
                    // if any fail, just move to the next one
                    // do not stop the app for any reason!
                }
            }
        }

    }
}

BlogArticleRepository:它做什么?

BlogArticleRepository 让我可以轻松创建 BlogArticle 列表。加载 BlogArticle 的工作实际上都在一个地方完成:`LoadBlogArticlesFromDataStore()`

正如您所见,该方法只是从管道分隔的文本文件中加载文章。

示例文本文件

我已将示例文本文件包含在代码下载中。它名为 **blog.dat**,内容如下

3|Visual Studio's Greatest Hits|Visual Studio|VisStudio1.htm|2015-04-02
2|Develop For Android|Android Dev|AndroidDev1.htm|2015-04-02
1|Biggest Tech Article Ever|Tech|TechBlog1.htm|2015-03-01

显然,这是一个管道分隔的文件,包含 5 个字段,如下所示

  1. id
  2. 文章标题
  3. 文章类别(以后组织文章的简单方式)
  4. 文件名(包含文章的 HTML 文件)
  5. 发布日期——将在视图中显示,以便用户了解文章的发布时间

目前,只有三篇文章将被加载并最终由某个视图显示。

我还创建了示例 HTML 文件,将为每个条目加载这些文件。当然,这些示例 HTML 文件命名为

`VisStudio1.htm`、`AndroidDev1.htm` 和 `TechBlog1.htm`,您可以在 **blogFiles 目录**中的项目文件下载中找到所有这些文件以及 **blog.dat**。

UnRio 项目中的工作到此完成。现在我们要回到 BasicMVC 项目,以便我们可以编写使用 UnRio 库的代码。这将有助于更好地整合所有内容。

设置 BasicMVC 以使用我们的博客引擎 (UnRio 库)

考虑内存中的 BlogArticle 列表

我们首先要考虑的是,无论哪个用户访问我们的网站,我们的博客文章列表都是相同的列表。这意味着,我们只需要在应用程序内存中有一个博客文章列表。一旦列表加载到内存中,那么每个用户会话都应该从该列表中读取。这引导我们查看 `Global.asax` 和 `Global.asax.cs`,因为 ASP.NET MVC 应用程序范围的资源可以在那里加载。

Visual Studio 项目生成器已在该文件中为我们创建了一些代码,因为 ASP.NET 引擎在应用程序启动时会初始化一些东西。这些代码看起来像这样(在我们进行任何修改之前)。

namespace BasicMVC
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}

您可以看到 `Application_Start()` 方法运行,并且很明显,这就是您的 ASP.NET MVC Web 应用程序启动时运行的方法。这也是我们正在寻找的,因为我们想要一次性加载我们的 `BlogArticle` 集合。

我们只需要在此应用程序启动时添加对 BlogArticleRepository 的引用。

静态(应用程序全局)博客文章列表

但是,我们需要创建博客文章集合(List<BlogArticle>)的静态(应用程序全局)实例,以便在内存中有一个全局博客文章列表。这样,一旦它们加载完成,就可以用于为查看我们博客站点的每个用户创建视图。

这是个好主意的原因

这是一个好主意,因为它还意味着从 **blog.dat** 文件加载文章的资源密集型工作(I/O 密集型)将只在应用程序启动时完成。没有必要为发生的每个用户会话加载此列表。 

让我们看看加载博客文章列表是多么容易,以及与在 Web 服务器中定位文件相关的挑战。

使用 BlogArticleRepository

要加载我们的博客文章列表,我们只需在 `Global.asax.cs` 中添加一个 using 语句,然后新建一个 `BlogArticleRepository`。它将如下所示(加粗项已添加)

using UnRio.Models;

namespace BasicMVC
{
    public class MvcApplication : System.Web.HttpApplication
    {
        public static BlogArticleRepository mainBlog; 

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            mainBlog = new BlogArticleRepository("TALK_ABOUT_PATH", "blog.dat");
        }
    }
}

挑战在于理解我们将传入的路径,该路径将允许我们访问 **blog.dat** 文件。

理解 Web 应用程序中的 CurrentDirectory

了解 Web 应用程序执行路径的最佳方法是在 Application_Start() 方法顶部设置一个断点,然后在 Visual Studio **即时窗口**中执行一些代码。

放置断点后,您可以按 F5,应用程序将以调试模式启动。

一旦应用程序启动并停在断点处,您将在 Visual Studio 中看到该行高亮显示。

此时,您可以转到即时窗口并执行以下代码行

System.IO.Directory.GetCurrentDirectory() <ENTER>

它将如下图所示

immediate window

这是 IIS Express(Visual Studio 的迷你 Web 服务器)运行以托管您的 ASP.NET MVC 应用程序的路径。

但是,这并不是我们想要从其中加载 **blog.dat** 的路径。

我们实际上希望从我们网站下的位置加载文件。我已向我们的应用程序添加了一个名为 blogFiles 的新文件夹,并将 **blog.dat** 文件放入其中。 

blogFiles folder

RootPath 的意义

我们需要该文件的完整绝对路径。很可能,在我的机器上,它会与您的不同,因为我的项目目录位于不同的位置。而且,它肯定会与您在生产 Web 服务器上的路径不同。这就是为什么我允许您传入 `rootPath`,它将用于确定文件的位置。 

生产路径挑战

我还发现,当我在本地机器上开发时,我需要一种简单的方法来切换路径,因为我的生产路径完全不同。我使用 GoDaddy 托管,它在同一服务器上托管许多网站,因此它们会生成到您网站的路径,您需要能够动态地发送该路径。这就是它单独存在的原因。

在我的开发机器上,该文件的路径是:c:\Dev\WebDev\BasicMVC2\BasicMVC\blogFiles

您可以看到我的路径的一部分包含“BasicMVC2”,这很可能与您的不同。在编写本文时,我一直在创建替代版本。 

使用真实 RootPath:逐步进入代码

所以现在我已经更改了代码,使其指向我开发机器上的真实路径,并且我再次启动了带有断点的调试模式,并逐步执行代码以证明 **blog.dat** 已加载。所有这些都如下图所示

blog.dat is loaded

使用即时窗口验证执行

您可以看到我在即时窗口中执行了一行引用我们新的 `BlogArticleRepository` 的代码。我运行的代码看起来像

mainBlog[0].Title <ENTER>

这反过来又显示了 BlogArticle 的值,即:Visual Studio 的最大热门作品

警告!!您必须在 Global.asax.cs 中设置 RootPath

第一次运行时,您必须在 global.asax.cs 中设置 RootPath 值,因为我无法知道该值是什么。我已将该值设置为 null,并对该值进行了检查,因此它会抛出异常以警告您。如果您不设置它,它将如下所示

rootPath is null exception

创建可用博客的后续步骤

这是一个巨大的成功,因为现在我们所要做的就是

  1. 添加一个视图来显示我们的文章列表。
  2. 添加一个视图来显示实际的目标文章(在本例中为 VisStudio1.htm)
  3. 添加一种用户访问博客项目的方式(添加菜单项)。

现在让我们来完成所有这些工作。

添加新菜单项

让我们把待办事项清单倒过来,首先添加一个访问博客内容的方法。这将有助于我们回忆在这系列文章的第一部分中如何学习做到这一点。

  1. 转到 BasicMVC 项目中的 **\Views\Shared 文件夹**,并打开 _Layout.cshtml 文件。
  2. 通过添加以下加粗代码,将新的博客菜单项添加为导航栏中的第一个菜单项
<div class="navbar-collapse collapse">
     <ul class="nav navbar-nav">
       <li class=@(@ViewBag.selectedItem == "blog" ? "active" : "")>@Html.ActionLink("Blog", "Index", "Blog")</li>
      <li class = @(@ViewBag.selectedItem == "about" ? "active" : "")>@Html.ActionLink("About", "About", "Home")</li>
     <li class = @(@ViewBag.selectedItem == "contact" ? "active" : "")>@Html.ActionLink("Contact", "Contact", "Home")</li>
   <li class = @(@ViewBag.selectedItem == "extra" ? "active" : "")>@Html.ActionLink("Extra", "Index", "Extra")</li>
</ul>

新的列表元素将成为新的导航栏项目——但请记住它尚未生效。

缺少控制器和动作

请记住,`ActionLink()` 方法接受一个 `Action`(`Controller` 方法)和一个控制器名称来确定哪个 `route` 将匹配,哪个 `action` 将运行以及哪个 `View` 将显示给用户。

添加 BlogController

要解决此问题,我们现在添加 BlogController。

为此(我们在第一部分中学过),您只需右键单击“控制器”文件夹,然后在 Visual Studio 中选择“添加”>“控制器...”菜单项。

add new controller

接下来,我们选择“添加带有读/写操作的 MVC5 控制器”。

add controller step 2

最后,我们必须使用 ASP.NET MVC 约定命名我们的控制器,即 <名词>Controller。在我们的例子中是 BlogController。

add BlogController

Visual Studio 将为我们生成新的 BlogController 并打开它进行编辑。

继续添加代码以设置 ViewBag.selectedItem,以便新的博客菜单项在选中时会更改其样式(在第 1 部分中学到)。

您要添加的代码在以下示例片段中已加粗

using System.Web.Mvc;

namespace BasicMVC.Controllers
{
    public class BlogController : Controller
    {
        // GET: Blog
        public ActionResult Index()
        {
            ViewBag.selectedItem = "blog";
            return View();
        }

我们还不能完全测试我们所做的更改,因为我们需要添加一个相关的 `View`。

现在就开始吧。

添加博客视图

当我们创建新的 BlogController 时,Visual Studio 预计我们想要一个新的 View,因此它在 Views 文件夹下创建了一个名为 Blog 的新文件夹。

blog folder

右键单击该文件夹,然后选择“添加”>“视图...”。将出现以下对话框:(如我们在第 1 部分中看到的)

new view

将视图名称更改为 Index,其余保持不变,然后单击 [添加] 按钮。

同样,Visual Studio 将生成新的视图 (`Index.cshtml`) 并打开它进行编辑。

构建并运行应用程序。**提示**:Visual Studio 构建和运行的快捷键是 `CTRL-F5`。

您将看到新的导航栏项目已添加,单击后会加载新的视图,并且选中时导航栏元素的样式会改变。

blog navbar item added

现在我们准备开始编写代码,这将使我们真正看到一些事情发生。

现在让我们快速行动,这样您就可以看到这个东西的实际效果了。

移动脚本以便我们可以在页面中使用它们

我们首先要做的是稍微改变我们渲染脚本的位置(我们在第 1 部分中学到了捆绑)。 

目前,`_Layout.cshtml` 将它们渲染(加载)在页面其余部分之后,但我需要 jQuery 已经加载,以便我可以操作 DOM。这意味着我们只是想将这些行从 `_Layout.cshtml` 的底部移动到 `head` 部分。  最终产品将如下所示

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap") 
</head>

您会在 _Layout.cshtml 文件的末尾找到加粗的行。剪切并向上移动它们。

接下来,让我们修改我们的 `BlogController` 来改变我们的 `Index` action,使其开始加载和使用我们的博客文章列表。继续更改代码,使其现在看起来像下面这样,然后我将解释代码的作用。

BlogController 代码

public ActionResult Index(int? articleId, bool? forceReload)
        {
            MvcApplication.mainBlog.GetAllBlogArticles(forceReload);
            ViewBag.Articles = (List<UnRio.Models.BlogArticle>)MvcApplication.mainBlog;
            // WARNING!!! Insure that ViewBag.BlogPath terminates with a slash /
            ViewBag.BlogPath = "../blogFiles/";
            if (articleId != null)
            {
                ViewBag.currentArticle = articleId;
            }
            return View();
        }

可空类型有所帮助

首先,您可以看到我添加了两个可空参数(`articleId` 和 `forceReload`),因为它们不会总是通过 URI 发送过来。 

ArticleId 用于加载特定文章

我们很快就会看到处理 `articleId` 值已设置的代码,然后它会自动加载该文章,以便用户可以立即阅读。这允许您以 *http://BasicMVC.com/blog?articleId=5* 的形式将特定博客文章的 URL 分发出去。

ForceReload 允许加载新文章

`forceReload` 布尔值帮助我们,如果它被传入且为 true,那么我们可以从 **blog.dat** 文件重新加载所有文章。如果我们不添加这样的选项,那么新文章只有在应用程序重启时才会加载。这是因为我们将这些作为静态应用程序全局资源加载到 **global.asax.cs** 中,并且该集合只有在应用程序启动时(**Application_Start()**)才会重新加载。

要重新加载文章,您只需发送一个包含 `forceReload` 设置为 true 的博客 URI,如下所示

http://BasicMVC.com/blog?forceReload=true

当您这样做时,UnRio 方法 `GetAllBlogArticles` 内部会评估该值,并且该方法将调用 `LoadBlogArticlesFromDataStore()` 方法,该方法将实际再次读取 blog.dat 文件并重新加载 `List`。以下是调用加载方法的代码

public void GetAllBlogArticles(bool? forceReload)
        {
            if (this.Count == 0 || (forceReload == true))
            {
                this.Clear();
                LoadBlogArticlesFromDataStore();
            }
        }
        

forceReload 有什么用?

真正的重点是,当您在 blog.dat 中添加新的文章条目和一篇新文章时,您只需在浏览器中加载 URI (http://BasicMVC.com/blog?forceReload=true),列表就会更新,然后所有用户都会看到那篇新文章作为列表顶部的默认文章。无需重启您的应用程序或任何其他操作。

回到 BlogController 代码,您可以看到我们下一步是设置/创建一个名为 Articles 的动态 ViewBag 变量中的新项。这只是一个方便变量,我将在视图中使用它来迭代 `List`。

ViewBag.Articles = (List<UnRio.Models.BlogArticle>)MvcApplication.mainBlog;

之后,我们在 ViewBag 中设置了另一个便利项,它将帮助我们构建目标 HTML 文件动态内容的路径。

 ViewBag.BlogPath = "../blogFiles/";

当接下来我们查看将在 `View` 中运行的代码时,这个值会更有意义。

最后,我们的 BlogController 还会检查 articleId 是否不为空。如果不是,则表示有人通过 queryString 发送了一个值,因为他们正在加载一篇他们想直接访问的旧文章。因此在这种情况下,我们再次在 ViewBag 中设置一个便利值。ViewBag 真有意思,不是吗?:)

if (articleId != null)
  {
    ViewBag.currentArticle = articleId;
  }

Blog.cshtml 视图:大部分工作都在这里进行

一旦我们更新了相关的视图 (Blog.cshtml),这个东西就开始工作了。

如果您正在跟着做,请从下载中获取 Blog.cshtml 的最终代码并将其添加到您的项目中。然后,我将不再一次性显示所有代码,而是显示代码块并准确描述它们的作用。

文章已加载,但尚未完成

在我解释每个代码片段之前,请先构建并运行它,这样您就可以看到它的样子以及它如何加载我们的顶部(最新)文章:**VisStudio1.htm**。 

Not quite complete

一些错误

这看起来可能正确,但仍然存在一些问题。

  1. 当鼠标悬停在文章标题上时,光标是 I 形条
  2. 文章标题并不真正突出。
  3. 用户无法判断文章标题是否可点击——我希望在悬停时样式发生变化

我们可以通过更新 CSS 来更改所有这些项目。让我们这样做,让最终产品运行起来,然后我将带您了解代码块,并确切解释 **blog.cshtml** 的作用,以便您可以自己掌握它。

修改 CSS:添加样式以激活视图

现在,我们将在我们的网站中添加一些样式,这将使我们的博客页面渲染得更漂亮一些,并在用户鼠标悬停在左侧可点击链接上时提供反馈。

在第 1 部分中,我们了解到 ASP.NET MVC 应用程序的主要样式在 Content 文件夹的 site.css 文件中。打开该文件,然后简单地粘贴所有以下样式。该文件中的最后一项应该是我们之前添加的样式:`navcustom`  您可以直接在该项之后复制以下样式。

input,
select,
textarea {
    max-width: 280px;
}

.article:hover{
    background-color:#efae14;
    font-weight:bold;
}
.article{
    font-size:large;
}

.pageSection {
    margin-left:0px;
    padding-left: 0px;
    padding-right: 0px;
     margin: 0px ;
     background-color:aliceblue;
}
.leftcolumn, .rightcolumn {
    border: 1px solid white;
    float: left;
    min-height: 25%;
    color: black;
}

.leftcolumn {
    margin: 0;
    padding: 0;
    border: 0;
    cursor: pointer;
        /*background-color: #111;*/
}

.rightcolumn {
/*        width: 75%;*/
        background-color: lightyellow;
        
}

.tight{
    margin-top:20px;
    padding:0px;
}

h3 .tight{
    display: inline-block;
    padding:-5px;
    padding-top:8px;

}
.pubDate{
    font-size:x-small;
    
}

.minus-container{
    margin: 0;
    padding: 0;
    border: 0;
}

.leftPad{
    margin-left:20px;
}

添加这些样式并重建、运行和刷新页面后,您应该会看到

  1. 当您将鼠标悬停在可点击的文章标题上时,会显示一个手形图标
  2. 文章标题采用更好的(更大字体)以区分它们。
  3. 鼠标悬停在标题上时会改变它们的颜色,以向用户指示该项目处于活动状态(请参阅下一部分图像)。

mouse hover action

视图代码解释

让我们看看代码片段,结束这篇文章,然后您应该可以很容易地在您自己的 Web 应用程序中使用 UnRio。

所有视图代码都可以在 `/Blog/Index.cshtml` 中找到。

我们将自上而下地检查文件中的代码片段。页面中找到的代码片段是 `Razor`、`jQuery` 和一些纯 `JavaScript` 的混合。这些将为您提供很好的示例,说明如何操作视图以在项目中显示数据。

我们看到的第一件事是 Razor 脚本

     @{   ViewBag.Title = "RAD Dev US - Blog";

        Layout = "~/Views/Shared/_Layout.cshtml";
        ViewBag.selectedItem = "blog"; }

在这里,我们只是设置了显示在浏览器标题栏上的标题。然后我们设置了用于页面的布局(它是普通的)。最后,我设置了 `selectedItem = "blog"`,正如我们在第 1 部分中看到的那样,以确保博客导航栏项突出显示。

接下来在 /Blog/Index.cshtml 中看到的是一个 jQuery 脚本

   <script>
  (function () {
    $(".pubDate").remove();
    $(".article").remove();

  }());

    </script>

在这里,我执行了一个 `jQuery` 选择器,以查找具有 `pubDate` 类和 `article` 类(CSS 类)的项,然后我简单地调用 `jQuery` 方法来删除这些元素。这确保了以后当我将这些元素附加到(当页面加载或刷新时)时,我不会在左侧列表中重复文章。

再往下一点,我们看到了 Razor 脚本中完成的真正工作。

 

        foreach (var item in ViewBag.Articles)
            {
                  <span class="pubDate">Published: @item.Created.ToString("yyyy-MM-dd")</span>
            <p class="article list-unstyled" id="article_id_@item.Id" onmousedown="showPreview('@ViewBag.BlogPath@item.RelativeFilePath','article_id_@item.Id')">
                @item.Title
            </p>

                    }
                    if (ViewBag.currentArticle != null)
                    {
                        List<UnRio.Models.BlogArticle> localArticles = (List<UnRio.Models.BlogArticle>)ViewBag.Articles;
                        ViewBag.currentArticle = localArticles.Find(x => x.Id == ViewBag.currentArticle);
                        if (ViewBag.currentArticle == null)
                        {
                            // the id for the article wasn't valid so load the default;
                            ViewBag.currentArticle = @ViewBag.Articles[0];
                        }
                    }
                    else
                    {
                        ViewBag.currentArticle = @ViewBag.Articles[0];
                    }
                }

 

动态显示文章列表

我们做的第一件事是迭代 `ViewBag.Articles`。

正如您所见,我们构建了显示在左侧的文章条目,并获取文章标题和发布日期以呈现给用户。

最后,您可以看到如果 `ViewBag.currentArticle` ID 匹配,我们将其设置为显示该 ID 的文章。否则,我们只渲染最新文章(`blog.dat` 中列出的第一篇)。

最后,您会看到两个 JavaScript 方法

 function showPreview(article,element) {
    $('.rightcolumn').load(article);
    if (element != null) {
      $(".article").css("background-color", "");
      $("#" + element).css("background-color", "lightgrey");
    }
  }
  function setSelectedArticle(articleId) {
    $("#" + "article_id_" + articleId).css("background-color", "lightgrey");
  }

showPreview JavaScript 使用 jQuery 异步调用

`showPreview`() JavaScript 函数是真正有趣的。当用户点击文章列表中的一个项目时,我调用 `jQuery load()` 方法来异步加载关联的 HTML 文件(例如 **VisStudio1.htm**)到目标 div(`.rightColumn`)中。

这就是它的全部内容。

现在,您可以进一步扩展此代码。

下一篇文章

我很快会为那些只想使用 UnRio 库并为其网站添加快速博客页面的人撰写另一篇文章。该文章将详细介绍使用 UnRio 并在他们自己的 ASP.NET MVC 网站上设置它的快速步骤。 

感谢您阅读我的文章。

历史

文章和代码的第一个版本:2015/01/23

© . All rights reserved.