in

Dot Net Mafia

Group site for developer blogs dealing with (usually) .NET, SharePoint 2010, and other Microsoft products, as well as some discussion of general programming related concepts.

This Blog

Syndication

Corey Roth - DotNetMafia.com - Tip of the Day

Bringing you the latest time saving tips for SharePoint 2010, MOSS 2007, ASP.NET, LINQ, and Visual Studio 2010
  • Reminder: Don’t use an administrator account for your default content access account

    This,my friends, is bad.

    EnterpriseSearchContentAccessAccountAdministrator

    I see issues caused by this all the times in the forums, so I thought I would write something up on it.  You do not want your default content access account (aka crawl account) to have administrator privileges.  Besides obvious security reasons, there are others.  The main reason is that if the account is an administrator, it can crawl things that you simply don’t want included in your index.  The last thing you want is sensitive information from some list or document library showing up in your search index.  Yes, SharePoint does security trimming, but when you use an admin account, things just get weird.  This also applies to file shares as well.

    There are other reasons you don’t want to do this as well.  If you use an administrator account, things that are not checked in may be indexed.  Also, you may run into issues where regular users cannot get any search results at all.  It effectively seems to mess up security trimming.  I’m sure there are many other reasons I’m not thinking of, but the bottom line is if you are using an administrator account, go change it now.  Of course, test before you make any changes.  You may need to assign permissions to your new account.  This could apply to permissions in SharePoint, on a file share, or in a database (if you’re using the BCS/BDC).

    Once you change accounts, you need to perform a full crawl on all of your content sources so that inappropriate items get removed.  You might even go as far as resetting all crawled content first.  You should especially consider this if sensitive information is in your search index and you need to get it out fast.

  • Get to know the Refinement Web Part in SharePoint 2010 Enterprise Search

    In MOSS 2007, people often extending the search results experience by using the Faceted Search Web Parts.  People really liked these so it looks like Microsoft decided to implement their own version called the RefinementWebPart (also known as the Refinement Panel).  If you are familiar with the Faceted Search Web Parts at all, you will notice there are a lot of similarities in the way things are implemented.  If you’re not familiar with what I’m talking about, it’s this web part that allows users to drill down into a set of search results based upon managed properties and other criteria.  Let’s take a look at a quick example.

    RefinementDefault

    On the left there, you will see a set of refinements that we get out of the box.  I didn’t have to do anything to configure these at all.  There are a number of refinements built in including file type, site, author, modified date, and taxonomy.  You can also easily create your own based on managed property which we will see here shortly. 

    Let’s take a look at some of the options on this web part.  If we edit the page and then edit the web part, we will be able to see the options.  If you’re on a small screen (or a small window in the case of a  VM), you will have to scroll right to see the web part properties.

    RefinementWebPartProperties1

    Since this is a search web part, you will see the familiar Cross-Web Part query ID.  This should be synced up to whatever else you are using on the page.  Usually it is set to User query.  The next section is where we can configure the refinement.  Make note of the Use Default Configuration checkbox.  If you don’t uncheck this, anything you customize will not be saved.  Each thing that you can filter on is called a category by the RefinementWebPart.  The Filter Category Definition property is an XML field where each category is specified.  We’ll also look at that later in the post.  Other properties to note here.  The Accuracy Index is the number of results it looks at to determine things to refine.  I assume this it mainly there to keep things performing well.  What this does mean is that if there is something unique to refine on but it doesn’t occur until result number 51, then it will not be included.  You can also configure how many categories to display. This is set to 6 by default.  The last thing I will point out is that you can configure how the web part displays its information using XSLT (not shown in the screenshot above).

    Now let’s look at how we can add our own managed property to the category list.  You should of course confirm the managed property works and that you can query on it first (do a full crawl if necessary).  We then, just need to take a look at the XML for the Filter Category Definition.

    <?xml version="1.0" encoding="utf-8"?>

    <FilterCategories>

      <Category    Title="Result Type"    Description="The file extension of the item"    Type="Microsoft.Office.Server.Search.WebControls.ManagedPropertyFilterGenerator"    MetadataThreshold="5"    NumberOfFiltersToDisplay="4"    MaxNumberOfFilters="0"    SortBy="Frequency"    SortDirection="Descending"    SortByForMoreFilters="Name"    SortDirectionForMoreFilters="Ascending"    ShowMoreLink="True"    MappedProperty="FileExtension"    MoreLinkText="show more"    LessLinkText="show fewer">

        <CustomFilters MappingType="ValueMapping" DataType="String" ValueReference="Absolute" ShowAllInMore="False">

          <CustomFilter CustomValue="Adobe PDF">

            <OriginalValue>pdf</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Email">

            <OriginalValue>eml</OriginalValue>

            <OriginalValue>msg</OriginalValue>

            <OriginalValue>exch</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Excel">

            <OriginalValue>odc</OriginalValue>

            <OriginalValue>ods</OriginalValue>

            <OriginalValue>xls</OriginalValue>

            <OriginalValue>xlsb</OriginalValue>

            <OriginalValue>xlsm</OriginalValue>

            <OriginalValue>xlsx</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Image">

            <OriginalValue>tif</OriginalValue>

            <OriginalValue>tiff</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Lotus Notes">

            <OriginalValue>nsf</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="One Note">

            <OriginalValue>one</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="PowerPoint">

            <OriginalValue>odp</OriginalValue>

            <OriginalValue>ppt</OriginalValue>

            <OriginalValue>pptm</OriginalValue>

            <OriginalValue>pptx</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Publisher">

            <OriginalValue>pub</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Text">

            <OriginalValue>odt</OriginalValue>

            <OriginalValue>txt</OriginalValue>

            <OriginalValue>url</OriginalValue>

            <OriginalValue>csv</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Visio">

            <OriginalValue>vdw</OriginalValue>

            <OriginalValue>vdx</OriginalValue>

            <OriginalValue>vsd</OriginalValue>

            <OriginalValue>vss</OriginalValue>

            <OriginalValue>vst</OriginalValue>

            <OriginalValue>vsx</OriginalValue>

            <OriginalValue>vtx</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Webpage">

            <OriginalValue>ascx</OriginalValue>

            <OriginalValue>asp</OriginalValue>

            <OriginalValue>aspx</OriginalValue>

            <OriginalValue>htm</OriginalValue>

            <OriginalValue>html</OriginalValue>

            <OriginalValue>jhtml</OriginalValue>

            <OriginalValue>js</OriginalValue>

            <OriginalValue>mht</OriginalValue>

            <OriginalValue>mhtml</OriginalValue>

            <OriginalValue>mspx</OriginalValue>

            <OriginalValue>php</OriginalValue>

            <OriginalValue></OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="XML">

            <OriginalValue>xml</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Word">

            <OriginalValue>doc</OriginalValue>

            <OriginalValue>docm</OriginalValue>

            <OriginalValue>docx</OriginalValue>

            <OriginalValue>dot</OriginalValue>

            <OriginalValue>nws</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Zip">

            <OriginalValue>zip</OriginalValue>

          </CustomFilter>

        </CustomFilters>

      </Category>

      <Category    Title="Site"    Description="Which site this document is from"    Type="Microsoft.Office.Server.Search.WebControls.ManagedPropertyFilterGenerator"    MetadataThreshold="5"    NumberOfFiltersToDisplay="4"    MaxNumberOfFilters="20"    SortBy="Frequency"    SortByForMoreFilters="Name"    SortDirection="Descending"    SortDirectionForMoreFilters="Ascending"    ShowMoreLink="True"    MappedProperty="SiteName"    MoreLinkText="show more"    LessLinkText="show fewer" />

      <Category    Title="Author"    Description="Use this filter to restrict results authored by a specific author"    Type="Microsoft.Office.Server.Search.WebControls.ManagedPropertyFilterGenerator"    MetadataThreshold="5"    NumberOfFiltersToDisplay="4"    MaxNumberOfFilters="20"    SortBy="Frequency"    SortByForMoreFilters="Name"    SortDirection="Descending"    SortDirectionForMoreFilters="Ascending"    ShowMoreLink="True"    MappedProperty="Author"    MoreLinkText="show more"    LessLinkText="show fewer"    />

      <Category    Title="Modified Date"    Description="When the item was last updated"    Type="Microsoft.Office.Server.Search.WebControls.ManagedPropertyFilterGenerator"    MetadataThreshold="5"    NumberOfFiltersToDisplay="6"    MaxNumberOfFilters="0"    SortBy="Custom"    ShowMoreLink="True"    MappedProperty="Write"    MoreLinkText="show more"    LessLinkText="show fewer" >

        <CustomFilters MappingType="RangeMapping" DataType="Date" ValueReference="Relative" ShowAllInMore="False">

          <CustomFilter CustomValue="Past 24 Hours">

            <OriginalValue>-1..</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Past Week">

            <OriginalValue>-7..</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Past Month">

            <OriginalValue>-30..</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Past Six Months">

            <OriginalValue>-183..</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Past Year">

            <OriginalValue>-365..</OriginalValue>

          </CustomFilter>

          <CustomFilter CustomValue="Earlier">

            <OriginalValue>..-365</OriginalValue>

          </CustomFilter>

        </CustomFilters>

      </Category>

      <Category    Title="Managed Metadata Columns"    Description="Managed metadata of the documents"    Type="Microsoft.Office.Server.Search.WebControls.TaxonomyFilterGenerator"    MetadataThreshold="3"    NumberOfFiltersToDisplay="3"    MaxNumberOfFilters="20"    ShowMoreLink="True"    MappedProperty="ows_MetadataFacetInfo"    MoreLinkText="show more"    LessLinkText="show fewer" />

      <Category    Title="Tags"    Description="All managed metadata of the documents and social tags"    Type="Microsoft.Office.Server.Search.WebControls.TaxonomyFilterGenerator"    MetadataThreshold="3"    NumberOfFiltersToDisplay="3"    MaxNumberOfFilters="20"    ShowMoreLink="True"    MappedProperty="ows_MetadataFacetInfo,popularsocialtags"    MoreLinkText="show more"    LessLinkText="show fewer" />

    </FilterCategories>

    I went ahead and posted the entire XML because it’s worth seeing.  For the most part the schema is pretty easy to follow.  The Category element defines each thing to refine and then it has some basic configuration items such as the number of filters to display.  You specify the name of the managed property to use in the MappedProperty attribute.  The MetadataThreshold property is the number of results that have to be returned with that property in order to do refinement.  If you are familiar with the schema used by Faceted Search, you will see a similar concept with the CustomFilter elements.  These allow you map a value into something more readable.  For example instead of display xlsx, it displays Excel. 

    One more thing I will point out is that the Category element has a Type attribute.  So far I have seen ManagedPropertyFilterGenerator and TaxonomyFilterGenerator.  These both inherit from RefinementFilterGenerator.  None of its sealed surprisingly which means you could actually write your own custom filter for the refinement web part.  That’s pretty cool.  I’m not sure why I would need to yet, but you never know what you might want to be able to customize.

    I want to add my own managed property, so I just add a category to the end like this.

    <Category    Title="Color"    Description="Use this filter to restrict results by color" Type="Microsoft.Office.Server.Search.WebControls.ManagedPropertyFilterGenerator"    MetadataThreshold="5"    NumberOfFiltersToDisplay="4"    MaxNumberOfFilters="20"    SortBy="Frequency"    SortByForMoreFilters="Name"    SortDirection="Descending"    SortDirectionForMoreFilters="Ascending"    ShowMoreLink="True"    MappedProperty="Color"    MoreLinkText="show more"    LessLinkText="show fewer"    />

    All I did was copy the category that was used for author and it works great.  You can tweak the individual settings if you like.  Here is what my custom managed property looks like.

    RefinementColor

    How does this all work though.  Well it’s pretty simple.  Just copy any link that the web part displays and we’ll see that it makes use of the new r query string property.  It will be URL encoded but you can easily decode it and see the magic.  In this case if I want to view Red products, the query string has a r parameter of the following.

    r=color="Red"

    If I wanted to view files modified in the last 24 hours, it uses the new >= operator.

    r=write>="3/14/2010”

    Don’t you just love that you can easily query against dates now using the keyword query syntax?  I think the r keyword is very interesting and I think it opens the door for some very interesting customizations of the search results page in the future.

  • How to: Use the new Append Text to query property in CoreResultsWebPart to return documents only

    One common thing people have asked for in the MSDN Search Forums a lot (besides the obvious things like wildcard search) is the ability to get results that contain just documents.  In this case, people just want documents, no list items or folders, or sites, or anything like that.  It wasn’t terribly difficult to do in MOSS 2007 and I even wrote a post about it, but now there is another way this can be done.  We’ll be looking at the CRWP in more detail pretty soon, but I thought this would be something quick to mention.  Consider the following search results.

    EnterpriseSearchResultsAccountingAll

    From the screenshot above you should see that I have documents and list items returned in my search results.  We want to filter that down to just documents.  Before we had to create a scope to handle it.  Now we can use the new Append Text to Query property.  Take a look.

    CoreResultsWebPartAppendQuery

    This new textbox allows you to append whatever you want to what the user searched for.  In my case I am adding IsDocument:”1” to the query to restrict our search to documents, but you could add whatever you can think of to your query here.  After adding it, here is what my search results look like.

    EnterpriseSearchResultsAccountingDocuments

    My results only contain documents now.  This may just be an issue with Beta 2, but it causes the record count to be incorrect and the pager to think there are additional pages.  Anyhow, I think this property will be quite useful.  This functionality was actually already sort of present in MOSS 2007.  There is an undocumented query string parameter, a, that does this same functionality.  I stumbled upon it once when I was using reflector on the CRWP.

  • Dude! Where’s my Search Center?

    You might have seen my last post on People Search and were so excited to try it out only to find that you only have a Basic Search Center template available or the search center you have already created doesn’t have a People tab.  By default, on the New Site menu, you are only able to create a Basic Search Center.  This site template is functional but it doesn’t give you the ability to do a people search.  This effectively corresponds to the Search Center site template in MOSS 2007. 

    NoSearchCenter

    There are two new search center templates available though Enterprise Search Center and FAST Search Center.  However, to see those, you need to activate the Enterprise Features on your site collection.

    EnterpriseSiteCollectionFeatureDeactivated

    Once you activate them, you’ll see the two new site templates available on the New Site menu.  Don’t you just love that new Silverlight app to pick new sites?

    NewSiteSearchCenters

    The Enterprise Search Center is the one you want (unless you actually got FAST working).  This site template corresponds to the old publishing site template Search Center with Tabs back in MOSS 2007.  You also had to do the same thing in the last version of SharePoint as well.

  • A quick look at phonetic People Search in SharePoint 2010

    Maybe you hadn’t noticed, but talking about Search is my favorite topic in SharePoint (with ECM closely following it). :)  This is why I am so excited about the new features we are seeing in Enterprise Search.  Wildcards and built in refinement were enough to bring a tear to my eye, but People Search is what I think a lot of people will be impressed by.  You see People Search is the gateway to many of the new social aspects in SharePoint 2010.  Your old stuffy CIOs are going to absolutely hate it (since they were probably the ones that blocked twitter and facebook at your organization).  The new hip CIOs that find value in social media are going to totally embrace it and organizational efficiency and the sense of community is really going to go up.  Not to tangent on the whole social thing though, let’s just take a look today at how it’s easier to find people in SharePoint 2010.

    Let’s consider my great new fictitious company.  It’s not a big company but there are a number of employees.  Ok, so my fake company isn’t as complete as the one we have seen at the demos at SPC or anything, but hopefully you get the point.  Consider the following users stored in Active Directory.

    PeopleSearchActiveDirectory

    To work with People Search, you must first have successfully configured user profile synchronization, set up a connection, and then done a full crawl on your Local SharePoint Sites content source.  If your user profile synchronization service isn’t working, do yourself a favor and just reinstall because you will never get it to work.  The content source still uses the sps3 protocol to crawl user profiles.  If no people are returned when you search make sure you have a content source setup using that protocol handler.  I’ll probably write another post on how to set this up pretty soon.

    To get started with People Search we start with an Enterprise Search center and click on the people link which gives us a plain search box like the one below.

    PeopleSearchStart

    Let’s say that I need to lookup the phone number for my IT Director, Michael Adams.  I can of course type his full name in like this and get a result (this is what we basically had in SharePoint 2007).

    PeopleSearchResultsFullName

    We get a result as expected, but you know, I really don’t call him Michael, I call him Mike.  Shouldn’t that return me a result too?

    PeopleSearchResultsPhonetic

    Absolutely!  In SharePoint 2007, if you asked for that people would look at you like you wanted the impossible.  Now it works beautifully.    Clicking on the user’s name takes you to the profile page where all of the cool social stuff happens.  I could do several posts on it alone, but here is a quick look at what it looks like.  It allows you to see the org chart along with recent activities along with a corporate style facebook.  Very cool.

    PeopleSearchProfile

    What else can this thing do though?  Say we want to look up our Team Lead, Richard Jackson.  He doesn’t go by Richard though.  He goes by *** (no jokes please).  Will that yield a result?

    PeopleSearchResultsPhonetic2

    How cool is that.  The search engine seems to understand nicknames.  So this really isn’t necessarily happening phonetically, it just has a nice thesaurus in it now, but at SPC, we did see search examples where things were spelled phonetically and it worked.  I haven’t had a ton of luck getting that to work.  I also saw it work with non-English names.  Hopefully I can demo that stuff too pretty soon, but I still thought these things were worth showing off.

    Let’s do one more example though.  Let’s say I know the last name of the person I need to contact is Williams.  We’ll pretend I am lazy and I only type in Willi in the search box.  Will that give me a result?

    PeopleSearchNoResults

    The answer this time is actually no.  People Search does support wildcards now, but it is not on by default.  Change the query to Willi* and we’re in business.

    PeopleSearchResultsWildcard

    It returns matches in both the first and last name.  Very cool.  I’d love to be able to inherit from the PeopleCoreResultsWebPart to add an option to allow wildcards all the time, but Harneet Sidhana [MSFT] does not think we should be able to.  Apparently the web part is perfect and no one would possibly ever want to change it.  Ok, so the web part is pretty cool, but I would like to make changes and that’s just not going to be possible. :-(

    Stepping aside from that tangent, I have to mention the Organization Browser.  It’s a cool use of Silverlight that makes it very easily to browser the organization. 

    PeopleSearchOrganizationBrowser

    This picture doesn’t do it justice.  It certainly would be a lot cooler if I had pictures uploaded for all of my users.  From all of this, hopefully you can see that it should be a lot easier for end users to find people in your organization.  I’m really excited about these new features.

  • Files uploaded to the wrong folder in a document library

    This is kind of a weird one so I thought it was definitely worth posting.  Recently we were doing some integration testing where an external application was linking directly to specific folders.  The users would then upload a document in that folder and then they could not find their file.  Where was the file?  Well it was sitting in the root folder for some reason.  Consider the following URL that was being used.

    http://moss-server/MySiteCollection/MySite/DocumentLibrary/SubFolder

    This can also be expressed like this using the RootFolder parameter.

    http://moss-server/MySiteCollection/MySite/DocumentLibrary/Allitems.aspx?RootFolder=/MySiteCollection/MySite/DocumentLibrary/SubFolder

    The application linking to us was using a path very similar to the ones above.  However, when the user tried to upload the file after coming from that external application, the file they uploaded would be sitting in the root folder every time.  It was strange because, the user was in the correct folder when they followed the link, but when they clicked Upload I noticed the breadcrumb did not have the subfolder listed in it.  When I tried browsing to the folder in SharePoint and uploading it worked correctly.  Something strange was definitely going on.  I started examining everything and I took a look at the link they were using to get to us.  Here is what they were using.

    http://moss-server/mysitecollection/mysite/documentlibrary/subfolder

    Notice the difference?  Exactly, the URL they were using was all lower case. I thought surely case sensitivity wouldn’t be the cause.  I corrected the case in the application and sure enough files started going into the correct folder.  I couldn’t find anything on the internet about this at all until I discovered the case sensitivity and found this post that confirmed a similar issue.  If you don’t believe me, go to any document library on your server and try changing the case and see what happens. :)

    What it comes down is that the case matters in the URL on everything after the server name.  I created the site collection as MySiteCollection (ok no I really don’t have a site collection named this, but this is an example :) ), so that means any time you have a URL the case better match.  The problem is you might not remember how you set the case up when you created the site, site collection, or document library.  If you don’t there is an easy way to figure it out, just browse to the subfolder you want and copy the URL from your browser.  If you URL decode the RootFolder querystring parameter you will see the casing that should be used.  I hope this helps in case you happen to run into it.

  • Speaking about How Business Connectivity Services (BCS) may change your life in SharePoint 2010 at Tulsa SharePoint Interest Group on 4/12

    Ok, so the title may be overly dramatic, but the BCS is really freaking cool now.  With SharePoint 2010 just around the corner, now is the time to start learning how you can leverage it.  I’ll be talking about the Business Connectivity Services at the Tulsa SharePoint Interest Group on 4/12.  If you’re not familiar with everything yet, here is what has changed.  The Business Data Catalog from MOSS 2007 had morphed into the new Business Connectivity Services also known as the BCS.  To add to the confusion, there are places where you will still see term BDC lying around such as the case of the BDC entity model (although maybe the name has changed by now).  With 2010, we get the ability to easily and quickly create new application definitions using SharePoint Designer 2010.  On top of that the data we have abstracted through the BCS can be manipulated in something new called the external list.  It’s so cool that in fact you can edit and do all CRUD operations on that external list and the changes get persisted to the backend database (or web service, etc).  If you’re not familiar with the BCS yet, this is a must-see session.

    If you are going to make it to the event, please RSVP.  Thanks.

  • A simple way to programmatically create SharePoint security groups

    When it comes to SharePoint deployments, I try to automate everything I can.  I don’t like manual steps especially when it comes to setting up security.  A common task when deploying any sites is setting up security in some manner.  Today I am going to cover how to easily store definitions your SharePoint security groups in an XML file.  We’ll use LINQ to XML to make reading the file a breeze, and then we’ll use the SharePoint object model to create the groups and add users (or AD groups).   I’ve blogged on how to create a group before, but we’re going to take this a step further by giving you code that you can easily add to a feature receiver or console application.  First let’s take a look at the XML file we’re going to use.

    <?xml version="1.0" encoding="utf-8" ?>

    <Groups>

      <Group Name="My Custom Read Group" Owner="SHAREPOINT\GroupOwner" Description="Readonly Permission Group" PermissionLevel="Read">

        <User Name="SHAREPOINT\TestUser1" />

        <User Name="SHAREPOINT\TestGroup1" />

        <User Name="SHAREPOINT\TestGroup2" />

      </Group>

      <Group Name="My Custom Contributors Group" Owner="SHAREPOINT\GroupOwner" Description="Contributors Permission Group" PermissionLevel="Contribute">

        <User Name="SHAREPOINT\TestGroup3" />

      </Group>

    </Groups>

    In this file, I am defining two SharePoint groups.  One that will have read access and one that will have contribute access.  I store the required information needed by the Add method on the SPGroupCollection object.  I then have one or more User elements with the name of my Active Directory user or group.  I tried to keep my XML schema pretty simple.  You can customize it obviously how you want, you would just have to alter your LINQ queries. 

    Let’s take a look at the code we need to make this happen.  I won’t go into as much detail of the object model since I went into it pretty well on my last post.  We’ll just focus on how we use LINQ to XML to read the information we need and then have it create our groups.  My method is called CreateGroups and it takes an SPWeb object and a string with the filename of the XML document.

    private void CreateGroups(SPWeb currentSite, string groupsFilename)

    {

        // get the xml document from the feature folder

        XDocument groupsXml = XDocument.Load(groupsFilename);

     

        // create a new anoynmous type with the group data

        var groups = from sharePointGroup in groupsXml.Root.Elements("Group")

                    select new

                    {

                        Name = sharePointGroup.Attribute("Name").Value,

                        Owner = sharePointGroup.Attributes("Owner").Any() ? sharePointGroup.Attribute("Owner").Value : null,

                        Description = sharePointGroup.Attributes("Description").Any() ? sharePointGroup.Attribute("Description").Value : string.Empty,

                        PermissionLevel = sharePointGroup.Attributes("PermissionLevel").Any() ? sharePointGroup.Attribute("PermissionLevel").Value : null,

                        Users = sharePointGroup.Elements("User").Any() ? sharePointGroup.Elements("User") : null

                    };

     

        // iterate through the groups and create the groups

        foreach (var sharePointGroup in groups)

        {

            // only create the group if it does not exist

            if (!ContainsGroup(currentSite.SiteGroups, sharePointGroup.Name))

            {

                // add the owner to the web site users

                currentSite.EnsureUser(sharePointGroup.Owner);

     

                // add the group

                currentSite.SiteGroups.Add(sharePointGroup.Name, currentSite.SiteUsers[sharePointGroup.Owner],

                    currentSite.SiteUsers[sharePointGroup.Owner], sharePointGroup.Description);

            }

     

            // add the users to the group

            AddUsersToGroup(sharePointGroup.Name, sharePointGroup.Users, currentSite, sharePointGroup.PermissionLevel);

        }

    }

    This seems like kind of a big method at first, but it’s really not that bad.  To keep things simple, I haven’t included any exception handling code.  We are really just querying the XML document, iterating through each group element inside of it, creating the groups, and then adding the users to the group.  The first line of code just creates an XDocument object.  We then construct a LINQ to XML query.  What we want is to return data from each Group element in the document.  The Add method doesn’t like nulls, so we check for them and use string.Empty if the value does not exist in the file.  The one case where I don’t do this is for the Name of the group.  If that is not present, I would rather the process throw an exception.  As for the Users assigned to the group, I grab all of them and add them to our anonymous type like this.

    Users = sharePointGroup.Elements("User").Any() ? sharePointGroup.Elements("User") : null

    This gives us an IEnumerable<XElement> that we can pass to a method later to add each Active Directory user (or group) to the SharePoint group.  Once we execute the query, we iterate through each group element.  The first thing we have to do is make sure that the group does not exist.  Of course there is no way to do that other than using the try/catch technique.  I will usually wrap this in an extension method, but for today’s purpose, we’ll just call a method to check.

    private bool ContainsGroup(SPGroupCollection groupCollection, string index)

    {

        try

        {

            SPGroup testGroup = groupCollection[index];

            return true;

        }

        catch (SPException e)

        {

            return false;

        }

    }

    Lame I know.  I’m so happy there are ways to get around this in SharePoint 2010.  Then this starts to look like code from the previous post.  We call .EnsureUser to make sure the domain account of the group owner is registered with the site.  We then just call the Add method with the Name, Owner, default user, and description.  Again there is more info on the previous post about that method call.  Assuming the group is created, we can then add the users to the group.  We call a new method AddUsersToGroup which takes the groupName, the users element, an SPWeb, and the permission level. 

    The first thing we do is query the names of the Active Directory users (or groups).  Here we are just grabbing it from the Name attribute of the User element.  I probably could have condensed this query, but at least it’s easy to read.  We then add each user (or group) from the User elements to the group.  If you are curious about the empty parameters, take a look at the previous post.  If you are going to run into an exception, it’s going to be here.  If the group failed to be created or if the user does not exist (i.e.: you typed it in the XML file wrong), this line will throw an exception.

    private void AddUsersToGroup(string groupName, IEnumerable<XElement> users, SPWeb currentSite)

    {

        // select the username from the xml document

        var userList = from user in users

                       select new

                       {

                           Name = user.Attribute("Name").Value

                       };

     

        // add the users to the sharepoint group

        foreach (var user in userList)

        {

            currentSite.SiteGroups[groupName].AddUser(user.Name, string.Empty, user.Name, string.Empty);

        }

    }

    Now, we’re almost done.  The last thing we need to do is set the permission level on the group.  This is where we specify whether the group has readonly, contribute, full control, etc access to the site.  Be sure and get the name on the permission level right otherwise you will get an exception.  I’ve also blogged about how to assign permission levels before.  Today’s post is really just a great practical use of putting together the things I have posted on before.

    private void SetRoleDefinitionBinding(string groupName, SPWeb currentSite, string permissionLevel)

    {

        // add the read role definition to the site group

        SPRoleAssignment roleAssignment = new SPRoleAssignment(currentSite.SiteGroups[groupName]);

        roleAssignment.RoleDefinitionBindings.Add(currentSite.RoleDefinitions[permissionLevel]);

        currentSite.RoleAssignments.Add(roleAssignment);

        currentSite.Update();

    }

    Effectively you create a new SPRoleAssignment by passing it a SPGroup object.  You then add a binding using the existing RoleDefinitions on the site.  You then add the assignment to the site and of course call .Update() so things get saved.

    That’s really all there is to it.  This is a great use of combining information from my previous posts into something that you can use everyday to set security on your sites.  How you execute this code is up to you.  I’ve used it in a feature receiver and in a console application before.  Setting up security through the UI is very slow and painful.  Once you create it on one server, there is no way to move it to another server and that’s not a lot of fun.  This should help you with that and eliminate those nasty manual steps in your deployment process. 

  • Speaking at the new OKC SharePoint Users Group in March

    SharePoint is hot in Oklahoma City right now with two new groups forming in the last month.  I am excited to be the first speaker at the new Oklahoma City SharePoint User Group on March 29th at 6pm.  I’ll be giving an introduction to SharePoint Enterprise Search where we will learn how to crawl content from SharePoint, File Shares, and maybe even line of business systems such as a database.  We’ll be demoing with SharePoint 2010, but most everything you will learn will also apply to MOSS 2007.  We’ll probably do a Q&A session afterwards as well.  I’m excited to see SharePoint users get together in OKC now and I’m looking forward to this meeting.

  • New Year and New Officers at the Tulsa SharePoint Interest Group

    I am excited to be serving as Vice President this year for the Tulsa SharePoint Interest Group.  This looks to be a great year as we hope to grow the group and make it better than ever.  We don’t have all the plans laid out yet, but we do hope to be able to communicate more with the members and be more a part of your day to day SharePoint lives. :)  Here are the officers and roles for this year.

    David McCollough – President

    Corey Roth – Vice President

    Chris McLean – Treasurer

    Dennis Bottjer – Director of Member Services

    Mohamed Yasuf – Director of Technology

  • Ctrl+Comma – The Navigate To Window in Visual Studio 2010

    I attended the monthly Microsoft Solution Advocate call this morning and during the demo of some cool code you use in your Windows 7 applications, they pointed out a new feature in Visual Studio 2010 that I hadn’t seen before.  When you press Ctrl+Comma (,), it brings up the new Navigate To window.

    NavigateToWindowBlank

    This window allows you to do a quick search for classes and methods that are in your solution.  If you have Resharper installed, I think this key combination is already bound, so this may not work.  Typing in a few letters, gives you results that look this.

    NavigateToWindowResults

    As you can see it brings up methods that are in my solution.  You can also type class names and various other things.  Now before you start, I am sure this was already in Resharper years ago, but it’s still kind of a neat feature.  Try it out.

  • Deploying an External List via Feature using CAML #sp2010

    I’ve been talking a lot about external lists lately as you may know.  They are so easy to create with SharePoint Designer, but you wouldn’t really deploy them to production that way would you?  Of course not!  We need a feature.  At first, you might think generating all of that CAML might be too difficult, but remember we can use the Save Site as Template page to generate a .wsp file for us.  Using this we can import it into Visual Studio and learn what CAML we need to use.

    We’re going to start with the same external list from yesterday.  You can build your own using SharePoint Designer as described in my BCS post.

    ExternalListFeatureList

    Once you are happy with your list, go to Site Settings –> Save Site as Template.  Fill in the fields and it will save a solution package in your solution gallery of your site collection.  Save the .wsp file to disk and we’re ready to begin.  Once you have your solution package, open Visual Studio 2010, create a new project, and use the Import SharePoint Solution Package project template.  You will be prompted for what site to use and where the package file is.  On the next step, you will be prompted for what you want to import.

    ExternalListSolutionImport

    The solution package has every site column, content type, page, list, etc, on the site so there is a lot to sift through.  However, the only thing we really need is the list instance in question (in my case Products).  You will want to unselect everything else as it will take forever to import if you don’t.

    Quick Tip: There isn’t a select all button, so press Ctrl+A, and then unclick a checkbox to deselect everything.

    On the next step you will get a warning about dependencies.  Go ahead and just say yes and your project will import.  Your project will likely have a bunch of stuff you don’t really care about.  All that you really need is what it is created in List Instances.  Your list instance might look something like this.

    ExternalListFeatureSolutionExplorer

    At this point, I created a new project because I want to keep things clean.  Create a new project and create a new List Definition.  At this point, you will have a schema file and two new elements files.  The elements.xml file with the list template can be deleted since I don’t want users creating new versions of this list.  Before we start digging into the CAML that is required to make an external list work, let’s go back and look at SharePoint Designer so we can remember what our application definition looked like.

    ExternalListFeatureApplicationDefinition

    The reason I show you this is because these values we’re going to see when we take a look at our elements.xml file.  Here is the file that came from the site export.

    <?xml version="1.0" encoding="utf-8"?>

    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">

      <ListInstance FeatureId="{00bfea71-9549-43f8-b978-e47e54a10600}" TemplateType="600" Title="Products"

                    Description="" Url="Lists/Products" CustomSchema="Files\Lists\Products\Schema.xml"

                    HyperlinkBaseUrl="http://sp2010/Test" RootWebOnly="FALSE"

                    xmlns="http://schemas.microsoft.com/sharepoint/">

        <DataSource>

          <Property Name="Entity" Value="Products" />

          <Property Name="EntityNamespace" Value="http://sp2010/test" />

          <Property Name="LobSystemInstance" Value="bcs_test" />

          <Property Name="SpecificFinder" Value="Read Item" />

        </DataSource>

      </ListInstance>

    </Elements>

    A couple of things to note here.  First, the TemplateType is 600.  We can only presume this is the list template id for an external list.  The other thing of note is the new DataSource element.  This was not in previous versions of SharePoint.  As you might notice here, these values correspond to what we see on the external content type.  This is what you will change should you decide to rename the entity in or change the LobSystemInstance name.  This XML is highly useable in our own feature, but I am going to remove some of the unnecessary attributes such as FeatureId and CustomSchema.  I’m also going to give it a new Title so that we know this is a different list.  Here is what my new elements.xml looks like.

    <?xml version="1.0" encoding="utf-8"?>

    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">

      <ListInstance TemplateType="600" Title="Products - Deployed by Feature" Description=""

                    Url="Lists/ProductsDeployedByFeature" HyperlinkBaseUrl="http://sp2010/Test"

                    RootWebOnly="FALSE" xmlns="http://schemas.microsoft.com/sharepoint/">

        <DataSource>

          <Property Name="Entity" Value="Products" />

          <Property Name="EntityNamespace" Value="http://sp2010/test" />

          <Property Name="LobSystemInstance" Value="bcs_test" />

          <Property Name="SpecificFinder" Value="Read Item" />

        </DataSource>

      </ListInstance>

    </Elements>

    Honestly, I think I can get rid of HyperLinkBaseUrl as well.  It doesn’t seem to matter though, I deployed it to a few other sites and it seems to work fine.  Now let’s take a look schema.xml.  It’s actually pretty small which is nice compared to the files we were used to in the past.

    <?xml version="1.0" encoding="utf-8"?>

    <List Title="Products" Direction="none" Url="Lists/Products" BaseType="0" Type="600"

          FolderCreation="FALSE" DisableAttachments="TRUE" Catalog="FALSE" RootWebOnly="FALSE"

          SendToLocation="|" ImageUrl="/_layouts/images/itgen.gif" xmlns:ows="Microsoft SharePoint"

          xmlns:spctf="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms"

          xmlns="http://schemas.microsoft.com/sharepoint/">

      <MetaData>

        <ContentTypes>

          <ContentType ID="0x01" Name="Item" Group="List Content Types" Description="Create a new list item." FeatureId="{695b6570-a48b-4a8e-8ea5-26ea7fc1d162}">

            <Folder TargetName="Item" />

            <FieldRefs>

              <FieldRef ID="{c042a256-787d-4a6f-8a8a-cf6ab767f12d}" Name="ContentType" />

              <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="TRUE" ShowInNewForm="TRUE" ShowInEditForm="TRUE" />

            </FieldRefs>

            <XmlDocuments>

              <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">

                <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">

                  <Display>ListForm</Display>

                  <Edit>ListForm</Edit>

                  <New>ListForm</New>

                </FormTemplates>

              </XmlDocument>

            </XmlDocuments>

          </ContentType>

        </ContentTypes>

        <Fields>

          <Field DisplayName="BDC Identity" Hidden="FALSE" Name="BdcIdentity" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="BdcIdentity" Type="Text" />

          <Field DisplayName="Name" Hidden="FALSE" Name="Name" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Name" Type="Text" />

          <Field DisplayName="Id" Hidden="FALSE" Name="Id" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Id" Type="Integer" />

          <Field DisplayName="Color" Hidden="FALSE" Name="Color" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Color" Type="Text" />

          <Field DisplayName="Description" Hidden="FALSE" Name="Description" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Description" Type="Text" />

          <Field DisplayName="Price" Hidden="FALSE" Name="Price" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Price" Type="Decimal" />

        </Fields>

        <Forms />

        <Views>

          <View DisplayName="Products Read List" DefaultView="TRUE" BaseViewID="1" Type="HTML" MobileView="TRUE" MobileDefaultView="TRUE" ImageUrl="/_layouts/images/generic.png" XslLink="main.xsl" WebPartZoneID="Main" WebPartOrder="1" Url="Read List.aspx" SetupPath="pages\viewpage.aspx">

            <XslLink>main.xsl</XslLink>

            <Method Name="Read List" />

            <Query>

              <OrderBy>

                <FieldRef Name="Name" />

              </OrderBy>

            </Query>

            <ViewFields>

              <FieldRef Name="Name" ListItemMenu="TRUE" LinkToItem="TRUE" />

              <FieldRef Name="Id" />

              <FieldRef Name="Color" />

              <FieldRef Name="Description" />

              <FieldRef Name="Price" />

            </ViewFields>

            <RowLimit Paged="TRUE">30</RowLimit>

            <Aggregations Value="Off" />

          </View>

        </Views>

      </MetaData>

    </List>

    As you can see it’s pretty clean.  It again uses the Type of 600.  In the ContentTypes section, it does define a regular list item, but it doesn’t actually add any of the fields from the external list there.  The Fields element has a field defined for each field in my external content type.  As you can see there is nothing special about the way they are defined.  The only one of note is the BdcIdentity field which I assume is required to keep track of the ID that ties back to the BCS itself.  The View is surprisingly clean as well.  The XslLink and Method elements are new.  I assume we can use XslLink to customize how the view is rendered, but I didn’t actually see a main.xsl file generated in the solution package anywhere.  The Method element I can only assume corresponds to the name of the finder method Read List which we have seen above.  The rest is pretty simple.  It just has a FieldRef for each column in my external content type. 

    I can pretty much use the Schema.xml file as is.  I did change the Title and Url attributes at the top but that is it.  At this point my new feature to deploy this is ready to go.  Here is what it looks like in Visual Studio.

    ExternalListNewSolutionExplorer

    Deploy your solution and have it activate your feature.  The new list won’t show up automatically in the navigation on the side, but it will be there.  Just go to the URL directly or view the lists on your site to get there.  Here it is on my new site.

    ExternalListOnNewSite

    As you can see it’s really not that hard to deploy an external list to another site properly using a feature.  Now, you might have noticed there are a few other elements.xml files generated when we did the site export.  One stores specific values in the property bag of the list.  This we did not want because we don’t really want to copy those internal properties.  The other deals with the forms of the list.  It uses the BinarySerializedWebPart which scares me a bit, so I haven’t messed with it much.  If you are just using default forms you don’t need to worry about it.  In a future post, I’ll try seeing if I can deploy some InfoPath forms along with the list, but I figured that deserves its own post.

    Also, one other thing to note.  If you are deploying your external content type to another server, you can do that in the same manner as you did in SharePoint 2007.  Just export the application definition and import it on the new server.  You can also use the Export Application Model button in SharePoint designer on the External Content Types list.

    ExternalListExportApplicationModel

    I hope this helps when you look to move lists into production.  This technique of exporting and importing will also work with regular lists of course.  Just remember, friends don’t let friends deploy lists without a feature.

  • Impress the Boss with the SharePoint 2010 Chart Web Part

    Let’s face it.  Nowadays, management absolutely loves BI.  Especially when there are lots of pretty charts and graphs.  The thing is I’m not a BI guy.  Cubes scare me to death.  Luckily, there is the new snazzy Chart Web Part in SharePoint 2010 that gives you some BI like capabilities.  It doesn’t allow you to drill down and pivot and do all that fancy stuff, but it does let you make some nice graphs and charts that any ordinary developer can do.

    To get started, first you need an Enterprise version of SharePoint 2010.  Unfortunately, I used the key that was later determined to be the wrong one which led me to reinstall SharePoint with a new key.  If you don’t have any Enterprise options available, then you will be reinstalling.  Assuming, you do have an Enterprise key, you then need to activate the SharePoint Server Enterprise Site Collection Features.

    ChartWebPartFeature

    This adds the chart web part (among other things).  Then edit any page and add a Chart Web Part.  You can find it under Miscellaneous as of Beta 2 (they may have found it a new home in later versions).

    ChartWebPartAdd

    When you add it to the page, it uses some dummy data and displays a simple bar chart.

    ChartWebPartDefault

    At this point, you might be asking yourself “What kind of data can I bind this to?”.  By clicking Data & Appearance, you will see the following screen which leads you to links to customize the appearance or bind to data.

    ChartWebPartDataAndAppearance

    We’ll start by going to Connect Chat To Data.  Look at these great options we have to choose from.

    ChartWebPartDataSources

    We can connect to another web part, a list, an external content type (looks like they need to update the BDC wording they have there), and to Excel Services.  I tried going straight to an external content type, but I got a yellow screen.  Apparently that is broken on my version, but I’m sure it will work in RTM.  There is a work around though.  You can pick an external list using the Connect to a List option.  This is exactly what I am going to do.

    Remember that external list I created on my BCS blog post?  I’m going to use that list and extend it some.  What I did is I created a new custom list to contain Monthly Sales information.  I used an External Data field to allow the user to pick a product from the external content type and enter in some sales data in a field.

    ChartWebPartList

    This is the list we are going to use on our chart.  On the next step of the wizard, we are allowed to pick a list.  Note that it also allows you to choose other sites in the collection as well.

    ChartWebPartListDataSource

    The next step allows you to filter your data first if you are so inclined.

    ChartWebPartWizardFilterData

    The Chart Web Part has a ton of configurable options.  On this last step is where you will start seeing some of them.  The main thing to set here is your X and Y fields.  You can also specify something to group by as well.

    ChartWebPartWizardBindData

    Once you finish this last step, you’ll get something that looks like this.

    ChartWebPartWithData

    So, what we have here is a chart bound to data coming from a database (via external content type) and a SharePoint list.  Pretty cool, right?  I think so.  It gets better though.  What if your boss doesn’t like bar charts?  No problem.  There are tons of chart types to choose from.  Just click on Data & Appearance again and then Customize Your Chart.  Look at all of these built in chart types you have.

    ChartWebPartOptionsPie

    ChartWebPartOptionsBar

    On the next step, you can further customize the chart you choose.  It has some nice pre-built color themes and you can customize the size and what not.  It also gives you a live preview as you change settings.

    ChartWebPartOptionsPie2

    Here is what my new chart looks like.

    ChartWebPartPie

    You can customize things even more by going to Advanced Properties.  It would probably take me a week to show you everything that this web part does, so I recommend you go try it out for yourself.  The charts and graphs this thing produces are so cool, you should have no issue getting your boss to sign off on the Enterprise license. :)

  • Intro to SharePoint 2010 Development: How to Build and Deploy a Web Part

    If you are already familiar with SharePoint 2010, you already know how easy it is to build and deploy a web part now.  However, this post is for those that don’t keep up with SharePoint as some of us do and may not realize how the development experience has improved so much.  My post How to Build and Deploy a Web Part is by far the most popular post on DotNetMafia.com.  I wanted to make today’s post just as a point to show you how much less work is involved in deploying a web part.  I am going to group this post into sections in a similar manner as I did the post for the WSS3 post.

    Environment

    There can be entire talks about what the best way to develop is now, but we’ll start with the simplest.  Although you can install SharePoint on Windows 7 and directly develop on it, most people are going to say stick with a virtual machine and run Windows Server 2008 R2.  It’s certainly simpler to get all of the prerequisites installed if you stick with Windows Server.  The benefits to developing directly on a machine with SharePoint on it are so great now that I would recommend against remote debugging (although you still can).  The SharePoint Root (or the 12 hive as you called it) is now the 14 hive and is located at the predictable path below.

    C:\Program Files\Common Files\microsoft shared\Web Server Extensions\14

    Coding the Web Part

    Here is where things start to change.  Instead of creating a class library and adding references to the SharePoint DLLs, we simply use one of the new included SharePoint project templates as you can see here.

    WebPartIntroEmptyProject

    Start by using the Empty SharePoint Project template.  Also make sure you have it set to .NET Framework 3.5 as SharePoint does not run under .NET Framework 4.0 (don’t get me started).  You’ll notice you have many different project templates to choose from.  Most of these can also be used once you create an empty project.  On the next dialogue, pick farm solution.  I’ll go into the difference between sandboxed and farm solutions, but more than likely you are going to use farm solutions every time.  You also need to specify the URL to your server.  You can change that if you want but the default value will probably work for you in this case.

    WebPartIntroSolutionType

    This gives us a solution that looks like this.

    WebPartIntroSolutionExplorer

    Now we are ready to build our new web part.  If you bring up the add new item context menu, you will see a number of choices for the types of new SharePoint Project Items (SPIs) that you can create.  We’re going to choose Web Part in this case.

    WebPartIntroSPI

    What is the Visual Web Part you ask?  That’s just a user control which relates directly to my second most popular post on How to Deploy a User Control.  Now we’re finally ready to add some code.  We’re just going to take our code from the WSS3 post and use it here.

    using System;

    using System.ComponentModel;

    using System.Runtime.InteropServices;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    using System.Web.UI.WebControls.WebParts;

    using Microsoft.SharePoint;

    using Microsoft.SharePoint.WebControls;

     

    namespace SharePointProject1.TestWebPart

    {

        [ToolboxItemAttribute(false)]

        public class TestWebPart : WebPart

        {

            public TestWebPart()

            {

            }

     

            protected override void CreateChildControls()

            {

                base.CreateChildControls();

                Controls.Add(new Label() { Text = "My Test SharePoint 2010 Web Part (Hello World)!" });

            }

     

            protected override void RenderContents(HtmlTextWriter writer)

            {

                base.RenderContents(writer);

            }

        }

    }

    The only line of code I added here was the line to add the label and set its text.  Everything else came from the template.

    Describing the Web Part

    In my WSS3 post, this is where I talked about building a .webpart file.  Well, you don’t need to worry about that any more as Visual Studio creates it for you.  Here is what solution explorer looks like after you add your first web part.

    WebPartIntroSolutionExplorer2

    As you can see the .webpart file is already there as well as an elements.xml file for a feature to deploy the web part.  The WSS3 post went on to talk about all of the things you need to know about building a feature.  This is still good stuff to know, but its already taken care of for you.  If you want to edit the basic feature information, just open it up in solution explorer and you get a nice new interface that looks like this.

    WebPartIntroFeatureEditor

    I’m not going to waste space showing you the insides of the files it creates for you.  Just know it creates them for you and it saves you a ton of time.

    Deploying via Solution Package

    In my WSS3 post, I explained how to create a cab.ddf and manifest.xml file.  Well guest what?  That is taken care of for you now as well.  The Package.package file in the solution explorer provides another nice editor which allows you to choose with files go into the package.  You don’t have to keep track of a thing any more, it just builds the package and takes care of it for you.

    WebPartIntroPackageEditor

    At this point, Visual Studio has created the .webpart file, the feature, and the solution package.  However, we still need to deploy it and if we could debug it that would be even cooler right?  Take a look at our new options in the Build menu.

    WebPartIntroBuildMenu

    We can build and rebuild just like any other project, but notice the options for Deploy, Package, and Retract.  Those are all SharePoint functions.  In this case, I want to deploy my solution.  Choosing deploy, we see the following in the output window.

    ------ Build started: Project: SharePointProject1, Configuration: Debug Any CPU ------
      SharePointProject1 -> C:\Code\SharePointProject1\bin\Debug\SharePointProject1.dll
      Successfully created package at: C:\Code\SharePointProject1\bin\Debug\SharePointProject1.wsp
    ------ Deploy started: Project: SharePointProject1, Configuration: Debug Any CPU ------
    Active Deployment Configuration: Default
    Run Pre-Deployment Command:
      Skipping deployment step because a pre-deployment command is not specified.
    Recycle IIS Application Pool:
      Recycling IIS application pool 'SharePoint - 80'...
    Retract Solution:
      Skipping package retraction because no matching package on the server was found.
    Add Solution:
      Adding solution 'SharePointProject1.wsp'...
      Deploying solution 'SharePointProject1.wsp'...
    Activate Features:
      Activating feature 'Feature1' ...
    Run Post-Deployment Command:
      Skipping deployment step because a post-deployment command is not specified.
    ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
    ========== Deploy: 1 succeeded, 0 failed, 0 skipped ==========

    From inspecting the text of the log, you can see that Visual Studio compiled, created a package, reset my Application Pool, Added the Solution, Deployed the Solution, and activated the feature.  Let’s check SharePoint and see if it’s really there.

    WebPartIntroGallery

    Checking the web part gallery, we see our .webpart file.  Let’s add it to a page and see how it looks.  Edit any page and use add a web part and you will see the new interface for choosing a web part.  It puts it in the Custom group by default.

    WebPartIntroAddWebPart

    One you hit and add finish editing, we see the web part working correctly.

    WebPartIntroWorking

    You have to admit this is quite a bit easier than deploying a web part in SharePoint 3.  What if you want to debug though?  No problem.  Just set a breakpoint and choose debug from the build menu like you would any other type of project.

    WebPartIntroBreakPointHit

    As I mentioned earlier, if you are familiar with SharePoint 2010, this is nothing new to you.  However, my point today is for those who shied away from SharePoint in the past because the development experience was far from optimal.  Try it for yourself and you will see how easy it is to get up and running with your code.  Even with pictures this post is half the size of the WSS3 post.  That’s because it really is just that easy.  I really think Visual Studio 2010 will open the way for a new round of SharePoint developers.  Try it out today.

  • Troubleshooting the Unexpected Error has Occurred in Office Web Apps

    Office Web Apps is one of my favorite new parts of SharePoint 2010, but there are a number of steps you need to follow to ensure that they actually work.  To start with, be sure and download the Installation guide and run any scripts mentioned in there as necessary.  Also, you will want to run the script mentioned in Jie Lie’s post.  You also want to verify that the Word Viewer Service application is started.  However, if you are like me, you may still find that you get an error like the one below.

    An unexpected error has occurred.

    OfficeWebAppsWordViewerError

    Yes, it’s good to know that useful error message hasn’t gone away.  However, we do gain something here.  You will notice that I have the Correlation Id highlighted.  This corresponds to an actual error message in the ULS logs in the 14 hive.  What is great, is you can use the handy ULS Viewer tool, to make troubleshooting this error even easier.  Simply search for that Correlation Id and you will find out what the actual error was.  In my case, the answer was really quite simple as you can see from the error message.

    Microsoft.Office.Web.Common.BadCanaryConfigurationException: This feature is not activated for the site collection.

    OfficeWebAppsULSViewer

    If you want to use the Word Viewer, you actually need to activate the feature on the Site Collection.  To resolve this, I simply activated the Office Web Apps feature.

    OfficeWebAppsFeature

    Strangely enough, my Excel Viewer was working the entire time without this activated.  If you haven’t seen Office Web Apps, here is what the Word Viewer looks like running in Chrome using Silverlight.

    OfficeWebAppsChrome

    I’ll also mention that in the past I have gotten a yellow screen instead of an error message.  This makes it difficult to determine a Correlation Id, but you can still browse the ULS logs using the ULS viewer pretty easily.

More Posts Next page »
2009 dotnetmafia.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems