Use app.config transformation in WPF projects with ClickOnce publishing

Thanks to this great post of João Angelo, I finally found a solution to the issue of using app.config transformation in WPF projects with ClickOnce publishing.

Following are the steps I implemented to solve it:

  1. Right click on the WPF project and select Unload Project
  2. Right click on the unloaded project and select Edit projectname.csproj
  3. Add the following lines at the beginning of the file (just under the Project declaration):

    <!-- The transformation target (TransformWebConfig) in this targets file—>  

    <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets" />  

    <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

  4. Add the following lines at the end of the document (just before the Project tag closing):

      <PropertyGroup>    

    <!-- Prevent circular dependency on Build target –>    

    <PipelineDependsOnBuild>false</PipelineDependsOnBuild>    

    <!-- Override project config file name (By default is set to Web.config) –>    

    <ProjectConfigFileName>App.config</ProjectConfigFileName>  

    </PropertyGroup>  

    <!-- Removes the need to set config files Build Action as Content –>  

    <ItemGroup>    

    <FilesForPackagingFromProject Include="$(ProjectConfigFileName)">      

    <DestinationRelativePath>$(ProjectConfigFileName)</DestinationRelativePath>    

    </FilesForPackagingFromProject>  

    </ItemGroup>  

    <!-- Insert transformation targets in the build process –>  

    <PropertyGroup>    

    <BuildDependsOn> TransformWebConfig; OverrideAppConfigWithTargetPath; $(BuildDependsOn); CopyTransformedConfig </BuildDependsOn>  

    </PropertyGroup>  

    <PropertyGroup>    

    <TransformedConfig>$(TransformWebConfigIntermediateLocation)\transformed\App.config</TransformedConfig>  

    </PropertyGroup>  

    <!-- Overrides AppConfigWithTargetPath allowing the transformed config to be used for manifest generation –>  

    <Target Name="OverrideAppConfigWithTargetPath">    

    <ItemGroup>      

    <AppConfigWithTargetPath Remove="@(AppConfigWithTargetPath)" />      

    <AppConfigWithTargetPath Include="$(TransformedConfig)" Condition="'$(TransformedConfig)'!=''">        

    <TargetPath>$(TargetFileName).config</TargetPath>      

    </AppConfigWithTargetPath>    

    </ItemGroup>  

    </Target>  

    <!-- Copy transformed file to output directory –>  

    <Target Name="CopyTransformedConfig" Condition="'$(TargetName)' != ''">    

    <Copy Condition="Exists('$(TransformedConfig)')" SourceFiles="$(TransformedConfig)" DestinationFiles="$(OutputPath)$(TargetName)$(TargetExt).config" />    

    <Copy Condition="Exists('$(TransformedConfig)') And '$(TargetExt)' == '.exe'" SourceFiles="$(TransformedConfig)" DestinationFiles="$(OutputPath)$(TargetName).vshost.exe.config" />  

    </Target>  

    <!--   Override After Publish to support ClickOnce      AfterPublish target replaces the untransformed config file copied to the   deployment directory with the transformed one   -->  

    <Target Name="AfterPublish">    

    <PropertyGroup>      

    <DeployedConfig>$(_DeploymentApplicationDir)$(TargetName)$(TargetExt).config$(_DeploymentFileMappingExtension)</DeployedConfig>    

    </PropertyGroup>    

    <!-- Publish copies the unstransformed App.config to deployment directory so overwrite it –>    

    <Copy Condition="Exists('$(DeployedConfig)')" SourceFiles="$(TransformedConfig)" DestinationFiles="$(DeployedConfig)" />  

    </Target>

  5. Use the following lines to view App.Debug.config and App.Release.config under the default App.config file, as a subtree, in VS IDE:
     <None Include="App.Debug.config">
          <DependentUpon>App.config</DependentUpon>
        </None>
        <None Include="App.Release.config">
          <DependentUpon>App.config</DependentUpon>
        </None>
  6. Save the project and Reload the project.
  7. Try it changing the Build configuration and publishing the solution!
Advertisements

runas can’t execute the copy command: The system cannot find the file specified

Today I was trying to create a script to copy files using runas, but it is failing with:
"C:\>runas /user:user "copy test.txt test2.txt””
Enter the password for user:
Attempting to start copy test.txt as user user…
RUNAS ERROR: Unable to run – copy test.txt
2: The system cannot find the file specified.

Of course the file exists, so after several attempts I found that the problem was not related to the file to be copied but to the copy command itself!

In order to solve I run the following command

"C:\>runas /user:user /env "cmd /k copy test.txt test2.txt

The /env flag is to use current environment instead of user’s.

The /k flag is to block the output shell in order to read the output of the command.

Reassigning the correct SSL certificate to SharePoint 2010 Web Services IIS Site

Yesterday I experienced an error on the Sharepoint 2010 Web Services IIS site. I wrongly changed the default binding certificate for the https protocol and the following are the errors I got in the event viewer:

The Secure Store Service application SecureStoreServiceApplication is not accessible. The full exception text is: There was no endpoint listening at https://sharepointserver:32844/d135288cc8de436c8d899a64003c5585/SecureStoreService.svc/https that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.

An operation failed because the following certificate has validation errors:\n\nSubject Name: CN=<CN>, OU=<OU>, O=<O>, L=Rome, S=Rome, C=IT\n Issuer Name: CN=<CN>, DC=<DC>, DC=it\n Thumbprint: 8D149D3FA98CA0FF1F5D0077FFC4DF9D0318829A\n\n Errors:\n\n SSL policy errors have been encountered.  Error code ‘0x2’..

The Secure Store Service application SecureStoreServiceApplication is not accessible. The full exception text is: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was ’00:10:00′.

It was very frustrating because I unsuccesfully tried to rerun the Sharepoint 2010 configuration wizard, to cancel and recreate the binding and to change the certificate via the UI of IIS.

Then I found this excellent post about Rik Hepworth that solved my issue:

http://blogs.blackmarble.co.uk/blogs/rhepworth/post/2010/01/07/reassigning-the-correct-ssl-certificate-to-sharepoint-2010-web-services-iis-site.aspx

Basically the two command, I run, are:

netsh http delete sslcert ipport=0.0.0:32844

and

netsh http add sslcert ipport=0.0.0:32844 certhash=<thumbprint> appid=<appid> certstorename=SharePoint

After then I fixed the problem. Great!

For further reading, I also found this post that explain very well the SharePoint 2010 Certificates and Certificate Authority:

http://blogs.msdn.com/b/besidethepoint/archive/2010/11/30/sharepoint-2010-certificates.aspx