GithubHelp home page GithubHelp logo

uhaciogullari / simplemvcsitemap Goto Github PK

View Code? Open in Web Editor NEW
127.0 11.0 39.0 906 KB

A minimalist library for creating sitemap files inside ASP.NET MVC and ASP.NET Core MVC applications

License: MIT License

C# 100.00%
sitemap-files seo asp-net-core-mvc c-sharp generating-sitemaps

simplemvcsitemap's Introduction

SimpleMvcSitemap

A minimalist library for creating sitemap files inside ASP.NET Core applications.

SimpleMvcSitemap lets you create sitemap files inside action methods without any configuration. It also supports generating sitemap index files. Since you are using regular action methods you can take advantage of caching and routing available in the framework.

Table of contents

Install the NuGet package on your MVC project.

.NET Framework

Support for .NET Framework and ASP.NET MVC has been dropped by version 4. Use version 3 if you need to support this scenario.

You can use SitemapProvider class to create sitemap files inside any action method. You don't even have to provide absolute URLs, SimpleMvcSitemap can generate them from relative URLs. Here's an example:

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));
    }
}

SitemapNode class also lets you specify the optional attributes:

new SitemapNode(Url.Action("Index", "Home"))
{
    ChangeFrequency = ChangeFrequency.Weekly,
    LastModificationDate = DateTime.UtcNow.ToLocalTime(),
    Priority = 0.8M
}

Sitemap files must have no more than 50,000 URLs and must be no larger then 50MB as stated in the protocol. If you think your sitemap file can exceed these limits you should create a sitemap index file. If you have a logical seperation, you can create an index manually.

List<SitemapIndexNode> sitemapIndexNodes = new List<SitemapIndexNode>
{
   new SitemapIndexNode(Url.Action("Categories","Sitemap")),
   new SitemapIndexNode(Url.Action("Products","Sitemap"))
};

return new SitemapProvider().CreateSitemapIndex(new SitemapIndexModel(sitemapIndexNodes));

If you are dealing with dynamic data and you are retrieving the data using a LINQ provider, SimpleMvcSitemap can handle the paging for you. A regular sitemap will be created if you don't have more nodes than the sitemap size.

Generating sitemap index files

This requires a little configuration:

public class ProductSitemapIndexConfiguration : SitemapIndexConfiguration<Product>
{
    private readonly IUrlHelper urlHelper;

    public ProductSitemapIndexConfiguration(IQueryable<Product> dataSource, int? currentPage, IUrlHelper urlHelper)
        : base(dataSource,currentPage)
    {
        this.urlHelper = urlHelper;
    }

    public override SitemapIndexNode CreateSitemapIndexNode(int currentPage)
    {
        return new SitemapIndexNode(urlHelper.RouteUrl("ProductSitemap", new { currentPage }));
    }

    public override SitemapNode CreateNode(Product source)
    {
        return new SitemapNode(urlHelper.RouteUrl("Product", new { id = source.Id }));
    }
}

Then you can create the sitemap file or the index file within a single action method.

public ActionResult Products(int? currentPage)
{
    var dataSource = products.Where(item => item.Status == ProductStatus.Active);
    var productSitemapIndexConfiguration = new ProductSitemapIndexConfiguration(dataSource, currentPage, Url);
    return new DynamicSitemapIndexProvider().CreateSitemapIndex(new SitemapProvider(), productSitemapIndexConfiguration);
}

You should convert your DateTime values to local time. Universal time format generated by .NET is not accepted by Google. You can use .ToLocalTime() method to do the conversion.

You can use Google's sitemap extensions to provide detailed information about specific content types like images, videos, news or alternate language pages. You can still use relative URLs for any of the additional URLs.

using SimpleMvcSitemap.Images;

new SitemapNode(Url.Action("Display", "Product"))
{
    Images = new List<SitemapImage>
    {
        new SitemapImage(Url.Action("Image","Product", new {id = 1})),
        new SitemapImage(Url.Action("Image","Product", new {id = 2}))
    }
}

By version 4, multiple videos are supported. Start using Videos property if you are upgrading from v3 to v4.

using SimpleMvcSitemap.Videos;

new SitemapNode("http://www.example.com/videos/some_video_landing_page.html")
{
    Videos = new List<SitemapVideo>
    { 
        new SitemapVideo(title: "Grilling steaks for summer",
                         description: "Alkis shows you how to get perfectly done steaks every time",
                         thumbnailUrl: "http://www.example.com/thumbs/123.jpg", 
                         contentUrl: "http://www.example.com/video123.flv")
    }
}
using SimpleMvcSitemap.News;

new SitemapNode("http://www.example.org/business/article55.html")
{
    News = new SitemapNews(newsPublication: new NewsPublication(name: "The Example Times", language: "en"),
                           publicationDate: new DateTime(2014, 11, 5, 0, 0, 0, DateTimeKind.Utc),
                           title: "Companies A, B in Merger Talks")
}
using SimpleMvcSitemap.Translations;

new SitemapNode("abc")
{
    Translations = new List<SitemapPageTranslation>
    {
        new SitemapPageTranslation("http://www.example.com/deutsch/", "de"),
		new SitemapPageTranslation("http://www.example.com/english/", "en")
    }
}

SimpleMvcSitemap supports XSL style sheets by version 3. Keep in mind that XML stylesheets are subjected to the same origin checks.

using SimpleMvcSitemap.StyleSheets;

new SitemapModel(new List<SitemapNode> { new SitemapNode("abc") })
{
    StyleSheets = new List<XmlStyleSheet>
    {
        new XmlStyleSheet("/sitemap.xsl")
    }
};

You can see how you can utilize multiple XSL style sheets in this tutorial.

SimpleMvcSitemap can generate absolute URLs from the relative URLs using the HTTP request context. If you want to customize this behaviour, you can implement IBaseUrlProvider interface and pass it to the SitemapProvider class.

public class BaseUrlProvider : IBaseUrlProvider
{
    public Uri BaseUrl => new Uri("http://example.com");
}

var sitemapProvider = new SitemapProvider(new BaseUrlProvider());

SitemapProvider class implements the ISitemapProvider interface which can be injected to your controllers and be replaced with test doubles. All methods are thread safe so they can be used with singleton life cycle.

public class SitemapController : Controller
{
    private readonly ISitemapProvider _sitemapProvider;

    public SitemapController(ISitemapProvider sitemapProvider)
    {
        _sitemapProvider = sitemapProvider;
    }
	
    //action methods
}

SimpleMvcSitemap is licensed under MIT License. Refer to license file for more information.

simplemvcsitemap's People

Contributors

bitdeli-chef avatar bugthesystem avatar humanbeinc avatar uhaciogullari avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

simplemvcsitemap's Issues

Date/timeformat is incorrect

Hello Ufuk,

The date/timeformat for the "lastmod"-tag is incorrect.
The current implementation outputs "2019-11-15T09:40:00".
This should be a date "2019-11-15" or a datetime with a timezone "2019-11-15T09:40:00Z".
The timezone (in the example the "Z") is missing in the current version of the package!

Also take a look at these webpages:
https://www.w3.org/TR/NOTE-datetime
https://www.sitemaps.org/protocol.html

Can you fix this in the next version?

Kind regards,
Leon

DateMod is always in invalid format, should never include time

The node's LastModificationDate is a DateTime value. Whenever I feed in a DateTime it renders the datetime quite literally in the sitemap which make the sitemap invalid. It should only include year, month, date, but you will notice that it has "T*".

Can you please fix this bug?

SitemapNode with empty url creates invalid sitemap markup

I'm dynamically adding nodes from my menu provider

foreach (var menuItem in menu.Items)
{
    nodes.AddRange(GetAllChildren(menuItem, c => c.Items).Select(x => new SitemapNode(x.Url)));
}

And it happened I added menu item placeholder without an url, this resulted in invalid sitemap because absence of url renders invalid tag.

I had to add extra check to make sure that doesn't happen from my code.

.Where(x => !string.IsNullOrWhiteSpace(x?.Url))

It might be a good idea to add check that prevents rendering of SitemapNode when url is empty to prevent invalid sitemap scenario.

Output format of LastModificationDate is incorrect.

Hi,

I found that the lastmod format is like this:

<lastmod>2017-10-25T00:00:00</lastmod>

Google search console said this format is incorrect. The correct format need to be W3C Datetime. Witch can find here

https://www.w3.org/TR/NOTE-datetime

The example date format:

1994-11-05T13:15:30Z

So need to add 'Z' at the end of output?

Remove xmlns:i attribute from the root element

<urlset xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

DataContractSerializer creates this attribute by default and I couldn't find a way to remove it. Google does not show any issues but it would be better if we can just remove it.

Display Error in IIS

When i build project in vs2013,it works correct。but when i deploy project in IIS6,all the sitemaps display like '_HOME_Index_GET_NMS'。

How to specify keywords and genres in Sitemap.News?

Hi @uhaciogullari

First, thanks for a great library.
I am doing something like below to create a Google News Sitemap but I don't know the syntax for adding Keywords and Genres to the sitemap as the constructor does not take these two arguments.
Can you help?

    List<SitemapNode> nodes = new List<SitemapNode>();
    var data = await GetDataAsync().ConfigureAwait(false); // get data from database.

    foreach (var item in data)
    {
        nodes.Add(
            new SitemapNode(item.Url)
            {
                News = new SitemapNews(
                        newsPublication: new NewsPublication(name: "mysite", language: "en"),
                        publicationDate: DateTime.SpecifyKind(item.PublishTime, DateTimeKind.Utc),
                        title: item.HeadLine
                        <keywords here>
                         <genres here>
                        )
            }
        );
    }

ASP.NET Core using .NET Framework use wrong dlls

Hi,

I downloaded version 3.1 using nuget. I have project ASP.Net Core v2 using .NET Framework 4.7. After including SimpleMvcSitemap I am getting error because new SitemapProvider().CreateSitemap(new SitemapModel(nodes)); returns System.Web.Mvc.ActionResult instead of Microsoft.AspNetCore.Mvc.IActionResult.

I have to download source code for now and remove Mvc #ifs

Not generating xsi:schemaLocation= or xmlns= attributes!

Hi! Thanks for your very useful tool, but I have a little problem!

My sitemap gets generated without any attributes on the url element. You can see it here generated in real time.

The cose I used:

[Route(template: "sitemap.xml")]
public IActionResult SitemapXml()
{
    var routes = _routesInspector.AllRoutes;
    var nodes = new List<SitemapNode>();
    foreach (var section in routes)
    {
        foreach (var route in section.Value)
        {
            nodes.Add(new SitemapNode(Url.Content(route.Url)));
        }
    }

    return new SitemapProvider().CreateSitemap(new SitemapModel(nodes));
}

Do I missed something?
I noticed it because Google Search Console says it cannot read it!

Thanks.

How to add odd, urls to sitemap when using Dynamic Sitemap Index method

We have a large number of CMS driven URL's that we're using the Dynamic Sitemap Index method to generate the sitemaps for.

We also have a handful of additional URLs that are only present in the MVC app and we need to also include these in the sitemap.

Is there an example of how to add these extra URLs in when using the dynamic method?

Sitemap LastMod property serialized in an incorrect format

Google's webmasters tools is throwing several errors on the LastMod property, "An invalid date was found. Please fix the date or formatting before resubmitting". Upon inspection, as per sitemaps.org, the date must be in a W3C format.

I believe a minor update in SitemapNode.cs such as the following should do the trick (PS: not tested):

        /// <summary>
        /// Shows the date the URL was last modified, value is optional.
        /// </summary>
        [XmlElement("lastmod", Order = 2)]
        public string LastModificationDateW3C
        {
            get
            {
                if (this.LastModificationDate != null)
                {
                    return XmlConvert.ToString((DateTime)this.LastModificationDate);
                }
                return null;
            }
        }
        /// <summary>
        /// The date the URL was last modified
        /// </summary>
        public DateTime? LastModificationDate { get; set; }

not working on large sitemap .net core 3.1

just test out SimpleMvcSitemap.
it work fine on sitemap size around 50 urls+ however
when i want to use it to generate 50k urls i found out that if sitemap has larger than 1000+ urls
will get xml error "error on line 1 at column 65697: Opening and ending tag mismatch: lastmourl line 0 and url"

README.md error

The code example under Sitemap Index Files has an error.
return new SitemapProvider().CreateSitemap(new SitemapIndexModel(sitemapIndexNodes));

should be:
return new SitemapProvider().CreateSitemapIndex(new SitemapIndexModel(sitemapIndexNodes));

multiple dynamic sitemap provider

Let say i have multiple dynamic data i want to put in the sitemap ( let say multiple tables).
I created multiple SitemapIndexConfiguration for each type.
Is there a way i can merge them for SitemapIndexNode?
Can you provide an example if yes?

thanks.

Wrong datetime output format?

When having Google crawl the sitemap.xml which lives at my domain's root, I get back invalid date for each entry.

This is what I'm creating, but is this a valid date?
2019-10-16T09:56:15.9800168Z

If not, how can I modify it to something that's acceptable?

No option to gzip the result

I tried slapping a Compress attribute on the ActionResult as described here:

https://stackoverflow.com/questions/3802107/how-to-gzip-content-in-asp-net-mvc

But it's not working. I've tried using OnActionExecuting, OnActionExecuted, OnResultExecuting, and OnResultExecuted. OnResultExecuted doesn't work because the headers have already been sent. The other three, chrome gives an ERR_CONTENT_DECODING_FAILED error.

I see that on this page https://github.com/uhaciogullari/SimpleMvcSitemap/blob/40aed73035fde5aad59b3104f4349b62741de8d9/src/SimpleMvcSitemap/XmlResult.cs

you've got an ExecuteResult method which generates the XML. https://stackoverflow.com/questions/37356389/asp-net-mvc-executeresult-vs-actionresult

Anyway, it would be very awesome if you could put in an option to gzip this result.

Thanks Ufuk, your library is really elegant and awesome!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.