一步一步創建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](九)


前言

童鞋們,大家好

我是專注.NET開發者社區建設的實踐者Rector。

首先,為自己間隔了兩個星期五再更新本系列文章找個不充分的理由:Rector最近工作,家庭的各種事務所致,希望大家諒解。

本文知識要點

回到本文的主題,還是關於系列文章:《一步一步創建ASP.NET MVC5程序Repository+Autofac+Automapper+SqlSugar》,本文將為大家分享的主要內容有:

  • 響應式網站首頁的布局與制作
  • 文章列表的展示
  • 文章詳情頁面

前端布局與制作

響應式網站首頁的布局與制作

在以本文之前的系列文章的頁面中,我們的網站首頁以及文章列表頁面都沒有應用樣式,本文將給大家分享首頁的制作,其中包含的內容有:

  • 頭部導航
  • 文章列表
  • Bootstrap響應式布局

最終的首頁效果圖如下:

create-aspnet-mvc-5-web-application-repository-autofac-automapper-sqlsugar-step-by-step-09-01.png

CSS樣式

首先,在項目[TsBlog.Frontend]中創建資源文件夾命名為:resources,在其中創建一個css樣式文件夾,並新建一個樣式文件,命名為:site.css,此時的目錄結構如下:

create-aspnet-mvc-5-web-application-repository-autofac-automapper-sqlsugar-step-by-step-09-02.png

樣式代碼如下:

site.css

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td { border: 0; margin: 0; padding: 0; }

body { color: #333; font-size: 14px; font-family: -apple-system,'helvetica neue', helvetica,"Helvetica Neue",Helvetica,Arial,"PingFang SC","Hiragino Sans GB","WenQuanYi Micro Hei","Microsoft Yahei",sans-serif; line-height: 22px; width: 100%; height: 100%; }
h1, h2, h3, h4, h5, h6 { clear: both; font-weight: normal; }
ol, ul { list-style: none; }
blockquote { quotes: none; border-left: 5px solid #eee; font-size: 14px; margin: 10px 0; padding: 10px 20px; }
    blockquote:before, blockquote:after { content: ''; content: none; }

a { color: #4484ce; }

/*bootstrap override*/
.btn { border-radius: 2px !important; }
.btn-primary { background-color: #4484CE !important; }
    .btn-primary:hover { background-color: #3A77BE !important; }

.navbar-nav a { color: #333 !important; }
    .navbar-nav > .active > a, .navbar-nav > .active > a:focus, .navbar-nav > .active > a:hover, .navbar-nav a:hover { border-radius: 2px; background-color: #e7e7e7 !important; }
/*site begin*/
.ts-navbar .navbar-nav { height: 50px; vertical-align: middle; line-height: 50px; }
    .ts-navbar .navbar-nav li { vertical-align: middle; line-height: 50px; float: none; display: inline-block; }
.ts-navbar .dropdown li { display: block; }
.ts-navbar .navbar-nav li a { padding: 8px 15px; }
.navbar-brand { height: auto; }
a.nav-btn-login { color: #fff !important; }
    a.nav-btn-login:hover { background-color: #3A77BE !important; color: #fff !important; }
.navbar-profile { margin-right: 0; }
/*home begin*/
.jumbotron h1 { margin-bottom: 15px; }
.jumbotron p { line-height: 28px; }
.post-title { display: block; font-size: 16px; font-weight: 600; border-bottom: 2px solid #e7e7e7; padding-bottom: 8px; }
.post-item-box { margin-bottom: 15px; }
    .post-item-box li { margin-top: 15px; margin-bottom: 15px; padding-top: 10px; padding-bottom: 10px; }
        .post-item-box li h2 { font-size: 16px; font-weight: 500; margin-bottom: 10px; }
.post-item-summary { color: #555; }
.footer-box { padding: 15px; margin-top: 15px; border-top: 1px solid #e7e7e7; }


/*post details*/

.article-content { padding-top: 15px; padding-bottom: 15px; }
    .article-content p { margin-top: 20px; margin-bottom: 20px; }
.article-fixed p { margin-top: 0; margin-bottom: 5px; }
.article-content h1, .article-content h2, .article-content h3, .article-content h4, .article-content h5, .article-content h6 { margin: 15px 0 10px; }
.article-content h1, .article-content h2 { border-bottom: 1px solid #eee; padding-bottom: 10px; }
.article-content h2 { font-size: 1.75em; line-height: 1.2 }
.article-content h3 { font-size: 1.5em; line-height: 1.2 }
.article-content blockquote { background: #f6f6f6 none repeat scroll 0 0; border-left: 2px solid #009a61; color: #555; font-size: 1em; }
.cloud-tags .cloud-tag-item { border: 1px solid #efefef; background-color: #f7f7f7; padding: 5px 10px; }
.cloud-tags .cloud-tag-item, .side-bar-article-list, .article-content { word-break: break-all; word-wrap: break-word; white-space: normal; }
    .article-content pre { background-attachment: scroll; background-clip: border-box; background-color: #f6f6f6; border: medium none; line-height: 1.45; max-height: 35em; overflow: auto; padding: 1em; position: relative; margin-bottom: 15px; margin-top: 15px; }
    .article-content ul li { padding-left: 15px; list-style: inside; }
    .article-content ul li { padding-left: 15px; list-style: inside; }
    .article-content ul, .article-content ol { margin-left: 3em; padding-left: 0; }
        .article-content ul li, .article-content ol li { margin: .3em 0; }

以上的樣式表是本文中所用到的,你只需要復制即可。

頭部導航

打開視圖文件[...TsBlog\src\Presentation\TsBlog.Frontend\Views\Home\Index.cshtml],首先制作頭部導航條,其中導航條的HTML代碼如下:

<nav class="navbar navbar-default navbar-static-top ts-navbar">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="~/">TSBLOG</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="~/">網站首頁</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">分類導航 <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li class="dropdown-header">后端開發</li>
                            <li><a href="http://2sharings.com/category/csharp-development">C#程序設計</a></li>
                            <li><a href="http://2sharings.com/category/dot-net">.NET程序設計</a></li>
                            <li><a href="http://2sharings.com/category/asp-dot-net">ASP.NET</a></li>
                            <li><a href="http://2sharings.com/category/asp-net-mvc">ASP.NET MVC</a></li>
                            <li><a href="http://2sharings.com/category/asp-dotnet-core">ASP.NET Core</a></li>
                            <li><a href="http://2sharings.com/category/winform">Winform</a></li>
                            <li role="separator" class="divider"></li>
                            <li class="dropdown-header">數據庫</li>
                            <li><a href="http://2sharings.com/category/mysql">MySQL</a></li>
                            <li><a href="http://2sharings.com/category/sql-server">SQL Server</a></li>
                            <li><a href="http://2sharings.com/category/sqlite">SqLite</a></li>
                        </ul>
                    </li>
                    <li><a href="~/home/about">關於我們</a></li>
                    <li><a href="~/home/contact">聯系我們</a></li>
                </ul>
                <ul class="nav navbar-nav navbar-right navbar-profile">
                    <li><a href="~/account/register">免費注冊</a></li>
                    <li><a class="btn btn-primary nav-btn-login" href="~/account/login">立即登錄</a></li>
                </ul>
            </div><!--/.nav-collapse -->
        </div>
    </nav>

正文HTML

其中正文的第一部分為一個BANNER,在這個區域中,可以放置一些重要的關於站點的描述信息,也可以放滾動播放的廣告圖片等,按自己的需要處理就可以了。

第二部分則是一個文章列表區域,其中列出了網站最近發布的20條文章列表,正文的HTML代碼如下:

<div class="container">
        <div class="jumbotron">
            <h1>小伙伴,你好</h1>
            <p>歡迎來到 Rector 的ASP.NET MVC 5 系列文章教程。在這里,Rector將和你一起一步一步創建一個集成Repository+Autofac+Automapper+SqlSugar的WEB應用程序。</p>
            <p>你准備好了嗎?</p>
            <p>......</p>
            <p>讓我們開始ASP.NET MVC 5 應用程序的探索之旅吧!!!</p>
        </div>
        <strong class="post-title">文章列表(@(Model.Count())篇)</strong>
        <ul class="list-unstyled post-item-box">
            @foreach (var p in Model)
            {
                <li>
                    <h2><a href="~/post/details/@p.Id">@p.Title</a></h2>
                    <p class="post-item-summary">@p.Summary ... <a href="~/post/details/@p.Id">閱讀全文</a></p>
                </li>
            }
        </ul>
    </div>

頁腳

頁面最后為頁腳部分,包含比較簡單的版權等信息,HTML代碼如下:

<footer class="footer-box">
        <div class="container">
            版權所有 &copy; @(DateTime.Now.Year)
        </div>
    </footer>

首頁完整的HTML代碼如下:

Index.cshtml

@model IEnumerable<TsBlog.ViewModel.Post.PostViewModel>
@{
    Layout = null;
}
<!doctype html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>ASP.NET MVC 5 系列文章教程--首頁 | TSBLOG</title>
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
    <link href="~/resources/css/site.css" rel="stylesheet" />

</head>
<body>
    <nav class="navbar navbar-default navbar-static-top ts-navbar">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="~/">TSBLOG</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="~/">網站首頁</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">分類導航 <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li class="dropdown-header">后端開發</li>
                            <li><a href="http://2sharings.com/category/csharp-development">C#程序設計</a></li>
                            <li><a href="http://2sharings.com/category/dot-net">.NET程序設計</a></li>
                            <li><a href="http://2sharings.com/category/asp-dot-net">ASP.NET</a></li>
                            <li><a href="http://2sharings.com/category/asp-net-mvc">ASP.NET MVC</a></li>
                            <li><a href="http://2sharings.com/category/asp-dotnet-core">ASP.NET Core</a></li>
                            <li><a href="http://2sharings.com/category/winform">Winform</a></li>
                            <li role="separator" class="divider"></li>
                            <li class="dropdown-header">數據庫</li>
                            <li><a href="http://2sharings.com/category/mysql">MySQL</a></li>
                            <li><a href="http://2sharings.com/category/sql-server">SQL Server</a></li>
                            <li><a href="http://2sharings.com/category/sqlite">SqLite</a></li>
                        </ul>
                    </li>
                    <li><a href="~/home/about">關於我們</a></li>
                    <li><a href="~/home/contact">聯系我們</a></li>
                </ul>
                <ul class="nav navbar-nav navbar-right navbar-profile">
                    <li><a href="~/account/register">免費注冊</a></li>
                    <li><a class="btn btn-primary nav-btn-login" href="~/account/login">立即登錄</a></li>
                </ul>
            </div><!--/.nav-collapse -->
        </div>
    </nav>
    <div class="container">
        <div class="jumbotron">
            <h1>小伙伴,你好</h1>
            <p>歡迎來到 Rector 的ASP.NET MVC 5 系列文章教程。在這里,Rector將和你一起一步一步創建一個集成Repository+Autofac+Automapper+SqlSugar的WEB應用程序。</p>
            <p>你准備好了嗎?</p>
            <p>......</p>
            <p>讓我們開始ASP.NET MVC 5 應用程序的探索之旅吧!!!</p>
        </div>
        <strong class="post-title">文章列表(@(Model.Count())篇)</strong>
        <ul class="list-unstyled post-item-box">
            @foreach (var p in Model)
            {
                <li>
                    <h2><a href="~/post/details/@p.Id">@p.Title</a></h2>
                    <p class="post-item-summary">@p.Summary ... <a href="~/post/details/@p.Id">閱讀全文</a></p>
                </li>
            }
        </ul>
    </div>
    <footer class="footer-box">
        <div class="container">
            版權所有 &copy; @(DateTime.Now.Year)
        </div>
    </footer>
    <script src="~/Scripts/jquery-3.2.1.min.js"></script>
    <script src="~/Scripts/bootstrap.min.js"></script>
</body>
</html>

后端接口與實現

在完成了前端頁面的布局與制作之后,我們需要后端程序提供接口和服務,來供前端頁面調用,如首頁視圖中的視圖模型:

@model IEnumerable<TsBlog.ViewModel.Post.PostViewModel>

文章倉儲接口和實現

打開文件[IPostRepository.cs],在其中新增接口方法: FindHomePagePosts ,代碼如下:

using System.Collections.Generic;
using TsBlog.Domain.Entities;

namespace TsBlog.Repositories
{
    public interface IPostRepository : IRepository<Post>
    {
        /// <summary>
        /// 查詢首頁文章列表
        /// </summary>
        /// <param name="limit">要查詢的記錄數</param>
        /// <returns></returns>
        IEnumerable<Post> FindHomePagePosts(int limit = 20);
    }
}

打開文件[PostRepository.cs],實現對應的接口方法:FindHomePagePosts,代碼如下:

using SqlSugar;
using System.Collections.Generic;
using TsBlog.Domain.Entities;

namespace TsBlog.Repositories
{
    /// <summary>
    /// POST表的數據庫操作類
    /// </summary>
    public class PostRepository : GenericRepository<Post>, IPostRepository
    {
        #region Implementation of IPostRepository

        /// <summary>
        /// 查詢首頁文章列表
        /// </summary>
        /// <param name="limit">要查詢的記錄數</param>
        /// <returns></returns>
        public IEnumerable<Post> FindHomePagePosts(int limit = 20)
        {
            using (var db = DbFactory.GetSqlSugarClient())
            {
                var list = db.Queryable<Post>().OrderBy(x => x.Id, OrderByType.Desc).Take(limit).ToList();
                return list;
            }
        }
    }
    #endregion
}

文章服務接口和實現

打開文件[IPostService.cs],在其中新增接口方法: FindHomePagePosts ,代碼如下:

using System.Collections.Generic;
using TsBlog.Domain.Entities;

namespace TsBlog.Services
{
    public interface IPostService : IService<Post>
    {
        /// <summary>
        /// 查詢首頁文章列表
        /// </summary>
        /// <param name="limit">要查詢的記錄數</param>
        /// <returns></returns>
        IEnumerable<Post> FindHomePagePosts(int limit = 20);
    }
}

打開文件[PostService.cs],實現對應的接口方法:FindHomePagePosts,代碼如下:

using System.Collections.Generic;
using TsBlog.Domain.Entities;
using TsBlog.Repositories;

namespace TsBlog.Services
{
    public class PostService : GenericService<Post>, IPostService
    {
        private readonly IPostRepository _repository;
        public PostService(IPostRepository repository) : base(repository)
        {
            _repository = repository;
        }


        #region Implementation of IPostService

        /// <summary>
        /// 查詢首頁文章列表
        /// </summary>
        /// <param name="limit">要查詢的記錄數</param>
        /// <returns></returns>
        public IEnumerable<Post> FindHomePagePosts(int limit = 20)
        {
            return _repository.FindHomePagePosts(limit);
        }

        #endregion
    }
}

附加修改:重構了一下倉儲接口中的 FindListByClause 方法,將orderBy參數設置為可空參數,具體實現如下:

/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy = "");

對應的修改泛型倉儲中的對應實現:

/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
public IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy = "")
{
    using (var db = DbFactory.GetSqlSugarClient())
    {
        var query = db.Queryable<T>().Where(predicate);
        if (!string.IsNullOrEmpty(orderBy))
        {
            query = query.OrderBy(orderBy);
        }
        var entities = query.ToList();
        return entities;
    }
}

同樣的,服務層中也作相應的修改:

IService.cs 文件中的 FindListByClause接口方法:

/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy = "");

泛型服務類:GenericService.cs 中的 FindListByClause 方法實現:

/// <summary>
/// 根據條件查詢數據
/// </summary>
/// <param name="predicate">條件表達式樹</param>
/// <param name="orderBy">排序</param>
/// <returns>泛型實體集合</returns>
public IEnumerable<T> FindListByClause(Expression<Func<T, bool>> predicate, string orderBy = "")
{
    return _repository.FindListByClause(predicate, orderBy);
}

在開始處理HomeController控制器之前 ,我們先在項目[TsBlog.Core]中新建兩個幫助類,分別為:HtmlHelper.csStringHelper.cs。其中代碼分別為:

HtmlHelper.cs:

using System.Text.RegularExpressions;

namespace TsBlog.Core
{
    public static class HtmlHelper
    {
        #region 去掉HTML中的所有標簽,只留下純文本
        /// <summary>
        /// 去掉HTML中的所有標簽,只留下純文本
        /// </summary>
        /// <param name="strHtml"></param>
        /// <returns></returns>
        public static string CleanHtml(this string strHtml)
        {
            if (string.IsNullOrEmpty(strHtml)) return strHtml;
            //刪除腳本
            strHtml = Regex.Replace(strHtml, "(\\<script(.+?)\\</script\\>)|(\\<style(.+?)\\</style\\>)", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
            //刪除標簽
            var r = new Regex(@"<\/?[^>]*>", RegexOptions.IgnoreCase);
            Match m;
            for (m = r.Match(strHtml); m.Success; m = m.NextMatch())
            {
                strHtml = strHtml.Replace(m.Groups[0].ToString(), "");
            }
            return strHtml.Trim();
        }

        #endregion
    }
}

StringHelper.cs

using System;

namespace TsBlog.Core
{
    public static class StringHelper
    {
        #region
        /// <summary>
        /// 截取指定長度的字符串
        /// </summary>
        /// <param name="str">原始字符串</param>
        /// <param name="strLength">要保留的字符串長度</param>
        /// <returns></returns>
        public static string CutStrLength(this string str, int strLength)
        {
            var strNew = str;
            if (string.IsNullOrEmpty(strNew)) return strNew;
            var strOriginalLength = strNew.Length;
            if (strOriginalLength > strLength)
            {
                strNew = strNew.Substring(0, strLength) + "...";
            }
            return strNew;
        }

        #endregion

        #region
        /// <summary>
        /// 截取指定長度的字符串
        /// </summary>
        /// <param name="str">原始字符串</param>
        /// <param name="strLength">要保留的字符串長度</param>
        /// <param name="endWithEllipsis">是或以省略號(...)結束</param>
        /// <returns></returns>
        public static string CutStrLength(string str, int strLength, bool endWithEllipsis)
        {
            string strNew = str;
            if (!strNew.Equals(""))
            {
                int strOriginalLength = strNew.Length;
                if (strOriginalLength > strLength)
                {
                    strNew = strNew.Substring(0, strLength);
                    if (endWithEllipsis)
                    {
                        strNew += "...";
                    }
                }
            }
            return strNew;
        }

        #endregion

        #region 截斷字符串(可保留完整單詞)
        /// <summary>
        /// 截斷字符串(可保留完整單詞)
        /// </summary>
        /// <param name="valueToTruncate">需處理的字符串</param>
        /// <param name="maxLength">字符數</param>
        /// <param name="options">截斷選項</param>
        /// <returns></returns>
        public static string TruncateString(this string valueToTruncate, int maxLength, TruncateOptions options)
        {
            if (valueToTruncate == null)
            {
                return "";
            }

            if (valueToTruncate.Length <= maxLength)
            {
                return valueToTruncate;
            }

            var includeEllipsis = (options & TruncateOptions.IncludeEllipsis) ==
                    TruncateOptions.IncludeEllipsis;
            var finishWord = (options & TruncateOptions.FinishWord) ==
                    TruncateOptions.FinishWord;
            var allowLastWordOverflow =
              (options & TruncateOptions.AllowLastWordToGoOverMaxLength) ==
              TruncateOptions.AllowLastWordToGoOverMaxLength;

            var retValue = valueToTruncate;

            if (includeEllipsis)
            {
                maxLength -= 1;
            }

            var lastSpaceIndex = retValue.LastIndexOf(" ",
              maxLength, StringComparison.CurrentCultureIgnoreCase);

            if (!finishWord)
            {
                retValue = retValue.Remove(maxLength);
            }
            else if (allowLastWordOverflow)
            {
                var spaceIndex = retValue.IndexOf(" ",
                  maxLength, StringComparison.CurrentCultureIgnoreCase);
                if (spaceIndex != -1)
                {
                    retValue = retValue.Remove(spaceIndex);
                }
            }
            else if (lastSpaceIndex > -1)
            {
                retValue = retValue.Remove(lastSpaceIndex);
            }

            if (includeEllipsis && retValue.Length < valueToTruncate.Length)
            {
                retValue += "...";
            }
            return retValue;
        }

        #endregion
    }

    #region 截斷字符串用的枚舉
    /// <summary>
    /// 截斷字符串用的枚舉
    /// </summary>
    [Flags]
    public enum TruncateOptions
    {
        /// <summary>
        /// 不作任何處理
        /// </summary>
        None = 0x0,
        /// <summary>
        /// 保留完整單詞
        /// </summary>
        FinishWord = 0x1,
        /// <summary>
        /// 允許最后一個單詞超過最大長度限制
        /// </summary>
        AllowLastWordToGoOverMaxLength = 0x2,
        /// <summary>
        /// 字符串最后跟省略號
        /// </summary>
        IncludeEllipsis = 0x4
    }
    #endregion
}

在項[TsBlog.ViewModel]中的文章視圖文件[...TsBlog\src\Libraries\TsBlog.ViewModel\Post\PostViewModel.cs]中添加一個新的屬性:Summary,此時的PostViewModel是這樣的:

namespace TsBlog.ViewModel.Post
{
    /// <summary>
    /// 博文視圖實體類
    /// </summary>
    public class PostViewModel
    {
        /// <summary>
        /// ID
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 標題
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// 內容
        /// </summary>
        public string Content { get; set; }
        /// <summary>
        /// 作者ID
        /// </summary>
        public string AuthorId { get; set; }
        /// <summary>
        /// 作者姓名
        /// </summary>
        public string AuthorName { get; set; }
        /// <summary>
        /// 創建時間
        /// </summary>
        public string CreatedAt { get; set; }
        /// <summary>
        /// 發布時間
        /// </summary>
        public string PublishedAt { get; set; }
        /// <summary>
        /// 是否標識已刪除
        /// </summary>
        public string IsDeleted { get; set; }
        /// <summary>
        /// 是否允許展示
        /// </summary>
        public bool AllowShow { get; set; }
        /// <summary>
        /// 瀏覽量
        /// </summary>
        public int ViewCount { get; set; }

        /// <summary>
        /// 摘要
        /// </summary>
        public string Summary { get; set; }
    }
}

在項目[TsBlog.Frontend]中創建一個名為:Extensions 文件夾,並在其中創建一個文章的靜態擴展類[...\TsBlog.Frontend\Extensions\PostExtension.cs],同時實現以下靜態擴展方法:

using TsBlog.Core;
using TsBlog.ViewModel.Post;

namespace TsBlog.Frontend.Extensions
{
    public static class PostExtension
    {
        /// <summary>
        /// 格式化文章的視圖實體
        /// </summary>
        /// <param name="model">文章視圖實體類</param>
        /// <returns></returns>
        public static PostViewModel FormatPostViewModel(this PostViewModel model)
        {
            if (model == null)
            {
                return null;
            }

            model.Summary = model.Content
                .CleanHtml()            //去掉所有HTML標簽
                .TruncateString(200, TruncateOptions.FinishWord | TruncateOptions.AllowLastWordToGoOverMaxLength);     //截斷指定長度作為文章摘要
            return model;
        }
    }
}

網站首頁[HomeController]

在首頁的控制器[...TsBlog.Frontend\Controllers\HomeController.cs]中,利用文章服務接口的方法實現首頁文章列表的查詢,代碼如下:

using System.Linq;
using System.Web.Mvc;
using TsBlog.AutoMapperConfig;
using TsBlog.Frontend.Extensions;
using TsBlog.Services;

namespace TsBlog.Frontend.Controllers
{
    public class HomeController : Controller
    {
        /// <summary>
        /// 文章服務接口
        /// </summary>
        private readonly IPostService _postService;
        public HomeController(IPostService postService)
        {
            _postService = postService;
        }
        /// <summary>
        /// 首頁
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            var list = _postService.FindHomePagePosts();
            var model = list.Select(x => x.ToModel().FormatPostViewModel());
            return View(model);
        }
    }
}

好了,到此我們的首頁制作與數據綁定等到完成了,按F5運行,我們即可看到本文開篇所示的首頁效果。

文章詳情頁[PostController]

新建一個名為:PostController的控制器,並添加如下代碼:

using System.Web.Mvc;
using TsBlog.AutoMapperConfig;
using TsBlog.Services;

namespace TsBlog.Frontend.Controllers
{
    public class PostController : Controller
    {
        /// <summary>
        /// 文章服務接口
        /// </summary>
        private readonly IPostService _postService;

        public PostController(IPostService postService)
        {
            _postService = postService;
        }

        /// <summary>
        /// 文章詳情
        /// </summary>
        /// <param name="id">文章ID</param>
        /// <returns></returns>
        public ActionResult Details(int id)
        {
            var post = _postService.FindById(id);
            var model = post.ToModel();
            return View(model);
        }
    }
}

再添加文章詳情頁的視圖[...\TsBlog.Frontend\Views\Post\Details.cshtml],添加如下視圖HTML代碼:

@model TsBlog.ViewModel.Post.PostViewModel
@{
    Layout = null;
}
<!doctype html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>@(Model.Title) | TSBLOG</title>
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
    <link href="~/resources/css/site.css" rel="stylesheet" />
</head>
<body>
    <nav class="navbar navbar-default navbar-static-top ts-navbar">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="~/">網站名稱</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a href="~/">網站首頁</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">分類導航 <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li class="dropdown-header">后端開發</li>
                            <li><a href="http://2sharings.com/category/csharp-development">C#程序設計</a></li>
                            <li><a href="http://2sharings.com/category/dot-net">.NET程序設計</a></li>
                            <li><a href="http://2sharings.com/category/asp-dot-net">ASP.NET</a></li>
                            <li><a href="http://2sharings.com/category/asp-net-mvc">ASP.NET MVC</a></li>
                            <li><a href="http://2sharings.com/category/asp-dotnet-core">ASP.NET Core</a></li>
                            <li><a href="http://2sharings.com/category/winform">Winform</a></li>
                            <li role="separator" class="divider"></li>
                            <li class="dropdown-header">數據庫</li>
                            <li><a href="http://2sharings.com/category/mysql">MySQL</a></li>
                            <li><a href="http://2sharings.com/category/sql-server">SQL Server</a></li>
                            <li><a href="http://2sharings.com/category/sqlite">SqLite</a></li>
                        </ul>
                    </li>
                    <li><a href="~/home/about">關於我們</a></li>
                    <li><a href="~/home/contact">聯系我們</a></li>
                </ul>
                <ul class="nav navbar-nav navbar-right navbar-profile">
                    <li><a href="~/account/register">免費注冊</a></li>
                    <li><a class="btn btn-primary nav-btn-login" href="~/account/login">立即登錄</a></li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container">
        <h1 class="post-title">@Model.Title</h1>
        <article class="article-content">
            @Html.Raw(Model.Content)
        </article>
    </div>
    <footer class="footer-box">
        <div class="container">
            版權所有 &copy; @(DateTime.Now.Year)
        </div>
    </footer>
    <script src="~/Scripts/jquery-3.2.1.min.js"></script>
    <script src="~/Scripts/bootstrap.min.js"></script>
</body>
</html>

OK,今天這期的關於網站首頁及文章詳情頁面的布局與制作就分享到這里,希望對你了解ASP.NET MVC WEB應用程序開發有所幫助。

本期源碼托管地址:請至文章首發地址獲取《一步一步創建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](九)
數據庫腳本文件請到目錄下查看:TsBlog\document\scripts\mysql\v1.9\

如果你喜歡Rector的本系列文章,請為我點個大大的贊。

**看完教程如果覺得還不過癮的,想“勾對”的,歡迎加入圖享網官方QQ群:483350228,如果你按照教程還原出來的程序運行有問題,請參照本期源碼對應調整與修改遇到問題的,也歡迎加入QQ群。有什么,你懂的。。。_ **

謝謝你的耐心閱讀,本系列未完待續,我們下期再見……

本文首發於:圖享網一步一步創建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](九)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM