Run a c# console application in build process - c#

Suppose we have a solution with three projects:
DownloadDataBase is a console application that downloads data from web and creates a sqlite db file
Test is the main windows from application that uses the downloaded sqlite database.
TestLibrary is a class library that is referenced by the Test project.
I know How I can reorder the build of these three projects using Configuration Manager from build menu. But The main question is : How can I customize build process of the solution so that:
It first builds the DownloadDataBase
Then executes this console application DownloadDataBase
After that copy the created sqlite file from the last step to the resource directory of the Test Project
And Finally builds the Test project using the updated sqlite file?
Therefore every time that I build the new release I will have the latest data needed by my application.
Thanks for any help

You'll need to customize your MSBuild project files (i.e. .csproj files).
For example, in your DownloadDatabase project, add at the bottom of the XML file, inside the <project> element:
<Target AfterTargets="AfterBuild">
<Exec Command="$(ProjectDir)$(OutputPath)$(AssemblyName).$(OutputType)" />
<Copy SourceFiles="$(ProjectDir)$(OutputPath)file.db" DestinationFolder="$(SolutionDir)Test" />
</Target>
Maybe there's some mistake, but at the end of the day, you need to use MSBuild tasks to perform these actions.
See Exec and Copy MSBuild task documentation pages to get further details.

Related

How do I build a node project during a visual studio build, separately from a C# project?

Visual Studio 2019 comes with Single Page App templates for .net Core apps. The React typescript template sets up the project like the following:
Create a Solution in the Project/Project.sln
Create an ASP.NET Core REST endpoint example in Project/WebApi/WebApi.csproj
Contains a Single Page app in the Project/WebApi/ClientApp folder.
Build that project as part of building the rest of that project.
I'd like to do the same, but instead of having the node project embedded in the C# project folder, have them be separate projects within the same solution. So instead of:
* Project/Project.sln
* Project/WebApi/Startup.cs // and all other C# code
* Project/WebApi/ClientApp/package.json // and all other node/typescript code
I'd rather set up the project like:
* Project/Project.sln
* Project/WebApi/Startup.cs // and all other C# code
* Project/ClientApp/package.json // and all other node/typescript code.
What's the best way to go about separating out the node project from the C# project, and still get it to all build as part of the solution's build?
Bonus: how do I do this with just the dotnet command?
The basic idea behind how this can be accomplished involves touching two things:
You have to be able to serve static content (or front-end libraries) from node_modules that will be located inside a separate project
Every time you build a project, npm install should be triggered to make sure that all front-end dependencies are in place.
To be able to serve from node_modules, you either have to modify the UseStaticFiles() middleware yourself, or use OdeToCode.UseNodeModules and tweak it so that the path points to the folder inside the different project.
Finally, automatic postbuild actions can be set up inside .csproj file. Sample:
<Target Name="PostBuild" AfterTargets="ComputeFilesToPublish">
<Exec Command="npm install"/>
</Target>

A referenced project's pdb file not in this projects application files list

I have a C# WPF solution that contains three projects, MyApp, MyAppAdmin and MyAppLibrary. MyAppLibrary is referenced by the other two.
I need to be able to include MyAppLibrary.pdb when I publish MyApp (click once) but it does not show up in the projects Application Files even with "Show all files" checked.
If I open the Application Files for MyAppAdmin and have Show all files checked MyAppLibrary.pdb is in the list.
Any idea as to why the difference and/or how I can get it into the list for MyApp?
Thanks,
Dave
You didn't say what type of projects you have, so I can't confirm that this will work for you. If you have a web project, then you should be able to uncheck the Exclude generated debug symbols option on the Publish Web property page in Visual Studio.
Failing that, you can try to set that value directly in the project file. Right click your project file in a Windows Explorer window and edit in a text editor. You can add a new PropertyGroup with this value to the end of the file (within the Project element) like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<PropertyGroup>
<ExcludeGeneratedDebugSymbol>False</ExcludeGeneratedDebugSymbol>
<PropertyGroup>
</Project>
It looks like this issue is related to what solution platform is used. We need to run the application in 32 bit mode due to some dependancies we have. When this was originally setup we created a custom solution platform for some reason where MyAppLibrary and MyAppAdmin used the Any CPU platform but MyApp used x86. I switced to using the Any CPU for all of them and then specifying in each project to target the x86 platform.
Once this was done I know can see and include MyLibrary.pdb in the published output.
Dave

Web Application Build Error: The CodeDom provider type Microsoft.VisualC.CppCodeProvider could not be located

I'm building/packing a web application in a build server, and it fails with the following message:
ASPNETCOMPILER error ASPCONFIG: The CodeDom provider type
"Microsoft.VisualC.CppCodeProvider, CppCodeProvider, Version=10.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" could not be
located.
This is the build server environment:
Windows Server 2008 R2 Standard
TeamCity 8.0.4
.NET 4.5
Windows SDK for Windows 7 and .NET 4
Windows SDK for Windows 8 and .NET 4.5
Portable Class Library Tools
ASP MVC 4
It is a ASP MVC 4 web application, targeting .NET 4.5.
The build configuration consists in building the solution with MSBuild, and deploying it to a package, so I can publish it later.
Through the log of TeamCity, I can see the error arising when MSBuild runs aspnet_compiler.exe.
The builds with no problem in my DEV machine and can also publish it to a local IIS without problems.
Does anyone know what may be causing this issue?
UPDATE
See my answer below.
For me this error was popping up in VS2017 when building the web project. The fix was to make the node_modules directory hidden in File Explorer. Apparently this stops the ASP.NET compiler from scanning all these files and thus prevents the error.
This post gave me an important clue: apparently ASP.NET precompilation scans the project and output files and tries to compile every source file it finds in its way, despite its language (see here).
In the case, my web app depends on a project which includes some unmanaged dll along a ".h" file. These files are copied to the output directory ("Copy if newer") so I can pinvoke it at runtime.
It seems ASP.NET precompilation finds the ".h" and tries to compile it, even though there is no need of it. And, as I see it, it fails because my build server does not has the tools for the job (it looks like CppCodeProvider comes with the .NET 2.0 SDK).
When I changed the project not to copy those files to the output directory, the build ran fine. I also tested copying the files, but with "PrecompileBeforePublish" set to false in the publish profile, and it also worked.
Now I have some options, but I don't like any of them:
Disable "PrecompileBeforePublish". I believe the main disadvantage of that is the app users experience will be slower on the first site access.
Try to exclude files from the output folder and add them again after pre-compilation. That seems a lot of work for something I shouldn't be worrying in first place.
Try to tell "aspnet_compiler.exe" to exclude the offending files/folder when executing. I don't know how to do it using the publish profile, because I only have control over "PrecompileBeforePublish". Also, it seems "aspnet_compiler.exe" does not offer that option (here and here).
I think for now I'll disable "PrecompileBeforePublish", because it seems a fast path with few caveats. But I believe there should be a better way to handle it, excluding folders or file types from precompilation using the publish profile.
For the benefit of those who find this later on google...
Root Cause
As the error implies, the assembly "Microsoft.VisualC.CppCodeProvider" couldn't be found.
This was added to the Global Assembly Cache (GAC) as part of Visual Studio 2015 installation, but not Visual Studio 2017.
The Fix
The proper fix is to add the missing reference to the GAC.
Run the "Developer Command Prompt" as admin, and run the following
gacutil /i "path to CppCodeProvider.dll"
or gacutil /i "C:\Program Files (x86)\Microsoft Visual Studio\2
017\Professional\Common7\IDE\PublicAssemblies\CppCodeProvider.dll"
e.g.
C:\Windows\System32>gacutil /i "C:\Program Files (x86)\Microsoft Visual Studio\2
017\Professional\Common7\IDE\PublicAssemblies\CppCodeProvider.dll"
Microsoft (R) .NET Global Assembly Cache Utility. Version 4.0.30319.0
Copyright (c) Microsoft Corporation. All rights reserved.
Assembly successfully added to the cache
C:\Windows\System32>
On next build the following error is no longer thrown.
ASPNETCOMPILER error ASPCONFIG: The CodeDom provider type "Microsoft.VisualC.CppCodeProvider, CppCodeProvider, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" could not be located.
This started happening when I updating to VS2017. The problem for me was node.js, if I deleted the node_modules folder then the project would build without errors. It turns out that changing the value of MvcBuildViews to false in the csproj file as suggested by anders here fixes it. This isn't ideal though since mvc views won't be compiled until IIS renders them. Personally, I just hide the node_modules folder to get around the issue but I wanted to add this answer in case it helps shed some light on the underlying issue for someone else.
<MvcBuildViews>false</MvcBuildViews>
In my case I had added an angular website to my solution which caused this error.
Resolved the error with following steps.
On the menu bar, choose Build > Configuration Manager.
In the Project contexts table, exclude the angular website (which contained node_modules)
In the Build column for the project, clear the check box.
Choose the Close button, and then rebuild the solution.
In my scenario, I have to ship a Perl interpreter with my ASP.Net website (don't ask why I need Perl, and I'm sorry I do in advance!), and that included .c files that caused the aspnet_compiler.exe to error out, as others have mentioned being their problem. The perl directory is in my bin folder, and is required at runtime.
The trouble I found was when you attrib +H the folder, it indeed was skipped by aspnet_compiler, but then wouldn't be in my publish output folder. So I had to hack it even more by hiding the folder, compile views, unhide folder, and then copy folder to the right location. This involved modifying the original AspNetPreCompile task. See below:
<!-- Overwrite AspNetPreCompile task because it was trying to compile .c files found in the Perl directory. This prevents that but still copies Perl to publish file. -->
<!-- Taken from: C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\Microsoft\VisualStudio\v15.0\Web\Transform -->
<Target Name="AspNetPreCompile" DependsOnTargets="$(AspNetPreCompileDependsOn)" Condition="'$(AspNetPreCompile)' != 'false'">
<PropertyGroup Condition="'$(UseMetabasePath)' == 'true'" >
<_PreAspnetCompileMergeSingleTargetFolderFullPath></_PreAspnetCompileMergeSingleTargetFolderFullPath>
<_AspNetCompilerVirtualPath></_AspNetCompilerVirtualPath>
</PropertyGroup>
<PropertyGroup Condition="'$(UseMetabasePath)' != 'true'" >
<_PreAspnetCompileMergeSingleTargetFolderFullPath>$([System.IO.Path]::GetFullPath($(_PreAspnetCompileMergeSingleTargetFolder)))</_PreAspnetCompileMergeSingleTargetFolderFullPath>
</PropertyGroup>
<PropertyGroup>
<_PostAspnetCompileMergeSingleTargetFolderFullPath>$([System.IO.Path]::GetFullPath($(_PostAspnetCompileMergeSingleTargetFolder)))</_PostAspnetCompileMergeSingleTargetFolderFullPath>
</PropertyGroup>
<!-- Modification #1. -->
<Exec Command="attrib +H "$(IntermediateOutputPath)AspnetCompileMerge\Source\bin\perl"" />
<AspNetCompiler
PhysicalPath="$(_PreAspnetCompileMergeSingleTargetFolderFullPath)"
TargetPath="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)"
VirtualPath="$(_AspNetCompilerVirtualPath)"
Force="$(_AspNetCompilerForce)"
Debug="$(DebugSymbols)"
Updateable="$(EnableUpdateable)"
KeyFile="$(_AspNetCompileMergeKeyFile)"
KeyContainer="$(_AspNetCompileMergeKeyContainer)"
DelaySign="$(DelaySign)"
AllowPartiallyTrustedCallers="$(AllowPartiallyTrustedCallers)"
FixedNames="$(_AspNetCompilerFixedNames)"
Clean="$(Clean)"
MetabasePath="$(_AspNetCompilerMetabasePath)"
ToolPath="$(AspnetCompilerPath)"
/>
<!-- Modification #2. -->
<Exec Command="attrib -H "$(IntermediateOutputPath)AspnetCompileMerge\Source\bin\perl"" />
<!--
Removing APP_DATA is done here so that the output groups reflect the fact that App_data is
not present
-->
<RemoveDir Condition="'$(DeleteAppDataFolder)' == 'true' And Exists('$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\App_Data')"
Directories="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\App_Data" />
<CollectFilesinFolder Condition="'$(UseMerge)' != 'true'"
RootPath="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)" >
<Output TaskParameter="Result" ItemName="_AspnetCompileMergePrecompiledOutputNoMetadata" />
</CollectFilesinFolder>
<ItemGroup Condition="'$(UseMerge)' != 'true'">
<FileWrites Include="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\**"/>
</ItemGroup>
<!-- Modification #3. -->
<ItemGroup>
<Perl Include="$(IntermediateOutputPath)AspnetCompileMerge\Source\bin\perl\**\*.*" />
</ItemGroup>
<!-- Modification #4. -->
<Copy SourceFiles="#(Perl)" DestinationFolder="$(_PostAspnetCompileMergeSingleTargetFolderFullPath)\bin\perl\%(RecursiveDir)"></Copy>
</Target>
DO NOT modify the original .targets file, copy this into your .csproj file as a child to the <project> node.
Key takeaways:
Use Exec command to attrib +H Directory before running aspnet_compiler.exe via the AspNetCompiler task, and attrib -H Directory afterwards.
Create an ItemGroup to suck in all the files that still need to be copied.
Run the Copy task, utilizing that ItemGroup to put the files where they need to be in order for the rest of the publish task to include them. We get to use all of the variables that Microsoft made when authoring this Task, so we can use those here too.
Pro to modifying the original task: very little changes about the normal behavior, so it should still just work.
Possible con to modifying the original task: Microsoft might change this task in the future, making our copy out of date.
If you don't have my weird requirements, the simpler solution to hiding a folder is as follows:
<Target Name="Test" BeforeTargets="AspNetPreCompile">
<Exec Command="attrib +H Directory" />
</Target>
<Target Name="Test" AfterTargets="AspNetPreCompile">
<Exec Command="attrib -H Directory" />
</Target>
Answer inspired by the comment twamley made in Arthur Nunes answer.
In my case it was the node_modules folder. I made this change in my csproj file for my .net 4.8 app to fix it.
This will just add the hidden attribute to the node_modules folder and then unhide it after the Razor pages are compiled.
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<Exec Command="attrib +H "$(ProjectDir)node_modules"" />
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
<Exec Command="attrib -H "$(ProjectDir)node_modules"" />
</Target>
Try doing the folowing.
Setting RequireTargetFramework to 4.0.
Link:ASPNETCOMPILER error ASPCONFIG: Could not load file or assembly 'Microsoft.VisualBasic.Activities.Compiler' or one of its dependencies
In my case the issue was that the web config of a parent solution (root level project) in IIS had this in it's web config (by mistake, not sure how it got there). Took a long time to track down, because nothing I could do in my solution/project could affect it in any way.
So might be worth checking the web.config of all that might be involved.
For me this error was showing when my website's physical path was invalid in IIS. To resolve that right click on website (Manage website -> Advanced settings -> Physical Path).
In my case, on a new machine, installed VS2017 and opened an asp.net core 1.1 web application from source control. The error showed up. I installed node.js and the project compiled.
My solution to this error was a combination of two pre-existing answers on this page. I had a .h file in my web project directory that had not caused a problem until I tried to build the project on a VS 2017 machine.
In my case I simply zipped it up, but the upshot seems to be that you can no longer keep unrelated code files in the web directory or VS will trip up trying to compile them.
I solved it with deleting node modules folder then running npm i from git bash and not from VS2019 built in terminal.
Copy cppprovider.dll from Visual Studio 2015 installation path to:
C:\Program Files (x86)\Microsoft Visual Studio
11.0\Common7\IDE\PublicAssemblies
An easy way to solve is that to reference the CppCodeProvider.dll.
It may locate at
C:\Program Files (x86)\Microsoft Visual Studio{version}\{edition}\Common7\IDE\PublicAssemblies
For example:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\CppCodeProvider.dll
It will be in the bin folder.
I moved my solution from VS2019 to VS2022 and was having this error when I tried to publish solution. This is how I made the error disappear.
Right-click on References>> Add References
Then Search for Microsoft.VisualC
tick Microsoft.VisualC and Microsoft.VisualC.VSCodeProvider
click ok.
Error gone!
I installed VS2019 on a new laptop but kept getting the same error message as the OP. (it still worked fine on my desktop PC).
After a day or so of trying every answer on here and Google, and getting no joy, I tried using, from the toolbar, Build -> Publish Web App, which built my website into the Publish folder ok.
I then took this 'Publish' folder and copied it to a new place on my C:drive.
Then after closings and re-opening VS2019, started with "continue without code".
Then File -> Open -> Web Site... select my 'Publish' folder, and hooray I can now build and debug my project locally.
The issue was occurring for me when I was building a web project with node_modules. I fixed the error by enabling Desktop development with C++ option in my Visual Studio installer.
Source: https://developercommunity.visualstudio.com/t/cppcodeprovider-not-properly-installed-with-vs2017/240322#T-N333161
In Visual Studio 2017 CppCodeProvider.dll is getting shipped with “Desktop development with C++” as a result installing “Desktop development with C++” should resolve the issue.

Setting web.config properties during build (not through publishing)

I'm trying to deploy an app using a Web Setup Project. The problem I'm running into is that the web.config file is never transformed. According to this post it's by design that transformation only takes place during a publish. How do I get the web.config properties to update correctly if building the Setup Project in turn calls the other assemblies build command?
I fixed it by adding a dummy web.Template.config file like Andriy K suggested in this post, and then calling TransformXml during my BeforeBuild event like so:
<Target Name="BeforeBuild">
<TransformXml Source="$(WebFolderName)Web.Template.config"
Transform="$(WebFolderName)Web.$(Configuration).config"
Destination="$(WebFolderName)Web.config" />
</Target>
The simplest option is to install a command-line xslt utility and launch it in the post-build action of your project. You could also use one of the many MSBuild XSLT tasks and add it into the .csproj file. (It's just an MSBuild script file; there are comments already in there near the bottom explaining how to customize the build.)
You could also perform either of these steps in the pre-build action of your setup project, instead of the post-build action of your web application. If you also use the publishing wizard, this second option may work better as it won't interfere with the normal XSLT transforming going on in the publisher.
Microsoft XSLT command-line utility: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=2fb55371-c94e-4373-b0e9-db4816552e41&displaylang=en
Example MSBuild XSLT Task: http://www.arlt.eu/blog/2007/10/01/msbuild-xslt-task/

Visual Studio 2008 locks custom MSBuild Task assemblies

I'm developing a custom MSBuild task that builds an ORM layer, and using it in a project. I'm being hampered by Visual Studio's behaviour of holding onto MSBuild task DLLs and not letting go.
I'd like to organize my solution like this;
My Solution
|
+- (1) ORM Layer Custom Task Project
| |
| +- BuildOrmLayerTask.cs // here's my task
|
+- (2) Business Logic Project // and here's the project that uses it.
|
+- <UsingTask TaskName="BuildOrmLayerTask" AssemblyFile="$(TaskAssembly)" />
However, when project (2) builds, it locks onto the assembly from project (1). So now I can't build project (1) again without closing the solution and re-opening it.
Is there any way I can organize things so that the custom build task is not kept locked by Visual Studio?
(Edit: Sayed Ibrahim Hashimi, who literally wrote the book on msbuild, suggests the AppDomainIsolatedTask class for a better approach)
I've managed to solve this one myself...
Found this forum post from Dan Moseley, one of the MSBuild developers from Microsoft:
Hi there,
Unfortunately this is because MSBuild loads task assemblies in the
primary appdomain. The CLR does not allow assemblies to unload
from an appdomain as this allows important optimizations on their
part.
The only workarounds I suggest is to call out tomsbuild.exe to
build the projects that use the task. To do this, create
MSBuild.exe <> as an external tool in VS.
Dan
developer on msbuild
DanMoseley - MSFT
So, it seems that to stop the locks, you must spawn out a new MSBuild.exe process. It can't be the one that runs inside Visual Studio, because when MSBuild runs, it loads the tasks into Visual Studio's primary app domain, and that can never be unloaded.
create a new MSBuild project (a .csproj or similar) which overrides the 'Build' Target and performs your custom actions, eg;
<!-- fragment of Prebuild.csproj -->
<Target Name="Build">
<BuildOrmLayerTask Repository="$(Repository)" />
</Target>
Add it to visual studio if you want, but use Configuration Manager to make sure it is notbuilt in any configuration. Just let VS take care of source control and suchlike, not building.
Edit the .csproj file of the project that depends on Prebuild.csproj. Add a BeforeBuild target which invokes MSBuild using the Exec task. This will start a new process, and when that process ends, the file locks are released. Example;
<PropertyGroup>
<PrebuildProject>$(SolutionDir)Prebuild\Prebuild.csproj</PrebuildProject>
</PropertyGroup>
<Target Name="BeforeBuild">
<Exec Command="msbuild.exe "$(PrebuildProject)"" />
</Target>
Now, when you build the dependent project, it executes MSBuild in a new process before running the compile.
Can you edit the project files and include the following property declaration
<PropertyGroup>
<GenerateResourceNeverLockTypeAssemblies>true</GenerateResourceNeverLockTypeAssemblies>
</PropertyGroup>
Let me know if that works for you.
As I mentioned in a comment directed at #Al-Muhandis, it seems possible to create a wrapper around the custom task so that the wrapper gets locked but not the custom task DLL. I have taken an initial shot at doing so with the isolated-task project. It may be buggy, and it only works with VS2008 for now. Pull requests welcome.
The idea for the project was based on the observation that tasks deriving from MarshalByRefObject (using, perhaps, AppDomainIsolatedTask) appear to be loaded into the main application domain for reflection purposes, but a new application domain is created to execute the task. Since loading into the main application domain still seems to lock the DLL, it was useful to create a DLL with a task derived from AppDomainIsolatedTask that loads the custom task DLLs. That way, the wrapper DLL gets locked, but because it executes in its own app domain, the custom task DLLs are unloaded when the wrapper task's executing domain is unloaded. This procedure avoids keeping a lock on the custom task DLLs after the build is complete.

Categories

Resources