Question

I am on a team developing a "portal" for SharePoint Foundation 2010. I am responsible for making the installer which sets up a new instance of SharePoint. It handles more than just the installation of the solution files and configuration of SharePoint. The installer handles deploying files to the GAC and creating our federated security client (used for our SharePoint claims based auth).

During the install of an instance I complete a few tasks that are specifically related to SharePoint and use the SharePoint API in .NET 3.5:

  1. Create/Configure Trust
  2. Create a web application.
  3. Deploy solutions to farm and web application
  4. Create default site collection
  5. Activate default features on the site collection
  6. Update the web application "properties"

Up to know I have been able to have an install work properly on a single SharePoint server, ie one server hosts the farm database and another is the full stack of SharePoint services. I have begun testing with a setup that will mimic the real world setup of SharePoint in our hosting environment. There we have a database server and at least three SharePoint servers, only one of of which has Central Administration.

The problem I've run into is that in this case I can correctly and without any errors do all the steps above except the activation of features. I've removed the code which does this step and verified that the web application, site collection, trust, etc (except for the "properties") have been created correctly by launching the site, authenticating, and seeing the default "team" theme. However, once I activate the default features, either via API or through the site collection settings, I can no longer access the site and receive an error.

This comes to the crux of my problem and the issue I face when explaining it here. Our solution is highly complex in that it involves a lot configuration from aspects of security and reliance on other services outside of SharePoint. I don't know if some of our settings are not propagating across the servers causing an internal error in our solution to cause the error page. I also do not know if when I'm setting the "properties" if they're sticking in the farm situation. I had an issue where I was not setting these right when I first started out on this task and it caused an issue similar to what I'm seeing now.

I also am unsure if the solutions are correctly being deployed therefore corrupting the features. I've setup ULS viewer on each of the SharePoint servers yet I cannot find anything relating to the correlation ID for the error I receive on the error page. I actually get no events in the ULS viewer on "master" SharePoint server. I can see the deploying and retracting of solutions in the viewer on the other two servers.

I must be missing something that happens in a farm with multiple servers. I am hoping that someone can take a look at the bit of code I use to deploy solutions and set properties to help me out. I would also really like to figure out why I cannot see the error that I'm getting in any of the ULS Viewers. Can someone explain this for me?

Also I'm looking for more definitive examples of how to configure and setup SharePoint via the C# API. Up to this point I've been decompiling the code for the commandlets and replicating what I can in code. I still do not have a "correct" way to activate a feature via C# and am just creating a process running stsadm.exe to activate the features.

Here is my code for adding and deploying a solution:

      SPSolution newSolution = SPFarm.Local.Solutions.Add(Path.Combine(this.SharePointPointRootFolder, solutionDefinition.filename));

      if (!solutionDefinition.webApplicationSpecific)
      {
        Console.WriteLine("Adding a farm specific solution.");

        newSolution.Deploy(DateTime.Now, true, true);

        this.WaitForSolutionJobsToComplete(newSolution.Id);

        newSolution.Synchronize();
      }
      else //specific to a web application.  Load the new solution.
      {
        Console.WriteLine("Adding web application specific solution.");

        Collection<SPWebApplication> webAppCol = new Collection<SPWebApplication>();
        webAppCol.Add(this.WebApplication);

        newSolution.Deploy(DateTime.Now, true, webAppCol, true);

        this.WaitForSolutionJobsToComplete(newSolution.Id);

        newSolution = SPFarm.Local.GetObject(newSolution.Id) as SPSolution;

        newSolution.Synchronize();

        this.WaitForSolutionJobsToComplete(newSolution.Id);

        newSolution.Update();
      }

Here is my code for activating features. It just uses a process to use STSADM.EXE:

void UpdateFeatures(SPSite site)
{
  Console.WriteLine("Updating features.");

  SPSolutionDefinitionCollection collection = SolutionConfigurer.LoadSolutionDefinitions();

  foreach (SPSolutionDefinition solutionDefinition in collection.spSolutionDefinition)
  {

    Guid id = new Guid(solutionDefinition.ID);

    if (solutionDefinition.spFeatureDefinition != null && solutionDefinition.spFeatureDefinition.Length > 0)
    {
      foreach (Models.SPFeatureDefinition fDef in solutionDefinition.spFeatureDefinition)
      {
        Guid fDefId = new Guid(fDef.ID);

        //this.Activate(fDefId, site);

        Process stsadmP = WebApplicationConfigurer.GetSTSADMProcess(this.STSADMPath, "-o activatefeature -id " + fDef.ID + " -url " + this.SiteCollectionUrl + " -force");

        Console.WriteLine(string.Format("Invoking STSADM.EXE for feature deployment: {0} with arguments:{1}", stsadmP.StartInfo.FileName, stsadmP.StartInfo.Arguments));

        stsadmP.Start();
        stsadmP.WaitForExit();

        if (stsadmP.ExitCode == 0)
        {
          Console.WriteLine(string.Format("STSADM.EXE successfully ran for feature id {0} and produced this output: {1}", fDefId, stsadmP.StandardOutput.ReadToEnd()));
        }
        else
        {
          Console.WriteLine(string.Format("STSADM.EXE did not produce a successful exit code for feature id {0} and produced this output: {1} + {2}", fDefId, 
            stsadmP.StandardOutput.ReadToEnd(), stsadmP.StandardError.ReadToEnd()));
        }
      }
    }
  }
}

Here's how I update a property. I do this last because I was doing it after deploying the solutions, but it seems that activating features was resetting the values.

public void UpdatePropertiesWebApplication()
{
  string dnsName = this.SigningCertificate.GetNameInfo(X509NameType.DnsName, false);

  SPWebApplication webApplication = SPFarm.Local.GetObject(this.WebApplicationId) as SPWebApplication;

  if (webApplication != null)
  {
    Console.WriteLine("Updating property information for the web application.");

    if (!webApplication.Properties.ContainsKey(Constants.PropertyBagKeys.ESB_ROOT))
    {
      webApplication.Properties.Add(Constants.PropertyBagKeys.ESB_ROOT, this.ESBUrl);
    }
    else
    {
      Console.WriteLine("Updating ESB Root URL. " + this.ESBUrl);
      webApplication.Properties[Constants.PropertyBagKeys.ESB_ROOT] = this.ESBUrl;
    }

    Console.WriteLine("ESB Root Url: " + webApplication.Properties[Constants.PropertyBagKeys.ESB_ROOT]);

    if (!webApplication.Properties.ContainsKey(Constants.PropertyBagKeys.REALM))
    {
      webApplication.Properties.Add(Constants.PropertyBagKeys.REALM, this.SharePointTrustPoint);
    }
    else
    {
      Console.WriteLine("Updating realm. " + this.SharePointTrustPoint);
      webApplication.Properties[Constants.PropertyBagKeys.REALM] = this.SharePointTrustPoint;
    }

    Console.WriteLine("Realm: " + webApplication.Properties[Constants.PropertyBagKeys.REALM]);

    if (!webApplication.Properties.ContainsKey(Constants.PropertyBagKeys.SSO_ROOT))
    {
      webApplication.Properties.Add(Constants.PropertyBagKeys.SSO_ROOT, this.SSOUrl);
    }
    else
    {
      Console.WriteLine("Updating the broker url. " + this.SSOUrl);
      webApplication.Properties[Constants.PropertyBagKeys.SSO_ROOT] = this.SSOUrl;
    }

    Console.WriteLine("Broker Url: " + webApplication.Properties[Constants.PropertyBagKeys.SSO_ROOT]);

    if (!webApplication.Properties.ContainsKey(Constants.PropertyBagKeys.TRUSTED_CERT_DNS_IDENT))
    {
      webApplication.Properties.Add(Constants.PropertyBagKeys.TRUSTED_CERT_DNS_IDENT, dnsName);
    }
    else
    {
      Console.WriteLine("Updating trusted cert dns identity. " + dnsName);
      webApplication.Properties[Constants.PropertyBagKeys.TRUSTED_CERT_DNS_IDENT] = dnsName;
    }

    Console.WriteLine("Trusted Certificate Identity: " + webApplication.Properties[Constants.PropertyBagKeys.TRUSTED_CERT_DNS_IDENT]);

    webApplication.Update(true);
  }
}
Was it helpful?

Solution

To answer your general question, the recommended way to deploy solution in SharePoint 2010 is to use PowerShell.

From What's New: Windows PowerShell for SharePoint:

Windows PowerShell supersedes the Stsadm.exe administration tool. Moving forward, you should use Windows PowerShell scripting technology to develop any new command-line scripts in SharePoint Foundation 2010.

Here are some samples and scripts for deploying with PowerShell:

And here is information on activating features in PowerShell:

To answers your specific question, it is possible to activate a feature in C#:

Guid fDefId = new Guid(fDef.ID);
site.Features.Add(fDefId);

For more information, see SPSite.Features and SPFeatureCollection.Add.

OTHER TIPS

to be totally honest I never see the point anymore of doing anything in code that I can do with stsadm directly.

So I always just use the equivalent to what I require:

stsadm -o deletesolution -name solution.wsp -override
stsadm -o addsolution -filename c:\path\solution.wsp
stsadm -o deploysolution -name solution.wsp -allowgacdeployment -local -force

Then...

Activate features
Setup solution options
Apply master template
Create sub sites
Create lists
Add Web parts
Set permissions
Hide/Show navigation and columns
Add any data to deployment required
Finish

I have had to many problems trying to deploy a solution using the method you use (Just search I posted on here and found no solutions)

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top