Code Contracts and Programmatically compiling projects - c#

I have a bunch of legacy web projects that are compiled using a custom build application that we wrote. This because the depedencies were complex and the code... is... less than optimal. On the plus side it has recently been upgraded to .NET 4.5 and we are using Visual Studio 2013.
I recently started using code contracts in one of our other projects and really like the SoC it provides. I want to implement this in the legacy code that we are maintaining for new features (without doing a complete re-write). In development I have gotten it to work as long as I do a build from within VS and copy the compiled DLL files into the BIN folder of the web application (aps.net 32bit latest IIS).
I want to include the contracts in our release build as well using our Build tool. Otherwise I would have to use the tool and then use VS to create a release which is a 2 step process. I have complete source control over the tool (which is executed locally on my DEV PC) but I cannot get it to produce output with the code contracts. I read the Code Contract documentation and they mention the build script Microsoft.CodeContracts.targets and I have tried to add this into the build code without success. Admittedly my knowledge of the build process, build scripts, etc. is lacking at best. Any help / pointers in how to get this to work would be greatly appreciated. I would still like to normally compile my code in VS and have contracts work as well as use the build tool and and contracts work.
(i have not manually changed any of the CSPROJ files)
Build Code:
Build code is done using Microsoft.Build and Microsoft.Build.Framework assemblies.
var pc = new ProjectCollection();
var buildLogger = new FileLogger();
var logFilePath = #"MyLog.log";
buildLogger.Parameters = string.Format("logfile={0}", logFilePath);
var binDirectory = Path.Combine(outputWebDir, "Bin");
var globalProperty = new Dictionary<string, string>();
globalProperty.Add("OutputPath", binDirectory);
globalProperty.Add("Configuration", publishParams.ReleaseMode);
globalProperty.Add("Platform", publishParams.PlatformMode);
if (projectFileToPublish.IndexOf("SOTAQ.WebPoint.Web.csproj", StringComparison.OrdinalIgnoreCase) < 0)
globalProperty.Add("SolutionDir", publishParams.SparcoSolutionPath);
if (isWebSite)
{
globalProperty.Add("WebProjectOutputDir", outputWebDir);
globalProperty.Add("DeployOnBuild", "True");
}
globalProperty.Add("CodeContractsInstallDir", #"C:\Program Files (x86)\Microsoft\Contracts\");
globalProperty.Add("CodeContractRewriteCommand", #"C:\Program Files (x86)\Microsoft\Contracts\Bin\ccrewrite.exe");
globalProperty.Add("CodeContractAnalysisTargets", #"C:\Program Files (x86)\Microsoft\Contracts\MsBuild\v4.0\Microsoft.CodeContractAnalysis.targets");
globalProperty.Add("CodeContractsCCDocgenCommand", #"C:\Program Files (x86)\Microsoft\Contracts\Bin\ccdocgen.exe");
globalProperty.Add("CodeContractsCCRefgenCommand", #"C:\Program Files (x86)\Microsoft\Contracts\Bin\ccrefgen.exe");
string[] targets;
if (isWebSite)
targets= new[] { "Build", "ResolveReferences", "_CopyWebApplication" };
else
targets = new[] { "Build", "ResolveReferences" };
var buildRequestData = new BuildRequestData(projectFileToPublish, globalProperty, null, targets, null);
var buildParams = new BuildParameters(pc);
buildParams.Loggers = new[] {buildLogger};
BuildResult buildResult = BuildManager.DefaultBuildManager.Build(buildParams, buildRequestData);
Any help is greatly appreciated!!
Thanks in advance,
-Igor

After reading and re-reading the diagnostic output from Visual Studio and comparing it to my build project and trying many various possible solutions I found online the answer was to add the variable CodeContractsEnableRuntimeChecking with value true.
globalProperty.Add("CodeContractsEnableRuntimeChecking", "true");
Once that was added everything worked as expected.
-Igor

Related

Convert publish profile file (.xml) into DacDeployOptions class

I am working on a C# project where I should deploy few .dacpac files so I have used the Microsoft.SqlServer.DacFx library (github from DacFx here).
I have used also in another part the SqlPackage.exe executable to deploy another .dacpac files (no relation between them), so I'm using a publish profile (.xml / .pubxml file) to configure the deployment options. The cmd command looks like this:
SqlPackage /Profile:"Database.publish.xml"
I would need to deserialize this .xml file into a DacDeployOptions class in order to use the same pulish profile when publishing the dacpacs, but as much as I have been able to search I can't find a way to do it. I would appreciate some help with this.
Thanks 😃
After a long search I found the solution. Here the needed Code:
DacProfile profile = DacProfile.Load(#"C:\temp\publish.xml");
PublishOptions options = new PublishOptions();
options.GenerateDeploymentReport = true;
options.GenerateDeploymentScript = true;
options.DeployOptions = profile.DeployOptions;

Enumerate Files in a .csproj (dotnet core)

I am working on a build tool in C# that should work with Visual Studio / MSBuild. I want to enumerate all files that are part of a C# project. The project format is the new (.NET Core) .csproj.
The documentation describing the Project System points at using MSBuild (file format) or Common Project System (project tree). I'm unfamiliar with both APIs. Looking at documentation for those respective projects is not immediately helpful.
As the expert probably knows, the new .csproj file does not list every file that is implicitly part of the project. On the other hand it may list a 'linked' file that is outside the project folder. I want to make sure I get all files that are considered part of the project.
Ultimately I want to focus on a particular file type (.json), but I thought the general question was worth asking.
To sum up: How can I write a C# library that leverages the appropriate packages to (hopefully easily) enumerate all the files in a csproj?
Buildalyzer is the easiest package to use, and it targets .NETStandard 2.0 making it cross-platform. (Omnisharp does not currently offer a NuGet package for working with the workspace. And Microsoft.CodeAnalysis poses a challenge to get the correct references in place, and is limited to net46.)
using Buildalyzer;
private static IList<string> InlcudedProjectKeys = new[] { "None", "Compile", "Content", "EmbeddedResource" };
private static IEnumerable<string> EnumerateProjectFiles(string projectPath)
{
AnalyzerManager manager = new AnalyzerManager();
ProjectAnalyzer analyzer = manager.GetProject(projectPath);
AnalyzerResults results = analyzer.Build();
AnalyzerResult result = results.Single();
// If only interested in C# files, check out:
//string[] sourceFiles = result.SourceFiles;
IReadOnlyDictionary<string, ProjectItem[]> items = result.Items;
foreach (var item in items)
{
// Skip keys like ProjectReference that aren't for files
if (!InlcudedProjectKeys.Contains(item.Key))
continue;
ProjectItem[] projectItems = item.Value;
foreach (var projectItem in projectItems)
{
// The item spec for files will be the path relative to the project directory
yield return projectItem.ItemSpec;
}
}
}
And for bonus points, to get only *.json files:
var jsonFiles = EnumerateProjectFiles(projectPath)
.Where(path => path.EndsWith(".json"))
.ToArray();
Thanks Hitesh for linking to relevant resources.
You can use Roslyn Analyzer Libraries to load csproject and access it's content as well as properties in program. you can follow instructions from this previous SO post, or use OpenProjectAsync(projectFilePath) method to load instance of Project class in Microsoft.CodeAnalysis namespace.
using Microsoft.CodeAnalysis.MSBuild;
AnalyzerManager manager = new AnalyzerManager();
ProjectAnalyzer analyzer = manager.GetProject(#"C:\MyCode\MyProject.csproj");
You can find more information on roslyn at Github.

How can I use an SLN file with MSBuild programmatically from C#?

I am trying to create a custom MSBuild script in C#, using the newer Microsoft.Build.Evaluation API. The problem I have is that this newer API does not support .sln files. The older deprecated Microsoft.Build.Engine API does support .sln files, but I'd like to use the newer one because 1) it's not deprecated and 2) there seems to be more online documentation and usage to reference. I've seen that MSBuild can create a .metaproj file when is successfully compiles a solution, when this assignment is made in CMD: set MSBuildEmitSolution=1. I need the .metaproj file to be able to compile the solution in the first place. Is there anything in the API for converting .sln to .metaproj? Is there any library out there for parsing .sln files?
I figured it out after more searching. Finding good examples online is a little difficult because of the two different versions of the MSBuild API, and the popularity of just running MSBuild from the command line.
Here is the code that is now working for me, using the newer MSBuild API:
var pc = new ProjectCollection();
var parameters = new BuildParameters(pc)
{
Loggers = new[] { _logger } //Instance of ILogger instantiated earlier
};
var request = new BuildRequestData(
projectFullPath: pathToMySlnFile, //Solution file path
globalProperties: myPropertyDictionary,
toolsVersion: null,
targetsToBuild: myTargetsArray,
hostServices: null,
flags: BuildRequestDataFlags.ProvideProjectStateAfterBuild);
var buildResult = BuildManager.DefaultBuildManager.Build(parameters, request);

How Can I run EntityFramework Reverse POCO Code First Generator (T4) programmatically?

I want to use "EntityFramework Reverse POCO Code First Generator" but programmatically not from VS.
EntityFramework Reverse POCO Code Github
In fact I want to Run T4 for this purpose from C# code
I downloaded simple-t4-engine for this purpose
Simple T4 Engine
I wrote some code like this :
Engine engine = new Engine();
TemplatingHost host = new TemplatingHost(System.Text.Encoding.UTF32);
host.IncludeFileSearchPaths.Add(#"D:\IncludeFiles");
string templateFileName = "some template";
// NOTE: Doesn't actually seem to care about the name of the template file? True, but does use the path to search for stuff.
host.TemplateFile = templateFileName;
string input = File.ReadAllText(#"D:\IncludeFiles\T4Files\Database.tt");
string output = engine.ProcessTemplate(input, host);
File.WriteAllText(#"D:\IncludeFiles\T4Files\Output.txt", output);
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in host.Errors)
{
sb.AppendLine(error.ToString());
}
File.WriteAllText(#"D:\IncludeFiles\T4Files\ErrorLog.txt", sb.ToString());
But I got some errors (Output.txt is Empty)
ErrorLog.txt :
error : Running transformation: System.InvalidCastException: Unable to cast transparent proxy to type 'System.IServiceProvider'.
at Microsoft.VisualStudio.TextTemplating31A64EBEAB614B57E81A1789EC7637709A091834D5CA991E8A2195B15E2A0DFF588B0C98DCEDA8AD6902329A28B09556BDE2A9BEDFA48812CCC12CA1E68AA1C9.GeneratedTextTransformation.GetDTE()
at Microsoft.VisualStudio.TextTemplating31A64EBEAB614B57E81A1789EC7637709A091834D5CA991E8A2195B15E2A0DFF588B0C98DCEDA8AD6902329A28B09556BDE2A9BEDFA48812CCC12CA1E68AA1C9.GeneratedTextTransformation.GetCurrentProject()
at Microsoft.VisualStudio.TextTemplating31A64EBEAB614B57E81A1789EC7637709A091834D5CA991E8A2195B15E2A0DFF588B0C98DCEDA8AD6902329A28B09556BDE2A9BEDFA48812CCC12CA1E68AA1C9.GeneratedTextTransformation.GetConfigPaths()
at Microsoft.VisualStudio.TextTemplating31A64EBEAB614B57E81A1789EC7637709A091834D5CA991E8A2195B15E2A0DFF588B0C98DCEDA8AD6902329A28B09556BDE2A9BEDFA48812CCC12CA1E68AA1C9.GeneratedTextTransformation.GetConnectionString(String& connectionStringName, String& providerName, String& configFilePath)
at Microsoft.VisualStudio.TextTemplating31A64EBEAB614B57E81A1789EC7637709A091834D5CA991E8A2195B15E2A0DFF588B0C98DCEDA8AD6902329A28B09556BDE2A9BEDFA48812CCC12CA1E68AA1C9.GeneratedTextTransformation.InitConnectionString()
at Microsoft.VisualStudio.TextTemplating31A64EBEAB614B57E81A1789EC7637709A091834D5CA991E8A2195B15E2A0DFF588B0C98DCEDA8AD6902329A28B09556BDE2A9BEDFA48812CCC12CA1E68AA1C9.GeneratedTextTransformation.GetDbProviderFactory()
at Microsoft.VisualStudio.TextTemplating31A64EBEAB614B57E81A1789EC7637709A091834D5CA991E8A2195B15E2A0DFF588B0C98DCEDA8AD6902329A28B09556BDE2A9BEDFA48812CCC12CA1E68AA1C9.GeneratedTextTransformation.TransformText()
Can anyone help me for solve this problem ?
or introduce a better way for run Database.tt in runtime an execute in C# programmatically.
Database.tt
EF.Reverse.POCO.Core.ttinclude
EF.Reverse.POCO.ttinclude
EF.Utility.CS.ttinclude
EF6.Utility.CS.ttinclude
GenerateTSQL.Utility.ttinclude
I am the author of the Entity Framework Reverse POCO Generator.
Unfortunately, you can't run this outside of Visual Studio because the code depends on it. The EnvDTE provides the ability for the reverse generator to add/remove generated files from the Visual Studio project. Without this, it will not be able to do it's job.
Others have asked if they can run it on the build server. However the build server may not have access to the database it needs to reverse engineer. So always generate the code by saving the tt settings file, and commit the generated code to source control, and from there on to your build server.
By the way, just to be clear: I don't want this project to be automated outside of Visual Studio, or to be included in another product of any kind. This is stipulated in the license.
You can use TextTransform Utility to transform T4 files outside Visual Studio. Normally you can find util in folder:
\Program Files\Common Files\Microsoft Shared\TextTemplating\
I think this is a start for your problem please research more about this tool and check if fit your issue.

MSBuild: define subprojects build configuration in BuildEngine

I'm using BuildEngine as a step to create a one click build environment. The code is the following:
Engine engine = new Engine();
FileLogger logger = new FileLogger { Parameters = #"logfile=C:\builds\build.log" };
engine.RegisterLogger(logger);
var project = new Project(engine);
project.Load("Example.csproj");
project.SetProperty("Configuration", "Release");
bool success = project.Build();
And he seems to build project Example with release configuration. But when I look at the build.log, all of the dependencies of Example project were build as debug.
Is there any way to force it to build all dependencies on Release?
Set the global properties on the engine:
BuildPropertyGroup bpg = new BuildPropertyGroup ();
bpg.SetProperty ("Configuration", "Release");
engine.GlobalProperties = bpg;
These will override the properties set by the project themselves.
Engine class is obsolete.
Use Microsoft.Build.Evaluation.ProjectCollection instead.
It enables to pass global properties as you do when calling msbuild from command line.
I should warn you that msbuild eats a lot memory. I have a bot on a build machine working as a service. When it recieves command to build it creates new process and calles Build(). Sometimes memory usage reaches 2GB (our build is huge). When you call MSBuild from command line it releases memory much more effective.
Try to test 2 implementations - throw API and throw calling MSBuild.exe - in a loop. May be in MSBuild 4.0 MS solved those memory problems.

Categories