Globals are not really global, in the sense that they're not shared across the entire application - only between multiple runs of the same type of rule. So it might be working in your Dashboard Extender because you're using it across multiple Dashboard Extenders (or other Dashboard-related types of rule, it's a bit more vague there).
Correctly estimating the lifecycle of a global can be tricky. In practice, they are typically used in two situations:
- Transformation/Parser rules. Since they have to execute for hundreds or thousands of rows on each Import, it makes sense to cache as much as you can in global objects (typically setup actions or lookups).
- Calculation rules. Again, these can be run hundreds or thousands of times with each consolidation, so it makes sense to reuse as much as you can between runs.
Now, back to your problem. Custom Calculations are not meant to return values, they are meant to save values to the database; so if you want something back, ExecuteCustomCalculationBusinessRule is the wrong approach.
What you want to do is to have your method as a separate Function in the business rule:
Namespace OneStream.BusinessRule.Finance.MyBR
Public Class MainClass
Public Function Main(ByVal si As SessionInfo, ByVal globals As BRGlobals, ByVal api As FinanceRulesApi, ByVal args As FinanceRulesArgs) As Object
[...]
End function
' add another function to the class
Public Function GetDataTable() as DataTable
' do your thang here
[...]
return myShinyDataTable
End Function
End Class
End Namespace
Now you can execute it from elsewhere (note: you will have to add "BR\MyBR" in the Referenced Assemblies property of this other rule):
Dim myBr as new OneStream.BusinessRule.Finance.MyBR.MainClass
Dim myDt as DataTable = myBr.GetDataTable()
Note that this doesn't stop you from using the function in the CustomCalculate section of the same rule, if necessary:
Case = FinanceFunctionType.CustomCalculate
Dim myDt = me.GetDataTable()
(You'll probably want your function to actually accept some parameters - particularly the SI object, which you will need pretty much all the time. Note that you don't have a valid api object in Dashboard contexts, so you can't use that.)
Last but not least: you probably don't want to put this sort of method, fetching random data, in Finance rules. It's literally the job for which Dashboard DataSet were invented. Among other benefits, you can execute DDS calls from Parameters or Data Adapter, which allow you to preview your dataset very easily as well as wiring it effortlessly to widgets. If you're not familiar with them, I strongly recommend to look them up (there is a decent intro on the blog, but look in the docs as well) and move your DT-fetching code there - again, you can still reference it from other rules, including Finance ones.
Hope this helps.