Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Matthieu Nelmes 102 posts 385 karma points
    Nov 11, 2015 @ 17:26
    Matthieu Nelmes
    0

    Exporting CSV from BackOffice (non usercontrol)

    The decision to try a non usercontrol approach was because I've managed to create a custom property editor that renders a list-view. So I wanted to stick with my angular/MVC approach.

    Struggling to see how I can force download as it seems the UmbracoAuthorizedApiController only returns Json so I'm open to suggestions.

    [Umbraco.Web.Mvc.PluginController("My.Admin")]
    public class RoomListExportApiController : UmbracoAuthorizedApiController
    {
        [System.Web.Http.AcceptVerbs("GET", "POST")]
        [System.Web.Http.HttpGet]
        public FileContentResult DownloadCsv()
        {
            string csv = "test,test1,test2";
            FileContentResult result = new FileContentResult(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv");
            return result;
        }
        }
    

    This only returns Json. I guess I could use a plain old SurfaceController but wouldn't this compromise security?

  • Matthieu Nelmes 102 posts 385 karma points
    Nov 11, 2015 @ 18:39
    Matthieu Nelmes
    0

    Found a solution! A well written tutorial here was exactly what I was looking for!

    http://umbracodevelopers.sdesign1dev.co.uk/2015/7/30/ajax-newsletter-sign-up/

  • Taylor Mitchell 19 posts 43 karma points
    Nov 16, 2015 @ 22:16
    Taylor Mitchell
    2

    This may be old, but this is how I solved it:

    I created an export button with angular with exportForms as the action

    exportForms: function(type) {
                return $http.post("backoffice/MySection/ExportAction/export");
            }
    

    I then built an authorization handler. Just something simple to check if the user was logged in

    public class AuthorizationHandler
    {
        public static bool UserLoggedIn()
        {
            var httpCtxWrapper = new HttpContextWrapper(HttpContext.Current);
            var umbTicket = httpCtxWrapper.GetUmbracoAuthTicket();
            if (umbTicket == null || umbTicket.Name.IsEmpty() || umbTicket.Expired)
                return false;
            return true;
        }
    }
    

    Then I built a surface controller which throws an unauthorized if someone is not logged in.

    public class ExportActionsController : SurfaceController
    {
        public ActionResult Export(string type)
        {
            if (AuthorizationHandler.UserLoggedIn())
            {
                var query = //my sql statement here
                var forms = DatabaseContext.Database.Fetch<dynamic>(query);
    
                ExcelService.ExportForm(forms, type);
    
                if (HttpContext.Request.UrlReferrer != null)
                {
                    return Redirect(HttpContext.Request.UrlReferrer.AbsoluteUri);
                }
                return Redirect("/#/MySection");
            }
            else
            {
                throw new HttpException(401, "Unauthorized access");
            }
        }
    }
    

    Then I had to handle the exporting. I like to use closedXML.

    I'm modifying this code a bit because my original is a bit more complex.

        public class ExcelService
       {
           public static void ExportForm<T>(IEnumerable<T> forms, string filename)
          {
            XLWorkbook wb = new XLWorkbook();
    
            //this handles exporting my data into a datatable. You have to build this yourself.
            DataTable dt = ToDataTable(forms.ToList());
    
            //adds a worksheet with the data and the filename is the sheet name
            wb.Worksheets.Add(dt, filename);
    
            //This handles the download.
            HttpResponse httpResponse = HttpContext.Current.Response;
            httpResponse.Clear();
    
            //tell it the content type
            httpResponse.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    
            //give it your filename
            httpResponse.AddHeader("content-disposition", "attachment;filename=\"" + filename + " " + DateTime.Now.ToShortDateString() + ".xlsx\"");
    
            MemoryStream memoryStream = new MemoryStream();
    
            //save the workbook as a memory stream
            wb.SaveAs(memoryStream);
    
            //write file to users computer
            memoryStream.WriteTo(httpResponse.OutputStream);
    
            //never forget to close the stream and the response
            memoryStream.Close();
    
            httpResponse.End();
           }
        }
    

    Hope that helps

  • Biagio Paruolo 1619 posts 1912 karma points c-trib
    Dec 02, 2015 @ 15:04
    Biagio Paruolo
    0

    like

  • Matthieu Nelmes 102 posts 385 karma points
    Nov 16, 2015 @ 23:22
    Matthieu Nelmes
    0

    Thanks Taylor, I'll take a look.

    I did get a version working with some AngularJs magic but it's always worth exploring other options!

  • Michele Di Maria 34 posts 239 karma points
    Mar 30, 2021 @ 14:43
    Michele Di Maria
    1

    Thank you @Taylor Mitchell !!

    For Umbraco 8 things are a little different, but your reply was a very good starting point.

    The button in the html file changes to a simple link:

    <umb-button type="link"
        button-style="link"
        label="Scarica PDF"                            
        href="/umbraco/surface/BackofficeDownload/DownloadPDF?ID={{model.dialogData.IDData}}">
    </umb-button>
    

    Then the controller changes to:

    namespace XXX.Controllers
    {
        public class BackofficeDownloadController : SurfaceController
        {
            private readonly ILogger _logger;
    
            public BackofficeDownloadController()
            {
            }
    
            public BackofficeDownloadController(ILogger _logger)
            {
                this._logger = _logger;
            }
    
            [HttpGet]
            public ActionResult DownloadPDF(int ID)
            {
                if (AuthorizationHandler.UserLoggedIn())
                {
                    try
                    {
                        DocumentGenerator generatore = new DocumentGenerator ();
                        generatore.GeneratePDF(ID);
                        if (Request.UrlReferrer != null)
                        {
                            return new RedirectResult(Request.UrlReferrer.AbsoluteUri);
                        }
                        return new RedirectResult("/#/Preventivi");
                    }
                    catch (Exception ex)
                    {
                        Console.Write(ex.ToString());
                        _logger.Error("Error in BackofficeDownloadController.DownloadPDF", ex);
                        return null;
                    }
                }
                else
                {
                    throw new HttpException(401, "Unauthorized access");
                }
            }
        }
    }
    

    The Authorization Handler remains the same

    public class AuthorizationHandler
    {
        public static bool UserLoggedIn()
        {
            var httpCtxWrapper = new HttpContextWrapper(HttpContext.Current);
            var umbTicket = httpCtxWrapper.GetUmbracoAuthTicket();
            if (umbTicket == null || umbTicket.Identity == null || umbTicket.Identity.Name.IsEmpty() || !umbTicket.Identity.IsAuthenticated)
                return false;
            return true;
        }
    }
    

    Finally the document generator is whatever you need to create the document. In this case I am using ASPOSE.Words to generate a PDF file from a Word Document.

    public void GeneratePDF(int ID)
      {
            Document documento;
    
            try
            {
                MemoryStream stream = new MemoryStream();
                documento = GeneraDocumento(ID);
                documento.Save(stream, SaveFormat.Pdf);
                System.Web.HttpContext.Current.Response.Clear();
                System.Web.HttpContext.Current.Response.Buffer = true;
                System.Web.HttpContext.Current.Response.ContentType = "application/pdf";
                System.Web.HttpContext.Current.Response.AddHeader("content-length", stream.Length.ToString());
                System.Web.HttpContext.Current.Response.AddHeader("content-disposition", string.Format(@"attachment;filename=""Preventivo_{0}.pdf""", IDPreventivo));
                System.Web.HttpContext.Current.Response.BinaryWrite(stream.ToArray());
                System.Web.HttpContext.Current.Response.End();
            }
            catch (Exception ex)
            {
                Umbraco.Web.Composing.Current.Logger.Error(typeof(GeneratoreDocumenti), ex, "Error in DocumentGenerator.GeneratePDF");
            }
        }
    

    I hope it helps to someone else, as the previous answers helped me.

    Michele

Please Sign in or register to post replies

Write your reply to:

Draft