dotnet watch to msbuild (#2746)

* dotnet watch to msbuild

* remove white space

* clean up

* clean up

* TD feedback
pull/2897/head
Rick Anderson 2017-02-13 09:59:08 -10:00 committed by Tom Dykstra
parent a63cb12f45
commit 58715f7b93
10 changed files with 87 additions and 260 deletions

View File

@ -1,195 +1,97 @@
---
title: Developing ASP.NET Core applications using dotnet watch | Microsoft Docs
title: Developing ASP.NET Core apps using dotnet watch | Microsoft Docs
author: rick-anderson
description:
keywords: ASP.NET Core,
description: Shows how to use dotnet watch.
keywords: ASP.NET Core, using dotnet watch
ms.author: riande
manager: wpickett
ms.date: 10/14/2016
ms.date: 02/14/2017
ms.topic: article
ms.assetid: 563ffb3f-d369-4aa5-bf0a-7300b4e7832c
ms.technology: aspnet
ms.prod: asp.net-core
uid: tutorials/dotnet-watch
---
# Developing ASP.NET Core applications using dotnet watch
# Developing ASP.NET Core apps using dotnet watch
<a name=dotnet-watch></a>
By [Victor Hurdugaci](https://twitter.com/victorhurdugaci)
By [Rick Anderson](https://twitter.com/RickAndMSFT) and [Victor Hurdugaci](https://twitter.com/victorhurdugaci)
## Introduction
`dotnet watch` is a tool that runs a `dotnet` command when source files change. For example, a file change can trigger compilation, tests, or deployment.
`dotnet watch` is a development time tool that runs a `dotnet` command when source files change. It can be used to compile, run tests, or publish when code changes.
In this tutorial we use an existing Web API app with two endpoints: one that returns a sum and one that returns a product. The product method contains an bug that we'll fix as part of this tutorial.
In this tutorial we'll use an existing WebApi application that calculates the sum and product of two numbers to demonstrate the use cases of `dotnet watch`. The sample application contains an intentional bug that we'll fix as part of this tutorial.
Download the [sample app](https://github.com/aspnet/Docs/tree/master/aspnetcore/tutorials/dotnet-watch/sample). It contains two projects, `WebApp` (a web app) and `WebAppTests` (unit tests for the web app).
## Getting started
In a console, navigate to the WebApp folder and run the following commands:
Start by downloading [the sample application](https://github.com/aspnet/Docs/tree/master/aspnetcore/tutorials/dotnet-watch/sample). It contains two projects, `WebApp` (a web application) and `WebAppTests` (unit tests for the web application)
- `dotnet restore`
- `dotnet run`
In a console, open the folder where you downloaded the sample application and run:
The console output will show messages similar to the following (indicating that the app is running and waiting for requests):
1. `dotnet restore`
2. `cd WebApp`
3. `dotnet run`
The console output will show messages similar to the ones below, indicating that the application is now running and waiting for requests:
```bash
```console
$ dotnet run
Project WebApp (.NETCoreApp,Version=v1.0) will be compiled because inputs were modified
Compiling WebApp for .NETCoreApp,Version=v1.0
Compilation succeeded.
0 Warning(s)
0 Error(s)
Time elapsed 00:00:02.6049991
Hosting environment: Production
Content root path: /Users/user/dev/aspnet/Docs/aspnet/tutorials/dotnet-watch/sample/WebApp
Content root path: C:/Docs/aspnetcore/tutorials/dotnet-watch/sample/WebApp
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
```
In a web browser, navigate to `http://localhost:5000/api/math/sum?a=4&b=5` and you should see the result `9`.
In a web browser, navigate to `http://localhost:5000/api/math/sum?a=4&b=5`, you should see the result `9`.
If you navigate to `http://localhost:5000/api/math/product?a=4&b=5` instead, you'd expect to get the result `20`. Instead, you get `9` again.
Navigate to the product API (`http://localhost:5000/api/math/product?a=4&b=5`), it returns `9`, not `20` as you'd expect. We'll fix that later in the tutorial.
We'll fix that.
## Add `dotnet watch` to a project
## Adding `dotnet watch` to a project
- Add `Microsoft.DotNet.Watcher.Tools` to the *.csproj* file:
```xml
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0-msbuild3-final" />
</ItemGroup> ```
1. Add `Microsoft.DotNet.Watcher.Tools` to the `tools` section of the *WebApp/project.json* file.
2. Run `dotnet restore`.
The console output will show messages similar to the ones below:
```bash
log : Restoring packages for /Users/user/dev/aspnet/Docs/aspnet/tutorials/dotnet-watch/sample/WebApp/project.json...
log : Restoring packages for tool 'Microsoft.DotNet.Watcher.Tools' in /Users/user/dev/aspnet/Docs/aspnet/tutorials/dotnet-watch/sample/WebApp/project.json...
log : Installing Microsoft.DotNet.Watcher.Core ...
log : Installing Microsoft.DotNet.Watcher.Tools ...
```
- Run `dotnet restore`.
## Running `dotnet` commands using `dotnet watch`
Any `dotnet` command can be run with `dotnet watch`: For example:
<!-- Command Command with watch dotnet run dotnet watch run dotnet run -f net451 dotnet watch run -f net451 dotnet run -f net451 -- --arg1 dotnet watch run -f net451 -- --arg1 dotnet test dotnet watch test -->
Any `dotnet` command can be run with `dotnet watch`, for example:
| Command | Command with watch |
| ---- | ----- |
| dotnet run | dotnet watch run |
| dotnet run | dotnet watch run |
| dotnet run -f net451 | dotnet watch run -f net451 |
| dotnet run -f net451 -- --arg1 | dotnet watch run -f net451 -- --arg1 |
| dotnet test | dotnet watch test |
To run `WebApp` using the watcher, run `dotnet watch run` in the `WebApp` folder. The console output will show messages similar to the ones below, indicating that `dotnet watch` is now watching code files:
```bash
user$ dotnet watch run
[DotNetWatcher] info: Running dotnet with the following arguments: run
[DotNetWatcher] info: dotnet process id: 39746
Project WebApp (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Hosting environment: Production
Content root path: /Users/user/dev/aspnet/Docs/aspnet/tutorials/dotnet-watch/sample/WebApp
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
```
Run `dotnet watch run` in the `WebApp` folder. The console output will indicate `watch` has started.
## Making changes with `dotnet watch`
Make sure `dotnet watch` is running.
Let's fix the bug in *WebApp/Controllers/MathController.cs* that we discovered when we tried to compute the product of two number:
Fix the bug in the `Product` method of the `MathController` so it returns the product and not the sum.
[!code-csharp[Main](dotnet-watch/sample/WebApp/Controllers/MathController.cs?range=12-17&highlight=5)]
```csharp
public static int Product(int a, int b)
{
return a * b;
} ```
Fix the code by replacing `a + b` with `a * b`.
Save the file. The console output will show messages similar to the ones below, indicating that `dotnet watch` detected a file change and restarted the application.
```bash
[DotNetWatcher] info: File changed: /Users/user/dev/aspnet/Docs/aspnet/tutorials/dotnet-watch/sample/WebApp/Controllers/MathController.cs
[DotNetWatcher] info: Running dotnet with the following arguments: run
[DotNetWatcher] info: dotnet process id: 39940
Project WebApp (.NETCoreApp,Version=v1.0) will be compiled because inputs were modified
Compiling WebApp for .NETCoreApp,Version=v1.0
Compilation succeeded.
0 Warning(s)
0 Error(s)
Time elapsed 00:00:03.3312829
Hosting environment: Production
Content root path: /Users/user/dev/aspnet/Docs/aspnet/tutorials/dotnet-watch/sample/WebApp
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
```
Save the file. The console output will show messages indicating that `dotnet watch` detected a file change and restarted the app.
Verify `http://localhost:5000/api/math/product?a=4&b=5` returns the correct result.
## Running tests using `dotnet watch`
The file watcher can run other `dotnet` commands like `test` or `publish`.
- Change the `Product` method of the `MathController` back to returning the sum and save the file.
- In a command window, naviagate to the `WebAppTests` folder.
- Run `dotnet restore`
- Run `dotnet watch test`. You see output indicating that a test failed and that watcher is waiting for file changes:
1. Open the `WebAppTests` folder that already has `dotnet watch` in *project.json*.
```console
Total tests: 2. Passed: 1. Failed: 1. Skipped: 0.
Test Run Failed.
```
- Fix the `Product` method code so it returns the product. Save the file.
2. Run `dotnet watch test`.
If you previously fixed the bug in the `MathController` then you'll see an output similar to the one below, otherwise you'll see a test failure:
```bash
WebAppTests user$ dotnet watch test
[DotNetWatcher] info: Running dotnet with the following arguments: test
[DotNetWatcher] info: dotnet process id: 40193
Project WebApp (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Project WebAppTests (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
xUnit.net .NET CLI test runner (64-bit .NET Core osx.10.11-x64)
Discovering: WebAppTests
Discovered: WebAppTests
Starting: WebAppTests
Finished: WebAppTests
=== TEST EXECUTION SUMMARY ===
WebAppTests Total: 2, Errors: 0, Failed: 0, Skipped: 0, Time: 0.259s
SUMMARY: Total: 1 targets, Passed: 1, Failed: 0.
[DotNetWatcher] info: dotnet exit code: 0
[DotNetWatcher] info: Waiting for a file to change before restarting dotnet...
```
Once all the tests run, the watcher will indicate that it's waiting for a file to change before restarting `dotnet test`.
3. Open the controller file in *WebApp/Controllers/MathController.cs* and change some code. If you haven't fixed the product bug, do it now. Save the file.
`dotnet watch` detects the file change and reruns the tests. The console output will show messages similar to the one below:
```bash
[DotNetWatcher] info: File changed: /Users/user/dev/aspnet/Docs/aspnet/tutorials/dotnet-watch/sample/WebApp/Controllers/MathController.cs
[DotNetWatcher] info: Running dotnet with the following arguments: test
[DotNetWatcher] info: dotnet process id: 40233
Project WebApp (.NETCoreApp,Version=v1.0) will be compiled because inputs were modified
Compiling WebApp for .NETCoreApp,Version=v1.0
Compilation succeeded.
0 Warning(s)
0 Error(s)
Time elapsed 00:00:03.2127590
Project WebAppTests (.NETCoreApp,Version=v1.0) will be compiled because dependencies changed
Compiling WebAppTests for .NETCoreApp,Version=v1.0
Compilation succeeded.
0 Warning(s)
0 Error(s)
Time elapsed 00:00:02.1204052
xUnit.net .NET CLI test runner (64-bit .NET Core osx.10.11-x64)
Discovering: WebAppTests
Discovered: WebAppTests
Starting: WebAppTests
Finished: WebAppTests
=== TEST EXECUTION SUMMARY ===
WebAppTests Total: 2, Errors: 0, Failed: 0, Skipped: 0, Time: 0.260s
SUMMARY: Total: 1 targets, Passed: 1, Failed: 0.
[DotNetWatcher] info: dotnet exit code: 0
[DotNetWatcher] info: Waiting for a file to change before restarting dotnet...
```
`dotnet watch` detects the file change and reruns the tests. The console output will show the tests passed.

View File

@ -11,8 +11,9 @@ namespace WebApp.Controllers
public static int Product(int a, int b)
{
// We have an intentional bug here
// + should be *
// We have an intentional bug here.
// change to:
// return a * b;
return a + b;
}
}

View File

@ -1,10 +1,5 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Builder;
namespace WebApp
{

View File

@ -1,24 +1,11 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace WebApp
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
@ -26,11 +13,8 @@ namespace WebApp
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
public void Configure(IApplicationBuilder app)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMvc();
}
}

View File

@ -0,0 +1,16 @@
<Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0-msbuild3-final" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.0" />
</ItemGroup>
</Project>

View File

@ -1,48 +0,0 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
},
"tools": {
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-*"
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"runtimeOptions": {
"configProperties": {
"System.GC.Server": true
}
},
"publishOptions": {
"include": [
"web.config"
]
},
"scripts": {
"postpublish": [
"dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%"
]
}
}

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
-->
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
</system.webServer>
</configuration>

View File

@ -0,0 +1,22 @@
<Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\WebApp\WebApp.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0-*" />
<PackageReference Include="Microsoft.DotNet.InternalAbstractions " Version=" 1.0.0-*" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0-beta5-build1225" />
<PackageReference Include="xunit" Version="2.2.0-beta5-build3474" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0-msbuild3-final" />
</ItemGroup>
</Project>

View File

@ -1,25 +0,0 @@
{
"version": "1.0.0-*",
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"type": "platform"
},
"dotnet-test-xunit": "1.0.0-*",
"NETStandard.Library": "1.6.0",
"WebApp": "1.0.0-*",
"xunit": "2.1.0"
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dnxcore50",
"portable-net451+win8"
]
}
},
"tools": {
"Microsoft.DotNet.Watcher.Tools": "1.0.0-*"
},
"testRunner": "xunit"
}

View File

@ -1,6 +0,0 @@
{
"projects": [ "WebApp", "WebAppTests" ],
"sdk": {
"version": "1.0.0-preview2-1-003177"
}
}