Tuesday, May 13, 2014

Creating a Document Set with SharePoint Designer 2013 Workflow

Synopsis: This post describes the challenges with creating a document set via a SharePoint 2013 workflow.

My client needed the ability to fill out a form, then trigger a workflow for various approvals. As approvers went through various process, then needed a place to collect documents. A document set made sense here and it only made sense that the workflow create the document set.

So I set off researching how to do this. I found a good article by Ann Stenberg on technet which walked through this process for 2010. It exactly what I needed. In the workflow section, you can see that it simply creates a new document set by creating a new list item. And that made sense because it was really a folder, sort of, which was itself an item.

Now that I understood this, I first created a new document set following the instructions here manually. I manually created a document set from the new item menu and that worked fine. It provides a nice landing page for the document set too. Fine.

image

(By the way, as you see above I used my own content type which simply inherited from Document Set called Sample Document Set)

Next, I went on to create a site workflow (based on SharePoint 2013) in SharePoint Designer to prove this out. I added a create item action and specified the following:

Content Type ID: Document Set
Path and Name (*): 234 *

* This was just some arbitrary value that was to represent my form ID eventually. It would become my document set name/folder.

I manually ran the workflow in the browser. It worked, but I didn’t get what I wanted. I got a plain old folder instead. Not what was supposed to happen. Thanks SharePoint. And there was no friendly welcome page that the other manually-created document sets have.

image

After looking at this with SharePoint Manager it was the right content type, but it was just a folder to the user. Everything was exactly as the other items.

image

By the way, SP Manager 2013 Online is a great tool to have if you’re doing cloud development.

As it turns out there are properties on the folders that are important. Drilling up to the folders in the site, you’ll see the issue. The SharePoint 2013 workflow action/activity for creating a new item is different than 2010.

image 

The work around…

Since this works in SharePoint 2010 workflows, the solution is to build a SharePoint 2010 workflow that does this and call it from the SharePoint 2013 workflow. Thankfully, the new workflow engine can initiate 2010 workflows. The way I did this was to create a 2010 site workflow in SharePoint Designer first. That performs the work of creating the document set properly.

image

When choosing the site workflow, I chose 2010 as the workflow engine.

SNAGHTML38229c38

When editing the workflow, I created an initiation parameter so I could pass the name of the document set (in this case I called it document set ID).

SNAGHTML382704b3

If you were to run this workflow by itself, you would see this parameter in the UI for you to type in before the workflow starts. We’ll call this workflow from another workflow, so we’ll just pass it as a parameter.

Next I created a new item in the host document set library – this is the library that has the appropriate doc set content attached to it. I changed the content type and used the workflow initiation parameter for the name of the document set (I also used a “Request ID” field in my custom content type):

image

The 2010 workflow looks like this. The new item ID is returned in a variable, which you can use or ignore:

image

Next, I created a list-based workflow using the 2013 workflow engine. This workflow calls the 2010 workflow. See below for the entire workflow:

image

The highlighted line above shows how we are starting a separate workflow. When run, we pass in “202” as the name of our document set. The parameter dialog for the workflow shows how our 2013 workflow wires up values to the initiation of the 2010 workflow (or any other workflow for that matter).

image

Again, here we are passing DocSetID, but that’s really just the name of the document set. It produces the results we wanted too.

This is a pretty neat thing to know as far as reusability goes. There’s a draw-back here in that we’re depending on the 2010 workflow engine. So future versions of SharePoint may have issues with this, but this is a decent work-around for now.

Monday, March 31, 2014

Debugging Workflows In SharePoint 2013 Online using Azure

This is just so cool… You’re now able to debug workflows in SharePoint 2013 online by using your Azure account. Just this past weekend we (Composable Systems) hosted the Azure bootcamp here in Louisville, KY and I gave a dev talk on Service Bus. As it turns out, you can use one of your service bus namespaces to help you develop SharePoint 2013 workflows as well as remote events. Very timely indeed.

I’m building a SharePoint 2013 App for our largest client, Microsoft. This one is specifically for the Bing division, which they’ll use internally. I’m using Visual Studio 2013, SharePoint Online through our Office 365 subscription and a SharePoint App template. We’ll eventually deploy this to their internal SharePoint App store.

The first thing you need to do is go into the Azure portal and create a namespace under the Service Bus category, or choose an existing one you’ve already created. I just created a new one. No other configuration was needed here.

image

Once the namespace is setup, you’ll need to copy the connection string from the connection settings button near the bottom of the screen.

image

I just copied the ACS connection string.

Next, open the SharePoint App project properties in Visual Studio.

image

Now that is setup, I can do a couple of things. I can write details out to the console and I can set breakpoints. Wait… write to the console? Yep. When you press play to deploy/run your app, VS.NET starts a console that listens to that Service Bus.

So in this case, I added a WriteLine activity to my workflow (this comes from the Primitives section of the toolbox).

image

This will show up in my console when running the app. Here’s what that looks like.

image

And the breakpoint experience is really neat. When it breaks, you can explore all your local variables. Very handy.

image

Tuesday, March 4, 2014

The Future of InfoPath Forms

Probably one of the most important topics to Composable Systems, and myself personally, at the SharePoint Conference (2014) is the future of InfoPath Forms. InfoPath is supposedly gone as a product… That means in about 10 years, we’ll have to deal with migrating our forms to some other tool or set of tools.

Relax. That’s 10 years. InfoPath is going to be supported in its current form and will still be part of the next version(s) of SharePoint. Forms hosted in SharePoint will still work. The app will work on the desktop as well. So we’ll have time to migrate to a new solution, but we shouldn’t wait too long to re-think our forms. Having said all that, the future is still not too clear. At the SharePoint Conference today, Microsoft said that they’re very much in flux here and are looking for help from the community to guide this. They said there’s a lot of work going on here within Microsoft, but there’s nothing ready to ship anytime soon. So there was no big announcement. It’s not what I wanted to hear, but at least they’re transparent in their position here.

Despite this, the team gave a good classification of the different types of options/tools available to deal with this. Here are the items they covered. Some things are available today, others are coming in the future.

Excel Surveys

This has already shipped with SharePoint. It’s often overlooked and most people haven’t even heard of this. This is actually a great solution for simple surveys and forms. There is a simple designer to add as many questions, of varying type, to the form. These simply become columns in Excel. And you get to share the survey URL for people to fill out. When results come in, they go directly to the spreadsheet – and in real-time. To create one, just choose new “Excel Survey” from within a document library.

List Forms

This is new stuff. It wasn’t really a product announcement as in replacing InfoPath, but it did put a nicer experience on top of a list. These are MS Access-based forms that sit on top of a list. Before we go too far here, this is just the form part of MS Access and is entirely web-based. It’s based on HTML5 and is initiated using the ribbon while editing a list – there is a new “design form” button that sits right next to the InfoPath button. It’s a fast and flexible design surface which allows drag/drop support of labels and fields. You can re-size and re-position. It’s just form elements for the current list though. You essentially create a new view. It’s not as comprehensive as I would have hoped. This will ship in SharePoint online within the next 3-6 months.

Structured Documents

This is another scenario where Word documents are used as high-fidelity documents which gives users a more WYSIWYG experience. These are fillable word documents where the form fields can be edited and/or filled out. It meets the need of an online as well as offline scenario. These most closely resemble the InfoPath forms, but are not nearly as complex. They’re just for filling out and capturing data. Also, the data is kept in the Word document, so it makes for a good archival story. This functionality is about a year off.

App Forms

These are the most complex forms. These are based on MS Access online which allows for a relational and fully transactional database behind the scenes. By the way, the new MS Access online databases are based on SQL Azure. So it’s going to be scalable, capable and reliable. This is currently shipping in the online version.

So, this is sort of like the Shuttle program being shut down without a real clear path to get to the space station. Not what I wanted to hear – I really wanted a cool HTML5 based application that did what InfoPath did, but without all the strings attached. I guess we’ll wait and see on this – we’ll keep you up to date on this. We’ll also deal with this on a case-by-case basis. Sometimes using InfoPath, sometimes creating our own HTML5 forms.

Saturday, August 1, 2009

Odd Error When Retrieving Items from an SPView

When attempting to retrieve items from an SPView programmatically, you cannot reference fields by name or by their ID.  Note, I’m using MOSS 2007 with SP2.  So here’s the code that causes the issue (and resulted in over 3 hours of wasted time)…

Guid listId = new Guid(...);
Guid viewId = new Guid(...);

SPList list = SPContext.Current.Web.Lists[listId];
SPView view = list.Views[viewId];

SPListItemCollection filteredItems = list.GetItems(view);

foreach (SPListItem item in filteredItems)
{
Response.Write(item["Title"]); // THIS FAILS
}

And you’ll see this error:


Exception has been thrown by the target of an invocation. ---> System.ArgumentException: Value does not fall within the expected range. at Microsoft.SharePoint.SPFieldMap.GetColumnNumber(String strFieldName) at Microsoft.SharePoint.SPListItemCollection.GetRawValue(String fieldname, Int32 iIndex) …


Thankfully, the SPView object exposes a Query property which is a string that contains the CAML that filters list items.  Using this property, you can just create your own SPQuery object and retrieve the items from the list.  The following code has this modification.


Guid listId = new Guid(...);
Guid viewId = new Guid(...);

SPList list = SPContext.Current.Web.Lists[listId];
SPView view = list.Views[viewId];

SPQuery query = new SPQuery();
query.Query = view.Query; // GET THE QUERY PROPERTY FROM THE VIEW

SPListItemCollection filteredItems = list.GetItems(query);

foreach (SPListItem item in filteredItems)
{
Response.Write(item["Title"]);
}

Hopefully, this saves you some time.

Tuesday, June 30, 2009

Document Library Icons Missing

Here’s something to keep in mind as you provision document libraries inside SharePoint.  You can provision document libraries through both the web (site) and site (site collection) scoped features.  The way you would do this is through use of the ListInstance element similar to the following:

<ListInstance
Id="Expenses" Title="Expenses" OnQuickLaunch="False" RootWebOnly="true"
FeatureId="00BFEA71-E717-4E80-AA17-D0C71B360101"
Description="Contains expense documents."
TemplateType="101" Url="Expenses">
</
ListInstance>

Unfortunately, when provisioning document library instances from site collection features the icons appear to be missing.  In the object model, which you can’t change after the fact, the ImageUrl property is empty.  If you look at the “View all site content” link, you’ll see what I’m talking about.


image_2_3B6F10A9.png (501×191)


This is just something to be aware of.  It may not be a show-stopper, but it’s an inconvenience to your users.  I’d recommend provisioning your lists as site features (at the Web scope).  It may mean more features to manage, however.

Thursday, June 11, 2009

Keep Site Definition IDs Unique

This recently bit me.  I had two different site definitions.  They had two different webtemp xml files, of course.

Here’s the first one:

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

<Templates xmlns:ows="Microsoft SharePoint" >
  <Template Name="STORESITEDEF" ID="10010">

...

The second looked like this

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

<Templates xmlns:ows="Microsoft SharePoint" >
  <Template Name="MARKETSITEDEF" ID="10010">

...

When I went to create my site, I kept getting this error:

The template you have chosen is invalid or cannot be found...

I incorrectly assumed that the ID was only relevant within a given site definition – why this wasn’t a GUID, I don’t know.  Anyway, I changed one of my IDs to be different and after an IISRESET all is well.

Tuesday, June 2, 2009

Always Capitalize (all-caps) Boolean Values in CAML

So here I was, late at night, banging my head against the desk trying to figure out why my a custom field’s custom property wasn’t hiding when I clearly stated Hidden=”true”.  As it turns out, you need to specify the uppercase value for that boolean or it simply won’t work.  There’s no error; it just doesn’t hide.  Here’s a snippet of code where this bit me while developing a custom column using the ProperySchema section to allow additional settings to be used for the field.

<FieldTypes>
<
FieldType>
<
Field Name="TypeName">CustomColumn</Field>
<
Field Name="ParentType">Note</Field>
<
Field Name="TypeDisplayName">My Custom Column</Field>
<
Field Name="TypeShortDescription">My Custom Column</Field>
<
Field Name="UserCreatable">TRUE</Field>
<
Field Name="ShowOnListCreate">TRUE</Field>
<
Field Name="ShowOnSurveyCreate">TRUE</Field>
<
Field Name="ShowOnDocumentLibraryCreate">TRUE</Field>
<
Field Name="ShowOnColumnTemplateCreate">FALSE</Field>
<
Field Name="FieldTypeClass">ACME.SharePoint.Blah.CustomField,
ACME.SharePoint.Columns, Version=1.0.0...</Field>
<PropertySchema>
<
Fields>
<
Field Name="MySetting"
Hidden="TRUE"
DisplayName="My Setting:"
MaxLength="500"
DisplaySize="40"
Type="Text">
<
Default></Default>
</
Field>
   ...

As you can see Hidden is set to “TRUE.”  “true” simply does not work.



What’s funny is that the WSS.XSD gives you intellisense in VS.NET (in most areas) for the following options for boolean fields: true, false, True, False, TRUE, FALSE.  Ok.  Why?


This was just one case where my choice of case caused an issue.  What about everywhere else?  So proceeded to tell my colleagues, including Bryan Phillips, about this oddity with hiding properties of custom fields.  He said that he always uses uppercase.  Not only for custom columns, but for everything.  I’ve typically used lowercase since it seemed to be close to my c# practices.  However, from now on, I’m going to capitalize my boolean values.

Wednesday, May 13, 2009

Understanding SharePoint Lists and Content Types

This post discusses lists and content types in SharePoint.  It’s an overview of the concepts from a developer’s perspective.

Before getting into content types, it’s important to do a brief review of Lists.  Central to SharePoint is the concept of a list, which is often compared to a database table.  If you spend any amount of time with lists you’ll quickly see the similarities.  Like database tables, lists have columns and rows.  You can query them, modify them, sort them and even index them.  And both lists and database tables also have a variety of column types for things like text, numbers, dates... Conceptually, they’re equals.

So why use lists in SharePoint?  Well, there are a number of features above and beyond what you can do with simple database tables.  Here are some of the main benefits:

  • User Interface: A SharePoint list provides not only the storage, but the user interface for working with the data.
  • Item Security: Lists support row-level security and security trimming.
  • Versioning: You can store multiple versions of data.
  • Ease of Use: Lists can easily be modified from within the browser.  End users can make these changes without a developer.
  • Content Types: Lists support content types.
  • There’s more, but I don’t have all day :)

User Interface

When you create a list in SharePoint, you get (for free) the user interface for working with the data in the list.  You get a new form, edit form, display form and a variety of views to display the data in a listing format.  As you add new columns the user interface changes and users can easily enter that information.  Compare this to a database table.  If you’re an end-user, you need to call a developer to modify the forms as fields change in the database.  A real pain and definitely not worth anyone’s time, in my opinion.

Item Security

You can lock down one row of data in a SharePoint list.  This not only prevents access to that one item, but it also prevents unauthorized users from actually seeing data in the list.  Even when you query the object model and retrieve items (rows) from a list, your results have unauthorized records trimmed out automatically.  That’s really cool.  Try doing that in a database.  It’s a lot more work.

Versioning

When you modify data in a SharePoint list, you have the option to enable versioning.  This will keep track of all changes for all columns in the list.  This feature also allows you to revert back to previous versions.  This is difficult to achieve in a database table solution.

Ease of Use

End users no longer have to bother the developer when they want to create a list to store something.  On their own, and with proper permissions, users can create and modify new lists.  Since all the forms are already done and up to date, users can essentially build a “web application” that has the functionality that used to take weeks to do in plain-old ASP.NET.  What?!!!  You mean that I can no longer charge my clients to build tables and the simple CRUD forms used to input/edit data?  That’s right.  All the out-of-the-box capabilities of SharePoint has essentially raised the bar regarding client expectations.  Clients expect it done now and can they actually do it themselves.  However ... do not despair.  There’s still plenty of software development to be done for your SharePoint users: workflows, web parts, custom jobs, custom forms...  Clients are never satisfied for long and, for a developer, this is a good thing.

Content Types

Let’s spend the remainder of this post on Content Types.  A content type is essentially a set of columns that can be used over and over in multiple lists.

Before we get too deep, you need to understand that columns can live on their own.  In a SharePoint site, there’s a special list of “Site Columns” that are already created and can be used in multiple lists.  For instance, there are standard columns like Author, Address, Spouse, and many more.  These are listed in the Site Column Gallery.  This is found on the Site Settings screen.

image_10_2D47FEB8.png (155×175)

And when you look at the Site Column Gallery, you’ll see a list of columns that Microsoft provides.  You can add your own, too.

image_8_2D47FEB8.png (529×409)

So Site Columns live in the Site Column Gallery.  They have all the settings required for each column.  For choices, these are things like the actual choices that need to be selected.  For others, it might be whether or not they’re required.

You can add one or more columns to a list when you go into the list settings screen of the list.  Here’s a simple Projects list where we want to add some site columns.  As you can see, it can be a real time-saver compared to creating new columns on the list each time.

image_12_2D47FEB8.png (514×264)

Next choose to add from existing site columns.

image_14_5B355170.png (640×259)

Then choose some columns to add.  Pretty easy.

image_16_5B355170.png (640×394)

So now we have a list with new columns no big deal.  But where do Content types come into this.  Well, just as we can add columns to a list, we can add columns to a Content Type.  Let’s create a Project content type and show how we can use that on two different lists (one for internal projects and one for external projects).

There’s another gallery that we need to introduce.  This is the Content Type Gallery.  Look under Site Settings and you’ll see this.

image_18_5B355170.png (170×182)

From here, we can see all of the built-in content types.  Open the Contacts content type and look around.

image_20_5B355170.png (640×451)

Notice how the Columns appear here just like they did in our list settings screen.  Although the content type doesn’t really store any data, it does define the structure of the data.  Let’s create a new content type for our projects.  Go back to the Content Type Gallery and click Create.

image_22_5B355170.png (285×111)

Next, give the content type a title and choose “Item” as the parent content type.  This is found under the “List Content Types” category.  I’ll talk more about the parent content type shortly. 

image_24_5B355170.png (640×395)

Once you’ve done this, you’ll be sent to the content type settings screen for your new content type.  From here, you can add new columns as necessary.  Notice that you already have a Title column.  This is because we chose the Item content type as it’s parent.  Item is the top-most content type for all items in SharePoint.  Every content type you create must use Item as a parent or some child of Item.  This is a really powerful concept that essentially lets you “inherit” the columns from a parent type.  It’s really just that simple.  We inherit from Item and we automatically get a Title fields.  If we inherited from Contact, we would get all the fields of Contact.  Let’s add some of our own fields for our project structure.

image_26_5B355170.png (279×165)

Note that you can create new site columns on the fly, but we’ll just choose from the existing site columns.  It’s quicker.  Add some columns that make sense for projects.

image_28_5B355170.png (503×280)

Now, let’s create a couple of custom lists: Internal Projects and Client Projects.  From the Create page, choose Custom List.

image_30_5B355170.png (172×157)

So now, we have three lists.  The one I originally started with where I added my own columns and the two we just created.  So we have two distinct lists to contain our internal and client projects now.  Let’s enable content types for each and then choose our “Project” content type.  Here are the steps for the Internal Projects list.  First, go to the settings for the list and choose Advanced Settings:

image_34_5B355170.png (578×333)

Next, choose to enable content types.

image_36_5B355170.png (640×72)

This gives us the ability to add new content types.  It also shows a new section in the list settings page that displays the content types that are in play.

image_38_5B355170.png (640×454)

Notice the new section.  Also notice that one content type is already in play.  Content types are always in play in SharePoint lists and document libraries.  Allowing management of content types simply let’s us see and work with them.

Next, add our Project content type.  Choose “Add from Existing Content Types” and choose project.

image_40_5B355170.png (640×314)

Save your changes and now, let’s see the list.  Click on the New button drop-down.

image_42_5B355170.png (306×165)

You can create new Item (that only has a Title) and a new Project that contains a new project form with all the fields we selected for our content type.  Here are the two forms.

image_44_5B355170.png (640×255)

So regardless of whether or not you’re in the Internal projects list or the Client Projects list, you’ll have the same form, but the data is stored in two different lists.  This concept doesn’t even exist in a typical database.  Try playing around with this.  Go back to one of your lists and chose a bunch of content types.  You’ll see some pretty impressive behavior:

image_46_4643CEFD.png (274×341)

Content types are quite powerful and I’ve just scratched the surface here.  They’re used all over the place in SharePoint.  In the MOSS Publishing and Collaboration Portal sites, content types are used to define the fields used in Page Layouts.  This is great concept that helps “prescribe” the fields that users can fill out in when creating new web pages for public facing sites.  And more at home, content types can be used with document libraries to define default document templates.  For instance, you can define a default “contract” document for your entire organization.  Then when users create new documents in a Document Library, they always have the latest contract boiler plate.

There’s certainly more to lists, document libraries and content types, but i hope this has given you a taste of the concept.  It took me a while to understand them, but I’m glad it finally sunk in.  Happy SharePointing.

Thursday, April 16, 2009

SharePoint Governance

We just had another great Kentucky SharePoint User Group meeting (KYSPUG) tonight.  Rob Bogue came all the way down from Indianapolis and spoke to the group about the topic of governance.  He did a wonderful job sharing with the group what governance is all about and how to get starting putting a plan in place so the business has a process to follow when it comes to SharePoint.  Here are some take-a-ways:

Quotas are a good thing.  A quota is a “governor” of sorts that can be set on SharePoint site collections which limits the overall content size.  Setting them relatively low helps keeps SLAs in-check because there are limits within SharePoint that can cause problems when exceeded.  For instance, you shouldn’t go beyond 100GB for a site collection’s size.  the size of the database becomes too unwieldy at that point when it comes to disaster/recovery scenarios, or even simple backup/restore scenarios for that matter.

In general governance is about the process, not so much a document.  However, when writing a document be very clear on what you mean.  Keep it concise.  Write just enough information and don’t fall into the trap of adding too much garbage that’s not really relevant. 

Getting “setup” properly, before you begin, is key.  If you don’t plan for things like training, you end up being in a reactionary state when you go to implement your governance plan/process.  Training is key, but often overlooked.  You don’t need to spend a lot of money however.  There are numerous reference materials online and plenty of books available.

Much thanks for Rob coming down to visit our group.

Wednesday, April 15, 2009

SharePoint Designer is FREE!

Yes.  It wasn’t an April fools joke as someone asked me :).  Microsoft actually made SharePoint Designer a free tool.  In case you don’t know about SharePoint Designer, it is the replacement product for FrontPage.  It’s a great tool that has all the capabilities of FrontPage, but clearly stands apart from that tool.  It’s meant to be a tool for power users and developers to modify pages within SharePoint sites.  It can be used to edit various HTML files in a stand-alone fashion, but SharePoint is really where it excels.

It’s a great thing that this tool is free.  You really can do a lot with it.  Enjoy:

http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=baa3ad86-bfc1-4bd4-9812-d9e710d44f42

Tuesday, April 14, 2009

Using CKS:EBE 2.5

I finally carved out some time to look into the latest updates to the CKS:EBE (Community Kit for SharePoint: Enhanced Blog Edition).  I took the dive, got the latest build and ran with it.  I’ve come to like it, but it wasn’t without a few issues.  I implemented EBE 2.0 about a year ago and always had some minor issues.  Things like CAPTCHA not working and a crazy amount of spam.  So I couldn’t receive comments.  I blogged a little but was mainly frustrated.  So I went to CodePlex to see what the great EBE team put together with the latest bits from (4/12/09).  Although there doesn’t appear to be too much in the way of updated news or documentation, I have to say the team really did a great job.  There were a number of improvements that fixed the issues I had with the previous version (2.0).

Having said that, the SharePoint blog site has some oddities that make it different than other sites.  And the CKS:EBE on top of that adds another layer of complexity.  With that complexity, I have to admit that it crossed my mind several times to just abandon this whole thing and start using my Live Spaces account.  But after some tweaking, things seem to be working fine now.

Things are still “under construction” but here’s a list of the items changed so far:

  • added the tag cloud to the “Intense” theme
  • removed links to trackbacks and trackback counters
  • removed anonymous permissions to the trackbacks received list –  I have no use for trackbacks.  I just want a simple blog :)
  • enabled alerts for comments so I’ll be notified when a comment comes in

These changes included changes to the files in the theme directory and the root directory using SharePoint Designer.

I’m hopeful that this package will meet my needs for blogging going forward.  Thanks EBE team.

Sunday, April 12, 2009

Sharing Resources among WSPs is Dangerous

Did you know that if you create two different SharePoint solution packages (WSPs) that both share assemblies or even images, that retracting the one of the solutions will remove the resource and break the other WSP(s)?

Let’s say you have a shared utility library that has some common SharePoint routines in it that gets installed in the GAC.  Ideally, you would want your clients to only install one solution package for this functionality.  So you build a workflow, for instance, that uses your utility assembly and install it and everything is OK.  The way you’d do that is to modify the manifest.xml so that the WSP includes your assembly, installs it into the GAC and makes the appropriate Safe Control entry, if necessary.  Your manifest.xml might look something like this:

<?xml version="1.0" encoding="utf-8"?>
<Solution SolutionId="8d231d46-e165-4e39-8c69-dfd0d1b1d0de" ResetWebServer="True"
xmlns="http://schemas.microsoft.com/sharepoint/"
>
<!--Feature Manifest files-->
<
FeatureManifests
>
<
FeatureManifest Location="SuperWebPart\feature.xml"
/>
</
FeatureManifests
>
<!--Assembly files
-->
<
Assemblies
>
<
Assembly Location="SuperWebPart.dll" DeploymentTarget="GlobalAssemblyCache"
>
<
SafeControls
>
<
SafeControl Assembly="SuperWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=de41bace3a102f2c"
Namespace="SuperWebPart" TypeName="*" Safe="True"
/>
</
SafeControls
>
</
Assembly
>
<
Assembly Location="MySuperUtilities.dll" DeploymentTarget="GlobalAssemblyCache"
>
<
SafeControls
>
<
SafeControl Assembly="MySuperUtilities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=21bf3856ad364e35"
Namespace="MySuperUtilities" TypeName="*" Safe="True"
/>
</
SafeControls
>
</
Assembly
>
</Assemblies
>
</
Solution>

You can see how the instructions above will place the utility library (MySuperUtilities.dll) in the GAC.


Next, you build another web part (or some other SharePoint thing: workflow, web page…) that needs to use the same utility library.  You also want clients to only have to install this one WSP.  It’s just simpler for them to have to install one WSP as opposed to multiple.  And this new web part may be installed on a farm that doesn’t have the first on installed.  So you, being a well-intentioned developer, make sure your manifest.xml includes the utility assembly.  Your second web part might look something like this:

<?xml version="1.0" encoding="utf-8"?>
<!--
Manifest created STSDEV utility at 2/10/2009 1:37:08 PM
-->
<
Solution SolutionId="83224d36-a135-4bb9-cd39-dfdfddddfb23" ResetWebServer="True"
xmlns="http://schemas.microsoft.com/sharepoint/"
>
<!--
Feature Manifest files
-->
<
FeatureManifests
>
<
FeatureManifest Location="SuperDuperWebPart\feature.xml"
/>
</
FeatureManifests
>
<!--Assembly files
-->
<
Assemblies
>
<
Assembly Location="SuperDuperWebPart.dll" DeploymentTarget="GlobalAssemblyCache"
>
<
SafeControls
>
<
SafeControl Assembly="SuperDuperWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b3adf5ce3a132f33"
Namespace="SuperDuperWebPart" TypeName="*" Safe="True"
/>
</
SafeControls
>
</
Assembly
>
<Assembly Location="MySuperUtilities.dll" DeploymentTarget="GlobalAssemblyCache"
>
<SafeControls>
<
SafeControl Assembly="MySuperUtilities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=21bf3856ad364e35"
Namespace="MySuperUtilities" TypeName="*" Safe="True"
/>
</
SafeControls
>
</
Assembly
>
</Assemblies>
</
Solution>

So you can see how your two web parts will each install (and retract) the utility assembly (MySuperUtilities.dll).  Nice.  What happens when you want to install both web part packages on the same server.  No problem.  They both install and both work great.


Ok.  What’s the catch?  There’s always a catch :)  So the client decides that they don’t use the first web part.  They’ve decided to completely stop using it and want to retract the package using central admin or STSADM.  Unfortunately, as soon as they do that MySuperUtilities.dll is removed from the GAC, along with all the other files for this package.  Then the second web part will obviously break.



Note:


When talking about web parts and some other SharePoint coding concepts, you do have the option to use CAS (Code Access Security), which allows you to drop your DLLs in the /bin folder of your web application.  Using the bin avoids the complication of shared assemblies that may be removed.  The scenario that I’m describing here deals with a more common approach and that is adding assemblies in the GAC.  There’s a much larger discussion on CAS verses GAC, which I won’t go into here.


So how do we solve this dilemma?  Unfortunately, we have to install those shared resources manually or through a separate WSP.  I recommend a separate WSP, because it will assist you in deployment/retraction across an entire farm of servers.  So this WSP exists only to install DLLs or other shared resources.  This whole issue is a complex one to solve, but one I hope the SharePoint team addresses at some point.  It sure would be nice that before SharePoint retracted something in a farm, it would look at a complete list of farm resources in use by other packages to see if it can be retracted.  All that information is “known” by SharePoint in the configuration database anyway.  Then maybe it would prompt/warn users about these shared resources.

Saturday, March 21, 2009

Online Color Scheme Tool

If you have anything to do with user experience development, you often have to deal with colors.  For those of us programmers, it’s not something that comes naturally.  It seems more of an art than a science.  Actually, there’s quite a bit of science to it.  The human eye is attracted to color schemes that are based on mathematical formulas.  Some colors complement others better.  There are also a variety of tools that help you choose colors that “relate” to your main color choice.  I’ve used this approach on several projects and it’s worked quite well.

Here’s a very good tool from Petr Stanicek that allows you to choose a color and then look at different themes based on that color.  You can also download a dynamically generated CSS of your color choices.  A very cool application.  Kudos for Petr’s work and I urge you to donate so he can keep up this good work.

image_2_522C7B06.png (514×341)

Oh yeah, there’s no install.  It’s all through your browser:

http://colorschemedesigner.com/

Enjoy.

Sunday, December 28, 2008

Re-Provisioning Data in a SharePoint List

Synopsis: This post addresses a technique I recently found to provision data in a SharePoint list instance where a feature may be activated and deactivated.

The documentation here tells you how you can use the ListInstance element to provision an instance of a list and you can provision that list instance with rows of data.  Here's a simplified version of ListInstance XML I've used in a file:

<ListInstance
    Description="Contains all work locations."
    Id="Location"
    OnQuickLaunch="FALSE"
    TemplateType="10012"
    Title="Location"
    Url="Lists/Location">
    <Data>
        <Rows>
            <Row>
                <Field Name="Title">Jacksonville</Field>
            </Row>
            <Row>
                <Field Name="Title">Louisville</Field>
            </Row>
            <Row>
                <Field Name="Title">Marion</Field>
            </Row>
        </Rows>
    </Data>
</ListInstance>

What the documentation lacks is any explanation of what you can put in the Field attributes.  It's pretty intuitive that the Name attribute corresponds to the name of a field. It would have been nice if the documentation explained that this was the internal name, but that's ok.  Now we know, right?  Anyway, you can just specify any field available in your list structure.  Now, if we provision our feature the data will be provisioned to the designated list.  In the example above, I had created my own list (#10012), but this could be any out-of-the-box list or document library.

That's all good, but what happens if someone deactivates and re-activates the feature.  A very likely scenario.  In that case, data is duplicated each time.  The first time the feature is activated on an empty list the follow are created:

  • Jacksonville
  • Louisville
  • Marion

When the feature is deactivated and re-activated, the list instance provisioning process occurs again and the data is duplicated.  You end up with the following:

  • Jacksonville
  • Louisville
  • Marion
  • Jacksonville
  • Louisville
  • Marion

This was certainly not desirable behavior and was confusing to me why SharePoint would do this by default.  So my options had been to programmatically delete the list or empty the list during deactivation.  Not pretty in my opinion, but it got the job done.

I lived with this "problem" for many months until I got fed up and went on a hunt for the solution.  I spent time looking for a flag somewhere that would change this default behavior.  I looked for the longest time for a way to turn this off.  What I finally figured out is that by simply specifying the ID, I can control this.  The ID field is usually automatically generated for each item in the list.  Here we're able to set the value.  All I needed to do was to specify a unique value for the ID field for each row.  That's it!  So my resulting XML looked like this:

<ListInstance
    Description="Contains all work locations."
    Id="Location"
    OnQuickLaunch="FALSE"
    TemplateType="10012"
    Title="Location"
    Url="Lists/Location">
    <Data>
        <Rows>
            <Row>
                <Field Name="ID">1</Field>
                <Field Name="Title">Jacksonville</Field>
            </Row>
            <Row>
                <Field Name="ID">2</Field>
                <Field Name="Title">Louisville</Field>
            </Row>
            <Row>
                <Field Name="ID">3</Field>
                <Field Name="Title">Marion</Field>
            </Row>
        </Rows>
    </Data>
</ListInstance>

Now, when re-provisioning the list instance data, the three items I originally provisioned will never be duplicated like before.  I can deactivate/activate the feature to my heart's content.  This is helpful for simple lookup lists like states/provinces.

Tuesday, June 24, 2008

Fun with SharePoint Designer: Press Releases

Synopsis: This is one in a series of blogs on how I used SharePoint Designer in real-world solutions.  This covers creating a list and a set of pages in a WSS site that render press releases online.

I recently helped a client build a web site that required a press release page. On the main page, the anonymous users were supposed to see a list of short titles in the corner of the page.  When they click on that short title, they should be directed to a page that displays a full title and the full article.  Additionally, when users navigate to the tab on the top toolbar, they should see a listing of all the active press releases.  All this is to be styled using custom HTML defined in the master page.

From the administration perspective, we want the admin (not me as the programmer) to go into an admin area to edit these press releases.  They need to be able to create new ones, approve them and set begin/end dates on them.

A SharePoint list is a great solution to this.  The first big win is that we don't have to build much of the administration functionality at all.  With any SharePoint list, of course, you get all the input/listing and edit forms.  So the admin need only know how a list works.  Also, we want to be able to support things like versioning, check-in/check-out and lightweight approvals -- again, all available in a simple SharePoint list and all available in WSS as well as MOSS.  So we'll start in a simple blank site and build a custom list that meets our needs and call it "Press Releases."  From here, we'll add some columns to end up with these:

  • Title (already on the list, required)
  • ShortTitle (single line of text, required)
  • Body (multi-line text that supports rich text, required)
  • StartDate (date and time, required)
  • EndDate (date and time, required)

Your columns should look like this now:

image_2_01409BA9.png (559×219)

Then, while in List Settings, go to Versioning and enable that.  Also enable item approval, and check-in/check-out.  Approval is really all we need here, but the other is an added bonus for the administrator.  Add a couple of press releases to the list to have something like the following:

image_4_01409BA9.png (640×419)

The next thing we need to do is turn our attention to SharePoint Designer, as this will be the tool we'll use to render our data in various pages.  There are two pages we're concerned about: PressRelease.aspx, and ReleaseList.aspx.  The PressRelease.aspx page will show a single press release.  ReleaseList.aspx is going to show us multiple press release titles in a full-view page.  The default page could display a short list of press releases so users can see them right up front on our page. 

ReleaseList.aspx

Let's start with our most simple page, the ReleaseList page.  Using SharePoint Designer, create the ReleaseList.aspx page in the root of the site and, if you want, attach the master page so you have the look and feel you want to achieve.  In this exercise, we'll simply use a blank page so we don't make things too complicated.  You'll see something like this:

image_6_01409BA9.png (640×330)

Next we need to add some data from our list.  Go to the Task Panes menu and make sure the Data Source Library tab is selected.  If selected, you can see it appear to the right as an additional tab which is peer to the toolbox.  This task pane shows us all the data sources available in the environment.  When SharePoint Designer opens up, it communicates to the server to see what's available.  Notice you can have lists, document libraries, XML files, and external data.  Also, if you're using MOSS Enterprise, you'll see BDC data sources show up here.

Next, we need to select our data source (Press Releases list) and right-click to see a drop-down.  We'll choose Show Data, which will take us another task pane which shows us all the columns available in the list we've chosen.  Select the Press Releases list from the available lists and then choose to Show Data from the drop-down that appears, just like this:

image_10_01409BA9.png (622×480)

Once you do this, all the available columns show up in the display tab called Data Source Details.  From here, click the Title field and drag it to the design surface below the title.  This will render all the items in the list in design-time, which is pretty cool.  The resulting screen looks like this:

image_14_01409BA9.png (640×355)

Next we need to filter out those item which aren't approved and don't fall into the desired publishing timeframe.  Note, we'll use the Common Data View Tasks to do this.  Click on the filter link and then set the criteria as follows:

Approval Status = Approved

Start Date <= today

End Date >= today

The filter should look like:

image_18_01409BA9.png (438×258)

Next, you can adjust the layout by selecting the Data View Properties.

Now that we have a press release listing page, what happens when I click on a title?  Now, we need to link the title to the PressRelease page, which will display a single press release.  Select the Title and change it's type to Hyperlink as below.

image_12_01409BA9.png (640×355)

Continue through the warning about the trusted environment.  Change the following:

Address: PressRelease.aspx?id={@ID}

Text to Display: {@Title}

Your screen should look like this:

image_16_2F2DEE61.png (640×320)

PressRelease.aspx

Now, let's create PressRelease.aspx.  This page is going to receive a querystring parameter.  Let's start with another blank aspx page and choose the data library to find our Press Releases list first.  Then select "show data" to view the available columns.  Next, choose the Title and Body columns an choose to insert a single item view:

image_22_2F2DEE61.png (370×450)

Now, we need to filter the item that displays with the querystring parameter passed in.  Choose "Parameters" from the Common Data View Tasks pane that appears.  Then add a new parameter that looks at ID as a source parameter in the querystring.

image_24_2F2DEE61.png (502×333)

Next choose Filter from the Common Data View Tasks.  We need to filter the press releases to find the one from our newly created parameter.  The filter should look like this:

image_26_2F2DEE61.png (438×258)

Now you have a press release system.  Administrators can get to administrative pages to add/update press releases and end users can only see those press releases which are active and approved.  Through the use of a SharePoint list, we also have versioning, which is difficult to achieve in a typical database.

Monday, June 23, 2008

How to Provision a Link in Site Settings

Have you ever wondered how you could add your own links to the Site Settings area within SharePoint?  If you want to add a link that shows up in that location try this out.  The following is CAML provisioning code that is initiated by a feature.  This assumes you know what SharePoint Features are.

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

    <CustomAction
       Id="MyCustomLink"
       GroupId="SiteCollectionAdmin"
       Location="Microsoft.SharePoint.SiteSettings"
       RequireSiteAdministrator="true"
       Sequence="300"
       Title="Synchronize Root Names">
        <UrlAction
           Url="_layouts/CustomApplicationPage.aspx" />
    </CustomAction>

</Elements>

This will give you a link as shown below:


Location tells SharePoint to target the site settings page.

GroupId tells SharePoint to put the link in the site collection administration section.

Sequence is the position in the list.  If you're not happy with it's position, just change the number.  Lower numbers appear higher in the list.

RequireSiteAdministrator is pretty self-explanitory.  If you're not a site administrator, you won't see the link.