Visual Studio 2017的csproj .NET Core构建 - 视图未被正确复制

7

我有一个在.NET Core上运行的项目,使用VS2017作为IDE。

当我通过Visual Studio 2017构建我的项目时,它不会自动将Views文件夹和wwwroot文件夹添加到[projectRoot]/bin/Debug/netcoreapp1.1/win10-x64BuildDir)的输出中。这意味着如果我尝试直接从在bin文件夹中创建的.exe文件运行我的网站,我会因为缺少viewswwwroot而出现错误。如果我手动将这些文件夹复制到BuildDir,则可以正确加载视图。

我可以在我的.csproj文件中设置如下:

<Content Update="Views\**">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

现在Views正常工作,但是我的布局文件没有被编译,所以我得到了以下结果:

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - FirstAgenda</title>

    <environment names="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css"/>
        <link rel="stylesheet" href="~/css/overwrite.css" asp-append-version="true" />
    </environment>
    <environment names="Staging,Production">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
        <link rel="stylesheet" href="~/css/overwrite.css" asp-append-version="true" />
    </environment>
</head>

这意味着我的根文件夹没有被正确地定位。这也告诉我,仅仅将文件复制到输出目录是不正确的。
如果我发布应用程序(也没有添加到.csproj文件中),上述所有内容都可以正常工作。我只需要一个项目运行器,可以指向我的网站可执行文件的Debug版本,因为与使用VS2017构建项目相比,很容易忘记发布。
我不知道该怎么做,任何帮助都将不胜感激?
编辑:添加了csproj的简化版本(不起作用)。
<Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <PreserveCompilationContext>true</PreserveCompilationContext>
    <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.1" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.1" />
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.1" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.1" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.1" />
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
    <PackageReference Include="Microsoft.AspNetCore.Routing" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="1.0.1" />
    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.1.0-preview4-final" />
    <PackageReference Include="IdentityServer4" Version="1.3.1" />
    <PackageReference Include="IdentityServer4.AspNetIdentity" Version="1.0.0" />
    <PackageReference Include="IdentityServer4.EntityFramework" Version="1.0.0" />
    <PackageReference Include="OctoPack" Version="3.5.2" />
    <PackageReference Include="Serilog.Extensions.Logging.File" Version="1.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.ViewCompilation" Version="1.1.0" />
  </ItemGroup>
  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet">
      <Version>1.1.0-preview4-final</Version>
    </DotNetCliToolReference>
    <DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools">
      <Version>1.0.0-msbuild1-final</Version>
    </DotNetCliToolReference>
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools">
      <Version>1.0.0-msbuild1-final</Version>
    </DotNetCliToolReference>
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\[OWNPROJECT]" />
    <ProjectReference Include="..\[OWNPROJECT1]" />
  </ItemGroup>
</Project>

我尝试使用dotnet new mvc创建了一个新项目,但它也无法工作。

我的dotnet core cli版本是[1.0.1]。

编辑:

我按照您概述的步骤进行操作。我还尝试使用dotnet new mvc创建了一个新项目,并按照您的步骤进行操作。两者都给我带来了相同的错误。它无法找到appsettings.json。如果我向.csproj添加一个propertygroup,那么就告诉msbuild将appsettings.json和web.config复制到输出中。

<ItemGroup>
  <Content Update="appsettings.json;web.config">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </Content>
</ItemGroup>

我可以通过exe启动程序,但当我访问索引时,尝试访问其中一个视图时会出现以下错误:

Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[0]
    An unhandled exception has occurred while executing the request
    System.InvalidOperationException: The view 'Index' was not found. The following locations were searched:
  /Views/Home/Index.cshtml
  /Views/Shared/Index.cshtml

更新:

Shaun Lutins的答案对我有效。无论是构建还是发布选项都可以使用。唯一的问题是我遇到了一个错误:

重复包含“Content”项。.NET SDK默认会从您的项目目录中包含“Content”项。

但是,通过更改以下内容解决了这个问题:

<ItemGroup>                                                                            
   <Content Include="appsettings.json" CopyToOutputDirectory="Always" />
   <Content Include="Views\**\*" CopyToOutputDirectory="Always" />
   <Content Include="wwwroot\**\*" CopyToOutputDirectory="Always" />
</ItemGroup>      

to

<ItemGroup>                                                                            
   <Content Update="appsettings.json;web.config" CopyToOutputDirectory="PreserveNewest"/>
   <Content Update="Views\**\*" CopyToOutputDirectory="PreserveNewest" />
   <Content Update="wwwroot\**\*" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>      

我已经更新了我的答案,让我们能够从任何位置运行输出的EXE文件。请告诉我它是否对您有效。 - Shaun Luttin
在你的更新中出现错误,是因为你没有使用Shaun的示例中包含的<EnableDefaultContentItems>false</EnableDefaultContentItems>。 - Professor of programming
2个回答

7
我理解的挑战是要运行dotnet build并能够在任何地方执行编译后的EXE。答案需要两个步骤:
1. 将所需内容复制到bin文件夹中。 2. 相对于bin文件夹设置ContentRoot和WebRoot。
首先,修改csproj文件以将所需内容复制到bin文件夹中。默认情况下,dotnet build不会将Views、appsettings.json或wwwroot文件夹复制到bin文件夹中。因此,我们需要显式地指定CopyToOutputDirectory;为了实现这一点,我们还需要将EnableDefaultContentItems设置为false,否则我们的显式设置会重复默认内容项设置。
其次,修改Program.cs文件以指定新的ContentRoot和WebRoot。默认情况下,Program.cs使用UseContentRoot(Directory.GetCurrentDirectory())进行设置。对于我们的情况存在问题,当前目录是从中运行可执行文件的目录。因此,如果我们在桌面上从命令行运行EXE,则当前目录将是C:/Users/MyUser/Desktop。应用程序无法找到Views、appsettings.json和其他内容。
以下是我用来满足自己理解的挑战的工作步骤。
工作步骤:
1. cd C:\temp 2. dotnet new mvc 3. 使用“Working csproj” XML更新temp.csproj文件。 4. 使用“Working Program.cs”代码更新Program.cs文件。 5. dotnet restore 6. dotnet build 7. cd .. 8. 从任何地方运行C:\temp\bin\Debug\netcoreapp1.0\win10-x64\temp.exe 以下是工作中使用的csproj。
<Project Sdk="Microsoft.NET.Sdk.Web">                                                    

  <PropertyGroup>                                                                        
    <TargetFramework>netcoreapp1.0</TargetFramework>                                     
    <RuntimeIdentifier>win10-x64</RuntimeIdentifier>                                     
    <OutputType>exe</OutputType>                                                         
    <EnableDefaultContentItems>false</EnableDefaultContentItems>
  </PropertyGroup>                                                                       

  <ItemGroup>                                                                            
     <Content Include="appsettings.json" CopyToOutputDirectory="Always" />
     <Content Include="Views\**\*" CopyToOutputDirectory="Always" />
     <Content Include="wwwroot\**\*" CopyToOutputDirectory="Always" />
  </ItemGroup>                                                                           

  <ItemGroup>                                                                            

     <!-- Package references omitted for clarity -->

  </ItemGroup>                                                                           

</Project>  

Program.cs 的工作原理

public class Program
{
    public static void Main(string[] args)
    {
        // C:\temp\bin\Debug\netcoreapp1.0\win10-x64\temp.dll            
        var assemblyFilePath = 
            System.Reflection.Assembly.GetEntryAssembly().Location;

        // C:\temp\bin\Debug\netcoreapp1.0\win10-x64\
        var binDirectory = 
            System.IO.Path.GetDirectoryName(assemblyFilePath);

        Console.WriteLine(assemblyFilePath);
        Console.WriteLine(binDirectory);

        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(binDirectory) // <--
            .UseWebRoot("wwwroot") // <--
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        host.Run();
    }
}

我已经定义了那个,但它不起作用。我还尝试创建一个新项目,但也不起作用(当我添加你定义的propertygroup时)。你能在编辑中看到我的.csproj文件吗? - Kristian Barrett
1
PreserveCompilationContext is already set by way of Microsoft.NET.Sdk.Web - ChadT
谢谢@ChadT。经过进一步的研究,我相信我已经找到了答案。你有什么想法? - Shaun Luttin
1
我不是MSBuild的专家,但那看起来没问题。实际上,我不同意OP认为这里存在问题。 BuildingPublishing是两个离散的步骤 - 这是按设计进行的。您不希望在每次需要编译C#时都复制所有静态资源。 - ChadT
1
@ChadT 说得好。在某些方面,楼主正在问如何射击自己的脚。 - Shaun Luttin
显示剩余3条评论

0
我已经在 GitHub 的 ASP.NET Core 存储库中发布了这个问题: https://github.com/aspnet/Home/issues/2897 尽管已经接受的答案有效,但感觉有点像黑客攻击。
它也存在问题。当有大量文件需要复制时,构建过程会很慢,并且构建过程不会删除已删除的文件。
已接受的答案还误用了 EnableDefaultContentItems 设置。
因此,虽然我很高兴问题有了临时解决方案,但需要寻找长期解决方案。
希望我在 GitHub 上提出的问题能够在某种程度上解决更持久的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接