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);

4 comments:

  1. Hi,
    I'm having problem in adding location.

    ON the AddNewLocationConfiguration method call, I get the following error:
    {"Procedure or function 'proc_MSS_AddNewLocationConfiguration' expects parameter '@PropertySchema', which was not supplied."}

    I've tried to manually import the file and the location is created correctly.

    Any idea?

    ReplyDelete
  2. Are you using the SearchServiceApplication object or the proxy object? From the error it appears you are using the proxy object which has this bug.

    ReplyDelete
  3. This is the code:

    SearchServiceApplicationProxy proxy = (SearchServiceApplicationProxy)SearchServiceApplicationProxy.GetProxy(SPServiceContext.GetContext(site));
    var doc = new XmlDocument();
    doc.Load("location.OSDX");
    var searchLocation = new LocationConfiguration(doc);
    proxy.AddNewLocationConfiguration(searchLocation);

    Many thanks for your help

    ReplyDelete
  4. You should change the first line from using SearchServiceApplicationProxy to using SearchServiceApplication instead as there is a bug for the Location object via the proxy class. Read this thread: http://social.technet.microsoft.com/Forums/en-US/sharepoint2010setup/thread/dbbe70f1-3014-44b1-9567-f03118717e4a


    // Service Application Info object to retrieve the application id for the search service.
    SearchServiceApplicationInfo searchApplictionInfo = searchApplicationProxy.GetSearchServiceApplicationInfo();

    // Retrieve the search application instance for the specified id.
    SearchServiceApplication searchApplication = Microsoft.Office.Server.Search.Administration.SearchService.Service.SearchApplications.GetValue (searchApplictionInfo.SearchServiceApplicationId);

    searchApplication.AddNewLocationConfiguration(.....)

    ReplyDelete