问题
I have written a C# custom action for my WIX V3 Installer which is supposed to modify my appsettings.json in the INSTALLFOLDER. The action´s Execute-attribute is set to immediate and Impersonate="no",it is called after InstallFinalize but it encounters a problem within this action which is the missing admin permission. The action modifies appsettings.json in the INSTALLFOLDER which is Program File (x86).
The custom action reads, deserializes, modifies, and serializes the data normally with no error. The error happens during writing to appsettings.json in InstallFolder. Although the error appears the rest of the application is installed and is working fine.
I have tried combining Execute and Custom actions in ALL possible combinations, and while I get privileges to write to InstallFolder if I change the Custom Action to run before the installation is finished I can't find the appsettings.json file because all the files at that point are temporary files (.tmp), and with non-relevant names.
The error that appears: Error message
Part of my Product.wsx code:
<Property Id="Password" Value="Error password" />
<Property Id="FilePath" Value="C:\Program Files (x86)\Company\Product\" />
<CustomAction Id="SetUserName" Property="Username" Value="[ACCOUNT]"/>
<CustomAction Id="SetPassword" Property="Password" Value="[PASSWORD]"/>
<CustomAction Id="SetFilePath" Property="FilePath" Value="[INSTALLFOLDER]"/>
<Binary Id="GetData" SourceFile="$(var.SetupExtensions.TargetDir)\$(var.SetupExtensions.TargetName).CA.dll" />
<CustomAction Id="ChangeJSON" BinaryKey="GetData" DllEntry="CustomAction1" Execute="immediate" Impersonate="no" Return="check"/>
<InstallExecuteSequence>
<Custom Action="SetUserName" After="CostFinalize" />
<Custom Action="SetPassword" After="CostFinalize" />
<Custom Action="SetFilePath" After="CostFinalize"/>
<Custom Action='ChangeJSON' After='InstallFinalize'></Custom>
</InstallExecuteSequence>
My Custom Action code:
public static ActionResult CustomAction1(Session session)
{
try
{
session.Log( "Begin CustomAction1" );
string user = session["Username"];
string password = session["Password"];
string loc = session["FilePath"];
var json = System.IO.File.ReadAllText( loc +"appsettings.json" );
var root = JsonConvert.DeserializeObject<Root>(json);
root.Default.UserName = user;
root.Default.Password = password;
json = JsonConvert.SerializeObject( root, Formatting.Indented );
System.IO.File.WriteAllText( loc + "appsettings.json", json );
//The MessageBox bellow shows(and is with correct info) when I remove System.IO.File.WriteAllText above ^^
MessageBox.Show("Username: "+ user +"\nPassword: "+password +"\nFilePath: " + loc);
return ActionResult.Success;
}
catch(Exception ex )
{
session.Log( "Error: " + ex.Message );
MessageBox.Show(ex.Message);
return ActionResult.Failure;
}
How do I modify appsettings.json through my Custom Action?
回答1:
Custom actions that change the system state should run between InstallIntialize and InstallFinalize. This means you should schedule it Before InstallFinalize not after.
It should also run in deferred execution with no impersonation. You will need another custom action scheduled prior to this one that creates custom action data and passes the data to the deferred custom action.
Ideally you should also have rollback and commit actions to support rollbacks and test using the WIXFAILWHENDEFERRED custom action.
Read: http://www.installsite.org/pages/en/isnews/200108/index.htm http://blog.iswix.com/2011/10/beam-me-up-using-json-to-serialize.html
回答2:
Application Launch: I would consider updating the JSON via the application launch sequence if you can.
1)
Single source solution,2)
familiar territory for developers,3)
easier and better debugging features and4)
noimpersonation-
,sequencing-
andconditioning-complexities
like you get for custom actions: Why is it a good idea to limit the use of custom actions in my WiX / MSI setups?
Deferred CA Sample: You can find a sample of a deferred mode custom action WiX solution here: https://github.com/glytzhkof/WiXDeferredModeSample
Inline Sample: This older answer shows the key constructs inline in the answer: Wix Custom Action - session empty and error on deferred action.
CustomActionData: Deferred mode custom actions do not have access to the session objects property values like immediate mode custom actions do. As Painter has written you need to "send" text or settings to deferred mode by writing the data into the execution script. The data is then available in deferred mode by reading the special property CustomActionData
. The above sample should have the required constructs to see how this works. See the MSI documentation as well and also Robert Dickau's MSI Properties and Deferred Execution.
Transaction: Deferred mode custom actions can only exist between InstallInitialize and InstallFinalize. Actions between these actions run with elevated rights and can write to per-machine locations (not writeable for normal users). You can schedule yourself right before InstallFinalize for starters to test your current delete mechanism (I would try other approaches).
Rollback CAs: Rollback custom actions are intended to undo what was done with your JSON custom action and then revert everything to the previous state (cleanup after failed install). Writing these is quite involved and takes a lot of testing - many just skip them. It is best to try to find a library or a framework that does the job for you. I am not aware of any except the one linked to below, and I don't know its state. Rollback custom actions must precede the actual CA in the InstallExecuteSequence
(when an MSI is rolling back it executes the sequence in reverse).
With all this complexity, custom actions become the leading source of deployment errors: https://robmensching.com/blog/posts/2007/8/17/zataoca-custom-actions-are-generally-an-admission-of-failure/
Links:
- How to pass CustomActionData to a CustomAction using WiX?
- https://github.com/NerdyDuck/WixJsonExtension (not sure of status of this)
来源:https://stackoverflow.com/questions/65358312/wix-custom-action-modify-file-in-installfolder-after-installfinalize