如何在.NET core 2中动态创建站点地图.xml?



谁能告诉我如何在.NET Core 2中创建站点地图?

这些文章/备用链接在 .NET Core 2 中不起作用。

我从我正在处理的示例 Web 应用程序中找到了您问题的解决方案。功劳归于麦德斯·克里斯滕森。这是您正在寻找的内容的非常简化的版本。将此代码放在控制器类(如 HomeController(中,方法与添加操作方法的方式相同。

下面是返回 XML 的方法:

[Route("/sitemap.xml")]
public void SitemapXml()
{
string host = Request.Scheme + "://" + Request.Host;
Response.ContentType = "application/xml";
using (var xml = XmlWriter.Create(Response.Body, new XmlWriterSettings { Indent = true }))
{
xml.WriteStartDocument();
xml.WriteStartElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9");
xml.WriteStartElement("url");
xml.WriteElementString("loc", host);
xml.WriteEndElement();
xml.WriteEndElement();
}
}

当您键入http://www.example.com/sitemap.xml时,这将产生以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.example.com/</loc>
</url>
</urlset>

我希望这有帮助?如果您还发现了某些内容,请将您的解决方案作为您问题的更新。

实际上,我更喜欢使用Razor将其写入模板文件中。假设您只有一个页面,.NET Core 3.1 中的示例代码将如下所示(.NET Core 2 代码不会有太大区别(:

<!-- XmlSitemap.cshtml -->
@page "/sitemap.xml"
@using Microsoft.AspNetCore.Http
@{
var pages = new List<dynamic>
{
new { Url = "http://example.com/", LastUpdated = DateTime.Now }
};
Layout = null;
Response.ContentType = "text/xml";
await Response.WriteAsync("<?xml version='1.0' encoding='UTF-8' ?>");
}
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@foreach (var page in pages)
{
<url>
<loc>@page.Url</loc>
<lastmod>@page.LastUpdated.ToString("yyyy-MM-dd")</lastmod>
</url>
}
</urlset>

希望这有帮助!

幸运的是,已经有一个预建库的列表。安装此工具 https://github.com/uhaciogullari/SimpleMvcSitemap

然后像这样创建一个新的控制器(github上有更多示例(:

public class SitemapController : Controller
{
public ActionResult Index()
{
List<SitemapNode> nodes = new List<SitemapNode>
{
new SitemapNode(Url.Action("Index","Home")),
new SitemapNode(Url.Action("About","Home")),
//other nodes
};
return new SitemapProvider().CreateSitemap(new SitemapModel(nodes));
}
}

中间件工作正常,但需要小修复。

if (context.Request.Path.Value.Equals("/sitemap.xml", StringComparison.OrdinalIgnoreCase))
{
// Implementation
}
else
await _next(context);

我创建了一个新项目,然后在添加中间件并运行后,我在浏览器中输入 http://localhost:64522/sitemap.xml,得到以下结果:

<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://localhost:64522/home/index</loc>
<lastmod>2018-05-13</lastmod>
</url>
<url>
<loc>http://localhost:64522/home/about</loc>
<lastmod>2018-05-13</lastmod>
</url>
<url>
<loc>http://localhost:64522/home/contact</loc>
<lastmod>2018-05-13</lastmod>
</url>
<url>
<loc>http://localhost:64522/home/privacy</loc>
<lastmod>2018-05-13</lastmod>
</url>
<url>
<loc>http://localhost:64522/home/error</loc>
<lastmod>2018-05-13</lastmod>
</url>
</urlset>

动态站点地图"sitemap-blog.xml"用于博客部分和24小时缓存。(ASP.NET 核心3.1(

  • 站点地图.xml存在于wwwroot中(由 xml-sitemaps.com 或...生成(。
  • 站点地图-博客.xml动态生成。

机器人.txt

User-agent: *
Disallow: /Admin/
Disallow: /Identity/
Sitemap: https://example.com/sitemap.xml
Sitemap: https://example.com/sitemap-blog.xml

启动.cs

services.AddMemoryCache();

首页控制器.cs

namespace MT.Controllers
{
public class HomeController : Controller
{
private readonly ApplicationDbContext _context;
private readonly IMemoryCache _cache;
public HomeController(
ApplicationDbContext context,
IMemoryCache cache)
{
_context = context;
_cache = cache;
}
[Route("/sitemap-blog.xml")]
public async Task<IActionResult> SitemapBlog()
{
string baseUrl = $"{Request.Scheme}://{Request.Host}{Request.PathBase}";
string segment = "blog";
string contentType = "application/xml";
string cacheKey = "sitemap-blog.xml";
// For showing in browser (Without download)
var cd = new System.Net.Mime.ContentDisposition
{
FileName = cacheKey,
Inline = true,
};
Response.Headers.Append("Content-Disposition", cd.ToString());
// Cache
var bytes = _cache.Get<byte[]>(cacheKey);
if (bytes != null)
return File(bytes, contentType);
var blogs = await _context.Blogs.ToListAsync();
var sb = new StringBuilder();
sb.AppendLine($"<?xml version="1.0" encoding="utf-8"?>");
sb.AppendLine($"<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"");
sb.AppendLine($"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"");
sb.AppendLine($"   xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">");
foreach (var m in blogs)
{
var dt = m.LastModified;
string lastmod = $"{dt.Year}-{dt.Month.ToString("00")}-{dt.Day.ToString("00")}";
sb.AppendLine($"    <url>");
sb.AppendLine($"        <loc>{baseUrl}/{segment}/{m.Slug}</loc>");
sb.AppendLine($"        <lastmod>{lastmod}</lastmod>");
sb.AppendLine($"        <changefreq>daily</changefreq>");
sb.AppendLine($"        <priority>0.8</priority>");
sb.AppendLine($"    </url>");
}
sb.AppendLine($"</urlset>");
bytes = Encoding.UTF8.GetBytes(sb.ToString());
_cache.Set(cacheKey, bytes, TimeSpan.FromHours(24));
return File(bytes, contentType);
}
}
}

下面的代码适用于 ASP.NET Core 2.2。

public class SitemapUrl
{
public string Page { get; set; }
public DateTime? LastModifyed { get; set; }
/*
always
hourly
daily
weekly
monthly
yearly
never
*/
public string ChangeFreq { get; set; }
public float Priority { get; set; } = 0.5f;
}
public class SitemapResult : ActionResult
{
private readonly IEnumerable<SitemapUrl> _urls;
public SitemapResult(IEnumerable<SitemapUrl> urls)
{
_urls = urls;
}
public override async Task ExecuteResultAsync(ActionContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var response = context.HttpContext.Response;
response.ContentType = "application/xml; charset=utf-8";
var settings = new XmlWriterSettings() { Async = true, Encoding = Encoding.UTF8, Indent = false };
using (var writer = XmlWriter.Create(response.Body, settings))
{
WriteToXML(writer);
await writer.FlushAsync();
}
}
private void WriteToXML(XmlWriter writer)
{
writer.WriteStartDocument();
// Write the urlset.
writer.WriteStartElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9");
// url element
foreach (var item in _urls)
{
writer.WriteStartElement("url");
// loc
writer.WriteStartElement("loc");
writer.WriteValue(item.Page);
writer.WriteEndElement();
// changefreq
if (!string.IsNullOrEmpty(item.ChangeFreq))
{
writer.WriteStartElement("changefreq");
writer.WriteValue(item.ChangeFreq);
writer.WriteEndElement();
}
// lastmod
if (item.LastModifyed.HasValue)
{
writer.WriteStartElement("lastmod");
writer.WriteValue(item.LastModifyed.Value.ToString("yyyy-MM-dd"));
writer.WriteEndElement();
}
// priority
writer.WriteStartElement("priority");
writer.WriteValue(item.Priority);
writer.WriteEndElement();
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}

之后调用 MVC 控制器类中的SitemapResult

public IActionResult Sitemap(){
return new SitemapResult(new SitemapUrl[] { new SitemapUrl() { } });
}

在 ASP.NET 3.0+ 中,只需删除async操作即可在所有服务器中禁用XmlWriterSettings或 AllowSynchronousIO

我使用SitemapHub站点地图工具为我的多个网站构建XML站点地图,无需编码,节省了我的时间。

SEOHelper是一个用于SEO管理的nuget库。

Install-Package AspNetCore.SEOHelper

SEOHelper 包提供了用于设置 URL 的 SitemapNode 类和用于创建 sitemap.xml的 CreateSitemapXML 方法。

var list = new List<SitemapNode>();  
list.Add(new SitemapNode { LastModified = DateTime.UtcNow, Priority = 0.8, Url = "https://www.example.com/page 1", Frequency = SitemapFrequency.Daily });  
list.Add(new SitemapNode { LastModified = DateTime.UtcNow, Priority = 0.9, Url = "https://www.example.com/page2", Frequency = SitemapFrequency.Yearly });  
new SitemapDocument().CreateSitemapXML(list, _env.ContentRootPath);  

让我们采取两种方法来获得预期的结果。

首先,这些文章使用中间件方法。有使用控制器和 nuget 包的简单解决方案SimpleMvcSitemap

public class SitemapController : Controller
{
public ActionResult Index()
{
List<SitemapNode> nodes = new List<SitemapNode>
{
new SitemapNode(Url.Action("Index","Home")),
new SitemapNode(Url.Action("About","Home")),
//other nodes
};
return new SitemapProvider().CreateSitemap(new SitemapModel(nodes));
}
}

第二部分是使用反射动态获取所有控制器和操作。使用 iaspnetcore 示例,下面介绍如何获取控制器和操作的列表

// get available controllers
var controllers = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type)
|| type.Name.EndsWith("controller")).ToList();
foreach (var controller in controllers)
{
var controllerName = controller.Name.Replace("Controller", "");
// get available methods  in controller
var methods = controller.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(method => typeof(IActionResult).IsAssignableFrom(method.ReturnType));
foreach (var method in methods)
{
var myRoute = Url.Action(method.Name, controllerName);
}
}

把它们放在一起,我们有这个代码

/// <summary>
/// Base URL Provider for sitemap. Replace with your domain
/// </summary>
public class BaseUrlProvider : IBaseUrlProvider
{
public Uri BaseUrl => new Uri("https://example.com");
}
public class SitemapController : Controller
{
[Route("sitemap.xml")]
public ActionResult Index()
{
List<SitemapNode> nodes = new List<SitemapNode>();

// get available contrtollers
var controllers = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type)
|| type.Name.EndsWith("controller")).ToList();
foreach (var controller in controllers)
{
// get available methods
var methods = controller.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(method => typeof(IActionResult).IsAssignableFrom(method.ReturnType));
foreach (var method in methods)
{
// add route name in sitemap
nodes.Add(new SitemapNode(Url.Action(method.Name, controllerName)));
}
}
return new SitemapProvider(new BaseUrlProvider()).CreateSitemap(new SitemapModel(nodes));
}
}

使用列表:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using SimpleMvcSitemap;
using SimpleMvcSitemap.Routing;

最后只需开放路线,例如:

https://localhost:44312/sitemap.xml

启动

services.AddMvcCore(options =>
{
options.OutputFormatters.Clear(); // Remove json for simplicity
options.OutputFormatters.Add(new MyCustomXmlSerializerOutputFormatter());
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "sitemapxml",
pattern: "/sitemap.xml",
defaults: new { controller = "Home", action = "SitemapXML" }
);

自定义格式化程序

public class MyCustomXmlSerializerOutputFormatter : XmlSerializerOutputFormatter
{
protected override void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
{
xmlSerializer = new XmlSerializer(typeof(List<url>), new XmlRootAttribute("urlset"));
xmlSerializer.Serialize(xmlWriter, value);
}
}

网址类

public class url
{

public string changefreq { get; set; }
public DateTime? lastModified { get; set; }
public double? priority { get; set; }
public string loc { get; set; }
}

控制器

[HttpGet]
[Produces("application/xml")]
public ActionResult<List<url>> SitemapXML() 
{
var list = new List<url>();
var dokumanlar = _dokumanCategoryService.GetAll().Where(i => i.Yatirimci == 1).ToList();


foreach (var dokuman in dokumanlar)
{
var dokumanurl = dokuman.SeoUrl;
var culture = dokuman.Culture;
if (dokuman.Culture == "tr")
{
list.Add(new url { lastModified = DateTime.UtcNow, priority = 0.8, loc = $"https://example.com/yatirimci-iliskileri/{dokumanurl}", changefreq = "always" });
}
else
{
list.Add(new url { lastModified = DateTime.UtcNow, priority = 0.8, loc = $"https://example.com/{culture}/investor-relations/{dokumanurl}", changefreq = "always" });
}

}


return list;
}

如果您使用的是 .net core 2 及更高版本,请执行以下操作:

将此添加到 .csproj 文件

然后在程序.cs文件中添加引用 使用X.Web.Sitemap;

在程序中.cs文件在 Main 方法中执行此操作:

var sitemap = new Sitemap();
sitemap.Add(new Url
{
ChangeFrequency = ChangeFrequency.Daily,
Location = "https://www.website.com",
Priority = 0.5,
TimeStamp = DateTime.Now
});
sitemap.Add(CreateUrl("https://www.website.com/about"));
sitemap.Add(CreateUrl("https://www.website.com/services"));
sitemap.Add(CreateUrl("https://www.website.com/products"));
sitemap.Add(CreateUrl("https://www.website.com/casestudies"));
sitemap.Add(CreateUrl("https://www.website.com/blogs"));
sitemap.Add(CreateUrl("https://www.website.com/contact"));
//Save sitemap structure to file
sitemap.Save(@"wwwrootsitemap.xml");
//Split a large list into pieces and store in a directory
//sitemap.SaveToDirectory(@"d:wwwsummituniversity.edu.ngsitemaps");
//Get xml-content of file
Console.Write(sitemap.ToXml());
Console.ReadKey();

外侧主方法这样做:

private static Url CreateUrl(string url)
{
return new Url
{
ChangeFrequency = ChangeFrequency.Daily,
Location = url,
Priority = 0.5,
TimeStamp = DateTime.Now
};
}

到目前为止,我发现使用.Net Core 3.x的最优雅的方式是使用ParkSquare.AspNetCore.Sitemap。这将根据您定义的路线动态创建站点地图.xml和机器人.txt。

在 startup.cs 中,注册中间件:

app.UseSitemap();

若要排除任何内容,可以修饰控制器类以排除该控制器或特定路由中的所有内容:

// All routes in this controller will be ignored
[SitemapExclude]
public class BlahController : Controller
{
[Route("some-route")]
public IActionResult Something()
{
return View();
}
}
public class BlahController : Controller
{
[SitemapExclude]
[Route("some-route")]
public IActionResult Ignored()
{
return View();
}
[Route("some-other-route")]
public IActionResult NotIgnored()
{  
return View();
}
}

最新更新