Can I grab the project output app.config file in the XML file Changes area of InstallShield 2012? - app-config

I need to change a couple paths from the debug/testing App.config files to their final home on the end user's machine. I see the XML File Changes option when editing the Installer project through Visual studio, and the help indicates I should Import the xml file to be changed.
BUT...
Is there any way to import the output of the project for the XML file? If I browse directly to the file itself I have to use the Debug or Release config file, which seems like it would be annoying. Otherwise I could use the base App.config but if any transformations are applied when building they'd be lost.
So am I stuck with just browsing to a file, or can I grab the "Project Output" somehow like I can for the .exe file?

XML File Changes is pretty weak tea.
To do what you are looking for your going to have to create a custom action that loads the .config file and updates it outside of InstallShield.
If you are using 2012 C# Wizard project type an option should be to create a .rul that catches the OnEnd() event in After Move Data. From the .rul call into a dll via UseDLL and invoke a method that accepts the target path to the config and the value to update the value to.
The following is code I'm testing so...
Using a C# Wizard project type I added the following InstallScript rule to call into a C# dll:
function OnEnd()
string basePath;
BOOL bResult;
string dllPath;
OBJECT oAppConfig;
begin
dllPath = TARGETDIR ^ APPCONFIG_DLL;
try
set oAppConfig = DotNetCoCreateObject(dllPath, "AppConfig.ConfigMgr", "");
catch
MessageBox("Error Loading" + dllPath + ": " + Err.Description, INFORMATION);
abort;
endcatch;
try
basePath = "C:\\Program Files (x86)\\MyCompany\\Config Test\\";
bResult = oAppConfig.ConfigureSettings(basePath + "appsettings.xml", basePath + "app.config", "someAppSection");
catch
MessageBox("Error calling ConfigureSettings " + dllPath + " " + Err.Number + " " + Err.Description, INFORMATION);
endcatch;
end;
C# test code:
public bool ConfigureSettings(string configFilePath, string targetAppConfigPath, string targetAppName)
{
bool completed = true;
try
{
XmlDocument configFileDoc = new XmlDocument();
configFileDoc.Load(configFilePath);
string installerTargetFileDoc = targetAppConfigPath; // InstallShield's build process for Visual Studio solutions does not rename the app.config file - Awesome!
System.IO.FileInfo fi = new System.IO.FileInfo(installerTargetFileDoc);
if (fi.Exists == false) installerTargetFileDoc = "app.config";
XmlDocument targetAppConfigDoc = new XmlDocument();
targetAppConfigDoc.Load(installerTargetFileDoc);
// ensure all required keys exist in the target .config file
AddRequiredKeys(configFileDoc.SelectSingleNode("configuration/" + targetAppName + "/requiredKeys"), ref targetAppConfigDoc);
// loop through each key in the common section of the configuration file
AddKeyValues(configFileDoc.SelectSingleNode("configuration/common/appSettings"), ref targetAppConfigDoc);
// loop through each key in the app specific section of the configuration file - it will override the standard configuration
AddKeyValues(configFileDoc.SelectSingleNode("configuration/" + targetAppName + "/appSettings"), ref targetAppConfigDoc);
// save it off
targetAppConfigDoc.Save(targetAppConfigPath);
}
catch (Exception ex)
{
completed = false;
throw ex;
}
return completed;
}
private void AddKeyValues(XmlNode configAppNodeSet, ref XmlDocument targetAppConfigDoc)
{
foreach (XmlNode configNode in configAppNodeSet.SelectNodes("add"))
{
XmlNode targetNode = targetAppConfigDoc.SelectSingleNode("configuration/appSettings/add[#key='" + configNode.Attributes["key"].Value + "']");
if (targetNode != null)
{
targetNode.Attributes["value"].Value = configNode.Attributes["value"].Value;
}
}
}
private void AddRequiredKeys(XmlNode targetAppNodeSet, ref XmlDocument targetAppConfigDoc)
{
foreach (XmlNode targetNode in targetAppNodeSet.SelectNodes("key"))
{
// add the key if it doesn't already exist
XmlNode appNode = targetAppConfigDoc.SelectSingleNode("configuration/appSettings/add[#key='" + targetNode.Attributes["value"].Value + "']");
if (appNode == null)
{
appNode = targetAppConfigDoc.SelectSingleNode("configuration/appSettings");
XmlNode newAddNode = targetAppConfigDoc.CreateNode(XmlNodeType.Element, "add", null);
XmlAttribute newAddNodeKey = targetAppConfigDoc.CreateAttribute("key");
newAddNodeKey.Value = targetNode.Attributes["value"].Value;
XmlAttribute newAddNodeValue = targetAppConfigDoc.CreateAttribute("value");
newAddNodeValue.Value = "NotSet";
newAddNode.Attributes.Append(newAddNodeKey);
newAddNode.Attributes.Append(newAddNodeValue);
appNode.AppendChild(newAddNode);
}
}
}

While it seems like it should work, Installshield is unable to grok project output correctly (dependencies are missed often, merge modules are duplicated even when they dont apply), or give you a way to deal with individual files in project output.
I have no less than 5 bugs open with them about problems using project output and their workaround is always "Add the files manually".
If you are just getting started with install shield, I suggest you try another alternative. If you have to use it, either complain about this not working to their support team and use the suggested workaround until they get it together.
This may not be the "answer" to your question, but hopefully helps your sanity when dealing with the broken feature set in this product.

You can import any file you want (by browsing), and make changes to it in any run-time location you like. I suggest just putting the minimal amount you need to make your changes; after all it's the XML File Changes view. That way most updates to the file won't cause or require any changes to your XML File Changes settings, no matter how it's included.

Related

Best practices for file system of application data JavaFX

I am trying to build an inventory management system and have recently asked a question about how to be able to store images in a package within my src file. I was told that you should not store images where class files are stored but have not been told what the best practices are for file systems. I have created a new page that allows the user to input all the data about a new part that they are adding to the system and upload an image associated with the part. When they save, everything worked fine until you try to reload the parts database. If you 'refresh' eclipse and then update the database, everything was fine because you could see the image pop into the package when refreshed. (All database info was updated properly as well.
I was told not to store these types of 'new' images with the program files but to create a separate file system to store these types of images. Is there a best practice for these types of file systems? My confusion is when the program gets saved where ever it is going to be saved, I can't have it point to an absolute path because it might not be saved on a C drive or K drive and I wouldn't want an images folder just sitting on the C drive that has all of the parts images for anyone to mess with. Please give me some good resources on how to build these file systems. I would like the images folder 'packaged' with the program when I compile it and package all the files together, I have not been able to find any good information on this, thanks!
To answer this question, probably not in the best way, but works pretty well.
I ended up making another menuItem and menu that you can see at the top 'Image Management', where it lets the user set the location that they would like to save all the images as well as a location to back up the images. it creates the directory if it is not there or it will save over the images if the directory is already there. This menu will only appear if the user has admin privileges. I would think that this could be set up with an install wizard, but I have no idea how to make one, where it only runs on installation. I am also going to add an autosave feature to save to both locations if a backup location has been set. This is the best way I can think of managing all the parts images, if anyone has some good input, please let me know. I considered a server, but think that is too much for this application and retrieving images every time the tableView populates would take a lot of time. If interested the code I used is:
public class ImageDirectoryController implements Initializable{
#FXML private AnchorPane imageDirectory;
#FXML private Label imageDirLbl, backupLbl;
#FXML private Button setLocationButton, backupButton;
#FXML private TextField imageDirPathTxtField;
Stage window;
String image_directory;
#Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
public void setImageDirectory(String image_address, String backup_address) {
imageDirLbl.setText(image_address);
backupLbl.setText(backup_address);
}
#FXML
public void setLocationButtonClicked () {
String imagesPath = imageDirPathTxtField.getText() + "tolmarImages\\";
File files = new File(imagesPath + "asepticImages");
File generalFiles = new File(imagesPath + "generalImages");
File facilitiesFiles = new File(imagesPath + "facilitiesImages");
boolean answer = ConfirmBox.display("Set Image", "Are you sure you want to set this location?");
if(answer) {
if (!files.exists()) {
if (files.mkdirs() && generalFiles.mkdirs() && facilitiesFiles.mkdirs()) {
JOptionPane.showMessageDialog (null, "New Image directories have been created!", "Image directory created", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog (null, "Failed to create multiple directories!", "Image directory not created", JOptionPane.INFORMATION_MESSAGE);
}
}
DBConnection dBC = new DBConnection();
Connection con = dBC.getDBConnection();
String updateStmt = "UPDATE image_address SET image_address = ? WHERE rowid = ?";
try {
PreparedStatement myStmt = con.prepareStatement(updateStmt);
myStmt.setString(1, imageDirPathTxtField.getText());
myStmt.setInt(2, 1);
myStmt.executeUpdate();
myStmt.close();
imageDirPathTxtField.clear();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#FXML
public void backupButtonClicked () {
String backupStatus = null;
if (backupLbl.getText().equals("")&& !imageDirPathTxtField.getText().equals("")) {
backupStatus = imageDirPathTxtField.getText();
} else if (!imageDirPathTxtField.getText().equals("")) {
backupStatus = imageDirPathTxtField.getText();
} else if (!backupLbl.getText().equals("")){
backupStatus = backupLbl.getText();
} else {
JOptionPane.showMessageDialog(null, "You must create a directory.", "No directory created", JOptionPane.INFORMATION_MESSAGE);
return;
}
boolean answer = ConfirmBox.display("Set Image", "Are you sure you want to backup the images?");
if(answer) {
DBConnection dBC = new DBConnection();
Connection con = dBC.getDBConnection();
String updateStmt = "UPDATE image_address SET image_address = ? WHERE rowid = 2";
try {
PreparedStatement myStmt = con.prepareStatement(updateStmt);
myStmt.setString(1, backupStatus);
myStmt.executeUpdate();
myStmt.close();
String source = imageDirLbl.getText() + "tolmarImages";
File srcDir = new File(source);
String destination = backupStatus + "tolmarImages";
File destDir = new File(destination);
try {
FileUtils.copyDirectory(srcDir, destDir);
JOptionPane.showMessageDialog(null, "Images copied successfully.", "Images copied", JOptionPane.INFORMATION_MESSAGE);
} catch (IOException e) {
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

Can't read file without additional prefix on Intellij

I have met some strange trouble with reading file at Intellij Idea and on Windows 8.1.
And always I got FileNotFoundException.
Here is code snippet:
public XlsReader(String fileName, String sheetName) {
open(fileName, sheetName);
}
public void open(String fileName, String sheetName) {
InputStream fis = null;
try {
if (sheetName == null || sheetName.isEmpty()) {
throw new IllegalArgumentException("Please, provide sheet name");
}
Logger.logDebug("PATH: " + new File(".").getAbsolutePath());
fis = new FileInputStream(fileName);
String resourceFilePath = this.getClass().getResource(fileName).getFile();
Logger.logDebug(resourceFilePath);
fis = new FileInputStream(resourceFilePath);
XSSFWorkbook workBook = new XSSFWorkbook(fis);
sheet = workBook.getSheet(sheetName);
getMetaData();
I couldn't understand why at this line:
new FileInputStream(fileName)
I have got this exception.
And when chcenging path from:
xls = new XlsReader("InputDataIndirect.xlsx", "Calculator");
to:
xls = new XlsReader("test/InputDataIndirect.xlsx", "Calculator");
And it works now.
Here is project struckture:
I tried to load file from class path as well this.getClass().getResource(fileName).getFile() but it wasn't successful.
Any suggestions?
If you're running a main method or test from inside IntelliJ idea, it uses the root of the project as the root to load files from. Therefore, it will look under new_automation, so you need to add the test folder to your path.
To change this, you can change the working directory location in your run configuration to the location you want it to look in for files.

app.Config file entries are cleared on Repair installed Setup

I have created a Setup Project for my Project. This project connects to a live DB server through asmx services. That URL will be determined after the client will deploy the web services on some server. So in setup project i have added a "TextBoxes" dialog in User Interface Editor section of the Setup Project where i have enabled only one TextBox to get the URL of the deployed Services. In my project i have added a file to be executed during Setup installation and i have defined it as follows:
[RunInstaller(true)]
public class InstallerHelper : System.Configuration.Install.Installer
{
// Other Code also exists that is not needed to be shown here<br/>
//.....
// The following method gets executed during setup installation
public override void Install(IDictionary stateSaver)
{
try
{
base.Install(stateSaver);
//Proceed only if the Context object has some parameters
if (Context.Parameters.Count != 0 && !string.IsNullOrEmpty(Context.Parameters["WEBSITEURL"]))
{
//Get the installation Folder's Path
string installationFolder = Context.Parameters["INSTALLFOLDER"];
// Get the Site's URL entered by Client
string websiteUrl = Context.Parameters["WEBSITEURL"];
//Create different Key Value pairs based on entered URL
string[][] keyValues = {
new string[] {"SiteUrl",websiteUrl},
new string[] {"WebServiceURL", websiteUrl + "Users.asmx" },
new string[] {"TicketsServiceURL", websiteUrl + "Tickets.asmx"},
new string[] {"CampaignsAndProjetcsServiceURL", websiteUrl + "CampaignsAndProjetcs.asmx"},
new string[] {"EntitiesURL", websiteUrl + "Entities.asmx"},
new string[] {"AccountsURL", websiteUrl + "Accounts.asmx"},
new string[] {"TransactionsURL", websiteUrl + "Transactions.asmx"},
new string[] {"RelatedReportsURL", websiteUrl + "RelatedReports.asmx"},
new string[] {"GiftAidsURL", websiteUrl + "GiftAids.asmx"}
};
// Load the app.Config file and store these values in it.
//********************************************
string configFilePath = installationFolder + #"\MyProject.exe.config";
XmlDocument configuration = new XmlDocument();
// Load App.Config File
configuration.Load(configFilePath);
//Add the values in it
Utility.UpdateValue(keyValues, configuration);
//Save configuration File
configuration.Save(configFilePath);
//********************************************<br/>
}
}
catch (Exception ex)
{
throw new InstallException("The following Error(s) occured during installation. \n " + ex.Message);
}
}
}
Here i Store the entered URL and some other generated URLs of different web services in App.Config of the Project to be used in Project for accessing data.
It works fine when i install a fresh copy of the Setup, but problem occurs when i try to Repair the installed project by again executing the Setup.exe file.
Repair process does not asks me to enter the URL again and also the Items stored in App.Config during first time installation are lost. So the whole application stops working.
Any help is greatly appreciated
A good approach is to save this custom information somewhere and retrieve it during maintenance using searches:
create some string registry entries which contain your custom properties; the registry entry value can be something like:
[WEBSITEURL]
create registry searches which read these entries and save them in your custom properties; for this use the property names for the actual searches
This way a repair will read the property values from registry and restore your original properties.
Both the Registry Editor and Launch Conditions Editor can be opened by selecting your setup project in Solution Explorer and clicking the appropriate button on its top pane.

Sharepoint 2010 Upload file using Silverlight 4.0

I am trying to do a file upload from Silverlight(Client Object Model) to Sharepoint 2010 library.. Please see the code below..
try{
context = new ClientContext("http://deepu-pc/");
web = context.Web;
context.Load(web);
OpenFileDialog oFileDialog = new OpenFileDialog();
oFileDialog.FilterIndex = 1;
oFileDialog.Multiselect = false;
if (oFileDialog.ShowDialog().Value == true)
{
var localFile = new FileCreationInformation();
localFile.Content = System.IO.File.ReadAllBytes(oFileDialog.File.FullName);
localFile.Url = System.IO.Path.GetFileName(oFileDialog.File.Name);
List docs = web.Lists.GetByTitle("Gallery");
context.Load(docs);
File file = docs.RootFolder.Files.Add(localFile);
context.Load(file);
context.ExecuteQueryAsync(OnSiteLoadSuccess, OnSiteLoadFailure);
}
}
catch (Exception exp)
{
MessageBox.Show(exp.ToString());
}
But I am getting the following error
System.Security.SecurityException: File operation not permitted. Access to path '' is denied.
at System.IO.FileSecurityState.EnsureState()
at System.IO.FileSystemInfo.get_FullName()
at ImageUploadSilverlight.MainPage.FileUpload_Click(Object sender, RoutedEventArgs e)
Any help would be appreciated
Thanks
Deepu
Silverlight runs with very restricted access to the client user's filesystem. When using an open-file dialog, you can get the name of the selected file within its parent folder, the length of the file, and a stream from which to read the data in the file, but not much more than that. You can't read the full path of the file selected, and you are getting the exception because you are attempting to do precisely that.
If you want to read the entire content of the file into a byte array, you'll have to replace the line
localFile.Content = System.IO.File.ReadAllBytes(oFileDialog.File.FullName);
with something like
localFile.content = ReadFully(oFileDialog.File.OpenRead());
The ReadFully method reads the entire content of a stream into a byte array. It's not a standard Silverlight method; instead it
is taken from this answer. (I gave this method a quick test on Silverlight, and it appears to work.)

Setting PathAnnotation on SSIS path from code

I have been trying lately to create SSIS packages from .NET code rather than using drag and drop in Visual Studio. As part of the package documentation, I would like to be able to annotate data flow paths.
The code below - copied from MSDN - establishes a path between two SSIS data flow components. By adding
path.Name = "My name";
new Application().SaveToSqlServer(package, null, "localhost", "myUser", "myPassword");
I can set the name of the path to whatever I like and then save the package in my local SQL Server. When I open the package in Visual Studio 2008, however, the name of the path can only be seen under path properties.
In Visual Studio, there is another path property, PathAnnotation, with the value AsNeeded and additional possibilities SourceName, PathName, Never. Changing the value to PathName gives me what I want: The path name appears next to the path in the data flow tab in Visual Studio.
My question is: Is it possible to set the value of the PathAnnotation property from code?
using System;
using Microsoft.SqlServer.Dts.Runtime;
using Microsoft.SqlServer.Dts.Pipeline;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
namespace Microsoft.SqlServer.Dts.Samples
{
class Program
{
static void Main(string[] args)
{
Package package = new Package();
Executable e = package.Executables.Add("STOCK:PipelineTask");
TaskHost thMainPipe = e as TaskHost;
MainPipe dataFlowTask = thMainPipe.InnerObject as MainPipe;
// Create the source component.
IDTSComponentMetaData100 source =
dataFlowTask.ComponentMetaDataCollection.New();
source.ComponentClassID = "DTSAdapter.OleDbSource";
CManagedComponentWrapper srcDesignTime = source.Instantiate();
srcDesignTime.ProvideComponentProperties();
// Create the destination component.
IDTSComponentMetaData100 destination =
dataFlowTask.ComponentMetaDataCollection.New();
destination.ComponentClassID = "DTSAdapter.OleDbDestination";
CManagedComponentWrapper destDesignTime = destination.Instantiate();
destDesignTime.ProvideComponentProperties();
// Create the path.
IDTSPath100 path = dataFlowTask.PathCollection.New();
path.AttachPathAndPropagateNotifications(source.OutputCollection[0],
destination.InputCollection[0]);
}
}
I succeeded in getting an answer in a different forum. Please see
http://social.msdn.microsoft.com/Forums/en-US/sqlintegrationservices/thread/23e6a43f-911f-44da-8e69-cd9e53d7e5ed

Resources