maartenba / MvcSiteMapProvider

An ASP.NET MVC SiteMapProvider implementation for the ASP.NET MVC framework.
Microsoft Public License
537 stars 220 forks source link

The SiteMapLoader has not been initialized. #435

Open ElTamero opened 8 years ago

ElTamero commented 8 years ago

Hi I just followed the instructions for configuring the External DI for sitemap in the link below: https://github.com/maartenba/MvcSiteMapProvider/wiki/Configuring-MvcSiteMapProvider

and I'm using asp.net MVC 5 .net 4.6 and installed the latest package for mvc and I received this error

**The SiteMapLoader has not been initialized.

Check the 'MvcSiteMapProvider_UseExternalDIContainer' setting in the AppSettings section of web.config.

If the setting is set to 'false', you will need to call the MvcSiteMapProvider.DI.Composer.Compose() method at the end of Application_Start in the Global.asax file. Alternatively, if you are using .NET 4.0 or higher you can install the MvcSiteMapProvider.MVCx NuGet package corresponding to your MVC version.

If the setting is set to 'true', you must set the SiteMaps.Loader property during Application_Start in Global.asax to an instance of the built-in SiteMapLoader type or a custom ISiteMapLoader instance. This can be achieved most easily by using your external DI container.**

another thing I followed before the instructions for localized sitemap but it can't find the object in the recource file and I'm sure that it's included in the code and quite sure the syntax of the namespace and class file . I hope to get a reply because i believe this is an awesome package for sitemap

one last thing . i tried to access sitemap.xml when external DI is disabled and using sitemap file enabled in web.config is doesn't show and it redirects to my home page

NightOwl888 commented 8 years ago

Check out #221, this question is a duplicate.

Which package did you install?

The page you are referring to is just a reference to get you up to speed on DI, it does not have complete instructions to assist you with setting up a project for DI manually. There are NuGet packages to give you a starting point for several containers. There are 2 types of packages:

Dependency Injection Configuration Packages

If your project does not already use Dependency Injection, you can use one of these packages to install a composition root into your application that contains all of the startup code necessary to "just work" after installation.

PM> Install-Package MvcSiteMapProvider.MVC[x].DI.[containerName]

Replace the x with your MVC version and the containerName with the container that you are using.

Modules Packages

If you already are using DI in your project or prefer to use a composition root provided by one of the DI container integrations, you can just add the module and then manually add it to your DI container's configuration by following the steps in the README within the package.

PM> Install-Package MvcSiteMapProvider.MVC[x].DI.[containerName].Modules

Replace the x with your MVC version and the containerName with the container that you are using.

Here are those instructions for each container.


Since NuGet installs the lowest dependency versions by default and doesn't always seem to install the entire dependency chain, it is recommended that you install 3 packages in the following order:

  1. MvcSiteMapProvider.Web
  2. MvcSiteMapProvider.MVC5
  3. One of the DI configuration or modules packages.
ElTamero commented 8 years ago

Thanks alot . I passed the article you posted before and i downloaded the demo and thought it's just to post the code . I installed the package and it works fine . but here is an issue I would like to make the sitemap.xml exists for arabic and english pages based on localization url routing http://localhost/ar and http://localhost/en and i want to create two sitemap.xml one for arabic and have 'ar' as culture paramter for each link and one have 'en' culture parameter for each . if I type localhost/sitemap.xml it doesn't show up at all . so should i create controller for sitemap.xml ? and I appreciate yout tips to create these two sitemaps . Thanks

NightOwl888 commented 8 years ago

You just need to remove the code that registers the routes for the XmlSiteMapController and create your own routes.

// Register the Sitemaps routes for search engines
// XmlSiteMapController.RegisterRoutes(RouteTable.Routes);

RouteConfig.cs

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "SiteMap-Localized",
                url: "{culture}/sitemap.xml",
                defaults: new { controller = "XmlSiteMap", action = "Index", page = 0 },
                constraints: new { culture = new CultureConstraint(defaultCulture: "en", pattern: "[a-z]{2}") }
            );

            routes.MapRoute(
                name: "SiteMap",
                url: "sitemap.xml",
                defaults: new { controller = "XmlSiteMap", action = "Index", page = 0 }
            );

            routes.MapRoute(
                name: "SiteMap-Paged-Localized",
                url: "{culture}/sitemap-{page}.xml",
                defaults: new { controller = "XmlSiteMap", action = "Index", page = 0 },
                constraints: new { culture = new CultureConstraint(defaultCulture: "en", pattern: "[a-z]{2}") }
            );

            routes.MapRoute(
                name: "SiteMap-Paged",
                url: "sitemap-{page}.xml",
                defaults: new { controller = "XmlSiteMap", action = "Index", page = 0 }
            );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }

Refer to this answer for the implementation of CultureConstraint and some other useful info about localization in MVC.

If you keep the default behavior of using App_GlobalResources for your localization, make sure you follow this post. Alternatively, you can move the resources elsewhere by implementing IStringLocalizer or by creating your own resource provider.

Refer to How to: Localize Site-Map Data for how to format the localization tags. Note that the only thing that differs from this documentation is how to enable/disable localization (which is done at the top of the DI module).

You could alternatively use separate SiteMap instances for each culture, but it would take up a lot more RAM if you did it that way and you would need to create a custom controller for the sitemap.xml.

    [AllowAnonymous]
    public class LocalizedXmlSiteMapController
        : Controller
    {
        public LocalizedXmlSiteMapController(
            IXmlSiteMapResultFactory xmlSiteMapResultFactory
            )
        {
            if (xmlSiteMapResultFactory == null)
                throw new ArgumentNullException("xmlSiteMapResultFactory");
            this.xmlSiteMapResultFactory = xmlSiteMapResultFactory;
        }

        private readonly IXmlSiteMapResultFactory xmlSiteMapResultFactory;

        public ActionResult Index(int page = 0, string culture)
        {
            string siteMapCacheKey = "EnglishSiteMap";
            if (culture.Equals("ar", StringComparison.OrdinalIgnoreCase))
            {
                siteMapCacheKey = "ArabicSiteMap";
            }

            return xmlSiteMapResultFactory.Create(page, new string[] { siteMapCacheKey });
        }
    }

Do note that if you do it that way, you have the option to merge all of the nodes for all of your SiteMap instances into the same sitemap.xml endpoint, so you wouldn't need localized routing.

Be sure you are aware of the limitation of the sitemap protocol in that you may not include anything for pages that exist outside of the virtual path the sitemap.xml exists in.