This should be obvious to do, but I just couldn't make it work...
What I'm trying to do is simple: I would like my compilation to fail with an error if there is a warning. Yes, the famous TreatWarningsAsErrors...
I configured it in my C# project properties
This results in the expected TreatWarningsAsErrors section in my csproj:
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
So far so good, if I add an useless private variable in my code, it results in a compilation error:
private int unused;
Error 3 Warning as Error: The field 'XXXX.unused' is never used
But the whole problem is, I can't make it work for assembly reference issues. If I have a reference to an unknown assembly, the compiler (either devenv or msbuild) throws a warning, but I want an error instead.
Ultimately, I'm trying to configure a gated check-in TFS build configuration, so TFS would reject a commit in case there is a "The referenced component 'XXXX' could not be found." warning. Something simpler than modifying the build process template would be great.
MSBuild warnings (all start with MSB*) as opposed to CSC warnings cannot be suppressed nor promoted to errors. For the reason the ResolveAssemblyReference task prints its messages on the fly and does not aggregate any of them.
The only feasible solution is reading the MSBuild log files created during the TFS build.
I think the most elegant solution is to implement a custom Build CodeActivity. The following is a simple activity that will output to results any files containing a given SearchString:
using System;
using System.Activities;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.TeamFoundation.Build.Client;
namespace MyBuildActivities.FileSystem
{
[BuildActivity(HostEnvironmentOption.Agent)]
public sealed class ReadStringFromFile : CodeActivity
{
[RequiredArgument]
public InArgument<IEnumerable<string>> Files { get; set; }
[RequiredArgument]
public InArgument<string> SearchString { get; set; }
public OutArgument<string> Result { get; set; }
protected override void Execute(CodeActivityContext context)
{
var files = context.GetValue(Files);
var searchString = context.GetValue(SearchString);
var list =
(files.Where(file => File.ReadAllText(file).Contains(searchString))
.Select(file => string.Format("{0} was found at {1}", searchString, file))).ToList();
if(list.Count > 0)
Result.Set(context, string.Join(Environment.NewLine, list));
}
}
}
Declared in the build process template like so:
xmlns:cfs="clr-namespace:MyBuildActivities.FileSystem;assembly=MyBuildActivities"
Invoked just at the end of the Compile and Test for Configuration sequence:
<Sequence DisplayName="Handle MSBuild Errors">
<Sequence.Variables>
<Variable x:TypeArguments="scg:IEnumerable(x:String)" Name="logFiles" />
<Variable x:TypeArguments="x:String" Name="readStringFromFileResult" />
</Sequence.Variables>
<mtbwa:FindMatchingFiles DisplayName="Find Log Files" MatchPattern="[String.Format("{0}\**\*.log", logFileDropLocation)]" Result="[logFiles]" mtbwt:BuildTrackingParticipant.Importance="Low" />
<cfs:ReadStringFromFile Files="[logFiles]" SearchString="MSB3245" Result="[readStringFromFileResult]" />
<mtbwa:WriteBuildMessage DisplayName="Write Result" Message="[readStringFromFileResult]" Importance="[Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High]" />
<If Condition="[readStringFromFileResult.Count > 0]" DisplayName="If SearchString Was Found" mtbwt:BuildTrackingParticipant.Importance="Low">
<If.Then>
<Throw DisplayName="Throw Exception" Exception="[New Exception(readStringFromFileResult)]" mtbwt:BuildTrackingParticipant.Importance="Low" />
</If.Then>
</If>
</Sequence>
I've tested this on TFS 2012 though it should work for TFS 2010 as well.
MSBuild 15 now supports a /warnaserror flag, which forces MSBuild warnings to be treated as errors.
MSBuild 15 is intalled with Visual Studio 2017 but can also be downloaded from GitHub
This GitHub issue explains why it cannot be set via an MSBuild property (tl;dr a property is too late)
Related
I'm trying to create a custom SonarQube rule in VisualStudio 2015, using the Roslyn SDK Generator.
The generator works fine and I'm able to publish the .jar file to SonarQube server and use my custom rule in daily builds.
Now I would like to categorize the rule as "Vulnerabilty", but it always appear as "Code Smell".
I tried a couple of approaches:
Changed the "Category" of the DiagnosticDescriptor class to "Security"
private const string Category = "Security";
private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
Changed the xml template provided by the generator and regenerated the plugin using the new xml (I tried "SECURITY" and "SECURITY_COMPLIANCE" in place of the generated "MAINTENABILITY_COMPLIANCE")
<sqale xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<chc>
<key>SECURITY</key>
<chc>
<rule-key>MyRule</rule-key>
<prop>
<key>remediationFunction</key>
<txt>CONSTANT_ISSUE</txt>
</prop>
<prop>
<key>offset</key>
<txt />
<val>15min</val>
</prop>
</chc>
</chc>
</sqale>
Nothing worked so far.
I'm using the following configuration:
VS2015 Update 3
SonarQube v. 6.1
SonarLint v. 2.8
Custom C# analyzer developed with SonarQube.Roslyn.SDK v. 1.0
Unfortunately seems that ability to explicitly set category is not yet implemented - see
https://jira.sonarsource.com/browse/SFSRAP-48
As a workaround you can add tag security to a rule and rule will be categorized as Vulnerabilty thanks to automatic conversion of tag into category in SonarQube. However it seems that SonarQube.Plugins.Roslyn.RuleGenerator is not considering the CustomTags property when building the SonarQube rule, but addition of newRule.Tags = diagnostic.CustomTags?.ToArray(); to the method SonarQube.Plugins.Roslyn.RuleGenerator.GetAnalyzerRules and rebuild of sonarqube-roslyn-sdk will do the job.
I have a bunch of small C# projects which use a couple of NuGet packages. I'd like to be able to update version of a given package automatically. More then that: I'd like to be warned if a project uses different version from the others.
How do I enforce same version dependency across multiple C# projects?
As I haven't found another way to enforce this, I've written a unit test which will fail if different package versions are being found in any packages.config in any subfolder.
As this might be useful for others, you'll find the code below. You'll have to adapt the resolution of the root folder done in GetBackendDirectoryPath().
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using NUnit.Framework;
namespace Base.Test.Unit
{
[TestFixture]
public class NugetTest
{
private const string PACKAGES_CONFIG_FILE_NAME = "packages.config";
private const string BACKEND_DIRECTORY_NAME = "DeviceCloud/";
private const string PACKAGES_NODE_NAME = "packages";
private const string PACKAGE_ID_ATTRIBUTE_NAME = "id";
private const string PACKAGE_VERSION_ATTRIBUTE_NAME = "version";
/// <summary>
/// Tests that all referenced nuget packages have the same version by doing:
/// - Get all packages.config files contained in the backend
/// - Retrieve the id and version of all packages
/// - Fail this test if any referenced package has referenced to more than one version accross projects
/// - Output a message mentioning the different versions for each package
/// </summary>
[Test]
public void EnforceCoherentReferences()
{
// Act
IDictionary<string, ICollection<PackageVersionItem>> packageVersionsById = new Dictionary<string, ICollection<PackageVersionItem>>();
foreach (string packagesConfigFilePath in GetAllPackagesConfigFilePaths())
{
var doc = new XmlDocument();
doc.Load(packagesConfigFilePath);
XmlNode packagesNode = doc.SelectSingleNode(PACKAGES_NODE_NAME);
if (packagesNode != null && packagesNode.HasChildNodes)
{
foreach (var packageNode in packagesNode.ChildNodes.Cast<XmlNode>())
{
if (packageNode.Attributes == null)
{
continue;
}
string packageId = packageNode.Attributes[PACKAGE_ID_ATTRIBUTE_NAME].Value;
string packageVersion = packageNode.Attributes[PACKAGE_VERSION_ATTRIBUTE_NAME].Value;
if (!packageVersionsById.TryGetValue(packageId, out ICollection<PackageVersionItem> packageVersions))
{
packageVersions = new List<PackageVersionItem>();
packageVersionsById.Add(packageId, packageVersions);
}
//if (!packageVersions.Contains(packageVersion))
if(!packageVersions.Any(o=>o.Version.Equals(packageVersion)))
{
packageVersions.Add(new PackageVersionItem()
{
SourceFile = packagesConfigFilePath,
Version = packageVersion
});
}
if (packageVersions.Count > 1)
{
//breakpoint to examine package source
}
}
}
}
List<KeyValuePair<string, ICollection<PackageVersionItem>>> packagesWithIncoherentVersions = packageVersionsById.Where(kv => kv.Value.Count > 1).ToList();
// Assert
string errorMessage = string.Empty;
if (packagesWithIncoherentVersions.Any())
{
errorMessage = $"Some referenced packages have incoherent versions. Please fix them by adapting the nuget reference:{Environment.NewLine}";
foreach (var packagesWithIncoherentVersion in packagesWithIncoherentVersions)
{
string packageName = packagesWithIncoherentVersion.Key;
string packageVersions = string.Join("\n ", packagesWithIncoherentVersion.Value);
errorMessage += $"{packageName}:\n {packageVersions}\n\n";
}
}
Assert.IsTrue(packagesWithIncoherentVersions.Count == 0,errorMessage);
//Assert.IsEmpty(packagesWithIncoherentVersions, errorMessage);
}
private static IEnumerable<string> GetAllPackagesConfigFilePaths()
{
return Directory.GetFiles(GetBackendDirectoryPath(), PACKAGES_CONFIG_FILE_NAME, SearchOption.AllDirectories)
.Where(o=>!o.Contains(".nuget"));
}
private static string GetBackendDirectoryPath()
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
var uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path.Substring(0, path.IndexOf(BACKEND_DIRECTORY_NAME, StringComparison.Ordinal) + BACKEND_DIRECTORY_NAME.Length));
}
}
public class PackageVersionItem
{
public string SourceFile { get; set; }
public string Version { get; set; }
public override string ToString()
{
return $"{Version} in {SourceFile}";
}
}
}
I believe I have found a setup which solves this (and many other) problem(s).
I just realized one can use a folder as nuget source. Here is what I did:
root
+ localnuget
+ Newtonsoft.Json.6.0.1.nupkg
+ nuget.config
+ packages
+ Newtonsoft.Json.6.0.1
+ src
+ project1
nuget.config looks like this:
<configuration>
<config>
<add key="repositoryPath" value="packages" />
</config>
<packageSources>
<add key="local source" value="localnuget">
</packageSources>
</configuration>
You can add Nuget server to nuget.config to get access to updates or new dependencies during development time:
<add key="nuget.org" value="https://www.nuget.org/api/v2/" />
Once you're done, you can copy .nupkg from cache to localnuget folder to check it in.
There are 3 things I LOVE about this setup:
I'm now able to use Nuget features, such as adding props and targets. If you have a code generator (e.g. protobuf or thrift) this becomes pricesless.
It (partially) solves the problem of Visual Studio not copying all DLLs, because you need to specify dependencies in .nuspec file and nuget loads indirect dependencies automatically.
I used to have a single solution file for all projects so updating nuget packages was easier. I haven't tried yet but I think I solved that problem too. I can have nuget packages for the project I want to export from a given solution.
I don't know how to enforce it, but I've found the "Consolidate" tab to help.
This tab shows you packages that have different versions throughout the solution. From there you can select projects and use the install button to install the same package version across them. This tab can be found under "Manage NuGet for solution".
See Consolidate tab in Microsoft documentation.
Thank you for asking this - so I am not alone. I put considerable time into ensuring all projects in my solution use the same package version. The NuGet user interface (and also the command line interface) also contribues to having different versions among the projects within a solution. In particular when a new project is added to the solution and package X shall be added to the new project, NuGet is overly greedy to download the latest version from nuget.org instead of using the local version first, which would be the better default handling.
I completely agree with you, that NuGet should warn if different versions of a package are used within a solution. And it should help avoiding this and fixing such version maze.
The best I found to do now is to enumerate all packages.config files within the solution folder (your projects-root) which look like
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net451" />
...
</packages>
then sorting the xml-nodes by id and analysing the version numbers.
If any package occurs with different version numbers, making them all equal and afterwards running the NuGet command
Update-Package -ProjectName 'acme.lab.project' -Reinstall
should fix wrong package versions.
(Since NuGet is open source it would certainly be a cool thing to get our hands dirty and implement the missing version-conflict avoidance utility.)
Additionally to the "Consolidate" tab in VS, you can use powershell Sync-Package
https://learn.microsoft.com/en-us/nuget/reference/ps-reference/ps-ref-sync-package.
Examples:
# Sync the Elmah package installed in the default project into the other projects in the solution
Sync-Package Elmah
# Sync the Elmah package installed in the ClassLibrary1 project into other projects in the solution
Sync-Package Elmah -ProjectName ClassLibrary1
# Sync Microsoft.Aspnet.package but not its dependencies into the other projects in the solution
Sync-Package Microsoft.Aspnet.Mvc -IgnoreDependencies
# Sync jQuery.Validation and install the highest version of jQuery (a dependency) from the package source
Sync-Package jQuery.Validation -DependencyVersion highest
I'm trying to allow a user to enter data into a textbox that will be added to the web.config file. I've added the relevent lines to the web.config file but when I make this class all goes wrong.
I keep getting the are you missing a using directive or assembly refenrence error whenever I try to run my app. I have looked at the other times this question has been asked and can't seem to figure out where I'm going wrong. The thing is that I am extremely new to Visual Studio and am just left blank at what could be the answer.
Below here is the class file that's generating the error. I hope I've included everything you need to assist me. Thank you.
using System.Collections.Generic;
using System.Linq;
using System.Configuration;
namespace WebConfigDemo
{
public class CompanyConfigSection : ConfigurationSection
{
[ConfigurationProperty("", IsRequired = true, IsDefaultCollection = true)]
public CompanyConfigCollection Companies
{
get
{
return (CompanyConfigCollection)this[""];
}
set
{
this[""] = value;
}
}
}
public class CompanyConfigElement : ConfigurationElement
{
[ConfigurationProperty("id", IsKey = true, IsRequired = true)]
public int Id
{
get
{
return (int)this["id"];
}
set
{
this["id"] = value;
}
}
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get
{
return this["name"].ToString();
}
set
{
this["name"] = value;
}
}
} '
public class CompanyConfigCollection : ConfigurationElementCollection
{
protected override ConfigurationElement CreateNewElement()
{
return new CompanyConfigElement();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((CompanyConfigElement)element).Id;
}
}
public class CompaniesConfig
{
private static readonly Dictionary<int, CompanyConfigElement>
Elements;
static CompaniesConfig()
{
Elements = new Dictionary<int, CompanyConfigElement>();
var section = (CompanyConfigSection)ConfigurationManager.GetSection ("companies");
foreach (CompanyConfigElement system in section.Companies)
Elements.Add(system.Id, system);
}
public static CompanyConfigElement GetCompany(int companyId)
{
return Elements[companyId];
}
public static List<CompanyConfigElement> Companies
{
get
{
return Elements.Values.ToList();
}
}
}
} '
Any help is appreciated
You probably don't have the System.Configuration dll added to the project references. It is not there by default, and you have to add it manually.
Right-click on the References and search for System.Configuration in the .net assemblies.
Check to see if it is in your references...
Right-click and select Add Reference...
Find System.Configuration in the list of .Net Assemblies, select it, and click Ok...
The assembly should now appear in your references...
.Net framework of the referencing dll should be same as the .Net framework version of the Project in which dll is referred
If you've tried the above solutions and haven't found the answer, make sure that the .NET versions of all projects are the same.
I ran into this problem when importing a .NET version 4.6.1 into a .NET version 4.6.2 project. Without any warnings from Visual Basic!
More Info: The type or namespace name could not be found
Your using statements appear to be correct.
Are you, perhaps, missing the assembly reference to System.configuration.dll?
Right click the "References" folder in your project and click on "Add Reference..."
This problem would be caused by your application missing a reference to an external dll that you are trying to use code from. Usually Visual Studio should give you an idea about which objects that it doesn't know what to do with so that should be a step in the right direction.
You need to look in the solution explorer and right click on project references and then go to add -> and look up the one you need. It's most likely the System.Configuration assembly as most people have pointed out here while should be under the Framework option in the references window. That should resolve your issue.
I have observed a quote ' in your 1st line and also at the end of your last line.
'using System.Collections.Generic;
Is this present in your original code or some formatting mistake?
I had the same problem earlier today. I could not figure out why the class file I was trying to reference was not being seen by the compiler. I had recently changed the namespace of the class file in question to a different but already existing namespace. (I also had using references to the class's new and previous namespaces where I was trying to instantiate it)
Where the compiler was telling me I was missing a reference when trying to instantiate the class, I right clicked and hit "generate class stub". Once Visual Studio generated a class stub for me, I coped and pasted the code from the old class file into this stub, saved the stub and when I tried to compile again it worked! No issues.
Might be a solution specific to my build, but its worth a try.
In some cases, when necessary using has been obviously added and studio can't see this namespace, studio restart can save the day.
I was getting warnings about different versions in .NET framework; I ignored them.
The project compiles fine making the change in the solution's properties.
I'm using Visual Studio Code and could not use instructions from above so I found another way to fix the problem with referencing to namespace from another file.
All what need to be done is to add include to your .csproj file e.g:
<ItemGroup>
<Compile Include="filename.cs" />
</ItemGroup>
Then you can use namespaces from filename.cs
The following technique worked for me:
1) Right click on the project Solution -> Click on Clean solution
2) Right click on the project Solution -> Click on Rebuild solution
I created a new VSIX extension project in Visual Studio 2012, and wrote a MEF classifier (as a test) that should simply highlight all text in a .mylang file. Here are the relevant parts of my .NET 4.5 code:
internal static class MyLangLanguage
{
public const string ContentType = "mylang";
public const string FileExtension = ".mylang";
[Export(typeof(ClassificationTypeDefinition))]
[Name(ContentType)]
[BaseDefinition("code")]
internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;
[Export]
[FileExtension(FileExtension)]
[ContentType(ContentType)]
internal static FileExtensionToContentTypeDefinition MyLangSyntaxFileExtensionDefinition = null;
}
[Export(typeof(IClassifierProvider))]
[ContentType(MyLangLanguage.ContentType)]
[Name("MyLangSyntaxProvider")]
internal sealed class MyLangSyntaxProvider : IClassifierProvider
{
[Import]
internal IClassificationTypeRegistryService ClassificationRegistry = null;
public IClassifier GetClassifier(ITextBuffer buffer)
{
return buffer.Properties.GetOrCreateSingletonProperty(() => new MyLangSyntax(ClassificationRegistry, buffer));
}
}
internal sealed class MyLangSyntax : IClassifier { }
Here is the full code.
These are the relevant parts from my source.extension.vsixmanifest file. Based on suggestions and similar files I found across the web, I added the dependency on MPF and the two assets.
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<!-- ... -->
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="4.5" />
<Dependency d:Source="Installed" Id="Microsoft.VisualStudio.MPF.11.0" DisplayName="Visual Studio MPF 11.0" Version="[11.0,12.0)" />
</Dependencies>
<Assets>
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
</Assets>
</PackageManifest>
I also tried a version 1.0 manifest:
<?xml version="1.0" encoding="utf-8"?>
<Vsix Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
<!-- ... -->
<References />
<Content>
<MefComponent>|%CurrentProject%|</MefComponent>
</Content>
</Vsix>
When I run it, it starts an experimental instance of Visual Studio 2012, and the Extensions and Updates window shows that my extension is active. However, it does not do anything when I load or create a .mylang file. Any exceptions I throw (as a test) from my extension are never thrown. Breakpoints are never hit, and get an exclamation mark with the following warning:
The breakpoint will not currently be hit. No symbols have been loaded for this document.
It feels as if my extension is never really loaded at all. My problem is similar to this problem and this problem, but I'm using Visual Studio 2012 which uses a new VSIX manifest format.
What I know:
I can find my DLL and VSIX file in the %localappdata%\Microsoft\VisualStudio\11.0Exp\Extensions\MyLang\VSIXProject1\1.0 folder, so I know they are copied.
Their timestamp corresponds to when I last built the project, so I know they are up-to-date.
Project Properties > Debug > Start external program: is already automatically set to C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe, and the Command line arguments were automatically set to /rootsuffix Exp.
The Visual Studio log (created with the /log option) has two entries related to my extension: Successfully loaded extension... and Extension is enabled....
My DLL does not appear on the Modules tab (list of all loaded DLLs) of the debugging Visual Studio, while some (not all) other extensions do appear.
It doesn't get loaded in Visual Studio 2012 or 2010 both on my laptop and my desktop PC.
What I've tried:
Set <IncludeAssemblyInVSIXContainer> to true in the .csproj file, per this suggestion, but it did not make any difference.
I can't add the line <MefComponent>|%CurrentProject%|</MefComponent> to the source.extension.vsixmanifest file as it uses a different format (2.0) than VSIX projects for previous versions of Visual Studio (1.0).
This suggestion (setting IncludeAssemblyInVSIXContainer and friends in my .csproj to true) but it does not make a difference. And my breakpoints are still showing the warning and not being hit.
Reset the VS Experimental instance using the Reset the Visual Studio 2012 Experimental Instance shortcut in the Start Menu, as per this suggestion. It didn't make a difference.
How can I at the very least be sure my VSIX MEF extension is loaded and works? And if possible, how can I make by breakpoint work and debug it?
Edit: The problem is you've improperly exported your ContentTypeDefinition as a ClassificationTypeDefinition. You should use the following instead:
[Export] // <-- don't specify the type here
[Name(ContentType)]
[BaseDefinition("code")]
internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;
Here's my two guesses right now:
Try removing the following line from your vsixmanifest. I assume you do not have a class in your project that extends Package, in which case Visual Studio might be refusing to load your package due to the following Asset line (your extension does not actually provide this asset).
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
If that fails, try replacing your current source.extension.vsixmanifest with one written to the old schema (version 1.0). I know this form still works in Visual Studio 2012 because all ~20 extensions I work on (with >10 public releases) use the old schema.
280Z28 solved the problem! For completeness, this is the full tried and tested code that will create a super simple VSIX Visual Studio MEF extension that colors all text in a .mylang file blue (or whatever the current keyword color is).
How to create a simple coloring MEF VSIX extension
Make sure you have the Visual Studio SDK installed. (VS2010 SP1 SDK, VS2012 SDK)
Create a new VSIX Project(From the template under Installed → Templates → Visual C# → Extensibility.)
Enter something in the Author field of the VSIX manifest editor, then save and close it.
Add references to the following libraries,version 10.0.0.0 for VS2010, or 11.0.0.0 for VS2012:
Microsoft.VisualStudio.CoreUtility.dll
Microsoft.VisualStudio.Language.StandardClassification.dll
Microsoft.VisualStudio.Text.Data.dll
Microsoft.VisualStudio.Text.Logic.dll
Microsoft.VisualStudio.Text.UI.dll
Microsoft.VisualStudio.Text.UI.Wpf.dll
Add a reference to the following library:
System.ComponentModel.Composition.dll version 4.0.0.0
Create and add a new code file MyLang.cs, and copy-and-paste the code below in it.
Edit source.extension.vsixmanifest as XML.
For Visual Studio 2010, add the following XML just before the closing tag </Vsix>, and save:
<Content>
<MefComponent>|%CurrentProject%|</MefComponent>
</Content>
(If there is already an empty <Content/>, remove it.)
For Visual Stuio 2012, add the following XML just before the closing tag </PackageManifest>, and save:
<Assets>
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
</Assets>
(If there is already an empty <Assets/>, remove it.)
Only for Visual Studio 2010:
Unload the VSIX project (right-click the project → Unload project).
Edit the .csproj project file (right-click the project → Edit MyProject.csproj).
Change the value at <IncludeAssemblyInVSIXContainer> to true.
Save and close the file.
Reload the VSIX project (right-click the project → Reload project).
Now build and run it. When you load a .mylang file, all text should be colored blue (or whatever the default keyword color is).
MyLang.cs
using Microsoft.VisualStudio.Language.StandardClassification;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
namespace VSIXProject1
{
internal static class MyLangLanguage
{
public const string ContentType = "mylang";
public const string FileExtension = ".mylang";
[Export]
[Name(ContentType)]
[BaseDefinition("code")]
internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;
[Export]
[FileExtension(FileExtension)]
[ContentType(ContentType)]
internal static FileExtensionToContentTypeDefinition MyLangSyntaxFileExtensionDefinition = null;
}
[Export(typeof(IClassifierProvider))]
[ContentType(MyLangLanguage.ContentType)]
[Name("MyLangSyntaxProvider")]
internal sealed class MyLangSyntaxProvider : IClassifierProvider
{
[Import]
internal IClassificationTypeRegistryService ClassificationRegistry = null;
public IClassifier GetClassifier(ITextBuffer buffer)
{
return buffer.Properties.GetOrCreateSingletonProperty(() => new MyLangSyntax(ClassificationRegistry, buffer));
}
}
internal sealed class MyLangSyntax : IClassifier
{
private ITextBuffer buffer;
private IClassificationType identifierType;
private IClassificationType keywordType;
public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;
internal MyLangSyntax(IClassificationTypeRegistryService registry, ITextBuffer buffer)
{
this.identifierType = registry.GetClassificationType(PredefinedClassificationTypeNames.Identifier);
this.keywordType = registry.GetClassificationType(PredefinedClassificationTypeNames.Keyword);
this.buffer = buffer;
this.buffer.Changed += OnBufferChanged;
}
public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan snapshotSpan)
{
var classifications = new List<ClassificationSpan>();
string text = snapshotSpan.GetText();
var span = new SnapshotSpan(snapshotSpan.Snapshot, snapshotSpan.Start.Position, text.Length);
classifications.Add(new ClassificationSpan(span, keywordType));
return classifications;
}
private void OnBufferChanged(object sender, TextContentChangedEventArgs e)
{
foreach (var change in e.Changes)
ClassificationChanged(this, new ClassificationChangedEventArgs(new SnapshotSpan(e.After, change.NewSpan)));
}
}
}
Set <IncludeAssemblyInVSIXContainer> to true in the .csproj file, per
this suggestion.
I had exactly the same problem and this solved it. Do a full rebuild.
I want to include the current time and date in a .net application so I can include it in the start up log to show the user what version they have. Is it possible to retrieve the current time during compilation, or would I have to get the creation/modification time of the executable?
E.g.
Welcome to ApplicationX. This was built day-month-year at time.
If you're using reflection for your build number you can use that to figure out when a build was compiled.
Version information for an assembly consists of the following four values:
Major Version
Minor Version
Build Number
Revision
You can specify all the values or you can accept the default build number, revision number, or both by using an asterisk (*). Build number and revision are based off Jan 1, 2000 by default.
The following attribute will set Major and minor, but then increment build number and revision.
[assembly: AssemblyVersion("5.129.*")]
Then you can use something like this:
public static DateTime CompileTime
{
get
{
System.Version MyVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
// MyVersion.Build = days after 2000-01-01
// MyVersion.Revision*2 = seconds after 0-hour (NEVER daylight saving time)
DateTime compileTime = new DateTime(2000, 1, 1).AddDays(MyVersion.Build).AddSeconds(MyVersion.Revision * 2);
return compileTime;
}
}
The only way I know of doing this is somewhat convoluted -
You can have a pre-build event that runs a small application which generates the source code on the fly. An easy way to do this is to just overwrite a very small file that includes a class (or partial class) with the day/month/year hardcoded as a string constant.
If you set this to run as a pre-build event, it will rewrite that file before every build.
You could use PostSharp to weave in the date immediately post-build. PostSharp comes with a lightweight aspect-oriented programming library, but it can be extended to weave in anything you need in a wide variety of ways. It works at the IL level, but the API abstracts you a bit from that.
http://www.postsharp.org/
There's nothing built into the language to do this.
You could write a pre-build step to write out the current date and time to a source file though (in a string literal, for example, or as source code to generate a DateTime), and then compile that as part of your build.
I would suggest you make this source file as simple as possible, containing nothing but this information. Alternatively it could edit an existing file.
For an example of this, see the build file for MiscUtil which embeds the current SVN revision into the AssemblyFileVersion attribute. Some assorted bits of the build file:
<!-- See http://msbuildtasks.tigris.org -->
<Import
Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<!-- Find out what the latest version is -->
<SvnInfo RepositoryPath="$(SvnUrl)">
<Output TaskParameter="LastChangedRevision" PropertyName="Revision" />
</SvnInfo>
<!-- Update the AssemblyInfo with the revision number -->
<FileUpdate Files="$(OutputDirectory)\MiscUtil\MiscUtil\Properties\AssemblyInfo.cs"
Regex='(\[\s*assembly:\s*AssemblyFileVersion\(\s*"[^\.]+\.[^\.]+)\.([^\.]+)(\.)([^\.]+)("\)\s*\])'
ReplacementText='$1.$2.$(Revision)$5' />
In makefiles for C programs, it is common to see something like this:
echo char * gBuildSig ="%DATE% %TIME%"; > BuildTimestamp.c
And then the resulting C source file is compiled into the image. The above works on Windows because the %date% and %time% variables are known in cmd.exe, but a similar thing would work on Unix using cat.
You can do the same thing using C#. Once again, this is how it would look if you are using a makefile. You need a class, and a public static property.
BuildTimestamp.cs:
echo public static class Build { public static string Timestamp = "%DATE% %TIME%";} > BuildTimestamp.cs
And then for the thing you are building, a dependency and a delete:
MyApp.exe: BuildTimestamp.cs MyApp.cs
$(_CSC) /target:exe /debug+ /optimize- /r:System.dll /out:MyApp.exe MyApp.cs BuildTimestamp.cs
-del BuildTimestamp.cs
Be sure to delete the BuildTimestamp.cs file after you compile it; you don't want to re-use it. Then, in your app, just reference Build.Timestamp.
Using MSBuild or Visual Studio, it is more complicated. I couldn't get %date% or %time% to resolve. Those things are pseudo environment variables, I guess that is why. So I resorted to an indirect way to get a timestamp, using the Touch task with AlwaysCreate = true. That creates an empty file. The next step writes source code into the same file, referencing the timestamp of the file. One twist - I had to escape the semicolon.
Your pre-build step should build the target "BuildTimestamp". And be sure to include that file into the compile. And delete it afterwards, in the post-build step.
<ItemGroup>
<StampFile Include="BuildTimestamp.cs"/>
</ItemGroup>
<Target Name="BuildTimestamp"
Outputs="#(StampFile)">
<Message Text="Building timestamp..." />
<Touch
AlwaysCreate="true"
Files="#(StampFile)" />
<WriteLinesToFile
File="#(StampFile)"
Lines='public static class Build { public static string Timestamp = "%(StampFile.CreatedTime)" %3B }'
Overwrite="true" />
</Target>
You could update the Assembly version in AssemblyInfo.cs as part of your build. Then you could do something like this
FileVersionInfo lvar = FileVersionInfo.GetVersionInfo(FileName);
FileVersionInfo has the information (build/version,etc) that you looking for. See if this works out for you.
Hi I used following method for the same...
private DateTime ExecutableInfo()
{
System.IO.FileInfo fi = new System.IO.FileInfo(Application.ExecutablePath.Trim());
try
{
return fi.CreationTime;
}
catch (Exception ex)
{
throw ex;
}
finally
{
fi = null;
}
}