more caching, more seo
This commit is contained in:
@@ -12,9 +12,10 @@ namespace TerribleDev.Blog.Web.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
static List<IPost> postsAsList = new BlogFactory().GetAllPosts().OrderByDescending(a=>a.PublishDate).ToList();
|
||||
static IDictionary<string, IPost> posts = postsAsList.ToDictionary(a=>a.Url);
|
||||
static IDictionary<int, List<IPost>> postsByPage = postsAsList.Aggregate(new Dictionary<int, List<IPost>>() { [1] = new List<IPost>() }, (accum, item) =>
|
||||
public static List<IPost> postsAsList = new BlogFactory().GetAllPosts().OrderByDescending(a=>a.PublishDate).ToList();
|
||||
public static HashSet<string> totalTags = postsAsList.Where(a=>a.tags != null).SelectMany(a => a.tags).ToHashSet();
|
||||
public static IDictionary<string, IPost> posts = postsAsList.ToDictionary(a=>a.Url);
|
||||
public static IDictionary<int, List<IPost>> postsByPage = postsAsList.Aggregate(new Dictionary<int, List<IPost>>() { [1] = new List<IPost>() }, (accum, item) =>
|
||||
{
|
||||
var highestPage = accum.Keys.Max();
|
||||
var current = accum[highestPage].Count;
|
||||
@@ -57,6 +58,7 @@ namespace TerribleDev.Blog.Web.Controllers
|
||||
}
|
||||
|
||||
[Route("{postUrl}")]
|
||||
[OutputCache(Duration = 31536000, VaryByParam = "postUrl")]
|
||||
[ResponseCache(Duration = 180)]
|
||||
public IActionResult Post(string postUrl)
|
||||
{
|
||||
|
||||
59
src/TerribleDev.Blog.Web/Controllers/SeoController.cs
Normal file
59
src/TerribleDev.Blog.Web/Controllers/SeoController.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SyndicationFeed;
|
||||
using Microsoft.SyndicationFeed.Rss;
|
||||
using TerribleDev.Blog.Web.Models;
|
||||
|
||||
namespace TerribleDev.Blog.Web.Controllers
|
||||
{
|
||||
public class SeoController : Controller
|
||||
{
|
||||
public static DateTimeOffset publishDate = DateTimeOffset.UtcNow; // keep publish date in memory so we just return when the server was kicked
|
||||
public static IEnumerable<SyndicationItem> postsToSyndication = HomeController.postsAsList.Select(a => a.ToSyndicationItem()).ToList();
|
||||
[Route("/rss")]
|
||||
[Route("/rss.xml")]
|
||||
[ResponseCache(Duration = 7200)]
|
||||
[OutputCache(Duration = 86400)]
|
||||
public async Task Rss()
|
||||
{
|
||||
Response.StatusCode = 200;
|
||||
Response.ContentType = "text/xml";
|
||||
using (XmlWriter xmlWriter = XmlWriter.Create(this.Response.Body, new XmlWriterSettings() { Async = true, Indent = false, Encoding = Encoding.UTF8 }))
|
||||
{
|
||||
var writer = new RssFeedWriter(xmlWriter);
|
||||
await writer.WriteTitle("The Ramblings of TerribleDev");
|
||||
await writer.WriteValue("link", "https://blog.terribledev.io");
|
||||
await writer.WriteDescription("My name is Tommy Parnell. I usually go by TerribleDev on the internets. These are just some of my writings and rants about the software space.");
|
||||
|
||||
foreach (var item in postsToSyndication)
|
||||
{
|
||||
await writer.Write(item);
|
||||
}
|
||||
|
||||
|
||||
await xmlWriter.FlushAsync();
|
||||
}
|
||||
}
|
||||
[Route("/sitemap.xml")]
|
||||
[ResponseCache(Duration = 7200)]
|
||||
[OutputCache(Duration = 86400)]
|
||||
public void SiteMap()
|
||||
{
|
||||
Response.StatusCode = 200;
|
||||
Response.ContentType = "text/xml";
|
||||
var ser = new XmlSerializer(typeof(SiteMapRoot));
|
||||
var sitemap = new SiteMapRoot()
|
||||
{
|
||||
Urls = HomeController.postsAsList.Select(a => new SiteMapItem() { LastModified = DateTime.UtcNow, Location = $"https://blog.terribledev.io/{a.Url}" }).ToList()
|
||||
};
|
||||
ser.Serialize(this.Response.Body, sitemap);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/TerribleDev.Blog.Web/Extensions/IPostExtensions.cs
Normal file
23
src/TerribleDev.Blog.Web/Extensions/IPostExtensions.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Microsoft.SyndicationFeed;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TerribleDev.Blog.Web.Models;
|
||||
|
||||
namespace TerribleDev.Blog.Web
|
||||
{
|
||||
public static class IPostExtensions
|
||||
{
|
||||
public static SyndicationItem ToSyndicationItem(this IPost x)
|
||||
{
|
||||
return new SyndicationItem()
|
||||
{
|
||||
Title = x.Title,
|
||||
Description = x.ContentPlain,
|
||||
Id = $"https://blog.terribledev.io/{x.Url}",
|
||||
Published = x.PublishDate
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TerribleDev.Blog.Web.Extensions
|
||||
namespace TerribleDev.Blog.Web
|
||||
{
|
||||
public static class StringExtension
|
||||
{
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.IO;
|
||||
using TerribleDev.Blog.Web.Models;
|
||||
using YamlDotNet.Serialization;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using TerribleDev.Blog.Web.Extensions;
|
||||
using Markdig;
|
||||
|
||||
namespace TerribleDev.Blog.Web
|
||||
@@ -40,7 +39,7 @@ namespace TerribleDev.Blog.Web
|
||||
var markdownText = string.Join("", splitFile.Skip(1));
|
||||
var pipeline = new MarkdownPipelineBuilder().UseEmojiAndSmiley().Build();
|
||||
var postContent = Markdown.ToHtml(markdownText, pipeline);
|
||||
var postContentPlain = Markdown.ToPlainText(markdownText, pipeline);
|
||||
var postContentPlain = String.Join("", Markdown.ToPlainText(markdownText, pipeline).Split("<!-- more -->"));
|
||||
var postSettings = ParseYaml(ymlRaw);
|
||||
var resolvedUrl = !string.IsNullOrWhiteSpace(postSettings.permalink) ? postSettings.permalink : fileName.Split('.')[0].Replace(' ', '-').WithoutSpecialCharacters();
|
||||
var summary = postContent.Split("<!-- more -->")[0];
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace TerribleDev.Blog.Web.Models
|
||||
string Url { get; set; }
|
||||
string Title { get; set; }
|
||||
HtmlString Summary { get; set; }
|
||||
DateTimeOffset PublishDate { get; set; }
|
||||
DateTime PublishDate { get; set; }
|
||||
HtmlString Content { get; set; }
|
||||
string ContentPlain { get; set; }
|
||||
string SummaryPlain { get; set; }
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace TerribleDev.Blog.Web.Models
|
||||
{
|
||||
public string Url { get; set; }
|
||||
public string Title { get; set; }
|
||||
public DateTimeOffset PublishDate { get; set; }
|
||||
public DateTime PublishDate { get; set; }
|
||||
public HtmlString Content { get; set; }
|
||||
public HtmlString Summary { get; set; }
|
||||
public string ContentPlain { get; set; }
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace TerribleDev.Blog.Web.Models
|
||||
public List<string> tags { get; set; }
|
||||
public string title { get; set; }
|
||||
public string permalink { get; set; }
|
||||
public DateTimeOffset date { get; set; }
|
||||
public DateTimeOffset updated { get; set; }
|
||||
public DateTime date { get; set; }
|
||||
public DateTime updated { get; set; }
|
||||
public string id { get; set; }
|
||||
public string thumbnail_image { get; set; }
|
||||
public string thumbnailImage { get; set; }
|
||||
|
||||
24
src/TerribleDev.Blog.Web/Models/SitemapModel.cs
Normal file
24
src/TerribleDev.Blog.Web/Models/SitemapModel.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace TerribleDev.Blog.Web.Models
|
||||
{
|
||||
[XmlRoot("urlset")]
|
||||
public class SiteMapRoot
|
||||
{
|
||||
[XmlElement("url")]
|
||||
public List<SiteMapItem> Urls { get; set; }
|
||||
}
|
||||
|
||||
public class SiteMapItem
|
||||
{
|
||||
[XmlElement("loc")]
|
||||
public string Location { get; set; }
|
||||
[XmlElement("lastmod")]
|
||||
public DateTime LastModified { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ namespace TerribleDev.Blog.Web
|
||||
.AddCacheTagHelper()
|
||||
.AddRazorViewEngine()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
|
||||
services.AddOutputCaching();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
@@ -80,7 +81,8 @@ namespace TerribleDev.Blog.Web
|
||||
"public,max-age=" + cacheTime;
|
||||
}
|
||||
});
|
||||
app.UseRewriter(new Microsoft.AspNetCore.Rewrite.RewriteOptions().AddRedirect("(.*[^/])$", "$1/", 301));
|
||||
app.UseRewriter(new Microsoft.AspNetCore.Rewrite.RewriteOptions().AddRedirect("(.*[^/|.xml])$", "$1/", 301));
|
||||
app.UseOutputCaching();
|
||||
app.UseMvc();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="5.3.0" />
|
||||
<PackageReference Include="HardHat" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2" />
|
||||
<PackageReference Include="WebEssentials.AspNetCore.OutputCaching" Version="1.0.16" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user