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

来源:https://www.cnblogs.com/bobositlife/archive/2018/02/06/8421149.html
-Advertisement-
Play Games

前言 童鞋們,大家好 我是專註.NET開發者社區建設的實踐者Rector。 首先,為自己間隔了兩個星期五再更新本系列文章找個不充分的理由:Rector最近工作,家庭的各種事務所致,希望大家諒解。 本文知識要點 回到本文的主題,還是關於系列文章:《一步一步創建ASP.NET MVC5程式Reposit ...


前言

童鞋們,大家好

我是專註.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](九)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在開發 XAML(WPF/UWP) 應用程式中,有時候,我們需要創建自定義控制項 (Custom Control) 來滿足實際需求。而在自定義控制項中,我們一般會用到一些原生的控制項(如 Button、TextBox 等)來輔助以完成自定義控制項的功能。 自定義控制項並不像用戶控制項 (User Control ...
  • PDF是一種在我們日常工作學習中最常用到的文檔格式之一,但常常也會因為文檔的不易編輯的特點,在遇到需要編輯PDF文檔內容或者轉換文件格式的情況時讓人苦惱。通常對於開發者而言,可選擇通過使用組件的方式來實現PDF文檔的編輯或者格式轉換,因此本文將介紹如何通過使用免費版的組件Free Spire.PDF ...
  • 轉載http://www.cnblogs.com/zzqvq/p/5816091.html Asp.Net MVC+EF+三層架構的完整搭建過程 架構圖: 使用的資料庫: 一張公司的員工信息表,測試數據 解決方案項目設計: 1.新建一個空白解決方案名稱為Company 2.在該解決方案下,新建解決方 ...
  • "回到目錄" Aspect面向方面編程 面向側面的程式設計(aspect oriented programming,AOP,又譯作面向方面的程式設計、觀點導向編程、剖面導向程式設計)是電腦科學中的一個術語,指一種程式設計範型。該範型以一種稱為側面(aspect,又譯作方面)的語言構造為基礎,側面是 ...
  • 一、自定義控制項的基本步驟: (本示例項目名稱為:W;添加的自定義控制項名稱為) 1、 在“解決方案資源管理器”視窗的項目名上: 右擊à添加à新建項(Ctrl+Shift+A) 2、則會彈出如下視窗,在該視窗中選擇“自定義控制項(WPF)”並修改類“名稱”,點擊“添加” 3、添加成功後則會在該項目中生成C ...
  • 學習.NET的正則表達式時,對零寬斷言比較迷惑,拿出時間學習了一下,做個筆記。 零寬斷言概述 (?<=pattern) (?<!pattern) STRING (?=pattern) (?!pattern) :各種斷言出現的相對位置 ?< lookbehind STRING <lookahead : ...
  • 這是MVVM之旅系列文章的第一篇,許多文章和書喜歡在開篇介紹某種技術的誕生背景和意義,但是我覺得對於程式員來說,一個能直接運行起來的程式或許能夠更直觀的讓他們瞭解這種技術。在這篇文章里,我將帶領大家一步一步創建一個最簡單的MVVM程式,程式雖然簡單,但是卻涵蓋了MVVM的基本要素,對於那些還不是很了 ...
  • 當一份web報表項目壓縮包躺在我的文件夾里時,我是完全懵的。作為一個學習了一個月java的asp.net小白,以前從來沒有接觸過這方面,我完全不知道從何入手。(出於其他原因,不方便貼圖,貼代碼) 手裡也有asp.net開發學習視頻,但都因為懶沒看。網上搜集了很多資料,得知這種web報表一般是由三層物 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...