using System.IO.Compression; using System.Net; using System.Xml; using Netina.Core.Models; using Netina.Domain.Entities.ProductCategories; namespace Netina.Core.BaseServices; public class SiteMapService( IOptionsSnapshot snapshot, IUploadFileService uploadFileService, IRepositoryWrapper repositoryWrapper, IPageService pageService) : ISiteMapService { private readonly SiteSettings _siteSetting = snapshot.Value; public async Task CreateSiteMapAsync() { XmlDocument doc = new XmlDocument(); XmlDeclaration documentType = doc.CreateXmlDeclaration("1.0", "utf-8", null); doc.AppendChild(documentType); // XML declaration //XmlNode declaration = doc.CreateNode(XmlNodeType.XmlDeclaration, "sitemap.xml", null); //doc.AppendChild(declaration); // Root element: Catalog XmlElement root = doc.CreateElement("sitemapindex", "http://www.sitemaps.org/schemas/sitemap/0.9"); doc.AppendChild(root); var productCategories = await repositoryWrapper.SetRepository() .TableNoTracking .ToListAsync(); var blogCategories= await repositoryWrapper.SetRepository() .TableNoTracking .ToListAsync(); foreach (var siteMapsUId in SiteMapUIds.AllSiteMapsUIds) { XmlElement siteMapElement = doc.CreateElement("sitemap", doc.DocumentElement?.NamespaceURI); root.AppendChild(siteMapElement); XmlElement id = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI); id.InnerText = Path.Combine(_siteSetting.StorageBaseUrl, "site-maps", $"{siteMapsUId}.gz"); siteMapElement.AppendChild(id); XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI); lastmod.InnerText = DateTime.Today.ToString("yyyy-MM-dd"); siteMapElement.AppendChild(lastmod); } foreach (var blogCategory in blogCategories) { XmlElement siteMapElement = doc.CreateElement("sitemap", doc.DocumentElement?.NamespaceURI); root.AppendChild(siteMapElement); XmlElement id = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI); id.InnerText = Path.Combine(_siteSetting.StorageBaseUrl, "site-maps", $"{blogCategory.Id.ToString().ToUpper()}.gz"); siteMapElement.AppendChild(id); XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI); lastmod.InnerText = DateTime.Today.ToString("yyyy-MM-dd"); siteMapElement.AppendChild(lastmod); } foreach (var productCategory in productCategories) { XmlElement siteMapElement = doc.CreateElement("sitemap", doc.DocumentElement?.NamespaceURI); root.AppendChild(siteMapElement); XmlElement id = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI); id.InnerText = Path.Combine(_siteSetting.StorageBaseUrl, "site-maps", $"{productCategory.Id.ToString().ToUpper()}.gz"); siteMapElement.AppendChild(id); XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI); lastmod.InnerText = DateTime.Today.ToString("yyyy-MM-dd"); siteMapElement.AppendChild(lastmod); } System.IO.MemoryStream stream = new System.IO.MemoryStream(); XmlTextWriter writer = new XmlTextWriter(stream, System.Text.Encoding.UTF8); doc.WriteTo(writer); writer.Flush(); byte[] byteArray = stream.ToArray(); await uploadFileService.UploadFileByteAsync(new FileUploadRequest { FileBytes = byteArray, ContentType = "text/xml", FileName = "site-map.xml", FileUploadType = FileUploadType.SiteMap, }); await CreateCategoriesSiteMapsAsync(); await CreateProductsSiteMapsAsync(); await CreateBlogsSiteMapsAsync(); await CreateBrandsSiteMapsAsync(); await CreateBlogCategoriesSiteMapsAsync(); await CreatePagesSiteMapsAsync(); } private async Task CreatePagesSiteMapsAsync() { var siteMapsUId = SiteMapUIds.Pages; var pages = await pageService.GetPagesAsync(); XmlDocument doc = new XmlDocument(); XmlDeclaration documentType = doc.CreateXmlDeclaration("1.0", "utf-8", null); doc.AppendChild(documentType); //XmlNode declaration = doc.CreateNode(XmlNodeType.XmlDeclaration, "sitemap.xml", null); //doc.AppendChild(declaration); XmlElement root = doc.CreateElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9"); root.SetAttribute("xmlns:image", "http://www.google.com/schemas/sitemap-image/1.1"); doc.AppendChild(root); foreach (var page in pages) { string slugHtml = page.Slug; if (slugHtml.Contains(' ')) slugHtml = WebUtility.UrlEncode(slugHtml.Replace(' ', '-')); var productUrl = $"{_siteSetting.WebSiteUrl}/{slugHtml}"; XmlElement urlElement = doc.CreateElement("url", doc.DocumentElement?.NamespaceURI); root.AppendChild(urlElement); XmlElement loc = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI); loc.InnerText = Path.Combine(productUrl); urlElement.AppendChild(loc); XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI); lastmod.InnerText = page.ModifiedAt == DateTime.MinValue ? page.CreatedAt.ToString("yyyy-MM-dd") : page.ModifiedAt.ToString("yyyy-MM-dd"); urlElement.AppendChild(lastmod); XmlElement changeFeq = doc.CreateElement("changefreq", doc.DocumentElement?.NamespaceURI); changeFeq.InnerText = "weekly"; urlElement.AppendChild(changeFeq); XmlElement priority = doc.CreateElement("priority", doc.DocumentElement?.NamespaceURI); priority.InnerText = "0.8"; urlElement.AppendChild(priority); } using var siteMapStream = new MemoryStream(); await using var siteMapWriter = new XmlTextWriter(siteMapStream, Encoding.UTF8); doc.WriteTo(siteMapWriter); siteMapWriter.Flush(); byte[] unZipBytes = siteMapStream.ToArray(); using (var compressedStream = new MemoryStream()) await using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) { zipStream.Write(unZipBytes, 0, unZipBytes.Length); zipStream.Close(); var siteMapArray = compressedStream.ToArray(); await uploadFileService.UploadFileByteAsync(new FileUploadRequest { FileBytes = siteMapArray, ContentType = "text/plain", FileName = $"{siteMapsUId}.gz", FileUploadType = FileUploadType.SiteMap, }); } } private async Task CreateBrandsSiteMapsAsync() { var siteMapsUId = SiteMapUIds.Brands; var brands = await repositoryWrapper.SetRepository() .TableNoTracking .ToListAsync(); XmlDocument doc = new XmlDocument(); XmlDeclaration documentType = doc.CreateXmlDeclaration("1.0", "utf-8", null); doc.AppendChild(documentType); //XmlNode declaration = doc.CreateNode(XmlNodeType.XmlDeclaration, "sitemap.xml", null); //doc.AppendChild(declaration); XmlElement root = doc.CreateElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9"); root.SetAttribute("xmlns:image", "http://www.google.com/schemas/sitemap-image/1.1"); doc.AppendChild(root); foreach (var brand in brands) { string slugHtml = brand.Slug; if (slugHtml.Contains(' ')) slugHtml = WebUtility.UrlEncode(slugHtml.Replace(' ', '-')); var productUrl = $"{_siteSetting.WebSiteUrl}/brands/{brand.Id}/{slugHtml}"; XmlElement urlElement = doc.CreateElement("url", doc.DocumentElement?.NamespaceURI); root.AppendChild(urlElement); XmlElement loc = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI); loc.InnerText = Path.Combine(productUrl); urlElement.AppendChild(loc); XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI); lastmod.InnerText = brand.ModifiedAt == DateTime.MinValue ? brand.CreatedAt.ToString("yyyy-MM-dd") : brand.ModifiedAt.ToString("yyyy-MM-dd"); urlElement.AppendChild(lastmod); XmlElement changeFeq = doc.CreateElement("changefreq", doc.DocumentElement?.NamespaceURI); changeFeq.InnerText = "daily"; urlElement.AppendChild(changeFeq); XmlElement priority = doc.CreateElement("priority", doc.DocumentElement?.NamespaceURI); priority.InnerText = "0.9"; urlElement.AppendChild(priority); } using var siteMapStream = new MemoryStream(); await using var siteMapWriter = new XmlTextWriter(siteMapStream, Encoding.UTF8); doc.WriteTo(siteMapWriter); siteMapWriter.Flush(); byte[] unZipBytes = siteMapStream.ToArray(); using (var compressedStream = new MemoryStream()) await using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) { zipStream.Write(unZipBytes, 0, unZipBytes.Length); zipStream.Close(); var siteMapArray = compressedStream.ToArray(); await uploadFileService.UploadFileByteAsync(new FileUploadRequest { FileBytes = siteMapArray, ContentType = "text/plain", FileName = $"{siteMapsUId}.gz", FileUploadType = FileUploadType.SiteMap, }); } } private async Task CreateCategoriesSiteMapsAsync() { var siteMapsUId = SiteMapUIds.Categories; var categories = await repositoryWrapper.SetRepository() .TableNoTracking .ToListAsync(); XmlDocument doc = new XmlDocument(); XmlDeclaration documentType = doc.CreateXmlDeclaration("1.0", "utf-8", null); doc.AppendChild(documentType); //XmlNode declaration = doc.CreateNode(XmlNodeType.XmlDeclaration, "sitemap.xml", null); //doc.AppendChild(declaration); XmlElement root = doc.CreateElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9"); root.SetAttribute("xmlns:image", "http://www.google.com/schemas/sitemap-image/1.1"); doc.AppendChild(root); foreach (var productCategory in categories) { string slugHtml = productCategory.Slug; if (slugHtml.Contains(' ')) slugHtml = WebUtility.UrlEncode(slugHtml.Replace(' ', '-')); var productUrl = $"{_siteSetting.WebSiteUrl}/categories/{productCategory.Id}/{slugHtml}"; XmlElement urlElement = doc.CreateElement("url", doc.DocumentElement?.NamespaceURI); root.AppendChild(urlElement); XmlElement loc = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI); loc.InnerText = Path.Combine(productUrl); urlElement.AppendChild(loc); XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI); lastmod.InnerText = productCategory.ModifiedAt == DateTime.MinValue ? productCategory.CreatedAt.ToString("yyyy-MM-dd") : productCategory.ModifiedAt.ToString("yyyy-MM-dd"); urlElement.AppendChild(lastmod); XmlElement changeFeq = doc.CreateElement("changefreq", doc.DocumentElement?.NamespaceURI); changeFeq.InnerText = "daily"; urlElement.AppendChild(changeFeq); XmlElement priority = doc.CreateElement("priority", doc.DocumentElement?.NamespaceURI); priority.InnerText = "0.9"; urlElement.AppendChild(priority); } using var siteMapStream = new MemoryStream(); await using var siteMapWriter = new XmlTextWriter(siteMapStream, Encoding.UTF8); doc.WriteTo(siteMapWriter); siteMapWriter.Flush(); byte[] unZipBytes = siteMapStream.ToArray(); using (var compressedStream = new MemoryStream()) await using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) { zipStream.Write(unZipBytes, 0, unZipBytes.Length); zipStream.Close(); var siteMapArray = compressedStream.ToArray(); await uploadFileService.UploadFileByteAsync(new FileUploadRequest { FileBytes = siteMapArray, ContentType = "text/plain", FileName = $"{siteMapsUId}.gz", FileUploadType = FileUploadType.SiteMap, }); } } private async Task CreateProductsSiteMapsAsync() { var products = await repositoryWrapper.SetRepository() .TableNoTracking .Select(ProductMapper.ProjectToSDto) .ToListAsync(); var groupedProducts = products.GroupBy(p => p.CategoryId); foreach (var group in groupedProducts) { XmlDocument doc = new XmlDocument(); XmlDeclaration documentType = doc.CreateXmlDeclaration("1.0", "utf-8", null); doc.AppendChild(documentType); //XmlNode declaration = doc.CreateNode(XmlNodeType.XmlDeclaration, "sitemap.xml", null); //doc.AppendChild(declaration); XmlElement root = doc.CreateElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9"); root.SetAttribute("xmlns:image", "http://www.google.com/schemas/sitemap-image/1.1"); doc.AppendChild(root); foreach (var product in group) { string slugHtml = product.Slug; if (slugHtml.Contains(' ')) slugHtml = WebUtility.UrlEncode(slugHtml.Replace(' ', '-')); var productUrl = $"{_siteSetting.WebSiteUrl}/products/{product.Id}/{slugHtml}"; XmlElement urlElement = doc.CreateElement("url", doc.DocumentElement?.NamespaceURI); root.AppendChild(urlElement); XmlElement loc = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI); loc.InnerText = Path.Combine(productUrl); urlElement.AppendChild(loc); XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI); lastmod.InnerText = product.ModifiedAt == DateTime.MinValue ? product.CreatedAt.ToString("yyyy-MM-dd") : product.ModifiedAt.ToString("yyyy-MM-dd"); urlElement.AppendChild(lastmod); XmlElement changeFeq = doc.CreateElement("changefreq", doc.DocumentElement?.NamespaceURI); changeFeq.InnerText = "daily"; urlElement.AppendChild(changeFeq); XmlElement priority = doc.CreateElement("priority", doc.DocumentElement?.NamespaceURI); priority.InnerText = "0.9"; urlElement.AppendChild(priority); if (product.MainImage != string.Empty) { XmlElement image = doc.CreateElement("image:image", "http://www.google.com/schemas/sitemap-image/1.1"); urlElement.AppendChild(image); XmlElement imageLoc = doc.CreateElement("image:loc", "http://www.google.com/schemas/sitemap-image/1.1"); var imageUrl = product.MainImage.Contains("Med") || product.MainImage.Contains("Thumb") ? product.MainImage.Replace("Med", "Thumb") : Path.Combine("Images", "Med", product.MainImage); imageLoc.InnerText = $"{_siteSetting.StorageBaseUrl}/{imageUrl}"; image.AppendChild(imageLoc); XmlElement imageCaption = doc.CreateElement("image:caption", "http://www.google.com/schemas/sitemap-image/1.1"); imageCaption.InnerText = product.PersianName; image.AppendChild(imageCaption); } } using var siteMapStream = new MemoryStream(); await using var siteMapWriter = new XmlTextWriter(siteMapStream, Encoding.UTF8); doc.WriteTo(siteMapWriter); siteMapWriter.Flush(); byte[] unZipBytes = siteMapStream.ToArray(); using (var compressedStream = new MemoryStream()) await using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) { zipStream.Write(unZipBytes, 0, unZipBytes.Length); zipStream.Close(); var siteMapArray = compressedStream.ToArray(); await uploadFileService.UploadFileByteAsync(new FileUploadRequest { FileBytes = siteMapArray, ContentType = "text/plain", FileName = $"{group.Key.ToString().ToUpper()}.gz", FileUploadType = FileUploadType.SiteMap, }); } } } private async Task CreateBlogsSiteMapsAsync() { var blogs = await repositoryWrapper.SetRepository() .TableNoTracking .Select(BlogMapper.ProjectToSDto) .ToListAsync(); var groupedProducts = blogs.GroupBy(p => p.CategoryId); foreach (var group in groupedProducts) { XmlDocument doc = new XmlDocument(); XmlDeclaration documentType = doc.CreateXmlDeclaration("1.0", "utf-8", null); doc.AppendChild(documentType); //XmlNode declaration = doc.CreateNode(XmlNodeType.XmlDeclaration, "sitemap.xml", null); //doc.AppendChild(declaration); XmlElement root = doc.CreateElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9"); root.SetAttribute("xmlns:image", "http://www.google.com/schemas/sitemap-image/1.1"); //root.SetAttribute("xmlns:news", "http://www.google.com/schemas/sitemap-news/0.9"); doc.AppendChild(root); foreach (var blog in group) { XmlElement urlElement = doc.CreateElement("url", doc.DocumentElement?.NamespaceURI); root.AppendChild(urlElement); XmlElement loc = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI); string slugHtml = blog.Slug; if (slugHtml.Contains(' ')) slugHtml = WebUtility.UrlEncode(slugHtml.Replace(' ', '-')); loc.InnerText = Path.Combine($"{_siteSetting.WebSiteUrl}/blogs/{blog.Id}/{slugHtml}"); urlElement.AppendChild(loc); XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI); lastmod.InnerText = blog.ModifiedAt == DateTime.MinValue ? blog.CreatedAt.ToString("yyyy-MM-dd") : blog.ModifiedAt.ToString("yyyy-MM-dd"); urlElement.AppendChild(lastmod); XmlElement changeFeq = doc.CreateElement("changefreq", doc.DocumentElement?.NamespaceURI); changeFeq.InnerText = "daily"; urlElement.AppendChild(changeFeq); XmlElement priority = doc.CreateElement("priority", doc.DocumentElement?.NamespaceURI); priority.InnerText = "0.9"; urlElement.AppendChild(priority); //Image if (blog.MainImage != string.Empty) { XmlElement image = doc.CreateElement("image:image", "http://www.google.com/schemas/sitemap-image/1.1"); urlElement.AppendChild(image); XmlElement imageLoc = doc.CreateElement("image:loc", "http://www.google.com/schemas/sitemap-image/1.1"); var imageUrl = blog.MainImage.Contains("Med") || blog.MainImage.Contains("Thumb") ? blog.MainImage.Replace("Med", "Thumb") : Path.Combine("Images", "Med", blog.MainImage); imageLoc.InnerText = $"{_siteSetting.StorageBaseUrl}/{imageUrl}"; image.AppendChild(imageLoc); XmlElement imageCaption = doc.CreateElement("image:caption", "http://www.google.com/schemas/sitemap-image/1.1"); imageCaption.InnerText = blog.Title; image.AppendChild(imageCaption); } ////News //XmlElement news = doc.CreateElement("news:news", "http://www.google.com/schemas/sitemap-news/0.9"); //urlElement.AppendChild(news); //XmlElement newTitle = doc.CreateElement("news:title", "http://www.google.com/schemas/sitemap-news/0.9"); //newTitle.InnerText = blog.Title; //news.AppendChild(newTitle); //XmlElement newPublificationDate = doc.CreateElement("news:publication_date", "http://www.google.com/schemas/sitemap-news/0.9"); //newPublificationDate.InnerText = blog.CreatedAt.ToString("yyyy-MM-dd"); //news.AppendChild(newPublificationDate); //XmlElement newsPublification = doc.CreateElement("news:publication", "http://www.google.com/schemas/sitemap-news/0.9"); //news.AppendChild(newsPublification); //XmlElement newsPublicationName = doc.CreateElement("news:name", "http://www.google.com/schemas/sitemap-news/0.9"); //newsPublicationName.InnerText = blog.Title; //newsPublification.AppendChild(newsPublicationName); //XmlElement newsPublicationLanq = doc.CreateElement("news:language", "http://www.google.com/schemas/sitemap-news/0.9"); //newsPublicationLanq.InnerText = blog.CreatedAt.ToString("yyyy-MM-dd"); //newsPublification.AppendChild(newsPublicationLanq); } using var siteMapStream = new MemoryStream(); await using var siteMapWriter = new XmlTextWriter(siteMapStream, Encoding.UTF8); doc.WriteTo(siteMapWriter); siteMapWriter.Flush(); byte[] unZipBytes = siteMapStream.ToArray(); using (var compressedStream = new MemoryStream()) await using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) { zipStream.Write(unZipBytes, 0, unZipBytes.Length); zipStream.Close(); var siteMapArray = compressedStream.ToArray(); await uploadFileService.UploadFileByteAsync(new FileUploadRequest { FileBytes = siteMapArray, ContentType = "text/plain", FileName = $"{group.Key.ToString().ToUpper()}.gz", FileUploadType = FileUploadType.SiteMap, }); } } } private async Task CreateBlogCategoriesSiteMapsAsync() { var siteMapsUId = SiteMapUIds.BlogCategories; var blogCategories = await repositoryWrapper.SetRepository() .TableNoTracking .ToListAsync(); XmlDocument doc = new XmlDocument(); XmlDeclaration documentType = doc.CreateXmlDeclaration("1.0", "utf-8", null); doc.AppendChild(documentType); //XmlNode declaration = doc.CreateNode(XmlNodeType.XmlDeclaration, "sitemap.xml", null); //doc.AppendChild(declaration); XmlElement root = doc.CreateElement("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9"); root.SetAttribute("xmlns:image", "http://www.google.com/schemas/sitemap-image/1.1"); root.SetAttribute("xmlns:news", "http://www.google.com/schemas/sitemap-news/0.9"); doc.AppendChild(root); foreach (var blogCategory in blogCategories) { XmlElement urlElement = doc.CreateElement("url", doc.DocumentElement?.NamespaceURI); root.AppendChild(urlElement); XmlElement loc = doc.CreateElement("loc", doc.DocumentElement?.NamespaceURI); loc.InnerText = Path.Combine($"{_siteSetting.WebSiteUrl}/blogs?blogCategoryId={blogCategory.Id}"); urlElement.AppendChild(loc); XmlElement lastmod = doc.CreateElement("lastmod", doc.DocumentElement?.NamespaceURI); lastmod.InnerText = blogCategory.ModifiedAt == DateTime.MinValue ? blogCategory.CreatedAt.ToString("yyyy-MM-dd") : blogCategory.ModifiedAt.ToString("yyyy-MM-dd"); urlElement.AppendChild(lastmod); XmlElement changeFeq = doc.CreateElement("changefreq", doc.DocumentElement?.NamespaceURI); changeFeq.InnerText = "daily"; urlElement.AppendChild(changeFeq); XmlElement priority = doc.CreateElement("priority", doc.DocumentElement?.NamespaceURI); priority.InnerText = "0.9"; urlElement.AppendChild(priority); } using var siteMapStream = new MemoryStream(); await using var siteMapWriter = new XmlTextWriter(siteMapStream, Encoding.UTF8); doc.WriteTo(siteMapWriter); siteMapWriter.Flush(); byte[] unZipBytes = siteMapStream.ToArray(); using (var compressedStream = new MemoryStream()) await using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) { zipStream.Write(unZipBytes, 0, unZipBytes.Length); zipStream.Close(); var siteMapArray = compressedStream.ToArray(); await uploadFileService.UploadFileByteAsync(new FileUploadRequest { FileBytes = siteMapArray, ContentType = "text/plain", FileName = $"{siteMapsUId}.gz", FileUploadType = FileUploadType.SiteMap, }); } } }