1

I created a report using ReportViewer and I can generate it on local machine without any problem. On the other hand, I encounter an error "Access to the path 'C:\xxxxxxx.xlsx' is denied." after publishing the application to IIS. Of course it is caused by the permission problem, but in our company, in most cases there is no writing permission to any location of C drive and I think the best approach is to open the generated excel file in memory, etc. (without writing to disk). So, how can I update the method I use in order to achieve this? Any idea?

I send the report (created using ReportViewer) to this method as Stream and I open the generated report without writing to disk:

public static void StreamToProcess(Stream readStream, string fileName, string fileExtension)
{
    var myFile = fileName + "_" + Path.GetRandomFileName();
    var writeStream = new FileStream(String.Format("{0}\\{1}.{2}",
            Environment.GetFolderPath(Environment.SpecialFolder.InternetCache), myFile, 
                fileExtension), FileMode.Create, FileAccess.Write);

    const int length = 16384;
    var buffer = new Byte[length];
    var bytesRead = readStream.Read(buffer, 0, length);
    while (bytesRead > 0)
    {
        writeStream.Write(buffer, 0, bytesRead);
        bytesRead = readStream.Read(buffer, 0, length);
    }
    readStream.Close();
    writeStream.Close();
    Process.Start(Environment.GetFolderPath(Environment.SpecialFolder.
                    InternetCache) + "\\" + myFile + "." + fileExtension);
}       

Any help would be appreciated.

Update :

I pass the report stream to this method as shown below:

StreamToProcess(reportStream, "Weekly_Report", "xlsx");

Note : reportStream is the generated report using ReportViewer.

Jack
  • 1
  • 21
  • 118
  • 236
  • 1
    I believe you can can just write the file at the root folder of your application. You have access there. If you are worried about the files being stuffed there, you can delete them right after download, or make a process do that for in you in a batch. – jpgrassi Dec 26 '15 at 13:10
  • You need to grant the `IIS_User` that your application pool uses, write permissions to the folder you want to write to. Because you use `Process.Start` you can't use a MemoryStream. – Alex Dec 26 '15 at 13:15
  • @Jaco Why did you delete your good answer? I do not have to use Process.Start if I solve the problem without it. Could you post it and edit so that I can open the stream your method returned? Thanks... – Jack Dec 26 '15 at 13:17
  • @jpgrassi You are right, but how can I set the root folder so that the generated file is written to there? – Jack Dec 26 '15 at 13:18
  • I have undeleted the answer, I will not be able to update it for a few hours now. You could set a static output folder and grant write permissions to that one. – Alex Dec 26 '15 at 13:21
  • 1
    Often people use the "App_Data" folder for these purposes. You can get its relative path like this: string path = HttpContext.Current.Server.MapPath("~/App_Data/"); – jpgrassi Dec 26 '15 at 13:22
  • @Jaco No problem, if it is possible for you to edit later, I can wait for 2 days :) – Jack Dec 26 '15 at 13:28
  • @jpgrassi What about MVC? There is no App_Data folder on the published folders. – Jack Dec 26 '15 at 13:29
  • 1
    The App_Data is in you VS Solution, fore sure. What often happens is that if the folder is empty, when you generate a build/publish the folder does not go inside the package generated. To fix that, add a dumb .txt file inside your App_Data from Visual Studio and publish again. The folder will be there. Also make sure to set the .txt file Build Action to Content – jpgrassi Dec 26 '15 at 13:31

1 Answers1

2

You can write to a MemoryStream instead and return this stream to the caller. Make sure you do not close the instance of your memory stream. You can then pass this memory stream to a StreamWriter instance if you want to process the in-memory file.

public static Stream StreamToProcess(Stream readStream)
{
    var myFile = fileName + "_" + Path.GetRandomFileName();
    var writeStream = new MemoryStream();

    const int length = 16384;
    var buffer = new Byte[length];
    var bytesRead = readStream.Read(buffer, 0, length);
    while (bytesRead > 0)
    {
        writeStream.Write(buffer, 0, bytesRead);
        bytesRead = readStream.Read(buffer, 0, length);
    }
    readStream.Close();

    return writeStream;     
}       

Your current approach of calling Process.Start will not work on the IIS server as it will open the Excel document on the server rather than on the users computer. You will have to provide a link to the user to download the file, you could use an AJAX request for this that streams from the MemoryStream. Have a look at this post on further details on how to implement this.

Community
  • 1
  • 1
Alex
  • 21,273
  • 10
  • 61
  • 73
  • Many thanks for your reply, but I cannot pass this stream to the `StreamWriter` instance. I also add an update. By looking to this update could you please update your answer indicating how to get this stream? – Jack Dec 26 '15 at 12:29
  • I extended my answer, will try to add an example later this evening. – Alex Dec 27 '15 at 17:48
  • Many thanks for your help. I solved the problem by applying the method on [Error while creating open XML excel sheet from ASP.NET MVC](http://stackoverflow.com/questions/21861288/error-while-creating-open-xml-excel-sheet-from-asp-net-mvc). Your reply is also useful and voted+ – Jack Dec 28 '15 at 10:19