Sitemap per user problem, SitemapProvider problems

Last post 05-09-2008 5:34 PM by raymonette200. 7 replies.

Sort Posts:

  • Sitemap per user problem, SitemapProvider problems

    05-06-2008, 12:45 PM

    Hello, Ive created a portal that uses a master page in which a TreeView control loads the content for a sitemap after querying a DB (in this case a MySQL db). Ive read this thread (http://forums.asp.net/p/982950/1531734.aspx) and modified David Sussman's code appropriately (the db connection section), and I cant seem to get the treeview control to display anything but the nodes under the root. The nodes that contain children and that are not directly under the root are not displaying (the children nodes do seem to be picked up though via the GetChildNodes fct). I am not sure what the problem is exactly, but when stepping through code, the problem seems to be in here, in the FindSitemapNode function

    foreach (KeyValuePair<int, UserDbSiteMapNode> node in _userDbSiteMapNodes[HttpContext.Current.User.Identity.Name])
    {
     HttpContext.Current.Trace.Write("FSMN", "testing " + node.Value.Node.Url);
     if (node.Value.Node.Url == rawUrl)
     {
      HttpContext.Current.Trace.Write("found");
      return ReturnNodeIfAccessible(node.Value.Node);
     }
    }

    When the code hits the children nodes, the RawURL value (passed in as the function parameter) is numerical and therefore the condition is not met and I think this is what causes the children to never show up.

     Ive disabled security trimming, Ive added "*" to the Roles, ive copied the data from the SQL table that came with the example... What am I missing? This is the only portion of code that changed, the rest is identical:

    // create database provider factory
    //DbProviderFactory factory = DbProviderFactories.GetFactory(this._dbProviderName);
    //DbConnection conn = factory.CreateConnection();
    //DbCommand cmd = factory.CreateCommand();
    //DbDataReader rdr;

    // set connection and command details
    MySqlConnection mscConnection = new MySqlConnection(ConfigurationManager.ConnectionStrings["MySqlLocalSqlServer"].ConnectionString);
    MySqlCommand mscmdCmd;
    MySqlDataReader rdr;
    //mscConnection.ConnectionString = ConfigurationManager.ConnectionStrings[this._connectionStringName].ConnectionString;
    //cmd.Connection = mscConnection;
    string strQuery = "SELECT * FROM UserMenu WHERE UserName ='" + userName + "'";
    //cmd.CommandType = CommandType.Text;
    //DbParameter param = cmd.CreateParameter();
    //param.DbType = DbType.String;
    //param.ParameterName = "@UserName";
    //param.Value = HttpContext.Current.User.Identity.Name.ToLower();
    //cmd.Parameters.Add(param);

    mscConnection.Open();
    mscmdCmd = new MySqlCommand(strQuery, mscConnection);
    rdr = mscmdCmd.ExecuteReader();

     

  • Re: Sitemap per user problem, SitemapProvider problems

    05-06-2008, 6:02 PM

    Ok. I think figured it out. The problem was that in some cases, the URL was empty (I was also testing with another table, in which the identifying key was a userid [int]), and based on the code flow, I wouldnt reach this function:

    return ReturnNodeIfAccessible(kvpNode.Value.smnNode), which seems to be the code thats needed to show the children nodes.

    What I ended up doing was implementing the FindSiteMapNodeFromKey function and voila! Children nodes showed up. What I am unsure of is this: how is the Key value passed in as a parameter assigned, especially given the statements in this msdn article: http://msdn.microsoft.com/en-us/library/aa479033.aspx. Somehow, the key number in my case turns out to be the nodeid value. So that simplified things... In any case, here is the code

    public override SiteMapNode FindSiteMapNodeFromKey(string key)

    {

    SiteMapNode smnNode = new SiteMapNode(this, key);

     

    return ReturnNodeIfAccessible(smnNode);

    }

    It seems to work locally, so the next step will be to test it "live"

  • Re: Sitemap per user problem, SitemapProvider problems

    05-07-2008, 3:56 AM

    I'm glad you got it sorted. To be honest, I haven't looked at that code for a while, bbut I think I use the database ID as the key. It's probably passed into the provider from the SiteMapDataSource control.

  • Re: Sitemap per user problem, SitemapProvider problems

    05-09-2008, 10:59 AM

    Actually, Ive discovered, or realised, that another problem is occuring. Im still gettting cross user session "pollution". The solution has improved in the sense that when user A logs in, he gets the nodes as per the query specifies, and user B gets his nodes as well (before, with a StaticSitemapProvider, user B would get user A's sitemap from the get go). The problem now is that when user A refreshes his page, the nodes displayed revert to User B's nodes. Im wondering, is there a way to cache the data per user or is the solution one where I could force a clearing of the nodes everytime a refresh happens and restart the whole process? I realise that this seems tremoundsly innefficient, but I have very few users and the tree is quite small, so Im not too worried about performance, for now... 

    I stepped through the code as user A, when two users where logged in and when the FindSitemapNodebyKey kicks in, it sees the keys for User B. I did this locally from the dev environment, which may explain why it happens, at least there, but the live server has the same behavior, so it seems that still the custom provider does not manage to differentiate the threads per users... I guess Im getting a bit confused as to how sessions work. I was under the impression that they were a bit like threads, where each thread lives in its own space, and therefore all the data per session was persistent per user. What I think is happening is that because the web.config provider section points to the same provider, it keeps stacking the objects on top of each other, and the session refers to the latest one on the stack, meaning that its not associating the provider object to the corresponding session.

     Anybody have some insight or a possible resolution for this?

     

  • Re: Sitemap per user problem, SitemapProvider problems

    05-09-2008, 11:12 AM
    Answer

    You know what, I hadn't even tried this with different users. You can certainly cache on a user by user basis, and indeed should be caching anyway, since fetching from the DB every page is relatively slow. Use the Cache object:

    HttpContext.Current.Cache.Add("key", objectToCache)

    You could use the user name as the key.

    Session data is separated, but the provider doesn't store the data in the session. Although you have a session active, it's not required, nor is data that's used automatically stored in there. Site map providers have to cache their own data in a way that's suitable, but the provider framework actually caches data centrally for all users, so you'd want to overide that with your own caching. so instead of fetching the data directly from the datbase, what you'd do is first fetch it from the cache; if it's not in the cache, then fetch it from the database and store it in the cache. This is the accepted pattern for caching:

    object o = Cache["mykey"];
    if (o == null)
    {
        // get data from database
        HttpContext.Current.Cache.Insert("mykey", mydata);
    {
    else
    {
        // cast o to appropriate type
    }

    With the user name as the cache key, you'll get a new entry in the cache for each user, so data is separated.

  • Re: Sitemap per user problem, SitemapProvider problems

    05-09-2008, 11:28 AM
    Ill give it a try and let you know. Thanks!
  • Re: Sitemap per user problem, SitemapProvider problems

    05-09-2008, 5:13 PM

    Ok. Ive been trying a few things and I seem to be stymied. Im not that familiar with Caching objects and where to assign them in the codeflow. I tried placing it in the BuildSitemap fct and when actually building it, I wasnt sure what callback I would pass in as a parameter, and what that callback would do. In any case, I think there may be a problem with the approach in no matter what because of the nature of HttpContext.Current. It assigns itself to the latest logged-in user. I am not sure how I would iterate over the cache objects to then match it with the correct logged user and then retrieve the correct cached data, ie, I have key value pairs of users and cached data, but then how do I display the correct data for the correct user. So, as was mentioned, I would probably do something like HttpContext.Current.Cache.Insert("mykey", mydata), but how would I get the correct key?

    As an alternative, in my login page, I set a Session["userid"] session variable, which I thought I could then use in the overriden class. The first thing I saw was that its not visible to the class as it is in other classes/pages. For example, in my master page, I reference that variable so that I can query the db to retrieve the display name and put in on a label on the top right. I then created a global variable (which I now realise is probably treated as an App global var, as opposed to a Session var) and when I log in as two different users, I get the correct text on the labels. Since I was able to differentiate between users at that level, I tried to access the same variable in the provider class, but it just takes the latest logged in user. I realise that as Jeff mentioned, its probably because of the framework diffs in terms of caching fro providers, but the more I think about it, the more I wonder if using the HttpContext.Current class will help me...

     Im stuck.

  • Re: Sitemap per user problem, SitemapProvider problems

    05-09-2008, 5:34 PM

    Ok. My apologies, it does seem to work: I was doing all my tests on the same machine!! On different machines, with two different users, it works. I guess I can live with that for now. I feel though that long term, the solution should be tailored that even if on the same machine, the tree should load up based on who you are. So, if anyone knows how to do that, let me know please.

Page 1 of 1 (8 items)