This is a migrated thread and some comments may be shown as answers.

[Solved] You must have SiteMap defined with key "*" in ViewData dictionary.

18 Answers 475 Views
Menu
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Gabriela Soares
Top achievements
Rank 1
Gabriela Soares asked on 18 Jan 2010, 01:46 AM
Hi!

For some reason, I cannot seem to get menu binding with sitemap to work... Can you please help me?

Here's my Web.sitemap:
<?xml version="1.0" encoding="utf-8" ?> 
<siteMap> 
  <siteMapNode title="Home" controller="Home" action=""
  </siteMapNode> 
</siteMap> 

And, in my Site.master, i have:

            <%  
                
                Html.Telerik().Menu() 
                    .Name("Home") 
                    .BindTo("Web") 
                    .Render();  
            %> 

in my HomeController I have:

        [PopulateSiteMap(SiteMapName = "Web"ViewDataKey = "Web")] 
 
 
        public ActionResult SiteMapBinding() 
        { 
            if (!SiteMapManager.SiteMaps.ContainsKey("Web")) 
            { 
                SiteMapManager.SiteMaps.Register<XmlSiteMap>("Web", sitmap => sitmap.LoadFrom("~/Web.sitemap")); 
            } 
            return View(); 
        } 

And it stills gives me this error:

You must have SiteMap defined with key "Web" in ViewData dictionary.

What am I doing wrong?

Thank you



18 Answers, 1 is accepted

Sort by
0
Georgi Krustev
Telerik team
answered on 19 Jan 2010, 09:00 AM
Hello Gabriela,

I was not able to reproduce the depicted issue. In my attempt to replicate the problem, I have created a test project and bind menu to sitemap.

 I have attach it to this message.

Please review it and let me know if I am missing something.

Sincerely yours,
Georgi Krustev
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
0
Tom Dahlberg
Top achievements
Rank 1
answered on 27 Jan 2010, 08:19 PM
I am having the exact same problem.  Driving me crazy...
0
Georgi Krustev
Telerik team
answered on 28 Jan 2010, 08:09 AM
Hi Tom,

Could you please review the test project attached to my previous message?
Let me know what the differences are.

All the best,
Georgi Krustev
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
0
David
Top achievements
Rank 1
answered on 10 Feb 2010, 09:29 AM
I am having the same issue using MVC 2 RC 2 with Telerik MVC 2009.3.1320.235

To aid debugging this issue I removed the [PopulateSiteMap] attribute from the controller action and just added the SiteBase to ViewData within the action:
public ActionResult Index()  
        {  
             
            SiteMapManager.SiteMaps.Register<XmlSiteMap>("Web", sitemap => sitemap.LoadFrom("~/user.sitemap"));  
 
            var siteMap = SiteMapManager.SiteMaps["Web"];  
            ViewData["Web"] = siteMap;  
            return View();  
        } 

 

In my Index.ascx file I set a breakpoint in the inline server code that renders the menu and via the VS 2008 debugger I can see that ViewData has a key called Web with a value set to the relevant SiteBase


<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> 
 
<%  
    Html.Telerik().Menu()  
        .Name("Home")  
        .BindTo("Web")  
        .Render();   
            %> 

 

An exception is thrown

NotSupportedException: You must have SiteMap defined with key "Web" in ViewData dictionary.]  
   Telerik.Web.Mvc.UI.NavigationItemContainerExtensions.BindTo(INavigationItemContainer`1 component, String sitemapViewDataKey, ViewContext viewContext, Action`2 siteMapAction) +403  
   Telerik.Web.Mvc.UI.MenuBuilder.BindTo(String viewDataKey) +45  
   ASP.views_mainmenu_index_ascx.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in m:\users\david\Visual Studio 2008\Projects\TimeManagementSystem\FuelCardOptimiser\Views\MainMenu\Index.ascx:4  
   System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256  
   System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19  
   System.Web.UI.Control.Render(HtmlTextWriter writer) +10  
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27  
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99  
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25  
   System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134  
   System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19  
   System.Web.UI.Page.Render(HtmlTextWriter writer) +29  
   System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +59  
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27  
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99  
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25  
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1266  
 

Regards

David

0
Georgi Krustev
Telerik team
answered on 15 Feb 2010, 08:56 AM
Hello David,

In a first look the code snippets that you provide look correct. Unfortunately it is hard to understand where could be the problem without a running test project which reproduces the depicted issue.
Could you please review my test project attached to one of my previous messages? Let me know if there are some differences in the implementation or in the structure of the sitemap.

Regards,
Georgi Krustev
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
Daniel Collier
Top achievements
Rank 1
answered on 15 Mar 2010, 04:26 PM
I had the same error.  I downloaded the telerik sample and saw that it works.  I also was able to create my own sample.  It seems the key for me is that you have to put the attribute over the controller method being called, not just the sitemapbinding method, which makes sense.  It would be nice to be able to do this in one global area since we are loading a sitewide menu.  Having to put this attribute above method above every controller method would be crazy and be a showstopper for making this a practical solution.

I read a thread that mentions doing this globally, by adding the code to the global.asax, then adding the attribute to all controllers.  We have a lot of controllers and the maintenance of this solution (having the code on every controller class) makes this approach a nonstarter for me.  Anybody have a better solution?  I think I'm gonna go with feeding the menu an ienumerable or something.
0
Georgi Krustev
Telerik team
answered on 18 Mar 2010, 11:14 AM
Hello Daniel,

Thank you for your feedback.

I will forward this thread to our developers for further discussion. If we are able to find better solution, we definitely will implement it.

Kind regards,
Georgi Krustev
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
ls
Top achievements
Rank 1
answered on 20 Mar 2010, 10:32 AM

Tried to make a base controller class and then inherit the class on every other controller.
This works well for setting ViewData[].   This didn't work for the Telerik MVC menu.

NullReference Exception was unhandled by user code.  (Object reference not set to an instance of an object.)

The Telerik menu for Webforms was so great and easy to use!  It's too bad that you couldn't use the same xml files as a datasource in MVC!

0
Georgi Krustev
Telerik team
answered on 25 Mar 2010, 09:16 AM
Hello Mike,

I suppose that the exception is thrown by the "GetAuthorizeAttributes" method. This is part of the validation process, where the BindTo method checks whether the provided Controller and Action names are correct.
Please verify that your sitemap is correctly constructed.

Nevertheless we implement additional feature to our navigation components - rather than apply PopulateSitemapAttribute to every controller, you just can register the sitemap in the Global.asax with SiteMapManager (as we do in our examples) and then give the name of the sitemap to the BindTo method.

This feature will be included in next release of Telerik Components for ASP.NET MVC.

Currently the work around of the need to add attribute to every controller is to make base controller and all others to inherit it. I have attached test project which shows what I mean.

Sincerely yours,
Georgi Krustev
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
ls
Top achievements
Rank 1
answered on 30 Mar 2010, 05:59 PM
Hi Georgi,

Will definitely wait for the next release of Telerik Components for MVC.   That is a huge feature.

I'm hoping that I can define mulitple sitemaps in Global.asax.   Then based on a session variable chose the correct name of the sitemap in the BindTo method.

Will you be releasing the next Telerik Components for MVC with Visual Studio 2010?

Thanks,

Mike
0
Georgi Krustev
Telerik team
answered on 31 Mar 2010, 09:13 AM
Hello Mike,

Use SiteMapManager to register multiple sitemaps with unique names. With the new release of Telerik Components for ASP.NET MVC you can use this unique names to bind navigation controls without applying PopulateSiteMap attribute.

Currently I am not able to define concrete date for our release. Nevertheless the aforementioned improvement will be included in the next minor release.

Kind regards,
Georgi Krustev
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
ls
Top achievements
Rank 1
answered on 15 Apr 2010, 06:54 PM
Hi Georgi,

Any updates on the internal build release date?

Thanks,

Mike
0
Georgi Krustev
Telerik team
answered on 16 Apr 2010, 08:10 AM
Hello Mike,

We are going to release service pack of the Telerik Components for ASP.NET MVC in the begging of the next week (19.04.2010). As you are customer you will be able to download it from your account.

Greetings,
Georgi Krustev
the Telerik team

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
Ron DeFreitas
Top achievements
Rank 2
answered on 19 Apr 2010, 08:01 AM
I found a pretty simple way of combating this problem, albeit this solution would be needed on every controller that displays the map either from the PanelBar, Menu (or another component if applicable).

First, decorate the entire controller class with the PopulateSiteMap Attribute.

Then, inside your controller class, Call a public instance of itself, and place your Registration code in there...

Example:
namespace MVCSite.Controllers  
{  
    [PopulateSiteMap(SiteMapName = "sample", ViewDataKey = "sample")]  
    public class HomeController : Controller  
    {  
        public HomeController()  
        {  
            if (!SiteMapManager.SiteMaps.ContainsKey("sample"))  
            {  
                SiteMapManager.SiteMaps.Register<XmlSiteMap>("sample", sitemap => sitemap.LoadFrom("~/sample.sitemap"));  
            }  
        } 

        //Your Controller's Actions Go Here

    }
}

Another method, instead of doing this for each Controller, would be to create a partial Controller class and derive all of your other controllers from that.

Personally, for performance, I prefer having to add this to each Controller that calls it, as I'm not using this functionality on every view, just multiple views within the same Area.
0
ls
Top achievements
Rank 1
answered on 20 Apr 2010, 04:59 AM
Ron,

This is what I was attempting to do also.   Just curious why inheriting the base controller class would be less efficient?   Wouldn't the code be compiled.

What I would really like to do is generate the menu from a model and then cache the model after the user logs in or when a change is needed.

This way the menu system could be controlled completely from the database and have the performance similar to storing a sitemap.  Would this even be possible?

Mike
0
Ron DeFreitas
Top achievements
Rank 2
answered on 20 Apr 2010, 05:54 AM
The code would be compiled, but in the case of using static sitemap files, you'd be loading that sitemap on every single page that uses that custom Controller type...

Granted, this is incredibly efficient if you need the Sitemap on every page, but for the application I'm using it on curently I do not, and it varies in different areas of the site.

So, rather than consistently keeping data I don't need in memory, I've opted to call it only on those controllers that I feel actually need it.  Now I could do this by using the base class method, as well, but for me, having the attribute decorated on each Controller I use it in makes it a bit more visible for me in the code, and easier for me to track down those items, rather than looking to see whether it inherits from Controller or from "CustomController".
0
Ron DeFreitas
Top achievements
Rank 2
answered on 20 Apr 2010, 06:18 AM

While you certainly could put together a custom SiteMap Provider that is database generated and geared towards asp.NET MVC (I'd check the Asp.NET Provider Samples and modify the SQLSiteMapProvider to taste for MVC and the Telerik controls), caching it based on the user profile is whoilly unnecessary, as now you have yet another complex type that is stored in session memory for each and every logged in user.

I'd highly recommend utilizing the RolesProvider, whichever flavor of it you prefer (I use a custom one built off of LINQ for my current project), and decorating your actions to restrict access as necessary.  The Telerik SiteMapManager already uses some initelligent caching, near as I could tell, AND will defer to any restrictions you place.  The SiteMap Binding of each of the Telerik MVC Controls fully supports Roles and User Authorization based upon the Authorize Attribute (or any derivative thereof) of that Action.

For example, if we build upon the previous code sample:

Controller:

namespace MVCSite.Controllers  
{  
    [PopulateSiteMap(SiteMapName = "sample", ViewDataKey = "sample")]  
    public class HomeController : Controller  
    {  
        public HomeController()  
        {  
            if (!SiteMapManager.SiteMaps.ContainsKey("sample"))  
            {  
                SiteMapManager.SiteMaps.Register<XmlSiteMap>("sample", sitemap => sitemap.LoadFrom("~/sample.sitemap"));  
            }  
        }  
 
        public ActionResult Index()  
        {  
            //perform actions  
            return View();  
        }  
 
        public ActionResult Create()  
        {  
            //perform actions  
            return View();  
        }  
 
        public ActionResult Update()  
        {  
            //perform actions  
            return View();  
        }  
 
        public ActionResult Delete()  
        {  
            //perform actions  
            return View();  
        }  
 
    }  


We now have 4 Actions on this controller, so the "sample" SiteMap file may look like this:
<?xml version="1.0" encoding="utf-8" ?> 
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" > 
    <siteMapNode title="Home" controller="Home" action="Index" > 
        <siteMapNode title="Home">  
            <siteMapNode title="Homepage Title" controller="Home" action="Index" /> 
            <siteMapNode title="Create Title" controller="Home" action="Create" /> 
            <siteMapNode title="Delete Title" controller="Home" action="Delete" /> 
            <siteMapNode title="Update Title" controller="Home" action="Update" /> 
        </siteMapNode> 
    </siteMapNode> 
</siteMap> 


So we have our simple SiteMap which relates to those entries... We'd see a menu with all of those items ("Homepage Title", "Create Title","Delete Title","Update Title") appeared as sub items of the "Home" Menu item.

Now, if we decorate the Delete ActionResult as follows:
        [Authorize(Roles="Administrator")]  
        public ActionResult Delete()  
        {  
            //perform actions  
            return View();  
        } 

And then we login as a User who is NOT in the "Administrator" Role, the menu with show only the other 3 links, but not "Delete Title".
So, no need to cache additional data, just decorate your Actions with the Authorize Attribute, and you're golden! :)
0
Sebastian
Top achievements
Rank 1
answered on 08 Nov 2010, 12:43 AM
I cannot understand why panelbar using sitemapbinding gives me so many errors. (

Object reference not set to an instance of an object

 or

You must have SiteMap defined with key "*" in ViewData dictionary.

)

Even I copy pasted the telerik mvc demo details into my application in order to have same kind of info that the app uses but with no success... I dont know what to do....

Additionally, why in the example the app uses telerik.web.mvc.products and telerik.web.mvc.products.examples?. These two details were only defined in populateproductsitemapattribute and in navigation, but nothing more...?.

any idea will be appreciated.

Tags
Menu
Asked by
Gabriela Soares
Top achievements
Rank 1
Answers by
Georgi Krustev
Telerik team
Tom Dahlberg
Top achievements
Rank 1
David
Top achievements
Rank 1
Daniel Collier
Top achievements
Rank 1
ls
Top achievements
Rank 1
Ron DeFreitas
Top achievements
Rank 2
Sebastian
Top achievements
Rank 1
Share this question
or