21 November 2013

shifting gears

/EXISTENCE
When I posted my last entry, I talked about a change of pace. Little did I realize at the time how big of a change that pace would be. To give you a perspective, let compare the phases of my life so far to a car's gearbox. My life in Montana was nice and laid back. I had a job at a video rental store and enjoyed shooting the breeze with the regulars. The speed limit in town was a lazy 25MPH. At these speeds, I could remain in first gear or a really low RPM second gear.

When I move to eastern Washington, the pace picked up a bit. There were more people, roads were faster, but it was still a pretty laid back community. School kept me busy and work was flexible enough to allow me to say, "I'm not planning on coming in during the week of finals" and my supervisor would be cool with it. When I became a regular employee, it was still pretty chill. I never really had to leave second gear much. Third gear was optional.

Now I live in southern California, near Irvine. There are a lot of people. And I travel north to L.A. on a fairly consistent basis where there are even more people. On top of this, people drive like demons on the freeways when given the opportunity. I have to be constantly aware of traffic when driving. My job as an IT support technician means that I'm solving other people's emergency's. Constantly. Fourth gear is nearly a constant with fifth gear occasionally necessary.

As you can imagine, unnecessary things have fallen by the wayside, one of which included this blog. I wish it hadn't but as you can imagine, life has changed a lot for me. One might ask, "If unnecessary things have fallen to the wayside, why do you still play so many video games?" My answer to that is they are necessary. Video games are my way of letting my brain unwind. But as life settles more and I keep trying to improve my life, I find myself thinking about writing here again. I will try to make an effort to post here again, though it will be on a new schedule as posting on Mondays will no longer work very well. But I'm tired and unwilling to commit to a schedule right now. So I'll bid you good night.

And until next time:
Work smart. Play hard. Sleep well.

08 May 2013

a change of pace

/EXISTENCE
Typically when someone mentions a "change of pace" they're usually referring to slowing down, stopping to enjoy nature, and even finding a bit of serenity amid the normal noise. On the contrary for me, I am happy to announce that I've accepted a job offer at eStream in Southern California. I'll be starting in June. So over the next month I will be busy trying to concentrate on work, sorting through my stuff to sell and donate various items, packing the rest, and finding the money to move myself and stuff.

So why do you care? Well, mostly because I won't be writing about SharePoint for much longer in the current context. My new job will be providing support. So after I finish my "codeless" series, I won't have much to say about SharePoint any more. This is a wonderful thing in my opinion. Don't get me wrong, SharePoint is a very versatile system. It's also quite quirky and must be managed carefully. And constantly. I think Wictor Wilén put it best: "It is always fun to get back on site after a couple of days off work. SharePoint 2010 is like an annoying little critter, if you're not there to cuddle with it it will do the most strange things."

The next note of business is that my posting schedule will be changing over the next month as well. Instead of posting every other Monday, I'm going to look into posting on Sundays. I haven't decided how frequently yet but I should have a better idea of that once I'm functioning again after moving to California.

Until next time:
Work smart. Play hard. Sleep well.

12 April 2013

Please Log In, Please Log In, Please Log In

/TECH
Life and work has kept me busy for several weeks and is my excuse for not posting anything in quite some time. It's not much and probably not a very good excuse, but it's the one you're getting. One of the things that's been keeping me busy is that I've been doing a lot of documentation lately. Over the past 3 years I haven't documented the many InfoPath forms I've developed and am now paying the price for waiting so long. It isn't so hard as it is time consuming, not as exciting, and a lesson in how it doesn't take long to forget why you built it that way. Of course, InfoPath doesn't have any kind of documentation tool built in to it and you can't exactly add comments to your forms. So I've been using Microsoft's Word software to copy screen captures and type explanations where necessary. It's not the most amazing thing ever, but it gets the job done.

But every now and then a login box pops up and asks me to log in to the SharePoint server. It doesn't happen very often, but it's annoying because I never asked Word to connect to the server. I did a Google search and found this article outlining the same problem, though much worse than my experience with it. In the article, Ernst mentions that the issue occurs when you use a particular feature of Office to connect to a SharePoint server, but I've never used that feature directly. Somehow just by opening a document located in a SharePoint Document Library causes the issue. So I'm here to document the issue again and inform you how to remove this annoyance.

The problem stems from a feature where Office remembers the locations you've created or accessed previously and tries to connect them every now and then. To fix this, you will need to use regedit.
  1. Close all Office programs to be safe.
  2. Hit Win+R and type regedit
  3. Navigate to HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Common\Portal\Link Providers\
  4. This should have one or more sub-keys with the same name as the offending sites Office keeps trying to connect to. Delete the offending keys and close regedit.
Now your Office programs should stop asking you to log in.

Until next time:
Work smart. Play well.

11 March 2013

codeless: temporary variables

/TECH
One of the problems I ran into in January was that the userName() function in InfoPath returns something different when used on a web form in a claims-based environment. This post will walk you through two things: creating "temporary variables" in InfoPath and sanitizing the userName() result.

Temporary variables are wonderful in programming and I missed them dearly when I started working with InfoPath. Typically I'd just make a field in some obscure part of the form and not publish it, but there was always a chance that someone with some know how could find that data. It became even more prudent when I started experimenting with a service that retrieved a list of the current user's SP security groups. So I finally searched for a solution. I don't remember who's blog I read first, but there are lots of results out there that all say the same thing: use an XML file.

It's a pretty simple and clever solution. Since data connections can either be "read" OR "write", when you change the data in a secondary connection that's a read-only connection it doesn't save the data. Hey, that's kind of like a temporary variable! Constructing the XML file is pretty simple. Here's one that I've used:
<?xml version="1.0" encoding="utf-8"?>
<currentuser>
 <username />
 <preferredname />
</currentuser>
You can't specify type--as far as I can figure out--but most of the time strings are just fine. The advantage of this system is that you can get info about the current user, store it in a field for use, but not have to worry about purging the data before saving the form. This became a huge advantage with our recent userName() debacle.

In January, we launched a new web application on our SharePoint farm that utilized single sign-on and a claims-based authentication. Two major things broke when we tried using a form: accessing web services and the userName() function returned a string I'd never seen. Normally the function would return "jdoe", but in the claims-based environment it returned "i:0#.w|domain\jdoe". This was a huge issue because a lot of our forms compare the current user to some kind of list to determine access. Changing every single rule that used userName() to some unwieldy expression was not sounding fun either. So I devised a new method.

Instead, I used a temporary field and two form load rules. Using the XML example above, I then created two rules in my form load rules.

Click here to return to my listing of "codeless" blog entries. The underlined username is referring to the field in the secondary XML resource.

Rule #1 - current user has slash
Condition: contains(xdUser:get-UserName(), "\")
Action:
  Set a field's value: username = substring-after(userName(), "\")

Rule #2 - current user no slash
Condition: not(contains(xdUser:get-UserName(), "\"))
Action:
  Set a field's value: username = userName()

Now I have a field that will always contain only the username of the current user. The disadvantage of this is where you have fields that set their default value once and used the userName() function. To overcome this problem all you have to do is add a third form load rule that I like to call "First Load".

Rule #3 - First Load
Condition: FormName is blank
Action:
  Set a field's value: FormName = concat(now(), "_", username)

And that's all there is to it. Click here to return to my listing of "codeless" blog entries.

Until next time:
Work smart. Live free.

25 February 2013

changes

/TECH RANT
I looked at my blog today and realized it has been quite some time since I last posted and there's a reason for this. Actually several reasons that all combine into a singular issue that has caused me some personal and work grief. In most cases I would mask my troubles by writing a more technically oriented entry, but this time there is no getting around the technical and emotional issues that have occurred.

To begin, in the week of January 21st we were finally publishing a form to our newly setup production environment, complete with claims-based authentication to facilitate single sign on. We did a backup of the test site collection and restored it to production. The first thing I check were the workflows as I had used a new feature to help ease the pains of changing publish locations. It worked fantastically. The workflows generated links based on where they were and didn't have to be statically set. Then we launched the all important full-trust form that was to go live by the end of January and immediately there was an error screen. Okay, so it wasn't a flawless victory. I hit OK and proceeded to attempt to visually diagnose what was broken. It didn't take long to see that every single data connection had failed to connect.

The rest of that week was spent diagnosing what had happened and what was truly broken. As it turned out, it was a small quartet of issues. The first and foremost: the test environment used classic authentication, the production environment used claims-based authentication. This small oversight caused a small cascade of issues to crop up, namely: using web services in InfoPath forms no longer worked, username() returned a very different string than expected, and SSO is really annoying to develop under.

Let's start with the string returned by username(). In InfoPath, username() normally returns something like "jdoe". And it still does when you hit preview or you happen to be using a client form. But in a web-form on a claims-based web app, username() returns something like "i:0#.w|domain\jdoe". This is a huge issue when the form is trying to compare "jdoe" to the whole claims token. This was easily enough worked around by creating a temporary variable that was assigned the current username based on a couple of form load rules. Some aspects of the form become less dynamic with this method, but it fixes the issue of "jdoe" != "i:0#.w|domain\jdoe" when it is clearly supposed to.

The next issue is that of web services. One of the services I use in most InfoPath forms is the userprofileservice.asmx service. This allows me to get the current user's preferred name, work phone number, preferred email, and Whitworth ID number. It's quite useful, and in some forms, required. And now it was completely inaccessible. At first I thought it was a problem with the string from username() causing problems, but even after I fixed that issue, the server kept spitting out a SharePoint error code 5566. I discovered this is similar to the HTTP 401 error, namely that the service is reachable, but the user has either not provided credentials or their credentials have failed to authenticate. Most sources that talk about this particular issue state that it is because InfoPath is not "claims aware", but none of their solutions work or cause a security concern.

Finally, single sign on is a wonderful tool for end users and probably even for most development situations. But for SharePoint Designer and InfoPath Designer, this caused me undue grief. This is largely due to the way the tools function in this situation. Every time I went to add a data connection, I had to log in. Every time I published, I had to log in. Every time I went to access the site collection with SharePoint Designer I had to log in, and then open the site a second time to get it to actually load. And just getting the site collection to open in the first place took me hacking the link into the Recent Sites list in SharePoint Designer. It's annoying.

At the end of this week of discovery, I found myself unable to do anything because it was all server settings I don't have access to. It was also very disheartening to realize that most of the forms I had worked on over the past 9 months wouldn't work in the production environment. My mood fell and I let a lot of things go. I probably used more sick time in January than I had previously at all. Even now I still have issues motivating myself to continue working on forms. New forms have gone to utilizing manual entry of the current user's name and ID number when needed. Where I used to have a tolerant love of SharePoint has turned into something else. I've reached the end of what little sanity I had left. When I get home from work, I can't think about design any more and usually find myself playing a game, watching a show, or reading a book that has nothing to do with work. This blog sadly refers to work quite frequently and thus it has been put off for far too long.

Don't get me wrong, I know that SharePoint can be an amazing system that provides awesome features for team sites, file sharing and collaboration, and business processes with automated workflows. I think I just need a short break from SharePoint's particular blend of crazy and a new perspective. In fact I made the decision a couple weeks ago that if I'm going to truly continue to work with SharePoint I will become an expert so that when someone comes to me and says, "It's broke", I can tell them why and what to do to fix it.

Until next time:
Work hard. Play harder.

17 January 2013

codeless: on-change workflows

/TECH
When I started working in SharePoint nearly 3 years ago, I noticed a severe lack of looping functionality built-in to InfoPath or SharePoint itself. This was irritating because when I started work, I was still a student learning C++ and there loops are life-blood. So, what was a programmer to do in a designer's system?

The place I noticed the greatest need for looping was actually in the workflows that our custom forms used to notify approvers. And when I arrived to the SharePoint team, workflows were done in such a way that it would start when the form was created and keep running, waiting for changes before proceeding, and finishing when the form reached its completed state. The real problem occurred when there was a issue with a form and the process had to be reset. This meant terminating the workflow, making the changes, and then restarting the workflow. Even then, the workflow had to go through each of the steps again, even if the change affected only the last step. Wouldn't it be nice if it could keep checking everything until it was actually complete? Yeah, like you can with a loop.

This is when I noticed that the SharePoint team didn't utilize the option that a workflow would run when an item was changed. There were reasons, good reasons for this, but if it's there we should at least understand why we weren't using it for that workflow. The first form I worked on I discovered a really good reason not to use the on change option: if your workflow changes a field/column for the item it is running on and then completes, it detects there was a change to the item and the workflow is triggered again. Welcome to the infinite loop of SharePoint. The workflow in question had to first set the form's Status and then emailed the next person in the process (me). Because it finished so quickly, the Status change was detected as a change and the workflow triggered again. And again. And again. And again. And it proceeded to send me a constant stream of emails while I frantically tried to stop the loop. 15 seconds later I was deleting the 60+ emails I had received.

But this only occurred because something was being modified in the current item by the workflow. I quickly learned that it is better to handle changes in the form template as much as possible. To solve the problem however, I employed another workflow feature: Wait for Duration. This enabled me to change the field, wait, and then send the email a couple minutes later. By having it wait the event handler no longer saw the change as recent enough to start the workflow again. The problem with this solution was that it slowed down the process. And I still had to worry about workflows spamming because several processes I work with use more than one workflow and often one of those has to make changes to the item. In these cases I employ a flag for each email to mark which ones have been sent already. The flag can be added to the library or content type directly, but I prefer to add it to the template. This is because InfoPath forms have a much more powerful rule system built in than the ones that libraries and workflows can do. An excellent example of using these flags is actually in a process I'm currently working on.

Workflows that trigger on-change were essentially the "loop" I was looking for. We also discovered that this method reduced the server load significantly, an unintended benefit. Ever since then my boss has asked me that when I'm rebuilding a workflow that if I can change a workflow to triggering on change that I should.

The best practice in my opinion is to assess what needs to be accomplished to see if the on-change workflow fits your process. In my case, most situations benefit from the on-change style workflow.

Oh, and always test the workflow by having it send to yourself first. You really don't want to have to explain yourself to your boss's boss as to why you flooded his inbox with God knows how many emails.

Until next time:
Work hard. Play harder.

04 January 2013

codeless: double eval

/TECH
My current job title is SharePoint Developer. However, my work is a lot more specific than that. Yes I develop for SharePoint, but more specifically I develop custom, codeless web forms using InfoPath as my primary design tool. The key here is that everything I do doesn't contain custom code but rather out-of-the-box functionality used creatively. And boy do I get creative. Over the next several blog entries I want to explore some of the codeless designs I've found, developed, and refined.

The first trick I want to talk about is one that I use a ton: the double eval. When I first started developing with InfoPath I found that there were several things I couldn't do that I could in C++. Now, I understand that InfoPath isn't a programming language, but it is based on web-technology and several web languages support. So why the hell can't I systematically grab data from a repeating field?! Well, you can. I remember looking at all the functions I could use in an expression once and when I got to eval(), I had no idea how to use it. Even the description of for using it was cryptic: "Returns a node-set containing the result of the expression for each set of elements in the context field." If you added it to the expression, you got the following template:
eval(double click to insert field, "type expression here")
Now I don't know about you but I learn much more about a function by seeing an example of it being used. I finally saw an example one day of the following expression from Infopath codeless programming (walkthrough) 2:
eval(eval(Person, 'concat(my:AccountId, "|")'), "..")
At first I couldn't figure out what was going on, but after I used it several times in different forms I figured out how the two eval() functions were working together. Let's break this down starting with the inner eval().
eval(Person, 'concat(my:AccountId, "|")')
This eval() is referencing the field Person and then using concat() on it. The trick here is that the concat() function is being run relative to where Person is located. This means that if you need to do a comparison to another field with your concat(), you need to write the xpath as if the concat was running on Person. Say you want to filter AccountId based on Department. If you were to look at the xpath for the two fields you might get something like this:
- MyFields
  - Person
    = AccountId
  = Department
You'll notice that Person and Department are parallel and AccountId is a child of Person. For our concat() above to filter AccountId using Department, it would have to be done like so:
'concat(my:AccountId[../../my:Department = "IT"], "|")'
What this does is back up twice relative to where AccountId is located and then looks for Department. It's really important to know where in the hierarchy an expression is going to run. You may have also noticed that the entire expression for the eval() is enclosed in single quotes, not double quotes. That's because the expression needs to use double quotes to function correctly, thus you change the overall encapsulation to single quotes.
eval(eval(Person, 'concat(my:AccountId, "|")'), "..")
The outer eval is easier to break down and is where the "looping" action actually occurs. The outer eval() is treating the inner eval() as the field it is working on and the ".." as the expression. The unique thing about the expression here is that it is looking for one thing: when the field has to go back or up a level in the hierarchy. As soon as that happens, the outer eval returns the results of the inner eval() that occurred on each instance of Person, in this case, a string of concatenations that results in the output of a single string of text. The output would look something like this:
jcool|cbrown|ppatty|lucyvanpelt|
This is now a really useful way to gather info into a single field for further use and/or processing. I've used it to concatenate the usernames from a SharePoint list to use in a comparison in the form for security, creating a list of approvals still needed, and even doing a sort of "group by" query on a repeating table.

Thanks to Alec Pojidaev and posting that little trick to his blog. It's come in extremely useful. Check out his blog for some other codeless solutions. Click here to return to my listing of "codeless" blog entries.

Until next time:
Work hard. Play harder.

codeless

/TECH
My current job title is SharePoint Developer. However, my work is a lot more specific than that because the I nearly exclusively develop custom, codeless web forms using InfoPath as my primary design tool. The key here is that everything I do doesn't contain custom code but rather out-of-the-box functionality used creatively. And boy do I get creative. Over the next several blog entries I want to explore some of the codeless designs I've found, developed, and refined. To keep things tidy, I'll preface each post title with "codeless" so you know what you're getting into and additionally keep links to all my "codeless" posts here. If you're working with InfoPath, I hope these articles help you.

"codeless" articles:
Until next time:
Work hard. Play harder.