Friday, December 18, 2009

FullTextSqlQuery People search annoyance resolved

Ok, here's an easy one. A lot of us leverage the FullTextSqlQuery class to perform our People searches. Well, one annoyance I find is revealing the proper syntax to return the property values. There's generally no good references since People search varies from farm to farm. So what do you do? Well, you can look through all the Managed Properties in SSP to find them, or you could implement a method that could return the properties you need based on Display name. I prefer the latter since it takes the grunt work out of sifting through hundreds of records.

On to the solution. So by leveraging the UserProfileManager, you can get an instance of the PropertyCollection class and voila! A quick loop through the collection will get you the property you need. Here goes...


static string GetProfileMatchingProperty(string propertyDisplayName)
{
UserProfileManager oSPManager = new UserProfileManager(ServerContext.Default, true);

Microsoft.Office.Server.UserProfiles.PropertyCollection profileProperties =
oSPManager.Properties;

foreach (Property profProperty in profileProperties)
{
if (profProperty.DisplayName.ToLower(System.Globalization.CultureInfo.InvariantCulture) ==
propertyDisplayName.ToLower(System.Globalization.CultureInfo.InvariantCulture))
return profProperty.ManagedPropertyName;
}

throw new Exception("Couldn't find it. Sorry.");
}

Friday, December 11, 2009

Working with SPFieldChoice type

This may come as a no-brainer for some, but I thought I'd share it in any case. So, there may be times in a developers life that they need to write some functionality that fiddles around with SPList objects. Within those SPList objects, you may have a field derived from SPFieldChoice type. I'm not going to make this a note about how to derive the current value since that is ultimately a trivial task, but what I will do is talk about defaulting values programmatically (again, probably something trivial for most, but then again, maybe something you don't think about).

Ok, so let's say that you wrote a webpart that has to apply default values to an SPListItem. And within that SPListItem, say you have an SPFieldChoice type. Of course, within SharePoint, you can declare you're own default values, but say you want to buck the trend and set one of the other choices as a defaulted value.

Now you have a few decisions to make: hard code the value (bad design), always take field default value, or loop through choices. I'll show you how to get the latter 2 choices (I'm not about to champion the hardcoding movement).

To get the default value for SPFieldChoice:
  • SPListItem.Fields[Guid, Index, or Name of Column].DefaultValue
To loop through the SPFieldChoice choices:

foreach (string oneChoice in ((SPFieldChoice)SPListItem.Fields[Guid, Index, or Name of Column].Choices)
{
switch (oneChoice)
{
case value1:
{some code}
break;
case value2:
{some code}
break;
default:
{some code}
break;
}
}

Friday, December 4, 2009

MOSS Page Timeout Issues

So I was asked to write a simple webpart that would tally survey responses. Everything was moving along just fine and the code was behaving beautifully. Wouldn't you know it, once the code reached User Acceptance, issues started creeping along. I won't get into all the issues since most were minor. The one biggie was a timeout issue that appears as a nasty little default error message that reads "An unexpected error has occurred."

This was mind-boggling for me at first. How could my code fail after it passed unit testing and QA? Digging a little further, I copied masses of data over to my dev box and started debugging my code. Again, no problem while I was stepping through the code. But a funny thing happened when I switched my web.config settings on my dev machine from debug="true" to debug="false." The page threw this error at me. Finally, I was making head-way!

So I started stepping through the code once again, but nothing happened! How could this be? I thought my box was off debug mode? Turns out, when stepping through code, the box interprets those actions as having set debug="true" in web.config.

It finally dawned on me that the code was timing out. So I shut off debugger and added a new timeout setting to web.config. Presto! The code ran fine, but I wasn't satisfied. I wanted to apply my timeout setting to run only against that page. So I setup the web.config under my Layouts folder and wouldn't you know it, the issue appeared again. Now this was ridiculous, I should have the ability to set a path in MOSS to increase my timeout settings.

Turns out, I had to apply my setting in web.config at the root level. So under the home directory found in IIS (for most it would be c:\Inetpub\wwwroot), I updated web.config with the following under the configuration node and presto, my timeout setting applied only to my particular page url:

<location path="SomePath/MyPage.aspx">
<system.web>
<httpRuntime executionTimeout="3600" />
</system.web>
</location>

Friday, November 27, 2009

Downloading Attachments from a List

So I was asked to get all attachments from a List. Now, there are several articles on the web that show you how to leverage the Object Model, so I'm not going to get into that. What I was asked to do was to connect to a remote SharePoint instance and bring down all attachments found in a list.

My first inclination was to leverage the Object Model, but after spending an hour on it, I remembered, I can't connect to a remote instance via the Object Model. So I was left with Web Services. The solution wasn't bad at all either. Once you've connected to Lists service, you can call the GetAttachmentCollection method to return attachments per list item. I'm assuming that everyone knows how to grab List ids and ListItem ids via Web services, so I'll skip that tutorial.

Here's the code:

XmlNode attachmentColl = wsListObj.GetAttachmentCollection(listIDStringWithBrackets, listItemIDString);

for (int i = 0; i < attachmentColl.ChildNodes.Count; i++)
{
string[] attachmentArr = attachmentColl.ChildNodes[i].InnerXml.Split(new char[] { '/' });

System.Net.WebRequest file = System.Net.WebRequest.Create(attachmentColl.ChildNodes[i].InnerXml);

CopyFileToFolder(file.GetResponse().GetResponseStream(),
attachmentArr[attachmentArr.Length - 1]);

file = null;
}

Tuesday, November 17, 2009

Reusing the SSP LDAP Connection

So, I was asked to generate a new SPList in MOSS 2007 based on a specific AD group. And, as I brainstormed, I recalled an AD connection setup within SSP to import user profiles. "Now, wouldn't it be nice to leverage the SSP LDAP connection to setup my LDAP connection," I thought. Well, it would be nice indeed and would take away the headache of having to setup a new webconfig item for my LDAP.
And thus, I scoured the web for articles that focused in on this technique for grabbing LDAP connectivity, but my search turned cold pretty quick. Since I'm so hard-headed, I decided I'd uncover this gem myself and here is what I discovered.

By getting an instance of the UserProfileConfigManager, I immediately had access to the available datasources in SSP. With a UserProfiles.Datasource in hand, I enumerated the connections and looped through until I found the one I wanted. With that, I now had the information I needed to build my LDAP connection. Check it out...

------------------------------------------------------------------
string ldapConnectionPath = string.Empty;
UserProfileConfigManager configMgr = new UserProfileConfigManager(ServerContext.Current);
DataSource adDataSource = configMgr.GetDataSource();

System.Collections.IEnumerator ConnEnumerator = adDataSource.Connections.GetEnumerator();
ConnEnumerator.Reset();

while (ConnEnumerator.MoveNext())
{
if(ConnEnumerator.Current.GetType().Name.Equals("LDAPConnection"))
{
LDAPConnection adConn = (LDAPConnection)ConnEnumerator.Current;
ldapConnectionPath = string.format("LDAP://{0}:{1}/{2}",
adConn.Server,
adConn.Port,
adConn.SearchBase);

// adConn.DomainName // Domain Name is also available
break;
}
}