Return a FileAttachment from a contributed action

Jan 24, 2013 at 6:11 AM

Can a FileAttachment be used a return object from a contributed action. I'm trying to export the collection of objects as an excel file. The only thing giving me trouble is a null reference error whenever I have a contributed action returning a FileAttachment.

 

Has anyone overcome this problem, or has a better way of returning the excel file.

Coordinator
Jan 24, 2013 at 8:53 AM

We don't support returning FileAttachments from actions. I agree it fails 'inelegantly' and I'll raise a ticket for this.

I suggest you make the FileAttachment  a property on a domain object in the standard way.

Feb 7, 2013 at 6:26 AM
Adding it as a property won't work as the output file is generated from a collection of domain objects.

Is there any other way to get a contributed action to return a file attachment that can be downloaded.
Coordinator
Feb 7, 2013 at 7:33 AM
You could presumably just arrange it so that your contributed action actually returns another simple object called (for the sake of argument) ExcelSaver, which holds the data to be saved, and which has a FileAttachment property for specifying where. From the user perspective this new object is merely seen as a dialog. Not the most elegant solution, I agree, but the only thing I can think of right now.
Feb 7, 2013 at 8:00 AM
Hi Richard,

Thanks for the advice. I've got it working up to trying to download the file attachment. I'm assuming that is because I'm trying to not persist the object. But obviously once it's returned the object from the action, it's no longer there to download. Is there anyway to have this method work without persisting the object? It's not a deal breaker, but for tidyness would be nice, rather than persisting and removing each download.

Cheers,
Pat
Coordinator
Feb 7, 2013 at 8:24 AM
I'm note sure you can do it without persisting the intermediate object (and then deleting when done). This is a capability that is coming: the idea of 'addressable view models' (objects that are not persisted, but which do have an identity and can be addressed - so they appear to exist between interactions).. This is basically implemented and working now for Restful Objects (for the next release), but not yet done for Naked Objects MVC.
Feb 16, 2013 at 12:40 PM
I'm left a little perplexed now. I've got the file object being persisted. Look at the table in the database shows all the information put in. However trying to retreive the file attachment from the object itself results in a 404 error. I lifted code from a working implementation returning file attachment objects, however that was done in the previous NOF version. Are there any changes that would have broken it?
Coordinator
Feb 18, 2013 at 7:31 AM
Please show your code, and also advise which version of NOF you had it working for.
Feb 18, 2013 at 8:45 AM
Working Code in NOF4
public class Document
    {
        [Hidden]
        public virtual int Id { get; set; }
        [Hidden]
        public virtual byte[] Data { get; set; }
        [Hidden]
        public virtual string MIMEType { get; set; }
        [Hidden, Title]
        public virtual string Name { get; set; }
        public virtual FileAttachment Attachment
        {
            get
            {
                if (Data == null) return null;
                return new FileAttachment(Data, Name, MIMEType);
            }
        }


public class Meeting 
{
        private ICollection<Document> _Documents = new List<Document>();

        public virtual ICollection<Document> Documents
        {
            get
            {
                return _Documents;
            }
            set
            {
                _Documents = value;
            }
        }
}
Non-working code in NOF5
public class FileDownload
    {
        
        [Hidden]
        public virtual int Id { get; set; }
        [Hidden]
        public virtual byte[] Data { get; set; }
        [Hidden]
        public virtual string MIMEType { get; set; }
        [Hidden, Title]
        public virtual string Name { get; set; }
        public virtual FileAttachment Attachment
        {
            get
            {
                if (Data == null) return null;
                return new FileAttachment(Data, Name, MIMEType);
            }

        }
    }

        public FileDownload ExportList(IQueryable<Task> tasklist)
        {
            using (ExcelPackage p = new ExcelPackage())
            {
                ExcelWorksheet ws = CreateSheet(p, "Task List");

                ws.Cells[1, 1].Value = "Projector Task List"; // Heading Name
                ws.Cells[1, 1].Style.Font.Bold = true; //Font should be bold

                int RowIndex = 2;

                ws.Cells[1, 1].Value = "Due Date";
                ws.Cells[1, 2].Value = "Task Name";
                ws.Cells[1, 3].Value = "Accountability";
                ws.Cells[1, 4].Value = "Current Status";
                ws.Cells[1, 1].Value = "Category";

                foreach (var task in tasklist)
                {
                    ws.Cells[RowIndex, 1].Value = task.DueDate;
                    ws.Cells[RowIndex, 2].Value = task.Name;
                    ws.Cells[RowIndex, 3].Value = task.Accountability.Name;
                    ws.Cells[RowIndex, 4].Value = task.CurrentStatus.Name;
                    ws.Cells[RowIndex, 1].Value = task.Category.Name;
                    RowIndex++;
                }

                FileDownload newdownload = Container.NewTransientInstance<FileDownload>();
                newdownload.Data=p.GetAsByteArray();
                newdownload.Name=DateTime.Now + " Export.xlsx";
                newdownload.MIMEType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

                Container.Persist<FileDownload>(ref newdownload);

                return newdownload;

            }
        }
    }
Coordinator
Feb 18, 2013 at 10:34 AM
I'm not aware of anything that changed with NOF v5 that should have impacted FileAttachement.

Just to narrow down the issue ...

1) does it make any difference if you retrieve a persisted FileDownload directly (rather than looking at the one returned from your ExportList method. In other words, can you add a SimpleRepository<FileDownload>() and see if you can return one of those and view the attachment.

2) If you still get the error - at what point is the 404 error occurring? Is it when you attempt to retrieve the FileDownload object, or when you attempt to view the attachment? In either case, can you intercept the URL that is being called?