Apr 12

I've always wondered why SP 2010 document libraries has an Add Document but not a New Document link on their document libraries. Probably because they don't expect users to click on New Document very often and only expect users to Add Documents (upload documents from their PC to the document library).

Anyway, the client has these custom word templates and they require users to use these word templates when creating new documents. This means their process requires users to click on New Document everytime they want to place something in the document library. So to make things easier for them, I have added a Content Editor web part and added code to it that would allow users to click the link to create the document based off the template.

<IMG alt="" src="/_layouts/images/rect.gif">&nbsp;<a href="#" onclick="createNewDocumentWithProgID('http:\u002f\u002fintranet\u002fDocument Library\u002fForms\u002fDocument Template.dotx', 'http:\u002f\u002fintranet\u002fDocument Library', 'SharePoint.OpenDocuments', false)">New Document</a>

&nbsp;&nbsp;&nbsp;

<span style="height:10px;width:10px;position:relative;display:inline-block;overflow:hidden;"><img src="/_layouts/images/fgimg.png" alt="" style="left:-0px !important;top:-128px !important;position:absolute;" /></span>&nbsp;<a id="idHomePageNewDocument" href="http://intranet/_layouts/Upload.aspx?List={DocLibGUID}&amp;RootFolder=" onclick="javascript:NewItem2(event, &quot;http://intranet/_layouts/Upload.aspx?List={DocLibGUID}&amp;RootFolder=&quot;);javascript:return false;" target="_self">Add document</a>

Don't forget to edit the DocLibGUID with the GUID to the document library in order for the Add document link to work. Remember to also check the path to the document libraries and templates.

Using the same method, we can replicate everything in the ribbon on the site itself. This way, the client has an option to hide the ribbon and have more control over what options are available to different groups of users.

Mar 1

I've removed the .exe file extension from the Blocked File List in SharePoint Central Admin (Security > Define blocked file types). This allowed me to upload .exe files to document libraries but when I click on the .exe file to download it, I get a 404 Page not found error. I can download it if I click the drop down and select download, or if I go into Explorer view, but it's a Page not Found error when I click on the .exe file itself.

The issue is not with SharePoint. I found that the problem is with IIS.

If you are using IIS6, then to resolve, you do the following:

  1. Open IIS
  2. Right click on the website in question
  3. Click Properties
  4. Choose the Home Directory
  5. Look for the Execute Permissions drop down list
  6. Set it to "Scripts Only"

If you are using IIS7, then to resolve, you do the following:

  1. Open IIS
  2. Select the website in question
  3. Double Click on Handler Mappings
  4. Click on Edit feature permissions (on the right navigation)
  5. Uncheck the Execute checkbox
  6. Click OK

This will automatically recycle the app pool and you can now click on the executable file and you will be prompted to download it.

WARNING: There are some shortfalls to this method, click here to read more and for a way to circumvent the shortfalls.

Feb 17
Word 2010 Retrieve and Set Properties
Posted by Wei in C#, SharePoint, VSTO on 02 17th, 2011| | No Comments »

There are 3 types of properties for Word Documents... that's right, 3. Not 2. Initially I thought there are the Built in properties and the custom properties. But then, there are also content type properties.

I'm not sure how to explain this, but I'll do my best. Content Type properties are set in SharePoint. A custom content type is created and this custom content type inherits columns which are also set in SharePoint. I won't go into detail about how that is set up but it requires you to Allow Management of Content Types for the document library.

Once that is done and the columns added for this content type, they will appear as Content Type properties in the Word document. This means that when the user opens the word document, they can see the custom content types available for them to fill in.

Whatever the user enters into these custom content type properties will be saved into the columns of the list when the user saves the document. Note that if the user saves the document as a PDF, the columns will not be populated with the properties.

Anyway, to go back on to my topic of how to retrieve all 3 types of properties, here is the code:

Microsoft.Office.Interop.Word.Document currentDocument = Globals.ThisAddIn.Application.ActiveDocument;

DocumentProperties builtInDocProperties = (DocumentProperties)currentDocument.BuiltInDocumentProperties;
DocumentProperties customDocProperties = (DocumentProperties)currentDocument.CustomDocumentProperties;
MetaProperties contentTypeProperties = (MetaProperties)currentDocument.ContentTypeProperties;

// for each of these properties, I placed them in a Hashtable for ease of querying later
Hashtable htProperties = new Hashtable();

try
{
    foreach (MetaProperty prop in contentTypeProperties)
    {
        try
        {
            htProperties.Add(prop.Name, prop.Value);
        }
        catch { } // some property names/values cause exceptions, which is why I have this here
    }
}
catch
{
    // no content type properties found in this document
}

foreach (DocumentProperty prop in builtInDocProperties)
{
    try
    {
        htProperties.Add(prop.Name, prop.Value);
    }
    catch { }
}

foreach (DocumentProperty prop in customDocProperties)
{
    try
    {
        htProperties.Add(prop.Name, prop.Value);
    }
    catch { }
}

Now all the properties can be queried from the Hashtable htProperties.

For example, to get the title, you would use htProperties["Title"].ToString(). To get a custom property named "Favourite Colour", you would use htProperties["Favourite Colour"].ToString(). These properties are objects and need to be cast to the right variable type. Such as (DateTime)htProperties["BirthDate"].

To set the value of a property via code, you would need to know the name of the property and the type of property, be it a BuiltInDocumentProperty, a CustomDocumentProperty or a MetaProperty (content type property).

MetaProperty mp = contentTypeProperties["Favourite Colour"];
mp.Value = "Blue";

Feb 17

Usually most of my code is run on the server, meaning that the DLLs sit on the server. This means that I can use the Microsoft.SharePoint DLL to query SP lists, SP document libraries, and so on.

My last project required me to code a Word Add-in. This is a client side application that required a connection to SharePoint to query a SP list. This means that I am no longer able to use Microsoft.SharePoint DLL to query the list as that is only for server side code. I was aware that I had to use the Microsoft.SharePoint.Client and Microsoft.SharePoint.Client.Runtime DLLs but they did not exist in the .NET references list, so I was not able to add them (the list is filtered based on the type of app you are writing).

I did notice that the filter was set to ".NET Framework 4 Client Profile". I modified that to ".NET Framework 4" (in the Project Properties) and was then able to add the required DLL references.

The code to query the list on the client side is also quite different to querying the list on the server side.

Here's the code to query a list on the client side:

using SP = Microsoft.SharePoint.Client; // Make sure you have added the reference to Microsoft.SharePoint.Client
string sharePointSite = "http://intranet";
string siteName = "/site/subsite";
string listName = "MyListName";

SP.ClientContext ctx = new SP.ClientContext(sharePointSite + siteName);
var web = ctx.Web;
SP.List oList = web.Lists.GetByTitle(listName);

SP.CamlQuery oQuery = new SP.CamlQuery();
// the following query queries everything in the list ordered by ID and limited to 100 results
oQuery.ViewXml = "<View><Query><OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy></Query><RowLimit>100</RowLimit></View>";
SP.ListItemCollection oListItems = oList.GetItems(oQuery);

ctx.Load(oListItems);

ctx.ExecuteQuery();

for (int i = 0; i < oListItems.Count; i++)
{
    SP.ListItem oListItem = oListItems[i];

    // do what you want with oListItem as it now contains the values in the list item.
}

Nov 10

I was having some difficulty setting up User Profile imports from AD recently and it took me a while to figure out what I was doing wrong. Because I was working on a VM, that also gave me a headache. Although Virtual Machines are great (if you make a disastrous mistake and need to revert back), they also, for some reason, cuts off the connection to AD when it is reverted back. So each time I reverted, I needed to re-set the connection to the domain.

I'm not sure if this would help, but here's what I had to do to get the user profile synchronization service started in SP 2010 and to import users from AD.

When you initially installed SharePoint, make sure you use a service account that has access to AD. Let's call this account DOMAIN\svc-spadaccess (short for SharePoint Active Directory Acess). Make sure that this user is in the Farm Administrators group (in Central Admin).

Once SharePoint is installed, in Central Admin, click on Security > Configure Service Accounts.

 

Where it says Select one..., choose Windows Service - User Profile Synchronization Service. Where it says Select an account for this component, select DOMAIN\svc-spadaccess. If you don't see it there, then you need to click on Register new managed account to register it.

Click OK. If for some reason you get an error that looks like "An object of the type Microsoft.SharePoint.Administration.SPWindowsServiceCredentialDeployment JobDefinition named "windows-service'credentials-FIMSynchronizationService" already exists under the parent Microsoft.Office.Server.Administration.ProfileSynchronizationService named "FIMSynchronizationService". Rename your object or delete the existing object." then you need to do what it says and remove it. Click on Monitoring > Review job definitions (under Timer Jobs) and look for "Windows Service "FIMSynchronizationService" Credential Deployment". Click on it and click on Delete. Then try again.

Once you have done that, you need to set the Farm Account (from the same Select one... dropdown in the image above) to use DOMAIN\svc-spadaccess and click OK.

When I do that, I would get a 503 error. When you changed the farm administrator, the Application Pool identity for the SharePoint Central Administration v4 app pool also changes. For some reason, this causes the application pool to stop and refuse to start. I'm not sure if this is the best fix, but I found that when I clicked on Advanced Settings for that application pool and edit the Identity by re-entering the username and password again, then trying to start the app pool, it actually starts.

Next, we need to start the User Profile Synchronization Service. Click on Application Management > Manage services on server. The status for the User Profile Synchronization Service should be Stopped. Click on Start and you are prompted to log in to DOMAIN\svc-spadaccess. Once you log in, it should start after a few minutes (could take about 10 minutes). I find that this isn't the case and it hangs on "Starting" indefinitely. On checking the event logs, I see this error:

Error provisioning the local timer service instance during deploying of administration application pool credentials, please provision manually. The password for the account DOMAIN\svc-spadaccess, as currently stored in SharePoint, is not the same as the current password for the account within Active Directory. To fix this with PowerShell, run Set-SPManagedAccount -UseExistingPassword.

To fix, I had to go to Start > Administrative Tools > Services and select the SharePoint 2010 Timer. It wasn't started in my case and when I try to start it, I get the login error. As with the application pool, I had to re-enter my password and start the service in order to get it to run.

Now when I go back to Central Admin the status is still stuck on "Starting" and there is no way for me to stop it. So I had to start the SharePoint 2010 Management Shell, type in get-spserviceinstance to get a list of all the GUIDs. Copy the GUID for the User Profile Synchronization Service (which should have its Status as Provisioning) and enter stop-spserviceinstance <GUID> to stop the service. Once you have done that, you can go back into Central Admin and you'll notice that you can try to Start the service again.

Click on Start, enter your password and 10 minutes later, it should be running.

After the service starts, you can go ahead and configure the AD import. Click on Application Management > Manage Service Applications > User Profile Service Application > Configure Synchronization Connections and Create New Connection. If you are getting an Unknown Error when you try to do this, then do an iisreset before coming back here. You might have to wait a couple of minutes after logging back in to see this section working.

Enter all the relevant details to your connection but use the Account name DOMAIN\svc-spadaccess to access AD. Click on Populate Containers, select what you want to import and click ok. Then go back, Click on Application Management > Manage Service Applications > User Profile Service Application and Start Profile Synchronization which should import all user details from what you selected in the Container into SP 2010.

« Previous Entries Next Entries »