Current filter:
                                You should refresh the page.
                                  • Having followed various support tickets in relation to exporting reports ( V2) programmatically I was able to use the sample in
                                    T275059/how-to-create-and-setup-an-xtrareport-report-for-exporting-to-a-stream-in-a-non-xaf to create and export reports in a workflow using the InvokeMethod activity and return a stream to pass to a custom SMTP email activity.
                                    The reports actually worked and emails were sent on the first attempt amazingly enough however after a number of reports ( approx. 100) were generated they stopped.
                                    My initial reaction was to assume memory leaks with all the streaming however when I examined the Workflow history I found this error in the execution log.

                                    [C#]
                                    Fault info: Activity: InvokeMethod Exception Message: Unable to open database. Connection string: 'Server= tcp:*********;Database= *******;User ID=**********;Password=***REMOVED***;Trusted_Connection= False;Encrypt= True;Connection Timeout= 30;'; Error: 'System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection) at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions) at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions) at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)

                                    From looking at other Pooling related tickets I know now that each time the workflow runs a new ObjectSpaceProvider is created taking a connection from the pool however I don't know anyway to recycle the handle to the provider within the context of the WorkflowServer service. Should the code be explicitly disposing of the helper objects after each run?
                                    Its a pity we cant use the ObjectSpace from the Workflow application to create the reports as the current approach seems to be a bit of a heavyweight operation anyhow.
                                    I wonder if there could be any recommended alternative approach that can be tried.
                                    Many thanks in advance
                                    Brian

                                • Uriah (DevExpress Support) 08.30.2019

                                  Hello Brian,

                                  We need additional time to answer your question. Please bear with us. We will get back to you as soon as possible.

                                1 Solution

                                Creation Date Importance Sort by

                                Hello Brian,

                                Its a pity we cant use the ObjectSpace from the Workflow application to create the reports as the current approach seems to be a bit of a heavyweight operation anyhow.

                                It is possible to pass an IObjectSpace instance created in ObjectSpaceTransactionScope to an InvokeMethod activity. Use the TransactionalGetObjectSpace activity to retrieve an IObjectSpace instance and save it to a local variable.

                                However, you still need access to an XAF Application instance because it is necessary to call the ReportDataSourceHelper.SetupBeforePrint method. To overcome this difficulty, save an XafApplication instance in a static property. You can use the Value Manager class to make sure that different XafApplication instances do not overwrite each other.

                                [C#]
                                public sealed partial class DxSampleModule : ModuleBase { public static XafApplication Instance { get { IValueManager<XafApplication> valueManager = ValueManager.GetValueManager<XafApplication>("DxSampleInstance"); if (valueManager.CanManageValue) return valueManager.Value; return null; } set { IValueManager<XafApplication> valueManager = ValueManager.GetValueManager<XafApplication>("DxSampleInstance"); if (valueManager.CanManageValue) valueManager.Value = value; } } public static Stream ExportInvoiceReport(Guid invoiceId) { if (Instance == null) throw new UserFriendlyException("An XafApplication instance is not assigned"); ReportsModuleV2 module = ReportsModuleV2.FindReportsModule(Instance.Modules); if (module == null) throw new UserFriendlyException("PrintOrdersReport: Cannot find Reports Module"); if (module.ReportsDataSourceHelper == null) throw new UserFriendlyException("PrintOrdersReport: Reports Data Source Helper is not initialized"); using (IObjectSpace objectSpace = ReportDataProvider.ReportObjectSpaceProvider.CreateObjectSpace(module.ReportDataType)) { CriteriaOperator filter = CriteriaOperator.Parse("[DisplayName] = ?", "InvoiceReport"); IReportDataV2 reportData = (IReportDataV2)objectSpace.FindObject(module.ReportDataType, filter); if (reportData == null) throw new UserFriendlyException("PrintOrdersReport: Cannot find Report Data"); XtraReport report = ReportDataProvider.ReportsStorage.LoadReport(reportData); CriteriaOperator reportFilter = CriteriaOperator.Parse("[Oid] = ?", invoiceId); module.ReportsDataSourceHelper.SetupBeforePrint(report, null, reportFilter, true, new SortProperty[0], false); Stream stream = new MemoryStream(); report.ExportToImage(stream); stream.Position = 0; return stream; } }

                                In the Workflow Service application, add ReportsModuleV2 to the server application and initialize your static property.

                                [C#]
                                serverApplication.Modules.Add(new ReportsModuleV2()); DxSampleModule module = new DxSampleModule(); DxSampleModule.Instance = serverApplication; serverApplication.Modules.Add(module);
                                • brainscan 09.02.2019

                                  Hello Uriah

                                  This works like a charm! Thanks very taking the time to research this and providing a very straightforward implementation.
                                  Excellent support from DevExpress!

                                  Brian Scannell

                                • Uriah (DevExpress Support) 09.03.2019

                                  You are welcome, Brian!