How do I force a new site collection to inherit a master page? - sharepoint

I have some code that creates a new site in SharePoint. Upon browsing to the newly created site, a File Not Found error is thrown. If you browse to /_layouts/ChangeSiteMasterPage.aspx you can select a new site master & system master page, and the site works fine. This kb article describes my symptoms perfectly: http://support.microsoft.com/kb/936908
My problem is that of the two (maybe three?) solutions given, only one works. If I manually select the new master pages it works fine. The second workaround is to activate the publishing feature on the new site. This does not fix anything.
There is also a recommendation to staple the publishing feature to the site definition I am using for the new site. In my case, this is STS#1 (the blank site), and stapling the publishing feature does not alleviate my problem.
Anyone have an idea of how I can get the correct master page sorted out?

We do this through a delegate control. In the OnLoad we call the following method:
private void ConfigureMasterPage(SPWeb web)
{
string masterURL = string.Empty;
masterURL = web.Site.ServerRelativeUrl + "/_catalogs/masterpage/XXX.master";
masterURL = masterURL.Replace("//", "/");
web.MasterUrl = masterURL;
web.CustomMasterUrl = masterURL;
web.Update();
}
Dont forget to do a dispose of the SPSIte and SPWeb objects and You will have to set AllowUnsafeUpdates to true.
Hope this helps

Turns out I just needed to change the master template in one of the generated sites and then save that as a template. I deleted the broken template and put this in its place. Now all the generated sites work fine.

Related

Collaboration portal approval workflow

The company I work for has recently taken over a SharePoint 2007 project form another company. The other company created a site using the Collaboration Portal Publishing template. Since this is an internet web site, this is causing me a couple of problems.
By default the approval workflow is not activated on the Pages Libraries of the site, and the client requires the workflow to be active on all of the Pages Libraries. The problem is that the site is massive, and doing this manually will take too long, and because it’s such a large site I can’t recreate it from scratch.
Is there a way I can activate the approval workflow on all the Pages Libraries of the site? Could I maybe change something in the site definition? Or is there a way to activate it programmatically? Then I could create a console app that will recursively iterate through the sites and attach the workflow to the Pages Libraries?
Your can try with this code :
using (MossFramework.DocumentLibraryHelper docLibraryHelper = new MossFramework.DocumentLibraryHelper("SITENAME"))
{
using (SPSite site = new SPSite(docLibraryHelper.MossSiteAddress))
{
SPWeb siteCollection = site.OpenWeb();
siteCollection.AllowUnsafeUpdates = true;
SPFolder folder = siteCollection.GetFolder("Document Centre");
SPList list = siteCollection.Lists["Document Centre"];
Guid wfBaseId = new Guid("{5703E6AC-1C65-440F-88DC-EB65F2C6DF82}");
SPWorkflowAssociation wrkFl = list.WorkflowAssociations.GetAssociationByBaseID(wfBaseId);
foreach (SPListItem spListItem in list.Items)
{
site.WorkflowManager.StartWorkflow(spListItem, wrkFl, wrkFl.AssociationData);
// Error occurs here
}
site.Close();
}
}
or
You can try with this
I hope that helps

Deploy two connected webparts in a page layout during feature activation?

I've implemented 2 webparts (deriving from Microsoft.SharePoint.WebPartPages.WebPart, the WSS 3 WebPart), one of which is a provider and the other the consumer (implementing ASP.net connection model, with ConnectionProviderAttribute and ConnectionConsumerAttribute methods).
I managed to deploy them in a feature which also deploys a Page Layout containing two webpart zones, which are themselves populated during the FeatureAvtivated method of the feature receiver, with the 2 newly created webparts. All of this works just fine.
For information, I used this link to make it work. Beware, the method using AllUsersWebPart tag in elements.xml, shown in links like this one (http://www.andrewconnell.com/blog/archive/2007/10/07/Having-Default-Web-Parts-in-new-Pages-Based-Off-Page.aspx) work, but if you deactivate, then reactivate your feature, you just have double webparts in your future pages based on the layout. The method described here (http://sharepoint.coultress.com/2008/06/adding-web-part-to-page-layout.html) just threw me an error when analysing metadata for the layout aspx file (the problem seemed to come from the line in the ZoneTemplate tag).
My next goal is to connect these webparts together right after all this, thus enabling the end user to create pages, based on the layout, containing by default the two webparts connected together (right now everything works except for the connected part).
I tried something like this, using ASP.net connection model (the other one, WSS model, throws logically an error because I'm not implementing the good interfaces). But even though the connection resulting from the "mgr.SPConnectWebParts()" method doesn't throw any exception and actually adds the connection to the connection list of the webpart manager, I can see in debug mode that the connection property 'IsActive" is false (maybe normal), and that when I create a new page based on the layout, the webparts appear not connected.
Any guess? I believe there's something with the fact that the webparts cannot be connected before the page containing them is actually created, but I'm far from sure of it.
Declarative web part connection provisioning is actually quite straightforward:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="Module1">
<File Path="Module1\default.aspx" Url="demo.aspx">
<AllUsersWebPart ID="testProvider">...</AllUsersWebPart>
<AllUsersWebPart ID="testConsumer">...</AllUsersWebPart>
<WebPartConnection ID="testConnection"
ProviderID="testProvider"
ProviderConnectionPointID="providerID"
ConsumerID="testConsumer"
ConsumerConnectionPointID="consumerID" />
</File>
</Module>
</Elements>
Details:
http://blogs.code-counsel.net/Wouter/Lists/Posts/Post.aspx?ID=161
You can find connection point IDs with PowerShell if you first connect your web parts manually:
$web = Get-SPWeb <WebURL>
$wpman = $web.GetLimitedWebPartManager("<PageURL>", [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)
$wpman.SPWebPartConnections
Tried creating the web parts on the page programmatically? You'll have far fewer headaches than trying to do it declaratively.
Look up the SPLimitedWebPartManager class for how to handle web parts on a provisioned page.
Also, web parts in a web part zone are tied to the URL of the page on which they are added. This is by design of the the ASP.NET Web Part Manager.
Thus, if you added web parts to zones on a page layout at directory: http://webapp/sites/site/_catalog/master/mypagelayout.aspx - the web parts will ONLY appear on that page. Createa new page at /sites/site/Pages/MyPage.aspx and the web parts you added before won't appear. The workaround for this is to explicitly add web parts not within web part zones, and this can only be done in an authored page layout (usually in SharePoint Designer).
If the web parts are static in the page layout (and you want them to show in every page) then this is actually easier for you to deploy - just maintain the layout in your source, and have it provisioned via a Module element.
Finally I used another approach to reach my goal. In the OnLoad event of the provider webpart, I check if my page is in edit/new mode, and then check if the page contains the consumer webpart (via the webpartmanager) and if they are not already connected. If this is the case, I connect them.
The code to connect permanently the webparts:
private void SetUpConnections()
{
SPSecurity.RunWithElevatedPrivileges(delegate() {
using (SPSite siteContext = new SPSite(SPContext.Current.Site.ID))
using (SPWeb webContext = siteContext.OpenWeb(siteContext.ServerRelativeUrl))
using (SPLimitedWebPartManager spManager = webContext.GetFile(SPContext.Current.File.Url).GetLimitedWebPartManager(PersonalizationScope.Shared))
{
foreach (Microsoft.SharePoint.WebPartPages.WebPart consumer in spManager.WebParts)
{
if (consumer is MyConsumerWebPart)
{
bool alreadyConnected = false;
Microsoft.SharePoint.WebPartPages.WebPart provider = spManager.WebParts[this.ID] as Microsoft.SharePoint.WebPartPages.WebPart;
foreach (SPWebPartConnection connection in spManager.SPWebPartConnections)
{
if (connection.Provider == provider && connection.Consumer == consumer) { alreadyConnected = true; break; }
}
if (!alreadyConnected)
{
// Connects webparts permanently (but the page would need a reload to display the connection)
ProviderConnectionPoint providerConnectionPoint = spManager.GetProviderConnectionPoints(provider)["MyConnectionProviderInterfaceId"];
ConsumerConnectionPoint consumerConnectionPoint = spManager.GetConsumerConnectionPoints(consumer)["MyConnectionConsumerInterfaceId"];
spManager.SPConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint);
// Connects webparts locally (for current edit mode)
SPWebPartManager currentSPManager = WebPartManager.GetCurrentWebPartManager(this.Page) as SPWebPartManager;
System.Web.UI.WebControls.WebParts.WebPart currentProvider = this;
System.Web.UI.WebControls.WebParts.WebPart currentConsumer = currentSPManager.WebParts[consumer.ID];
ProviderConnectionPoint currentProviderConnectionPoint = currentSPManager.GetProviderConnectionPoints(currentProvider)["SearchBarProvider"];
ConsumerConnectionPoint currentConsumerConnectionPoint = currentSPManager.GetConsumerConnectionPoints(currentConsumer)["SearchBarConsumer"];
currentSPManager.SPConnectWebParts(currentProvider, currentProviderConnectionPoint, currentConsumer, currentConsumerConnectionPoint);
}
}
}
}
});
}
The code to check if the page is in new/edit mode:
if (SPContext.Current.FormContext.FormMode == SPControlMode.New
|| SPContext.Current.FormContext.FormMode == SPControlMode.Edit)
{
this.SetUpConnections();
}

SharePoint 2007 deploy MasterPage as Feature delete files on deactivation

I have a MasterPage that I am deploying to a SharePoint 2007 server. I am using a feature and a wsp to do the deployment. After deployment, my new masterpage isn't available to select and use for my site. Then, if I activate my feature, I am able to select my master page. But, when I deactivate my feature (or even retract the solution and delete it from SharePoint), the master page is still available for selection and all of the other files that were part of my feature/solution are still on SharePoint. So, is there any way to remove the master page from being available when my feature is deactivated, and then if it gets activated again, have it be available again?
Hope this makes sense, thanks.
SharePoint doesn't by default clean up files deployed as part of a feature activation.
In order to remove the master page and other associated files you'll need to write a feature receiver for your feature, implement the FeatureDeactivating method, and remove your files using object model code instead of CAML. MSDN document for feature receivers is here, and there are blog examples of writing feature receiver code all over the web.
Bear in mind that in order to remove your master page you'll first need to make sure you reset the master page for all sites in the site collection to the default/another available master page. You'll also want to be careful not to remove resource files (CSS, images, etc.) that are shared among master pages or page layouts.
First make sure you are not using the Master page anymore in the feature deactivating. Then you can remove it.
SPWeb web = (SPWeb)properties.Feature.Parent;
string customMasterUrl = (new Uri(web.Url + "/_catalogs/masterpage/Sample.master")).AbsolutePath;
if (web.MasterUrl != customMasterUrl)
{
try
{
SPFile file = web.GetFile(customMasterUrl);
SPFolder masterPageGallery = file.ParentFolder;
SPFolder temp = masterPageGallery.SubFolders.Add("Temp");
file.MoveTo(temp.Url + "/" + file.Name);
temp.Delete();
}
catch (ArgumentException)
{
return;
}
}

No current context when creating a sharepoint site

I've added a feature to my onet.xml file which gets activated whenever a site gets created. However, that feature needs to know the url of the site being created. I thought I could figure that out from the current SPContext within the activation event of the feature, but when I created the site I got a null reference on SPContext.Current.
Is that to be expected, or have I done something wrong? If that is the case, does anyone have any suggestions how I can dynamically learn the URL of the site being created?
Thanks
It seems like you have created a feature receiver? They don't use SPContext but find the site they have been activated on through the properties, like so:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
using (SPWeb web = properties.Feature.Parent as SPWeb)
{...}
}

SharePoint Development Permissions

Hi I am using the SharePoint namespace to pull items from various lists throughout the site. My web part works, but only on my account. When I try it on another account it gives me "Error: Access Denied" for the page. I have taken all web parts out and have only this web part on the page. When I remove the following lines the page loads for everyone, when I add it back in however it does not work. I am guessing this is some permission problem. I was wondering is there away to programatically query different lists on SharePoint by assigning a user id to use? Thank you for any help
...
SPSite site = new SPSite(_SPSite);
SPWeb eachWeb = site.AllWebs[0];
SPListItemCollection myItemCollection = eachWeb.Lists["Listings"].Items;
...
You're correct, the access denied error is occurring when you're using an account which does not have access to the "Listings" list in the current website.
The easiest way around the issue is to use a SPSecurity.RunWithElevatedPrivleges call:
SPSecurity.RunWithElevatedPrivleges(delegate()
{
//Your code here
});
which will run whatever code is contained in the anonymous method using the SharePoint/System account, granting complete control. Be careful when using this technique though, as it equivalent to running code at full trust with a super user account. There are other caveats to be aware of as well.
Try:
SPWeb eachWeb = SPContext.Current.Site.RootWeb.Webs[0];
SPListItemCollection myItemCollection = eachWeb.Lists["Listings"].Items;
Remember that SPWeb should be used in a using block, or disposed of explicitly after use.
As regards the first caveat from EvilGoatBob, I quote:
"If you're manipulating any Object Model elements within your elevated method, you need to get a fresh SPSite reference inside this call. For example
SPSecurity.RunWithElevatedPrivileges(delegate(){
SPSite mySite = new SPSite(http://sharepoint/);
SPWeb myWeb = SPSite.OpenWeb();
// further implementation omitted
});"
Notice that the site parameter is hard-coded - this is because of a bug. If you instead had tried:
using (SPSite site = new SPSite("http://" + System.Environment.MachineName)) {}
You would get the rather generic "No SharePoint Site exists at the specified URL..." error. This caused me no end of grief. Bottom line is that you have to hard-code the server name (unless anyone has an alternative). You can also get a similar error message when debugging Web Parts for the first time with VSeWSS 1.3.
You do not need to hardcode the server name in this case because your requirement is to retrieve items from list inside the same site as your webpart. You are correct, if you do not have enough privileges with your account, then you get the Access Denied. The solution is to create a new SPSite object within a different security context, and do your work:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(SPContext.Current.Site.Url))
{
using (SPWeb web = site.OpenWeb())
{
//the web object was retrieved with elevated privileges under the system account.
//do your work here:
SPListItemCollection myItemCollection = web.Lists["Listings"].Items;
//...
}
}
}
);
With the code above, your webpart is portable because there's no hardcoding, and runs in the correct security context while disposing of all unmanaged SPRequest objects created by the SPSite and SPWeb constructors.

Resources