J'ai mis à niveau MVC / AngularJS 1.x vers DotNet Core 2.2 / Angular 6.x. avec @ angular / common / http
La plupart du temps, cela a été un jeu d'enfant, mais l'API Web me tue. Je me suis mis au travail en quelques minutes, mais j'ai passé une semaine à tout essayer sous le soleil pour que le Web Post fonctionne.
Ce que j'ai fait ici est vraiment simple à reproduire. p>
Allez dans Visual Studio 17 et cliquez sur Fichier / Nouveau projet
Choisissez Installé / Visual C # /. NET Core
Sélectionnez le modèle: Application Web ASP.NET core
Sur l'écran secondaire, définissez les listes déroulantes en haut sur .NET Core et ASP.NET Core 2.2
Sélectionnez le modèle angulaire du bouclier rouge "A"
Laissez le projet extraire les dépendances et reconstruire.
TOUT est l'application de démonstration prête à l'emploi de Microsoft, à l'exception de:
Ajoutez les boutons à l'écran.
Ajoutez du code aux .ts pour appeler le contrôleur d'API
Ajoutez le paramètre d'entrée à la méthode get dans le contrôleur
Ajouter une méthode de publication très simple au contrôleur
J'essaye également d'obtenir DotNet Core 2.0 / Angular 4.x. avec @ angular / http travailler avec exactement les mêmes résultats. L'obtention était très facile, mais j'ai essayé toutes les configurations sous le soleil pour que le poste fonctionne. Je ferai également un article comme celui-ci pour l'autre version. Pour le moment, j'essaie juste de faire fonctionner tout ce que je peux et de laisser AngularJS 1.x derrière.
using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; namespace NG_22.Controllers { [Route("api/[controller]")] public class SampleDataController : Controller { private static string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; [HttpGet("[action]")] public IEnumerable<WeatherForecast> WeatherForecasts(int startDateIndex = 0) { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { DateFormatted = DateTime.Now.AddDays(index + startDateIndex).ToString("d"), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }); } [HttpPost("[action]")] public WeatherForecast PostWeatherForecast([FromBody] WeatherForecast weatherForecast) { var forecast = weatherForecast; //return weatherForecast; return new WeatherForecast() { DateFormatted = DateTime.Now.ToString("d"), TemperatureC = 30, Summary = Summaries[2] }; } public class WeatherForecast { public string DateFormatted { get; set; } public int TemperatureC { get; set; } public string Summary { get; set; } public int TemperatureF { get { return 32 + (int)(TemperatureC / 0.5556); } } } } }
<h1>Weather forecast</h1> <p>This component demonstrates fetching data from the server.</p> <p *ngIf="!forecasts"><em>Loading...</em></p> <table class='table table-striped' *ngIf="forecasts"> <thead> <tr> <th>Date</th> <th>Temp. (C)</th> <th>Temp. (F)</th> <th>Summary</th> </tr> </thead> <tbody> <tr *ngFor="let forecast of forecasts"> <td>{{ forecast.dateFormatted }}</td> <td>{{ forecast.temperatureC }}</td> <td>{{ forecast.temperatureF }}</td> <td>{{ forecast.summary }}</td> </tr> </tbody> </table> <button class='btn btn-default pull-left' (click)="OnClick('Prior')">Previous</button> <button class='btn btn-default pull-left' (click)="OnClick('Next')">Next</button> <button class='btn btn-default pull-right' (click)="OnClick('Post')">Post</button>
import { Component, Inject } from '@angular/core'; import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http'; @Component({ selector: 'app-fetch-data', templateUrl: './fetch-data.component.html' }) export class FetchDataComponent { public Http: HttpClient; public BaseURL: string; public HttpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; public startDateIndex = 0; public forecasts: WeatherForecast[] = []; public forecast: WeatherForecast = { dateFormatted: "3/27/2020", temperatureC: 0, temperatureF: 32, summary: "Cold Post" }; constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) { this.Http = http; this.BaseURL = baseUrl; http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts') .subscribe(result => { this.forecasts = result; }, error => console.error(error)); } public OnClick(pControl: string) { //console.log("LogOn.OnClick * pControl=" + pControl); switch (pControl) { case "Prior": this.startDateIndex -= 5; this.Http.get<WeatherForecast[]>(this.BaseURL + 'api/SampleData/WeatherForecasts/', { params: new HttpParams().set('startDateIndex', this.startDateIndex.toString()) }) .subscribe(result => { this.forecasts = result; }, error => console.error(error)); break; case "Next": this.startDateIndex += 5; this.Http.get<WeatherForecast[]>(this.BaseURL + 'api/SampleData/WeatherForecasts/', { params: new HttpParams().set('startDateIndex', this.startDateIndex.toString()) }) .subscribe(result => { this.forecasts = result; }, error => console.error(error)); break; case "Post": console.log("Post * this.forecast=" + JSON.stringify(this.forecast) + "this.HttpOptions=" + JSON.stringify(this.HttpOptions)); this.Http.post<WeatherForecast>(this.BaseURL + '/api/SampleData/PostWeatherForecast/', this.forecast, this.HttpOptions); } } } interface WeatherForecast { dateFormatted: string; temperatureC: number; temperatureF: number; summary: string; }
4 Réponses :
Résolu !!!!!
Le problème était qu'il n'y avait rien d'abonné. Si personne n'écoute, cela ne prend pas la peine d'appeler le Post. J'ai ajouté un .subscribe et cela a bien fonctionné.
import { Component, Inject } from '@angular/core'; import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http'; @Component({ selector: 'app-fetch-data', templateUrl: './fetch-data.component.html' }) export class FetchDataComponent { public Http: HttpClient; public BaseURL: string; public HttpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; public startDateIndex = 0; public forecasts: WeatherForecast[] = []; public forecast: WeatherForecast = { dateFormatted: "3/27/2020", temperatureC: 0, temperatureF: 32, summary: "Cold Post" }; constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) { this.Http = http; this.BaseURL = baseUrl; http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts') .subscribe(result => { this.forecasts = result; }, error => console.error(error)); } public OnClick(pControl: string) { //console.log("LogOn.OnClick * pControl=" + pControl); switch (pControl) { case "Prior": this.startDateIndex -= 5; this.Http.get<WeatherForecast[]>(this.BaseURL + 'api/SampleData/WeatherForecasts/', { params: new HttpParams().set('startDateIndex', this.startDateIndex.toString()) }) .subscribe(result => { this.forecasts = result; }, error => console.error(error)); break; case "Next": this.startDateIndex += 5; this.Http.get<WeatherForecast[]>(this.BaseURL + 'api/SampleData/WeatherForecasts/', { params: new HttpParams().set('startDateIndex', this.startDateIndex.toString()) }) .subscribe(result => { this.forecasts = result; }, error => console.error(error)); break; case "Post": console.log("Post * this.forecast=" + JSON.stringify(this.forecast) + "this.HttpOptions=" + JSON.stringify(this.HttpOptions)); this.Http.post<WeatherForecast>(this.BaseURL + '/api/SampleData/PostWeatherForecast/', this.forecast, this.HttpOptions) .subscribe(result => { console.log("Posted" + JSON.stringify(result)); }, error => console.error(error)); } } } interface WeatherForecast { dateFormatted: string; temperatureC: number; temperatureF: number; summary: string; }
Réponse améliorée. L'interface n'est pas nécessaire et d'autres améliorations plus petites et suppression du code inutile.
using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; namespace NG_22.Controllers { [Route("api/[controller]/[action]")] public class SampleDataController : Controller { private static string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; [HttpGet] public IEnumerable<WeatherForecast> WeatherForecasts(int startDateIndex = 0) { var rng = new Random(); return Enumerable.Range(1, 5).Select(index => new WeatherForecast { DateFormatted = DateTime.Now.AddDays(index + startDateIndex).ToString("d"), TemperatureC = rng.Next(-20, 55), Summary = Summaries[rng.Next(Summaries.Length)] }); } [HttpPost] public object PostWeatherForecast([FromBody] WeatherForecast weatherForecast) { var forecast = weatherForecast; //return weatherForecast; return new { DateFormatted = DateTime.Now.ToString("d"), TemperatureC = 30, Summary = Summaries[2] }; } public class WeatherForecast { public string DateFormatted { get; set; } public int TemperatureC { get; set; } public string Summary { get; set; } public int TemperatureF { get { return 32 + (int)(TemperatureC / 0.5556); } } public object Data { get; set; } } } }
<h1>Weather forecast</h1> <p>This component demonstrates fetching data from the server.</p> <p *ngIf="!forecasts"><em>Loading...</em></p> <table class='table table-striped' *ngIf="forecasts"> <thead> <tr> <th>Date</th> <th>Temp. (C)</th> <th>Temp. (F)</th> <th>Summary</th> </tr> </thead> <tbody> <tr *ngFor="let forecast of forecasts"> <td>{{ forecast.dateFormatted }}</td> <td>{{ forecast.temperatureC }}</td> <td>{{ forecast.temperatureF }}</td> <td>{{ forecast.summary }}</td> </tr> </tbody> </table> <button class='btn btn-default pull-left' (click)="OnClick('Prior')">Previous</button> <button class='btn btn-default pull-left' (click)="OnClick('Next')">Next</button> <button class='btn btn-default pull-right' (click)="OnClick('Post')">Post</button>
import { Component, Inject } from '@angular/core'; import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http'; @Component({ selector: 'app-fetch-data', templateUrl: './fetch-data.component.html' }) export class FetchDataComponent { public Http: HttpClient; public BaseURL: string; public HttpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; public startDateIndex = 0; public forecasts: any; public forecast = { dateFormatted: "3/27/2020", temperatureC: 0, temperatureF: 32, summary: "Cold Post", Data: { color: "red", Size: "Large" } }; constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) { this.Http = http; this.BaseURL = baseUrl; http.get(baseUrl + 'api/SampleData/WeatherForecasts') .subscribe(result => { this.forecasts = result; }, error => console.error(error)); } public OnClick(pControl: string) { //console.log("LogOn.OnClick * pControl=" + pControl); switch (pControl) { case "Prior": this.startDateIndex -= 5; this.Http.get(this.BaseURL + 'api/SampleData/WeatherForecasts/', { params: new HttpParams().set('startDateIndex', this.startDateIndex.toString()) }) .subscribe(result => { this.forecasts = result; }, error => console.error(error)); break; case "Next": this.startDateIndex += 5; this.Http.get(this.BaseURL + 'api/SampleData/WeatherForecasts/', { params: new HttpParams().set('startDateIndex', this.startDateIndex.toString()) }) .subscribe(result => { this.forecasts = result; }, error => console.error(error)); break; case "Post": console.log("Post * this.forecast=" + JSON.stringify(this.forecast) + "this.HttpOptions=" + JSON.stringify(this.HttpOptions)); this.Http.post(this.BaseURL + '/api/SampleData/PostWeatherForecast/', this.forecast, this.HttpOptions) .subscribe(result => { alert("Posted" + JSON.stringify(result)); }, error => console.error(error)); } } }
using DMChess_Data.Model; using Microsoft.EntityFrameworkCore; using System; using System.Linq; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; namespace DMChess_Data { public class Entities { private dmchessContext DMCConnection = new dmchessContext(); private Guid AppId = new Guid("B6C093C8-AE8C-40CD-9E0D-3BD2118422EC"); public bool SaveChanges() { try { DMCConnection.SaveChangesAsync(); } catch(Exception pException) //catch (Microsoft.EntityFrameworkCore.) //catch (System.Data.Entity.Validation.DbEntityValidationException ex) { var ex = pException; //foreach (var eve in ex.EntityValidationErrors) //{ // var type = eve.Entry.Entity.GetType().Name; // var state = eve.Entry.State; // foreach (var ve in eve.ValidationErrors) // { // var propertyName = ve.PropertyName; // var ErrorMessage = ve.ErrorMessage; // } //} //var m = ex; throw; } DMCConnection.SaveChanges(); return true; } #region AUsers public AUsers AUsersGet(Guid pId, string pPassword) { return DMCConnection.AUsers.FirstOrDefault(x => x.KAppId == AppId && x.KId == pId && x.Password == pPassword); } public AUsers AUsersGet(string pEmailAddress, string pPassword) { return DMCConnection.AUsers.FirstOrDefault(x => x.KAppId == AppId && x.EmailAddress == pEmailAddress); } #endregion #region DProfiles public DProfiles DProfileGet(Guid pKUserId, int pKIdx) { return DMCConnection.DProfiles.FirstOrDefault(x => x.KAppId == AppId && x.KUserId == pKUserId && x.KIdx == pKIdx); } public List<DProfiles> DProfilesGet(string pUserIdName) { return DMCConnection.DProfiles.Where(x => x.KAppId == AppId && x.UserIdToLower == pUserIdName.ToLower()).ToList(); } #endregion } }
using D2Chess.Server.IO; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; namespace D2Chess.Controllers { [Route("api/[controller]/[action]")] public class WebController : Controller { #region Init private JsonSerializer jsonSerializer = new JsonSerializer(); private Repository repository = new Repository(); public WebController(IHubContext<D2Chess.Server.IO.Hub> hubContext) { D2Chess.Server.IO.Hub.StaticContext = hubContext; } #endregion #region Classes public class Parms { public Guid? TokenId { get; set; } public string Action { get; set; } public object Data { get; set; } } public class Result { public bool Success { get; set; } public object Data { get; set; } public Result(bool pSuccess, object pData = null) { this.Success = pSuccess; this.Data = pData; } } #endregion #region Sync Methods [HttpGet] public object Get(string pAction, string pKey = "", Guid? pTokenId = null) { return repository.WebGet(pAction, pKey, pTokenId); //var result = repository.WebGet(pAction, pKey, pTokenId); //return result; } [HttpPost] public object Post([FromBody] object pParms) { var parms = ((JObject)pParms).ToObject<Parms>(); return repository.WebPost(parms.Action, parms.Data, parms.TokenId); //var result = repository.WebPost(parms.Action, parms.Data, parms.TokenId); //return result; } #endregion } }
Avez-vous essayé Stringify les données que vous transmettez au contrôleur? Vous utilisez stringify dans le journal mais pas dans l'appel
Je n'ai pas été dans ce genre de choses depuis un moment, mais je me souviens de problèmes lorsque votre URL a été générée en tant que / WeatherForecast? StartDateIndex = "2" au lieu de / WeatherForecast / 2 ou vice versa. Je verrai si je peux déterrer quelque chose.
Donc je crois que c'est vos attributs [Http *]. Lisez docs.microsoft. com / en-us / aspnet / core / mvc / controllers /… . Essayez de changer [Route ("api / [controller]")] en [Route ("api / [controller] / [action]")] et [HttpGet ("[action]")] en [HttpGet]. Je suis presque sûr que ce sera une combinaison de cela.
*** Avez-vous essayé Stringify les données que vous transmettez au contrôleur? Vous utilisez stringify dans le journal mais pas dans l'appel *** J'ai essayé cela, cela n'a pas fonctionné, même si j'ai changé l'en-tête en texte au lieu de JSON
*** Je n'ai pas été dans ce genre de choses depuis un moment, mais je me souviens de problèmes lorsque votre URL a été générée en tant que / WeatherForecast? StartDateIndex = "2" au lieu de / WeatherForecast / 2 ou vice versa. **** Le Get, qui utilise le startindex, fonctionne correctement. Le seul problème est avec la poste
**** Donc je crois que c'est vos attributs [Http *]. Lisez docs.microsoft.com/en-us/aspnet/core/mvc/controllers/…. Essayez de changer [Route ("api / [controller]")] en [Route ("api / [controller] / [action]")] et [HttpGet ("[action]")] en [HttpGet]. Je suis presque sûr que ce sera une combinaison de cela. *** Merci! Je vais essayer. À un moment donné, en jouant avec le code, je l'ai fait frapper la méthode Controller post, mais les paramètres sont apparus comme nuls
*** Je n'ai pas été dans ce genre de choses depuis un moment, mais je me souviens de problèmes lorsque votre URL a été générée en tant que / WeatherForecast? StartDateIndex = "2" au lieu de / WeatherForecast / 2 ou vice versa. **** J'ai changé [Route ("api / [controller]")] en [Route ("api / [controller] / [action]")] et changé [HttpGet ("[action]")] en [HttpGet ] et remplacé [HttpPost ("[action]")] par [HttpPost] Le résultat était identique. Le Get fonctionne bien mais le message ne touche pas. Cela a cependant rationalisé le code.