You want to grab the Site or Web that your feature was installed on to do some last minute clean up before the package is retracted from your site; well me friend too bad. Don't believe me? paste this code into your Feature Receiver.
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\output.txt", true))
{
file.WriteLine("Feature Uninstalling {0}", DateTime.Now.ToString());
if (properties.Feature == null)
file.WriteLine("FML");
else
file.WriteLine("Not FML");
}
}
now go check your c:\output.txt file; what's it say? oh that's right, FML, or I should say FYL, meaning that:
using (SPWeb web = properties.Feature.Parent as SPWeb){} or
using (SPSite site = properties.Feature.Parent as SPSite){}
is useless, so how do we deal with this?
To make my goal clear: what I'm trying to accomplish is delete list instances that were deployed through a feature in the package, as you may know when you retract your package the list instance(s) hang out, it's an artifact that gets left behind, . This is especially a problem for me because when the package is retracted so are the content types for my lists, leaving my lists useless, unopenable.
So what do we do now? If you run the above experiment with "properties.Definition" you'll get much more satisfying results. Should you dive further you'll learn that you can grab the SPFarm object. Is this ideal? by no means, but you got to do, what you got to do.
Now you most likely have multiple environments: DEV, TEST, prePROD, and PROD, now you probably do not want to be refactoring your event receiver for each environment, so the dirty work around I use is:
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
string[] WebApplicationNames = { "Dev", "Test", "PreProd","Production" };
SPFarm farm = properties.Definition.Farm;
SPWebApplicationCollection webApps =
farm.Services.GetValue<SPWebService>("").WebApplications;
foreach (SPWebApplication webApp in webApps)
{
if (Array.Exists(WebApplicationNames, delegate(string s)
{return s.Equals(webApp.Name);}))
{
foreach (SPSite s in webApp.Sites)
{
using(SPWeb web = s.RootWeb)
DeleteListInstances(web, new string[] { "List Instance1 Name", "List Instance2
name" });
s.Dispose();
}
}
}
}
private void DeleteListInstances(SPWeb web, string[] listInstanceNames)
{
foreach (string listInstanceName in listInstanceNames)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPList list = web.Lists.TryGetList(listInstanceName);
if (list != null)
web.Lists.Delete(list.ID);
});
}
web.Dispose();
}
Now do I feel Dirty? you bet I do; so if you have a better way please feel free to let me know.