I have developed a custom external extension/add-in in ArcGIS Pro 2.9 that is available in the Licensing section. I have a number of days until the extension (add-in) will time out. However, I don't have an ideal way to track the count down of days and ultimately lock down the code for the extension when the license expires. Is there an event that I can key off of that runs in the background, like the button OnUpdate event? I could tie into this event and then know when the number of licensing days has expired and I can disable the extension. I would use the button OnUpdate event, but as far as I can tell that requires that the tab that the button is located on to be active for the event to fire. I need something to key off of that would execute all the time that the application is running.
Please let me know if any further information is required.
Solved! Go to Solution.
That will work for sure, but as an optimization i would check the licensing only once at startup and return the time span left before the license expires. Using the returned timespan i would then set the duration for one single timer event. This is a bit more optimized compared to calling your license checking code every second. Using DispatchTimer as compared to Timer will work fine, it will ensure that your event code runs on the UI thread.
Your Module class implementation is a singleton and hence should be home of your license time out code (just add your code in the Module class constructor). By default, the Module class is executed just-in-time (JIT) when a user is using the add-in or the class is always instantiated when Pro starts up, if the 'autoLoad' attribute in the 'insertModule' tag is set to 'true' in the config.daml (see: ProConcepts Framework · Esri/arcgis-pro-sdk Wiki (github.com))
Also there's some information about ArcGIS Pro Add-in licensing - maybe not applicable for your use case:
ProGuide License Your Add in · Esri/arcgis-pro-sdk Wiki (github.com)
Wolf,
I have already done everything that you suggested regarding the Module class. I also have 'autoLoad' set to true in the config.daml. I followed all of the directions in the configurable extensions section of the link that you included. Unfortunately, however, that only helps me when Pro starts up (as you mentioned). I need to be able to track when the license expires while Pro is still running. The user may not shut the application down and just leave it running past the license timeout. This is why I need to tie into some kind of event that is always polling like the button OnUpdate. Is there anything that I can do like that?
Understood. In the Module class startup just check how much time is left and set a timer event using the time left. When the time is up disable your state/condition for the UI.
In the Module class you define the timer in the ctor i just one minute in my snippet:
public Module1()
{
// set Timer ...
var timer = new System.Timers.Timer(60000); // set milliseconds delay
timer.Elapsed += Timer_Elapsed;
timer.Start();
//activates the state
FrameworkApplication.State.Activate(timerStateId);
}
private static string timerStateId = "timer_state";
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (FrameworkApplication.State.Contains(timerStateId))
{
//deactivates the state
FrameworkApplication.State.Deactivate(timerStateId);
}
else
{
//activates the state
FrameworkApplication.State.Activate(timerStateId);
}
}
Define the state in config.daml under the conditions tag and add the condition attribute to your UI element like buttons, groups, tools:
...
</AddInInfo>
<conditions>
<!-- our custom condition -->
<insertCondition id="timer_state_condition" caption="Timer state">
<!-- our condition is set true or false based on this underlying state -->
<state id="timer_state" />
</insertCondition>
</conditions>
<modules>
...
<tool id="MapT..."
condition="timer_state_condition">
...
Wolf,
The following is the timer code that I came up with, which seems to work. I didn't see that you had included a snippet until just now. I placed this in my Module (Module1). It calls a method called "CheckLicensing" which does all of the condition checking and a little bit more. The timeout is 1 second at the moment, but that can certainly be changed to every minute, hour, or whatever. Is this sufficient?
private DispatcherTimer _licenseTimer = null;
private void LicenseTimer_Tick(object sender, EventArgs e)
{
if (Current.State == ExtensionState.Enabled)
{
CheckLicensing(false);
}
}
protected override bool Initialize()
{
_licenseTimer = new DispatcherTimer();
_licenseTimer.Tick += new EventHandler(LicenseTimer_Tick);
_licenseTimer.Interval = new TimeSpan(0, 0, 1);
_licenseTimer.Start();
return true;
}
protected override void Uninitialize()
{
base.Uninitialize();
if (_licenseTimer != null) { _licenseTimer.Stop(); }
}
That will work for sure, but as an optimization i would check the licensing only once at startup and return the time span left before the license expires. Using the returned timespan i would then set the duration for one single timer event. This is a bit more optimized compared to calling your license checking code every second. Using DispatchTimer as compared to Timer will work fine, it will ensure that your event code runs on the UI thread.
Wolf,
I am not sure that I am getting what you are suggesting. Could you include a snippet? I would really appreciate it. Thank you.
You have two scenarios:
1) your add-in starts and the license is already timed out, hence you disable your add-in features
2) your add-in starts and the license will expire in x minutes after startup. Use the x minutes to setup your single timer event and when the event occurs you disable your add-in features.