August 2008 - Posts

If you are using LINQ to XML, sooner or later, you will need to work with XML documents that don't use the namespace.  For example, you might be working with the XML from an InfoPath form and you want to get the value of a particular element.  InfoPath uses the my namespace, and you can't just specify it directly in the string (i.e.: Root.Elements("my:Group2") will not work).  To resolve this, we create a XNamespace object and pass it the URI to the namespace.

XNamespace myNamespace = "http://schemas.microsoft.com/office/infopath/2003/myXSD/2008-02-15T09:18:32";

Once you declare the XNamespace, it's just a matter of including it before any elements or attributes you might use.

var transmittalCollection = from transmittalNode in formDocument.Root.Descendants(myNamespace + "group2")

                            select new Transmittal

                            {

                                MyNode = transmittalNode.Elements(myNamespace + "MyNode").Any() ? transmittalNode.Element(myNamespace + "MyNode").Value : null,

                            };

That's all there is to it.  I have found it very useful when I want to query data out of an InfoPath form.  I just submit the data to a service and then I use LINQ to XML to parse out the values I need.  It is much easier for me than using XPath.

with no comments
Filed under: ,

Today, I am continuing in my How to series of posts.  According to the stats, they have been quite popular, so I will keep them coming.  We are going to talk about how to create a SharePoint security group.  A group (represented by SPGroup) is an internal collection of users (or Active Directory) groups that you can then assign a permission level to on a given site.  You can do this through the web interface but in the case where you are programmatically provisioning sites, you will need code to set who is allowed to use it.

Creating a group is pretty simple, but before you start you need to make sure that the group doesn't already exist.  Of course there is no exists method in any of the SharePoint collections, so you may want to use the try/catch technique.  Once you have established that the group does not exists, you need to decide who is going to be the owner of the group.  The owner of the group must be a member of the site you are using before you try to create a group.  Luckily the EnsureUser method makes adding this user easy.  Assume below that currentSite is an SPWeb object.  This could be for a specific subsite or perhaps RootWeb on your site collection.

currentSite.EnsureUser(@"DOMAIN\OWNER");

The EnsureUser method adds the user to the site if it doesn't exist.  If it does exist, it just returns without error.  We use the SiteGroups collection on the SPWeb object to add the group to the site. 

currentSite.SiteGroups.Add("My Custom Group", currentSite.SiteUsers[@"DOMAIN\OWNER"],

    currentSite.SiteUsers[@"DOMAIN\OWNER"], "My Custom Group Description");

The Add method takes four parameters.  The first parameter is the group name.  The second parameter is the owner of the group.  Note that it requires an SPMember object (SPUser inherits from SPMember) not a string with an Active Directory account.  This is why we have to execute the EnsureUser method above.  The third parameter is a default user.  Honestly, I have no idea what this is for.  It's not something you have to specify when creating a group using the UI, so I usually just pass the owner.  The last parameter is a description.

The next thing we want to do is add users to the group.  To do that, we just get a reference to our newly created group and call the AddUser method.  We would call this multiple times if we were adding more than one user.

currentSite.SiteGroups["My Custom Group"].AddUser(@"DOMAIN\USER1", string.Empty, "User 1", string.Empty);

The first parameter is the login name.  The second is an E-mail address.  The third is the user's actual name and the last parameter is for notes.  If I don't know all of the values for the parameters, I just pass an empty string (I believe null causes an exception).

The last thing we need to do is set the permissions on the group (i.e.: does this group have Read or Contribute access).  The way the API does it may not seem straight forward at first.  We have to create a SPRoleAssignment object by passing it our new group.  We then add a role definition binding to that SPRoleAssignment object.  We then add that SPRoleAssignemnt object to the RoleAssignments collection on the SPWeb object.

SPRoleAssignment roleAssignment = new SPRoleAssignment(currentSite.SiteGroups["My Custom Group"]);

roleAssignment.RoleDefinitionBindings.Add(currentSite.RoleDefinitions["Contribute"]);

currentSite.RoleAssignments.Add(roleAssignment);

currentSite.Update();

In this case, we are setting Contribute access for this group.  You could also specify a custom permission level here as well.  Note, the last statement we must execute is the Update method on the SPWeb object.  Don't forget this otherwise your changes would not be saved. 

with 3 comment(s)
Filed under:

As anyone that has worked with SharePoint knows, there is next to zero correlation to what something is called in the SharePoint UI with what it is called in the SharePoint API.  A lot of this is due to the fact that they changed the name for most everything between versions 2 and 3.  This will be an ongoing post and I will add to it as I think of things. 

SharePoint UI Term SharePoint API Class
Site Collection SPSite
Site SPWeb
Business Data Catalog ApplicationRegistry
Site Column SPField
Permission Level SPRoleDefinition
Alternate Access Path SPAlternateUrl
Top Level Site RootWeb
My Sites QuickLink
Content Approval Moderation

Think of something I am missing?  Leave a comment so that I can get it added.

with 1 comment(s)
Filed under:

I have been doing some quite a bit of mentoring to new SharePoint developers lately and was asked the question of what the difference was between a .dwp and .webpart file and which one should be used.  Yes, I know this is an intro topic but if you are new to SharePoint you aren't going to know this.  As you may know, they are both files used for describing where the code is for a web part.  The difference is .dwp was the file extension used in version 2 of SharePoint and .webpart is a new extension used in version 3.  Inside the files, the schemas are different and it is indicated as such by the version number on the xmlns attribute.

Here is an example of a version 2 schema.

<WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">

  <Assembly>Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>

  <TypeName>Microsoft.SharePoint.Portal.WebControls.SearchBoxEx</TypeName>

  <Title>Search Box</Title>

  <Description>Used to search document and items.</Description>

  <FrameType>None</FrameType>

  <AllowMinimize>true</AllowMinimize>

  <AllowRemove>true</AllowRemove>

  <IsVisible>true</IsVisible>

  <Width>335px</Width>

  <GoImageUrl xmlns="urn:schemas-microsoft-com:SearchBoxEx">/_layouts/images/gosearch.gif</GoImageUrl>

  <GoImageUrlRTL  xmlns="urn:schemas-microsoft-com:SearchBoxEx">/_layouts/images/goRTL.gif</GoImageUrlRTL>

  <GoImageActiveUrl xmlns="urn:schemas-microsoft-com:SearchBoxEx">/_layouts/images/gosearch.gif</GoImageActiveUrl>

  <GoImageActiveUrlRTL  xmlns="urn:schemas-microsoft-com:SearchBoxEx">/_layouts/images/goRTL.gif</GoImageActiveUrlRTL>

</WebPart>

Version 3 is a little different.

<webParts>

  <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">

    <metaData>

      <type name="Microsoft.SharePoint.Portal.WebControls.BusinessDataListWebPart, Microsoft.SharePoint.Portal,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" />

      <importErrorMessage>Cannot import this web part.</importErrorMessage>

    </metaData>

    <data>

      <properties>

        <property name="Title" type="string">Business Data List</property>

        <property name="Description" type="string">Display a list of items from a data source in the Business Data Catalog.</property>

        <property name="CatalogIconImageUrl" type="string">/_layouts/images/bizdatawebpart.gif</property>

        <property name="CacheXslStorage" type="bool">true</property>

        <property name="CacheXslTimeOut" type="int">600</property>

      </properties>

    </data>

  </webPart>

</webParts>

The main difference is that all properties passed to the web part are specified with a property element and a name attribute in version 3.  Version 2 uses different element names for everything. 

Which file extension should you be using?  Probably .webpart since it is version 3.  However, there is really nothing wrong with using version 2 although maybe it will be removed from a future version of SharePoint.  If you take a look at the web part gallery, you will see plenty of web parts still using .dwp.  So for now, I recommend version .webpart, but if you are more familiar with the syntax of version .dwp, have at it.

with 16 comment(s)
Filed under:

I was pleased to see that a new version of the Faceted Search web parts had come out recently.  On my last couple of projects, the Faceted Search worked, but it didn't quite meat all the clients needs.  Mainly it didn't work with fixed queries, advanced search or support the keyword OR syntax.   So I ended up writing my own faceted search controls.  They weren't as functional and were coded to meet the needs of specific needs of my clients.  They weren't as nice as Faceted Search, but they did got the job done.  So when a new version came out, I had to try it out as soon as possible.

If you are going to try them out, the first thing I recommend is to read the setup guide.  I didn't and just assumed the install process was the same as previous versions, and it was complete FAIL.  I went back and read the guide and that got me going somewhat.  There are a couple of things you need to remember to do.  First, remove the old version.  Deactivate the feature, retract the feature, and delete the solution.  Another thing you need to do is manually delete the web parts from the web part gallery.  The reason for this is that when you try to activate the new feature, you will get a file already exists error.  I wish more people would put code in their feature receivers to do that.  It's a pretty simple process and I should probably write something on it. 

The last thing you need to do is to be sure and download the version of Enterprise Library that is provided on the Faceted Search site.  The reason for this is that the faceted search controls require partial trust and the Enterprise Library has to be recompiled to allow partially trusted callers.  Hopefully, Microsoft will put this attribute in the library next time so that, it doesn't have to be added manually.  You will need to throw these DLLs in the GAC.  Don't assume that the existing version of Enterprise Library will work because the code looks for a version with a specific public key token.

After getting everything installed, I was pleased to see that I could now pass multiple values for the same managed property (i.e.: Color:"Red" Color:"Blue").  It also now has support for advanced search.  It has all sorts of other great new features that I haven't messed with yet.  On my setup, I did not have the caching database working correctly at first, so it puts the text Not Cached at the header of the facets control.  I really don't like that since the user doesn't really have any need for that information.  Not a deal breaker since I can just resolve the issue by getting my caching database setup correctly.  I would just modify the source code for the web part and recompile, but unfortunately it's not available yet.  Anyhow, the Faceted Search web parts are really nice now and from my experience users really like them.  If you haven't used them before, I encourage you to go try it.

I am putting today's post out there in a hope of getting more of a feel for what the community does in regards to web parts.  The question is when you need to write custom functionality on a SharePoint site (i.e.: a form, some fancy data binding code, whatever), do you build a web part or do you build a web user control and expose it through some sort of SmartPart.  It may be that there is a best practice here or it may just come down to personal preference.  Personally, I don't really care to do HTML markup using code.  That is not any fun at all and makes it difficult to do any kind of changes.  On the other hand if you want to make use of custom properties that the end user can customize, building a web part is the way to go.  So what do you prefer?  How do you choose what you build?  Leave a comment and let us know.

with 1 comment(s)
Filed under: