[英]How to deduplicate an automatic “Canonical Link” redirector in ASP.NET Core 3.1 C#?
For every web page within my ASP.NET Core 3.1 C# application, I want to automatically generate an canonical link for SEO purposes.对于我的 ASP.NET Core 3.1 C# 应用程序中的每个 web 页面,我想为 SEO 目的自动生成规范链接。
Currently (POC phase), I have the following snippet in every controller action function:目前(POC 阶段),我在每个 controller 动作 function 中都有以下片段:
Uri actualUrl = new Uri($"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.Path}{HttpContext.Request.QueryString}");
RouteValueDictionary values = RouteData.Values;
values.Remove("controller");
values.Remove("action");
foreach (var q in HttpContext.Request.Query)
values.Add(q.Key, q.Value);
// Further route/query parameter "fixes" here.
Uri canonicalUrl = new Uri(Url.ActionLink(values: values));
if (!canonicalUrl.Equals(actualUrl))
return RedirectPermanentPreserveMethod(canonicalUrl.ToString());
This snippet first builds a Uri
with the current actual URL.此代码段首先使用当前实际的 URL 构建一个
Uri
。 Then it may "fixes" some important route/query parameters (as shown below).然后它可能会“修复”一些重要的路由/查询参数(如下所示)。 Finally it compares the actual uri with the desired uri, and redirects to the desired uri, when the actual uri is different compared to the desired uri (case sensitive).
最后,它将实际 uri 与所需 uri 进行比较,并在实际 uri 与所需 uri 不同时重定向到所需 uri(区分大小写)。
RouteData.Values["subpage"] = "Digital-Contents";
This process enables the web application to generate the correct canonical url ( http://example.com/MyController/MyAction/Digital-Contents ) for the following sample urls.此过程使 web 应用程序能够为以下示例 URL 生成正确的规范 url( http://example.com/MyController/MyAction/Digital-Contents )。
However, the POC is a massive duplication of code, and thus not desirable itself.然而,POC 是大量的代码重复,因此本身并不理想。
My first thought was to use a middleware.我的第一个想法是使用中间件。 However, with an middleware, the action controller cannot "fix" route/query parameters, which are out-of-scope of the regular routing construct (like the "id" route parameter which is shown in most ASP.NET examples).
但是,对于中间件,操作 controller 无法“修复”路由/查询参数,这些参数超出了常规路由结构的范围(如大多数 ASP.NET 示例中显示的“id”路由参数)。 Eg
ActionLink
is capable of producing the correct case sensitive url slugs for controller and action, but cannot process ("fix") other route/query parameters.例如,
ActionLink
能够为 controller 和操作生成正确的区分大小写的 url slug,但不能处理(“修复”)其他路由/查询参数。
My second thought was to use a generic class, but there I lose the context.我的第二个想法是使用通用的 class,但我失去了上下文。
The best solution would be a single (void) function call, which can be placed before the actual action heavy processing (inside the action controller before processing data and generating output).最好的解决方案是单个(无效)function 调用,它可以放置在实际操作重处理之前(在处理数据和生成输出之前的操作 controller 内部)。
How to deduplicate this "automatic canonical redirector" code?如何对这个“自动规范重定向器”代码进行重复数据删除?
This may not be the best solution, i just modified the case based on the code you provided:这可能不是最好的解决方案,我只是根据您提供的代码修改了案例:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CanonicalUrlAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var httpContext = filterContext.HttpContext;
Uri actualUrl = new Uri($"{httpContext.Request.Scheme}://{httpContext.Request.Host}{httpContext.Request.Path}{httpContext.Request.QueryString}");
RouteValueDictionary values = filterContext.RouteData.Values;
values.Remove("controller");
values.Remove("action");
foreach (var q in httpContext.Request.Query)
values.Add(q.Key, q.Value);
// Further route/query parameter "fixes" here.
Uri canonicalUrl = new Uri(new UrlHelper(filterContext).ActionLink(values));
if (!canonicalUrl.Equals(actualUrl))
filterContext.Result = new LocalRedirectResult(canonicalUrl.ToString());
}
}
[CanonicalUrl]
public class HomeController : Controller {
}
If you're using names from view models to generate urls like example.com/some-category/some-product
then i would use the helper in this Link to generate a slug in kebab case based on the model name (in my case its saved to db on model creation) then with a custom route:如果您使用视图模型中的名称来生成诸如
example.com/some-category/some-product
之类的 URL,那么我将使用此链接中的帮助程序根据 model 名称(在我的情况下为在创建 model 时保存到 db)然后使用自定义路由:
endpoints.MapControllerRoute(
name: "category",
pattern: "{Category}/{Product}",
defaults: new { controller = "Product", action = "Index" });
This pattern omits the action and controller names from route (which i prefer) and gives you something like this example.com/some-category/some-product
and in your action you just compare the model's slug with the route segment that is provided by the user (using the route contraint) like this:这种模式省略了动作和 controller 来自 route 的名称(我更喜欢),并为您提供类似
example.com/some-category/some-product
的内容,在您的操作中,您只需将模型的 slug 与提供的路线段进行比较用户(使用路由约束)如下:
public async Task<IActionResult> Index([FromRoute,Required] Category,[FromRoute,Required] Product)
and you do a route redirect on mismatch like this:并且您对不匹配进行路由重定向,如下所示:
return RedirectToRoutePermanent("category", new { Product = Product.Slug, Category = Product.Category.Slug });
Hope this helps.希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.