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

CNX-8397-DLL-Conflict-Handling in existing DUI2 connectors #3273

Merged
merged 14 commits into from
Apr 23, 2024

Conversation

connorivy
Copy link
Contributor

@connorivy connorivy commented Apr 9, 2024

Description & motivation

Changes:

Added DllConlfictManagement project

DllConflictManager

  • Detects conflicts between assemblies referenced by the connector and currently loaded assemblies in the app domain
    • I think we probably need to add this exception handling in more places. I currently only have it for the loading of the connector when Revit starts up

DllConflictUserNotifier

  • Handles any exceptions that occur, reference them with the conflictManager, and report them to the user. This is an abstract class that is expected to be implemented by the host app to use the host app specific way of notifying a user.

DllConflictManagmentOptions

  • Holds a list of dll conflicts that the user has elected to ignore
  • DllConflictManagmentOptionsLoader class will load these options from a json file in the same directory as the connector dll

RevitExternalApplication

  • Moved all types that are not either connector, System, or Revit types out of the "OnStartup" method.
    • This is because if there are conflicting dll types in this method, then an exception will be thrown before the method is even entered
    • By putting the other types in different methods, the type loading exception will be thrown on entering that method. Therefore we can alert the user about the exception

To-do before merge:

Questions to be answered (probably by @AlanRynne)

  • Where in appdata should I keep options.json file? Can this be the same for all c# connectors that use this?
  • Currently I'm only trying to catch typeLoadException and MissingMethodException. Are there others that will be thrown when dll mismatch occurs?
  • I'm only catching the above exceptions in the plugin initialization. I'm thinking we also want to catch these for the operations. Is this needed / is it okay to do?
  • How to log while detecting plugin conflicts? Should I prioritize logger dependencies and then move to connector dependencies?
  • I'm referencing the System.Text.Json nuget in the new project because it isn't built into .net standard. Should I reference a really new version or a really old version of this?

Screenshots:

Validation of changes:

Checklist:

  • My pull request follows the guidelines in the Contributing guide?
  • My pull request does not duplicate any other open Pull Requests for the same update/change?
  • My commits are related to the pull request and do not amend unrelated code or documentation.
  • My code follows a similar style to existing code.
  • I have added appropriate tests.
  • I have updated or added relevant documentation.

References

@connorivy connorivy requested a review from teocomi as a code owner April 9, 2024 20:52
@connorivy connorivy changed the title add conflict management project CNX-8397-DLL-Conflict-Handling in existing DUI2 connectors Apr 9, 2024
@connorivy connorivy requested review from AlanRynne and removed request for teocomi April 9, 2024 20:54
@connorivy connorivy marked this pull request as draft April 10, 2024 12:37
@connorivy connorivy marked this pull request as ready for review April 10, 2024 18:06
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Text.Json" Version="4.6.0" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to @BovineOx and my future self. We may want to consider using Speckle.Newtonsoft considering many more people will use System.Text.Json in varying versions

Copy link
Contributor

@BovineOx BovineOx Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ha, yeah that's interesting, because System.Text.Json is becoming the more mainstream package, though there are still gaps, but maybe so.

@AlanRynne AlanRynne self-requested a review April 12, 2024 08:51
Copy link
Member

@AlanRynne AlanRynne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been poking around this new feature in debug and I have a couple considerations:

  • When a user sees this pop-up, it is unclear what they are expected to do about it.
  • It is unclear what the consequences are of "not warning about this again"
  • The checkbox to not warn will apply to each conflict individually, but users can't individually choose which ones to ignore
  • From Matteo: We should have metrics on when does this pop-up get shown, how many conflicts we find or not, etc...

Further discussions may be needed.

Copy link
Member

@teocomi teocomi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was checking the data in MP:

  • the distinct_id should either be undefined or yours, but it has some other value
  • the allDetectedConflicts value should be a list of objects, but it's a list of strings
  • identifiedConflictingAssemblyName and some other props you're adding are null, not sure if this is correct?

image

@connorivy
Copy link
Contributor Author

@teocomi,

the distinct id's that you're probably seeing are when I was using a fallback value that didn't come from the accounts (you should know that I pulled this fallback value from the existing Analytics class, so this alternate distinct_id may be being used already). I have changed this and have hard-coded an id of "undefined" for the "lite" version of the analytics.

some system object types (System.Type, System.Reflection.AssemblyName, System.Reflection.Assembly) were throwing when attempting to be serialized so I just made a custom serialization to string. However, I have now implemented a data transfer object which has good serialization behavior, and I am sending that object instead of just a string.

identifiedConflictingAssemblyName can be null if a single conflict was not identified to be the culprit of a thrown exception. Is there a more clear way to handle this?

Here is an example of a couple events. The first is a "DllConflictsDetected" event and the second is a "DllConflictExceptionDialogShown" event

@BovineOx
Copy link
Contributor

I've been poking around this new feature in debug and I have a couple considerations:

  • When a user sees this pop-up, it is unclear what they are expected to do about it.
  • It is unclear what the consequences are of "not warning about this again"
  • The checkbox to not warn will apply to each conflict individually, but users can't individually choose which ones to ignore
  • From Matteo: We should have metrics on when does this pop-up get shown, how many conflicts we find or not, etc...

Further discussions may be needed.

For this we could have a blog post and a link to that.

@teocomi
Copy link
Member

teocomi commented Apr 23, 2024

For this we could have a blog post and a link to that.

There's already a docs page about dll conflicts, if you want to link to it we can add some more explanation about the dialog...

Copy link
Member

@AlanRynne AlanRynne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see much blockers. Just one class that should be in it's own file, and a question about the autodesk specific method

Comment on lines +69 to +73
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Design",
"CA1031:Do not catch general exception types",
Justification = "Catching all exceptions to avoid an unobserved exception that could crash the host app"
)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting... could we do something like IsFatal here (though not directly that as it would require referencing something else)

Comment on lines 57 to 66
private static string GetPathFromAutodeskOrFullPath(string fullPath)
{
string[] splitOnAutodesk = fullPath.Split(separator, StringSplitOptions.None);

if (splitOnAutodesk.Length == 2)
{
return splitOnAutodesk[1];
}
return fullPath;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autodesk specific? 🤔 Ideally this project should work on any connector. Not a deal breaker, just found it weird.

@AlanRynne AlanRynne self-requested a review April 23, 2024 17:02
Copy link
Member

@AlanRynne AlanRynne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're looking good! We should make a WIP to really test this in the wild (maybe ping some DPs and users we know have had conflicts in the past?)

@AlanRynne AlanRynne dismissed teocomi’s stale review April 23, 2024 17:03

My understanding is that Matteo has already given his blessing to this, though not officially through the PR. So I'm dismissing this to get it through

@AlanRynne AlanRynne merged commit 93dd518 into dev Apr 23, 2024
32 checks passed
@AlanRynne AlanRynne deleted the CNX-8397-DLL-Conflict-Handling branch April 23, 2024 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants