canonical tags, dotnet 3.1
This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -9,7 +9,7 @@
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
"program": "${workspaceFolder}/src/TerribleDev.Blog.Web/bin/Debug/netcoreapp2.2/TerribleDev.Blog.Web.dll",
|
||||
"program": "${workspaceFolder}/src/TerribleDev.Blog.Web/bin/Debug/netcoreapp3.1/TerribleDev.Blog.Web.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/src/TerribleDev.Blog.Web",
|
||||
"stopAtEntry": false,
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace TerribleDev.Blog.Web.Controllers
|
||||
var ser = new XmlSerializer(typeof(SiteMapRoot));
|
||||
var sitemap = new SiteMapRoot()
|
||||
{
|
||||
Urls = postCache.PostsAsLists.Select(a => new SiteMapItem() { LastModified = DateTime.UtcNow, Location = $"https://blog.terrible.dev/{a.Url}/" }).ToList()
|
||||
Urls = postCache.PostsAsLists.Select(a => new SiteMapItem() { LastModified = DateTime.UtcNow, Location = a.CanonicalUrl }).ToList()
|
||||
};
|
||||
sitemap.Urls.AddRange(sitewideLinks);
|
||||
ser.Serialize(this.Response.Body, sitemap);
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace TerribleDev.Blog.Web.Controllers
|
||||
return Redirect($"/404/?from=/tag/{tagName}/");
|
||||
}
|
||||
{
|
||||
return View(new Models.GetTagViewModel { Tag = tagName, Posts = models });
|
||||
return View(new Models.GetTagViewModel { Tag = tagName, Posts = models, CanonicalUrl = $"https://blog.terrible.dev/tag/{tagName.ToLower()}/" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base
|
||||
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
FROM microsoft/dotnet:2.2-sdk AS build
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
|
||||
WORKDIR /src
|
||||
COPY ["./TerribleDev.Blog.Web.csproj", "."]
|
||||
RUN dotnet restore "TerribleDev.Blog.Web.csproj"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
title: Hosting your blog on the cheap
|
||||
date: 2018-08-22 04:49:46
|
||||
date: 2019-08-17 04:49:46
|
||||
tags:
|
||||
- cloud
|
||||
|
||||
@@ -9,13 +9,12 @@ A load of people have been asking me lately how I host my blog. Incase its not a
|
||||
|
||||
<!-- more -->
|
||||
|
||||
Since I make no money, on this my strategy is about cutting costs. My grandfather use to say "take care of the pounds, because the pennies will take care of themselves." Now since my grandfather is in England, and their dollar is known as the pound, he was telling me to focus on the bigger picture.
|
||||
Since I make no money, on this my strategy is about cutting costs. My grandfather use to say "take care of the pounds, let the pennies take care of themselves." Now since my grandfather is in England, and their dollar is known as the pound, he was telling me to focus on the bigger picture.
|
||||
|
||||
The first big decision for blogs is what "engine" you are going to use, or if you are going to make your own. These usually fall into 2 categories. Static sites, which are usually when blogs are written in text files, and are compiled into static html, or server rendered blogs such as wordpress. When a request is made to blog that has server rendering, the html is dynamically built in time and delivered to the consumer. Static sites, on the other hand are precomputed and thus are just delivered to the browser.
|
||||
|
||||
I won't go into the details on what is better for different scenarios. If you are being cheap, then you will want to use static sites. Static sites are precomputed, which essentially means you just need to serve files to the user. There is no dynamic server to host, you won't need a database, etc. There are a few I like. This blog is ran off [Hexo](https://hexo.io)
|
||||
I won't go into the details on what is better for different scenarios. If you are being cheap, then you will want to use static sites. Static sites are precomputed, which essentially means you just need to serve files to the user. There is no dynamic server to host, you won't need a database, etc. There are a few I like, but my favorite is [gatsbyjs](https://www.gatsbyjs.org/).
|
||||
|
||||
|
||||
|
||||
<!-- So I know what you are thinking, static sites are just 'better' for page load time. While this is true, they can lack dynamic features that might be important to you, such as adding new blog posts on a schedule, or limiting ip addresses, or even some kind of login/subscription model. -->
|
||||
So I know what you are thinking, static sites are just 'better' for page load time. While this is true, they can lack dynamic features that might be important to you, such as adding new blog posts on a schedule, or limiting ip addresses, or even some kind of login/subscription model.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace TerribleDev.Blog.Web
|
||||
{
|
||||
public static SyndicationItem ToSyndicationItem(this IPost x)
|
||||
{
|
||||
Uri.TryCreate($"https://blog.terrible.dev/{x.Url}/", UriKind.Absolute, out var url);
|
||||
Uri.TryCreate(x.CanonicalUrl, UriKind.Absolute, out var url);
|
||||
var syn = new SyndicationItem()
|
||||
{
|
||||
Title = x.Title,
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace TerribleDev.Blog.Web.Factories
|
||||
}
|
||||
return accum;
|
||||
}).ToImmutableSortedDictionary();
|
||||
var urlToPosts = posts.ToImmutableDictionary(a => a.Url);
|
||||
var urlToPosts = posts.ToImmutableDictionary(a => a.UrlWithoutPath);
|
||||
var postsByPage =
|
||||
posts.Aggregate(ImmutableDictionary.Create<int, ImmutableList<IPost>>(), (accum, item) =>
|
||||
{
|
||||
|
||||
@@ -67,7 +67,9 @@ namespace TerribleDev.Blog.Web
|
||||
PublishDate = postSettings.date.ToUniversalTime(),
|
||||
tags = postSettings.tags?.Select(a => a.Replace(' ', '-').WithoutSpecialCharacters().ToLower()).ToList() ?? new List<string>(),
|
||||
Title = postSettings.title,
|
||||
Url = resolvedUrl,
|
||||
RelativeUrl = $"/{resolvedUrl}/",
|
||||
CanonicalUrl = $"https://blog.terrible.dev/{resolvedUrl}/",
|
||||
UrlWithoutPath = resolvedUrl,
|
||||
Content = new HtmlString(postContent),
|
||||
Summary = new HtmlString(summary),
|
||||
SummaryPlain = postSummaryPlain,
|
||||
|
||||
@@ -9,5 +9,6 @@ namespace TerribleDev.Blog.Web.Models
|
||||
{
|
||||
public IEnumerable<IPost> Posts { get; set; }
|
||||
public string Tag { get; set; }
|
||||
public string CanonicalUrl { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ namespace TerribleDev.Blog.Web.Models
|
||||
{
|
||||
public interface IPost
|
||||
{
|
||||
string Url { get; set; }
|
||||
string CanonicalUrl { get; set; }
|
||||
string UrlWithoutPath { get; set; }
|
||||
string RelativeUrl { get; set; }
|
||||
string Title { get; set; }
|
||||
HtmlString Summary { get; set; }
|
||||
DateTime PublishDate { get; set; }
|
||||
|
||||
@@ -8,7 +8,9 @@ namespace TerribleDev.Blog.Web.Models
|
||||
[DebuggerDisplay("{Title}")]
|
||||
public class Post : IPost
|
||||
{
|
||||
public string Url { get; set; }
|
||||
public string CanonicalUrl { get; set; }
|
||||
public string UrlWithoutPath { get; set; }
|
||||
public string RelativeUrl { get; set; }
|
||||
public string Title { get; set; }
|
||||
public DateTime PublishDate { get; set; }
|
||||
public HtmlString Content { get; set; }
|
||||
|
||||
@@ -12,8 +12,8 @@ using Microsoft.AspNetCore.Rewrite;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using HardHat.Middlewares;
|
||||
using HardHat;
|
||||
using TerribleDev.Blog.Web.Models;
|
||||
using TerribleDev.Blog.Web.Factories;
|
||||
@@ -22,14 +22,14 @@ namespace TerribleDev.Blog.Web
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration, IHostingEnvironment env)
|
||||
public Startup(IConfiguration configuration, IWebHostEnvironment env)
|
||||
{
|
||||
Configuration = configuration;
|
||||
Env = env;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
public IHostingEnvironment Env { get; }
|
||||
public IWebHostEnvironment Env { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
@@ -53,15 +53,17 @@ namespace TerribleDev.Blog.Web
|
||||
|
||||
})
|
||||
.AddMemoryCache()
|
||||
.AddMvcCore()
|
||||
.AddMvcCore(a => {
|
||||
a.EnableEndpointRouting = false;
|
||||
})
|
||||
.AddCacheTagHelper()
|
||||
.AddRazorViewEngine()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
services.AddOutputCaching();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -14,12 +15,12 @@ namespace TerribleDev.Blog.Web.Taghelpers
|
||||
[HtmlAttributeName("href")]
|
||||
public string Href { get; set; }
|
||||
|
||||
private IHostingEnvironment HostingEnvironment { get; }
|
||||
private IWebHostEnvironment HostingEnvironment { get; }
|
||||
private IMemoryCache Cache { get; }
|
||||
|
||||
|
||||
|
||||
public InlineStyleTagHelper(IHostingEnvironment hostingEnvironment, IMemoryCache cache)
|
||||
public InlineStyleTagHelper(IWebHostEnvironment hostingEnvironment, IMemoryCache cache)
|
||||
{
|
||||
HostingEnvironment = hostingEnvironment;
|
||||
Cache = cache;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<UserSecretsId>9a1f51b6-f4d9-4df7-a0af-e345176e9927</UserSecretsId>
|
||||
@@ -24,8 +24,6 @@
|
||||
<PackageReference Include="BuildBundlerMinifier" Version="2.8.391" />
|
||||
<PackageReference Include="Markdig" Version="0.15.7" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.0.2105168" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.0" />
|
||||
<PackageReference Include="UriBuilder.Fluent" Version="1.5.2" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@inject Microsoft.AspNetCore.Hosting.IHostingEnvironment env
|
||||
@inject Microsoft.AspNetCore.Hosting.IWebHostEnvironment env
|
||||
@{
|
||||
ViewData["Title"] = "Debug";
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<meta name="description" content="@Model.SummaryPlainShort" />
|
||||
<meta property="og:type" content="blog">
|
||||
<meta property="og:title" content="@Model.Title">
|
||||
<meta property="og:url" content="https://blog.terrible.dev/@Model.Url/">
|
||||
<meta property="og:url" content="@Model.CanonicalUrl">
|
||||
<meta property="og:site_name" content="@config.Title">
|
||||
<meta property="og:description" content="@Model.SummaryPlainShort">
|
||||
<meta property="og:updated_time" content="@Model.PublishDate.ToString("O")">
|
||||
@@ -22,6 +22,7 @@
|
||||
<meta name="twitter:description" content="@Model.SummaryPlainShort">
|
||||
<meta name="twitter:site" content="@@TerribleDev">
|
||||
<meta name="twitter:creator" content="@@TerribleDev">
|
||||
<link rel="canonical" href="@Model.CanonicalUrl" />
|
||||
@foreach(var image in Model.Images.Take(6))
|
||||
{
|
||||
<meta property="og:image" content="@image">
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
@model IPost
|
||||
|
||||
<article class="btmRule">
|
||||
<h3 itemprop="headline" class="headline"><a href="/@Model.Url/" class="link-unstyled">@Model.Title</a></h3>
|
||||
<h3 itemprop="headline" class="headline"><a href="@Model.RelativeUrl" class="link-unstyled">@Model.Title</a></h3>
|
||||
<time class="headlineSubtext" itemprop="datePublished" content="@Model.PublishDate.ToString()">@Model.PublishDate.ToString("D")</time>
|
||||
<div itemprop="articleBody">
|
||||
@Model.Summary
|
||||
</div>
|
||||
<a href="/@Model.Url/">Continue Reading </a>
|
||||
<a href="@Model.RelativeUrl">Continue Reading </a>
|
||||
</article>
|
||||
@@ -12,4 +12,5 @@
|
||||
</cache>
|
||||
@section Head {
|
||||
<partial name="StockMeta" />
|
||||
<link rel="canonical" href="https://blog.terrible.dev/all-tags/" />
|
||||
}
|
||||
@@ -9,3 +9,9 @@
|
||||
<partial name="PostSummary" model="post" />
|
||||
}
|
||||
</cache>
|
||||
|
||||
@section Head {
|
||||
@if(!String.IsNullOrEmpty(Model.CanonicalUrl)) {
|
||||
<link rel="canonical" href="@Model.CanonicalUrl" />
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user