I have an html file in my asp.net webforms project that people can download when clicking a button.
I would like to generate some <select> lists and append to certain parts of the html based on some database values before the file gets sent to the user. Is this possible using c#? My current download functionality:
public void DownloadOfflineAuditSheetEditor(object s, EventArgs e)
{
Response.AppendHeader("content-disposition", "attachment; filename=thefile.html");
Response.WriteFile(Server.MapPath("~/thefile.html"), true);
Response.End();
}
Yes - you'd have to manipulate "the file" before it gets sent to the user.
In your method DownloadOfflineAuditSheetEditor you could have call a new method that reads the current file, gets the contents from the DB and then writes to the file or a new file, for example:
public void GenerateRealTimeContent()
{
var path = Server.MapPath("~/thefile.html");
var dbContent = Database.GetContent(); // returns the <select> Options
string[] lines = System.IO.File.ReadAllLines(path);
StringBuilder sb = new StringBuilder();
foreach (var line in lines)
{
if (line == "CONTENT WHERE YOU WANT TO EDIT")
{
SB.AppendLine(dbContent);
}
SB.AppendLine(line);
}
// code to write to your file
}
Then in your original function do:
public void DownloadOfflineAuditSheetEditor(object s, EventArgs e)
{
GenerateRealTimeContent();
Response.AppendHeader("content-disposition", "attachment; filename=thefile.html");
Response.WriteFile(Server.MapPath("~/thefile.html"), true);
Response.End();
}
http://msdn.microsoft.com/en-us/library/ezwyzy7b.aspx - Reading from a file
http://msdn.microsoft.com/en-us/library/aa287548(v=vs.71).aspx - Write to a file
You can read the file with a StreamReader, edit it or add anything and write the all thing in the Resposne.
Related
In my application I want to give user the option to download a PDF file. In my code, the file gets opened by browser; however, I want the file to be downloaded. Here's my code:
Controller
string name = id; //id is the name of the file
string contentType = "application/pdf";
var files = objData.GetFiles(); //list of files
string filename = (from f in files
orderby f.DateEncrypted descending
where f.FileName == name
select f.FilePath).First(); //gets the location of the file
string FullName = (from f in files
where f.FileName == name
select f.FileName).First(); //gets the new id in new location to save the file with that name
//Parameters to File are
//1. The File Path on the File Server
//2. The content type MIME type
//3. The parameter for the file save by the browser
return File(filename, contentType, FullName);
Here's how I'm using it in dropdown menu.
View:
<li><a id="copyURL" href="#Url.Action("Download", "Home", new { id = item.FileName})">Download</a></li>
By clicking on "Download", the file gets opened browser.
Set your content type to "application/octet-stream" so the PDF plugin won't try to pick it up and display it. Then the browser will handle it as a file download.
Download Files from Web:
This example shows how to download files from any website to local disk. The simply way how to download file is to use WebClient class and its method DownloadFile. This method has two parameters, first is the url of the file you want to download and the second parameter is path to local disk to which you want to save the file.
Download File Synchronously
The following code shows how to download file synchronously. This method blocks the main thread until the file is downloaded or an error occur (in this case the WebException is thrown).
[C#]:
using System.Net;
WebClient webClient = new WebClient();
webClient.DownloadFile("pdf file address", #"c:\myfile.pdf");
Download File Asynchronously:
To download file without blocking the main thread use asynchronous method DownloadFileAÂsync. You can also set event handlers to show progress and to detect that the file is downloaded.
[C#]:
private void btnDownload_Click(object sender, EventArgs e)
{
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
webClient.DownloadFileAsync(new Uri("pdf file address"), #"c:\myfile.pdf");
}
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("Download completed!");
}
ref: http://www.csharp-examples.net/download-files/
Browser will try to show the file unless you specify not to.
Try Adding ContentDisposition before returning File.
var cd = new System.Net.Mime.ContentDisposition
{
FileName = filename,
Inline = false,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(filename, contentType, FullName);
I need to set a handler to <asp:Button> element. When user clicks, txt file must be generated in code-behind and must be automatically downloaded by user. There is no need to get any data from user. All file content will be generated in code behind. For example, how to return to user a txt file with content of this variable:
string s = "Some text.\nSecond line.";
For this kind of job you should create file on the fly.
Please see the code:
protected void Button_Click(object sender, EventArgs e)
{
string s = "Some text.\r\nSecond line.";
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=testfile.txt");
Response.AddHeader("content-type", "text/plain");
using (StreamWriter writer = new StreamWriter(Response.OutputStream))
{
writer.WriteLine(s);
}
Response.End();
}
}
Just note for new line you need to use \r\n instead of only \n or use WriteLine function for each line
You can simply generate the file on the server side and then push it down to the user. s would be the content of the File that you will generate.
Creating the File
Creating a new File is as simple as writing the data to it,
// var s that you're having
File.Create(Server.MapPath("~/NewFile.txt")).Close();
File.WriteAllText(Server.MapPath("~/NewFile.txt"), s);
This will create a new file (if doesn't exist) and write the content of the variable s to it.
Pushing it down to the user
You can allow the user to download it, using the following code,
// Get the file path
var file = Server.MapPath("~/NewFile.txt");
// Append headers
Response.AppendHeader("content-disposition", "attachment; filename=NewFile.txt");
// Open/Save dialog
Response.ContentType = "application/octet-stream";
// Push it!
Response.TransmitFile(file);
This will let him have the file you just created.
I do have a similar case but a little bit more complex usecase.
I do generate different types of files. I wrote a container class Attachment witch holds the content type and the value of the generated file as an Base64 string.
public class Attachment {
public string Name {get;set;}
public string ContentType {get;set;}
public string Base64 {get;set;}
}
This enables me to serve different file types with the same download method.
protected void DownloadDocumentButton_OnClick(object sender, EventArgs e) {
ASPxButton button = (ASPxButton) sender;
int attachmentId = Convert.ToInt32(button.CommandArgument);
var attachment = mAttachmentService.GenerateAttachment(attachmentId);
Response.Clear();
Response.AddHeader("content-disposition", $"attachment; filename={attachment.Name}");
Response.AddHeader("content-type", attachment.ContentType);
Response.BinaryWrite(Convert.FromBase64String(attachment.Base64));
Response.End();
}
I've got a C# file upload that is meant to extract XML tags from inside a DocX document, the problem I'm facing is that when the file is uploaded, the error "File is being used by another process" comes up. Attempting to delete the document shows it is being used by IIS process manager.
Is there a way to stop my code to get it to continue running?
<script runat="server">
//foreach (DataRow row in table.Rows)
//{
// string dbColumnNames = (selectedData.ToString());
//send files
//}
public string _TempFileLocation = ""; //Used to locate Word Document File Path
//THE USER UPLOAD CONTROL. users use this to upload the document to the server
public void XMLextractor(string _filePath)
{
//XML extraction code
displayFilepath.Text = _filePath;
_TempFileLocation = _filePath;
}
//names the script manager which will be used when the user attempts to upload a form / gives an error if they incorrectly attempt to upload
protected void UploadButton_Click(object sender, EventArgs e)
{
//if file is located
if (FileUploadControl.HasFile)
{
try
{
//allow content type of document / docx
if (FileUploadControl.PostedFile.ContentType == "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
{
if (FileUploadControl.PostedFile.ContentLength < 10485760) // 10mb)
{
//name the filename, find the path of the name
string filename = Path.GetFileName(FileUploadControl.FileName);
//path of server upload (we just need to save it as a variable to be found on the next page, as it will be made / deleted
FileUploadControl.SaveAs(Server.MapPath("~/") + filename);
//update the label with file uploaded
StatusLabel.Text = "Upload status: File uploaded!";
XMLextractor(Server.MapPath("~/") + filename);
//move onto template wizard page
//Response.Redirect("http://portal.acoura.com/admin/templatewizard.aspx", false);
WordprocessingDocument _TempDoc = WordprocessingDocument.Open(Server.MapPath("~/") + filename, true);
XDocument xdoc = XDocument.Load(Server.MapPath("~/") + filename);
//query to find particular descendants
var lv1s = from document in xdoc.Descendants("table")
select new
{
Header = document.Attribute("name").Value,
Children = document.Descendants("tag")
};
//Loop through results
StringBuilder result = new StringBuilder();
foreach (var lv1 in lv1s)
{
result.AppendLine(lv1.Header);
foreach (var lv2 in lv1.Children)
result.AppendLine(" " + lv2.Attribute("name").Value);
}
//the label should contain the content controls of the document, using the class, XMLfromDocument
labelContentControls.Text = fileUpload_Displayx(XMLfromDocument.GetContentControls(_TempDoc));
}
else
//display the size the file needs to be less than
StatusLabel.Text = "Upload status: The file has to be less than 10mb!";
}
else
//tell the user only docx files are accepted
StatusLabel.Text = "Upload status: Only DOCX files are accepted!";
}
catch (Exception ex)
{
//display the exception message, in which case it would be either size / type / if it's present
StatusLabel.Text = "Upload status: The file could not be uploaded. The following error occured: " + ex.Message;
}
}
}
//needs to be replaced with the variable found in descendants / var tagContent
public string fileUpload_Displayx(XElement _contentcontrol)
{
string str = "";
str = _contentcontrol.Name.ToString();
return str;
}
//public static displayDatabase(object sender, EventArgs e)
// {
//}
//run the validate button on templatewizard, will mark up any problems or give green light
//if red, allow users to replace fields in the left column, from ones in the atabase on the right
//display upload button when validation is succesful. When Upload button runs, Take to new
// / existing page of reports, allow users to download this
</script>
You are opening the file without closing it on this line:
WordprocessingDocument _TempDoc = WordprocessingDocument.Open(Server.MapPath("~/") + filename, true);
Then you are opening it again with xDocument.Load():
XDocument xdoc = XDocument.Load(Server.MapPath("~/") + filename);
I assume that is where the error occurs.
If you handle all of the stuff XDocument needs to do first, and then open and close the WordProcessingDocument.Open() line to get the content controls, you should be fine.
Basically only one process can have a open and read or modify a file at a time, so if two operations from two different sources need to be performed, they must be performed sequentially on the file.
You can also open the file via a FileStream and then load the content into memory and into your XDocument, therefore negating the need to have the file opened twice by XDocument and WordProcessingDocument simultaneously.
Hope this helps!
So I have this page on my application where the user can download a "hard copy" of a rendered view, which represents Skills and their Requirements on Roles within a Project, showing the fulfilment of said Skills by any people on the Role.
I have the functionality working with a csv file, as I can just use a StringBuilder for creating a comma-delimited file.
However, before approaching the Excel approach, where I want some light formatting, I realise I cannot acheive this the same way.
I have used Interop for generating Excel files before, but how would I be able to create one that can be downloaded after it's generation?
Here is the working code to generate and return a CSV file:
public ActionResult DownloadSQEPToCSV(int projectID)
{
//source my data
StringBuilder sBuilder = new StringBuilder();
sBuilder.Append("SQEPMatrix, For Project," + data.First().Project.ContractNumber);
foreach (var role in data)
{
sBuilder.Append("\r\nRole:," + role.First().Title.Name);
sBuilder.Append("\r\nSkill,Requirement");
foreach (var person in role.Distinct(uCom))
{
sBuilder.Append("," + person.User.UserDetail.Name);
}
foreach (var skill in role.Distinct(uCom))
{
//More stuff to generate what I want
}
sBuilder.Append("\r\n");
}
//Attach file to the header
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment;filename=SQEPMatrix for " + data.First().Project.ContractNumber + ".csv");
Response.ContentType = "text/csv";
Response.Write(sBuilder);
Response.End();
return SetTitleAndID("SQEP","dl_sqep_csv");
}
This code is invoked by the following script:
function download(id) {
window.location.href = '../../Project/DownloadSQEPExcel?projectID=' + id;
}
So my question, is how can I generate an Excel spreadsheet, and return the generated file in a manner similar to how I return my .csv file?
If you use something like DocumentFormat.OpenXml you can create the Excel file in a memory stream and then return the stream using a FileStreamResult:
var theStreamContainingSpreadsheet = CreateSpreadsheet();
theStreamContainingSpreadsheet.Position = 0;
return new FileStreamResult(theStreamContainingSpreadsheet, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{FileDownloadName = "Export.xlsx"};
I Tried a few solutions mentioned in the site like Using System.Microsoft.Office.Excel and Excel = System.Microsoft.Office.Excel, but it dint work....
Here, I'm trying to get the data in a table and download to a file in the specified location in the server in .xls format and then giving the users a link to download the file.
this is the code for export `
protected void btnExcelExport_Click(object sender, EventArgs e)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using( HtmlTextWriter htw = new HtmlTextWriter(sw))
{
// Create a form to contain the grid
Table table = new Table();
// get gridlines from gridview
table.GridLines = GridView2.GridLines;
if (GridView2.HeaderRow != null)
{
table.Rows.Add(GridView2.HeaderRow);
}
foreach (GridViewRow row in GridView2.Rows)
{
table.Rows.Add(row);
}
if (GridView2.FooterRow != null)
{
table.Rows.Add(GridView2.FooterRow);
}
// render the table into the htmlwriter
table.RenderControl(htw);
}
var myRootPath = Server.MapPath("~");
var docPath = Path.GetFullPath(Path.Combine(myRootPath, "/Compare/c.xls"));
File.WriteAllText(docPath, sw.ToString());
}
dwndlink.Visible = true;
}
And when this is code for linkbutton:
protected void dwnlink(object sender, EventArgs e)
{
var webRootPath = Server.MapPath("~");
var docPath = Path.GetFullPath(Path.Combine(webRootPath, "/Compare/c.xls"));
string name = Path.GetFileName(docPath);
Response.AppendHeader("content-disposition", "attachment; filename=" + name);
Response.ContentType = "Application/vnd.ms-excel";
Response.TransmitFile(docPath);
Response.End();
}
so when the user opens the downloaded file, gives a warning as its not in the same extension.
Why is this happening..??
I tried working with the solutions provided in various sites, but to no avail...
Thanks
try using
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
Try changing Response.ContentType = "application/vnd.xls"; to Response.ContentType = "application/vnd.ms-excel"
Also
Microsoft document says :
"The current design does not allow you to open HTML content from a web site in Excel... So ASP pages that return HTML and set the MIME type to something like XLS to try to force the HTML to open in Excel instead of the web browser (as expected) will always get the security alert... If you use an HTML MIME type, then the web browser will open the content instead of Excel. So there is no good workaround for this case because of the lack of a special MIME type for HTML/MHTML that is Excel specific. You can add your own MIME type if you control both the web server and the client desktops that need access to it, but otherwise the best option is to use a different file format or alert your users of the warning and tell them to select Yes to the dialog."
Visit this site too : http://devblog.grinn.net/2008/06/file-you-are-trying-to-open-is-in.html