forge

Link Tracking Beta

I finished a new web part kit over the weekend.  It is called Link Tracking, and allows you to see how frequently that users are actually using the links that are in the portal.  Most customers I’ve talked to are completely unaware of when the users are using the links on the portal, as a result it’s hard to fine-tune the number and type of links on the site.

Link tracking fixes this by recording each link as it’s clicked so you can go back and review the number of people who have used the link.

I’m looking for three beta participants with the commercial release being later this month.  If selected for the beta, I’ll give you a license to the final code when it comes out.

Rob

forge

How to use SharePoint as a Mail Merge Source

I was looking for how to perform a mail merge using a SharePoint list as a source and found Wayne’s post asking the same question.  There wasn’t help there, however, amongst the comment was on from Yatin Purohit indicating that you could link to the SharePoint list as a table in Access and then use the Access table as a source for Word to use in a mail merge.  It’s a pretty useful technique — too bad there’s not an OLEDB driver for SharePoint lists. I suppose this will work for now.
forge

A few other dumb things that you can do with .NET — but shouldn’t.

In my previous post I highlighted a single bad idea that I had seen in some code.  I want to offer up a few other things that I saw and why you shouldn’t do them…

  • Tightly nested Try/Catch blocks — basically, put a try block, do one statement, add a try block in that block and repeat…  See the code…

            static public void LogRequestResult(string url, string status)

            {

                  try

                  {

                        FileStream objFileStream = null;

                        StreamWriter objStreamWriter = null;

 

                        try

                        {

                              objFileStream = File.Open(cnstMyFilePath, FileMode.Append, FileAccess.Write, FileShare.Read);

                              try

                              {

                                    objStreamWriter = new StreamWriter(objFileStream);

                                    lock(objStreamWriter)

                                    {

                                          objStreamWriter.Write(Status + url);

                                    }

                              }

                              finally

                              {

                                    if (objStreamWriter != null) objStreamWriter.Close();

                              }

                        }

                        finally

                        {

                              if (objFileStream != null) objFileStream.Close();

                        }

                  }

                  catch

                  {

                  }

            }

 


Ignoring the fact that we’re not actually doing any error checking… Isn’t the following much more straightforward easier to read, and less prone to errors?  The moral to the story, try/catch blocks are cool but don’t abuse them.


            static public void LogRequestResult(string url, string status)

            {

                  FileStream objFileStream = null;

                  StreamWriter objStreamWriter = null;

                  try

                  {

                        objFileStream = File.Open(cnstMyFilePath, FileMode.Append, FileAccess.Write, FileShare.Read);

                        objStreamWriter = new StreamWriter(objFileStream);

                        lock(objStreamWriter)

                        {

                              objStreamWriter.Write(Status + url);

                        }

                  }

                  finally

                  {

                        if (objStreamWriter != null) objFileStream.Close();

                        if (objFileStream != null) objFileStream.Close();

                  }

            }


  • Magic Numbers (or in this case letters), just stop — I can’t tell you how many times I’m looking through code and I come across an if statement that looks like “if myvariable == “A““  Why in the world would your variable is “A“.  What does “A“ mean?  In .NET we have enumerations and constants.  Why can’t we just them?  I have no idea what “A“ means — and neither will the author 2 months from now.  If you put quotes around the same text twice it should be a constant.  If you use a number for an if statement or as part of an assignment that isn’t a 0 or a 1, you should have a constant.  (Zero is a number to compare against, 1 is a number to fix a number of offset issues.)
  • Comments — Hey, there’s a concept.  And I don’t mean one that says, // the following line adds one to the number.  Thanks.  I can read code.  How about writing comments that tell me why you’re adding one to the number?  Oh, yea, those XML comment things that .NET supports.  Those are useful.  You can use them too, they’re not expensive.

Do you have any pet peves about code that should go on this list?

forge

How Not to test for a null string in .NET

Today I was forced to read some code for a developer that I loathe.  Just when I believe I’ve seen every stupid thing you can do with code I am surprised by a new structure that he repeats everywhere through his code.  Here’s what I saw today…

string myString = (GetStringFromConfiguration(”keyvalue”) + “”).ToLower();

At first I did a double take, it doesn’t make sense to add an empty string to a string … that is unless you’re trying to prevent the null reference exception from ToLower().  Adding null to any string results in that string.  Thus, you *CAN* work around null references by using this technique.  However, here is why you shouldn’t.

When you do this you actually force the CLR to create an extra, unnecessary new string object.  It creates a temporary string object which it concatenates the result of the function and the empty string into.  Another string is created when the string is taken ToLower().  That one can’t be helped, but the intervening one — the one caused by the concatenation, can be eliminated.

OK, sure, it’s a detail and it probably won’t matter much to most people but it will perform slower, require more memory, etc. The biggest thing for me is that it’s really odd from a readability/understandability perspective.  (Did I mention that there are no comments in this code?)

Ideally, I’d create a GetStringFromConfiguration function overload that took a second parameter of what I wanted back if the entry wasn’t in the configuration file.  That way the code doesn’t concern itself with the details, it knows that it will always get back a valid string.  This is in fact what I do when I have to be concerned about getting back a null when I need it to be functionally equivelent of a default or an empty string.

As a sidebar, it would have been nice to see a String.Empty instead of ““ … oh well, you can’t win them all.

forge

Develop a strategy for requirements gathering

There’s more to requirements gathering than getting an initial framework. Understanding the differing goals of the requirements process is an important key to understanding how to get requirements done right.

In most mid-sized IT organizations the process of gathering requirements is a little more advanced than scribbling a few wire frame representations of what the screen for the new system should look like. (A wire frame is simply a line drawing with boxes, rectangles, and text which roughly describes what the final product may look like.) This mechanism for collecting requirements is quick. After a few minutes and a handful of sketches, enough information can be gathered to start developing a solution.

While this may be required for some projects, it’s more often than not going to create more challenges down the road as small details escape everyone’s attention until very late in the process — where changes and fixes cost the most money.

This technique does have its place. It’s a necessary part of the overall process. However, there’s more to requirements gathering than getting an initial framework. Understanding the differing goals of the requirements process is an important key to understanding how to get requirements done right.

http://www.techrepublic.com/article/develop-a-strategy-for-requirements-gathering/

forge

Custom Configuration Sections in a .NET config file

I’ve been working on a basic rules based web service for InfoPath forms.  The basic idea is to allow us to do “poor man’s integration.” to some back end systems now and then swap that out later without modifying the forms — since the forms will be adapted by several people and there may be more forms than we want to go back through. So a single web service that all InfoPath forms call on submission — by the way one they call in addition to whatever else they want to do — for instance, post themselves to a SharePoint site.

Anyway, so I needed a rules section in the config file where each rule had some attributes.  The problem is that .NET isn’t setup to easily hand you back the XML from a section in the configuration file — actually it gets pretty upset about the section even being in the file.  The solution is a IConfigurationSectionHandler.  Here’s what it takes to implement…

1) Modify the web.config file.

a) Add a <configSections> tag.  Note this must be the first tag in the <configuration> node.  This looks something like…

 

<configSections>
  <sectionGroup name=”customConfig”>
    <section name=”rules” type=”InfoPathRouting.Classes.XMLConfigurationSectionHandler, infopathrouting” />
  </sectionGroup>
</configSections>

In this case, I’m creating a new section called customConfig and adding a section in it called rules, which my class (InfoPathRouting.Classes.XMLConfigurationSectionHandler) in my DLL will handle.  (InfoPathRouting is the ASP.NET project name)

b) Add the actual section in the file.  In this case I’d add something like:

 

<customConfig>
<rules>
  <!– Whatever I want in here —>
</rules>

 

2) Add the class to the project.  Here’s the XMLConfigurationSectionHandler that I wrote.  The only restriction is that it must support the IConfigurationSectionHandler interface.  That interface only defines one method, Create().

 

using System;
using System.Configuration;
using System.Xml;
namespace InfoPathRouting.Classes
{
  public class XMLConfigurationSectionHandler : IConfigurationSectionHandler
{
    public object Create(object parent, object configContext, XmlNode section)
{
      return (section);
    }
}
}

In this case I wanted the XMLNode back so I could do my own thing with the XML fragment, so that’s what I returned.

 

3) Reference the configuration section in your code.  The following line of code fetches the XMLNode for my new rules section:

 

XmlNode rules = (XmlNode) System.Configuration.ConfigurationSettings.GetConfig(“customConfig/rules”);

That’s it.  I now have a repeatable way to store any kind of XML configuration I want in my app.config and web.config files.

forge

Anatomy of a Software Development Role: Training

Wrapping up the software development lifecycle and turning over the completed product to the users is the training role. The training professional is the last one in the process since they are the ones who get the mass of users to use the software that has been created. Their purpose is to help the users understand how to use the software that’s been created. (If you’ve not been following the series, you should read Cracking the Code: Breaking Down the Software Development Roles.)

What’s the Training role?

The training professional first and foremost creates the materials necessary to train users how to use software. For that reason, training professionals are often tapped to create user documentation and help files in smaller organizations.

The training professional is ideally someone who has an instructional design background and therefore understands how to create materials that are effective in helping adults learn. They are also, ideally, someone who can approach the problems that the software solves in a way which makes sense to the users. Click here to see how the Deployment role fits within the full organizational chart.

http://www.developer.com/java/other/article.php/3523171

forge

Four Things you’re missing in your backup strategy

Backup Strategies aren’t always about when to backup and what to backup. They are often about how to create the right systems to allow you to discover problems when they occur.

When most people think of a backup strategy they think about tape rotation and backup schedules. While these are important parts of a backup strategy they’re not the whole story. As an organization begins to assimilate more and more servers, a reliable backup strategy becomes more challenging. Instead of one tape drive that backs up the entire network, libraries become necessary. Instead of doing one backup job and schedule, you need several. Here are four fundamentals for developing your backup strategy.

Plan for growth

Most organizations have begun to start monitoring their disk storage needs. While disk storage is cheap, the cost of maintaining all those files, including archives and backups, starts to become a real expense. When an organization plans its disk needs, it needs to review its growth and determine how much extra disk space will need to be purchased over the next year.

But here’s the rub. Adding more disk space is relatively easy. You just add new drives to the disk array or you swap out smaller disks for larger ones. The process takes time but it’s relatively transparent. Upgrading tape capacity isn’t so easy for most organizations.

http://www.techrepublic.com/article/four-things-youre-missing-in-your-backup-strategy/

 

forge

Getting the original display name for an internal name

Bil Simser posted on a problem with CAML where he mentioned reverse engineering the internal field name to the original display name that created it.  I had to do just this thing for one of migration utilities.  Here’s the code (C#):

// Fixup an internal name back to the regular way that it should be so that we can get the same
// internal name back when we create a title.
private static string FixInternalName(string internalName)
{
// Get the most common one out of the way as quickly as possible
string f1 = internalName.Replace(“_x0020_”, ” “);
int pos;
// while we have more processing to do
while ((pos = f1.IndexOf(“_”)) >= 0)
{
int chrVal;
if (pos + 6 > f1.Length)
{
chrVal = PartialEncoding(f1,pos);
}
else
{
chrVal = int.Parse(f1.Substring(pos+2, 4), System.Globalization.NumberStyles.HexNumber);
}

if (f1.Length > pos + 7)
{
// char isn’t at the end of the string
f1 = f1.Substring(0, pos) + Convert.ToChar(chrVal) + f1.Substring(pos+7);
}
else
{
f1 = f1.Substring(0, pos) + Convert.ToChar(chrVal);
}
}
return (f1);
}

private static char PartialEncoding(string fix, int pos)
{
pos += “_x”.Length;
if (fix.Length > pos)
{
string nw = String.Empty;
while(pos < fix.Length)
{
nw = nw + fix[pos];
pos++;
}
while(nw.Length < 4)
{
nw = nw + ‘0’;
}
return (Convert.ToChar(int.Parse(nw, System.Globalization.NumberStyles.HexNumber)));
}
else
{
// Not even enough to start — return a space it will get encoded
return ‘ ‘;
}
}

forge

Quick Tip: Don’t forget Outlook’s ability to display a web page for a folder

While working with a client recently we were discussing the issues with the Exchange web parts that are shipped as a part of SPS.  (This spawned the development on the new Exchange web parts, see my previous post.)

However, we came to the conclusion that it might be too small to include some email items in SharePoint.  So I mentioned the idea of doing things the reverse way.  Use Outlook to host your SharePoint site.  It’s a feature that’s been around in Outlook for a while.  All you have to do is…

  1. Create a folder in Outlook.
  2. Right click, select properties.
  3. Click the home page tab.
  4. Enter the address of your SharePoint site in the address text box.
  5. Select the show home page by default for this folder checkbox
  6. Click the OK button.

Now when you navigate to this folder in Outlook you’ll see your SharePoint site.  Not a bad deal when you’re looking to have a single dashboard to the organization and you live in email — as many of us do.