9 Nov
2009

StructureMap and SharePoint

Category:UncategorizedTag: , , :

I’ve started doing some SharePoint development and have brought some of my favorite tools and practices with me.  Like unit tests.  And IoC.  And that other SOLID stuff. 

I’m writing a very basic WebPart to get started with SharePoint – this web part will display a list of links to other applications that the user is authorized to use.  The source of this data (names, URLs, etc.) comes from an external-to-SharePoint system, accessed through another C# assembly.  Once the web part gets the data there is some more processing to be done – we need to do more than just blindly display a list of URLs.  Rather than get into details I’m just going to do some handwaving here and say that “if you have access to X, then {stuff happens}, or if you have access to Y then {other stuff happens}.”  You know, business logic, stuff that is good to test.

the first thing I need to do is get business logic out of the WebPart and into something that I can write without having to reset AppPools over and over, not to mention have some unit tests to verify I’m going in the right direction.  So, I created a standard application service class which has a dependency on the external authorization system, via constructor injection. 

public class AuthorizedAppsService : IAuthorizedAppsService
{
  private readonly ExternalAuthorizeService authService;

  public AuthorizedAppsService(
    ExternalAuthorizeService authService) 
  {
    this.authService = authService;
  }

  public AuthorizedApplications GetAuthorizedApplications(
                                  string userName)
  {
    var allApps = authService.AuthorizedApplications(userName);
    // business logic stuff happens here
    return thoseResultsWeJustFiguredOut;
  }
}

Next, I created a StructureMap Registry class to scan my assemblies, as well as adding in the details of how to create this external authorize service, using the typical method:

public class MyRegistry : Registry
{
  public MyRegistry()
  {
    Scan(scanner => {
      scanner.TheCallingAssembly();
      scanner.AssemblyContainingType(typeof(MyRegistry));
      scanner.WithDefaultConventions();
      });

    ForRequestedType<ExternalAuthorizeService>()
      .AsSingletons()
      .TheDefault.Is.ConstructedBy(c => Provider.GetService());

    // other dependency configuration...
  }
  public static void InitializeForSharepoint()
  {
    ObjectFactory.Initialize(init => init.AddRegistry<MyRegistry>());
    ObjectFactory.AssertConfigurationIsValid();
  }
}

And then, what remains is to have SharePoint call my StructureMap initialization when my SharePoint application starts up.  In an MVC or WebForms app, I’d just add code to the appropriate place in Global.asax.cs, but in SharePointLand, this is looked down on.  Instead, the preferred mechanism seems to be to use an HttpModule and a FeatureReceiver to plug the Module into the app’s web.config.

public class MyStartupModule : IHttpModule
{
  public void Init(HttpApplication context)
  {
        ConfigureOtherStuff();
        MyRegistry.InitializeForSharepoint();
  }
  public void Dispose() { }
}

And then the FeatureReceiver to alter the app’s Web.Config looks something like this (note I borrowed most of this code from another sample SharePoint project:

 

//
// this is borrowing heavily from http://www.codeplex.com/SPAXO
// 
public class StartupFeatureReceiver : SPFeatureReceiver
{
  public override void FeatureActivated(
        SPFeatureReceiverProperties properties)
  {
    var webApp = properties.Feature.Parent as SPWebApplication;
    AddWebConfigEntry(webApp);
    UpdateApp(webApp);
  }

  public override void FeatureDeactivating(
        SPFeatureReceiverProperties properties)
  {
    var webApp = properties.Feature.Parent as SPWebApplication;
    RemoveWebConfigEntry(webApp);
    UpdateApp(webApp);
  }


  private static void AddWebConfigEntry(SPWebApplication webApp)
  {
    SPWebConfigModification mod = GetModification();
    var existingModifications = 
             new List<SPWebConfigModification>(
                      webApp.WebConfigModifications);
    if (existingModifications.FindIndex(
                    value =>
                        value.Name == mod.Name &&
                        value.Value == mod.Value &&
                        value.Owner == mod.Owner) == -1)
    {
      // If the modifcation does not already exist 
      // add the entry to the config
      webApp.WebConfigModifications.Add(mod);
    }
  }

  private static void RemoveWebConfigEntry(
            SPWebApplication webApp)
  {
    SPWebConfigModification mod = GetModification();
    webApp.WebConfigModifications.Remove(mod);
  }

  private static SPWebConfigModification GetModification()
  {
    string asmName = typeof(StartupModule).AssemblyQualifiedName;
    string typeName = typeof(StartupModule).FullName;

    return new SPWebConfigModification
      {
        Path = "configuration/system.web/httpModules",
        Name = String.Format(CultureInfo.InvariantCulture,
                "add[@name='{0}'][@type='{1}']",
                typeName, asmName),
        Sequence = 0,
        Owner = asmName,
        Type = SPWebConfigModification.
                    SPWebConfigModificationType.EnsureChildNode,
        Value = String.Format(CultureInfo.InvariantCulture,
                  "<add name='{0}' type='{1}' />",
                  typeName, asmName)
      };
  }

  private static void UpdateApp(SPWebApplication webApp)
  {
    // Update the Web App and apply the changes 
    // to all servers in the farm
    webApp.Update();
    webApp.Farm.Services
        .GetValue<SPWebService>()
        .ApplyWebConfigModifications();
  }
}

2 thoughts on “StructureMap and SharePoint

  1. If you haven’t yet, check out the guidance from P&P on sharepoint development. It may help get you boostrapped so that you don’t have to figure out what all of the limitations are. Of course, a lot changes in 2010, but the fundamentals still are the same.

    http://spg.codeplex.com/

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.