2018-05-19
前言:
步骤1:创建初始的Blog应用
本次示例使用Phil Haack's Really Empty MVC Project Template,添加文件夹:App_Data/BlogPosts,Content/BlogPostImages;添加Controller: HomeController;以及相关联的View Views/Home/Index.cshtml;和其他Shared Views,初始的CSS样式。完整的Solution结构和完成后的应用运行截图如下:
placeholder:截图1
步骤2:安装Markdown
Markdown是一个text-to-HTML转化工具,针对人群为网络写手,博主等。Markdown允许你用容易读/写的纯文本格式写文章,然后转变成结构正确的XHTML(或者HTML)。Markdown格式的文本设计目的是允许内容以as-is发布,像纯文本,不需要用tag标记等。Markdown是免费软件,遵循BSD-style开源协议license。
既然我们使用MVC 3(语言为C#),可以利用MarkdownSharp,也是一个开源的Markdown处理器的C#实现,在Stack Overflow上被featured。使用Nuget Package Manager console安装(添加一个单独文件MarkdownSharp.dll到Bin目录):
PM> Install-Package MarkdownSharp
步骤3:Blog Post和Summary Data命名约定
Blog post是.txt文件,存储在文件夹AppData/BlogPosts。本次示例,我们对文件blog post和文件blog summary使用如下的命名约定,使用字符分割日期和名称信息:
YYYY-MM-DD[blog-post-name-separated-by-hyphens].txt // blog post markdown syntax content
YYYY-MM-DD[blog-post-name-separated-by-hyphens]_summary.txt // JSON formatted blog summary info
使用两个文件的目的是将Markdown的内容和Blog Post summary。Markdown的目标就是内容的as-is,无须任何额外的标记tag或者指令。YYYY-MM-DD用来表示博客发布时间,[]内为博客标题,使用-字符分开单词。Summary文件使用JSON语法现实blog summary。
步骤4:创建File System Data Model
首先,创建model Models/BlogListing.cs,用来表征创建博客需要的数据。
namespace TxtBasedBlog.Sample.Models{ public class BlogListing { public string Url { get; set; } public string Title { get; set; } public string ShortDescription { get; set; } public string Content { get; set; } public string Author { get; set; } public DateTime PostDate { get; set; } public string Image { get; set; } }}
然后,创建model Models/BlogPost.cs负责加载博客文章内容。
namespace TxtBasedBlog.Sample.Models{ public class BlogPost : BlogListing { public string Body { get; set; } }}
步骤5:写一个Blog Post示例
遵循上述命名约定,我们创建两个示例文件。Summary文件使用JSON语法,完整的blog post使用Markdown语法。
{ Title: "ASP.NET MVC Overview", Url: "asp_net_mvc_overview", PostDate: "2012-02-09", Author: "Microsoft ASP.NET Team", ShortDescription: "ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that enables a clean separation of concerns and that gives you full control over markup for enjoyable, agile development.", Image: "content/blogpostimages/image001.jpg"}
**ASP.NET MVC** gives you a powerful, patterns-based way to build dynamic websites that enables a clean separation of concerns and that gives you full control over markup for enjoyable, agile development. MVC includes many features that enable:* fast, TDD-friendly development for creating sophisticated applications* use the latest web standards.[Learn More About MVC](http://www.asp.net/mvc "Learn more about MVC today!")
步骤6:显示博客列表
在web.config中的appSetting键值中添加BlogPostsDirectory配置,这样可以无需编译修改数据目录。
<appSettings> ... <add key="BlogPostsDirectory" value="~/App_Data/BlogPosts"/> ...</appSettings>
Models/BlogFileSystemManager.cs用来检查上面配置的数据目录,然后返回博客列表。
namespace TxtBasedBlog.Sample.Models{ public class BlogFileSystemManager { private string filePathToBlogPosts; public BlogFileSystemManager(string dirPath) { filePathToBlogPosts = dirPath; } public List<BlogListing> GetBlogListings(int limit) { var allFileNames = getBlogPostsFiles(); var blogListings = new List<BlogListing>(); foreach (var fileName in allFileNames.OrderByDescending(i => i).Take(limit)) { var fileData = File.ReadAllText(fileName); var blogListing = new JavaScriptSerializer().Deserialize<BlogListing>(fileData); blogListings.Add(blogListing); } return blogListings; } private IEnumerable<string> getBlogPostsFiles() { return Directory.GetFiles(filePathToBlogPosts, "*summary.txt").ToList(); } }}
HomeController
加载BlogListing
,在View中渲染。
namespace TxtBasedBlog.Sample.Controllers{ public class HomeController : Controller { public ActionResult Index() { var manager = new BlogFileSystemManager(Server.MapPath(ConfigurationManager.AppSettings["BlogPostsDirectory"])); var model = manager.GetBlogListings(5); return View(model); } public ActionResult Error() { return View(); } }}
最后,是Views/Home/Index.cshtml的代码,注意我们使用的root级的URL,需要在下步定义一些Routes。
@model IEnumerable<TxtBasedBlog.Sample.Models.BlogListing><h2>Recent Blog Posts</h2> @{ foreach (var item in Model) { <div class="post"> <div class="img-post"> <a href="/@item.Url" title="@item.Title"><img src="../../@item.Image" alt="" /></a> </div> <div class="inline"> <p><a href="@item.Url">@item.PostDate.ToString("MM/dd/yyyy") - @item.Title</a><br />@Html.Raw(item.ShortDescription)</p> </div> </div> } }
现在,运行网站,如下图:
placeholder 截图
步骤7:显示博客内容
在Global.asax.cs定义一些Routes:
public static void RegisterRoutes(RouteCollection routes){ ... routes.MapRoute( "HomePage", "", new { controller = "Home", action = "Index" } ); routes.MapRoute( "Error", "Oops", new { controller = "Home", action = "Error" } ); routes.MapRoute( "BlogPost", "{postName}", new { controller = "Home", action = "ViewBlogPost", postName = "" } ); ...}
当用户点击一个博客链接时,调用Action方法ViewBlogPost
,在HomeController中添加ViewBlogPost
有关的代码。
namespace TxtBasedBlog.Sample.Controllers{ public class HomeController : Controller { ... public ActionResult ViewBlogPost(string postName) { var manager = new BlogFileSystemManager(Server.MapPath(ConfigurationManager.AppSettings["BlogPostsDirectory"])); if (!manager.BlogPostFileExistsByTitleForUrl(postName)) { return RedirectToRoute("Error"); } var model = manager.GetBlogPostByTitleForUrl(postName); return View(model); } ... }}
添加BlogFileSystemManager
来确保获得有效的数据文件。
namespace TxtBasedBlog.Sample.Models{ public class BlogFileSystemManager { ... public bool BlogPostFileExistsByTitleForUrl(string titleForUrl) { var matchingFiles = getFilesForBlogPostByTitleForUrl(titleForUrl); return (matchingFiles.Count == 2); } public BlogPost GetBlogPostByTitleForUrl(string titleForUrl) { var matchingFiles = getFilesForBlogPostByTitleForUrl(titleForUrl); var summaryFileData = File.ReadAllText(matchingFiles.Where(i => i.Contains("_summary")).FirstOrDefault()); var blogPost = new JavaScriptSerializer().Deserialize(summaryFileData); blogPost.Body = File.ReadAllText(matchingFiles.Where(i => !i.Contains("_summary")).FirstOrDefault()); return blogPost; } private List getFilesForBlogPostByTitleForUrl(string titleForUrl) { // Updated 2012-03-07: // Richard Fawcett's regex suggestion to prevent titleForUrl subset results. Thanks Richard! var files = Directory.GetFiles(filePathToBlogPosts, string.Format("*{0}*.txt", titleForUrl)); var r = new Regex(@"d{4}-d{2}-d{2}_" + titleForUrl + @"(_summary)?.txt", RegexOptions.IgnoreCase); return files.Where(f => r.IsMatch(f)).ToList(); } ... }}
然后,Views/Home/ViewBlogPost.cshtml负责渲染博客文章页面,我们使用一个自定义的Helper方法,@Html.Markdown()
来调用之前安装的Markdown库。
@using TxtBasedBlog.Sample.Models@model TxtBasedBlog.Sample.Models.BlogPost@{ ViewBag.Title = Model.Title;}<h2>@Model.Title</h2> <p>Posted on @Convert.ToDateTime(Model.PostDate).ToString("dd MMM, yyyy") by @Model.Author - @Html.ActionLink("Back to Blog List", "Index")</p>@Html.Markdown(Model.Body)
@Html.Markdown()是由 Danny Tuppeny创建,原文见original post。
namespace TxtBasedBlog.Sample.Models{ public static class MarkdownHelper { static readonly Markdown MarkdownTransformer = new Markdown(); public static IHtmlString Markdown(this HtmlHelper helper, string text) { var html = MarkdownTransformer.Transform(text); return MvcHtmlString.Create(html); } }}
最终完成,运行截图如下,注意URL已经优化。
placeholder:截图。
摘自:https://www.cnblogs.com/pieux/archive/2012/04/26/2471185.html