Saturday 27 August 2011

Microsoft InfoPath : Electronic Forms for the Business

I’ve been using InfoPath since 2004 and am continually amazed at how many businesses have never heard of it, or have it but have never considered using it. The thing is, you have probably used it without knowing it; have you ever completed a Document Information Panel in Word or a workflow form in SharePoint?

Microsoft InfoPath is part of the Microsoft Office family, providing a facility to design, distribute and complete electronic forms within your business. The current iteration of Office (Office 2010 Professional Plus) offers InfoPath as two products: InfoPath Designer 2010 and InfoPath Filler 2010.

Why migrate your company forms from Word and Excel format to InfoPath ?
  • InfoPath forms can be published on the desktop, via Email or to the Intranet, Extranet or Internet.
  • The forms can contain validation and business logic far above what can be achieved in Word and Excel without writing a line of code.
  • Instances of the form are stored in XML format which can be easily integrated into your back office systems.

Publishing forms

InfoPath offers a design once use everywhere approach. Forms may be published to the network, via email / Outlook, Microsoft Forms Server, SharePoint 2007, SharePoint 2010, or Office 365.
Please note that for browser based completion of your forms within SharePoint a SharePoint Enterprise CAL will be required.

Client based Forms may be completed via the InfoPath Filler 2010 application or embedded within Office or a Windows forms application via the InfoPath form control. InfoPath is integrated into most Office applications in the form of the Document Information Panel. In Outlook 2007+ forms may may be viewed as emails.

Form Design
Forms may be designed within the InfoPath Designer application which provides the same Office user interface most users are familiar with. The designing of forms is aimed at the Knowledge worker and after a little training is fairly easy to get to grips with. Controls may be dragged into position where validation and business rules may be applied in an intuitive manner. The form can connect to multiple data-sources but is most at home connecting to web services.

InfoPath is designed around the XML paradigm. Instances of the form are stored as XML files which makes post processing very easy. The form templates are stored in XSN format. This is a CAB format file which contains a mixture of XSL files (for each form page view) and XML to define the form business logic and data-sources.

Managed code may be added to the forms via installing the optional VSTA (Visual Studio Tools for Applications) module from the Office CD/ISO. Personally I consider this a last option when designing InfoPath forms preferring instead to put this logic into reusable web services wherever possible.

Conclusion
If you have never looked at using InfoPath then I hope this brief introduction may inspire you to check it out. I must however finish with a word of warning, as with any product please plan carefully before deploying InfoPath to the Enterprise (I will try and cover this in a future post).

Operation is not valid due to the current state of the object

When your perfectly good SharePoint web service or elevated delegate throws this error it could ruin your day. The cause of the error lies deep inside the SharePoint object model which uses the current SharePoint context assuming all is well with it. I have got around this issue in the past by temporarily wiping the HTTP context after which all is well:

   1:  HttpContext ctx = HttpContext.Current;
   2:  HttpContext.Current = null;
   3:   
   4:  try
   5:  {
   6:      // TODO:your code
   7:  }
   8:  finally
   9:  {
  10:      HttpContext.Current = ctx;
  11:  }

This has always worked for me although recently I spied another approach on Kristian Kjær blog which also works well; the choice is yours.

Permission to RIDE (part 2)

Last week I discussed how to clone permissions across site collections. Setting permissions is no good unless you apply them to a group or library, luckily performing this is fairly straightforward.

   1:  SyncUtils.PermissionGroupSetRole(web, "Super Member Group", "Blog Editor");

calling the routine below:

   1:  public Boolean PermissionGroupSetRole(SPWeb web, String groupName, String roleName)
   2:  {
   3:      Boolean groupSet = false;
   4:   
   5:      try
   6:      {
   7:          SPRoleDefinition role = PermissionRoleExists(web, roleName);
   8:          if (role == null) throw new ApplicationException("Role missing");
   9:   
  10:          foreach (SPRoleAssignment ra in web.RoleAssignments)
  11:              if (ra.Member.Name == groupName)
  12:              {
  13:                  ra.RoleDefinitionBindings.RemoveAll();
  14:                  ra.RoleDefinitionBindings.Add(role);
  15:                  ra.Update();
  16:                  groupSet = true;
  17:                  break;
  18:              }
  19:      }
  20:      catch (Exception ex)
  21:      {
  22:          logErr = String.Format("PermissionGroupSetRole: {0}", ex.ToString());
  23:      }
  24:   
  25:      return groupSet;
  26:  }

Monday 22 August 2011

Permission to RIDE

When working with solutions that contain many site collections managing security can be a bit of a pain. One technique that I like to use is to define all the permission roles within the root site collection and replicate these to the child site collections on creation (assuming you are creating it from a custom template).

Creating the permission within the root site collection.
The easiest way to define a new permission role is to copy an existing one via the UI; open the Contributor permission role and select the copy option to create your new permission role, let’s call it ‘Blog Editor’. For the new role choose the user permissions i.e. Read, Insert, Delete or Edit and save the role.

Cloning the permission role
To get the ‘Blog Editor’ permission role programmatically from the root site:

   1:  SPRoleDefinition role = web.RoleDefinitions['Blog Editor'];

Now let’s copy the role to the new site collection. I have chosen to elevate the permission to the application pool in the case below:

   1:  SPSecurity.RunWithElevatedPrivileges(delegate()
   2:  {
   3:      using (SPSite site = new SPSite(webUrl + "/" + siteUrl))
   4:      {
   5:          using (SPWeb web = site.OpenWeb())
   6:          {
   7:              web.AllowUnsafeUpdates = true;
   8:              PermissionRoleClone(web, role.Name, role.Description, role);
   9:          }
  10:      }
  11:  });

The clone permissions routine checks if the role already exists and then simply adds the copy from the root site with a new name and description:

   1:  public SPRoleDefinition PermissionRoleClone(SPWeb web, String roleName, String roleDescription, SPRoleDefinition sourceRole)
   2:  {
   3:      SPRoleDefinition newRole = null;
   4:   
   5:      try
   6:      {
   7:          newRole = PermissionRoleExists(web, roleName);
   8:   
   9:          if (newRole == null)
  10:          {
  11:              newRole = new SPRoleDefinition(sourceRole);
  12:              newRole.Name = roleName;
  13:              newRole.Description = roleDescription;
  14:              web.RoleDefinitions.Add(newRole);
  15:              web.Update();
  16:          }
  17:      }
  18:      catch (Exception ex)
  19:      {
  20:          logErr = String.Format("PermissionRoleClone:{0}",ex.ToString());
  21:      }
  22:   
  23:      return newRole;
  24:  }

To find if the role already exists within the target site collection:

   1:  public SPRoleDefinition PermissionRoleExists(SPWeb web, String roleName)
   2:  {
   3:      SPRoleDefinition matchRole = null;
   4:   
   5:      foreach (SPRoleDefinition role in web.RoleDefinitions)
   6:          if (role.Name == roleName)
   7:          {
   8:              matchRole = role;
   9:              break;
  10:          }
  11:   
  12:      return matchRole;
  13:  }

Now the permission role can be assigned to your site security groups, libraries and lists, I will cover this in part 2 of this post.