Microsoft.ML can't save model because of an illegal path? - c#

Have been playing around with machine learning as of late, made a basic machine learning algorithm. It was working perfectly and then I broke something and now it refuses to save the model.
here's the code:
private static string MODEL_FILEPATH = #"MLModel.zip";
// Create MLContext to be shared across the model creation workflow objects
// Set a random seed for repeatable/deterministic results across multiple trainings.
private static MLContext mlContext = new MLContext(seed: 1);
public static void CreateModel()
{
// Load Data
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<ModelInput>(
path: TRAIN_DATA_FILEPATH,
hasHeader: true,
separatorChar: ',',
allowQuoting: true,
allowSparse: false);
// Build training pipeline
IEstimator<ITransformer> trainingPipeline = BuildTrainingPipeline(mlContext);
// Evaluate quality of Model
//Evaluate(mlContext, trainingDataView, trainingPipeline);
// Train Model
ITransformer mlModel = TrainModel(mlContext, trainingDataView, trainingPipeline);
// Save model
SaveModel(mlContext, mlModel, MODEL_FILEPATH, trainingDataView.Schema);
}
private static void SaveModel(MLContext mlContext, ITransformer mlModel, string
modelRelativePath, DataViewSchema modelInputSchema)
{
try
{
mlContext.Model.Save(mlModel, null, (GetAbsolutePath(modelRelativePath)));
}
catch (Exception e)
{
Console.WriteLine(e.ToString() + "\n" + e.Message + ": " + GetAbsolutePath(modelRelativePath));
}
}
this code was automatically generated, I just removed the comment, added the try catch and specified the model path.
here's the exception:
> Exception thrown: 'System.ArgumentException' in mscorlib.dll
System.ArgumentException: The path is not of a legal form.
at System.IO.Path.NewNormalizePath(String path, Int32 maxPathLength, Boolean expandShortPaths)
at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean
expandShortPaths)
at System.IO.Path.GetFullPathInternal(String path)
at System.IO.Path.GetFullPath(String path)
at System.Diagnostics.FileVersionInfo.GetFullPathWithAssert(String fileName)
at System.Diagnostics.FileVersionInfo.GetVersionInfo(String fileName)
at Microsoft.ML.RepositoryWriter.CreateNew(Stream stream, IExceptionContext ectx, Boolean
useFileSystem)
at Microsoft.ML.ModelOperationsCatalog.Save(ITransformer model, DataViewSchema inputSchema, Stream
stream)
at Microsoft.ML.ModelOperationsCatalog.Save(ITransformer model, DataViewSchema inputSchema, String
filePath)
at MachineLearningTest.ModelBuilder.SaveModel(MLContext mlContext, ITransformer mlModel, String
modelRelativePath, DataViewSchema modelInputSchema) in
C:\Users\Michael\Source\Repos\new\MachineLearingTest\ModelBuilder.cs:line 83
The path is not of a legal form.:
C:\Users\Michael\Source\Repos\new\MachineLearingTest\bin\x64\Debug\MLModel.zip
and this is the file which is supposed to contain the model(it is empty)

Related

ConfigurationManager.OpenMappedExeConfiguration "because it is being used by another process"

I'd like to re-read the MySolution.main.config (my app.config) thanks FileSystemWatcher when users modify it. I built a wrapper called FileWatcher.
Catching OnChanged event with this piece of code
var map = new ExeConfigurationFileMap { ExeConfigFilename = _appConfigFilePath };
var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
raises this exception
System.Configuration.ConfigurationErrorsException HResult=0x80131902
Message=An error occurred loading a configuration file: The process
cannot access the file
'C:\Source\Solutions\MySolution_1.2.3\MySolution\bin\Debug\MySolution.main.config'
because it is being used by another process.
(C:\Source\Solutions\MySolution_1.2.3\MySolution\bin\Debug\MySolution.main.config)
Source=System.Configuration.ConfigurationManager StackTrace: at
System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean
ignoreLocal) in
//src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationSchemaErrors.cs:line
71 at
System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors
schemaErrors) in
//src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/BaseConfigurationRecord.cs:line
3634 at System.Configuration.Configuration..ctor(String
locationSubPath, Type typeConfigHost, Object[]
hostInitConfigurationParams) in
//src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/Configuration.cs:line
75 at
System.Configuration.ClientConfigurationHost.OpenExeConfiguration(ConfigurationFileMap
fileMap, Boolean isMachine, ConfigurationUserLevel userLevel, String
exePath) in
//src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ClientConfigurationHost.cs:line
485 at
System.Configuration.ConfigurationManager.OpenExeConfigurationImpl(ConfigurationFileMap
fileMap, Boolean isMachine, ConfigurationUserLevel userLevel, String
exePath, Boolean preLoad) in
//src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationManager.cs:line
214 at
System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(ExeConfigurationFileMap
fileMap, ConfigurationUserLevel userLevel) in
//src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationManager.cs:line
192 at
Siav.MySolution.Log.ConfigurationUtil.FileWatcher.OnChanged(Object
sender, FileSystemEventArgs e) in
C:\Source\Solutions\MySolution_1.2.3\Siav.MySolution.Log\ConfigurationUtil\FileWatcher.cs:line
60 at System.IO.FileSystemWatcher.OnChanged(FileSystemEventArgs e)
in f:\dd\NDP\fx\src\services\io\system\io\FileSystemWatcher.cs:line
822 at System.IO.FileSystemWatcher.NotifyFileSystemEventArgs(Int32
action, String name) in
f:\dd\NDP\fx\src\services\io\system\io\FileSystemWatcher.cs:line 773
at System.IO.FileSystemWatcher.CompletionStatusChanged(UInt32
errorCode, UInt32 numBytes, NativeOverlapped* overlappedPointer) in
f:\dd\NDP\fx\src\services\io\system\io\FileSystemWatcher.cs:line 594
at
System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32
errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP) in
f:\dd\ndp\clr\src\BCL\system\threading\overlapped.cs:line 121
This exception was originally thrown at this call stack:
System.IO.__Error.WinIOError(int, string) in __error.cs
System.IO.FileStream.Init(string, System.IO.FileMode, System.IO.FileAccess, int, bool, System.IO.FileShare, int,
System.IO.FileOptions,
Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES, string, bool, bool,
bool) in filestream.cs
System.IO.FileStream.FileStream(string, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare) in filestream.cs
System.Configuration.Internal.InternalConfigHost.StaticOpenStreamForRead(string)
in InternalConfigHost.cs
System.Configuration.Internal.InternalConfigHost.System.Configuration.Internal.IInternalConfigHost.OpenStreamForRead(string)
in InternalConfigHost.cs
System.Configuration.ClientConfigurationHost.OpenStreamForRead(string)
in ClientConfigurationHost.cs
System.Configuration.UpdateConfigHost.OpenStreamForRead(string) in UpdateConfigHost.cs
System.Configuration.ImplicitMachineConfigHost.OpenStreamForRead(string)
in ImplicitMachineConfigHost.cs
System.Configuration.BaseConfigurationRecord.InitConfigFromFile() in BaseConfigurationRecord.cs
Inner Exception 1: IOException: The process cannot access the file
'C:\Source\Solutions\MySolution_1.2.3\MySolution\bin\Debug\MySolution.main.config'
because it is being used by another process.
I tried with a simple lock, it doesn't work.
This is the constructor of my wrapper
public FileWatcher(string appConfigFilePath)
{
_appConfigFilePath = appConfigFilePath;
_lastRead = DateTime.MinValue;
var watcher = new FileSystemWatcher(Path.GetDirectoryName(_appConfigFilePath))
{
Filter = Path.GetFileName(_appConfigFilePath),
NotifyFilter = NotifyFilters.LastWrite,
EnableRaisingEvents = true
};
watcher.Changed += OnChanged;
watcher.Error += OnError;
}
Any suggestions?
Thanks
I had to manage some retry to access the file as log4net does. I suggest to you to do the same (log4net source is available on github)

ML.NET Integration in Blazor - Could not load file or assembly 'Microsoft.ML.Vision' The system cannot find the file specified

I am trying to implement ML.NET model into a Blazor server app and it throws this error.
public static class AIModel
{
public enum Label
{
Undefined,
Bolnav,
Sanatos
}
private static string MLNetModelPath = "BlazorTWProject.AiModelMers.zip";
public static readonly Lazy<PredictionEngine<ImageInput, ImageOutput>> PredictEngine = new Lazy<PredictionEngine<ImageInput, ImageOutput>>(AIModel.CreatePredictEngine, true);
public static ImageOutput Predict(ImageInput input)
{
var predEngine = PredictEngine.Value;
return predEngine.Predict(input);
}
private static PredictionEngine<ImageInput, ImageOutput> CreatePredictEngine()
{
MLContext? mlContext = new MLContext();
var thisAssembly = Assembly.GetExecutingAssembly();
var files= thisAssembly.GetManifestResourceNames();
using var stream = thisAssembly.GetManifestResourceStream(MLNetModelPath) ;
ITransformer mlModel = mlContext.Model.Load(stream, out DataViewSchema _);
return mlContext.Model.CreatePredictionEngine<ImageInput, ImageOutput>(mlModel);
}
}
I tried to add the zip file to the embedded resources but nothing worked.
I want to specify that even it does say that it can't find the file, if I change the stream parameter to a non-existing file path, the code throws an System.IO.File error, not System.Reflection.TargetInvocationException.
The problem was I haven't installed all the NuGet Packages required for the model.
After I installed all ML.Vision, ML.ImageAnalytics, ... the problem was solved.

the given path format is not supported; streamwriter

Below are the Stacktrace;
System.NotSupportedException
HResult=0x80131515
Message=The given path's format is not supported.
Source=mscorlib
StackTrace:
at System.Security.Permissions.FileIOPermission.EmulateFileIOPermissionChecks(String fullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access)
at EntryLog.Handlers.StreamEntryLogs.StreamWritter(String log, String foldername) in C:\Users\JNyingi\source\repos\EntryLog\EntryLog\Handlers\StreamEntryLogs.cs:line 31
at EntryLog.EntryLog.LogWarning(String Warning) in C:\Users\JNyingi\source\repos\EntryLog\EntryLog\EntryLog.cs:line 55
at EntryLogConsoleTest.Program.Main(String[] args) in C:\Users\JNyingi\source\repos\EntryLogConsoleTest\EntryLogConsoleTest\Program.cs:line 21
This exception was originally thrown at this call stack:
System.Security.Permissions.FileIOPermission.EmulateFileIOPermissionChecks(string)
System.IO.FileStream.Init(string, System.IO.FileMode, System.IO.FileAccess, int, bool, System.IO.FileShare, int, System.IO.FileOptions, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES, string, bool, bool, bool)
System.IO.FileStream.FileStream(string, System.IO.FileMode, System.IO.FileAccess)
EntryLog.Handlers.StreamEntryLogs.StreamWritter(string, string) in StreamEntryLogs.cs
EntryLog.EntryLog.LogWarning(string) in EntryLog.cs
EntryLogConsoleTest.Program.Main(string[]) in Program.cs
The exception is coming about from the following lines;
string filePath = System.IO.Path.Combine(EntryLog.LogPath.AbsolutePath, currentTimeFilename + " - " + $"{foldername}.log");
var fileStreamer = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
var streamWriter = new StreamWriter(fileStreamer);
The LogPath is obtained by this method;
LogPath = new Uri(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
I have tried all manner of debugging but it always throws the above exception at StreamWriter. Kindly assist me in resolving this. I'm using 4.5.2 .net Framework
FILE PATH
The file path in question is this;
C:\Users\JNyingi\source\repos\EntryLogConsoleTest\EntryLogConsoleTest\bin\Debug
CURRENT TIME AND FOLDER NAME
string currentTimeFilename = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
string foldername = "Log"
the problem is the : in your filename
string currentTimeFilename = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
^
Change it to - or _ or even a . for example and the error disappears
string currentTimeFilename = DateTime.Now.ToString("yyyy-MM-dd HH_mm");
Using ILSpy you can find that the code of the method EmulateFileIOPermissionChecks (which raises the NotSupportedException) is:
internal static void EmulateFileIOPermissionChecks(string fullPath)
{
if (AppContextSwitches.UseLegacyPathHandling || !PathInternal.IsDevice(fullPath))
{
if (PathInternal.HasWildCardCharacters(fullPath))
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars"));
}
if (PathInternal.HasInvalidVolumeSeparator(fullPath))
{
throw new NotSupportedException(Environment.GetResourceString("Argument_PathFormatNotSupported"));
}
}
}
So your path contains invalid chars.
EDIT
If in your settings hours - minutes separator is a colon (see your datetime formatted string), please consider that ':' cannot be used in a path, but after driver letter.

Comparison of two XMLs - "illegal characters in path"

When I try to use Compare function from MS API (XmlDiffPatch), it give me an error "illegal characters in path".
This is my code:
public void CompareXMLStructer(string a, string b)
{
try
{
using (var fs = new FileStream(#"C:\Test\result.xml", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
var diffWriter = XmlWriter.Create(fs);
var xmlDiff = new XmlDiff(XmlDiffOptions.IgnoreChildOrder |
XmlDiffOptions.IgnoreNamespaces |
XmlDiffOptions.IgnorePrefixes);
var identical = xmlDiff.Compare(a, b, false, diffWriter);
MessageBox.Show(identical ? "YES" : "NO");
diffWriter.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Exception:
Exception thrown: 'System.ArgumentException' in mscorlib.dll
System.ArgumentException: Niedozwolone znaki w ścieżce. //<-That means Illegal expresion in path
w System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional)
w System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
w System.IO.Path.GetFullPathInternal(String path)
w System.Xml.XmlResolver.ResolveUri(Uri baseUri, String relativeUri)
w System.Xml.XmlUrlResolver.ResolveUri(Uri baseUri, String relativeUri)
w System.Xml.XmlTextReaderImpl..ctor(String url, XmlNameTable nt)
w System.Xml.XmlTextReader..ctor(String url)
w Microsoft.XmlDiffPatch.XmlDiff.OpenDocuments(String sourceFile, String changedFile, XmlReader& sourceReader, XmlReader& changedReader)
w Microsoft.XmlDiffPatch.XmlDiff.Compare(String sourceFile, String changedFile, Boolean bFragments, XmlWriter diffgramWriter)
w WindowsFormsApplication1.Comparision.CompareXMLStructer(String a, String b) w C:\Users\zos-srv\documents\visual studio 2015\Projects\Porownywarka\WindowsFormsApplication1\Comparision.cs:wiersz 44
The thread 0x1334 has exited with code 0 (0x0).
Can it be caused by \r, \n etc. in my string or maybe encoding is wrong?
string:
a "<?xml version=\"1.0\" encoding=\"Windows-1250\"?>\r\n<Dokument idDokumentu=\"6183457\" numer=\"32178.2015\" idSprawy=\"6187041\" wersja=\"1\" dataDokumentu=\"2015-09-09T00:00:00\" numerObcy=\"\" rodzajObcy=\"\" idObcy=\"\" vidObcy=\"\" wersjonowanie=\"0\" statusBIP=\"E\" korespSystemWew=\"N\" nrWgRejestru=\"\" system=\"EDOKUMENT\" oznWysylka=\"true\" wysylka=\"false\" odbiorOsobisty=\"false\" kopia=\"false\" kodKreskowy=\"\" dostep=\"1\" format=\"\" typ_dublin_core_metadata=\"8\" rwa=\"0003\" znakDokumentu=\"\" obcy=\"false\" odwzorowanie=\"\" znak_sprawy_alt=\"\" kat_arch=\"A\" idDokumentuPierw=\"0\" numerWSprawie=\"4\" czySaUwagi=\"false\" ntas=\"false\" idSkladuChronologicznego=\"0\" zatwierdzonyUzytk=\"true\">\r\n <Opis>\r\n <![CDATA[Testowy dokument]]>\r\n </Opis>\r\n <Notatka>\r\n <![CDATA[]]>\r\n </Notatka>\r\n <Typ idTypu=\"12938\" nazwa=\"OR Inne\" kategoriaBIP=\"\" sciezkaBIP=\"\" podlegaZatwierdzaniu=\"true\" czyBip=\"false\"/>\r\n <Status idStatusu=\"0\" nazwa=\"\"/>\r\n <Podmiot idPodmiotu=\"6183458\" typPodmiotu=\"G\" idPodmiotuExt=\"5573\" rodzajPodmiotu=\"K\" imie=\"\" nazwisko=\"\" nazwaFirmy=\"Rekord Systemy Informatyczne Sp.z o.o.\" nazwaSkroconaFirmy=\"REKORD\" PESEL=\"\" NIP=\"\" REGON=\"\" idZewnetrzne=\"\" rodzajPodmiotuExt=\"F\" email=\"\">\r\n <Adres kodPocztowy=\"43-300\" miasto=\"Bielsko-Biała\" ulica=\"Kasprowicza\" numerDomu=\"5\" numerLokalu=\"\" kraj=\"Polska\" adresSkrytki=\"\" dzielnica=\"\" skrytkaPocztowa=\"\" adresZagraniczny=\"false\"/>\r\n </Podmiot>\r\n <Folder idFolderu=\"4823\" nazwa=\"MIROSŁAW ZIAJA\"/>\r\n <Utworzenie symbolPracownika=\"216\" nazwisko=\"ZIAJA\" imie=\"MIROSŁAW\" data=\"2015-09-09T11:48:36\"/>\r\n <Dysponenci>\r\n <Dysponent ident=\"6183461\" symbolPrac=\"216\" nazwisko=\"MIROSŁAW ZIAJA\" imie=\"\" wiodacy=\"true\" tylko.do.odczytu=\"false\" obcyId=\"\" obcyLogin=\"\" stanowisko=\"Inspektor (OR-o)\" rodzaj=\"P\"/>\r\n </Dysponenci>\r\n <Zatwierdzenia>\r\n <Zatwierdzenie data=\"2015-09-14T14:24:44\" rodzaj=\"1\" czyBlokuje=\"true\" kierownicze=\"false\">\r\n <Pracownik symbolPracownika=\"216\" nazwisko=\"ZIAJA\" imie=\"MIROSŁAW\" stanowisko=\"\" stanowiskoIdent=\"0\" pracIdent=\"216\" funkcjaIdent=\"0\"/>\r\n </Zatwierdzenie>\r\n </Zatwierdzenia>\r\n</Dokument>\r\n"
As you can read in the stack trace, the first two strings of xmlDiff.Compare(string, string, ...) accept paths, not XML strings.
I don't know where the documentation for this library resides, so I don't know whether there are Stream overloads, for example. If there aren't, just temporarily write the files to disk.

How to pass parameters for a managed code dll in installshield?

I have a dotnet script which is for encryption and decryption. I have to pass the parameters for the setvalues function in installshield. How can I achieve this? Dotnet code is as follows. I have the assembly (.dll) file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Security;
using System.Xml;
using System.Collections.Specialized;
namespace EncryptionDecryption
{
public class EncrptionHelper
{
#region Member variables
static byte[] entropy = { 0, 8, 2, 3, 5 };
#endregion
#region Public Methods
public static void SetValue(string configFilePathName, string appSettingKey, string appSettingValue)
{
appSettingValue = EncryptString(ToSecureString(appSettingValue));
SetSetting(appSettingKey, appSettingValue, configFilePathName);
}
public static string GetValue(string configFilePathName, string appSettingKey)
{
string value = GetSetting(appSettingKey, configFilePathName);
value = ToInsecureString( DecryptString(value));
return value;
}
#endregion
#region Private Methods
private static bool SetSetting(string Key, string Value, string configFilePath)
{
bool result = false;
try
{
// System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(configFilePath);
// config.AppSettings.File = configFilePath;
// config.AppSettings.Settings[Key].Value = Value;
// config.Save(ConfigurationSaveMode.Modified);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(configFilePath);
xmlDoc.SelectSingleNode("//appSettings/add[#key='" + Key +"']").Attributes["value"].Value = Value;
xmlDoc.Save(configFilePath);
ConfigurationManager.RefreshSection("appSettings");
result = true;
}
finally
{ }
return result;
}
private static string GetSetting(string Key, string configFilePath)
{
string result = null;
try
{
XmlDocument appSettingsDoc = new XmlDocument();
appSettingsDoc.Load(configFilePath);
XmlNode node = appSettingsDoc.SelectSingleNode("//appSettings");
XmlElement value = (XmlElement)node.SelectSingleNode(string.Format("//add[#key='" + Key + "']"));
result = (value.GetAttribute("value").ToString());
}
finally
{ }
return result;
}
private static SecureString ToSecureString(string input)
{
SecureString secure = new SecureString();
foreach (char c in input)
{
secure.AppendChar(c);
}
secure.MakeReadOnly();
return secure;
}
private static string ToInsecureString(SecureString input)
{
string returnValue = string.Empty;
IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
try
{
returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
return returnValue;
}
private static string EncryptString(System.Security.SecureString input)
{
byte[] encryptedData = System.Security.Cryptography.ProtectedData.Protect(
System.Text.Encoding.Unicode.GetBytes(ToInsecureString(input)), entropy, System.Security.Cryptography.DataProtectionScope.CurrentUser);
return Convert.ToBase64String(encryptedData);
}
private static SecureString DecryptString(string encryptedData)
{
try
{
byte[] decryptedData = System.Security.Cryptography.ProtectedData.Unprotect(
Convert.FromBase64String(encryptedData),
entropy,
System.Security.Cryptography.DataProtectionScope.CurrentUser);
return ToSecureString(System.Text.Encoding.Unicode.GetString(decryptedData));
}
catch
{
return new SecureString();
}
}
#endregion
}
}
Update: Action start 14:31:36: Encryption.
MSI (c) (84:40) [14:31:36:525]: Invoking remote custom action. DLL: C:\Users\<username>\AppData\Local\Temp\MSIE259.tmp, Entrypoint: m1
InstallShield: Attempting to load through CLR 4 APIs...
InstallShield: Getting meta host...
InstallShield: Enumerating available runtimes...
InstallShield: Highest available runtime: v4.0.30319
InstallShield: Trying to use highest runtime...
InstallShield: Using highest version runtime...
InstallShield: Loading assembly Security.Encryption from resource 4097
InstallShield: Calling method with parameters [(System.String)C:\Program Files (x86)\<Installdir>\<configfilename>.config, (System.String)VWFPassword, (System.String)]
InstallShield: Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Program Files (x86)\<Installdir>\<configfilename>.config'.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
at System.Xml.XmlDownloadManager.GetStream(Uri uri, ICredentials credentials, IWebProxy proxy, RequestCachePolicy cachePolicy)
at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn)
at System.Xml.XmlTextReaderImpl.OpenUrlDelegate(Object xmlResolver)
at System.Threading.CompressedStack.runTryCode(Object userData)
at
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.CompressedStack.Run(CompressedStack compressedStack, ContextCallback callback, Object state)
at System.Xml.XmlTextReaderImpl.OpenUrl()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlLoader.Load(XmlDocument doc, XmlReader reader, Boolean preserveWhitespace)
at System.Xml.XmlDocument.Load(XmlReader reader)
at System.Xml.XmlDocument.Load(String filename)
at Security.Encryption.EncrptionHelper.SetSetting(String appSettingKey, String appsettingValue, String configFilePathName)
at Security.Encryption.EncrptionHelper.SetValue(String configFilePathName, String appSettingKey, String appSettingValue)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at InstallShield.ClrHelper.CustomActionHelper.CallMethod(EntryPointInfo info)
at InstallShield.ClrHelper.CustomActionHelper.RunAction(UInt32 installHandle, Int32 entryNumber, Int64 instanceHandle)
InstallShield: Managed code threw an unhandled exception.
This is the error I receive after doing all that is mentioned in the screenshots below and doing some R&D. The directory mentioned "C:\Program Files (x86)\\.config" exists when the encryption custiom action is being called but it throws an exception.
Yes, it can be done with following steps:
1- write your required functionality in c# installer class (make sure your are using installer class)
2- Compile and add your dll into installshield (recomended create a separate component for this dll)
3- Select component view -> select above component and go to .Net settings section, set the ".Net Installer class" to true. Set the ".net installer class parameters"
Parameters are passed as key/value pair e.g
/targetDirectory="[INSTALLDIR]\"
All steps are same, just added screenshots.
Create a dll with an installer class and your encrypt/decrypt class.
Add dll and config file to component(above mentioned), if config file is already added to some other component then its fine. no need to add again.
I have added and retrieved INSTALLDIR variable as argument which is predefined. if you want to receive some input from user (from some custom textboxes) then you will need to define your own variables to store and pass values as arguments.
Creating dll with installer class and your requred logic for other task
Creating component and adding files
Mark the dll as installer class and pass arguments
Here goes installer class:
using System;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.ComponentModel;
using System.Configuration.Install;
using System.Collections.Generic;
namespace EncryptionDecryption
{
[RunInstaller(true)]
public class InstallerClassDemo : Installer
{
private string installationDirectory=string.Empty;
private string testString=string.Empty ;
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
try
{
//For testing purpose only.. work only in debug mode when pdb files are deployed as well.
//Debugger.Break();
installationDirectory = Context.Parameters["INSTALLDIR"];
//I believe, the config file must be located in the installation directory if so, then use the following way to compute path
string configFilePath = Path.Combine(installationDirectory, "myConfigFile.config");
EncrptionHelper.SetValue(configFilePath, "testKey", "testValue");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
protected override void OnCommitted(System.Collections.IDictionary savedState)
{
base.OnCommitted(savedState);
}
public override void Uninstall(System.Collections.IDictionary savedState)
{
base.Uninstall(savedState);
}
}
}
I think installshield cannot (or need extra work) for read your assemblies, but you can run simple console application which consume your assemblies from installscript and passing parameter from installshield.
Create simple console application
Include console application on Support Files
Copy to installation folder or assemblies location, so console application can access your assemblies
Launch from installscript using launchappandwait
If consoleapp.exe not use anymore, just delete it.

Categories