Open Word file stored in SQL Server - c#

We successfully add word documents in our SQL Server (varbinary column) using some web forms, then, we want some of our staff to be able to download them.
We have some code to display it, but sometimes it does display (in my local environment), sometimes it does not, but then, when it goes live to Production. So, we just want to download it, it doesn't matter if it opens or if it does not (in case you don't have Word installed), we just want to have it downloaded, something like the "Save as..." function. Because in my local environment it works well, but when it goes live to a IIS server, we are not able to retrieve the file (I am guessing, it is because it opens WORD automatically).
Here is the code to retrieve it.
public string showDoc(int id, int numRef)
{
string fileName = Path.GetTempFileName() + ".docx";
Db.Open();
string cuerito = "select doc from tbl_references where [userId]=#id and [refNum]=#numRef";
SqlCommand command = new SqlCommand(cuerito, base.Db);
command.Parameters.AddWithValue("#id", id);
command.Parameters.AddWithValue("#numRef", numRef);
using (SqlDataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
int size = 1024 * 1024;
byte[] buffer = new byte[size];
int readBytes = 0;
int index = 0;
using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
while ((readBytes = (int)dr.GetBytes(0, index, buffer, 0, size)) > 0)
{
fs.Write(buffer, 0, readBytes);
index += readBytes;
}
}
}
}
Db.Close();
return fileName;
}
Is there a way in C# just to do this? Not display but only download it from SQL Server?
EB.

All the code above does is read some data from a binary field and write it to a stream, which gets written to the disk on the server. There's no need to save the file to disk before you offer it for download, you can simply stream the data directly to the client - there are tons of examples and previous questions containing working examples of this process if you google it. They will work with any file, none of this is specific to Word files. And none of it relates to interop in any way.
BTW whether the file downloads directly to the user's disk or is opened up (saved in a temp folder on the user's machine) is largely down to the config of the user's machine, which browser they use, whether the Word plugin is installed in that browser, their general download settings. You can set HTTP headers (again google it) which hint to the browser to just save the file instead of trying to open it, but ultimately it's in the control of the browser, not the server.
Here's one reasonably simple example of sending binary data from a database table as a file download: https://ygtechme.wordpress.com/2012/08/27/downloading-file-from-database-using-c-asp-net/. There are dozens more similar ones with slight variations on the theme available online. But this is the general idea.

The code you posted already does what you ask for.

Related

Storing image in database in asp.net core. Should I store the image in bytes of just stooring the path of uploaded file is enough

I am storing the image file details in the database. Along with the path, I am also planning to store the byte array in case of accidental deletion of the uploaded folder. I would be using SQL express database as I want to use the app locally. As the size of SQL express is 10GB is it advisable to store a byte array of images in the database.
Does the size of the byte array is same as the size of the image? As I am expecting the images to be of around 5-10MB.
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
await postPatientInformationEntity.PatientPhoto.CopyToAsync(fileStream);
fileInformationEntity.Path = filePath;
fileInformationEntity.Name = postPatientInformationEntity.PatientPhoto.FileName;
fileInformationEntity.Type = postPatientInformationEntity.PatientPhoto.ContentType;
}
using (var ms = new MemoryStream())
{
await postPatientInformationEntity.PatientPhoto.CopyToAsync(ms);
var fileBytes = ms.ToArray();
fileInformationEntity.FileData = fileBytes;
// act on the Base64 data
}
An alternative, and better method is to store the images outside of the database and store only a link to the image file. You only need a text field in your database table to store this information. The only problem to this approach is that you must synchronize the data in the link field with your file system. The possible solution is to store it in the file system, if the images need to be accessed from another server, tools like rsync can be used to move files from one server to other. this tools can be automated in order to sync the filesystems in constant intervals. The path of uploaded file is enough.

Read/Write remote text from Google Drive or similar from Android in c#

So, the title may be misleading. I am building an android app that reads information from a text file, which is located on a cloud server (I would prefer to use either OneDrive, DropBox, or Google Drive [whichever is easiest]; others are fine). Periodically, the program will write information to the text file, still located on the cloud server. So, my question is twofold: Is it possible to read and write to a text file that is located on a cloud server? If so, how in the world would I complete this task? I have noticed the use of WebClient but I can't find a reasonable method or explanation on how this works. This program is coded in C#. This is what I have so far:
private string filename = "datafile.txt";
private List<Category> myList; //A list of an object that I developed ('Category')
//Allow the user interface to handle the error
public void readDatabase() {
//Here is where the magic has to occur, in order to read the file
...
//The usual reader that I use to read standard text files
StreamReader fileReader = new StreamReader(filename);
string line = "";
while ((line = fileReader.ReadLine()) != null)
//convertToCategory is my private method to convert the string to
myLine.Add(convertToCategory(line);
fileReader.close();
}
public void writeDatabase() {
//Here is where the magic has to occur, in order to write to the file
...
//The usual writer that I use to write standard text files
StreamWriter fileWriter = new StreamWriter(filename);
for (int i = 0; i < this.myList.Count; i++)
//toString() is something was developed in my object called 'Category'
fileWriter.WriteLine(fileWriter[i].toString());
fileWriter.close();
}
I would love to use Google Drive as my cloud server, but I am open to other possibilities, if necessary. I just want an easy and efficient method to read/write to the text file.
Possible Implementations:
Have seen possible solutions, where the file is downloaded locally and then read like normal and then uploaded at time of closing. However, if I could get away with it, I don't want the text file to be downloaded.
I have, also, seen several places where a SQL database is used in this instance. But the unfortunate thing is that I don't have any knowledge in developing with SQL. So, using a SQL server would be ideal (because speed is very important for this application) but it will be difficult for me to understand how it works.

IE9 randomly popping Windows Security Dialog when I send down a binary blob as a .xlsx

So on our website, we have multiple reports that can be downloaded as an Excel Spreadsheet, we accomplish this by reading in a blank template file from the harddrive, copying it into a MemoryStream, pushing the data into the template with DocumentFormat.OpenXml.Spreadsheet; Then we pass the MemoryStream to a function that sets the headers and copies the stream into the Response.
Works GREAT in FF & Chrome, but IE9 (and 8, so my QA tells me) randomly pop a Windows Security login dialog asking you to log into the remote server. I can either cancel the dialog, or hit ok (the credentials seem to be ignored), and get the Excel file as expected. Looking at the queries (using CharlesProxy) I cannot get the login dialog to pop until I disable CharlesProxy again, so I cannot see if there's any difference in the traffic between my dev machine and the server. It also doesn't happen when running debug from my local-host, just from the Dev/Test server.
Any help would be useful, the code in question follows. This is called out of a server-side function in the code behind, hence the RespondAsExcel clears the response and puts in the xlsx instead.
using (MemoryStream excelStream = new MemoryStream())
{
using (FileStream template = new FileStream(Server.MapPath(#"Reports\AlignedTemplateRII.xlsx"), FileMode.Open, FileAccess.Read))
{
Master.CopyStream(template, excelStream);
}
//Logic here to push data into the Memory stream using DocumentFormat.OpenXml.Spreadsheet;
Master.RespondAsExcel(excelStream, pgmName);
}
public void RespondAsExcel(MemoryStream excelStream, string fileName)
{
var contenttype = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.Clear();
Response.ContentType = contenttype;
fileName = Utils.ReplaceWhiteSpaceWithUnderScores(fileName);
Response.AddHeader("content-disposition", "inline;filename=" + fileName);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.BinaryWrite(excelStream.ToArray());
//If that doesn't work, can try this way:
//excelStream.WriteTo(Response.OutputStream);
Response.End();
}
public void CopyStream(Stream source, Stream destination)
{
byte[] buffer = new byte[32768];
int bytesRead;
do
{
bytesRead = source.Read(buffer, 0, buffer.Length);
destination.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
}
A couple of ideas come to mind regarding that "extra authentication dialog" that can always be dismissed...won't promise this is your issue, but it sure smells like a first-cousin of it.
Office 2007 and later documents open HTTP-based repositories with the WebClient libraries, which do not honor any of IE's security zone filters when requests are made. If the file is requested by IE, and host URL contains dots (implying a FQDN), even if the site is anonymously authenticated (requiring no credentials), you'll get the "credential" dialog that can be cancelled or simply clicked three times and discarded. I was dealing with this problem just yesterday, and as best I can tell, there's no workaround if the file is delivered with IE. There's some quirk about how IE delivers the file that makes Office apps believe it has to authenticate the request before opening it, even though the file has already been delivered to the client!
The dialog issue may be overcome if the document is delivered from a host server in the same domain as the requesting server, eg some-server.a.domain.com to my-machine.a.domain.com.
The second idea is something strictly born of my own experience - that the openoffice vendor format types sometimes introduce their own set of oddness in document stream situations. We've just used a type of application/vnd.ms-excel and, while it seems it should map to the same applications, the problems don't seem to be as prevalent.
Perhaps that can give you some thoughts on going forward. Ultimately, right now, I don't think there's an ideal solution for the situation you're encountering. We're in the same boat, and had to tell our in-house clients that get the dialog to just hit "Cancel," and they get the document they want.
In your RespondAsExcel() method, change your content-dispositon response header from inline to attachment. This will force the browser to open the file as read only. See KB899927.
Response.AddHeader("content-disposition", "attachment;filename=" + fileName);
I had something similar with VBScript when using "Response.ContentType="application/vnd.ms-excel". I simply added the following code and the Windows Security popup window no longer appeared:
Response.AddHeader "content-disposition","attachment; filename=your_file_name_here.xls"

how to get a picture from a postgresql database

i want to select a picture that save as a large object in a postgresql database.
i know i use lo_export to do this.
but there is a problem: i want to save this picture directly to my computer because i cant access the files that save on Server using lo_export
(i think that is best for me if picture transfer to my computer by a select query)
I don't exactly know my way around C# but the Npgsql Manual has an example sort of like this of writing a bytea column to a file:
command = new NpgsqlCommand("select blob from t where id = 1);", conn);
Byte[] result = (Byte[])command.ExecuteScalar();
FileStream fs = new FileStream(args[0] + "database", FileMode.Create, FileAccess.Write);
BinaryWriter bw = new BinaryWriter(new BufferedStream(fs));
bw.Write(result);
bw.Flush();
fs.Close();
bw.Close();
So you just read it out of the database pretty much like any other column and write it to a local file. The example is about half way down the page I linked to, just search for "bytea" and you'll find it.
UPDATE: For large objects, the process appears to be similar but less SQL-ish. The manual (as linked to above) includes a few large object examples:
NpgsqlTransaction t = Polacz.BeginTransaction();
LargeObjectManager lbm = new LargeObjectManager(Polacz);
LargeObject lo = lbm.Open(takeOID(idtowaru),LargeObjectManager.READWRITE); //take picture oid from metod takeOID
byte[] buf = new byte[lo.Size()];
buf = lo.Read(lo.Size());
MemoryStream ms = new MemoryStream();
ms.Write(buf,0,lo.Size());
// ...
Image zdjecie = Image.FromStream(ms);
Search the manual for "large object" and you'll find it.
Not familiar with C# but if you've contrib/dblink around and better access to a separate postgresql server, this might work:
select large object from bad db server.
copy large object into good db server using dblink.
lo_export on good db server.
If your pictures don't exceed 1GB (or if you don't access only parts of the bytes) then using bytea is the better choice to store them.
A lot of SQL GUI tools allow to directly download (even view) the content of bytea columns directly

How to save file in SQL Server database if have file path?

I am building some C# desktop application and I need to save file into database. I have come up with some file chooser which give me correct path of the file. Now I have question how to save that file into database by using its path.
It really depends on the type and size of the file. If it's a text file, then you could use File.ReadAllText() to get a string that you can save in your database.
If it's not a text file, then you could use File.ReadAllBytes() to get the file's binary data, and then save that to your database.
Be careful though, databases are not a great way to store heavy files (you'll run into some performance issues).
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
int numBytes = new FileInfo(fileName).Length;
byte[] buff = br.ReadBytes(numBytes);
Then you upload it to the DB like anything else, I'm assume you are using a varbinary column (BLOB)
So filestream would be it but since you're using SQL 2K5 you will have to do it the read into memory way; which consumes alot of resources.
First of the column type varchar(max) is your friend this give you ~2Gb of data to play with, which is pretty big for most uses.
Next read the data into a byte array and convert it to a Base64String
FileInfo _fileInfo = new FileInfo(openFileDialog1.FileName);
if (_fileInfo.Length < 2147483647) //2147483647 - is the max size of the data 1.9gb
{
byte[] _fileData = new byte[_fileInfo.Length];
_fileInfo.OpenRead().Read(_fileData, 0, (int)_fileInfo.Length);
string _data = Convert.ToBase64String(_fileData);
}
else
{
MessageBox.Show("File is too large for database.");
}
And reverse the process to recover
byte[] _fileData = Convert.FromBase64String(_data);
You'll want to dispose of those strings as quickly as possible by setting them to string.empty as soon as you have finished using them!
But if you can, just upgrade to 2008 and use FILESTREAM.
If you're using SQL Server 2008, you could use FILESTREAM (getting started guide here). An example of using this functionality from C# is here.
You would need the file into a byte array then store this as a blob field in the database possible with the name you wanted to give the file and the file type.
You could just reverse the process for putting the file out again.

Categories

Resources