Upload multiple Images but store in Database only one image - c#

How to upload multiple images?
I want to upload multiple images into the database; I select the multiple images and then hit the upload button, but it inserts only one image. Can any expert tell me where I am going wrong?
Image class:
public partial class Image
{
public int imgID { get; set; }
public string ImgPath { get; set; }
public long ProdID { get; set; }
public virtual Product Product { get; set; }
}
Controller:
public ActionResult AddNewProducts(ProductViewModel prod, List file)
{
try
{
List PTlist = _IproductType.PTList();
ViewBag.Ptlist = new SelectList(PTlist, "PType_ID", "P_Name");
// Product Color List
List pColorList = _IProductColor.PColorlist();
ViewBag.pColor_List = new SelectList(pColorList, "C_ID", "C_Name_OR_Code");
List pSizeList = _ISize.pSizeList();
ViewBag.pSizeLists = new SelectList(pSizeList, "S_ID", "S_Size");
string PathDB = string.Empty;
Image img = new Image();
foreach (HttpPostedFileBase files in file)
{
string filename = Path.GetFileName(files.FileName);
string _filename = DateTime.Now.ToString("yymmssff") + filename;
string extension = Path.GetExtension(files.FileName);
string path = Path.Combine(Server.MapPath("~/Upload/"), _filename);
PathDB = "~/Upload/" + _filename;
if (extension.ToLower() == ".jpeg" || extension.ToLower() == ".jpg" || extension.ToLower() == ".png")
{
if (files.ContentLength <= 1000000)
{
img = new Image();
img.imgID = prod.ImgID;
img.ImgPath = PathDB;
img.ProdID = prod.ProductID;
}
else
ViewBag.sizemsg = "Size limit exceeded";
}
else
ViewBag.fileformat = "File is not the correct format";
}
}
}

As you referenced the MCV pattern and used terms like "upload", I am going to asume this is Web Development. I am also asuming your pattern is:
user uploads a bunch of images
you do some processing on the images
you present the processed images, so the user can select one
that one is actually persisted
The "reconsider this path" answer
If you do, that is definitely a bad approach. Transfering bulk data to only actually use a fraction of it? A very common beginners mistake with Web and Database Development. Putting a lot of CPU work on the Server side is another one.
Whatever processing you are doing, you should ideally be doing it on the client side: Browser Plugin. Custom Client Side applicaiton. JavaScript element. Even just demanding a specific format from the user. That sort of thing. And then only upload that specific image.
If the server never has to see a bit from those images you do not want, it is a good design.
Staging table/database
This is the asnwer you are really comited to your approach or it is not a option for some reason. In order to have the server process and display a image, it must be saved on the server side.
In memory is not really an option. With a massively paralell design and ThreadPools of 50-100 Threads per CPU core, WebServers are notoriously easy to run out of resources, particular memory. And that asumes you can actually persist something in memory like that to begin with (the design does not make that easy, to get you off that path).
So the next best bet would be a staging table or temp directory. Something where you can:
store the images you just uploaded
have some background process process them
you can hand the processed images out of
you can transfer the one image the user wants into the proper persistent database
something that is regualry clearing up any data the user never made a decision on
Personally I would advise for a seperate set of DB Tables. In our day, temp direcotiries are a security vulnerability that no admin should accept without looking for alternatives.

Related

How can I delete an image in my image folder?

I can delete an image in my database but not in an image folder.
I want to delete also the image in folder when I delete the row.
public IActionResult Delete(int? id,MotorModel motor)
{
var motors = db.Motors.Find(id);
var filename = motor.Image.FileName;
var delete = Path.Combine(hostEnvironment.WebRootPath, "Image");
var filePath = Path.Combine(delete, filename);
if (motors == null)
{
return View();
}
db.Entry(motors).State = EntityState.Deleted;
if (db.SaveChanges() > 0)
{
if (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
}
return RedirectToAction("Index");
}
return View();
}
I suspect this is because you've made the questionable decision to have a method argument MotorModel motor and a local variable car motors = db.Motors.Find... and you're getting confused as to which motor/motors you're supposed to be using. Xavier is asking you "is anything null?" and you're looking in motors and going "nope, nothing is null" and the code is trying to delete based on motor instead
In my opinion a delete method need only take an id, it should look up what to delete based on that id and remove the file that is tracked by the db. It should not take an id and some other user provided data (motormodel) and delete files based on what it finds in the user provided data. It opens you up to abuse/hacking attempts if you're allowing the user to choose what files to delete arbitrarily by modifying the data provided. On that point too you should verify, given that the is to delete is an int, that the user truly owns the file they are deleting otherwise some script kid will just write a loop that calls Delete(1), Delete(2) ... Delete(10000000) and hose the entire contents of your server, for a laugh
As a style tip, a Find method will only return one entity so the variable to which it is assigned shouldn't have a plural name. Use plurals for collections of items

Entity Framework connection string from .DSN file

I have a problem, so I thought I would come to the brightest minds on the web.
I have written an ASP.NET MVC application that interfaces with a web service provided by another application. My app basically just adds some features to the other web application.
Both applications have a database. I am trying to limit the configuration for my application by using the other applications SQL Server credentials. This is so that if they decide to change the password for the other application, mine will just start working.
These credentials are saved in a .DSN file that my application can reach. How can I get my application, which uses Entity Framework, to use a connection string that is created from the details read in the .DSN file?
I can figure out the code to read the .DSN file, so if you wish to provide some code examples you can base them around setting the connection string for EF.
I am also open to other solutions, or even reasons why I shouldn't do this.
Thanks in advance.
PS. As I was writing this, I came up with a little concept. I am going to test it out now to see how it goes. But here is the basics:
On start up, read the needed details into static properties.
public MyContext() : base(getConnectionString()) { }
3.
private SomeObjectTypeHere getConnectionString()
{
//read static properties
//return .....something..... not sure yet....
}
Thoughts on that maybe?
EDIT
I have created a method that reads the .DSN file and gets the server, the user id and the password. I now have these stored in static properties. In my context, how can I set my connection string now that i have the required details.
So, the biggest issue that I was really having was how to set my connection string in Entity Framework. But I was also hoping that maybe someone else had worked with .DSN files.
Anyway, here was my solution. Still looking for problems that might arise from this, so if you can see any issues, let me know!
First, I created a method that was run on startup. This method ran through the .DSN file and picked out the gems.
Keep in mind that I have never worked with .DSN files, and the section that gets the password is unique to my situation.
var DSNFileContents = File.ReadAllLines(WebConfigurationManager.AppSettings["AppPath"] + #"\App.DSN");//reads DSN into a string array
//get UID
string uid = DSNFileContents.Where(line => line.StartsWith("UID")).First().Substring(4);//get UID from array
//test if uid has quotes around it
if (uid[0] == '"' && uid[uid.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
uid = uid.Substring(1, uid.Length - 2);
}
//get server
string server = DSNFileContents.Where(line => line.StartsWith("SERVER")).First().Substring(7);//get the server from the array
//test if server has quotes around it
if (server[0] == '"' && server[server.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
server = server.Substring(1, server.Length - 2);
}
//THIS WON'T WORK 100% FOR ANYONE ELSE. WILL NEED TO BE ADAPTED
//test if PWD is encoded
string password = "";
if (DSNFileContents.Where(line => line.StartsWith("PWD")).First().StartsWith("PWD=/Crypto:"))
{
string secretkey = "<secret>";
string IV = "<alsoSecret>";
byte[] encoded = Convert.FromBase64String(DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(12));
//THIS LINE IN PARTICULAR WILL NOT WORK AS DecodeSQLPassword is a private method I wrote to break the other applications encryption
password = DecodeSQLPassword(encoded, secretkey, IV);
}
else
{
//password was not encrypted
password = DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(4);
}
//build connection string
SqlConnectionStringBuilder cString = new SqlConnectionStringBuilder();
cString.UserID = uid;
cString.Password = password;
cString.InitialCatalog = "mydatabase";
cString.DataSource = server;
cString.ConnectTimeout = 30;
//statProps is a static class that I have created to hold some variables that are used globally so that I don't have to I/O too much.
statProps.ConnectionString = cString.ConnectionString;
Now that I have the connection string saved, I just have my database Context use it as below,
public class myContext : DbContext
{
public myContext() : base(statProps.ConnectionString) { }
//all my DbSets e.g.
public DbSet<Person> Persons{ get; set; }
}
This is simple, yes, but I hoping that it can provide some information to anyone that was looking to do something similar but was not sure about how it should be handled.
Again, let me know if you like or dislike this solution and if you dislike it, what is your solution and why.
Thanks again!

Xcode Cocoa - Drag Drop from NSTableView to Finder

I want my MacOS App to be able to Drag a item from NSTableView to an other Application like Logic Pro X, Finder, etc.
The items in this TableViews are classes I created which are representing Files on my HD.
public class AudioFile
{
#region Computed Propoperties
public string Filename { get; set; } = "";
public string Filepath { get; set; } = "";
#endregion
public AudioFile()
{
}
public AudioFile(string filename, string filepath)
{
this.Filename = filename;
this.Filepath = filepath;
}
}
Unfortunately I can't find a solution for Swift or Objective-C which I could translate to C# (Xamarin). Does anyone know one or has some code that could help here?
Thanks for your help!
I know nothing about C#, but you asked for a solution in Swift or Objective-C. That I can help with! The below is Swift 4.
First of all, make sure your ViewController is the table view's data source:
class ViewController: NSViewController, NSTableViewDataSource
You will also need to make that connection either in code or in IB.
You then need to set your table view as a dragging source. Choose the operation you want, usually either .move or .copy:
tableView.setDraggingSourceOperationMask(.move, forLocal: false)
This example assumes that you're using an ArrayController to manage the content of the tableView. You really should be, it makes a host of things easier. Also, this example is for dragging multiple files. (It will work for a single file, but there are other approaches if you only ever want to drag one.)
In your ViewController class, implement this method:
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
var filePaths = [String]()
// Swift 4 hack--the FilenamesPboardType is missing
let NSFilenamesPboardTypeTemp = NSPasteboard.PasteboardType("NSFilenamesPboardType")
pboard.addTypes([NSFilenamesPboardTypeTemp], owner: nil)
if let audioFiles = audioFilesArrayController.arrangedObjects as? [AudioFile] {
for i in rowIndexes {
filePaths.append(audioFiles[i].Filepath)
}
}
pboard.setPropertyList(filePaths, forType: NSFilenamesPboardTypeTemp)
return true
}
You can learn more about the NSFilenamesPboardTypeTemp hack here.
And that's it! Recompile and you should be able to move one or more of your files by dragging them to a Finder window. Simple. :-)

Sparx EA .feap projects images saved as blank

In addin for Sparx EA I use this code to get pictures and assign to entity. Then I use images from entities, to, as example, save at some folders or insert in word report etc (from this answer)
/// <summary>
/// Access to diagram image without using clipboard
/// </summary>
/// <param name="projectInterface">Ea Sparx interface</param>
/// <param name="eaDiagramGuid">Guid of the diagramm</param>
/// <returns></returns>
public static Image GetDiagramImage(this Project projectInterface, Guid eaDiagramGuid, ApplicationLogger _logger)
{
Image diagramImage;
try
{
var diagramByGuid = projectInterface.GUIDtoXML(eaDiagramGuid.ToString("B"));
string tempFilename = string.Format("{0}{1}{2}", Path.GetTempPath(), Guid.NewGuid().ToString(), ".png");
bool imageToFileSuccess = projectInterface.PutDiagramImageToFile(diagramByGuid, tempFilename, FileExtensionByName);
if (imageToFileSuccess)
{
using (var imageStream = new MemoryStream(File.ReadAllBytes(tempFilename)))
{
diagramImage = Image.FromStream(imageStream);
}
File.Delete(tempFilename);
}
else
{
throw new Exception(string.Format("Image to file exprot fail {0}", projectInterface.GetLastError()));
}
}
catch (Exception e)
{
throw;
}
return diagramImage;
}
The problem is - it works if project I work with saved as .eap file.
If it's .feap file, which, as I believe means that it works with Firebird database (instead of Access), all saved/exproted to report images are blank, like this down below
Why does it happens and is there workaround?
UPD
It works if I use projectInterface.PutDiagramImageOnClipboard instead but I don't wont to use clipboard at all
UPD 2
After some experiments today at the morning (at my timezone, gmt+3, it's still morning) I found out that the problem was with GUIDs register!
After I decided to apply .toUpper() here
var diagramByGuid = projectInterface.GUIDtoXML(eaDiagramGuid.ToString("B").ToUpper());
it started work fine!
Strange thing thou that if project is *.EAP type everything works even when guid is not in upper register!
UPD3
Well, unfortunately, I was wrong. Some pictures are still blank. But somehow that changes got impact on diagrams, I keep testing this stuff.
And some of the pictures are appeared twice or in wrong place.
But it's kinda interesting (if I could say so) behaviour.
UPD 4
I was wrong in my UPD2 part! GUID can contain down register symbols as well as upper ones.
So, first I removed that part.
What I done next - I started to pass GUID directly from diagram, so signature changed like that
public static Image GetDiagramImage(this Project projectInterface, string eaDiagramGuid, ApplicationLogger _logger)
and eaDiagramGuid should be passed right from EA.Diagram object.
When we parse it as Guid by Guid.Parse(eaDiagramGuid) it convert everything in lowercase like here
so, thats why I got the problem.
But for some reason it was not appeared in *.EAP type of projects!
Also it strange that register matters in that case, really. Seems like GUID in common and GUID in sparx ea are different things!
Okay, as I founded out here, the thing is, in case of *.FEAP all items GUIDs are surprisingly case sensetive.
So, my mistake was to store item GUID as Guid type - when we use Guid.Parse(myGuidString) function and then we converting it back to string - all symbols are appers to be in lowercase.
Also, I got my answer from support (they were surprisingly fast, I really like that)
Hello Danil,
Running over the Stack Overflow - it sounds like it's effectively
answered. The core point is that the Feap files are case sensitive.
To be technical, the collation used for our Firebird databases is case
sensitive.
So, in the Automation script you do need to adhere to the case.
So, I just change things to work directly with GUID string from project item like
Image diagramImage = _eaProjectInterface.GetDiagramImage(diagram.DiagramGUID, _logger);
and function now look like this
public static Image GetDiagramImage(this Project projectInterface, string eaDiagramGuid, ApplicationLogger _logger)
{
Image diagramImage;
try
{
var diagramByGuid = projectInterface.GUIDtoXML(eaDiagramGuid);
string tempFilename = string.Format("{0}{1}{2}", Path.GetTempPath(), Guid.NewGuid().ToString(), ".png");
bool imageToFileSuccess = projectInterface.PutDiagramImageToFile(diagramByGuid, tempFilename, FileExtensionByName);
if (imageToFileSuccess)
{
using (var imageStream = new MemoryStream(File.ReadAllBytes(tempFilename)))
{
diagramImage = Image.FromStream(imageStream);
}
File.Delete(tempFilename);
}
else
{
throw new Exception(string.Format("Image to file exprot fail {0}", projectInterface.GetLastError()));
}
}
catch (Exception e)
{
throw;
}
return diagramImage;
}
So, this means that Sparx EA *.FEAP project GUIDs are NOT really GUIDs but just string-keys (as I assume).
Be careful when your work with them :-)

MVC4 Image optimization caching on demand performance issues

THE QUESTION Is there some .net, ASP, MVC or even IIS optimizations I'm not taking in account? or is this whole approach simply a bad idea?
SCENARIO
The following works 0K
I have an ImageController that allows me to optimize and cache images on the fly.
The actual call looks like this: /image/user/1?width=200&height=200
And the controller itself like this:
[AllowAnonymous] // TODO author/revise
public class ImageController : FileController
{
private FileResult Image(string entity, long id, int? width, int? height, Position? position=null)
{
string file = base.ImageHandler.ImagesPaths(Paths.img, entity, id.ToString()).FirstOrDefault();
if (string.IsNullOrEmpty(file))
{
throw new HttpException(404, "File not found");
}
// implicit else
string extension = Path.GetExtension(file);
System.Drawing.Imaging.ImageFormat oImageFormat = WebFileSystemImageHandler.ImageFormat(extension);
if ((null != width) || (null != height))
{
// vvv Beginning of IS THERE SOMETHING WRONG WITH THIS? vvv
string path = string.Format("{0}{1}/{2}/", Paths.img, entity, id);
string pathServer = Server.MapPath(path);
if (!Directory.Exists(pathServer))
Directory.CreateDirectory(pathServer);
string pattern = "";
if (null != width ) pattern += width.ToString(); // 500
if (null != height) pattern += "x" + height.ToString(); // 500x400, or x400 w/o width
string cache = Directory.GetFiles(pathServer, pattern).FirstOrDefault();
// ^^^ End of IS THERE SOMETHING WRONG WITH THE ABOVE ^^^
if (string.IsNullOrEmpty(cache))
{// no cache? sure let's get you started!
Image oImage = System.Drawing.Image.FromStream( new MemoryStream( System.IO.File.ReadAllBytes(file) ) );
file = Server.MapPath(path + pattern + extension);
Bitmap oBitmap = new Bitmap(oImage);
oBitmap = oBitmap.Adjust(width:width, height:height, position:position);
oBitmap = oBitmap.Compress();
oBitmap.Save(file, oImageFormat);
}
else
file = cache;
}
MemoryStream oStream = new MemoryStream( System.IO.File.ReadAllBytes(file) );
string mime = string.Format("image/{0}", extension.Replace(".", ""));
return new FileContentResult(oStream.ToArray(), mime);
}
Where base.ImageHandler.ImagesPaths basically returns a Directory.GetFiles("{folder}\{entity}\", "{id}.*").FirstOrDefault()
THE PROBLEM When I have a gallery page with multiple of these images, the html renders immediately but the images show empty and start popping 1 by 1 (I imagine this is due to 1 call to the controller per session). I would expect this as expected behavior the 1st run only, but happens every time
As a side-comment:
If your application is using HttpSession, make sure it is either disabled for this Controller or at least read-only, using:
[SessionState(SessionStateBehavior.ReadOnly)]
That way at least 2 requests can execute in parallel.
Also, if the amount of images and sizes will be limited and not too large, you might be able to simplify all this by just using OutputCache both at the client and the server setting (in memory). You'd avoid writing the images to physical storage, and resized output would get reused between users.
I wouldn't advise you use GDI for image resizing at all in MVC, as it's not supported and can cause memory leaks and other issues if not used carefully (see http://weblogs.asp.net/bleroy/archive/2009/12/10/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi.aspx).
You should look at alternatives such as using Windows Imaging Components, or for simplicity and additional features use Imageresizer (http://imageresizing.net/)
Also see bertrand's follow up posts: http://weblogs.asp.net/bleroy/archive/2010/05/03/the-fastest-way-to-resize-images-from-asp-net-and-it-s-more-supported-ish.aspx
and http://weblogs.asp.net/bleroy/archive/2011/10/22/state-of-net-image-resizing-how-does-imageresizer-do.aspx for advice on the various approaches to achieving fast web-based resizing

Categories