Raising ExternalEvent stops before Execute method

Raising ExternalEvent stops before Execute method

hzamani
Advocate Advocate
1,327 Views
9 Replies
Message 1 of 10

Raising ExternalEvent stops before Execute method

hzamani
Advocate
Advocate

Hi, I have an ExternalEvent which I'm raising from a Button_Click event handler. Pretty normal stuff. However, today for some reason when ExternalEvenet is raised Revit is refusing to go to Execute method. By that I mean when I debug and go line by line I can see that when the button is click and Result.Succeed is returned, then the event is raised, which is normal. It then goes to GetName method of my IExternalEventHandler, but after that it just finishes execution and the focus comes back to the Revit UI. It's quite weird as it was working properly a few days ago. 

Wondering what could possibly trigger this behaviour?

 

 I can see the ExternalEventRequest.Accepted is returned when my event is raised.

My Revit is 2019 and updated. What I have tried so far:

- Restarting Revit

- Restarting Visual Studio

- Creating a new event handler in VS

 

 

 

Cheers.

 

 

0 Likes
Accepted solutions (1)
1,328 Views
9 Replies
Replies (9)
Message 2 of 10

hzamani
Advocate
Advocate

I have been trying to isolate the problem and I'm getting some weird and at the same time interesting results.

 

So I found so far that when I comment out part of my Execute method, Revit actually does call the method! The part that I commented out was a second Transaction in my event handler. When I went line by line commenting out and uncommenting I can see the the Execute method will be called when my code looks like this:

 

                    using (Transaction t2 = new Transaction(doc, "Linking Site Model"))
                    {
                        t2.Start();
                        FilePath sitePath = new FilePath(@"C:\Users\hzamani\Desktop\New Template\SITE Mock Template.rvt");
                        RevitLinkOptions revitLinkOptions = new RevitLinkOptions(false);
                        //RevitLinkLoadResult revitLinkType = RevitLinkType.Create(doc, sitePath, revitLinkOptions);
                        //RevitLinkInstance revitLinkInstance = RevitLinkInstance.Create(doc, revitLinkType.ElementId);

                        t2.Commit();
                    }

But as soon as I uncomment the two lines which are commented out, the Execute method is not called!

 

Does anyone have any explanation to why this is happening? 

0 Likes
Message 3 of 10

cwaluga
Advocate
Advocate

Most probably an exception is thrown in the first command. You could use Exception monitoring in Visual Studio or add try and catch to check what Revit is complaining about.

0 Likes
Message 4 of 10

hzamani
Advocate
Advocate

I do have encapsulated all my code in a try catch block. No exception is thrown. Revit just simply returns to the UI with no action.

0 Likes
Message 5 of 10

cwaluga
Advocate
Advocate
Not sure, but I think Revit catches Exceptions that occur during command invokation. Also, command invokation is always asynchronous. In that case your outer catch block will never catch anything.
0 Likes
Message 6 of 10

hzamani
Advocate
Advocate
Accepted solution

Turned out it was a junior mistake. I had referenced RevitAPI.dll from Revit 2017 and was testing on Revit 2019. The class name RevitLinkLoadResult has been renamed to LinkLoadResult since Revit 2018, hence not existing in Revit 2019 as well. Because Revit couldn't find the class name it wasn't calling the method which had used this class name.  

0 Likes
Message 7 of 10

Anonymous
Not applicable

I too have this problem now. 
The wierd thing is that sometimes it works and sometimes it doesnt. 
I have wrapped the entire Execute-method in a try catch block and I've set a breakpoint at the first line in the method, but nothing. 

 

Is there any way of figuring out what is wrong?

0 Likes
Message 8 of 10

Anonymous
Not applicable

I have now commented out the entire Execute-method without any success. It doesnt read the name of the External Event or Invoke the Execute method… 

0 Likes
Message 9 of 10

zhuliyi0
Enthusiast
Enthusiast

I encountered this issue when using addin manager. It turns out the Execute() method will be skipped if any assembly directly referenced by the method is missing. Addin Manager is supposed to find all the dlls inside the executing directory, and load them all, but for some unknown reason, sometimes it fails to load some dlls. When the code is running inside an external command or external event, there will be "Could not load file or assembly or one of its dependencies" exception thrown. However, if the Execute() method directly calls some missing assembly, there will be no exception thrown, and Revit will just silently continue.

 

My solution: before every external event is raised, register to AppDomain.AssemblyResolve event, and handle the event by manully specify the dll file inside executing directory. Now the execute() method no longer skips. This also solves all the "Could not load file" errors if assembly resolve event is handled during the whole execution. I unregister it after execute method is finished.

 

Havn't done lots of testing though. 

 

And here is my simple class for register and handling seembly resolve event:

 

public static class AssemblyLoader
{
private static bool registered = false;
public static void Register(bool _register)
{
if (_register == registered)
return;
if (_register)
AppDomain.CurrentDomain.AssemblyResolve += onAssemblyResolve;
else
AppDomain.CurrentDomain.AssemblyResolve -= onAssemblyResolve;

registered = _register;
}

private static Assembly onAssemblyResolve(object sender, ResolveEventArgs args)
{
var name = args.Name;
name = name.SplitBy(",").First();
var fullName = args.RequestingAssembly.FullName;
string path = args.RequestingAssembly.Location;
path = Path.GetDirectoryName(path);
path += "\\" + name + ".dll";
var a = Assembly.LoadFrom(path);
return a;
}
}

0 Likes
Message 10 of 10

zhuliyi0
Enthusiast
Enthusiast

Found one bug:

 

Assembly.LoadFrom => Assembly.LoadFile

 

.LoadFrom will load old version dll in app domain, while .LoadFile will differenciate dll version and actual content.

 

Seems I no longer need to change version number, that's great.

0 Likes