Paul's profilePaul Galvin's SharePoint...BlogListsSkyDrive Tools Help

Blog


    January 31

    This is Why I don't Like Using Tools Day Zero

    http://groups.google.com/group/microsoft.public.sharepoint.portalserver.development/browse_thread/thread/41e8cbe4f15e8b4c/76506ea401403e35?#76506ea401403e35

    If the tool is doing stuff you don't understand and then it fails in step n of an unknown number of steps, you're dead in the water...

    </end>

    Technorati Tags:

    Solution to BDC ADF Import Failure: "The following error occurred:"

    I was once again crafting BDC ADF files by hand (so that I can build up my "get off my lawn!" cred) and hit this lovely error:

    image

    "Application definition import failed.  The following error occurred:"

    As you can see, there's an error, but ... it's not going to tell me what it is.

    In my case, the issue turned out that I had started off with a functional ADF for a different project that connected to a database and executed a SQL query against a view.  In this new project, I am calling a method on a web service.  I had stripped out the DB specific stuff and added my web service stuff, but failed to update the <LobSystem>'s Type attribute.  I switched it to "WebService" and I happily moved on to newer and more exciting import errors, which were handled in due course.

    Here is the wrong LobSystem:

      <LobSystem
        xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
        xsi:schemaLocation=http://schemas.microsoft.com/office/2006/03/BusinessDataCatalogBDCMetadata.xsd
        Type="Database"
        Version="1.0.0.0" Name="xyzzy"
        xmlns="
    http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog">

    This is correct:

      <LobSystem
        xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
        xsi:schemaLocation=http://schemas.microsoft.com/office/2006/03/BusinessDataCatalogBDCMetadata.xsd
        Type="WebService"
        Version="1.0.0.0" Name="xyzzy"
        xmlns="
    http://schemas.microsoft.com/office/2006/03/BusinessDataCatalog">

    </end>

    Technorati Tags:

    BDC Seems a Viable Replacement For Lookups

    UPDATE: This MSDN posting has some interesting observations from JXJ based on his, mainly negative, experiences going down this path: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2623565&SiteID=1

    We have a business scenario where we need to link two documents libraries via a common "document ID" field.

    We often use a lookup column to implements links like this.  There are several drawbacks to lookup columns, three of which are:

    1. Only one column from the lookup lookup library can be linked. 
    2. Performance: The source library could contain hundreds of entries.  That's too many entries in the lookup.
    3. Search: There is no integrated search.  I don't mean in the MOSS sense of search, but there's no way to search / filter on multiple columns from the source document library and locate the link you want.

    Backed by BDC, we can use a "business data" column type and it provides a superior search and even allows multiple columns of data to appear in list views. 

    I've had some preliminary success with this approach and plan to write more about it.

    If you've worked this angle before and have any comments, please share!

    </end>

    Technorati Tags:
    January 30

    Solution to BDC Import Error: "Could not load Type described by TypeDescriptor's TypeName ..."

    I've been working with BDC today, coding ADF files by hand and generating myself some errors.  One such error:

    Application definition import failed. The following error occurred: Could not load Type described by TypeDescriptor's TypeName. Parameter name: typeName Error was encountered at or just before Line: '35' and Position: '20'.

    MOSS displayed this error when I tried to import the ADF XML file.

    I researched the Internets and found that I was referencing the LOB instance name (from the <LobSystemInstance>) in my <TypeDescriptor> node when I should have referenced the LOB name itself (from <LobSystem>).

    Wrong:

    <TypeDescriptor TypeName="Conchango.KeyValue, LOB Instance Name" Name="KeyValue">

    Correct:

    <TypeDescriptor TypeName="Conchango.KeyValue, LOB Name" Name="KeyValue">

    Hope this one saves someone an hour or two of time.

    </end>

     Subscribe to my blog!

    Technorati Tags:

    January 27

    Solution to Problem: "FileNotFoundException" With My Feature Receiver.

    I was working on a feature last week that would add some event receivers to a specific list instance.  (I blogged a bit about that list receiver here).

    Using the command line, I could install the feature with no error (but see below for the hidden error).  When I tried to deploy the feature on the site, MOSS complained of a "FileNotFoundException" error.  This blog entry describes how I solved it. 

    This is the error that MOSS showed me in the web browser:

    Feature 'b2cb42e3-4f0a-4380-aaba-1ef9cd526f20' could not be installed because the loading of event receiver assembly "xyzzyFeatureReceiver_0" failed: System.IO.FileNotFoundException: Could not load file or assembly 'xyzzyFeatureReceiver_0' or one of its dependencies. The system cannot find the file specified.
    File name: 'xyzzyFeatureReceiver_0'
       at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
       at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
       at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
       at System.Reflection.Assembly.Load(String assemblyString)
       at Microsoft.SharePoint.Administration.SPFeatureDefinition.get_ReceiverObject()
    WRN: Assembly binding logging is turned OFF.
    To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
    Note: There is some performance penalty associated with assembly bind failure logging.
    To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

    Troubleshoot issues with Windows SharePoint Services.

    I know how to deliberately cause that error: don't install the assembly in the GAC.  But, it was in the GAC.  I normally install assemblies into the GAC by dragging them into the c:\windows\assembly folder using windows explorer.  I've never felt 100% comfortable doing that because I always thought that gacutil existed for a reason ... so I tried that.  It made no difference.

    I searched the Internets and found this post: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2243677&SiteID=1

    The poster happened to be using the same root bit of code (from the Inside WSS book from this list) so that was a hopeful sign.  However, the suggestion of decorating the assembly with an [assembly: ] directive didn't make sense to me.  I tried it anyway and I was right.  It made no difference.

    Then I noticed that my class definition was not public.  I made it public and that made no difference.

    Next, I went to the trouble of enabling the "assembly bind failure log" (following the helpful and accurate instructions provided) and this is where things started to get interesting.  That log shows me that the runtime is searching everywhere on that server for my assembly.  It even appears to be searching for it in my medicine cabinet.  But ... it won't search for it in the GAC.

    I put on my winter jacket and go searching the Internets again and find that someone has had this problem too.  The lengthy discussion in that posting peters off into nothing and I can't find a solution.

    I move my assembly into one of the places the log claims it's searching and I make a little more progress.  I'm rewarded with a new error in the browser when I try to activate the feature:

    Failed to create feature receiver object from assembly "xyzzyFeatureReceiver_0", type "Conchango.xyzzyFeatureReceiver" for feature b2cb42e3-4f0a-4380-aaba-1ef9cd526f20: System.ArgumentNullException: Value cannot be null.
    Parameter name: type
       at System.Activator.CreateInstance(Type type, Boolean nonPublic)
       at System.Activator.CreateInstance(Type type)
       at Microsoft.SharePoint.Administration.SPFeatureDefinition.get_ReceiverObject()

    Troubleshoot issues with Windows SharePoint Services.

    Time for one last trip to the Internets!

    This time I find out, predictably enough, that MOSS issues this error because the assembly is not in GAC. 

    I want to get something positive out of this and try to feel a little proud that I've created the Fugitive of MSIL assemblies, but it's not working.  I'm just plain annoyed.  I find myself muttering "chicken or the egg" under my breath.

    I finally decide to punt.  I create an entirely new project and copy/paste the code from the incredible-cloaked-from-the-GAC-assembly non-working project over to this new project.  (I look for a build flag called something like "hide from assembly binding if installed in the GAC" but can't find one).

    I install the feature and activate it and ... it works!  So, after all that, I had to basically 'reboot' my project.  This is another reason why I hate computers.

    I did learn something useful  from this.  I had been installing features using the stsadm command line all day long and been using the "-force" option out of habit.  For some reason, I did not use the -force option when I installed the new project.  This time, I did actually, truly forget to copy this new project's assembly into the GAC.  As a result, I received that "FielNotFoundException" error.  This time, I got it from stsadm, not when I tried to activate the feature via the web browser.  So, -force actually plays two roles.  It allows you to re-install an existing feature.  It also allows you to install a buggy feature that cannot work at runtime by suppressing the error.  It probably says as much in the help somewhere but I never noticed it.

    </end>

    Sunday Funny: Top 10 Ways To Annoy Your Wife

    1. Buy broccoli when you know there is already more than enough in the fridge.
    2. Go for a run.  Cool off.  Take off clean pillow case and replace with T-shirt.  Cover with clean pillow case.
    3. When driving, ask if we should go the wrong way down a one-way street.
    4. For 15 years, every Sunday that you wife suggests going to a museum, express surprise that museums are open on Sunday's.
    5. For 15 years, occasionally suggest going to the local book store on Sunday.  Express surprise that they are not open on Sunday's (thanks a lot Blue Laws!).
    6. Use 20 points to do a 3 point turn. 
    7. On a cool early Fall afternoon, walk into the room and turn on the A/C.  Complain that it's cold.  When wife says, "then why did you turn that on, silly" and gets up to turn it off, grab the warm spot she had on the couch.  Bonus points if she does not realize you did it until much later.
    8. Open up a can of delicious white albacore tuna and eat it straight from the can, in bed, at night.
    9. Go into the kitchen while wife is eating dinner, open up the cutlery drawer and push utensils around until wife screams, "what are you looking for!"
    10. On receipt of new business cards, secretly place them all around the house: Under the bed, in pillow cases, inside coffee cups, in her purse, in coat pockets, car glove compartments, the pantry -- anywhere you can think of. 
    11. Write blog entries about your wife.
    12. Wake up.
    13. When walking the streets of New York City, be on the alert for "crusty" objects on the ground.  Keeping in mind your wife's special fears, reach down as if to pick one up up and ask, "hmm, I wonder what that is?" (Be prepared for wife to body slam you as if she's a secret service agent protecting the President  from a sniper or you'll find yourself laying on your back on the sidewalk).
    14. Drive twice around a parking lot looking for space.  You know you've really hit pay dirt when your son in the back seat yells, "Oh no! He's doing it again!"
    15. Write "top 10" lists that don't have 10 items.

    ===

    Bonus wife joke:

    Two male co-workers go out to lunch.  One of them tells the other, "I let loose an embarrassing Freudian slip the other night."

    "A Freudian slip?  What's that?"

    "Well, when we finished eating, the waitress came by and asked how we liked our meals. I meant say, 'I loved the chicken breast' but instead I said 'I loved your breasts'.  I was so embarrassed."

    "Ah," his co-worker replied.  "I had the same thing happen to me this weekend with my wife.  We were eating breakfast I meant to ask her to pass the butter, but instead I screamed at her, 'You ruined my life!'"

    </end>

    Technorati Tags:
    January 25

    Event ID 1023: "Windows cannot load extensible counter DLL MSSCNTRS"

    UPDATE (04/08/08): I seem to have solved this problem.  From the command line, I ran "c:\windows\system32\lodctr /R" as per an entry talking about InstallShield problems and that appears to have solved it for me.

    I have noticed that lately, my desktop/server fan never turns off.  I know it used to turn off.  I took a moment to check it out noticed that the a VMware process was running a consistent 20% utilization on one of the CPU's.  I checked the event log and saw these errors in the application log happening dozens of times per minute:

    Windows cannot load extensible counter DLL UGatherer, the first DWORD in data section is the Windows error code.

    Windows cannot load extensible counter DLL UGTHRSVC, the first DWORD in data section is the Windows error code.

    Windows cannot load extensible counter DLL MSSCNTRS, the first DWORD in data section is the Windows error code.

    If I drill into the details of one of those messages, I get this:

    Source: Perflib

    Type: Error

    Category: None

    Event ID 1023

    I did some research and there was some indication it could be a permission problem in terms of access to the DLLs in question.  I played around with that stuff but could not affect things in a positive way so I gave up on that.

    VMware had been nagging me about performing an update for quite some time, so I jotted down the version I had installed (apparently "1.0.1 build 29996") and did the update.  This upgraded me to v1.04.  Sadly, it did not fix the issue.

    I can stop the insane number of messages going to my application log if I shut down a service named "VMware Authorization Service".  This prevents me from using the VMware software, so ... not such a great option. 

    The host operating system is Windows XP 64 bit. 

    I don't think this has always happened, but I don't recall any particular event that might have led to it.

    This is why I hate computers.

    </end>

    Technorati Tags:

    Quick & Easy: Rename Uploaded File Using SharePoint Object Model Via an Event Receiver

     

    UPDATE: This works but there are significant limitations which are described in the comments.  This may still be useful in some cirumstances.

    UPDATE 2: In my current project, users always upload documents.  As a result, I don't run into a problem where MS Word is running and thinks that the file was renamed on it.  I did run into a problem, "the file was modified by someone else" and solved this via a simple semaphore type flag.  Users need to change a meta data field from its default value to something else.  The itemupdated() receiver looks for a valid value there before actually performing the rename and since then, I have not had any problems.  Your mileage may vary.

    I have a client requirement to change the name of files uploaded to a specific document library to conform with a particular naming convention.  The API does not provide a "rename()" method.  Instead, we use "MoveTo(...)".  Here is a minimal bit of code to accomplish this:

     

            public override void ItemAdded(SPItemEventProperties properties)
            {
                SPFile f = properties.ListItem.File;
    
                f.MoveTo(properties.ListItem.ParentList.RootFolder.Url + "/xyzzy.doc");
                f.Update();
    
            }
    

    The only tricky bit is the "properties.ListItem.ParentList.RootFolder.Url".  The MoveTo() method requires a URL.  That mashed up string points me to the root folder of my current document library.  This allows me to avoid any hard coding in my event receiver.

    This is a more useful version that does the same thing, but assigns the name of the file to "Title":

            public override void ItemAdded(SPItemEventProperties properties)
            {
                DisableEventFiring();
    
                // Assign the title of this item to the name of file itself.
                // NOTE: This assignment must take place before we modify the file itself.
                // Calling update() on the SPFile seems to invalidate the properties in 
                // some sense.  Updates to "Title" failed until that change (and update() call)
                // were moved in front of the change to the file name.
                properties.ListItem["Title"] = properties.ListItem.File.Name;
    
                properties.ListItem.Update();
    
                SPFile f = properties.ListItem.File;
    
                // Get the extension of the file.  We need that later.
                string spfileExt = new FileInfo(f.Name).Extension;
    
                // Rename the file to the list item's ID and use the file extension to keep
                // that part of it intact.
                f.MoveTo(properties.ListItem.ParentList.RootFolder.Url + 
                    "/" + properties.ListItem["ID"] + spfileExt);
    
                // Commit the move.
                f.Update();
    
                EnableEventFiring();
            }
     

    The tricky bit there is described in the comment.  That was a bit of a surprise to me, but not hard to manage.

    This works well for me "as is" because I don't have a folder structure to worry about.  If I did, then I'd have to do more coding.

    This is all new stuff to me, so if someone sees a flaw or better way to do this, please email me or leave a comment.  Thanks!

    </end>

    Forum Discussion: Enforcing Best Practices Compliance in Non-Trivial MOSS Environment

    A fellow, "Mark", has started up a potentially interesting newsgroup discussion focusing on "establishing excellent SharePoint Governance from the start" for a 35,000 user environment.

    The discussion is here: http://groups.google.com/group/microsoft.public.sharepoint.portalserver/browse_thread/thread/6d9a738d981af772/1c390b15c5407db6?#1c390b15c5407db6

    Pop on over and contribute!

    </end>

    January 24

    Custom Action URL Won't Display for New Feature

    I'm still in the habit of crafting my feature XML files by hand since it's all quite new to me.  I don't want to rely on a front-end tool that does stuff I don't understand (he said as he wrote a blog entry using a tool he does not understand).

    Today, I was trying to add a custom action to the site settings but it just wouldn't show up.  I could install the feature and see it in the site features, but when I activated it (without error) it simply wouldn't show up on the drop-down menu.

    I finally realized that I misspelled "SharePoint" in the Location attribute of the <CustomAction> node.  This is the bad elements.xml file:

    <?xml version="1.0" encoding="utf-8" ?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
      <CustomAction
        Id="SiteActionsToolbar"
        GroupId="SiteActions"
        Location="Microsoft.Sharepoint.StandardMenu"
        Sequence="100"
        Title="Hello!"
        Description="Custom menu action added via a feature."
        ImageUrl="_layouts/images/menuprofile.gif">
    
        <UrlAction Url="http://www.xyzzy.com"/>
    
      </CustomAction>
    </Elements>
    

     

    Good:

    <?xml version="1.0" encoding="utf-8" ?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
      <CustomAction
        Id="SiteActionsToolBar"
        GroupId="SiteActions"
        Location="Microsoft.SharePoint.StandardMenu"
        Sequence="100"
        Title="Hello!"
        Description="Custom menu action added via a feature."
        >
        <UrlAction Url="http://www.xyzzy.com"/>
      </CustomAction>
    </Elements>

    That one took me a good two hours to figure out :)

    I take solace in the fact that some day in the future, I'll be able to say with conviction, "back in the day, I had to walk three miles up hill in the snow (barefoot!) in order to deploy a custom feature to MOSS.  You kids, you don't know how easy you have it!  Get off my lawn!"

    Can't wait.

    </end>

    Technorati Tags: ,
    January 15

    Blog Stats

    I thought some people might be interested in my blog's statistics.  You can use mine as a benchmark to compare your own.

    I'm running my blog on windows live spaces.  They collect stats for me and I don't know any way to control that.  It's good as far as it goes, but it's fairly limited in that I can't do much actual analysis with it.  I'd love, for example, to be able to generate a listing of my most frequently hit posts but I can't do that without a prohibitive manual process.  If someone knows better, please tell me.

    Live spaces status tell me: total hits for the day, total hits for the week and total hits since day zero.  It also tells me what people did to get to my blog (e.g. google, MSDN forum link, etc).

    In some ways, a "hit" is obvious. If you're reading this sentence right now, you've almost certainly registered as a single hit.

    RSS is a little confusing.  On one hand, I see individual RSS hits all day long.  But, I also see RSS "sweeps".  A sweep is when I see 20 or 30 RSS hits all within a one or two second window.  I assume these are automated things like google checking in on my site, maybe other people's browsers ... not sure.  They are definitely some kind of automated process.  I cannot tell, however, how many of my total hits are automated and how many have an actual human on the other side.  I would guess at least 100 hits per day are automated.

    On to the numbers!

    I wrote my first blog entry on July 27th, 2007.

    I have written approximately 60 blog entries since then, more than 50 of which directly relate to SharePoint.

    I started to keep track of of my hits in a spreadsheet on a daily basis at the end of September.

    Monthly Starts:

    First week of: Total Hits
    October 1,234
    November 2,162
    December 3,071
    January 2008 4,253

     

    Total by Month

    Month Total Hits
    October 6,620
    November 11,110
    December 13,138

     

    High Water Marks

    Type Total Hits
    Best Day 958
    Best Week 4,253
    Total Hits Since Day Zero 42,438


    I'm interested in others' stats.  If you care to share yours in the comments, please do!

    </end>

    Technorati Tags:
    January 13

    Sunday Morning Funny: "Yeah, yeah, yeah. Blah, blah, blah."

    About six years ago, my four-year-old son and I were upstairs watching a Discovery channel "shark attacks" special (possibly this one).  He was very young at the point and I was always worried what he might see on a show like this and how he might take it.  I didn't want him to develop, for example, any special fears of the water or blab something inappropriate to his friends and possibly cause his baby friend network to come crashing down.

    Discovery handles these kinds of subjects very well.  It's not about creating a fear of something, but rather to show how unusual it is for sharks to attack humans. 

    So, we're watching it and there is this one particularly scary attack involving a small girl.  As Discovery is building the drama of the attack, my son (who has always been extremely jumpy anyway), is getting very excited.  I make some noises about how unusual it is for sharks to attack people, and how bad the poor girl must feel.  I'm trying to explain that people recover from these events and become stronger for it.  However, I had misinterpreted his excitement.  He was not worried about the girl at all.  Instead, while clapping his hands, he tells me, "The sharks love it!  It's terrific.  It's wonderful.  Its a DREAM COME TRUE!"

    I thought this was hilarious, but also very disturbing.  On the one hand, I was glad -- even a little proud -- that he could have strong empathic feelings, cross-species though they may be.  As humans, we need to develop our "empathic muscles" so speak or you'll end up like this guy :)  On the other hand, he was feeling cross-species empathy toward a species who was exhibiting behavior inimical to his own.  I was really struggling with this when the narrator used the word "paradigm".  My son picked up on that and asked me what that meant.

    That's not such an easy word to describe to a four year old, but I gave it a try.  When I think of the word "paradigm", Thomas Kuhn is never far from my thoughts.  I read The Structure of Scientific Revolutions back at Lafayette and for better or for worse, the word "paradigm" is pregnant with extra meaning for me.  (Sort of like the word "contact" after hearing a Movie Phone voice tell me where I could see that movie [I thought the book was better]; I always say to myself, "CONTACT!" whenever I see or hear someone say "contact").

    Anyway, I'm trying to explain to him a Kuhnian definition, that it's "a historical movement of thought" and that it's a "way of thinking with a number of built-in assumptions that are hard to escape for people living at that time."  Of course, you can't talk like to a four-year old, so I'm trying to successively define it to smaller pieces and feeling rather proud of myself as I do so.  (I just knew that someone outside of college would care that I had read Kuhn!).

    I'm just warming to the task when he interrupts me.  Waving his hand in my general direction and never taking his eyes off another brutal shark attack, he just says, "Yeah, yeah, yeah. Blah, blah, blah.".

    So much for that :)

    At that point, I decided to run away, rhetorically speaking, sit back, and enjoy watching sharks attack humans with my son.

    </end>

     

    Technorati Tags:
    January 12

    Switch View View Based on User ID In An InfoPath Form

    We had a developed an InfoPath form with multiple views to support a new hire / on-boarding process.  When the company hires a new person, the IT department and other groups need to take action (set up payroll, enable access to appropriate applications, locate a desk, etc).  We use on form but a different view of the form for each of those functions.

    At this company, most of the people involved in the business process are IT-savvy, so when they access the form, their default view is a "menu" view with buttons that direct them to their specific function.  However, we needed to simplify things for the new hire's direct manager.  This person should not see any of the IT related stuff.  In fact, she should see just one view of the form and not even have an option to see the other views.

    In our case, that direct manager's account is directly tied to the form courtesy of a contact selector (which I am always wanting to call a "people picker" for some reason).

    The steps are as follows:

    1. In design mode, go to Tools -> Form Options -> Open and Save.

    2. Select "rules".

    3. Create a new rule whose action is "switch to view" and whose condition leverages the userName() function.

    userName() returns the "simple" user name without the domain.  If I log into SharePoint with credentials "domain\pagalvin", userName() returns "pagalvin".

    The contact selector provides three bits of information for a contact.  The "AccountID" portion is most useful for this scenario.  The only thing that makes this even a little bit of challenge is that the contact selector (in my environment anyway) returns the domain and user ID, as in "domain\pagalvin".  This prevents us from doing a straight-forward equality condition since AccountID ("domain\pagalvin") will never equal userName() ("pagalvin"). 

    We can get around this using the "contains" operator: AccountID contains userName().

    We can take it further and pre-pend a hard-coded domain in front of the userName() function to get our equality check and eliminate the risk of a false positive on the contains operator.

    We would have REALLY like to automatically switch view for other users based on their AD security group membership.  For example, when a member of the "IT Analytics" group accesses the form, automatically switch to the IT Analytics view.  We didn't have time to implement it, but my first thought is to create a web service that would have a method like "IsMemberOfActiveDirectorySecurityGroup", pass it the userName() and return back true or false.  Does anyone have any other, more clever idea?  Is there any SharePoint function we can leverage from InfoPath to make that determination?

    </end>

    Technorati Tags:
    January 10

    Accidentally Adding Code to an InfoPath Form; Deliberately Removing It

    When working with buttons on a form, we often add rules.  You access the rules editor from the properties of the button.

    When clicking around quickly, it's easy to accidentally click on "Edit Form Code" instead of "Rules ...".

    The first time I did this, I canceled out of the code editor.  However, when I tried to publish the form a little while later, it required that I publish as an "Administrator-approved form template (advanced)".  I didn't actually do any programming and I absolutely didn't want to go through an unnecessary approval process.  I was in a bit of panic at the time due to time constraints.  To get past it, I simply restored a previous backup and continued.  I had recently seen some blog posts about people going into the form's XML to tweak things and I was afraid I would have to do something similar.

    Today, I did it again.  This time, I had a little more time on my hands and found that you can easily undo this.

    Go to:

    Tools -> Form Options -> Programming: "Remove Code"

    It does not get much easier than that.

    </end>

    Technorati Tags: ,
    January 09

    Minimum Security Required For InfoPath Forms

    I needed to meet a security requirement for an InfoPath form today.  In this business situation, a relatively small number of individuals are allowed to create a new InfoPath form and a much wider audience are allowed to edit it.  (This is new-hire on-boarding form used by Human Resources that launches a workflow).

    To meet that objective, I created created two new permission levels ("create and update" and "update only"), broke inheritance for the form library and assigned permissions to a "create, update" user and a separate "update only" user.  The mechanics all worked, but it turned out to be a little more involving than I expected.  (If you feel a little shaky on SharePoint permissions, check out this blog post).  The required security configuration for the permission level was not the obvious set of granular permissions.  To create an update-only permission level for an InfoPath form, I did the following:

    1. Create a new permission level.
    2. Clear away all options.
    3. Selected only the following from "List permissions":
      • Edit Items
      • View Items
      • View Application Pages

    Selecting these options allows a user to update a form, but not create it.

    The trick was to enable the "View Application Pages".  There isn't any verbage on the permission level that indicates that's required for update-only InfoPath forms, but turns out it is.

    Create-and-Update was even stranger.  I followed the same steps, 1 through 3 above.  I had to specifically add a "Site Permission" option: "Use client integration features".   Again, the description there does not make it seem like it ought to be required for an InfoPath form, but there it is.

    </end>

    Technorati Tags: ,
    January 08

    That "In-Between" Feeling; Observations on SharePoint Consulting

    Sadly, phase one of my last project has come to a close and the client has opted to move ahead by themselves on phase two.  We did our job too well, as usual :)  I'm now between projects, a special time for staff consultants like myself (as opposed to independents who must normally live in perpetual fear of in-between time :) ).  We staff consultants fill this time in various ways: Working with sales folk to write proposals; filling in for someone or backing up a person on this or that odd job;  studying;  Blogging :).  It's hard to plan more than a few days in advance.  At times like this, while I have a bit of time on my hands, I like to reflect.  

    I'm almost always sad to leave a client's campus for the last time.  We consultants form a peculiar kind of relationship with our clients, unlike your typical co-worker relationship.   There's the money angle -- everyone knows the consultant's rate is double/triple or even more than the client staff.  You're a known temporary person.  As a consultant, you're a permanent outsider with a more or less known departure date.  Yet, you eat lunch with the client, take them out to dinner and/or for drinks, buy cookies for the team, go on coffee runs, give/receive holiday cards -- all the kinds of things that co-workers do.  On one hand, you're the adult in the room.  You're an expert in the technology which puts you in a superior position.  On the other hand, you're a baby.  On day zero, consultants don't know the names, the places or the client's lingo.  Most times, consultants never learn it all.

    When things go well, you become very well integrated with the client's project team.  They treat you like a co-worker in one sense, and confidant in another.  Since we don't have a manager-style reporting relationship with the client, the project team often feels a little free to air their dirty laundry.  They let their barriers down and can put the consultant into an awkward position, never realizing they are doing it.

    Consultants often don't get to implement phase two and that never gets easy for me.  I think this is especially hard with SharePoint.  Phase one of of your typical SharePoint project covers setup/configuration, governance, taxonomy, basic content types, etc. and in many respects, amounts to a lengthy, extremely detailed discovery.  That's how I view my last project.  We did all the basic stuff as well as execute some nice mini-POC's by extending CQWP, implementing BDC connections to PeopleSoft, introduced a fairly complex workflow with SharePoint Designer, touched on basic KPI's and more.  A proper phase two would extend all of that with extensive, almost pervasive BDC, really nice workflow, fine tuned and better search, records center, excel services and probably most important, reaching out to other business units.  But, it's not to be for me, and that's sad.  

    Based on this recent experience, I think it's fair to say that a proper enterprise SharePoint implementation is a one year process.  It could probably legitimately run two years before reaching a point of diminishing returns.  Details matter, of course.

    That's the consultant's life and all of these little complaints are even worse in a SharePoint engagement.  As I've written before, SharePoint's horizontal nature brings you into contact with a wide array of people and business units.  When you're working with so many people, you can see so many ways that SharePoint can help the company become more efficient, save time, do things better...  but you don't always get to do them.  

    I often look back to my first job out of college, before starting a consulting career 1995.   We did get to do a phase two and even a phase three.  Those were nice times.  On the downside, however,  that means that that would mean a lot of routine stuff too.  Managing site security.  Tweaking content types.  Creating views and changing views.  Dealing with IE security settings.  Restoring lost documents.  Blech! :) 

    Despite my melancholy mood, I can't imagine a place I'd rather be (except at a warm beach with a goodly supply of spirits).

    I can't wait to get started implemented the next enterprise SharePoint project.

    (Apropos of nothing, I wrote most of this blog entry on an NJ Transit bus.  I don't think I made any friends, but one CAN blog on the bus :) )

    </end>

    Technorati Tags:
    January 06

    Sunday Funny: "They're Not THAT Bad"

    Back near 1999, I was spending a lot of weeks out in Santa Barbara, CA, working for a client, leaving my poor wife back here in New Jersey alone.  I dearly love my wife.  I love her just as much today as I did when she foolishly married me 1,000 years or so ago.  Somewhere along the line, I coined a phrase, "special fear", as in "Samantha has special fears."  She as a special fear of "bugs", which to her are not flies or ladybugs, but rather microbes.  She's afraid of this or that virus or unusual bacteria afflicting our son, or me, but never really herself.  (She is also specially afraid of vampires, miniature evil dolls (especially clowns) and submarine accidents; she has out-grown her special fear of people dressed in Santa Claus outfits).

    One day, my co-worker and I decided to drive up into the nearby mountains near Ohai.  At one point, we got out of the car to take in the scene.  When we got back into the car, I noticed that a tick was on my shoulder.  I flicked out the window and that was it.

    That night, I told her about our drive and mentioned the tick.  The conversation went something like this:

    S: "Oooo!  Those are bad.  They carry diseases."

    P: "Well, I flicked it out the window."

    S: "They are really bad though. They can get under your skin and suck blood and transfer bugs.  You better check your hair and make sure there aren't any in your head!"

    P: In a loud voice: "My God!  CAN THEY TAKE OVER YOUR MIND???"

    S: Literally reassuring me: "No, they're not THAT bad."

    </end>

    Technorati Tags:
    January 04

    Quick and Easy: Automatically Open InfoPath Form From SharePoint Designer Email

    UPDATE: Madjur Ahuja points out this link from a newsgroup discussion: http://msdn2.microsoft.com/en-us/library/ms772417.aspx.  It's pretty definitive.

    ===

    We often want to embed hyperlinks to InfoPath forms in emails sent from SharePoint Designer workflows.  When users receive these emails, they can click on the link from the email and go directly to the InfoPath form.

    This monster URL construction works for me:

    http://server/sites/departments/Technical%20Services/InformationTechnology/HelpDesk/_layouts/FormServer.aspx?XmlLocation=/sites/departments/Technical%20Services/InformationTechnology/HelpDesk/REC%20REM%20RED%20Forms/REC2007-12-18T11_33_48.xml&Source=http%3A%2F%2Fserver%2Ecorp%2Edomain%2Ecom%2Fsites%2Fdepartments%2FTechnical%2520Services%2FInformationTechnology%2FHelpDesk%2FREC%2520REM%2520RED%2520Forms%2FForms%2FAllItems%2Easpx&DefaultItemOpen=1

     

    Replace the bolded red text with the name of the form, as shown in the following screenshot:

    image

    Note that there is a lot of hard-coded path in that URL, as well as a URL-encoded component.  If this is too hard to translate to your specific situation, try turning on alerts for the form library.  Post a form and when you get the email, view the source of the email and you'll see everything you need to include.

    Astute readers may notice that the above email body also shows a link that directly accesses the task via a filtered view.  I plan to explain that in greater detail in a future post. 

    </end>

    Technorati Tags: