0
votes

Not sure where to begin. I have code setup to create a new site and then copy the look, lists, and webparts from a template site.

IT WORKS FINE WHEN LOGGED IN AS SYSTEM ADMIN!

foreach (Microsoft.SharePoint.WebPartPages.WebPart webPartTemplate in webPartCollectionTemplate)
{
  try
  {
MemoryStream memoryStream = new MemoryStream();
XmlTextWriter xmlWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
webPartManagerTemplate.ExportWebPart(webPartTemplate, xmlWriter);
xmlWriter.Flush();
memoryStream.Flush();
memoryStream.Position = 0;

XmlTextReader xmlReader = new XmlTextReader(memoryStream);

Microsoft.SharePoint.WebPartPages.ListViewWebPart listViewWebPartTemplate = null;
Microsoft.SharePoint.WebPartPages.ListViewWebPart listViewWebPartTarget = null;
Microsoft.SharePoint.WebPartPages.WebPart webPartTarget = null;

bool webPartIsListViewWebPart = false;

// If it throws an exception, the web part is not a ListViewWebPart
try
{
  listViewWebPartTemplate = (ListViewWebPart)webPartTemplate;
  webPartIsListViewWebPart = true;
}
catch { }

if (webPartIsListViewWebPart)
{
  string errorMessage = "";
  listViewWebPartTarget = (Microsoft.SharePoint.WebPartPages.ListViewWebPart)webPartManagerTarget.ImportWebPart(xmlReader, out errorMessage);

  if (errorMessage != null)
    // log it

  // Drop the brackets from the Guid and create a Guid object from the string. Then use it to find the list so we can get the title.
  SPList listTemplate = webTemplate.Lists[new Guid(listViewWebPartTemplate.ListName.ToString().TrimStart('{').TrimEnd('}'))];
  SPList listTarget = webTarget.Lists[listTemplate.Title];

  listViewWebPartTarget.ListName = listTarget.ID.ToString("B").ToUpper();
  listViewWebPartTarget.WebId = webTarget.ID;
  listViewWebPartTarget.TitleUrl = webPartTemplate.TitleUrl.ToString().Replace(siteTemplate.ServerRelativeUrl, siteTarget.ServerRelativeUrl);
  listViewWebPartTarget.Title = webPartTemplate.Title;
  listViewWebPartTarget.ZoneID = webPartTemplate.ZoneID;

  webPartDictTarget.Add(listViewWebPartTarget.ZoneID + webPartTemplate.ZoneIndex.ToString(), listViewWebPartTarget);
}
else
{
  string errorMessage = "";
  webPartTarget = (Microsoft.SharePoint.WebPartPages.WebPart)webPartManagerTarget.ImportWebPart(xmlReader, out errorMessage);

  if (errorMessage != null)
    // log it

  webPartTarget.ChromeType = webPartTemplate.ChromeType;
  webPartTarget.TitleUrl = webPartTemplate.TitleUrl.ToString().Replace(siteTemplate.ServerRelativeUrl, siteTarget.ServerRelativeUrl);
  webPartTarget.Title = webPartTemplate.Title;
  webPartTarget.ZoneID = webPartTemplate.ZoneID;

  webPartDictTarget.Add(webPartTarget.ZoneID + webPartTemplate.ZoneIndex.ToString(), webPartTarget);
}
  }
  catch (Exception ex)
  {
  }
}

// Acquire keys and sort them.
List<string> list = new List<string>(webPartDictTarget.Keys);
list.Sort();

// Loop through keys.
int i = 0;
foreach (var key in list)
{
  try
  {
    Microsoft.SharePoint.WebPartPages.WebPart wpTmp = (Microsoft.SharePoint.WebPartPages.WebPart)webPartDictTarget[key];
    webPartManagerTarget.AddWebPart(wpTmp, wpTmp.ZoneID, i);
  }
  catch (Exception ex)
  {
  }
  i++;
}

The error is thrown on the following line:

webPartManagerTarget.AddWebPart(wpTmp, wpTmp.ZoneID, i);

The stack trace follows {"There was an error generating the XML document."}:

at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id) at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o) at Microsoft.SharePoint.WebPartPages.WebPart.SerializeXml(XmlWriter writer, XmlSerializer xmls, Boolean shouldSerializeAll) at Microsoft.SharePoint.WebPartPages.WebPart.WriteXmlAsBytes(XmlSerializer xmls) at Microsoft.SharePoint.WebPartPages.WebPart.WriteXmlGlobal(Boolean disableSafeControlsCheck) at Microsoft.SharePoint.WebPartPages.BinaryWebPartSerializer.Serialize(PersonalizationScope scope) at Microsoft.SharePoint.WebPartPages.BinaryWebPartSerializer.get_Links() at Microsoft.SharePoint.WebPartPages.SPWebPartManager.AddWebPartToStore(WebPart webPart, Int32 viewId, String viewGuid) at Microsoft.SharePoint.WebPartPages.SPWebPartManager.AddWebPartInternal(SPSupersetWebPart superset, Boolean throwIfLocked) at Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager.AddWebPartInternal(WebPart webPart, String zoneId, Int32 zoneIndex, Boolean throwIfLocked) at Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager.AddWebPart(WebPart webPart, String zoneId, Int32 zoneIndex) at admSitePanelSolution.admSiteCreateCollection.<>c_DisplayClasse.b_c()

And the InnerException {"Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"}:

at Microsoft.SharePoint.SPGlobal.HandleUnauthorizedAccessException(UnauthorizedAccessException ex) at Microsoft.SharePoint.Library.SPRequest.GetViewsSchemaXml(String bstrUrl, String bstrListName, Boolean bFullBlown, ISP2DSafeArrayWriter p2DWriter, Int32& plDefaultViewIndex) at Microsoft.SharePoint.SPViewCollection.EnsureViewSchema(Boolean fullBlownSchema) at Microsoft.SharePoint.SPViewCollection..ctor(SPList list) at Microsoft.SharePoint.SPList.get_Views() at Microsoft.SharePoint.SPList.get_DefaultView() at Microsoft.SharePoint.SPList.get_DefaultViewUrl() at Microsoft.SharePoint.WebPartPages.ListViewWebPart.ShouldSerializeDetailLink() at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterListViewWebPart.Write9_ListViewWebPart(String n, String ns, ListViewWebPart o, Boolean isNullable, Boolean needType) at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterListViewWebPart.Write10_WebPart(Object o)

Can anyone provide some help of why this happens when not logged in as system admin. This whole block also runs inside elevated privileges and the SPSite and SPWeb were also instantiated inside the elevated block. This code is an excerpt.

UPDATE

If I make the user a site collection owner of the base site collection, then the code above runs fine. So what in the code above resets context or needs to reference the base site collection. Thank you.

1

1 Answers

0
votes

And my colleague swoops in to save the day! In SP dev, there is a well known 'hack' which is used a lot when permissions get weird and stupid. It is to nullify the HttpContext. I tried this around the line and loop which was giving me an issue but it appears that you have to place it much higher in the code during the import.

Here is the new fix.

HttpContext currentContext = HttpContext.Current;
HttpContext.Current = null;
listViewWebPartTarget = (Microsoft.SharePoint.WebPartPages.ListViewWebPart)webPartManagerTarget.ImportWebPart(xmlReader, out errorMessage);
HttpContext.Current = currentContext;

This code now works for copying webparts from one apsx page to another. Hope it helps someone.