Showing posts with label SSRS. Show all posts
Showing posts with label SSRS. Show all posts

Thursday, January 10, 2019

Merge a report exported into PDF with other PDF files

This is an example on how to alter the PDF created from a SSRS report with other PDF files (such as the ones attached as document attachments).

To be able to do this, we will need to download and install the PDFSharp library, which is an open source library to create or modify PDF files. First, download from www.pdfSharp.com, the extract the PdfSharp.dll and copy it to the bin folder of the model folder which you want to do the modification on. Second, from the Visual Studio, right click on the project, and add a reference into the .dll file.

As for the modification itself, we will need to override this delegate: SRSPrintDestinationSettingsDelegates.toSendFile() and make sure to set the result on the EventHandlerResult to false. This way, after calling the delegate, it will not continue with the rest of the codes in SrsReportRunPrinter.toFile(), which is going to save the report PDF file into the Azure storage or send it to the user.

The sample codes would look like this:

 using PdfSharp;  
 using Microsoft.Dynamics.ApplicationPlatform.SSRSReportRuntime.Instrumentation;  
 class SRSPrintDestinationSettingsDelegates_EventHandler  
 {  
   #SRSFramework  
   private static void saveFile(System.Byte[] reportBytes, SrsReportRunPrinter printer, SrsReportDataContract dataContract)  
   {  
     SRSPrintDestinationSettings printSettings = dataContract.parmPrintSettings();  
     //SRSReportFileFormat fileFormat = printSettings.fileFormat();  
     Filename filename = "";  
     if(printSettings.fileName())  
     {  
       filename = printSettings.fileName();  
     }  
     else  
     {  
       filename = dataContract.parmReportCaption() ? dataContract.parmReportCaption() + ".pdf" : dataContract.parmReportName() + ".pdf";  
     }  
     if (reportBytes)  
     {  
       System.IO.MemoryStream stream = new System.IO.MemoryStream(reportBytes);  
       // Send file to browser for on premise scenario.  
       if(SrsReportRunUtil::isOnPremEnvironment())  
       {  
         Dynamics.AX.Application.File::SendFileToUser(stream, filename);  
         SSRSReportRuntimeEventSource::EventWriteRenderReportToFileTaskStop(  
             "Printing report to file ended.",  
             dataContract.parmReportExecutionInfo().parmReportRunId());  
         return;  
       }  
       // Upload file to temp storage and direct the browser to the file URL  
       SrsFileUploadNameContract fileNameContract = new SrsFileUploadNameContract();  
       fileNameContract.FileName(filename);  
       str categoryName = SrsReportRunUtil::convertAndTrimGuidValue(dataContract.parmReportExecutionInfo().parmReportRunId());  
       fileNameContract.CategoryName(categoryName);  
       SRSFileUploadTempStorageStrategy fileUploader = new SRSFileUploadTempStorageStrategy();  
       fileUploader.uploadFile(stream, FormJsonSerializer::serializeClass(fileNameContract));  
       // Set global cache that indicates there is file uploaded for current report execution.  
       // Using SGC not SGOC because we want scope to be in current user session.  
       // Owner - #RunIdOwner macro, Key - RunId, Value - boolean value.  
       SysGlobalCache globalCache = classfactory.globalCache();  
       if(!globalCache.isSet(#RunIdOwner, dataContract.parmReportExecutionInfo().parmReportRunId()))  
       {  
         globalCache.set(#RunIdOwner, dataContract.parmReportExecutionInfo().parmReportRunId(), true);  
       }  
     }  
     SSRSReportRuntimeEventSource::EventWriteRenderReportToFileTaskStop(  
         "Printing report to file ended.",  
         dataContract.parmReportExecutionInfo().parmReportRunId());  
   }  
   [SubscribesTo(classStr(SRSPrintDestinationSettingsDelegates), delegateStr(SRSPrintDestinationSettingsDelegates, toSendFile))]  
   public static void SRSPrintDestinationSettingsDelegates_toSendFile(System.Byte[] reportBytes, SrsReportRunPrinter printer, SrsReportDataContract dataContract, Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[] paramArray, EventHandlerResult result)  
   {  
     Pdf.PdfDocument       outputPDFDocument = new Pdf.PdfDocument();  
     System.IO.MemoryStream   memoryStream = new System.IO.MemoryStream(reportBytes);  
     System.IO.MemoryStream   mergedStream = new System.IO.MemoryStream();  
     boolean           isOutputModified;  
     SRSPrintDestinationSettings printSettings = dataContract.parmPrintSettings();  
     System.Byte[]        finalReportBytes = reportBytes;  
     void addStream(System.IO.MemoryStream _stream, Pdf.PdfDocument _outputPDFDocument)  
     {  
       Pdf.PdfDocument inputPDFDocument = new Pdf.PdfDocument();  
       int       pageCount;  
       Pdf.PdfPages  pdfPages;  
       inputPDFDocument = PdfSharp.Pdf.IO.PdfReader::Open(_stream, PdfSharp.Pdf.IO.PdfDocumentOpenMode::Import);  
       _outputPDFDocument.set_Version(inputPDFDocument.get_Version());  
       pageCount = inputPDFDocument.get_PageCount();  
       pdfPages = inputPDFDocument.get_Pages();  
       if (pageCount > 0)  
       {  
         for (int idx = 0; idx < pageCount; idx++)  
         {  
           _outputPDFDocument.AddPage(pdfPages.get_Item(idx));  
         }  
       }  
     }  
     if (printSettings.fileFormat() == SRSReportFileFormat::PDF && dataContract.parmRdpName() == classStr(SalesInvoiceDP))  
     {  
       SalesInvoiceContract  salesInvoiceContract = dataContract.parmRdpContract();  
       DocuRef            docuRef;  
       int                 attachmentCounter;  
       try  
       {  
         new InteropPermission(InteropKind::ClrInterop).assert();  
         while select docuRef //add some criteria here  
         {  
           if (docuRef.fileType() == 'pdf')  
           {  
             if (!attachmentCounter)  
             {  
               addStream(memoryStream, outputPDFDocument);  
             }  
             System.IO.Stream docuStream = DocumentManagement::getAttachmentStream(docuRef);  
             memoryStream = new System.IO.MemoryStream();  
             docuStream.CopyTo(memoryStream);  
             addStream(memoryStream, outputPDFDocument);  
             attachmentCounter++;  
           }  
         }  
         if (attachmentCounter)  
         {  
           outputPDFDocument.Save(mergedStream, false);  
           finalReportBytes = mergedStream.ToArray();  
           result.result(false); //this is to force the SrsReportRunPrinter.toFile NOT to continue after calling this delegate  
           isOutputModified = true;  
         }  
         CodeAccessPermission::revertAssert();  
       }  
       catch(Exception::CLRError)  
       {  
         str errorMessage = AifUtil::getClrErrorMessage();  
         CodeAccessPermission::revertAssert();  
         throw error(errorMessage);  
       }  
     }  
     if (isOutputModified && finalReportBytes)  
     {  
       SRSPrintDestinationSettingsDelegates_EventHandler::saveFile(finalReportBytes, printer, dataContract);  
     }  
   }  
 }  

Wednesday, January 16, 2013

Intermittent SSRS report error: System.Security.Permissions.EnvironmentPermission when running reports for the first time

Just today I had an issue with Dynamics AX 2012 SSRS report when running reports for the first time. It sometimes came up with this error:
"The DefaultValue expression for the report parameter ‘AX_CompanyName’ contains an error: Request for the permission of type 'System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed. (rsRuntimeErrorInExpression)"

Then I've found a helpful blog that seems to explain the same issue in http://blogs.msdn.com/b/axsupport/archive/2012/02/02/microsoft-dynamics-ax-2012-reporting-extensions-error-system-security-permissions-environmentpermission-while-running-report.aspx

So basically I need to make some changes in the rssrvpolicy.config to change the permission set name from Execution to FullTrust and then restart the SSRS service.

You can find the rssrvpolicy.config file in:


  • If you are using SQL Server 2008, the default location of this file is: \Program Files\Microsoft SQL Server\MSRS10.[SSRSInstanceName]\Reporting Services\ReportServer
  • If you are using SQL Server 2008 R2, the default location of this file is: \Program Files\Microsoft SQL Server\MSRS10_50.[SSRSInstanceName]\Reporting Services\ReportServer
  • If you are using SQL Server 2012, the default location of this file is: \Program Files\Microsoft SQL Server\MSRS11.[SSRSInstanceName]\Reporting Services\ReportServer



<CodeGroup
class="UnionCodeGroup"
version="1"
PermissionSetName="FullTrust"
Name="Report_Expressions_Default_Permissions"
Description="This code group grants default permissions for code in report expressions and Code element. ">