NullReferenceException thrown in "GetAvailablePageLayouts" - sharepoint

I ran into this error recently when trying to get all the page layouts in a publishing site (Microsoft.SharePoint.Publishing.PublishingWeb) from a custom layouts page in a subsite. The code worked on a VM server using a site created from the Enterprise Wiki site template. But when running on the development server the code encountered various exceptions.
Attempting to get around the error, I coded the class three different ways. All three worked in the VM, but all three threw an exception when used in the development server. Example:
private PageLayout FindPageLayout(PublishingWeb pubWeb, string examplePage)
{
/* The error occurs in this method */
if (pubWeb == null)
throw new ArgumentException("The pubWeb argument cannot be null.");
PublishingSite pubSiteCollection = new PublishingSite(pubWeb.Web.Site);
string pageLayoutName = "EnterpriseWiki.aspx"; // for testing purposes
PageLayout layout = null;
/* Option 1: Get page layout from collection with name of layout used as index
* Result: System.NullReferenceException from GetPageLayouts()
*/
layout = pubSiteCollection.PageLayouts["/_catalogs/masterpage/"+pageLayoutName];
/* Option 2: Bring up an existing publishing page, then find the layout of that page using the Layout property
* Result: Incorrect function COM exception
*/
SPListItem listItem = pubWeb.Web.GetListItem(examplePage);
PublishingPage item = PublishingPage.GetPublishingPage(listItem);
layout = item.Layout;
/* Option 3: Call "GetPageLayouts" and iterate through the results looking for a layout of a particular name
* Result: System.NullReferenceException thrown from Microsoft.SharePoint.Publishing.PublishingSite.GetPageLayouts()
*/
PageLayoutCollection layouts = pubSiteCollection.GetPageLayouts(true);
for(int i = 0; i < layouts.Count; i++)
{
// String Comparison based on the Page Layout Name
if (layouts[i].Name.Equals(pageLayoutName, StringComparison.InvariantCultureIgnoreCase))
layout = layouts[i];
}
return layout;
}

Here was the solution I found after a week or so:
Make sure that when you are getting your "PublishingWeb" object by calling that PublishingWeb.GetPublishingWeb(SPWeb) method that you are passing into it an SPWeb objec that has been fully retrieved. More specifically, I would make sure to call SPSite.OpenWeb on any website, as follows:
using (SPSite site = new SPSite(folder.ParentWeb.Url))
{
SPWeb web = site.OpenWeb();
PublishingWeb pubWeb = PublishingWeb.GetPublishingWeb(web);
/* work with PublishingWeb here ... */
web.Close();
}
Once I made this simple change, all the errors mentioned in the question were cleared up, no matter in what context I called "GetPageLayouts" or "GetAvailablePageLayouts". The method documentation says this, and it really means it:
Use this method in order to access PublishingWeb behavior for an
instance of a SPWeb class that has already been retrieved.

Related

How to programmatically add target lists to the what's new web part in Sharepoint (or how to handle undocumented namespaces)

From code I've automatically created a lot of similar sites (SPWeb) in my site collection from a site template (in Sharepoint Foundation). Every site has a home page on which I've added the "what's new" web part (found under "Social collaboration").
Even though the web part has several "target lists" (I'd have called it "source lists") added to it on the template site, this connection is lost on the sites created from the template. So I need to programmatically find all these web parts and add the target lists to them. Looping the web parts is not an issue - I've done that before - but I can't seem to find a word on the net on how to go about modifying this particular web part. All I have is a brief intellisense.
I've found out that it recides in the
Microsoft.SharePoint.Applications.GroupBoard.WebPartPages
namespace, but on the lists provided on MSDN this is one of very few namespaces that doesn't have a link to a reference documentation.
Does anyone have any experience of modifying this web part from code? If not, how would you go about to find out? I can't seem to figure out a method for this..
Here is how I did it. It worked really well. I had a feature that created several list instances and provisioned the What's New web part. In the Feature Receiver, I looped through all of the list instances, indexed the Modified field, and then added the list to the web part:
private void ConfigureLists(SPWeb web, SPFeatureReceiverProperties properties)
{
List<Guid> ids = new List<Guid>();
SPElementDefinitionCollection elements =
properties.Feature.Definition.GetElementDefinitions(new CultureInfo((int)web.Language, false));
foreach (SPElementDefinition element in elements)
{
if ("ListInstance" == element.ElementType)
{
XmlNode node = element.XmlDefinition;
SPList list = web.Lists[node.Attributes["Title"].Value];
SPField field = list.Fields[SPBuiltInFieldId.Modified];
if (!field.Indexed)
{
field.Indexed = true;
field.Update();
}
ids.Add(list.ID);
}
}
string targetConfig = string.Empty;
foreach (Guid id in ids)
{
targetConfig += string.Format("'{0}',''\n", id);
}
SPFile file = web.GetFile("Pages/default.aspx");
file.CheckOut();
using (SPLimitedWebPartManager manager = file.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
WhatsNewWebPart webpart = null;
foreach (System.Web.UI.WebControls.WebParts.WebPart eachWebPart in manager.WebParts)
{
webpart = eachWebPart as WhatsNewWebPart;
if (null != webpart)
{
break;
}
}
if (null != webpart)
{
webpart.TargetConfig = targetConfig;
manager.SaveChanges(webpart);
}
}
file.CheckIn("ConfigureWebParts");
file.Publish("ConfigureWebParts");
file.Approve("ConfigureWebParts");
}
If you are unsure about the property, export the web part from the browser, then open the .webpart/.dwp file with a text editor. Somewhere in the xml will be a reference to the source list.
*.webparts are usually easier to modify, just set the property.
*.dwps are harder because you sometimes have to get the property (eg ViewXML), then load it into an XmlDocument, then replace the property, and write the xml document string value back to ViewXML.

Updates are currently disallowed on GET requests. To allow updates on a GET, set the 'AllowUnsafeUpdates' property on SPWeb

I have a hidden webpart that read query string value "optout=Yes" . This optout = Yes, then I need to update profile property. If you see in my code. It is failing at "userprof.Commit()" and throwing "Updates are currently disallowed on GET requests. To allow updates on a GET, set the 'AllowUnsafeUpdates' property on SPWeb" . Any solution for this?
private void OptOutMemberInvitation()
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//update the invitee's Profile property
UpdateInviteeOptOutProfile(InviteeConstitID);
});
}
private void UpdateInviteeOptOutProfile(string inviteeSiteColUrl)
{
ServerContext sc = ServerContext.Current;
UserProfileManager upm = new UserProfileManager(sc);
//Get the user profile
Microsoft.Office.Server.UserProfiles.UserProfile userprof = upm.GetUserProfile(MemberConstitID);
SPWeb web = userprof.PersonalSite.RootWeb;
//make sure we can update our list
web.AllowUnsafeUpdates = true;
web.Update();
//Update the OptOut Property on the user's profile.
userprof["OptOut"].Value = "Yes";
userprof.Commit(); //Fails here
//update the list item to persist it to list
web.AllowUnsafeUpdates = false;
//siteCol.Close();
//siteCol.Dispose();
}
We have used "SPSecurity.RunWithElevatedPrivileges" that means we would like to use app pool account context for this update process. But inside the function "UpdateInviteeOptOutProfile" we have used current context instead of creating a new site>web object.
Please create a new site and then web object using the URL Or ID.
Looks like you could be using two SPWeb objects, and setting AllowUnsafeUpdates on the wrong one. One would be connected with current server context and the other is userprof.PersonalSite.RootWeb. You'd be setting AllowUnsafeProperties on the RootWeb, and updating the SPWeb in profile (if there is one).
BTW don't forget to do a web.Update() after you set AllowUnsafeProperties at the end.

Sharepoint : Access denied when editing a page (because of page layout) or list item

I'm logged in as the System Account, so it's probably not a "real access denied"!
What I've done :
- A custom master page
- A custom page layout from a custom content type (with custom fields)
If I add a custom field (aka "content field" in the tools in SPD) in my page layout, I get an access denied when I try to edit a page that comes from that page layout.
So, for example, if I add in my page layout this line in a "asp:content" tag :
I get an access denied. If I remove it, everyting is fine. (the field "test" is a field that comes from the content type).
Any idea?
UPDATE
Well, I tried in a blank site and it worked fine, so there must be something wrong with my web application :(
UPDATE #2
Looks like this line in the master page gives me the access denied :
<SharePoint:DelegateControl runat="server" ControlId="PublishingConsole" Visible="false"
PrefixHtml="<tr><td colspan="0" id="mpdmconsole" class="s2i-consolemptablerow">"
SuffixHtml="</td></tr>"></SharePoint:DelegateControl>
UPDATE #3
I Found http://odole.wordpress.com/2009/01/30/access-denied-error-message-while-editing-properties-of-any-document-in-a-moss-document-library/
Looks like a similar issue. But our Sharepoint versions are with the latest updates. I'll try to use the code that's supposed to fix the lists and post another update.
** UPDATE #4**
OK... I tried the code that I found on the page above (see link) and it seems to fix the thing. I haven't tested the solution at 100% but so far, so good. Here's the code I made for a feature receiver (I used the code posted from the link above) :
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.Xml;
namespace MyWebsite.FixAccessDenied
{
class FixAccessDenied : SPFeatureReceiver
{
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
FixWebField(SPContext.Current.Web);
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
//throw new Exception("The method or operation is not implemented.");
}
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
//throw new Exception("The method or operation is not implemented.");
}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
//throw new Exception("The method or operation is not implemented.");
}
static void FixWebField(SPWeb currentWeb)
{
string RenderXMLPattenAttribute = "RenderXMLUsingPattern";
SPSite site = new SPSite(currentWeb.Url);
SPWeb web = site.OpenWeb();
web.AllowUnsafeUpdates = true;
web.Update();
SPField f = web.Fields.GetFieldByInternalName("PermMask");
string s = f.SchemaXml;
Console.WriteLine("schemaXml before: " + s);
XmlDocument xd = new XmlDocument();
xd.LoadXml(s);
XmlElement xe = xd.DocumentElement;
if (xe.Attributes[RenderXMLPattenAttribute] == null)
{
XmlAttribute attr = xd.CreateAttribute(RenderXMLPattenAttribute);
attr.Value = "TRUE";
xe.Attributes.Append(attr);
}
string strXml = xe.OuterXml;
Console.WriteLine("schemaXml after: " + strXml);
f.SchemaXml = strXml;
foreach (SPWeb sites in site.AllWebs)
{
FixField(sites.Url);
}
}
static void FixField(string weburl)
{
string RenderXMLPattenAttribute = "RenderXMLUsingPattern";
SPSite site = new SPSite(weburl);
SPWeb web = site.OpenWeb();
web.AllowUnsafeUpdates = true;
web.Update();
System.Collections.Generic.IList<Guid> guidArrayList = new System.Collections.Generic.List<Guid>();
foreach (SPList list in web.Lists)
{
guidArrayList.Add(list.ID);
}
foreach (Guid guid in guidArrayList)
{
SPList list = web.Lists[guid];
SPField f = list.Fields.GetFieldByInternalName("PermMask");
string s = f.SchemaXml;
Console.WriteLine("schemaXml before: " + s);
XmlDocument xd = new XmlDocument();
xd.LoadXml(s);
XmlElement xe = xd.DocumentElement;
if (xe.Attributes[RenderXMLPattenAttribute] == null)
{
XmlAttribute attr = xd.CreateAttribute(RenderXMLPattenAttribute);
attr.Value = "TRUE";
xe.Attributes.Append(attr);
}
string strXml = xe.OuterXml;
Console.WriteLine("schemaXml after: " + strXml);
f.SchemaXml = strXml;
}
}
}
}
Just put that code as a Feature Receiver, and activate it at the root site, it should loop trough all the subsites and fix the lists.
SUMMARY
You get an ACCESS DENIED when editing a PAGE or an ITEM
You still get the error even if you're logged in as the Super Admin of the f****in world (sorry, I spent 3 days on that bug)
For me, it happened after an import from another site definition (a cmp file)
Actually, it's supposed to be a known bug and it's supposed to be fixed since February 2009, but it looks like it's not.
The code I posted above should fix the thing.
Try to publish your MasterPage and Page Layouts, this is the most common reason. Since the system account is godmode, it wont get that error.
In SharePoint Designer you cannot do the last step in the publishing workflow (Approval), so you:
SharePoint Designer:
CheckIn => Publish Major Version, hit the OK button or go to /_catalogs/masterpage on the site .
Then and use the Context Menu to Approve the MasterPage and Layouts.
Some ideas:
Check if any web parts in your custom Page Layout and Master Page are not registered as safe.
Did you define your own custom field type, like write a class which extends SPField? If so, are you using a custom Field Control? If you are, check if it is doing anything which may need elevated privileges.
Likewise, check for any edit mode panels containing web parts of web controls which might be trying to do something which needs elevated privileges.
See the code I've posted in the edit of the post. It fixed my problem.
The problem appears to be caused by an error in the stsadm -o export function in certain versions of SharePoint (I got it doing an export from a 2007 RTM MOSS server). Importing the bogus export file causes the "edit-denied-access" problem in all NEWLY-CREATED lists. The patches for later version from Microsoft fix stsadm -o export, but DO NOT FIX the broken lists; that requires a procedure like tinky05's.

why my sharepoint workflow always stop when i use this code?

I need to find an user in a list to set the assignedto task property, these informations are in a list. So i use this method :
public static SPUser GetSPUser(SPListItem item, string key){
SPFieldUser field = item.Fields[key] as SPFieldUser;
if (field != null)
{
SPFieldUserValue fieldValue = field.GetFieldValue(item[key].ToString()) as SPFieldUserValue;
if (fieldValue != null)
{
return fieldValue.User;
}
}
return null;
}
The problem is that when i use this method or this part of code, my workflow stop without saying anything. Here an exemple of code when i use it :
using (SPSite site = new SPSite(adress_of_my_site))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["Acteurs du projet"];
SPView view = cobj_ListeDesActeursDuProjet.DefaultView;
SPListItemCollection itemcollection = list.GetItems(view);
foreach (SPListItem item in itemcollection)
{
SPUser lobj_acteur = Utilities.GetSPUser(item,"acteur");
// Dictionary<string,class>
ActeursDuProjet[item["Rôle"].ToString()] =
new ActeursDuProjet()
{
Login = lobj_acteur.LoginName,
Email = lobj_acteur.Email
};
}
}
}
If i comment the content of my foreach my workflow continue as well...
If anybody have an idea it will be cool.
Regards,
Loïc
edit: problem in the code
Here are some debugging tips that might help:
ULS logs
Any exceptions should be reported here in some detail.
Enable debugging for all .NET code
This will cause the debugger to break whenever an exception occurs in SharePoint as well as your code. The downside is that the debugger will break on 'normal' exceptions that cause no side effects. So don't be misled!
To enable: Go to Debug, Exceptions and tick Common Language Runtime Exceptions. Also go to Tools, Options, Debugging and untick Enable Just My Code. Then attach to w3wp.exe.
Commenting code
You could also comment out all of your code. If the workflow step fails, you know there is a problem elsewhere. If the workflow step passes, then start uncommenting code until it fails - then you know where to look.
I tried commenting this above but it didn't format nicely so here it is.
It probably is fine, but this looks fishy to me:
// Dictionary<string,class>
ActeursDuProjet[item["Rôle"].ToString()] =
new ActeursDuProjet()
{
Login = lobj_acteur.LoginName,
Email = lobj_acteur.Email
};
I would think it would be something like:
// dictionary declared somewhere earlier
Dictionary<string,ActeursDuProjet> roles = new Dictionary<string,ActeursDuProjet>();
// inside the foreach
string role = item["Rôle"].ToString();
if (!roles.ContainsKey(role))
{
ActeursDuProjet foo = new ActeursDuProjet();
foo.Login = lobj_acteur.LoginName;
foo.Email = lobj_acteur.Email;
roles.Add(role, foo);
}

Add items to list programmatically

I am using form base authentication in my Sharepoint site. On my login page there are custom fields to be filled by unauthenticated user. These fields i want to add in to my list. I am using following code to insert record in list.
protected void AddVendor(object sender, EventArgs e)
{
string strList = "http://comp01:5353/Lists/Vendors/";
using (SPSite site = new SPSite(strList))
{
site.AllowUnsafeUpdates = true;
using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
SPUser user = web.AllUsers["demouser"];
SPList list = web.Lists["Vendors"];
SPListItem Item = list.Items.Add();
Item["First Name"] = txtVendorName.Text;
Item["Last Name"] = txtVLastName.Text;
Item["business"] = txtDescription.Text;
Item["Description"] = txtDescription.Text;
Item["Mobile No"] = txtMobileNumber.Text;
Item["Approved"] = "No";
Item["Created By"] = "demoadmin";
Item["Modified By"] = "demoadmin";
Item.Update();
}
}
}
but is is giving me an error saying that Thread was being aborted. I don't know what exactly missing. but is it because I am performing add action and user is not authenticated...?
I don´t know if it will help you but the code that says (f.e.) Item["Modified By"] will not work since that is the internal name which is Modified_x0020_By. This goes for all the fields with "spaces" in them.
This might be one of your issues...
Where have you written this code, is it inside some event ? Login Control Provides two events that will help you to solve this
OnLoginError="OnLoginError" OnLoggedIn="OnLoggedIn"
I did similar functionality where I wanted to capture the user name loggin to the site and log it to the DB Table. And with respect to the ThreadAbort Exception, it happens when you use Response.Redirect while a code is being executed. In you case I doubt that its being thrown because you are trying to do the above code but the FBA system tries to redirect the user to the default.aspx . Try out above said Event of the Login Control it should help you.

Resources