Wednesday, June 22, 2011

Deleting a Federated Location via the API

I’m working on a SharePoint feature which will automatically add a federated search location on feature activation and which will delete it on de-activation.

To accomplish this I use the Microsoft.Office.Server.Search.Administration.SearchServiceApplication class, and more specifically the AddNewLocationConfiguration and DeleteLocationConfiguration methods. I tried to use the same methods of the SearchServiceApplicationProxy first, but there seems to be an error using the AddNewLocationConfiguration method on proxy object.

AddNewLocationConfiguration takes a LocationConfiguration object as parameter, which can be created by loading in the xml from an OSDX file like this:


var searchLocation = new LocationConfiguration(); 
var stream = …stream to xml file…; searchLocation.Import(stream);

As you see, adding is not too hard, but deleting is the problem. The DeleteLocationConfiguration method takes the id of a LocationConfiguration object as the parameter. But lo and behold, the Id property is defined as internal.

image

That means it’s not available for us to delete on. But we’re lucky to use .Net where reflection is possible. Buy using the helper class below we can get the value from the internal property. Note that the code could have used regular reflection, but emitting IL makes more optimized code, and I use this utility class a lot of other places where performance is an issue.


public class DynamicReflectionHelperforObject<V>
{
public delegate T GetPropertyFieldDelegate<T>(V obj);

public static GetPropertyFieldDelegate<C> GetP<C>(string memberName)
{
Type v = typeof(V);
PropertyInfo pi = v.GetProperty(memberName, BindingFlags.NonPublic | BindingFlags.Instance);
if (pi == null)
throw new NullReferenceException("No Property or Field");

DynamicMethod dm = new DynamicMethod("GetPropertyorField_" + memberName, typeof(C), new Type[] { v }, v.Module);
ILGenerator il = dm.GetILGenerator();

il.Emit(OpCodes.Ldarg_0); // loaded c, c is the return value
il.EmitCall(OpCodes.Call, pi.GetGetMethod(true), null);
il.Emit(OpCodes.Ret);
return (GetPropertyFieldDelegate<C>)dm.CreateDelegate(typeof(GetPropertyFieldDelegate<C>));
}
}

And to use it pass inn the object type, the property type and the object we want to retrieve the property from:

int id = Helpers.DynamicReflectionHelperforObject<LocationConfiguration>
.GetProperty<int>("Id")
.Invoke(frontLocation);
fastQuerySSA.DeleteLocationConfiguration(id);