Add a new class to your project and have it inherit from Umbraco.Forms.Core.ExportType. You have two options when implementing the class, as shown in the following examples.
Basic Example
You can implement the method public override string ExportRecords(RecordExportFilter filter) in your export provider class. You need to return a string you wish to write to a file. For example, you can generate a .csv (comma-separated values) file. You would perform your logic to build up a comma-separated string in the ExportRecords method.
In the constructor of your provider, you will need a further two properties, FileExtension and Icon.
FileExtension is the extension such as zip, txt or csv of the file you will be generating and serving from the file system.
In this example below we will create a single HTML file which takes all the submissions/entries to be displayed as a HTML report. We will do this in conjunction with a Razor partial view to help build up our HTML and thus merge it with the form submission data to generate a string of HTML.
Provider Class
usingSystem;usingUmbraco.Cms.Core.Hosting;usingUmbraco.Forms.Core;usingUmbraco.Forms.Core.Models;usingUmbraco.Forms.Core.Searchers;usingUmbraco.Forms.Web.Helpers;namespaceMyFormsExtensions{publicclassExportToHtml:ExportType {privatereadonlyIHttpContextAccessor _httpContextAccessor;privatereadonlyIFormRecordSearcher _formRecordSearcher;publicExportToHtml(IHostEnvironment hostEnvironment,IHttpContextAccessor httpContextAccessor,IFormRecordSearcher formRecordSearcher): base(hostEnvironment) { _httpContextAccessor = httpContextAccessor; _formRecordSearcher = formRecordSearcher; Name ="Export as HTML"; Description ="Export entries as a single HTML report"; Id =newGuid("4117D352-FB41-4A4C-96F5-F6EF35B384D2"); FileExtension ="html"; Icon ="icon-article"; }publicoverridestringExportRecords(RecordExportFilter filter) {var view ="~/Views/Partials/Forms/Export/html-report.cshtml";EntrySearchResultCollection model =_formRecordSearcher.QueryDataBase(filter);returnViewHelper.RenderPartialViewToString(_httpContextAccessor.GetRequiredHttpContext(), view, model); } }}
Razor Partial View
@model Umbraco.Forms.Core.Searchers.EntrySearchResultCollection@{var submissions =Model.Results.ToList();var schemaItems =Model.Schema.ToList();}<h1>Form Submissions</h1>@foreach (var submission in submissions){var values =submission.Fields.ToList();for (int i =0; i <schemaItems.Count; i++) {<strong>@schemaItems[i].Name</strong>@values[i].Value<br /> }<hr />}
This approach gives us more flexibility in creating the file we wish to serve as the exported file. We do this for the export to Excel file export provider we ship in Umbraco Forms. With this we can use a library to create the Excel file and store it in a temporary location before we send back the filepath for the browser to stream down the export file.
In this example we will create a collection of text files, one for each submission which is then zipped up into a single file and served as the export file.
usingSystem;usingSystem.IO;usingSystem.IO.Compression;usingSystem.Linq;usingUmbraco.Cms.Core.Hosting;usingUmbraco.Forms.Core;usingUmbraco.Forms.Core.Models;usingUmbraco.Forms.Core.Searchers;namespaceMyFormsExtensions{publicclassExportToTextFiles:ExportType {privatereadonlyIFormRecordSearcher _formRecordSearcher;publicExportToTextFiles(IHostingEnvironment hostingEnvironment,IFormRecordSearcher formRecordSearcher): base(hostingEnvironment) { _formRecordSearcher = formRecordSearcher;this.Name="Export as text files";this.Description="Export entries as text files inside a zip file";this.Id=newGuid("171CABC9-2207-4575-83D5-2A77E824D5DB");this.FileExtension="zip";this.Icon="icon-zip"; } /// <summary> /// We do not implement this method from the interface /// As this method is called from ExportToFile that we also override here & is expecting the file contents as a string to be written as a stream to a file /// Which would be OK if we were creating a CSV or a single based file that can have a simple string written as a string such as one large HTML report or XML file perhaps /// </summary>publicoverridestringExportRecords(RecordExportFilter filter) =>thrownewNotImplementedException(); /// <summary> /// This gives us greater control of the export process /// </summary> /// <paramname="filter"> /// This filter contains the date range & other search parameters to limit the entries we are exporting /// </param> /// <paramname="filepath"> /// The filepath that the export file is expecting to be served from /// So ensure that the zip of text files is saved at this location /// </param> /// <returns>The final file path to serve up as the export - this is unlikely to change through the export logic</returns>publicoverridestringExportToFile(RecordExportFilter filter,string filepath) { // Before Save - Check Path, Directory & Previous File export does not existstring pathToSaveZipFile = filepath; // Check our path does not contain \\ // If not, use the filePathif (filepath.Contains('\\') ==false) { pathToSaveZipFile =HostingEnvironment.MapPathContentRoot(filepath); } // Get the directory (strip out \\ if it exists)var dir =filepath.Substring(0,filepath.LastIndexOf('\\'));var tempFileDir =Path.Combine(dir,"text-files"); // If the path does not end with our file extension, ensure it's addedif (pathToSaveZipFile.EndsWith("."+ FileExtension) ==false) { pathToSaveZipFile +="."+ FileExtension; } // Check that the directory where we will save the ZIP file temporarily exists // If not just create itif (Directory.Exists(tempFileDir) ==false) {Directory.CreateDirectory(tempFileDir); } // Check if the zip file exists already - if so delete it, as we have a new updateif (File.Exists(pathToSaveZipFile)) {File.Delete(pathToSaveZipFile); } // Query the DB for submissions to export based on the filterEntrySearchResultCollection submissions =_formRecordSearcher.QueryDataBase(filter); // Get the schema objects to a list so we can get items using position indexvar schemaItems =submissions.schema.ToList(); // We will use this to store our contents of our file to save as a text filevar fileContents =string.Empty; // For each submission we have build up a string to save to a text fileforeach (EntrySearchResult submission insubmissions.Results) { // The submitted data for the form submissionvar submissionData =submission.Fields.ToList(); // For loop to match the schema position to the submission datafor (int i =0; i <schemaItems.Count; i++) { // Concat a string of the name of the field & its stored data fileContents +=schemaItems[i].Name+": "+submissionData[i] +Environment.NewLine; } // Now save the contents to a text file // Base it on the format of the record submission unique idvar textFileName =Path.Combine(tempFileDir,submission.UniqueId+".txt");File.WriteAllText(textFileName, fileContents); // Reset fileContents to be empty again fileContents =string.Empty; } // Now we have a temp folder full of text files // Generate a zip file containing them & save thatZipFile.CreateFromDirectory(tempFileDir, pathToSaveZipFile); // Tidy up after ourselves & delete the temp folder of text filesif (Directory.Exists(tempFileDir)) {Directory.Delete(tempFileDir,true); } // Return the path where we saved the zip file containing the text filesreturn pathToSaveZipFile; } }}