GlobalAssemblyInfo.cs and strong naming - c#

I have a GlobalAssemblyInfo.cs file in the root of my solution, and I have something like the following entry in it to enable strong naming of my output assemblies.
#pragma warning disable 1699
[assembly : AssemblyKeyFile("..\\keyfile.snk")]
#pragma warning restore 1699
This approach has two drawbacks. Firstly, AssemblyKeyFileAttribute is deprecated, and so to avoid compilation warnings I need the pragma lines you see above. Secondly, I either need to keep all my projects at the same depth relative to the root to use the relative path, or use an absolute path, which dictates a checkout location on other users' machines (and on continuous integration servers/build agents).
Does anyone have a better solution than this, other than going through each project setting strong naming in the project file?

Well, to avoid the path problem you can use [assembly:AssemblyKeyName(...)] instead (although IIRC this is also deprecated); use sn -i to install a named key. Each machine (that does builds) would need this key adding.
Other than that; yes, you'd probably need to edit the project files.

Those attributes for key signing were deprecated for good reason (information leakage), which is another reason to go the project route.
If you have a lot of projects it might be possible to set them via a recorded macro, or even directly manipulating the .csproj files (ensure they are unloaded from VS first).

Richard makes a good point about information leakage - I've now found posts from Microsoft's .NET team where they describe this. So I've gone for his suggestion and come up with the following NAnt target:
<target name="strongName" description="Strong names the output DLLs">
<foreach item="File" property="filename">
<in>
<items>
<include name="**/*.csproj"></include>
<exclude name="**/*.Test.csproj"></include>
</items>
</in>
<do>
<echo message="${filename}" />
<xmlpoke file="${filename}" xpath="/m:Project/m:PropertyGroup/m:SignAssembly" value="false">
<namespaces>
<namespace prefix="m" uri="http://schemas.microsoft.com/developer/msbuild/2003" />
</namespaces>
</xmlpoke>
<xmlpoke file="${filename}" xpath="/m:Project/m:PropertyGroup/m:AssemblyOriginatorKeyFile" value="..\keyfile.snk">
<namespaces>
<namespace prefix="m" uri="http://schemas.microsoft.com/developer/msbuild/2003" />
</namespaces>
</xmlpoke>
</do>
</foreach>
</target>
The <namespaces> element is necessary for the XPath to be resolved in the csproj file - note that this is for VS2008, and something slightly different may be needed in VS2005.

Related

Disabling a specific VS code analysis rule (IDE0058) globally, without writing to a project-specific file?

I work frequently in multiple EF Core projects across multiple solutions. It's getting very frustrating seeing IDE0058 analysis hints everywhere whenever I'm saving a DbContext:
From what I can gather, suppressing this code style violation requires modifying at least one file:
Adding a local discard for every call to database.SaveChangesAsync (looks terrible)
Adding a System.Diagnostics.CodeAnalysis.SuppressMessage annotation on a per-method basis (again not ideal)
Adding a GlobalSuppressions.cs file to each project in the solution (really not ideal either)
Adding a .editorconfig file to each project to configure this violation. None of the projects I work with use editorconfig files.
For code review reasons, I can't just keep adding irrelevant files/changes like this whenever I work on a different project.
The thing that gets me is that I swear this is a recent issue. I've been working in EF Core for years up until now and this has not been an issue.
Further to this, a Roslyn team member commented on GitHub saying it has "no UI impact" and "is hidden by default" (clearly not the case here). There appears to be no way of "resetting" this to the default value, as the linked comment suggests, either.
Is there anyway to suppress this violation, once and for all, across every project and solution that I work on?
Yes, you can create a global Analyzers.ruleset file and add the rule ids you wish to ignore.
In the .csproj file of each project, you will have to add in the PropertyGroup section the <CodeAnalysisRuleSet> and specify the path to the ruleset file.
The ruleset file is an XML file and this is an example of what you can do:
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Rules for Core Application" Description="Custom Rules" ToolsVersion="16.0">
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.Features" RuleNamespace="Microsoft.CodeAnalysis.CSharp.Features">
<Rule Id="IDE0058" Action="None" />
</Rules>
</RuleSet>
This is how the file looks:
You can decide for each one if it is a warning/message/error/hidden/info/none.
Update:
One more way would be to add a .editorconfig file and ignore the warning there.
dotnet_style_readonly_field = false:none

EXE file is not working

I have a .msi (windows installer package) file into my project . I generated .exe file from .msi file successfully but whenever I try to open that .exe file or run as administrator it does nothing . How to solve this? Anything will help regarding this . Please help
UPDATE
Here is my code for .msi file
components.wxs
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?include Defines.wxi?>
<Fragment>
<ComponentGroup Id="MenuComponents" Directory="ProductMenuFolder">
<Component Id="ProductMenuComponents" Guid="*">
<!--<Shortcut Id="UninstallPackage" Directory="ProductMenuFolder" Name="Uninstall package"
Target="[System64Folder]msiexec.exe" Arguments="/x {[ProductCode]}" Description="Uninstalls $(var.YourApplicationReference.TargetName)"/>-->
<RemoveFolder Id='ProductMenuFolder' On='uninstall' />
<RegistryValue Root='HKCU' Key='Software\[Manufacturer]\[ProductName]'
Type='string' Value='' KeyPath='yes' />
</Component>
</ComponentGroup>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="FileWatcher">
<File Source="$(var.FileWatcher.TargetPath)" />
<!--Register this file as a Windows service-->
<ServiceInstall Id="ServiceInstaller"
Type="ownProcess"
Description="Sends Incoming mainframe files to the Webservice"
DisplayName="FileWatcher"
Vital="yes"
Start="auto"
ErrorControl="ignore"
Interactive="no"
Name="FileWatcher"
Account="[ACCOUNT]"
Password="[PASSWORD]">
<ServiceConfig Id="svcConfig" DelayedAutoStart="yes" OnInstall="yes" OnReinstall="yes" OnUninstall="no" />
</ServiceInstall>
<!--Set the user to be used by the service-->
<util:User Id="ServiceUser" Name="[ACCOUNT]" Password="[PASSWORD]" CreateUser="no" LogonAsService="yes" UpdateIfExists="yes" />
<!--Added example of how to stop service automatically-->
<ServiceControl Id="ServiceControl" Stop="both" Remove="uninstall" Name="FileWatcher" Wait="yes" />
</Component>
<Component Id="FileWatcher.Files" Guid="*">
<!--<Component Id="MAIDFileWatcher.Files" Guid="*">-->
<File Id="filB93E7D71690869B9CD2D0A479DB69C6C" Source="$(var.FileWatcher.TargetDir)\ExceptionHandling.dll" />
<File Id="fil487232F7A833919419AF9537A4390083" Source="$(var.FileWatcher.TargetDir)\ExceptionHandling.xml" />
<File Id="filDE3649B71309470D2D7C086E0FAABAE8" Source="$(var.FileWatcher.TargetDir)\itextsharp.dll" />
<File Id="filF73350F1AEF9ECF2621D4E63B9823029" Source="$(var.FileWatcher.TargetDir)\FileWatcher.exe.config" KeyPath='yes'/>
</Component>
</ComponentGroup>
product.wxs
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include Version.wxi?>
<?include Defines.wxi?>
<Product Id="$(var.PRODUCTCODE)" Name="$(var.PRODUCTNAME)" Language="1033" Version="$(var.REVISION)" Manufacturer="$(var.MANUFACTURER)" UpgradeCode="$(var.UPGRADECODE)">
<Package InstallerVersion="400" Compressed="yes" InstallScope="perMachine" Comments="$(var.COMMENTS)" Description="$(var.DESCRIPTION)" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="$(var.PRODUCTNAME)" Level="1">
<ComponentGroupRef Id="ProductComponents" />
<ComponentGroupRef Id="MenuComponents"/>
</Feature>
<UIRef Id="USERUI" />
<?include Actions.wxi?>
</Product>
</Wix>
You can debug an msi installation with a command line like this:
msiexec /i someapplication.msi /L*vx log.txt
This will run the installer and output log info to a file called log.txt.
See also: Windows Installer Command Line Options
Another pro tip is to debug your installer in a virtual machine. Take a snapshot before installing so you can roll back, or repeat the installation after making code changes and start from a reproducible state. I can't imagine debugging installers without Hyper-V - it's essential to me.
This is basically just shooting from the hip, please ignore whatever is not relevant (maybe check the very last three bullet points first):
Best practice: first of all, you are installing multiple binaries with a single component. This is a violation of component creation best practice.
For something this small I would suggest you use one component per file. This solves all kinds of future problems with patching, upgrades and other things.
What happens if the component rules are broken? Please skim this, or take our word for it and just use one file per component. At least make a separate component for all binaries (required).
A little blurb about the nature and philosophy of component GUIDs: Change my component GUID in wix? Some find it helpful to understand the mysterious and always troublesome component GUIDs.
If you insist on using multiple files per component, make sure that the key file for the component is a versioned file. I would think WiX would auto-magic this.
If you don't have a versioned key file, you could risk the component not installing at all if there are files already in the target location.
If you do have a versioned key file, make sure that your install has a higher version binary than the one it may encounter on disk at the target location (if any). Please read about the MSI file versioning rules for an explanation.
Logging: Does your application have a log feature (by default, or one that you can enable) which you can use for debugging? Maybe to the system's event log? Wouldn't services write there?
Dependencies: Also, did you check the pointers I provided earlier with regards to dependency checking? C# Debug folder when copied to another location does not run the exe.
Checking first the modules view in Visual Studio, and then using Dependencies.exe to check for missing dependencies?
Using procmon.exe is a little involved, but almost always reveals surprises and problems that can be hard to detect in other ways: Registering a CPP dll into COM after installation using Wix Msi installer
Does Fuslogvw.exe tell you anything? (.NET assembly binding failures).
Service Credentials: are you sure that those login credentials are getting applied during installation?
Did you try to set them manually to see if the service will run then? Did you add these properties to the SecureCustomProperties list of properties allowed to pass to deferred installation mode?
I think WiX has "auto-magic" here and does this for you, I forget. Check SecureCustomProperties in the property table of your final, compiled MSI using an appropriate tool, for example Orca.
With that delayed service start setting, is the service even running? (got to mention it at least). Or did you say it crashes on launch?
Hard-coded references: pointers to missing resources.
Did you check all the manifest files and config files (FileWatcher.exe.config) for anything funky that points to resources on your developer box (erroneous, hard-coded references)?
Could there be lacking resource files? (images, dlls, etc...).
Architecture & runtime requirements: is the target computer the same architecture as your developer machine? Just to chalk it up, surely you would see a warning about this?
What is the CPU targeted by your code? Any CPU? Did you try to manually register the files on another machine (a clean virtual machine maybe).
Is there anything special about the problem, target computer? Does it have weird policies? Does it have security software blocking things? Does it lack a common runtime component that is installed on your development computer? (.NET, VC++ runtime, VC runtime, java, etc...). These are the things a procmon.exe session should reveal, or a check with Dependencies.exe should show.
Are you using the notorious FileSystemWatcher .NET class? I have used it only once many years ago, but it caused me a lot of grief and I had to stop using it. It did crash my service file regularly.
I will dig up some links here if you are using this class.
Found a couple for now: FileSystemWatcher events raising twice despite taking measures against it and FileSystemWatcher vs polling to watch for file changes.
When I have installed my EXE under %PROGRAMDATA% I had the same issue
When I have installed my EXE under %PROGRAMFILES% I solved the problem

How can you force StyleCop to ignore a file?

I've included a 3rd party .cs file in my code. It doesn't comply with StyleCop's rules but I desperately need to be able to exclude it from StyleCop's checks but none of the methods I've found so far will work.
Three methods are documented here: http://sethflowers.com/blog/force-stylecop-to-ignore-a-file/ .. but none of these methods seems to work in StyleCop 4.7
The most useful of which looks to be this method in .csproj:
<Compile Include="AViolatingFile.cs">
    <ExcludeFromStyleCop>true</ExcludeFromStyleCop>
</Compile>
But despite having added the files, StyleCop still causes a compilation error when parsing this file.
// <auto-generated/>
Put this at the top of the class
Style cop ignores auto generated code
I used stylecop a while back as well and I believe you have to use the following line in your csproj file:
<Import Project="$(MSBuildExtensionsPath)\StyleCop\v4.6\StyleCop.targets" Condition="Exists('$(MSBuildExtensionsPath)\StyleCop\v4.6\StyleCop.targets')" />
You will also need to change the version number in the xml declaration to whatever you have installed.
Hope this helps.
Atm, I'm running StyleCop 4.7.49 from Xamarin Studio, and I have some hideous autogenerated file outside of my control (looking at you ¬¬ netfx-System.StringFormatWith)...
The solution for me was to disable all rules for only that file... how to do that?
You have to modify the file Settings.StyleCop and insert inside the StyleCopSettings tag the following
<SourceFileList>
<SourceFile>HideousClass.cs</SourceFile>
<Settings>
<GlobalSettings>
<BooleanProperty Name="RulesEnabledByDefault">False</BooleanProperty>
</GlobalSettings>
</Settings>
</SourceFileList>
Change HideousClass.cs with the file you want. you can also have multiple SourceFile tags if you want to set the rules for various files at once.
Taken from Using File Lists at StyleCop at CodePlex.com (see "Disable all rules for a subset of files" under "Examples").
Similar approach to the one seen above can be used if you want to enable or disable some rules for only some files.
Anyone that is still pulling your hair out on this one, I did the following:
.editorconfig
Example:
[SpecFlow.Plus.Runner.AssemblyHooks.cs]
dotnet_diagnostic.SA1633.severity = none
dotnet_diagnostic.CS1591.severity = none
// <auto-generated/>
put this on top of namespace and that should be good.

How to automatically change which files are built depending on configuration - visual studio

I have a solution which is built for several customers, and I need to be able to specify different xml files for each customer. How can I do this automatically. I was thinking it might be done with different configurations, but can't seem to figure out how.
Any suggestions?
EDIT:
This is the code used for declaring the xml file right now:
protected readonly static string XML_PATH = #"Resources/xml/Description.xml";
And the way it is solved now is to manually copy the correct file to the Description.xml before building. This is of course error prone, and I would like to automate it, preferentially based on the configuration. I'm looking for a quick fix right now, as we unfortunately haven't got the time to refactor the code.
Build Configuration dependent config files are a tricky issue and there are multiple ways to solve it.
If you want to down the road you outlined, you would need to manually edit the *.csproj File and add a Conditional ItemGroup to include the correct xml file. The syntax below hasn't been checked, but something like this should do
<ItemGroup Condition="'${Configuration}' == 'DEBUG'">
<Content Include="blablabl.xml"/>
</ItemGroup>
I don't remember if Content was the right ItemGroup, but simply check what ItemGroup your current .xmls are in and use that.
Based on your reformulated question:
You could use conditional compilation (caveat: It's messy and not the right way to manage config files!):
protected readonly static string XML_PATH =
#if DEBUG
#"Resources/xml/Description.xml";
#else
#"Resources/xml/Description2.xml";
#endif
If you want to read up on better techniques for managing config files, this is worth a read.
Now, I now self-promotion is frowned upon, but in this case I hope it's ok as it sounds relevant to the question, and I don't gain anything from this.
Recently I wrote a couple of blog posts on how to target multiple environments/machines:
Targeting multiple environments and machines - part 1/2
Targeting multiple environments and machines – part 2/2
As I understand it, the problem in this case, is how do you automatically build the correct set of files without having to manually figure out which files belong to which customer/environment. The solution I propose in the blog posts, suggests the use of nAnt along with some extensions built on top. nAnt is the .NET versions of Ant, a build tool, which lets you generate e.g. xml files given a specific set of input files, allowing you for example to generate a customer specific web.config file.
In the following appSetting section of the web.config file, say you want to specify a different value for the CustomerName key for each customer:
<appSettings>
<add key="CustomerName" value="${CustomerName}"/>
</appSettings>
Instead of specifying a value for the CustomerName key, you define a property called CustomerName. Now, assuming we are using nAnt, you create another customer specific file with the following content:
<?xml version="1.0" encoding="utf-8"?>
<target xmlns="http://nant.sf.net/release/0.86-beta1/nant.xsd">
<property name="CustomerName" value="Acme Incorporated"/>
</target>
nAnt can then merge these two files and automatically build customer/environment specific files for you.
The solution I go through, allow you to automatically build environment and machine specific files, such as the web.config file, but also allow you to output static files such as license files or libraries, all depending on which environment/machine you are targeting. I also supply a sample Visual Studio 2010 solution that shows a very basic example on how to do it, which you can download here.
You can of course just go ahead and take a look at nAnt, but I thought I'd provide you with the option to use my solution.

Conditional References

Currently our .net code is not processor specific, but it depends on libraries (Oracle/ODP.Net) which are. We've found a solution where we edit the csproj file directly, and put the references in to item groups with a Condition clause based on our selected build configuration. We have 32 bit debug/release and 64bit debug/release, and the correct assemblies are references when you build that config.
This works more or less at build time, but it causes all kinds of wackiness in Visual Studio (2008). The end result is that the same assembly shows up four times under references, and three have the yellow exclamation mark. It also generates some 76 warnings that I can't get rid of. We try to aim for 0 warnings because we want to know when new ones show up so this is a bit of a problem.
Is anybody aware of a solution to conditional references that allow it to look like a single reference (which it really is) and doesn't fill up my warnings at build time?
The only thing that leaps to mind is having 4 separate project files... but before you panic about having to maintain 4 files when ever you add a class, you can use another csproj trick here:
<Compile Include="**\*.cs" />
which (IIRC) says "include all cs files at any level in the folder structure".
We found an answer that was a bit different than what we were looking for, but I kindof like it. If you add this to your config file under runtime->AssemblyBinding
<dependentAssembly>
<assemblyIdentity name="Oracle.DataAccess" publicKeyToken="89b483f429c47342" />
<bindingRedirect oldVersion="2.111.6.20" newVersion="2.111.6.0" />
</dependentAssembly>
Then the 64bit and 32bit versions work with the same build. All we have to do is not copy Oracle.DataAccess.dll locally when we deploy and let it pull it from the GAC.
Thanks!

Categories

Resources