Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load C# assemblies at startup #1335

Closed
Dre-Tas opened this issue Sep 21, 2021 · 20 comments
Closed

Load C# assemblies at startup #1335

Dre-Tas opened this issue Sep 21, 2021 · 20 comments
Labels
Question This is a question and not an issue Runtime Issues related to loading pyRevit runtime [subsystem]

Comments

@Dre-Tas
Copy link
Contributor

Dre-Tas commented Sep 21, 2021

Hey Ehsan!

I'm having issues with the startup script (C#) when initially loading the assemblies that are going to be necessary for the plugin.
The main issue seems to be with versions of the assemblies.

I'll use an example of what I'm trying to do to be more clear:
I'm creating a dockable panel at startup (we discussed here some months ago) and this panel, when being created gets some info from a database.
I'm storing some secrets to access this database on Azure Key Vault, hence, I'm using the NuGet packages called Azure.Identity and Azure.Security.KeyVault.Secret that allow me to retrieve those secrets from Azure. Both those packages have a third package called Azure.Core as a dependency, but they reference 2 different versions of it. Identity needs Azure.Core >= 1.17 and Security needs >= 1.15. I initially installed 1.19 so that I was sure it was working for both.
And this is where the problem is: pyRevit seems to load one version of Azure.Core (what gets built by VS, which is v1.19) but then it complains that it's not finding the right version
image

It sort of seems to lose the information that any version that is >= of version 1.x is fine.

I tried many different versions of all the packages but at some point something always goes wrong. I also found and tried to use the versions of Azure.Identity and Azure.Security.KeyVault.Secret that use the same version of Azure.Core and at that point the error above didn't happen anymore, but it happened with another assembly.

This is how I'm loading the assemblies in startup.cs

foreach (string dependencyAssembly in new string[] {
    "Azure.Core.dll",
    "Azure.Identity.dll",
    "Azure.Security.KeyVault.Secrets.dll"
    })
        Assembly.LoadFrom(
            Path.Combine(binDir, dependencyAssembly));

But I also tried with Assembly.Load and Assembly.LoadFile with the same results.

Am I missing something? Is there a way to load the assemblies without specifying which version it is? Or maybe it's something else?

Cheers!

@dosymep
Copy link
Member

dosymep commented Sep 24, 2021

Hello.
I think you can use AppDomain.CurrentDomain.AssemblyResolve event to load your assemblies.

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Sep 24, 2021

Thanks @dosymep !
I actually read about that at some point but I didn't fully understand how to use it.

Would you use it in the startup code or in the plugin code? Do you have an example?

Cheers

@dosymep
Copy link
Member

dosymep commented Sep 24, 2021

Simple example command class:
I wrote this code in notepad maybe it have some errors.

[Transaction(TransactionMode.Manual)]
public class RevitCommand : IExternalCommand {
	public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) {
		AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
		try {
			CommandExecuteMethod(commandData, message, elements);
		} finally {
			AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
		}

		return Result.Succeeded;
	}
	
	private void CommandExecuteMethod(ExternalCommandData commandData, ref string message, ElementSet elements) {
		// yourcode
		// this method mandatory,
		// because .NET try load assembly before executing code
	}
	
	private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) {
		var assemblyName = new AssemblyName(args.Name);
		
		// try get assembly path
		// referenced assembly must be next to the assembly of the command
		var assemblyPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutionAssembly().Location), assemblyName.Name + ".dll");
		
		return File.Exists(assemblyPath) ? Assembly.LoadFrom(assemblyPath) : null;
	}
}

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Oct 1, 2021

Thanks @dosymep for the sample code.

I tried it again, but this doesn't really fix my issue. AppDomain.CurrentDomain.AssemblyResolve just tells me when there's an issue with one of the dlls, but it doesn't really fix it.
Or am I missing something?

@dosymep
Copy link
Member

dosymep commented Oct 1, 2021

@Dre-Tas, The finding dll does exist?
assemblyPath must be correct path to finding dll.

@dosymep
Copy link
Member

dosymep commented Oct 1, 2021

@Dre-Tas,
1 my assembly resolver
2 my revit plugin command
3 my extension with all my reference assemblies

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Oct 1, 2021

Yeah @dosymep the dll definitely exists and it's in the right folder (together with the other dlls that get loaded correctly. It seems to be a problem with the versions of the dll (as per my first post at the top)

@dosymep
Copy link
Member

dosymep commented Oct 1, 2021

@Dre-Tas, I understand what is problem. Pyrevit load assemblies without context that's why my code doesn't work.
Pyrevit call Assembly.Load instead of Assembly.LoadFrom method, and .NET doesn't know where locate callable assembly.

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Oct 1, 2021

@dosymep you can actually use LoadFrom in the startup.cs
That's what I'm using, but still I get that weird error that might have to do with versions of the assembly

@dosymep
Copy link
Member

dosymep commented Oct 1, 2021

@Dre-Tas, I have created project witch use these libraries and then specified absolute paths in CurrentDomain_AssemblyResolve, and this project began executing. (pyrevit-extension - replace to your path)
image

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Oct 5, 2021

Nope not working for me :(

Now I just managed to use all packages that use the same version of the dependencies. It wasn't easy and I don't think it's going to work as a long-term solution, but we'll see.
(I'm not going to close the issue as it hasn't really been fixed, so maybe someone in the future will be able to help)

In the meantime I'm having another weird error in Revit 2019, but I'm gonna post a separate issue.

@eirannejad eirannejad added Question This is a question and not an issue Runtime Issues related to loading pyRevit runtime [subsystem] labels Oct 16, 2021
@eirannejad
Copy link
Collaborator

@Dre-Tas

I'm just reading the thread here but a couple of things aren't clear:

  • Are you using a startup.cs script or an .invokebutton?
  • Are you loading ALL the dependencies yourself or loading the ones you need and letting dotnet runtime load the rest?

I'm trying to figure out where does pyRevit fit into the picture here. I heard that this error is stopping you from deploying your tools on Revit 2019 so I'm ready to have a zoom chat as well if you think that'll help

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Oct 17, 2021

Thanks @eirannejad for the reply!

Sorry for the confusion. I'm using a startup.cs script and I'm loading just the dependencies that I need. Like this:
image

And sorry for the further confusion: The exception from the first post happens in all versions of Revit.
The issue with Revit 2019 started happening when I tried to use versions of Azure.Identity and Azure.Security.KeyVault.Secret that used the same version of Azure.Core to see if it stopping complaints. It was an experiment, but of course not the way we intended to proceed. We can forget about this for right now, if it makes it easier.
(You can see more details on the R2019 issue here https://forums.autodesk.com/t5/revit-api-forum/issue-with-azure-nuget/td-p/10668959 )

To be honest I'm trying to figure out myself if this is a pyRevit thing or not. I think it might be, as it's pyRevit loading those Azure assemblies and expecting certain versions.

Zoom sounds great! Do you want me to send you some files first to have a look at it or do you prefer calling first?

@eirannejad
Copy link
Collaborator

Yes. Let's schedule something for Friday maybe?

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Oct 21, 2021

Any chance we can do during the week? Your Friday would be my Saturday morning and considering they just lifted the lockdown here in Sydney I'll probably try and get away for the weekend 😉

@Dre-Tas
Copy link
Contributor Author

Dre-Tas commented Oct 28, 2021

@eirannejad let me know when you want to do that zoom call. I'll be home most of the day this Saturday so we can schedule it your Friday if it's the best time for you

@eirannejad
Copy link
Collaborator

@Dre-Tas Sounds great. I 'm open anytime Friday afternoon and Saturday (or Sunday) on Pacific Standard Time. Let me know what's a good time slot is for you and I'll send an invite :D

@eirannejad
Copy link
Collaborator

Part of this issue seems to be resolved. The rest is on #1373

@bfedonin
Copy link

bfedonin commented Feb 4, 2023

@Dre-Tas, I have created project witch use these libraries and then specified absolute paths in CurrentDomain_AssemblyResolve, and this project began executing. (pyrevit-extension - replace to your path) image

Worked for me while trying to use Google Sheets API

@kekejun
Copy link
Contributor

kekejun commented May 6, 2024

For those who encounters the same issue, I am making an invoke button and ran into the same problem, the assemblies couldn't got resolved even though I registered the AssemblyResolve event in Execute() with the LoadFrom method, I suppose the dependencies are checked before the execution.
I solved this problem by moving the line AppDomain.CurrentDomain.AssemblyResolve += MyAssemblyResolveHandler; to the static constructor of the IExternalCommand class.
Hope this solution may help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question This is a question and not an issue Runtime Issues related to loading pyRevit runtime [subsystem]
Projects
None yet
Development

No branches or pull requests

5 participants