ASP.NET v5 on a Build Server - asp.net

I'm trying to build a VS2015 ASP.NET v5 web app on our build server (basically, outside of Visual Studio). Our existing scripts simply invoke msbuild with the csproj file, but with this project I get:
Project File is empty
What is the "story" for "building" these new webapps outside Visual Studio? I believe they can still target .NET 4.5 (I hope so, as we're not upgrading web servers any time soon) so assumed it were possible.

Well there is no .csproj in a dnx project everything that is needed for dnu to build a project is contained in the project.json. There is a xproj file but you can ignore that. Microsoft has finally decided to see the light and uses xproj just for VS specific "stuff" and IDE agnostic project details are put in the project.json.
So to build a dnx project all you need is the right version of dnx and the project source code. Now AFAIK there are no out of the box solutions but everything is done with command line commands so script something up should be easy. It all depends on how robust of a solution you want to build.
To build a dnx project from the command line (assuming you have the proper dnx installed and set to active) it is just two commands. dnu restore runs a dependency check and dnu (a part of dnx) has a built in nuget client so it will reach out and grab dependencies if needed. dnu build runs that actual compilation.
So cd to the project root (which contains project.json) and run dnu restore then dnu build.
It gets more complex if you need to dynamically support different dnx versions. Keep in mind dnx versions are identified by runtime (coreclr or clr), architecture (x86, x64, etc), and a version number. So if you are only targetting say x64 builds on clr (full .net runtime) that eliminates two variables but what happens if a project requires a newer version of the runtime than what is installed on the build server? As an example say you installed (manually using dnvm) dnx-clr-win-x64.1.0.0-beta4 on the build server but at some point in the future a developer requires dnx-clr-win-x64.1.0.0-beta6-1200 to resolve a bug.
The simplistic solution would be just to install new runtime versions as needed and build all projects against the newest one needed. This isn't as bad as it might first sound. Once dnx gets out of beta changes to the runtime should be infrequent. Remember the runtime is the very low level code and unmanaged dlls. It is the bootstrapping stub that the BCL sits on top of. Hopefully there should not be that many changes to the dnx for a given OS, architecture and runtime.
For a more robust solution you could use scripting to find the runtime version required for a project. It is found in a solution level global.json. The script could then use dnvm list to determine if it has that runtime installed. If it doesn't then use dnvm install or dnvm upgrade to install the required version. Before starting the build it would use the command dnvm use to make the correct runtime active and then proceed with dnu restore and dnu build.
Honestly I expect some pretty robust solutions to come along. Task runners (gulp, grunt, etc) are first class citizens in .NET 5. Most likely your workflow will involve bower for client side dependency resolution, npm, grunt/gulp and some task packages for things like minifying js files. The build server is going to need all that as well so having a build task as a grunt or gulp package seems a pretty good fit.

Related

Building MSI in azure devops

We have for a while been building various web projects with AzureDevops and self hosted build agents.
Today I had to add a new build, consisting of a windows service written in .net core 3.1. This service has to be installed by our customers, so we have to provide it in a friendly installable way. As some of our developers were already used to handle MSI/*.vdproj projects, they added a vdproj into the *.sln to manage that. On a developper machine, this is not a problem even with VS2019: you just have to use the relevant VS studio extension...
But when it comes to building that in a CI/CD context, this becomes a real challenge. I quickly understood that we can't use MSBuild at all for that and found some alternative using directly Visual Studio (devenv)... Inspired by this thread (still opened), I came up with the following command line:
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\devenv" [...]\MySolution.sln /build "Release" /Project MyInstallationProject
This worked fine both on my developer machine and even on the build agent machine. But when I add it into a build pipeline as a command line task, it seems to hang, and after a while I get the following result for the job:
##[error]The job running on agent <MyAgent> ran longer than the maximum time of 60 minutes. For more information, see https://go.microsoft.com/fwlink/?linkid=2077134
What can I do to make it work?
What are the best practices for generating a self installable in a CI/CD context? (Is MSI still relevant? )
As a workaround, you can try to install the extension Build VS Installer and use the task DutchWorkz - Build VS Installer(s) to build Visual Studio Installer Project in Azure Pipelines.
Here are some tickets(ticket1, ticket2) with similar issue you can refer to.

NuGet exited with code -1073741502 - .Net Build Failing

I'm getting the error.
The command:
"C:\ProjectDir\.nuget\NuGet.exe" install "packages.config"
-source "https://www.nuget.org/api/v2/"
-NonInteractive
-RequireConsent
-solutionDir "C:\ProjectDir\ "
exited with code
-1073741502 while building one of my Class Library projects in my solution.
As a result, I'm getting many
Metadata file 'C:\ProjectDir\src\ProjectName\bin\ProjectName.dll' could not be found`
errors from other projects in my solution.
When I click on restore packages for the solution it shows that there are no packages to restore.
Any idea about the fix?
While it's interesting to know that NuGet exited with an error code, it's far more interesting and useful to know what the program's output is. By not sharing that with us, we have to do a lot of guessing, reducing the chance that you get an answer that helps your specific case.
Anyway, NuGet.exe's program returns 1 for almsot all error codes (unless something throws an ExitCodeException, but it appears that only signing related code returns anything other than 1). Therefore, I conclude that NuGet didn't actually run. My best guess is that you ran on a machine without recent versions of the .NET Framework installed, but you're running a newish version of nuget.exe that needs a newer .NET Framework.
You also didn't say what version of nuget.exe you're using. NuGet 5.x is designed for Visual Studio 2019, which has a minimum requirement of the .NET Framework 4.7.2. NuGet 4.x is designed for Visual Studio 2017, which has a requirement of .NET Framwork 4.6. However, Wikipedia says that the .NET Framework was released in April 2018, which suggests to me that if you don't have that installed, you're not running Windows Update and so you're probably vulnerable to all sorts of malware. Perhaps you've just turned off recommended updates and getting only the critical updates, but it's worth checking.
So, while I expect this to be the cause of the problem, I also want to comment that it's normal to run nuget restore, not nuget install, to restore packages for projects and solutions. Also, it's typical to simply run nuget restore mysolution.sln. This has several benefits. NuGet can restore the entire solution more efficiently than one project at a time. Secondly you no longer need to provide the -SolutionDir argument.
One possibility about why you're restoring one project at a time is hinted by the fact that you're running some_path\.nuget\nuget.exe. This was done in Visual Studio 2010, VS2012 and VS2013, but was removed from VS2015 onwards. Back then it was enabled by right clicking the project and selecting "Enable NuGet restore for solution" or something like that. This was because NuGet was not really integrated with Visual Studio back then, other than adding this command which would modify all your .NET project files and create the .nuget/ directory with 3 files. Since then NuGet is integrated with Visual Studio and can do automatic restores without hacking project files, so it's no longer needed. NuGet has docs on migrating to automatic package restore.
The only advantage of the old package restore that changes the .NET project files is that on a CI machine there's nothing extra to do. Simple clone the repo and run msbuild. Once it's removed, it's necessary to run nuget restore on the solution file before building, to restore packages.config projects. If you can migrate to PackageReference (needs Visual Studio 2017 or later), then the NuGet restore step isn't necessary, you can run msbuild /restore mysoltuion.sln, or if all projects in the solution are SDK style, just dotnet build. Although some people still prefer to separate restore and build into separate steps, so when there's a failure, it's more obvious if it was a restore or compile error.

what is the best way to find out if a nuget package is compatible with .net core without nuget.org?

I know nuget.org does not have this functionality yet, but I have been searching for release notes on the nuget package developer websites, and this is taking longer than expected, since I have a lot of nuget packages installed on my .net framework project.
Is there a better way to do this? maybe someone has already done it and posted a list somewhere?
thanks in advance
If you change the 'n' in the nuget URL to an 'f', so it becomes fuget, you'll get a list of which frameworks the package targets. If you see it targets a netstandard version then it will work with .NET Core.
If your project is using an "old" style csproj with packages.config, the first step is to migrate to using PackageReference instead. Here's some docs. As the docs say, there are some differences between how packages.config and PackageReference works. If you're affected, you're blocked until you can make your project work with PackageReference.
If your project is using an "old" style csproj with PackageReference (for example you did the migration above), then migrate to SDK-based csproj so you can build with the dotnet CLI. Here's a blog post with details how to do it.. Note you you can keep using the Windows .NET Framework with SDK csproj. Although SDK-based csproj came out at the same time as .NET Core, it's not necessary to use .NET Core with the new project style. If your project is a class library or console app, you're definitely fine, otherwise you need to research to find out if the project type is compatible with SDK projects or not.
Once you have your .NET Framework project working with SDK projects, either change the TargetFramework to netcoreapp or netstandard, or you can multi-target your project by changing TargetFramework to TargetFrameworks, and use a semi-colon separated list of TFMs you want to target. For example <TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>. Then simply run dotnet restore and if any of the packages you use is not compatible with .NET Core, restore will fail, and you simply revert to target only .NET Framework.
In summary, once your project uses SDK-based csproj, it takes 10 seconds to test if your dependencies are compatible with .NET Standard/.NET Core. If your project is not yet using SDK-based csproj, you undo your change to the TargetFramework(s) line in your csproj and continue with your life until the next time you test again. If you're not already on SDK-based csproj and there's nothing blocking you from doing so, then doing the upgrade is low risk and bring some benefits, such as fewer merge conflicts on the file, much easier to create nupkgs for any packages you maintain, and being able to test against .NET Core compatibility in seconds.
Alternative: If you're unable or unwilling to migrate to SDK-based projects and you want to check if your dependencies are compatible, then use dotnet new classlib to create a new .NET Core project, add package references to the same packages that your existing project uses, then try to restore. If you have a big solution with lots of projects and/or references, just write a small program to read your packages.config/csproj files as XML, find unique list of packages that you use, then write a new SDK-based csproj targeting .NET Core with all the packages you just found as package references.

Can I shrink a dotnet publish package

I have recently started developing using dotnet core (as opposed to old fashion plain .net) to create a number of small utility console applications.
The development is fine and it has come to the point I want to publish them.
I am using the CLI and as I am only interested in Win 10 deployments, tried
dotnet publish -c release -r win10-x64
It worked and built me a "publish" folder where everything seemed to work, though the "publish" folder is huge (~70mb) compared to the size of the app (~500 lines of code).
As I am only going to deploy to Win10 machines is there a way to package this so I don't need all the .NET files? I thought that was what the -r option was for but that does not seem to have achieved much.
It depends on how you want to deploy your app/who is going to use them.
The -r flag creates a self-contained app. This causes the publish command to include the necessary .NET Core DLL's for the specified platform (and platform specific nuget packages if they are avaiable), which means anyone can use the app without having to install .NET Core runtime.
If you remove the -r flag then publish will only include the DLL's for you app. But this means whoever wants to use your app must first install the .NET Core runtime.
You can see the difference by using the -o flag to write the publish output to different directories e.g.
dotnet publish -c release -r win10-x64 -o ./publish-win10
or
dotnet publish -c release -o ./publish-any
Now go and have a look at what has been written to ./publish-win10 and ./publish-any folders and you can the difference.
If you are installing them onto a system where the .NET Core runtime is already present then you can just distribute the DLL and save a lot of space. However if you want to be able to distribute the app without the end user having to worry about having the .NET Core runtime installed then the -r flag to create a self-contained distribution is the way to go, but results in the 'package' including the necessary .NET Core assemblies.
AFAIK the -r flag does not affect how you app is compiled, just what runtime DLL's are included as part of the publish command. So you always get the same DLL for your code if you publish it for win10-x64 or with, or without, the -r flag so your app DLL will run on any (.NET Core compatible) platform, but I am happy to be corrected on that point.
Unlike .NET 4.x which you are used to where building is the standard to create an output, .NET Core (And .NET 5) considers building and publishing to be very different.
The huge (70MB) size is because the publisher is assuming that your target does not have any form of the .NET Framework installed, so is bundling it in with your project.
You can change your publish line to
dotnet publish -r win-x64 --self-contained false
Just by itself, this will create the .NET Core standard - A .dll (Your application), a .exe (That runs the application), some .json files for settings, and a .pdb file for debugging symbols.
To alter the application to the .NET Framework standard output that you are used to, open the .csproj file in a text editor, and below the
<TargetFramework>netx.x</TargetFramework>
line, add
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
And rerun the publish command. This will result in a single .exe and a single .pdb in the publish directory (The .pdb file which you can safely delete).
Note: Since you have included --self-contained false, the target will need the specified version of the .NET Framework (The one specified in your .csproj file) installed. Whilst many versions of the .NET Framework are currently installed on most Windows 10 Devices (Generally located at C:\Windows\Microsoft.NET\Framework or C:\Program Files\dotnet\), the .NET Core / .NET 5 Runtimes aren't yet as common (Although will likely be distributed through Windows Update in the near future), so may require a once-off download if the recipient of your .exe does not have it.
Whilst the .NET Core / .NET 5 resultant binaries ARE larger (Although by around 150kb - Not 50MB), they run significantly faster than their .NET Framework 4.x counterparts.

ASP.net 5 publish output too large?

I have a barebones ASP.net 5 web project, created from the Empty template.
I publish it in the file system. I have the folders /approot, /logs, and /wwwroot in /bin/WebsiteName/Release/PublishOutput.
The /approot folder alone is 103MB.
That seems a bit much. How to lower that?
If that is how it is, what new concepts may I might not know?
That folder has the application, its dependencies, and the runtime. Basically, everything that you need in order to run the app. Move it to another machine and it runs, nothing else needed. If the app runs on CoreCLR, there's a good chance that a big chunk of that folder is only the runtime.
Now, there are a few ways to reduce the size of the deployment package but then you'll have to get the dependencies and/or the runtime on the target server.
So, a full application, with everything would be published with dnu like this:
dnu publish --runtime <runtime1> ... --runtime <runtimeN> --no-source`
Publish only for a particular framework. If your app targets both dnxcore50 (CoreCLR) and dnx451 (Desktop CLR) you can chose to publish only one of them using dnu publish:
dnu publish --framework dnxcore50 --runtime <the framework for dnxcore50>
Don't publish the runtime. Leave the runtime out and get it somehow else on the target machine (that's what Azure WebSites does):
dnu publish (no --runtime)
I don't recommend this but if you really want you can compile the target app on the server and only publish the sources. Then you can restore (dnu restore) on the server.
Check if you really need all the packages that your app includes. For example, do you include System.Linq.Expressions but don't use it? It will be published because the publish algorithm cannot determine what's actually used.

Resources