How can I delete an image in my image folder? - c#

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

Related

Upload multiple Images but store in Database only one image

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.

How to create a shared parameter that can be shared when project standards are transferred

I am working on a project where I need to create multiple revit files consisting of wall types and create shared parameters into them. I completed this process.
But on manually clicking on Manage > Transfer Project Standards
Copy from "project name" > Wall Types through the revit interface.
I imported the wall types of different revit files created into one.
But the shared parameters seems to repeat in the type parameter list of the wall type with data in one set and the repeated set has no data.
It looks like the parameters I created are not shareable.
if (Convert.ToString(value) != "")
{
Type type = value.GetType();
string originalFile = uiApp.Application.SharedParametersFilename;
string tempFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) + ".txt";
using (File.Create(tempFile)) { }
uiApp.Application.SharedParametersFilename = tempFile;
try
{
if (ele.LookupParameter(param) == null)
{
ExternalDefinitionCreationOptions edco = null;
if (type.Name.Equals("Double"))
edco = new ExternalDefinitionCreationOptions(param, ParameterType.Number);
else
edco = new ExternalDefinitionCreationOptions(param, ParameterType.Text);
edco.Visible = true;
var definition = uiApp.Application.OpenSharedParameterFile().Groups.Create("Custom Parameters").Definitions.Create(edco);
var newCategorySet = uiApp.Application.Create.NewCategorySet();
newCategorySet.Insert(doc.Settings.Categories.get_Item(BuiltInCategory.OST_Walls));
Autodesk.Revit.DB.Binding binding = uiApp.Application.Create.NewTypeBinding(newCategorySet);
doc.ParameterBindings.Insert(definition, binding, BuiltInParameterGroup.PG_IDENTITY_DATA);
if (!string.IsNullOrEmpty((string)value))
ele.LookupParameter(param).Set((string)value);
}
else
{
if (!string.IsNullOrEmpty((string)value))
ele.LookupParameter(param).Set((string)
}
}
catch (Exception ex)
{
}
finally
{
uiApp.Application.SharedParametersFilename = originalFile;
}
}
Here, this block of code is executed in a loop where "element" is the element into whom the shared parameter needs to be added. "param" is the parameter name and "value" is the value for the parameter. Please let me know if this is the right way to create shared parameter that can be shared when project wall types are transferred to another project.
Thank you
definitely this will happen, as long as you are in a loop, and keeps creating a shared parameter for each file. this will lead to creating unique GUID for each revit file. and when you combine all you will find all the shared parameters with different Guids but with the same name.
you need to create the shared parameter once, then for each revit file, set the sharedparameter file (that is already created with sharedparameter) and get the sharedparameter from it, then assign it to the category you wish for each revit file.
moreinfo about shared parameters here
hope that helps.

Is it possible to access the PPSONE data with the DI SDK from SAP B1?

I try to write a sowftware so the production can easily confirm the material items.
Now when I want to get a production order by a key, it can't find a PO.
If I do the same thing with business partner, it works.
We use the PPS One addon for the SAP B1, so is there the problem? Is it not possible to access the data from this addon or what have I to change?
SAPbobsCOM.BusinessPartners vBP = connection.company.GetBusinessObject(SAPbobsCOM.BoObjectTypes.oBusinessPartners);
SAPbobsCOM.ProductionOrders vPO = connection.company.GetBusinessObject(SAPbobsCOM.BoObjectTypes.oProductionOrders);
if(vBP.GetByKey("L22437"))
{
WriteLogLine("Name: " + vBP.CardName); // Works, i get the Name!
}
else { WriteLogLine("No matching customer record was found!"); }
if (vPO.GetByKey(anyKey)) // tried a lot of keys, no one worked
{
WriteLogLine(vPO.GetAsXML());
}
else { WriteLogLine("No matching production order record was found!"); }
There is also a weird thing, in the SAP GUI the po are displayed as work orders, but the coresponding table in the db is #PPSONE_PRDORDERS. But it works neither if I change from SAPbobsCOM.ProductionOrders to SAPbobsCOM.WorkOrders.
If I understood, it doesn't matter what the addon does if at least it creates a record in the PO table, if you want to find the records of PO's you have to query the OWOR table, the field to use in the GeyByKey method of PO is the OWOR.DocEntry.
If this is a UserTable with no Object ou can use the object UserTable
UserTable oUst = (UserTable)oCompany.UserTables.Item(YOURTABLE);
if oUst.GetByKey("1") ....
If it is a UserTable with Object you have to look for GenericServices
Dim oGeneralService As SAPbobsCOM.GeneralService
Dim oGeneralData As SAPbobsCOM.GeneralData
Dim oGeneralParams As SAPbobsCOM.GeneralDataParams
Dim sCmp As SAPbobsCOM.CompanyService
sCmp = oCompany.GetCompanyService
'Get a handle to the SM_MOR UDO
oGeneralService = sCmp.GetGeneralService("SM_MOR")
'Get UDO record
oGeneralParams = oGeneralService.GetDataInterface(SAPbobsCOM.GeneralServiceDataInterfaces.gsGeneralDataParams)
oGeneralParams.SetProperty("DocEntry", "2")
oGeneralData = oGeneralService.GetByParams(oGeneralParams)
There is a SDK from PPS One you can use. Refere to: C:\Program Files\SAP\SAP Business One\AddOns\PPSOne\PPSOne\X64Client\PPSOne_PPSOneSDK.dll. I don't test it.

certain user(s) can only use a command

Essentially this program allows a user to use a command !weaponrequest, it then saves their request into a list, with !nextweapon you can see what the next weapon in the list is, this allows a streamer to take weapon requests in a game with a fully automated system.
Anyway moving onto my problem, I need a way to make it so that a certain user(s) can only use a command. I know that I am going to need a list to store the users in. I will write them in manually so I don't need any kind of system for that. All I am wondering is using an IF statement how would I check to see if the user is in this list and then make it so that only that user(s) can activate that command and receive a response.
case "nextweapon":
{
if (new FileInfo("MyFile.txt").Length == 0)
{
irc.sendChatMessage("There are no weapons in the list!");
break;
}
string Lines = File.ReadLines("MyFile.txt").Take(1).First();
//irc.sendChatMessage(Lines);
List<string> WeaponList = File.ReadAllLines("MyFile.txt").ToList();
string FirstItem = WeaponList[0];
WeaponList.RemoveAt(0);
File.WriteAllLines("MyFile.txt", WeaponList.ToArray());
irc.sendChatMessage(Lines);
break;
}
This is the command that I want to only be used by a certain user(s).
Add your special users from a source (in-code, text, database, etc.) into a List<string> variable using the List<string>.Add(strUserName) function.
List<string> lstCertainUsers = new List<string>();
/*
* ToDo: Add users from source (in-code, text, database, etc.) into lstCertainUsers
*/
Then, get the list of users and check if it contains the certain user.
// Check if user has access to special commands
if (lstCertainUsers.Contains(strUserName))
{
/* nextweapon code here */
}
if ((username == "") || (username == "") || (username == ""))
{
}
This is how I solved the issue, it's not the most efficient way but there are only limited users that I needed so making a list was not necessary.
Obviously you need to replace the names with your own names you want to be able to use the command. For example:
(username == "RandomStranger")
{
}
You'd read the file into a buffer, split it line-by-line, loop through those lines and break the loop if and when their username is found. I'm not used to C# but the following pseudocode should highlight my idea:
username = /* the current user's username */;
userfile = readfile('users.txt');
userlist = split(userfile, "\n");
is_valid = false;
for user in userlist
if user equals username
command_is_valid = true;
break;
if command_is_valid:
// your code
else
// do nothing
I'm sure there's a better way to do it because, as I say, I'm not used to C#. On another note, MyFile.txt probably isn't the best name for your flat-file database. Hope this helps!

Unregistering datasource and deleting associated CSV file

I'm automating a mailmerge process which uses a CSV file. Part of this process requires creating a database (OpenOffice odb file) and then registering this as a datasource. When I come to delete the database I get an exception stating 'Cannot delete yourFile:It is being used by another person or program'. The problem is that I cannot get the OpenOffice process to release this resource (without killing it). My current code is:
public string DeleteDatasource(string datasourceName)
{
string result = string.Empty;
object databaseContext = _MultiServiceFactory.createInstance("com.sun.star.sdb.DatabaseContext");;
try
{
XDatabaseRegistrations databaseRegistrations = (XDatabaseRegistrations)databaseContext;
if(databaseRegistrations.hasRegisteredDatabase(datasourceName))
{
/* //attempt one
XNameAccess nameAccess = (XNameAccess)OODatabaseContext;
object datasource = nameAccess.getByName(datasourceName);
XNamingService namingservice = (XNamingService)OODatabaseContext;
namingservice.revokeObject(datasourceName);
*/
//attempt 2
string databaseLocation = databaseRegistrations.getDatabaseLocation(datasourceName);
databaseRegistrations.revokeDatabaseLocation(datasourceName);
if (!String.IsNullOrEmpty(databaseLocation))
try
{
//As File Path converts the uno file string into a standard form i.e. "file:///c:/temp/DatabaseFile.odb" to "c:\\temp\\DatabaseFile.odb"
File.Delete(databaseLocation.AsFilepath());
}
catch (System.Exception ex)
{
//some error handling
}
}
return result;
}
catch (System.Exception ex)
{
//More error handling
}
}
Any ideas how I can unregister this datasource such that I can then delete the odb.
Thanks
Managed to get around this issue and just in case anyone else is interested here's how.
The key was to get a reference to the actual datasource and to then dispose of this.
The basic steps are:
Check if a datasource exists with the specified name
Get datasource object
Get the datasource filename
Dispose of the database document associated with the datasource
Dispose the actual datasource
Delete the database file :)
The source code for this looks something like
XNameAccess nameAccess = (XNameAccess)_MultiServiceFactory.createInstance("com.sun.star.sdb.DatabaseContext");
object datasource = nameAccess.getByName(datasourceName);
XDocumentDataSource obj = (XDocumentDataSource)((Any)datasource).Value;
//get the location of the associated odb file before we dispose the document object
//and deregister the datasource
string databaseLocation = databaseRegistrations.getDatabaseLocation(datasourceName);
databaseRegistrations.revokeDatabaseLocation(datasourceName);
((XComponent)obj.DatabaseDocument).dispose();
((XComponent)obj).dispose();
//put in a try block as we want to continue even if this fails
//AsFilepath converts the OpenOffice file path to standard for that can be used with the standard IO file access classes
File.Delete(databaseLocation.AsFilepath());
If there are any improvements please let me know...
Click View,Click Data Sources,
Right Click Registered Databases you wanted to remove,
Click Registered Databases,
Click Delete for the highlighted registered database you want to remove.

Categories