Upload ePub file from ASP.NET MVC application - c#

Currently, I am uploading PDF files, and images from my MVC web application to a sql server database. This works perfectly, however I now want to be able to upload ePub files.
I tried to do it with the same uploader in some vain hope that it would work, however this is the error I get:
SqlException was unhandled by the user
code.
"The parameterized query
'(#FileContent varbinary(max)
,#MimeType nvarchar(4000),#FileName'
expects the parameter '#MimeType',
which was not supplied.
Here is also the code from my controller which handles the uploads:
public ActionResult Index()
{
foreach (string upload in Request.Files)
{
if (!Request.Files[upload].HasFile1()) continue;
string mimeType = Request.Files[upload].ContentType;
Stream fileStream = Request.Files[upload].InputStream;
string fileName = Path.GetFileName(Request.Files[upload].FileName);
int fileLength = Request.Files[upload].ContentLength;
byte[] fileData = new byte[fileLength];
fileStream.Read(fileData, 0, fileLength);
const string connect = #"Server=localhost;Database=Images;user id=taraw; password=****;";
using (var conn = new SqlConnection(connect))
{
var qry = "INSERT INTO FileStore (FileContent, MimeType, FileName) VALUES (#FileContent, #MimeType, #FileName)";
var cmd = new SqlCommand(qry, conn);
cmd.Parameters.AddWithValue("#FileContent", fileData);
cmd.Parameters.AddWithValue("#MimeType", mimeType);
cmd.Parameters.AddWithValue("#FileName", fileName);
conn.Open();
cmd.ExecuteNonQuery();
}
}
return View();
}
I know the error is pretty self explanatory as to what the problem is, I'm just unsure how to modify the code to allow it to accept ePub File formats.
Any help would be greatly appreciated :)

Add ePUB into your server's Mime type list as a known type, i guess mime-type is going null into db, that's why this error getting raised up.

Found out that the mimetype for an epub file is application / epub + zip. Specified this in my application rather than expecting it from the user and this seems to have done the trick. File is uploading and downloading without any issues.
Thanks to anyone who commented :)

Related

Blazor Server-Side download issues in IIS

I am trying to download a List of files (user has the option to select multiple). My current code below works fine in localhost (writing and opening the downloads folder). However, when I upload to IIS it gives an error saying that the system configuration is not found.
Please see below:
if (SelectDownloadFiles.Count > 0)
{
//Downloads folder (User profile)
string DownloadFolder = Environment.ExpandEnvironmentVariables("%userprofile%/downloads/");
//This is a little hack to get the literal path for the Downloads folder without too much of back-and-forth and ellaboration
string FolderForward = DownloadFolder.Replace(#"/", #"\");
string Folder = FolderForward.Replace(#"\\", #"\");
foreach (var items in SelectDownloadFiles)
{
//Get Date
var GetDate = items.Substring(0, 6);
//Add 2 days to be consistent to what is displayed to the user (when files were generated)
var FileDate = DateTime.ParseExact(GetDate, "yyMMdd", CultureInfo.InvariantCulture).AddDays(2);
//Get Files
string Pathname = #"D:\";
string FullPathName = Path.Combine(Pathname, items);
byte[] FileBytes = System.IO.File.ReadAllBytes(FullPathName);
MemoryStream Ms = new MemoryStream(FileBytes);
//Rename the file to become user friendly
string DownloadPath = Path.Combine(DownloadFolder, "My Files " + FileDate.ToString("MM-dd-yyyy") + ".zip");
//Write file(s) to folder
FileStream File = new FileStream(DownloadPath, FileMode.Create, FileAccess.Write);
Ms.WriteTo(File);
File.Close();
Ms.Close();
}
//Open Downloads Folder with files
Process.Start("explorer.exe", Folder);
navigationManager.NavigateTo("/default", true);
//DisplayMessage.Show("File(s) successfully downloaded. Please check your “Downloads” folder to access your file(s).", "OK", "check");
}
else
{
Toaster.Add("Please select at least one file to download.", MatToastType.Warning);
}
I've also tried to use the solution below to no avail:
private readonly IWebHostEnvironment _webHostEnvironment;
public YourController (IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment= webHostEnvironment;
}
If I use the "folderoptionpath" and choose "MyDocuments" for instance, the files download to the root path of the files inside IIS.
Is there anything else I need to be doing to get to this to work?
Thanks in advance!
Well, after spending some time researching this, I was finally able to get it going. I ended up using a Nuget Package called BlazorFileSaver and it works just fine. Here's the repo: https://github.com/IvanJosipovic/BlazorFileSaver/blob/master/src/BlazorFileSaver.Sample/Pages/Index.razor
I hope this can help someone else in the future.

Download XML file using .net core API to local machine

I am facing issue while downloading/exporting XML file from C# model to local machine of browser(I have front end for it).
However I am able to download/export the file from C# model to XML and save it on directory on server.
I am using below code for it :
var gradeExportDto = Mapper.Map<GradeExportDto>(responseGradeDto);
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(gradeExportDto.GetType());
var path = _configuration.GetValue<string>(AppConstants.IMPORT_EXPORT_LOCAL_URL) + "\\"+ responseGradeDto.Code+"_"+DateTime.UtcNow.ToString("yyyy-MM-dd") + ".xml";
System.IO.FileStream file = System.IO.File.Create(path);
writer.Serialize(file, gradeExportDto);
file.Close();
Angular Code :
onExport(selectedData: any): void{
this.apiService.post(environment.api_url_master, 'ImportExport/ExportGrade/', selectedData).subscribe(result => {
this.translateService.get('GradeExportSuccess').subscribe(value => this.toastr.success(value));
}, err => {
this.toastr.error(err.message);
});
}
I need help in getting this file downloaded to local system on which browser is running.
Please let me know if more information is required from my side.
NOTE : I am not trying to download existing file. I have model in C# which I need to convert in XML and then download it to my local. However I am able to convert it to XML but not able to download on local.
You cannot save anything directly to a client machine. All you can do is provide the file as a response to a request, which will then generally prompt a download dialog on the client, allowing them to choose to save it somewhere on their local machine.
What #croxy linked you to is how to return such a response. If the issue is that the answer is using an existing file, you can disregard that part. The idea is that you're returning a byte[] or stream, regardless of where that's actually coming from. If you're creating the XML in memory, then you can simply do something like:
return File(memoryStream.ToArray(), "application/xml", "file.xml");
Instead of serializing your data into a file, serialize it into a stream eg. MemoryStream and return a File() from your action:
public IActionResult GetXml()
{
var gradeExportDto = Mapper.Map<GradeExportDto>(responseGradeDto);
var writer = new System.Xml.Serialization.XmlSerializer(gradeExportDto.GetType());
var stream = new MemoryStream();
writer.Serialize(stream, gradeExportDto);
var fileName = responseGradeDto.Code + "_" + DateTime.UtcNow.ToString("yyyy-MM-dd") + ".xml";
return File(stream.ToArray(), "application/xml", fileName);
}

Issues when downloading PDF file from MVC application

I have created a function where a user can download a pdf file from my webpage. The file is stored in a databse and is requested from a webapi. The return value of the webapi is a byte[].
My issue here is that when i run the web application on my local iis this function runs without any errors. I get the pdf file and it is downloaded correctly on my machine. But when i deploy the web application to my Test server this code generates either RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION in chrome with some of the files where as other files are downloaded to the machine but when i try to open the pdf file i get: could not load the pdf file.
This happens with both chrome and IE.
This is my code:
[HttpGet]
[DoNotChangeCacheSettings]
public virtual FileResult DownloadTranslationFile(Guid id)
{
Guid assessmentTemplateId = id;
File translationFile = Services.GetFileContent(assessmentTemplateId);
var fileName = HttpUtility.UrlPathEncode(translationFile.FileName);
this.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
var result = File(translationFile.FileContent.Content, System.Net.Mime.MediaTypeNames.Application.Pdf, fileName);
return result;
}
I have been trying to fix this issue for 2 days now but i simply cant figure out what the issue is. Hope you guys can help. Thanks.
You don't need to use Content-Disposition. .Net will add it for you. From the docs.
The fileDownloadName parameter is used to generate the
content-disposition header. The result object that is prepared by this
method is written to the response by the ASP.NET MVC framework when
the object is executed. The MediaTypeNames class can be used to get
the MIME type for a specific file name extension.
I tend to use the Stream-overload:
[HttpGet]
[DoNotChangeCacheSettings]
public virtual FileResult DownloadTranslationFile(Guid id)
{
Guid assessmentTemplateId = id;
File translationFile = Services.GetFileContent(assessmentTemplateId);
var fileName = HttpUtility.UrlPathEncode(translationFile.FileName);
var stream = = new MemoryStream(translationFile.FileContent.Content);
return File(stream, "application/pdf", fileName);
}
But you can use the byte[] as well:
[HttpGet]
[DoNotChangeCacheSettings]
public virtual FileResult DownloadTranslationFile(Guid id)
{
Guid assessmentTemplateId = id;
File translationFile = Services.GetFileContent(assessmentTemplateId);
var fileName = HttpUtility.UrlPathEncode(translationFile.FileName);
return File(translationFile.FileContent.Content, "application/pdf", fileName);
}
EDIT:
If you got an error when opening the PDF you can ensure that the web browser is doing the right thing by manually saving the PDF from code as well. If that file has errors as well you're probably generating an incorrect byte[].
[HttpGet]
[DoNotChangeCacheSettings]
public virtual FileResult DownloadTranslationFile(Guid id)
{
Guid assessmentTemplateId = id;
File translationFile = Services.GetFileContent(assessmentTemplateId);
var fileName = HttpUtility.UrlPathEncode(translationFile.FileName);
var stream = = new MemoryStream(translationFile.FileContent.Content);
// Code for debugging
var tempDir = "C:\\temp"; // Make sure app pool can write here.
var path = Path.Combine(tempDir, fileName); // Possibly add extension here.
using (var fileStream = File.Create(path))
{
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(fileStream);
}
stream.Seek(0, SeekOrigin.Begin);
// Return to client.
return File(stream, "application/pdf", fileName);
}

How to manually store image in (database) table in Visual Studio 2012 and retrieve using jQuery Ajax in ASP.NET MVC

My database table
First I tried storing images with datatype image/varbinary but I get an error:
Invalid Value The changed value in this cell was not recognized as being valid. .Net Framework Data Type: Byte[] Error Message: You cannot use the result pane to set this Field data to values other than NULL Type a value appropriate for the data type or press ESC to cancel the change
How can I store image in my database table manually and retrieve them through jQuery Ajax method?
use in C# Button Submit with data source
if (FileUpload1.PostedFile != null && FileUpload1.PostedFile.FileName != null)
{
byte[] img = new byte[Request.Files[0].ContentLength];
Request.Files[0].InputStream.Read(img, 0, Request.Files[0].ContentLength);
datasource.Photo = img; --here you can save file to Database
}
for retrieving image from dbserver use belowed
img.ImageUrl = "data:image/jpg;base64," + Convert.ToBase64String(Upprofile.Photo);
Have you ever tried other ways to store images ?
I have never used such a way to store image in database if you want my two cents it would be better to save your image on host and save its url in the database.
You only need url to show picture in browser...!
I'm not sure if this works in VS2012, but you can try this approach that I'm using in my MVC projects:
public action UploadFile(HttpPostedFileBase file) //this is how you get the file that was submited from your form
{
//so now that I have the file, i need to save it somewhere
//let's see if we have a folder for that, if not let's create it
if(!Directory.Exists(Server.MapPath("~/The path from the root of the app to the uploaded files folder/")))
{
Directory.CreateDirectory(Server.MapPath("~/The path from the root of the app to the uploaded files folder/"));
} //the ~ symbol is part of the code, it returns the physical path to the root of the application
var storage = Server.MapPath("~/The path from the root of the app to the uploaded files folder/");
//now we need a name, we can generate one as a GUID for example, or we can get it's own.
var fileName = file.FileName.Substring(file.FileName.LastIndexOf("\"), file.Name.Length + 1);
//Now you might have to play a bit with the substring arguments, I'm not sure i wrote that right,
//it might not need the +1 part, or it might need it on the LastIndexOf as well,
//anyway, now we have the name and the folder where to save our file, let's do that:
path = String.Format("{0}\{1}", storage, filename);
try
{
file.SaveAs(path); //Now the file is on the server,
//just save this path and whatever else you need in the database so you can
//grab it later.
}
catch
{
//do your exception handling here
}
Saving to database here...
}
In order to grab it you just get that object from the database like any other objects like so:
Let's presume you're doing everything in your controller, which you shouldn't,
public Action GetFile(int id)
{
using(context = new YourDbContext())
{
var file = context.Files.FirstOrDefault(p => p.Id == id);
}
return View(file);
}
And put it's path for the src in html to show the image like so:
<img src="#Model.path" /> //Considering that in your controller you will `return View(file);`
//So your file object is the model.
One more thing, I'm not sure if in paths you'll need \ or /, I always get it wrong the first time so debug it on the first run and if your path looks likeFolder1Folder2Folder3File it means you need to change it :).
I hope this helped, good luck.
P.S., there might be better ways to do it, but this is how I'm doing it and it seams to work fine for me.
On server, you convert image to a base64 string and save to database.
using (Image image = Image.FromFile(Path))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
Beside Client, you put base64 string in Image object
var image = new Image();
image.src = 'data:image/png;base64,your base64 string';
document.body.appendChild(image);
I think store image on the disk better.

Local database "no format for SQL server Compact" after OneDrive download of .sdf file

I upload my database of my app into OneDrive as a .SDF file with this line:
iso.CopyFile(AppResources.DatabaseName + ".sdf", "/shared/transfers/" + databaseBackupname + ".sdf");
LiveConnectClient liveClient = new LiveConnectClient(oneDriveAuthClient.Session);
try
{
LiveOperationResult uploadResult = await liveClient.BackgroundUploadAsync(oneDriveFolderId, new Uri("/shared/transfers/" + databaseBackupname + ".sdf", UriKind.RelativeOrAbsolute), OverwriteOption.Overwrite);
After this I can successfully download this file with this code:
string tmpPathDatabase = "\\shared\\transfers\\downloadedDatabase.sdf";
LiveOperationResult downloadResult = await liveClient.BackgroundDownloadAsync(file.FileID, new Uri(tmpPathDatabase, UriKind.RelativeOrAbsolute));
Until I try to use the file as a database everything works fine. But when I try to use the file in this code:
string tmpDBConnectionString = "Data Source=isostore:" + tmpPathDatabase;
using (DBClass tmpDB = new DBClass(tmpDBConnectionString))
{
if (tmpDB.DatabaseExists() == true)
{
DatabaseSchemaUpdater dbNewUpdater = tmpDB.CreateDatabaseSchemaUpdater();
I get the error message when creating the DatabaseSchemaUpdater:
The file that is being referenced is not a SQL Server Compact database file format
[ Databasename = C:\Data\Users\DefApps\APPDATA\Local\Packages\xxx.TimecardApp_evtaxn4jfh7hw\LocalState\downloadedDatabase.sdf ]
Does the up- or download change the coding of files? Because when I just copy the files in the IsolatedStorage I can use them as databases without any changes. I thought the same about using OneDrive.
It was a noob mistake. Solution is simple:
await liveClient.DownloadAsync(file.FileID + "/content");
Pretty sure it would work with DownloadBackgroundAsync too.
I missed the /content. Thought the fileID would be enough and the Live SDK API knows what to do, when downloading a file (not just getting the properties) The download stream was almost empty. Found this out when I directly uploaded the file again to OneDrive and saw that it was just 2KB big.

Categories