一歩一歩ASPを作成する.NET MVC 5プログラム[Repository+Autofac+Automapper+SqlSugar](九)


前言


皆さん、こんにちは
私は集中しています.NET開発者コミュニティ建設の実践者Rector.
まず、自分のために2周间の金曜日に更に本シリーズの文章を更新して不十分な理由を探します:Rectorは最近仕事をして、家庭の各种の事务所は送って、みんなに理解してもらうことを望みます.

本文の知識の要点


このトピックに戻ります.または、シリーズの記事について説明します.「ASP.NET MVC 5プログラムRepository+Autofac+Automapper+SqlSugarを一歩一歩作成します.」
  • 応答型ウェブサイトトップページのレイアウトと制作
  • 記事リストの展示
  • 記事詳細ページ
  • フロントエンドのレイアウトと作成


    レスポンスWebサイトのトップページのレイアウトと作成
    本文の前のシリーズの文章のページの中で、私达のウェブサイトのトップページと文章のリストのページはすべてスタイルを適用していないで、本文はみんなにトップページの制作を分かち合って、その中の内容はあります:
  • ヘッドナビゲーション
  • 記事リスト
  • Bootstrap応答レイアウト
  • 最終的なトップページの効果図は以下の通りです.

    CSSスタイル


    まず、プロジェクト[TsBlog.Frontend]でリソースフォルダを作成する名前はresourcesで、cssスタイルフォルダを作成し、siteという名前のスタイルファイルを新規作成します.css、このときのディレクトリ構造は以下の通りです.
    スタイルコードは次のとおりです.
    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; }

    以上のスタイルシートは本稿で使用したもので、コピーするだけでいいです.

    ヘッドナビゲーション


    ビューファイルを開きます[...T s BlogsrcPresentationsTsBlog.FrontendViewsHomeIndex.cshtml]まず、ナビゲーションバーのHTMLコードが次のようになっているヘッダーナビゲーションバーを作成します.

    本文HTML


    ここで本文の第1部はBANNERであり、このエリアではサイトに関する重要な記述情報を置くこともできるし、スクロール再生された広告画像を流すこともできるなど、自分のニーズに応じて処理すればよい.
    第2部は、ウェブサイトが最近発表した20の文章のリストをリストする文章リスト領域で、本文のHTMLコードは以下の通りです.

    こんにちは

    Rector ASP.NET MVC 5 。 ,Rector Repository+Autofac+Automapper+SqlSugar WEB 。

    ......

    ASP.NET MVC 5 !!!

    (@(Model.Count()) )
      @foreach (var p in Model) {
    • @p.Title

      @p.Summary ... を む

    • }

    フッター


    ページの最後はフッター部分で、比較的簡単な著作権などの情報が含まれています.HTMLコードは以下の通りです.
    © @(DateTime.Now.Year)

    トップページの完全なHTMLコードは以下の通りです.
    Index.cshtml
    @model IEnumerable
    @{
        Layout = null;
    }
    
    
    
        
        
        ASP.NET MVC 5       --   | TSBLOG
        
        
    
    
    
        
        

    こんにちは

    Rector ASP.NET MVC 5 。 ,Rector Repository+Autofac+Automapper+SqlSugar WEB 。

    ......

    ASP.NET MVC 5 !!!

    (@(Model.Count()) )
      @foreach (var p in Model) {
    • @p.Title

      @p.Summary ... を む

    • }
    © @(DateTime.Now.Year)


    フロントエンドページのレイアウトと が した 、バックエンドプログラムは、トップページビューのビューモデルなどのフロントエンドページ び しのためにインタフェースとサービスを する があります.
    @model IEnumerable


    ファイル[IPostRepository.cs]を き、インタフェースメソッドを します:FindHomePagePosts、コードは のとおりです.
    using System.Collections.Generic;
    using TsBlog.Domain.Entities;
    
    namespace TsBlog.Repositories
    {
        public interface IPostRepository : IRepository
        {
            /// 
            ///         
            /// 
            ///        
            /// 
            IEnumerable FindHomePagePosts(int limit = 20);
        }
    }

    ファイル[postRepository.cs]を き、 するインタフェースを する :FindHomePagePosts、コードは の りです.
    using SqlSugar;
    using System.Collections.Generic;
    using TsBlog.Domain.Entities;
    
    namespace TsBlog.Repositories
    {
        /// 
        /// POST        
        /// 
        public class PostRepository : GenericRepository, IPostRepository
        {
            #region Implementation of IPostRepository
    
            /// 
            ///         
            /// 
            ///        
            /// 
            public IEnumerable FindHomePagePosts(int limit = 20)
            {
                using (var db = DbFactory.GetSqlSugarClient())
                {
                    var list = db.Queryable().OrderBy(x => x.Id, OrderByType.Desc).Take(limit).ToList();
                    return list;
                }
            }
        }
        #endregion
    }


    ファイル[IPostServices.cs]を き、インタフェースメソッドを します:FindHomePagePosts、コードは のとおりです.
    using System.Collections.Generic;
    using TsBlog.Domain.Entities;
    
    namespace TsBlog.Services
    {
        public interface IPostService : IService
        {
            /// 
            ///         
            /// 
            ///        
            /// 
            IEnumerable FindHomePagePosts(int limit = 20);
        }
    }

    ファイル[postServices.cs]を き、 するインタフェースメソッドを します:FindHomePagePosts、コードは のとおりです.
    using System.Collections.Generic;
    using TsBlog.Domain.Entities;
    using TsBlog.Repositories;
    
    namespace TsBlog.Services
    {
        public class PostService : GenericService, IPostService
        {
            private readonly IPostRepository _repository;
            public PostService(IPostRepository repository) : base(repository)
            {
                _repository = repository;
            }
    
    
            #region Implementation of IPostService
    
            /// 
            ///         
            /// 
            ///        
            /// 
            public IEnumerable FindHomePagePosts(int limit = 20)
            {
                return _repository.FindHomePagePosts(limit);
            }
    
            #endregion
        }
    }

    の : インタフェースのFindListByClause を し、orderByパラメータを のパラメータに し、 には のように した.
    /// 
    ///         
    /// 
    ///       
    ///   
    ///       
    IEnumerable FindListByClause(Expression> predicate, string orderBy = "");

    する における :
    /// 
    ///         
    /// 
    ///       
    ///   
    ///       
    public IEnumerable FindListByClause(Expression> predicate, string orderBy = "")
    {
        using (var db = DbFactory.GetSqlSugarClient())
        {
            var query = db.Queryable().Where(predicate);
            if (!string.IsNullOrEmpty(orderBy))
            {
                query = query.OrderBy(orderBy);
            }
            var entities = query.ToList();
            return entities;
        }
    }

    に、サービス・レベルでも が われます.
    IService.csファイルのFindListByClauseインタフェース :
    /// 
    ///         
    /// 
    ///       
    ///   
    ///       
    IEnumerable FindListByClause(Expression> predicate, string orderBy = "");

    サービスクラス:GenericServices.csにおけるFindListByClauseメソッドの :
    /// 
    ///         
    /// 
    ///       
    ///   
    ///       
    public IEnumerable FindListByClause(Expression> predicate, string orderBy = "")
    {
        return _repository.FindListByClause(predicate, orderBy);
    }

    HomeControllerコントローラの を する に、プロジェクト[TsBlog.Core]に2つのヘルプクラスを し、それぞれ:HtmlHelper.csStringHelper.csです.コードは のとおりです.HtmlHelper.cs :
    using System.Text.RegularExpressions;
    
    namespace TsBlog.Core
    {
        public static class HtmlHelper
        {
            #region   HTML      ,      
            /// 
            ///   HTML      ,      
            /// 
            /// 
            /// 
            public static string CleanHtml(this string strHtml)
            {
                if (string.IsNullOrEmpty(strHtml)) return strHtml;
                //    
                strHtml = Regex.Replace(strHtml, "(\\)|(\\<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
        }
    }</code></pre> 
     <p><code>StringHelper.cs</code>:</p> 
     <pre><code>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
    }
    </code></pre> 
     <p>  [TsBlog.ViewModel]        [...TsBlogsrcLibrariesTsBlog.ViewModelPostPostViewModel.cs]         :<code>Summary</code>,   <code>PostViewModel</code>    :</p> 
     <pre><code>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; }
        }
    }</code></pre> 
     <p>   [TsBlog.Frontend]       :<code>Extensions</code>    ,                [...TsBlog.FrontendExtensionsPostExtension.cs],            :</p> 
     <pre><code>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;
            }
        }
    }</code></pre> 
     <h3>    [HomeController]</h3> 
     <p>       [...TsBlog.FrontendControllersHomeController.cs] ,                      ,    :</p> 
     <pre><code>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);
            }
        }
    }</code></pre> 
     <p>  ,                   , F5  ,                 。</p> 
     <h3>     [PostController]</h3> 
     <p>      :<code>PostController</code>    ,       :</p> 
     <pre><code>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);
            }
        }
    }</code></pre> 
     <p>           [...TsBlog.FrontendViewsPostDetails.cshtml],      HTML  :</p> 
     <pre><code>@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">