Skip to content

Commit c5986d5

Browse files
authored
Merge pull request #35 from ernado-x/33-bug-nullref-in-savetodirectory
2 parents 7285ffb + 4bac9a9 commit c5986d5

22 files changed

+276
-216
lines changed

X.Web.Sitemap.sln

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "X.Web.Sitemap.Tests", "test
1111
EndProject
1212
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "X.Web.Sitemap", "src\X.Web.Sitemap\X.Web.Sitemap.csproj", "{704FA5E2-2694-44C9-826E-85C2CEC96D5D}"
1313
EndProject
14-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "X.Web.Sitemap.Examples", "src\X.Web.Sitemap.Examples\X.Web.Sitemap.Examples.csproj", "{EA29E3A8-D073-4517-BE60-B39AA3D089AF}"
14+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "X.Web.Sitemap.Example", "src\X.Web.Sitemap.Example\X.Web.Sitemap.Example.csproj", "{97B9B296-63C0-4816-AD53-E069E6BDEF66}"
1515
EndProject
1616
Global
1717
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -27,17 +27,17 @@ Global
2727
{704FA5E2-2694-44C9-826E-85C2CEC96D5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
2828
{704FA5E2-2694-44C9-826E-85C2CEC96D5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
2929
{704FA5E2-2694-44C9-826E-85C2CEC96D5D}.Release|Any CPU.Build.0 = Release|Any CPU
30-
{EA29E3A8-D073-4517-BE60-B39AA3D089AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31-
{EA29E3A8-D073-4517-BE60-B39AA3D089AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
32-
{EA29E3A8-D073-4517-BE60-B39AA3D089AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
33-
{EA29E3A8-D073-4517-BE60-B39AA3D089AF}.Release|Any CPU.Build.0 = Release|Any CPU
30+
{97B9B296-63C0-4816-AD53-E069E6BDEF66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31+
{97B9B296-63C0-4816-AD53-E069E6BDEF66}.Debug|Any CPU.Build.0 = Debug|Any CPU
32+
{97B9B296-63C0-4816-AD53-E069E6BDEF66}.Release|Any CPU.ActiveCfg = Release|Any CPU
33+
{97B9B296-63C0-4816-AD53-E069E6BDEF66}.Release|Any CPU.Build.0 = Release|Any CPU
3434
EndGlobalSection
3535
GlobalSection(SolutionProperties) = preSolution
3636
HideSolutionNode = FALSE
3737
EndGlobalSection
3838
GlobalSection(NestedProjects) = preSolution
3939
{5AA327E0-C63F-4567-9C09-23707EB5E4C4} = {5662CFB2-6193-4FB8-BBA3-B5822FDB583F}
4040
{704FA5E2-2694-44C9-826E-85C2CEC96D5D} = {DD3DEEE0-ABF3-4DFB-A5A9-14AA3FB1DBA2}
41-
{EA29E3A8-D073-4517-BE60-B39AA3D089AF} = {DD3DEEE0-ABF3-4DFB-A5A9-14AA3FB1DBA2}
41+
{97B9B296-63C0-4816-AD53-E069E6BDEF66} = {DD3DEEE0-ABF3-4DFB-A5A9-14AA3FB1DBA2}
4242
EndGlobalSection
4343
EndGlobal

src/X.Web.Sitemap.Example/IExample.cs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace X.Web.Sitemap.Example;
2+
3+
public interface IExample
4+
{
5+
void Run();
6+
}

src/X.Web.Sitemap.Example/Program.cs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using X.Web.Sitemap.Example;
2+
3+
Console.WriteLine("OK");
4+
5+
IExample example1 = new SitemapGenerationWithSitemapIndexExample();
6+
example1.Run();
7+
8+
9+
IExample example2 = new SimpleSitemapGenerationExample();
10+
example2.Run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace X.Web.Sitemap.Example;
2+
3+
public class SimpleSitemapGenerationExample : IExample
4+
{
5+
public void Run()
6+
{
7+
// Pick a place where you would like to write the sitemap files in that folder will get overwritten by new ones
8+
var directory = Path.Combine(Path.GetTempPath(), "XWebsiteExample");
9+
10+
var urlGenerator = new UrlGenerator();
11+
12+
// Get list of website urls
13+
var allUrls = urlGenerator.GetUrls("mywebsite.com");
14+
15+
var sitemap = new Sitemap(allUrls);
16+
17+
sitemap.SaveToDirectory(directory);
18+
}
19+
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
namespace X.Web.Sitemap.Example;
2+
3+
/// <summary>
4+
/// This is an example showing how you might take a large list of URLs of different kinds of resources and build
5+
/// both a bunch of sitemaps (depending on how many URls you have) as well as a sitemap index file to go with it
6+
/// </summary>
7+
public class SitemapGenerationWithSitemapIndexExample : IExample
8+
{
9+
public void Run()
10+
{
11+
// Pick a place where you would like to write the sitemap files in that folder will get overwritten by new ones
12+
var targetSitemapDirectory = Path.Combine(Path.GetTempPath(), "XWebsiteExample");
13+
14+
// Pick a place where sitemaps will be accessible from internet
15+
var sitemapRootUrl = "https://www.mywebsite.com/sitemaps/";
16+
17+
var sitemapGenerator = new SitemapGenerator();
18+
var sitemapIndexGenerator = new SitemapIndexGenerator();
19+
var urlGenerator = new UrlGenerator();
20+
21+
// Get list of website urls
22+
var allUrls = urlGenerator.GetUrls("mywebsite.com");
23+
24+
25+
// generate one or more sitemaps (depending on the number of URLs) in the designated location.
26+
var fileInfoForGeneratedSitemaps = sitemapGenerator.GenerateSitemaps(allUrls, targetSitemapDirectory);
27+
28+
var sitemapInfos = new List<SitemapInfo>();
29+
var dateSitemapWasUpdated = DateTime.UtcNow.Date;
30+
31+
foreach (var fileInfo in fileInfoForGeneratedSitemaps)
32+
{
33+
// It's up to you to figure out what the URI is to the sitemap you wrote to the file sytsem.
34+
// In this case we are assuming that the directory above has files exposed
35+
// via the /sitemaps/ subfolder of www.mywebsite.com
36+
37+
var uriToSitemap = new Uri($"{sitemapRootUrl}{fileInfo.Name}");
38+
39+
sitemapInfos.Add(new SitemapInfo(uriToSitemap, dateSitemapWasUpdated));
40+
}
41+
42+
// Now generate the sitemap index file which has a reference to all of the sitemaps that were generated.
43+
sitemapIndexGenerator.GenerateSitemapIndex(sitemapInfos, targetSitemapDirectory, "sitemap-index.xml");
44+
45+
// After this runs you'll want to make sure your robots.txt has a reference to the sitemap index (at the bottom of robots.txt) like this:
46+
// "Sitemap: https://www.mywebsite.com/sitemaps/sitemap-index.xml"
47+
// You could do this manually (since this may never change) or if you are ultra-fancy, you could dynamically update your robots.txt with the names of the sitemap index
48+
// file(s) you generated
49+
}
50+
}
+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
namespace X.Web.Sitemap.Example;
2+
3+
public class UrlGenerator
4+
{
5+
public List<Url> GetUrls(string domain)
6+
{
7+
var productPageUrlStrings = GetHighPriorityProductPageUrls(domain);
8+
9+
//--build a list of X.Web.Sitemap.Url objects and determine what is the appropriate ChangeFrequency, TimeStamp (aka "LastMod" or date that the resource last had changes),
10+
// and the a priority for the page. If you can build in some logic to prioritize your pages then you are more sophisticated than most! :)
11+
var allUrls = productPageUrlStrings.Select(url => new Url
12+
{
13+
//--assign the location of the HTTP request -- e.g.: https://www.somesite.com/some-resource
14+
Location = url,
15+
//--let's instruct crawlers to crawl these pages monthly since the content doesn't change that much
16+
ChangeFrequency = ChangeFrequency.Monthly,
17+
//--in this case we don't know when the page was last modified so we wouldn't really set this. Only assigning here to demonstrate that the property exists.
18+
// if your system is smart enough to know when a page was last modified then that is the best case scenario
19+
TimeStamp = DateTime.UtcNow,
20+
//--set this to between 0 and 1. This should only be used as a relative ranking of other pages in your site so that search engines know which result to prioritize
21+
// in SERPS if multiple pages look pertinent from your site. Since product pages are really important to us, we'll make them a .9
22+
Priority = .9
23+
}).ToList();
24+
25+
var miscellaneousLowPriorityUrlStrings = GetMiscellaneousLowPriorityUrls(domain);
26+
27+
var miscellaneousLowPriorityUrls = miscellaneousLowPriorityUrlStrings.Select(url => new Url
28+
{
29+
Location = url,
30+
//--let's instruct crawlers to crawl these pages yearly since the content almost never changes
31+
ChangeFrequency = ChangeFrequency.Yearly,
32+
//--let's pretend this content was changed a year ago
33+
TimeStamp = DateTime.UtcNow.AddYears(-1),
34+
//--these pages are super low priority
35+
Priority = .1
36+
}).ToList();
37+
38+
//--combine the urls into one big list. These could of course bet kept seperate and two different sitemap index files could be generated if we wanted
39+
allUrls.AddRange(miscellaneousLowPriorityUrls);
40+
41+
return allUrls;
42+
}
43+
44+
private IReadOnlyCollection<string> GetMiscellaneousLowPriorityUrls(string domain)
45+
{
46+
var result = new List<string>();
47+
48+
for (int i = 0; i < 40000; i++)
49+
{
50+
result.Add($"https://{domain}/page/{i}.html");
51+
}
52+
53+
return result;
54+
}
55+
56+
private IReadOnlyCollection<string> GetHighPriorityProductPageUrls(string domain)
57+
{
58+
var result = new List<string>();
59+
60+
for (int i = 0; i < 10000; i++)
61+
{
62+
result.Add($"https://{domain}/priority-page/{i}.html");
63+
}
64+
65+
return result;
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<ProjectReference Include="..\X.Web.Sitemap\X.Web.Sitemap.csproj" />
12+
</ItemGroup>
13+
14+
</Project>

src/X.Web.Sitemap.Examples/SitemapGenerationWithSitemapIndexExample.cs

-101
This file was deleted.

src/X.Web.Sitemap.Examples/X.Web.Sitemap.Examples.csproj

-12
This file was deleted.

src/X.Web.Sitemap/FileSystemWrapper.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using System.IO;
1+
using System.IO;
32
using System.Threading.Tasks;
43

54
namespace X.Web.Sitemap;

src/X.Web.Sitemap/ISitemap.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Threading.Tasks;
34
using JetBrains.Annotations;
45

@@ -11,7 +12,8 @@ public interface ISitemap : IList<Url>
1112

1213
Task<bool> SaveAsync(string path);
1314

14-
bool SaveToDirectory(string directory);
15+
[Obsolete("This method will be removed in future version. Use SitemapGenerator instead")]
16+
bool SaveToDirectory(string targetSitemapDirectory);
1517

1618
string ToXml();
1719
}

src/X.Web.Sitemap/ISitemapGenerator.cs

+26-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,31 @@ public interface ISitemapGenerator
2727
/// files with names like products-001.xml, products-002.xml, etc.
2828
/// </param>
2929
List<FileInfo> GenerateSitemaps(
30-
List<Url> urls,
31-
DirectoryInfo targetDirectory,
30+
IEnumerable<Url> urls,
31+
DirectoryInfo targetDirectory,
32+
string sitemapBaseFileNameWithoutExtension = "sitemap");
33+
34+
/// <summary>
35+
/// Creates one or more sitemaps based on the number of Urls passed in. As of 2016, the maximum number of
36+
/// urls per sitemap is 50,000 and the maximum file size is 50MB. See https://www.sitemaps.org/protocol.html
37+
/// for current standards. Filenames will be sitemap-001.xml, sitemap-002.xml, etc.
38+
/// Returns a list of FileInfo objects for each sitemap that was created (e.g. for subsequent use in generating
39+
/// a sitemap index file)
40+
/// </summary>
41+
/// <param name="urls">
42+
/// Urls to include in the sitemap(s). If the number of Urls exceeds 50,000 or the file size exceeds 50MB,
43+
/// then multiple files
44+
/// will be generated and multiple SitemapInfo objects will be returned.
45+
/// </param>
46+
/// <param name="targetDirectory">
47+
/// The directory where the sitemap(s) will be saved.
48+
/// </param>
49+
/// <param name="sitemapBaseFileNameWithoutExtension">
50+
/// The base file name of the sitemap. For example, if you pick 'products' then it will generate
51+
/// files with names like products-001.xml, products-002.xml, etc.
52+
/// </param>
53+
List<FileInfo> GenerateSitemaps(
54+
IEnumerable<Url> urls,
55+
string targetDirectory,
3256
string sitemapBaseFileNameWithoutExtension = "sitemap");
3357
}

0 commit comments

Comments
 (0)