【问题标题】:ASP.NET Core w/Angular Template - httpget Route is being caught by Angular - cannot match any routes带有 Angular 模板的 ASP.NET Core - httpget 路由被 Angular 捕获 - 无法匹配任何路由
【发布时间】:2020-09-06 12:36:10
【问题描述】:

我目前正在使用 Visual Studio 2019 提供的 Angular 模板开发 ASP.NET Core Web 应用程序 - 一切都运行良好,直到我尝试访问 ASP.NET Core api 路由,即使用默认路由的简单 HTTPGET通过构建数据库模型提供,我通过将 Azure SQL 数据库拉入 SQL 对象资源管理器来构建它。我还根据模型搭建了我的控制器,因此我当前使用的所有 api 路由都是默认的 CRUD 操作。

当我在 localhost:port/api/enrolees 访问我的应用程序时,我收到了这个角度错误:

未捕获(承诺中):错误:无法匹配任何路由。 URL 段:'api/enrolees'

我可以清楚地看到 Angular 正在抓取 api 路由并将其视为 Angular 路由。所以,我尝试在我的 web.config 中添加 url 重写规则,如下所示:

<rule name="AngularJS" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>

但是,这使得应用程序无法找到 css 文件,并且当我尝试访问路由时仍然会抛出错误。我应该提一下,应用程序中内置的默认控制器 WeatherForecast 可以正常工作。

如果我将我的 httpget 请求更改为只返回一个字符串,那么 url http://localhost:port/api/enrolees 会按预期返回该字符串。

当我调试代码并直接点击 api/controller 时,我收到一个 System.NotImplementedException,它指出:

函数或方法没有实现。

除此之外,我还设置了调用服务的函数,该服务调用 api 路由,所有这些都按预期命中但返回未定义。很明显,有些东西没有正确设置。我已经苦苦挣扎了几个小时,无法在这里或 Google 上找到合适的解决方案。

我的启动文件

using Hackathon.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace Hackathon
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            // In production, the Angular files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });

            services.AddDbContext<SQContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddCors(o =>
            {
                o.AddPolicy("AllowAllHeaders", builder =>
                {
                    builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
                });
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseRouting();

            app.UseCors("AllowAllHeaders");

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller}/{action=Index}/{id?}");
            });

            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

            });
        }
    }
}

我的控制器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Hackathon.Models;

namespace Hackathon.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class EnroleesController : ControllerBase
    {
        private readonly SQContext _context;

        public EnroleesController(SQContext context)
        {
            _context = context;
        }

        // GET: api/Enrolees
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Enrolee>>> GetEnrolee()
        {
            var list = await _context.Enrolee.ToListAsync();
            return list;
        }

        // GET: api/Enrolees/5
        [HttpGet("{id}")]
        public async Task<ActionResult<Enrolee>> GetEnrolee(int id)
        {
            var enrolee = await _context.Enrolee.FindAsync(id);

            if (enrolee == null)
            {
                return NotFound();
            }

            return enrolee;
        }

        // PUT: api/Enrolees/5
        // To protect from overposting attacks, enable the specific properties you want to bind to, for
        // more details, see https://go.microsoft.com/fwlink/?linkid=2123754.
        [HttpPut("{id}")]
        public async Task<IActionResult> PutEnrolee(int id, Enrolee enrolee)
        {
            if (id != enrolee.EnroleeId)
            {
                return BadRequest();
            }

            _context.Entry(enrolee).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!EnroleeExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return NoContent();
        }

        // POST: api/Enrolees
        // To protect from overposting attacks, enable the specific properties you want to bind to, for
        // more details, see https://go.microsoft.com/fwlink/?linkid=2123754.
        [HttpPost]
        public async Task<ActionResult<Enrolee>> PostEnrolee(Enrolee enrolee)
        {
            _context.Enrolee.Add(enrolee);
            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateException)
            {
                if (EnroleeExists(enrolee.EnroleeId))
                {
                    return Conflict();
                }
                else
                {
                    throw;
                }
            }

            return CreatedAtAction("GetEnrolee", new { id = enrolee.EnroleeId }, enrolee);
        }

        // DELETE: api/Enrolees/5
        [HttpDelete("{id}")]
        public async Task<ActionResult<Enrolee>> DeleteEnrolee(int id)
        {
            var enrolee = await _context.Enrolee.FindAsync(id);
            if (enrolee == null)
            {
                return NotFound();
            }

            _context.Enrolee.Remove(enrolee);
            await _context.SaveChangesAsync();

            return enrolee;
        }

        private bool EnroleeExists(int id)
        {
            return _context.Enrolee.Any(e => e.EnroleeId == id);
        }
    }
}

我的 app.module:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { HomeComponent } from './home/home.component';
import { CounterComponent } from './counter/counter.component';
import { FetchDataComponent } from './fetch-data/fetch-data.component';
import { TemplateComponent } from './template/template.component';
import { LoginComponent } from './login/login.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RegistrationComponent } from './registration/registration.component';
import { MaterialModule } from './material/material.module';
import { EnroleesService } from './services/enrolees.service';

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    CounterComponent,
    FetchDataComponent,
    TemplateComponent,
    LoginComponent,
    RegistrationComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    RouterModule.forRoot([
      { path: '', component: HomeComponent, pathMatch: 'full' },
      { path: 'counter', component: CounterComponent },
      { path: 'fetch-data', component: FetchDataComponent },
      { path: 'login', component: LoginComponent },
      { path: 'register', component: RegistrationComponent }
    ]),
    BrowserAnimationsModule,
    MaterialModule
  ],
  providers: [ EnroleesService ],
  bootstrap: [AppComponent]
})
export class AppModule { }

我认为不需要任何其他信息。我的 angular.json 是默认文件,除了我安装的 nuget 包之外,我的 package.json 也是如此。我通过 Visual Studio 将其发布到 IIS。我一定是错过了什么!

任何帮助将不胜感激!蒂亚!

【问题讨论】:

  • 你是如何运行应用程序的?
  • @ESG 我正在通过 Visual Studio 部署 - 发布到我的 C:\inetpub\wwwroot 目录中的文件夹,其中包含“无托管代码”的应用程序池。我在 IIS 中为它在 8011 端口上创建了一个网站。
  • 发布时输出到该文件夹​​的内容是什么?通常,aspnet 核心堆栈应该​​为 angular 文件提供服务,您不需要在 angular 中做任何事情来忽略 api 路由
  • 是的,这就是我以前以这种方式构建的应用程序所经历的。根文件夹包含 ASP.NET Core 文件以及 ClientApp Angular 目录,该目录包含 dist 文件夹和内部的 Angular 文件。我还将角度文件复制并粘贴到应用程序文件夹的 wwwroot 目录中(c:\inetpub\wwwroot\application\wwwroot)。
  • 那就是问题所在。在发布时,您的应用正在构建 clientapp/dist 文件夹,这就是您所需要的。如果你把 angular 文件放在 wwwroot 中,你就让 aspnet 使用静态文件中间件而不是 SPA 中间件

标签: angular asp.net-core


【解决方案1】:

我解决了我的问题。我在 appsettings 中的连接字符串中有语法错误!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-07
    • 2019-03-28
    • 1970-01-01
    相关资源
    最近更新 更多