namespace Yes.Application.Core.HostedServices { public class RssGenerationJob { private readonly BlogSettings _settings; private readonly BlogDbContext _db; private readonly ILogger _logger; private readonly IWebHostEnvironment _env; public RssGenerationJob( IOptionsMonitor options, BlogDbContext db, IWebHostEnvironment env, ILogger logger) { _settings = options.CurrentValue; _db = db; _env = env; _logger = logger; } public async Task Execute() { try { var queryArticle = _db.Articles.Where(x => x.Type == ArticleTypeEnum.Article && x.Status == ArticleStatusEnum.Normal).AsQueryable(); var pubDate = queryArticle.Any() ? _db.Articles.Min(x => x.PublishDate) : DateTime.MinValue; var channel = new Channel { Title = _settings.Name, Link = _settings.Url, Description = _settings.Description, Language = "zh-CN", FeedUrl = $"{_settings.Url}/feed/", PubDate = pubDate }; // 添加扩展元素(示例) channel.Extensions.Add(new XElement("generator", _settings.Name)); channel.Extensions.Add(new XElement("docs", "http://www.rssboard.org/rss-specification")); var query = from article in queryArticle join categoryTemp in _db.Categories.AsNoTracking() on article.CategoryId equals categoryTemp.Id into tempCategory from category in tempCategory.DefaultIfEmpty() join userTemp in _db.Users.AsNoTracking() on article.UserId equals userTemp.Id into tempUser from user in tempUser.DefaultIfEmpty() orderby article.Id descending select new ArticleModel { Id = article.Id, CanComment = article.CanComment, CommentCount = article.CommentCount, CategoryId = article.CategoryId, ModifyDate = article.ModifyDate.ToSafeTime(), PublishDate = article.PublishDate.ToSafeTime(), CreateDate = article.CreateDate.ToSafeTime(), Content = article.Content, CoverUrl = article.CoverUrl, Slug = article.Slug, ReadCount = article.ReadCount, Title = article.Title, Summary = article.Summary, UserId = article.UserId, Category = new CategoryModel { CoverUrl = category.CoverUrl, Description = category.Description, Id = category.Id, Name = category.Name, Slug = category.Slug } }; var items = query.Select(x => new Item { Content = x.Content, Title = x.Title, Url = $"{_settings.Url}/{_settings.ArticleRoute.ToRoute(x.Category, x)}", Description = x.Summary, CommentsCount = x.CommentCount, Creator = x.UserId.ToString(), PublishDate = x.PublishDate, CommentsUrl = $"{_settings.Url}/{_settings.ArticleRoute.ToRoute(x.Category, x)}#comments", CommentRssUrl = $"{_settings.Url}/feed/" }); var generator = new RssGenerator(); string xml = generator.GenerateRss(channel, items); File.WriteAllText(Path.Combine(_env.WebRootPath, "feed.xml"), xml); } catch (Exception ex) { _logger.LogError(ex, "RSS generation failed"); } } } }