delegateas/Daxif

Plugin Registration Setup

Closed this issue · 5 comments

Hi,

I've been looking at your automatic plugin registrations and got a question.
According to MS best practices a plugin should be stateless. The only state a plugin can obtain is defined by the configuration parameters in the ctor. See quote.

For improved performance, Microsoft Dynamics 365 caches plug-in instances. The plug-in's Execute method should be written to be stateless because the constructor is not called for every invocation of the plug-in. Also, multiple system threads could execute the plug-in at the same time. All per invocation state information is stored in the context, so you should not use global variables or attempt to store any data in member variables for use during the next plug-in invocation unless that data was obtained from the configuration parameter provided to the constructor. Changes to a plug-ins registration will cause the plug-in to be re-initialized.

The plugin registrations are stored in a global collection on the ExtendedPlugin thus the use of state.
Is there any idea behind it why it was done this way? Wouldn't Attributes be a better use? Plugin registrations are basicly metadata and in a way 'static'. No need to rebuild the RegisteredEvents every time the plugin is instanced.

I can see why it's possible to get confused. The RegisterPluginStep function is called, but not used, when the plugin is run by CRM.
This function makes it easier for DAXIF to get the registrations with reflection when you want to register your plugins. So the result of the RegisterPluginStep function is only used when the DAXIF script PluginSyncDev is called, which calls Plugin.Sync

Thanks for the quick feedback.

I understand the PluginStepConfigs are only used by the PluginSyncDev and has no impact during the plugin execution.
I just noticed there were 2 collections built by the RegisterPluginStep function: RegisteredEvents & PluginStepConfigs.
The RegisteredEvents are used at invocation (Execute) of the plugin which in a way violates the best practice since RegisteredEvents is defined as a global variable and keeps state.

I'd like to start using this tooling but would also like to know the reasoning behind this design choice since MS discourages keeping state in a plugin.

That is correct that the global collection RegisteredEvents is used in execution. Awesome that you looked into the code and found that. We had completely forgotten about that detail. However, we don't believe it is an issue.

The reason we have added RegisteredEvents is to be able to define different execute methods in the same class. This enables us to collect related plugins in the same class instead of splitting them up in multiple classes. Thereby making refactoring much easier and making it easier to see how plugins are related.

This design choice will not cause any problems even though it goes against Microsofts advice, Microsoft discourage the use of global variable as we can not reliably store data in global variables and use it in any following plugin executions.
In this case, the RegisteredEvents is created in the constructor and is only based on static data defined in the constructor. The RegisteredEvents collection is never modified afterwards or between plugin executions and the content will therefore always be the same, no matter if the plugin is created a new or if a cached version is used.

We hope that the answer is satisyfable and that you are still interested in using our tool.

Basically, RegisteredEvents holds static metadata that is only set in the constructor. It does not keep a "state" which is changed in invocations of Execute, so it adheres to the MS description.

Besides, the RegisteredEvents part is actually taken directly from MS. The Daxif base plugin class is an expanded version of the base plugin class generated by the CRM Developer Toolkit, and the RegisteredEvents has been kept intact to provide compatibility with it. An example of a plugin written for the Toolkit can be found in this blogpost (search for "RegisteredEvents")

Thanks all for the feedback.

I can relate to these answers.