?
Solved

Asp.net put menu in session Varible to save time

Posted on 2011-10-11
13
Medium Priority
?
748 Views
Last Modified: 2012-05-12
Hi to save time i want to put the navigation menu in a session varible. I thought about putting in an application varible put want it to refresh at least once a day. Either way how do you put it in the varible. Here is what I have tried:

    If Session("LeftBarNavigationMenu") Is Nothing Then
            Dim da As New SqlDataAdapter(objCommand)
            Dim dt As New DataTable()
            da.Fill(dt)
            PopulateMenuItems(dt, NavigationMenu.Items)
            Session("LeftBarNavigationMenu") = NavigationMenu
        Else
            NavigationMenu = Session("LeftBarNavigationMenu")
        End If
0
Comment
Question by:taz8020
  • 6
  • 5
  • 2
13 Comments
 
LVL 18

Expert Comment

by:Ajay Sharma
ID: 36947531
You need to put the dataTable into session not the menu itself.
Modify code as below:

        If Session("LeftBarNavigationMenu") Is Nothing Then
            Dim da As New SqlDataAdapter(objCommand)
            Dim dt As New DataTable()
            da.Fill(dt)
            PopulateMenuItems(dt, NavigationMenu.Items)
            Session("LeftBarNavigationMenu") = dt
        Else
            DataTable dt = Session("dt")
            PopulateMenuItems(dt, NavigationMenu.Items)
        End If
0
 
LVL 3

Expert Comment

by:KBerger
ID: 36947533
Hi,

your approach might be a problem. I guess NavigationMenu is a control? You should not put a control into your session-state (if it works at all).
Instead you should consider putting the DATA into your Session-State. You could put your data-table into the session-state for instance.
However, if the menu is the same for all users, this would consume more memory than needed.
Try to put the data into the HttpCache instead like this:

HttpContext.Current.Cache.Add("MyMenuData",dt)

This will allow to cache the data once and serve it from the cache to every user/session. If the menu changes (i.e. by configuration), you will just have to update it once.

Hope that helps you out!

Regards,

-Kristof
0
 
LVL 3

Author Comment

by:taz8020
ID: 36947575
Hi thanks both, the time delay is not in filling the datatable its populating the menu. Any ideas how I could speed this bit up?
0
Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

 
LVL 3

Author Comment

by:taz8020
ID: 36947587
The Code for populating the menu is:
Private Sub PopulateMenuItems(ByVal dt As DataTable, ByVal MenuItems As MenuItemCollection)
        For Each dr As DataRow In dt.Rows
            Dim tn As New MenuItem()
            tn.Text = dr("SectionName").ToString() & " (" & dr("childnodecount").ToString & ")"
            tn.Value = dr("SectionID").ToString()
            If dr("childnodecount").ToString = "0" Then
                tn.Selectable = False
            End If
            If PageSectionID = dr("SectionID").ToString Then
                tn.Selected = True
            End If
            tn.NavigateUrl = "~/ProductSections.aspx?ParentSectionID=" & dr("SectionID").ToString()
            MenuItems.Add(tn)
            AddSubMenuItems(tn.Value, tn)
        Next
    End Sub
    Private Sub AddSubMenuItems(ByVal ParentSectionID As Integer, ByVal MenuItem As MenuItem)
        Dim objConn As New SqlConnection(MainConnectionString)
        Dim objCommand As New SqlCommand("select SectionID,SectionName,(SELECT COUNT(*) AS Expr1 FROM ProductSections WHERE (ParentSectionID = sc.SectionID)) + (SELECT COUNT(*) AS Expr2 FROM Products WHERE (WebSection = sc.SectionID)) AS childnodecount FROM ProductSections sc where ParentSectionID = @ParentSectionID", _
          objConn)
        objCommand.Parameters.Add("@ParentSectionID", SqlDbType.Int).Value = ParentSectionID

        Dim da As New SqlDataAdapter(objCommand)
        Dim dt As New DataTable()
        da.Fill(dt)
        AddSubMenuItems2(dt, MenuItem)
    End Sub
    Private Sub AddSubMenuItems2(ByVal dt As DataTable, ByVal ParentMenuItem As MenuItem)
        For Each dr As DataRow In dt.Rows
            Dim tn As New MenuItem()
            tn.Text = dr("SectionName").ToString() & " (" & dr("childnodecount").ToString & ")"
            tn.Value = dr("SectionID").ToString()
            tn.NavigateUrl = "~/ProductSections.aspx?ParentSectionID=" & dr("SectionID").ToString()
            ParentMenuItem.ChildItems.Add(tn)
            AddSubMenuItems(tn.Value, tn)
        Next
    End Sub
0
 
LVL 3

Expert Comment

by:KBerger
ID: 36947595
Hi,

well, I guess that the control will have a view-state. So you will only have to populate it once. But this depends on how your site is designed. If every click/postback will reload the complete page (and along with it the menu), I think you will reload the menu every time. What you could do is to use MasterPages. You put your menu into the masterpage and the rest into the content-area. This way the control will not be rebuild every time.
Another approach might be to use output-caching. You might have to wrap the NavigationMenu in a usercontrol and then activate caching for it.

Regards,

-Kristof

Kristof
0
 
LVL 18

Expert Comment

by:Ajay Sharma
ID: 36947609
In that case don't use the viewstate/session to store menu/datatable.
What you want is Output Caching of controls, you should create a UserControl and place the menu inside this.

Read below links for more reference:
http://msdn.microsoft.com/en-us/library/h30h475z.aspx
http://msdn.microsoft.com/en-us/library/h30h475z(v=vs.71).aspx
http://www.4guysfromrolla.com/articles/121306-1.aspx
http://support.microsoft.com/kb/308375
0
 
LVL 3

Accepted Solution

by:
KBerger earned 2000 total points
ID: 36947624
Hi again,

I didn't see the code before.

Hum. I think the part which consumes most of the time is AddSubMenuItems. This method requests data from the database.You should think about that again.
You could get ALL MenuItems from the database ONCE and cache them.
Try to put the result auf the SQL-Query (which is a database again) into the HttpCache with a unique key which allows retrieval.
For instance (I am more C#, I hope you get it anyway)

string key = "SECTION_"+ParentSectionID.ToString();

If(HttpContext.Current.Cache[key]==null)
{
  // get the data from the database

 // put the data into the cache
 HttpContext.Current.Cache.Add(key,dt);

 // cleanup you database-stuff!
 objConn.Close();
 dt.Dispose();
}
else
{
  dt = (DataTable)HttpContext.Current.Cache[key];
}

AddMenuItems2(dt,MenuItem);

Basically you will reduce the amount of requests to the database and operate in memory instead.

Furthermore I saw that you do not close your connections, nor dispose the datatables. This will lead to leaks, as the connections will not be returned to the pool, so your application is likely to crash under load.

Hope that helps,

-Kristof
0
 
LVL 3

Author Comment

by:taz8020
ID: 36947842
KBerger thank you works perfect. Just 2 questions to wrap this up.
1). If the data changes how do i refresh the Cache
2). I did know i had to close connections but thought all the varibles were disposed at the end of the function/sub. Do you have to set all varibles to nothing at the end of the sub?
eg dim mystring as string
0
 
LVL 3

Expert Comment

by:KBerger
ID: 36947916
Hi taz,

well, the problem with Garbage-Collection (which is the way .NET keeps track of used/unused memory-resources) is, that many people think that they did not have to worry about their data at all - this is as sad as untrue. ;-)
The garbage collector can only get rid of data which is marked as unused. For managed resources (like strings, StringBuilders, etc.) this is done automatically within their scope.
However, when you use unmanaged resources (like you do implicitly when accessing a database or a file), you will have to cleanup yourself. This cleanup will do the necessary steps to tell the garbage collector that a given resource is actually not needed anymore.
That being said, it is always a good approach to cleanup resources as soon as you do not need them anymore - no matter whether they will be freed up automatically or nor.
For critical resources like database-connections, threads, files, etc. you should always Close/Dispose your objects if possible.
Another point is that database-connections and threads relay on a limited resource - the connections-pool or the thread-pool respectively. When you do not free you connections/threads, you will make your app crash or just stop responding.
You can read about that in the web.

Now for refreshing the cache.
That's easy. Just assign the new value:

if(HttpContext.Current.Cache[key]!=null)
{
  HttpContext.Current.Cache[key]=newValue;
}
else
{
 HttpContext.Current.Cache.Add(key,newValue);
}

You should consider that cached data has a lifetime (which you can specify explicitly). So there might be situations where an element that you thought would be in the cache has been removed by the runtime, as its lifetime exceeded. So you should write a simple common helper-method which handles these situations. You can make the necessary steps more easily when you invest a little into the architecture of your application. I think in your app there are 2 important points.

1. Never let the pages/forms access the database directly
2. Never let the pages/forms access the cache directly

You could for instance build a class called "MenuService" which exposes methods for getting the menu-data.
Your Form will just call "MenuService.GetMenuData". This method will then check whether the data is already in the cache or not, get it from the database if necessary, put it in the cache when updated and then return it to the caller.
I don't know enough about your appliction, so I will not get into detail - I guess you got the point.

Happy to be helpful,

-Kristof
0
 
LVL 3

Author Closing Comment

by:taz8020
ID: 36947954
Thank you so much, I dont understand why you should never let the pages/forms access the database directly. Is it a security risk?
0
 
LVL 3

Expert Comment

by:KBerger
ID: 36947981
Hi,

first of all : Thanks for accepting my answer.

It is not a security-risk, it is just better architecture. The pages should contain the least logic/knowledge about WHAT happens. They should just make it look good ;-)
If you are interested in  things like this try reading about design-patterns and software-architecture in general.
One simple point is, that you will ALWAYS have to think about your cache and your database when writing code in your pages. If you hide these details in appropriate classes, you will just have to call their methods and can be sure, that they will return the data you need - no matter whether from the cache or not.
And then even this minimalistic architectural approach will help you in writing Unit-Tests to verify the functionality of your solution.

Regards,

-Kristof
0
 
LVL 3

Author Comment

by:taz8020
ID: 36948006
Kristof, once again thank you. I wish everyone on here explained things as well as you. Instead they normally give you a link which is not relevent to the question.
Thank you.
0
 
LVL 3

Author Comment

by:taz8020
ID: 36949175
Kristof, as you were so helpfull on last question just wondered if you had time to look at new one at http://www.experts-exchange.com/Microsoft/Development/Q_27390716.html
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Is your OST file inaccessible, Need to transfer OST file from one computer to another? Want to convert OST file to PST? If the answer to any of the above question is yes, then look no further. With the help of Stellar OST to PST Converter, you can e…

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question