Sharepoint: How to obtain the current site/web/list properly - sharepoint

What is the best way to obtain the current site/web/list ?
Option 1 - Reusing existing objects
SPSite site = SPContext.Current.Site;
SPweb web = SPContext.Current.Web;
SPList list = SPContext.Current.List;
Option 2 - Creating new objects
SPSite site = new SPSite(SPContext.Current.Site.ID); // dispose me
SPweb web = site.OpenWeb(SPContext.Current.Web.ID); // dispose me
SPList list = web.Lists[SPContext.Current.List.ID];
I experienced problems when using option 1 in some situations. Since then I chose the 2nd option and it worked fine so far.
What is your opinion on this? I is generally better to go with option 2? Other suggestions?

Do use Option one, because it's more resource-efficient as you don't need to create new object (For example OpenWeb method involves querying database to do it's job). But you are not allowed to dispose objects from SPContext, that will definitely cause you problems.
You must use Option Two if your code is not run in context of application pages (like SharePoint timer or Workflow), because SPContext.Current object will be null.
Link
And yes, if you open SPWeb or SPSite object, you MUST dispose it.

I normally go with option 2 (which I believe si the approach recommended by Microsoft), but I tend to wrap things using using to ensure they are disposed of properly. Example:
using (SPSite site = new SPSite("MY SITE URL"))
{
using (SPWeb web= site.OpenWeb())
{
// Do stuff
}
}
This approach allows you to be explicit about when objects are created and destroyed.

Related

Get Current Navigation items for all site collections and webs - SP2010

I'm trying to make a site map for a Sharepoint 2010 that will list every site and that site's current nav items. Navigation between sites is done via the top nav. However, I'm having problems getting the current nav items for each site. It appears that each time I get the PortalSiteMapProvider for the web, it returns the provider for the whole site collection. How do I get the items for just that site? I run this code for each site I want to get the items for:
var provider = new PortalSiteMapProvider();
provider.NavigationType = PortalNavigationType.Current;
provider.CurrentWeb = web;
var rootNode = provider.RootNode;
Anyone have any idea where to go from here?
EDIT:
So it isn't possible to just access each site collection and run this code. The PortalSiteMapProvider doesn't allow it. It is, however, possible to run this code in a ashx that's located in the layouts folder. I just need to access that ashx file from the site collection I want to enumerate, and it will work just fine :)
private void DrawWeb(SPWeb web, TreeNode node)
{
SPWebCollection webCol = web.Webs;
foreach (SPWeb w in webCol)
{
var n = new TreeNode(w.Title);
node.ChildNodes.Add(n);
DrawWeb(w, n);
w.Dispose();
}
}
Try calling this method like:
TreeNode webNode = new TreeNode(rootNode.Title);
DrawWeb(provider.CurrentWeb, webNode);
Hope this will be helpful.
So it isn't possible to just access each site collection and run this code. The PortalSiteMapProvider doesn't allow it. It is, however, possible to run this code in a ashx that's located in the layouts folder. I just need to access that ashx file from the site collection I want to enumerate, and it will work just fine :)

SPContext.Current.Web is not latest

I am creating a list with a deployed list template. with the following code:
SPSite site = new SPSite("http://servername");
SPWeb web = site.OpenWeb();
web.Lists.Add(listName, listName, listTemplate);
web.Update();
SPList List = Web.Lists[listName];
I am able to access the list with the web object which is used to create it. But, SPContext.Current.Web is not updated. So, the following throws error:
SPContext.Current.Web.Lists[listName]
Is it possible to update the SPContext.Current object with latest information so that the list accessible after it is created?
Thanks in advance!
Update: Code updated.
Your code doesn't show this, so I'm going to ask for the obvious: did you try calling web.Update() right after adding the new list?
I added the below line after web.Update() and it started working.
SPContext myContext = SPContext.GetContext(Web);

Update sharepoint list view programmatically

I have an aspx page with inline code in which I am trying to update the view programmatically by setting view's Query property to my CAML query. When I run with administrator user everything works perfect view get updated successfully but when I logged in with a user who belongs to visitor group and having read only access then I get an error on view.Update() line saying that:
"Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack"
I have already try to run this code block with ElevatedPrivileges but not get any luck...(
following is my code which make you more clear:
SPUserToken token = CurrentSite.SystemAccount.UserToken;
using (SPSite st=new SPSite(SPContext.Current.Web.Url,token))
{
st.AllowUnsafeUpdates = true;
using (SPWeb wb=st.OpenWeb())
{
wb.AllowUnsafeUpdates = true;
vwSearchResult.Query = Query;
vwSearchResult.Update();
}
}
What you are doing here, is modifying the definition of the view for ALL users of the website, not only the current rendering instance of the page. This is why simple visitors cannot change it (they do not have such permission in the web)
If you want to do something, using the "SystemAccount" token, you have not only to do the "using SPSite, using SPWeb", but also find the list and the view using the "strong" SPWeb objects
Instead of modifying a view definition at runtime, you might want to consider using ListViewByQuery class http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.webcontrols.listviewbyquery.aspx

WebPart "metadata"?

I have not worked with webparts for sharepoint before, but need to make change to a webpart, that needs to be propagated to some 700 websites. It is a change to one of the properties of the webpart, the value needs to be changed. Is there a way to get metadata for a webpart and change it directly in the database (I assume that is where it is stored.)?
Here is the scenario: Webpart contains a comma delimited list of document types (internal type) that it should display. Now there are new doc. types that need to be added to all 700 websites. I need a way to enumerate websites, get the webpart metadata, and add these new doc types to webpart. Currently they go manually to each website, click on edit, type in new doc type, and save it.
As others have said the correct approach is to programmatically achieve this rather than edit the content database which will make your installation unsupportable. I regularly use a console application to do this in a site collection made up of sites created from a site template.
Here is an example that changes the Title property of a ListViewWebPart. Updated to include code for recursive loop. I haven't tested this but it should work.
private static void ProcessSiteCollection(string url)
{
using (SPSite siteCollection = new SPSite(url))
{
SPWeb rootWeb = siteCollection.RootWeb;
ProcessWebs(rootWeb);
}
}
private static void ProcessWebs(SPWeb parentWeb)
{
foreach (SPWeb web in parentWeb.Webs)
{
try
{
UpdateWebPart(web); // Set web part properties
ProcessWebs(web); // Recursively loop through children
}
finally
{
web.Dispose();
}
}
}
private static void UpdateWebPart(SPWeb web)
{
using (SPLimitedWebPartManager webPartManager =
web.GetLimitedWebPartManager("default.aspx", PersonalizationScope.Shared))
{
try
{
foreach (WebPart webPart in webPartManager.WebParts)
{
if (webPart.Title == "My Web Part")
{
ListViewWebPart listViewWebPart = (ListViewWebPart)webPart;
listViewWebPart.Title = "Updated Web Part";
webPartManager.SaveChanges(listViewWebPart);
web.Update();
break;
}
}
}
finally
{
webPartManager.Web.Dispose();
}
}
}
Directly accessing the sharepoint content databases is a big "no no." That's the official answer. :)
That being said, I have only ever looked in the content databases and never tried to actually change anything manually.
My suggestion, would be to modify the existing web part to modify the property based on currently set property(s). (I am assuming that some currently set property is invalid or needs to be updated based on changes to the infrastructure.) ... If this is the case, you can validate the property; making sure that current property is changed to what it needs to be, and/or making sure future property changes are valid.
Good luck!
DON'T
Seriously, do not go into the content databases and edit it. That way you are not supported anymore if anything should happen and Microsoft will not support you anymore (not until you revert the database back to an earlier version from a backup that is).
You can use the API to access webparts in your sites, here's some code that should get you started:
Enumerate page webparts

How do I programatically turn off show pages in navigation for sharepoint

I am progamatically creating a SharePoint site using
SPWeb spWeb = spSite.AllWebs.Add(...);
What code do I need run to set the spWeb to turn off the "Show pages in navigation" option?
Answer:
publishingWeb.IncludePagesInNavigation = false;
Wasn't sure myself but I was able to locate this:
Modifying navigation is another common
branding task since it affects what
users can see and how they can proceed
through a site hierarchy. The
Microsoft.SharePoint.Publishing
namespace exposes several classes that
target the Publishing site
infrastructure, such as PublishingWeb
and PublishingPage. Using these
classes, we can easily modify
navigation for each site. If you want
a child Web to display as a root level
site in global navigation, first turn
off inheritance from the parent site,
like so:
publishingWeb.InheritGlobalNavigation = false;
You might also want to hide all site
pages from global navigation. Setting
IncludePagesInNavigation to false
hides all pages in the site,
regardless of whether the
PublishingPage.IncludeInGlobalNavigation
property is set to true
// do not show pages in navigation
publishingWeb.IncludePagesInNavigation = false;
If you are dealing with default sites
that don't inherit from PublishingWeb,
it's still possible to hide these
sites from the global navigation bar.
For example, if you create a site
collection using the collaboration
portal template and want to exclude
the News site from global navigation,
add that site to the
__GlobalNavigationExcludes property of the site:
string globalNavExcludes = String.Empty;
SPWeb webSite = MSDNSiteCollection.RootWeb;
// _GlobalNavigationExcludes property contains a delimited string of
// GUIDs identifying the Id of each site to be excluded from global
// navigation
if (webSite.AllProperties.ContainsKey("__GlobalNavigationExcludes")) {
globalNavExcludes =
webSite.AllProperties["__GlobalNavigationExcludes"].ToString();
}
SPWeb newsSite = MSDNSiteCollection.AllWebs["News"];
// string is delimited "{GUID};{GUID};",
// use format code B to convert to string
globalNavExcludes += String.Concat(currentWeb.ID.ToString("B"), ";");
webSite.AllProperties["__GlobalNavigationExcludes"] = globalNavExcludes;
webSite.Update();
Adding navigation nodes directly to an
SPNavigationNodeCollection is a good
way to display only the nodes you want
as well as to group nodes and links to
external sites. Figure 10 shows how to
add an internal link, external link,
and a heading to the global navigation
bar. This example addresses some of
the properties of the SPNavigation
class that affect whether the link
opens in a new window and how to
handle empty URLs.
For SP 2010 use below...
publishingWeb.Navigation.GlobalIncludePages = false;

Resources