Speckle Connector installed changes how Speckle Converter code works in another plugin

Hi all,

tldr: We have Speckle Base objects in our plugin that can only be read as Speckle Brep objects when the Revit connector is installed on the user’s machine.

  • Goal: We are building an in-house plugin for Revit which receives breps from Rhino (sent through Speckle) and apply various data, remapping, etc. We are referencing and deploying the Speckle Core 2 dlls and Speckle Objects dll’s with the app.

  • Issue: The behaviour of our code, using Speckle Objects changes whether we have the Revit Connector installed or not. Ideally we’d want to decouple our plugin from having to install the connector, however the code only works with the connector installed. See below for the details.

  • Question: What do you think, in the Speckle Rvt Connector, could impact the behaviour of the code below ?


        public ApplicationObject FloorToNative(Base baseFloor, ConverterRevit converter)
        {
            // for the same object,
            // always true if the Revit Connector is installed
            // always false if the Revit Connector is not installed (even when ALL converters .dlls are loaded) (Objects.Converter.Revit-xxxx.dll)
            if (baseFloor is Objects.Geometry.Brep  brep)
            {
                // DEBUG INFO
                var assemblybrep = typeof(Brep).Assembly;  // this is correctly mapped to Objects.dll in both situations
                var assemblybase = typeof(Base).Assembly;  // this is correctly mapped to SpeckleCore2.dll in both situations
                /////////
             
                /// ....   rest of solution
             }
      
  • What we tried: We tried loading different versions of Speckle, we tried aligning / dealigning the speckle SDK / connector version, we tried manually loading all the same dll’s as when the converters is installed… Nothing changes the behaviour of the code above.

Any input would be welcome!

Hi @Romain_Bigare!

So you’re directly referencing Objects nuget in your project?

There is a known behaviour of C# dlls: A dll (Objects.dll in this case) will not be loaded until it is actively used in code (this is an optimisation we have no control over)

This means that loading the Objects.dll will be done at the latest time possible in your code.

On the other hand, our Deserialiser use reflection to try and find what types it has to cast the objects to; since we’re using reflection, the compiler doesn’t really know we’re using Objects.dll here where possible, so if it hadn’t loaded it before hand, it will not find the object types and instead return all Base instances with all the information dynamically attached.

Our connectors don’t reference objects nor converters directly and instead use KitManager to forceload all kit related stuff from the %appdata% folder into the app on startup.

I would heavily suggest you do the same. Specifically including the Objects.dll in your project may lead to DLL conflicts either on your side or ours, with very little capability for us to fix.

It would also be interested to know why you’re “using speckle” without using “the speckle connector” for that app.

Pinging @jonathon who I know has been doing some coding for Automate and may have some suggestions of his own for you :smiley:

1 Like

Thanks for your help @AlanRynne !

Fair question. I’ve written about it in this post on the forum. Essentially, we’re doing a lot of extra remapping, rebuilding and data transfer that the Speckle Connector wasn’t offering. Mainly Rhino UserStrings → Revit parameters, and Rhino breps → native editable floors (not direct shape).

Assuming this done via this line of code in your Revit connector ? I’m not too familiar with the KitManager, so thanks for pushing me in that direction, will have a go at relying on it for loading the scaffolding.

public partial class ConnectorBindingsRevit : ConnectorBindings
{
  
  public ISpeckleConverter Converter { get; set; } =
    KitManager.GetDefaultKit().LoadConverter(ConnectorRevitUtils.RevitAppName);

}

It prompts us to consider what’s next for the Speckle Mapper initiative. Allowing users to do more with that and “save” actions as a repeatable feat.

Allowing you to define just the real specifics that are unique to you but deal with the minimum of scaffolding is a preferable state for you and us. For us we’d want to enable you to have your custom workflows but not be blocked from using vanilla Speckle (before we get tied up in versioned Objects)

We have some further things we are working on BTS that some of the dev team might wish to ask you for your input if you have time/willingness.?

Yah, would be happy to help. Give me a shout whenever you guys want !

For future reference, if anyone is facing the same challenge, @AlanRynne’s answer was very helpful in coming up with the solution. Thanks Alan.

I’m not sure I implemented it correctly (?) but using the KitManager seems to work for machines with Speckle and for machines without Speckle.

Here’s the code for the initiation of our Speckle Controller ( / Connector) within our larger plugin.


        public SpeckleController()
        {
            IsInitialised = Task.Run(() => Initialize()).Result;
        }

        private Task<bool> Initialize()
        {
            // This function initializes our Speckle Controller ("connector")
            // It tries to initialize the KitManager from a specific location on the user's machine
            // And if that fails, we assume Speckle is already loaded and there's no reason to load kits and converters once more

            var thisAssemblyPath = Assembly.GetExecutingAssembly().Location;
            thisAssemblyPath = Path.GetDirectoryName(thisAssemblyPath);

            // THIS IS THE PATH OF OUR OWN DEPLOYMENT OF THE SPECKLE KITS, OBJECTS AND CONVERTERS DLLs
            var specklePath = Path.Combine(thisAssemblyPath, "speckle");
            var appName = AppSetup.AppName;

            try
            {
                KitManager.Initialize(specklePath);
            }
            catch (Exception e)
            {
                // Looks like the KitManager is already initialized, Speckle probably installed on this machine, ignore
            }

            try
            {
                var kit = KitManager.GetKitsWithConvertersForApp(appName).First();
                if (kit == null)
                    kit = KitManager.GetDefaultKit();

                // THIS IS THE MAIN CHANGE FROM PREVIOUS VERSION OF THE CODE!
                // INSTEAD OF CREATING A CONVERTER REVIT INSTANCE MANUALLY, WE HANDLE IT THROUGH THE KIT MANAGER
                converter = kit.LoadConverter(appName);
            }
            catch (Exception e)
            {
                Util.HandleError(e);
                return Task.FromResult(false);
            }

            return Task.FromResult(true);
        }
1 Like