January 3, 2012 - 07:20, by Steven Van de Craen
Categories: SharePoint 2007
You can configure the permission level of anonymous users to allow for viewing versions of documents and items, but no matter what you do, they get prompted for credentials.
The Version History page has the property “AllowAnonymousAccess” set to false. It is a virtual property in the Microsoft.SharePoint.ApplicationPages.UnsecuredLayoutsPageBase class that needs to be overridden in those layout pages that should be visible for anonymous users.
SharePoint 2007
The solution is an identical copy of the original Version History page of SharePoint 2007 but with the aforementioned property set to true.
The farm solution contains the page and a Site Collection Feature for activation which will add links to the page in the Toolbar and ECB menu for Document Libraries and Lists. You could hide or replace the link to the original page, but that isn’t straight-forward using CustomAction elements.
Installation and activation
Download from here (Ventigrate Codeplex Repository)
Deploy the WSP (farm solution) to the SharePoint Farm
STSADM -o addsolution -filename Ventigrate.Shared.AnonymousVersionHistory.wsp
STSADM -o deploysolution -name Ventigrate.Shared.AnonymousVersionHistory.wsp -allowgacdeployment -immediate
Activate the Site Collection Feature where you want this functionality
SharePoint 2010
SharePoint 2010 suffers from the same issue. You need to adapt the above solution to make it work for SharePoint 2010
- Copy the markup of the SharePoint 2010 Version History page (and add the property override)
- Adapt the CustomAction elements to add links to UI elements for SharePoint 2010 (and optional Dialog UI)
October 19, 2011 - 12:01, by Steven Van de Craen
Categories: SharePoint 2007, SharePoint 2010, Content Types
Ever enabled Content Types on a library, removed the default “Document” Content Type and then added your own document Content Type ? If you do it in that order it will set “Folder” as the Content Type for uploaded files.
There’s no apparent way in the user interface to change the default Content Type, since “Folder” is not visible in the list:
If you don’t have a lot of lists already or you can only access SharePoint through the browser, the quickest way to fix this is to add the default “Document” Content Type to the list and immediately remove it again.
If (like in my case) you already have a lot of lists, you can script the Content Type Ordering:
using (SPSite site = new SPSite(url)) { foreach (SPWeb web in site.AllWebs) { foreach (SPList list in web.GetListsOfType(SPBaseType.DocumentLibrary)) { if (list.ContentTypes["Main Document"] != null) { SPFolder folder = list.RootFolder; List<SPContentType> lstCT = new List<SPContentType>(); lstCT.Add(list.ContentTypes["Main Document"]); folder.UniqueContentTypeOrder = lstCT; folder.Update(); } } web.Close(); } }
The above code loops all libraries on all sites in a Site Collection and sets my “Main Document” Content Type as the only (and default) Content Type. If you have different needs feel free to adapt as required.
October 13, 2011 - 12:04, by Steven Van de Craen
Categories: General, SharePoint 2007, SharePoint 2010
If you happen to change the Windows Time Zone settings AFTER Central Administration has been provisioned, you will see that the time zone/date format is not updated in the administration pages:
Luckily, the fix is quite easy. You can just update the Regional Settings of the Central Administration site. Since this option is hidden from the Site Settings, you’ll have to navigate to it manually:
http://[centraladministration/_layouts/regionalsetng.aspx
Here’s a sample of setting it to Brussels time zone and Dutch Locale:
As you can see only the Time Zone is taken into account while format is still using US Locale. This only applies for certain Administration Pages such as Search Administration. The “Timer Job Status” page for example shows the specified (Dutch) format:
August 25, 2011 - 17:28, by Steven Van de Craen
Categories: InfoPath, SharePoint 2003, SharePoint 2007, SharePoint 2010
A short blog on how the Promoted Fields seem to behave for InfoPath forms stored in SharePoint.
They are created as fields (Date, Text, …) and have the XPath property configured to the field in InfoPath (example: /my:myFields/my:field1)
When the form is stored in the library, the value of the XPath’s InnerText is stored in the List Item. It is by no means a live evaluation of the XPath.
Through code one can update the XPath value of the SPField. This does not affect existing forms since the value is persisted during form save, only new forms are affected.
SPSite site = new SPSite(url); SPWeb web = site.OpenWeb(); SPList list = web.GetList(url); SPField field = list.Fields["Field1"]; field.XPath = "/my:myFields/my:field1"; field.Update();
When you set the XPath to an element that has child elements, the InnerText will render all the elements contents as you’d expect:
value 1
value 2
When the XPath is set to "/my:myFields”, the Promoted Field value will be “\n\t11\n\t22\n” (it preserves indents).
That’s all for this quick blog post !
March 11, 2011 - 18:17, by Steven Van de Craen
Categories: Debugging, SharePoint 2007, SharePoint 2010
Each SharePoint List can be altered with a custom DispForm.aspx, EditForm.aspx and NewForm.aspx to display, edit or create list items and metadata. This post is about restoring them to a working point.
Botched Forms
So one of these forms are edited to a loss state or deleted altogether. If this is the case it will have some tangible effects on the List display:
The above screen shows a botched Display Form where the Item Url shows http://moss/?ID=1
Behind the scene
All three forms are based on the same template {SharePointRoot}\TEMPLATE\Pages\form.aspx and have a List Form Web Part in the “Main” WebPartZone with specific settings to connect to the list and which function they have. Also, the ID property of the List Form Web Part must match the value of the __WebPartId attribute.
SharePoint 2007
|
SharePoint 2010 |
|
|
Recovery
In a perfect world you can reset the edited form to the Site Definition or restore the it from the Recycle Bin, however this is often not the case.
Here’s a quick reference to the Microsoft.SharePoint.PAGETYPE enum:
Member name
|
Description
|
PAGE_INVALID
|
Not used. Value= -1.
|
PAGE_DEFAULTVIEW
|
Default view. Value=0.
|
PAGE_NORMALVIEW
|
Normal view. Value=1.
|
PAGE_DIALOGVIEW
|
File dialog box view. Value=2.
|
PAGE_VIEW
|
View, including both default view and normal view. Value=3.
|
PAGE_DISPLAYFORM
|
Display form for list items. Value=4.
|
PAGE_DISPLAYFORMDIALOG
|
Display form for a file dialog box. Value=5.
|
PAGE_EDITFORM
|
Edit form for list items. Value=6.
|
PAGE_EDITFORMDIALOG
|
Edit form for a file dialog box. Value=7.
|
PAGE_NEWFORM
|
New form for list items. Value=8.
|
PAGE_NEWFORMDIALOG
|
New form for a file dialog box. Value=9.
|
PAGE_SOLUTIONFORM
|
Solution form. Value=10.
|
PAGE_MAXITEMS
|
Not used. Value=11.
|
(http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.pagetype.aspx)
I’ve highlighted the three related to this matter (applies to both SharePoint 2007 and SharePoint 2010).
Manually
1. It’s easiest if you take a corresponding form from another SharePoint List in the site and export it (SharePoint Designer) or just copy it to a text editor. This way, most of the settings of the List Form Web Part are already correct
2. Generate a new GUID and fill that in for the __WebPartId and properties of the List Form Web Part markup. It has to be the same GUID but the formatting is different. See the above screens for samples
3. Update the property with the List ID you’re targeting
4. Verify all other properties of the List Form Web Part and save the file as either DispForm.aspx, EditForm.aspx or NewForm.aspx
5. Import (SharePoint Designer) the page (or paste contents from the text editor)
Scripted
I had a botched list in SharePoint 2007 and I wrote a Console Application for it. It takes the markup for a Form and I’ve replaced some values with placeholders already. It connects to the List and replaces the placeholders with real values, then it saves the file to SharePoint.
1 string listUrl = "http://moss/Lists/Sample List"; 2 using (SPSite site = new SPSite(listUrl)) 3 { 4 using (SPWeb web = site.OpenWeb()) 5 { 6 SPList list = web.GetList(listUrl); 7 RestoreListForm(list, PAGETYPE.PAGE_DISPLAYFORM); 8 //RestoreListForm(list, PAGETYPE.PAGE_EDITFORM); 9 //RestoreListForm(list, PAGETYPE.PAGE_NEWFORM); 10 } 11 }
1 private static void RestoreListForm(SPList list, PAGETYPE ptype) 2 { 3 SPWeb web = list.ParentWeb; 4 5 // Create Form File 6 string formFilename = null; 7 SPControlMode formMode = SPControlMode.Invalid; 8 SPFileCollection files = list.RootFolder.Files; 9 Guid wpId = Guid.NewGuid(); 10 CalcFormInfo(ptype, out formFilename, out formMode); 11 12 byte[] formContents = Encoding.ASCII.GetBytes(String.Format(pagecontent, list.Title, list.ID.ToString("B"), formMode, (int)ptype, wpId.ToString("B"), String.Concat("g_", wpId.ToString("D").Replace("-", "_")).ToLower())); 13 14 try 15 { 16 if (files[formFilename].Exists) 17 files[formFilename].Delete(); 18 } 19 catch { } 20 21 SPFile formFile = files.Add(formFilename, formContents, true); 22 } 23 24 private static void CalcFormInfo(PAGETYPE type, out string fileName, out SPControlMode mode) 25 { 26 switch (type) 27 { 28 case PAGETYPE.PAGE_DISPLAYFORM: 29 fileName = "DispForm.aspx"; 30 mode = SPControlMode.Display; 31 break; 32 case PAGETYPE.PAGE_EDITFORM: 33 fileName = "EditForm.aspx"; 34 mode = SPControlMode.Edit; 35 break; 36 case PAGETYPE.PAGE_NEWFORM: 37 fileName = "NewForm.aspx"; 38 mode = SPControlMode.New; 39 break; 40 default: 41 fileName = null; 42 mode = SPControlMode.Invalid; 43 break; 44 } 45 }
Find the complete code here: Program.cs. Note that there’s a different page markup and additional properties for SharePoint 2010 and the code needs to be adapted to that.
There’s no magic in the code above, just automating some of the manual steps in a quick fix script.
Conclusion
As a general practice, don’t directly modify the default forms, rather create copies or blank forms and update the List or Content Type Settings (through SharePoint Designer or programmatically) to point to your custom forms.
If you do have a botched list, hopefully the above information can be of help.
March 8, 2011 - 10:28, by Steven Van de Craen
Categories: SharePoint 2007, SharePoint 2010, InfoPath, Forms Server
InfoPath Form Template URL
We have a solution that makes extensive use of online and offline InfoPath forms in a MOSS 2007 environment. An upgrade to SharePoint 2010 is due in a few months, including a redesign of Managed Paths and Site Collection ‘hierarchy’ having a direct effect on the URL of our Site Collection.
I thought this meant a lot of work for converting the thousands of InfoPath XML Forms by script, because they all contained an absolute URL to the InfoPath Form Template.
However as it seems after restoring the Site Collection all forms automagically had a corrected absolute URL to their template !!
xml version="1.0"?>
mso-infoPathSolution productVersion="12.0.0" PIVersion="1.0.0.0" href="https://public.contoso.com/sites/csapp/FormServerTemplates/LeaveRequest.xsn" name="urn:schemas-microsoft-com:office:infopath:LeaveRequest:-myXSD-2009-05-29T07-59-01" solutionVersion="1.0.0.422" ?>
mso-application progid="InfoPath.Document" versionProgid="InfoPath.Document.2"?>
<my:Data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dfs="http://schemas.microsoft.com/office/infopath/2003/dataFormSolution"
xmlns:tns="http://public.contoso.com/webservices"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2009-05-29T07:59:01"
xmlns:xd="http://schemas.microsoft.com/office/infopath/2003"
xml:lang="nl-be">
my:Data>
Default Alternate Access Mapping
What happens is that when you restore a Site Collection backup, it looks up the Web Application by the URL you specified as a parameter. From that Web Application, it takes the Alternate Mapping configured on the "Default” Zone and uses that URL to construct the absolute URL in the InfoPath XMLs.
Only at restore time
This mechanism only seems to trigger when the restore takes place. Changing the Default AAM afterwards to a different URL has no effect. You could temporarily change the AAM for the restore operation and then set it back if you want. Beats any script iterating and updating all Form XMLs any day.
Most of the times you expect the worst from SharePoint, but then it catches you by surprise and brings a huge smile to the face :)
March 6, 2011 - 07:41, by Steven Van de Craen
Categories: SharePoint 2007, SharePoint 2010, Sandbox Solutions
Property Bag
SPWeb exposes two ways of interacting with the property bag:
-
SPWeb.Properties exposes a Microsoft.SharePoint.Utilities.SPPropertyBag
-
SPWeb.AllProperties exposes a System.Collections.Hashtable
The former is considered legacy, also it stores the Key value as lowercase, while the latter keeps the casing of Key and Value intact.
Here’s a code sample:
1 string url = "http://intranet"; 2 3 using (SPSite site = new SPSite(url)) 4 { 5 SPWeb w = site.OpenWeb(); 6 w.AllProperties.Add("First Key", "First Value"); 7 w.Update(); 8 9 SPPropertyBag p = w.Properties; 10 p.Add("Second Key", "Second Value"); 11 p.Update(); 12 }
You can see the properties for a web using SharePoint Designer:
SharePoint 2007:
SharePoint 2010:
Case matters
When you configure a Search Center in the Site Collection Settings, a property named “SRCH_ENH_FTR_URL” stores the location to the Search Center. If this property isn’t entirely uppercase, it won’t be picked up correctly.
Sandbox Solutions
So what about Sandbox Solutions in SharePoint 2010 ?
- SPWeb.AllProperties can only be read from. Updating it doesn’t throw any exceptions but has no effects either.
- SPWeb.Properties cannot be used and throws a TypeLoadException:
March 4, 2011 - 17:23, by Steven Van de Craen
Categories: .NET, SharePoint 2007, SharePoint 2010, Custom Field Types
Custom Field Types are a rather advanced topic, but very powerful as well. They allow for real integration of custom components inside standard List and Library rendering. (See my other posts on Custom Field Types)
There are some things you can run into. Especially if you have custom Lookup Field Types like Cascading Lookup or Connected Lookup. Here’s what I’ve learned from a recent issue migration one from 2007 to 2010.
Custom Properties
Storing additional information in your Custom Field Types was always a real pain. The mechanism had serious flaws and it required some really dirty programming to work with. So instead I store my custom properties the same way SharePoint does. The involved API is internal but can be exposed through reflection.
I’m adding the this ‘reimplementation’ to every Custom Field Type of mine. When providing a null value to SetCustomProperty, the attribute is removed from the field XML.
1 #region Reimplementation of Get/Set Custom Property 2 public new void SetCustomProperty(string propertyName, object propertyValue) 3 { 4 Type type = typeof(SPField); 5 if (propertyValue != null) 6 { 7 MethodInfo set = type.GetMethod("SetFieldAttributeValue", BindingFlags.NonPublic | BindingFlags.Instance); 8 set.Invoke(this, new object[] { propertyName, propertyValue.ToString() }); 9 } 10 else 11 { 12 MethodInfo remove = type.GetMethod("RemoveFieldAttributeValue", BindingFlags.NonPublic | BindingFlags.Instance); 13 remove.Invoke(this, new object[] { propertyName }); 14 } 15 } 16 public new string GetCustomProperty(string propertyName) 17 { 18 Type type = typeof(SPField); 19 MethodInfo getField = type.GetMethod("GetFieldAttributeValue", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(String) }, null); 20 object o = getField.Invoke(this, new object[] { propertyName }); 21 return o as String; 22 } 23 #endregion
Now there’s also no more need to predefine custom properties in the FLDTYPES_*.xml either. This applies to any type of Custom Field Type.
AllowMultipleValues
You might see in some cases that when you set the value of SPFieldLookup.AllowMultipleValues to true, your custom field is reverted to a standard Lookup field.
If this is the case, you could override that Property and implement it accordingly.
1 private bool _allowMulti = false; 2 public override bool AllowMultipleValues 3 { 4 get 5 { 6 bool.TryParse(GetCustomProperty("AllowMultipleValues"), out _allowMulti); 7 return _allowMulti; 8 } 9 set 10 { 11 if (this.AllowMultipleValues != value) 12 { 13 _allowMulti = value; 14 SetCustomProperty("AllowMultipleValues", _allowMulti.ToString()); 15 if (value) 16 { 17 SetCustomProperty("Mult", "TRUE"); 18 SetCustomProperty("Sortable", "FALSE"); 19 } 20 else 21 { 22 SetCustomProperty("Mult", "FALSE"); 23 SetCustomProperty("Sortable", "TRUE"); 24 } 25 } 26 } 27 }
This applies to custom Multi Lookup Field Types.
Note: could not reproduce the issue with a new custom lookup field type in a clean SharePoint 2010 environment…
AllowBaseTypeRendering
We’ve seen this issue in a recent migration from SharePoint 2007 to SharePoint 2010 for a custom developed Connected Lookup Field (Single and Multi Valued). The field was ported from SharePoint 2007 with the following FLDTYPES_*.xml configuration:
The AllowBaseTypeRendering attribute will default to the rendering of the Base Type (in this case Lookup) when the Custom Field Type cannot be determined.
This had the weird effect that these fields would not render or store *any* value selected in a Multi Valued Field of this type. This behaviour might only be occuring when there’s a custom RenderPattern defined for the Custom Field Type.
In either way we had to remove the attribute for SharePoint 2010, since we really required the RenderPattern. Problem solved for new fields, but there was still an issue for existing fields (existing SharePoint 2007 content migrated to SharePoint 2010).
For those existing fields, we wrote a script that would remove the attribute causing the problem:
1 SPList list = web.GetList(listUrl); 2 SPField field = list.Fields["MyMULTI"]; 3 MyField clf = field as MyField; 4 clf.SetCustomProperty("BaseRenderingType", null); 5 clf.Update();
This is where the custom SetCustomProperty came in handy for removing the BaseRenderingType attribute (added because the Custom Field Type had the AllowBaseTypeRendering attribute).
In our case we knew exactly where the fields were that had our Custom Field Type, but it might be more difficult to write a generic script to find all fields based on the Custom Field Type…
Note: could not reproduce the issue with a new custom lookup field type in a clean SharePoint 2010 environment…
Enforce unique values
You can force unique values on fields in SharePoint 2010, however is is not compatible when storing multiple values.
If this is the case your custom “edit field control” should disable the option to “Enforce unique values” via JavaScript.
Oh, and for those wondering: you still can’t do cross site collection lookups with a lookup field. Which makes me wonder how that works in regard to the Content Type Hub.
February 22, 2011 - 10:39, by Steven Van de Craen
Categories: SharePoint 2007, SharePoint 2010, Office 2007, Office 2010
February 12, 2011 - 10:58, by Steven Van de Craen
Categories: SharePoint 2007, SharePoint 2010, FBA, Claims
Both in SharePoint 2007 and SharePoint 2010 policies can be defined where you grant or deny permissions to specific users on Web Application level. This overrules any permissions the user may or may not have on a Site Collection, Site, List or Item level.
For example: the Search Crawl Account (Content Access Account) will be given Full Read on all Web Applications to ensure all content is indexed.
In this section you have the option to check “Account operates as System”. This effectively hides the real user name and masks it as “System Account”.
Only for Windows Accounts
During experiments with Forms Based Authentication (in SharePoint 2010 through Claims Based Authentication), I found that while it is possible to give policy permissions to a non-Windows User, it is not possible to make it “operate as System”.
The SharePoint Logs confirmed that the underlying mechanism is really looking at Windows User Account Management to perform the lookup:
System.ComponentModel.Win32Exception: i:0#.f|fbamembershipprovider|demouser1 at Microsoft.SharePoint.Win32.SPAdvApi32.LookupAccountName(String strAccountName, String& strDomainName, SID_NAME_USE& sidUse) at Microsoft.SharePoint.Administration.SPPolicy.set_IsSystemUser(Boolean value)
Next >>