博客园中转

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

前言:

步骤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:截图。

posted on 2012-04-26 12:17  pieux  阅读(1328)  评论(0编辑  收藏  举报