这与Cannot find module @angular/core完全分开,即使我仍然拥有该解决方案包,以防万一有人有想法。
因此,在同一解决方案中,我有一个Angular7站点和一个Web API项目。我将IIS Express设置为仅使用端口5000;节点将使用端口4200。在Web API项目中,我创建了一个新的“ AccountController”控制器,一个“ LoginAttempt”模型和一个“ LoginResult”模型。
在Angular端,我有login.component.html,login.component.ts,login.service.ts和serviceCall.service.ts文件。 login.component.ts由html文件更新,并将请求传递到login.service.ts文件,后者将内容打包并发送到serviceCall.service.ts文件,以发送到API。
尝试调用时发生的情况是我收到404错误,但是Visual Studio递增了关联到Login调用的“ requests”值。我似乎找不到任何原因来说明为什么我会收到404并仍然在通话尝试中增加请求。
源代码: C#Web API: Startup.cs
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.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
LoginAttempt.cs
[Serializable]
public class LoginAttempt
{
public string username { get; set; }
public string password { get; set; }
}
LoginResult.cs
[Serializable]
public class LoginResult
{
public string token { get; set; }
public string message { get; set; }
public bool success { get; set; }
}
AccountController.cs
[Route("api/[controller]")]
public class AccountController : Controller
{
Account accountRepo = new Account();
[HttpPost]
public LoginResult Login(LoginAttempt input)
{
return accountRepo.verifyCredentials(input.username, input.password);
}
public IActionResult Index()
{
return View();
}
}
角度7 proxy.conf.json
{
"exclude": [
"**/bin",
"**/bower_components",
"**/jspm_packages",
"**/node_modules",
"**/obj",
"**/platforms"
],
"/api": {
"target": "http://localhost:5000",
"secure": false
}
}
angular.json
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"smart-goal": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/smart-goal",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "smart-goal:build",
"proxyConfig": "proxy.conf.json"
},
"configurations": {
"production": {
"browserTarget": "smart-goal:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "smart-goal:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"src/styles.css"
],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"smart-goal-e2e": {
"root": "e2e/",
"projectType": "application",
"prefix": "",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "smart-goal:serve"
},
"configurations": {
"production": {
"devServerTarget": "smart-goal:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
"defaultProject": "smart-goal"
}
LoginCredentials.ts
export class LoginCredentials {
username: string | undefined;
password: string | undefined;
}
LoginResults.ts
export interface ILoginResult {
token: string,
message: string,
success: boolean
}
login.component.html
<p>Login Page</p>
<form>
<label>Username:</label>
<input type="text" [(ngModel)]="Username" name="Username"/>
<label>Password:</label>
<input type="password" [(ngModel)]="Password" name="Password"/>
<button type="submit" (click)="LoginAttempt()">Submit</button>
</form>
login.component.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { Input } from '@angular/core';
import { LoginCredentials } from '../models/loginCredentials';
import { LoginService } from './login.service';
@Component({
selector: 'login',
templateUrl: './login.component.html'
})
export class LoginComponent {
private router: Router;
private Username: string;
private Password: string;
private Login: LoginCredentials;
private response: undefined;
private service: LoginService;
constructor(router: Router, service: LoginService) {
this.router = router;
this.Login = new LoginCredentials();
this.service = service;
this.Username = "";
this.Password = "";
}
LoginAttempt() {
let data = new LoginCredentials();
data.username = this.Username;
data.password = this.Password;
this.service.Login(data)
.subscribe(
result => {
let response = JSON.stringify(result);
alert("SUCCESS - " + response);
}
);
}
}
login.service.ts
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { LoginCredentials } from '../models/LoginCredentials';
import { ServiceCall } from '../shared/serviceCall.service';
import { ILoginResult } from '../models/LoginResult';
import { map } from 'rxjs/operators';
@Injectable()
export class LoginService {
call: ServiceCall;
constructor(call: ServiceCall) {
this.call = call;
}
public Login(loginAttempt: LoginCredentials): Observable<any> {
let myResponse = new Map<string, string>()
let data = new Map<string, string>();
let data2 = new Map<string, string>();
let url = "Account/Login";
data.set('Username', loginAttempt.username);
data.set('Password', loginAttempt.password);
return this.call.makeCall(url, 'POST', data).pipe(map(response => data2 = response));
}
}
serviceCall.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders, HttpRequest, HttpResponse, } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class ServiceCall {
private _http: HttpClient;
private _urlAppend: string;
private _isAuthenticated: boolean;
constructor(http: HttpClient) {
this._http = http;
this._urlAppend = '/api/';
this._isAuthenticated = false;
}
public makeCall(url: string, type: string, data: Map<string, string>): Observable<any> {
url = this._urlAppend + url;
let headers = new HttpHeaders();
headers.append('Content-Type', 'application/json');
headers.append('charset', 'utf-8');
let params = new HttpParams();
let result = new Response();
data.forEach((value: string, key: string) => {
params.set(key, value);
});
let options = { headers: headers, params: params, withCredentials: this._isAuthenticated };
let body = JSON.stringify(data);
if (type == "GET") {
return this._http
.get(url, options)
.pipe(map((result: Response) => result));
} else if (type == "POST") {
return this._http
.post(url, body, options)
.pipe(map(this.extractData));
} else {
Observable.throw("Invalid command.");
}
}
public setAuthentication(input: boolean) {
this._isAuthenticated = input;
}
private extractData(res: Response) {
let body = res.json();
return body || {};
}
private generateQueryString(input: Map<string, string>) {
let response = new URLSearchParams();
input.forEach((value: string, key: string) => {
response.append(key, value);
});
return response;
}
}
最后,Chrome控制台中显示的404响应:
HttpErrorResponse
{
error: null
headers: HttpHeaders
{
lazyInit: f()
lazyUpdate: null
normalizeNames: Map(0) {}
}
message: "Http failure response for http://localhost:4200/api/Acocunt/Login: 404 Not Found"
name: "HttpErrorResponse"
ok: false
status: 404
statusText: "Not Found"
url: "http://localhost:4200/api/Account/Login"
}
答案 0 :(得分:0)
U。这个问题。首先,在C#方面:我已经习惯了使用“常规” .NET框架的较早版本的Web API,并且在使用.NET Core时进行了一些更改。在AccountController.cs
文件中,需要在类声明的正上方指定该控制器的“分支”,以便在类声明的正上方具有[Route("api/[controller]")]
之类的内容。然后,在类中的每个方法上,我必须定义特定方法的URL是什么。在上述情况下,
[HttpPost]
public LoginResult Login(LoginAttempt input)
需要看起来像:
[Route("login")]
[HttpPost]
public IActionResult Login([FromBody]LoginAttempt input)
然后在Typescript方面,Angular2站点忽略了代理信息,而不是尝试转发到我的API端口。我必须在proxy.conf.json文件中使代理信息如下所示:
"/api": {
"target": "http://localhost:5000",
"secure": false,
"changeorigin": true,
"logLevel": "debug",
"pathRewrite": {"^/api": ""}
}
我尝试了所有可以找到的版本,直到我添加了“ changeorigin”位,该版本才起作用。这使事情如我所愿。