Wednesday, November 2, 2016

Disposing of a DLL

So I've been working on a feature for Sitecore Instance Manager to automate installing Sitecore instances with Solr turned on.  This has been pulled in to the Develop branch of SIM and should hopefully hit the downloadable version soon.

One interesting detail was how to handle the "Generate Solr Schema" step. This is normally done through the Sitecore Control Panel, and is responsible for updating the Solr schema.xml file to include definition of fields like "_uniqueid" and "__bucketable" that are required for Sitecore. To automate this step, I considered analyzing the changes and writing a script to apply them, or even copying a prebaked "schema.xml" to the Solr instance directory, but this didn't feel ideal. Suppose a new version of Sitecore introduces a new Solr field (let's say "__basketable"...). My feature would be instantly obsoleted. Bummer.

It would be far better to use the actual code that is run by this option, and with a little digging, I was able to find the C# class that does the transformation, Sitecore.ContentSearch.ProviderSupport.Solr.SchemaGenerator, in the Sitecore.ContentSearch.dll. What if directly loaded that from the bin directory of the new instance? That worked nicely.



The DLL path is passed in, because that depends on the instance, and the path to the schema is pulled from the Solr API. I ended up refactoring the bits that load the DLL to an existing ReflectionUtil class:



This worked really nicely until I tried to clean up some of the sites created during my testing, and got this error:



Of course! I loaded the DLL from that site's bin directory to the SIM process, so now I can't delete the file. I did some googling of whether you can dispose of a DLL once you've loaded it, and long story short, you can't.  Alen Pelin suggested I load the DLL from a memory stream, but that sounded complicated (= had no idea how to do this) so I did some more googling of disposing of DLLs and found discussion of AppDomains.  These seemed to be designed expressly for this purpose--the DLL is not disposable, but the app domain it is loaded to is. Cool. However, the documentation on MSDN looked pretty light, as did the Stack Overflow coverage, so it didn't look like a technique in heavy rotation. But what the hey, let's give it a try:



So that blew up because GenerateSolrSchema does not implement Serializable:



Okay, time to take another look at Alen's suggestion. It turns out that Assembly.Load can take a Stream parameter, so fixing this was as simple as adding FileStream.ReadOpen(path), and passing the results to AssemblyLoad (thanks to this Stack Overflow answer too). Load the steam in a Using block and you're all set:



Now you can create and delete Sitecore+Solr instances all day long!

As I mentioned at the top, this is not yet in the main branch of SIM, but you can play with it by building the Develop branch of https://github.com/sitecore/sitecore-instance-manager, and you can check out this feature intro video:


No comments:

Post a Comment