I found a better solution is to use the BeforePublish target to apply
dotfuscate on the executable assembly. The BeforePublish target is built
only once when publishing via Publish Wizard. For example:
I would really like to get this working as publishing locally, editing the script to match the
version number, running it manually and then FTP'ing is not the way to do this long term.
I put:
<Target Name="BeforePublish" Condition="'$(Configuration)'=='Release'">
<SAB_MsgBox Prompt="BeforePublish" />
<Exec Command=""C:\Program Files\PreEmptive Solutions\Dotfuscator Enhanced Community
Edition 4.2\dotfuscator.exe" /q "$(ProjectDir)Dotfuscator_Project_Exclude.xml" " />
<SAB_MsgBox Prompt="BeforePublish" />
</Target>
into the project file. (SAB_MsgBox is a custom task I put together so I could pause the process and
check what files were created.)
The Publish Now process runs without errors. Unfortunately, the program won't install. The error
log is below. I find it interesting that the fatal error is:
+ File, ApplicationName.exe, has a different computed hash than specified in manifest.
When the warnings are:
* The file named ApplicationName.exe does not have a hash specified in the manifest. Hash
validation will be ignored.
* The file named ApplicationName.exe does not have a hash specified in the manifest. Hash
validation will be ignored.
The manifest file and the application manifest have time stamps later than the Dotfuscatored
executable. Please note that for the purpose of this test I turned off strong name signing.
I check the manifest file and it does not have a hash specified for ApplicationName.exe. However,
neither does one that was created without running Dotfuscator.
Any idea as to what could be going on?
ERROR SUMMARY
Below is a summary of the errors, details of these errors are listed later in the log.
* Activation of
http://WEbSite/ApplicationName/ApplicationName.application resulted in
exception. Following failure messages were detected:
+ File, ApplicationName.exe, has a different computed hash than specified in
manifest.
COMPONENT STORE TRANSACTION FAILURE SUMMARY
No transaction error was detected.
WARNINGS
* The file named ApplicationName.exe does not have a hash specified in the manifest. Hash
validation will be ignored.
* The file named ApplicationName.exe does not have a hash specified in the manifest. Hash
validation will be ignored.
OPERATION PROGRESS STATUS
* [7/28/2009 11:09:01 PM] : Activation of
http://WEbSite/ApplicationName/ApplicationName.application has started.
* [7/28/2009 11:09:01 PM] : Processing of deployment manifest has successfully completed.
* [7/28/2009 11:09:01 PM] : Installation of the application has started.
* [7/28/2009 11:09:01 PM] : Processing of application manifest has successfully completed.
* [7/28/2009 11:09:02 PM] : Request of trust and detection of platform is complete.
ERROR DETAILS
Following errors were detected during this operation.
* [7/28/2009 11:09:02 PM] System.Deployment.Application.InvalidDeploymentException
(HashValidation)
- File, ApplicationName.exe, has a different computed hash than specified in
manifest.
- Source: System.Deployment
- Stack trace:
at System.Deployment.Application.ComponentVerifier.VerifyFileHash(String
filePath, Hash hash)
at System.Deployment.Application.ComponentVerifier.VerifyFileHash(String
filePath, HashCollection hashCollection)
at System.Deployment.Application.ComponentVerifier.FileComponent.Verify()
at System.Deployment.Application.ComponentVerifier.VerifyComponents()
at
System.Deployment.Application.DownloadManager.DownloadDependencies(SubscriptionState subState,
AssemblyManifest deployManifest, AssemblyManifest appManifest, Uri sourceUriBase, String
targetDirectory, String group, IDownloadNotification notification, DownloadOptions options)
at
System.Deployment.Application.ApplicationActivator.DownloadApplication(SubscriptionState subState,
ActivationDescription actDesc, Int64 transactionId, TempDirectory& downloadTemp)
at
System.Deployment.Application.ApplicationActivator.InstallApplication(SubscriptionState& subState,
ActivationDescription actDesc)
at
System.Deployment.Application.ApplicationActivator.PerformDeploymentActivation(Uri activationUri,
Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings
browserSettings, String& errorPageUrl)
at
System.Deployment.Application.ApplicationActivator.ActivateDeploymentWorker(Object state)
COMPONENT STORE TRANSACTION DETAILS
No transaction information is available.
Thanks Joe for your clarification!
Hi Stewart,
Thank you for your prompt response!
As for the strong-named executable assembly, you need to resign it after
applying dotfuscator. Use the Sn.exe command to resign an assembly.
It appears that the .application and .manifest files are created and
signed in the CoreCompile task.
No. The .applicatition file is created in the GenerateDeploymentManifest
target and the .manifest file is created in the GenerateApplicationManifest
target. Both the manifest files are signed in the
_DeploymentSignClickOnceDeployment target.
Publish activated AfterCompile five times. Clearly one would not want to
run Dotfuscator five
times. Is there someway to determine which of the five calls is the one
that should be used -- some switch that can be tested?
I found a better solution is to use the BeforePublish target to apply
dotfuscate on the executable assembly. The BeforePublish target is built
only once when publishing via Publish Wizard. For example:
<Target Name="AfterCompile">
<Exec Command="path\Dotfuscator /in:
$(IntermediateOutputPath)appname.exe /out: $(IntermediateOutputPath) "/>
</Target>
As for accessing application settings from an obsfuscated application, I
can reproduce the problem on my side. A workaround is to use the
ConfigurationManager and Configuration classes to access the application
settings by yourself rather than use the strong-typed setting class
generated by Visual Studio. The following are the methods to read and write
application settings.
string ReadSetting(string sectionGroupName, string sectionName, string
settingName)
{
Configuration configuration =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Get sectionGroup
ConfigurationSectionGroup sectionGroup =
configuration.GetSectionGroup(sectionGroupName);
// Get section
ClientSettingsSection section =
(ClientSettingsSection)sectionGroup.Sections.Get(sectionName);
// Get setting
SettingElement setting = section.Settings.Get(settingName);
// Read setting value
return setting.Value.ValueXml.InnerText;
}
void WriteSetting(string sectionGroupName, string sectionName,
string settingName,string newvalue)
{
Configuration configuration =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Get sectionGroup
ConfigurationSectionGroup sectionGroup =
configuration.GetSectionGroup(sectionGroupName);
// Get section
ClientSettingsSection section =
(ClientSettingsSection)sectionGroup.Sections.Get(sectionName);
// write setting
SettingElement setting = section.Settings.Get(settingName);
// Read setting value
setting.Value.ValueXml.InnerText = newvalue;
section.SectionInformation.ForceSave = true;
configuration.Save();
}
The above methods applies to application-scoped settings. For user-scoped
settings, since they are stored in the user.config file in the isolated
storage of the current user, it's a little complex to read and write them.
I'm performing research on this and would get back to you ASAP.
Sincerely,
Linda Liu
Microsoft Online Community Support