Ticket T810806
Visible to All Users

How to export an XAF report in a Workflow Activity

created 6 years ago

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

Comments (1)
DevExpress Support Team 5 years ago

    Hello Brian,

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

    Answers approved by DevExpress Support

    created 5 years ago (modified 5 years ago)

    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);
      Comments (2)

        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

        DevExpress Support Team 5 years ago

          You are welcome, Brian!

          Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

          Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.