visual tutorial studio net mvc asp and angularjs asp.net-core asp.net-core-mvc asp.net-core-webapi

angularjs - tutorial - asp.net core angular 5



Modelo/parámetro Angular JS MVC Web API no vinculante.NET Core (3)

El mejor enfoque aquí es seguir las pautas de HTTP y cambiar su acción de POST a GET ya que no está modificando ningún dato. Esto es bastante simple de hacer y aún así puede enviar datos con su solicitud utilizando el URI.

Cambios de MVC

Consulte Enlazado de modelo para las distintas opciones, el mejor enfoque aquí es vincular en función de la cadena de consulta, ya que solo desea un tipo primitivo. Si tuviera una matriz de tipos primitivos, aún podría enlazar a la cadena de consulta, el nombre de la variable de cadena de consulta se repetiría una vez para cada valor.

Entonces, los únicos cambios que hacemos son especificar que el parámetro proviene de la cadena Query y que está asociado con una solicitud de Get HTTP en lugar de Post.

[Route("api/[controller]")] public class DashboardController : BaseController { [HttpGet] // change to HttpGet [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromQuery]int companyId) // use FromQuery { return CreateJsonResult(() => { if (companyId == 0) { return new xPTJsonResult(null, xPTStatusCodesEnum.Success, "Company Id is 0"); } //var treeModel = _dashboardProvider.GetTreeModelByCompany(companyId, userModel); return new xPTJsonResult(null, xPTStatusCodesEnum.Success, "Loaded assets successfully"); }); } }

Cambios AngularJS

Extendemos el apiService para permitir el paso de datos para llamadas usando HttpGet. Esto se puede hacer utilizando los parámetros en la llamada $ http , creará dinámicamente la URL en función de los datos pasados ​​usando el nombre como el nombre de valor de la cadena de consulta y el valor como la parte de valor.

export class apiService { /* all other code is left as is, just change the get method to also accept data via the params. If null is passed in then it is ignored. */ get(url, config, data, success, failure) { return this.$http({ url: url, config: config, params: data, method: "GET" }) .then(result => { this.handleResponse(result, success); }, result => { this.handleError(result, failure) }); } }

En la llamada, solo tenemos que cambiar de una post a otra, y debería funcionar.

// only change from post to get onCompanyChanged(selectedCompany, model, companyName) { this.apiService.get(''/api/Dashboard/GetAssetListByCompany'', { companyId: selectedCompany.id }, response => { this.assetListViewModel = response.data.data; }, response => { this.notificationService.displayError(response.data.message); }); }

Editar - Esto es flexible

Una nota más importante, este diseño es flexible en el lado angular. Si extiende su MVC Action o tiene varias acciones que toman parámetros adicionales, funciona sin tener que implementar ningún otro cambio. Ejemplo:

[HttpGet] [Route("GetSomethingElseFromServer")] public IActionResult GetSomethingElseFromServer([FromQuery]int companyId, [FromQuery]string assetName, [FromQuery]string companyModelNumber) // use FromQuery

la llamada a su API angular sería

this.apiService.get(''/api/Dashboard/GetSomethingElseFromServer'', { companyId: companyId, assetName: somePassedInAssetNameVar, companyModelNumber: somePassedInModelNumber }

Editar - También puedes enviar matrices

Para responder la pregunta sobre cómo enviar múltiples tipos primitivos como una matriz, puede hacerlo de esta manera. De nuevo, esto supone que no es un tipo complejo que está enviando, pero, por ejemplo, una lista de identificadores de la empresa.

código c #

[HttpGet] [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromQuery]int[] companyIds) // use an array of int ie. int[]. i changed the variable name to make it clear there can be more than 1

Llamada angular, tenga en cuenta que no es necesario cambiar el servicio

onCompanyChanged(selectedCompany, model, companyName) { this.apiService.get(''/api/Dashboard/GetAssetListByCompany'', { "companyIds[]": [id1, id2, id3] }, // note the name is now enclosed in quotes, made plural, and includes []. The value is an array response => { this.assetListViewModel = response.data.data; }, response => { this.notificationService.displayError(response.data.message); }); }

Editar - Si desea enviar de todos modos

Está cursando únicamente el envío de un solo campo primitivo, por lo que el framework MVC no lo deserializará correctamente en un POST. Debe envolver el parámetro en un modelo de vista, enviarlo como una parte de cadena de consulta o enviarlo como un valor de campo de formulario. Aquí está el POST con una parte de cadena de consulta que funciona bien.

Opción 1

Añádalo a la URL

[HttpPost] // change to HttpGet [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromQuery] int companyId) // use FromQuery

Llamada angular

this.apiService.post(''/api/Dashboard/GetAssetListByCompany/?companyId='' + selectedCompany.id + , null, // the rest of the code remains unchanged so I did not include it

opcion 2

Extienda el apiService para que también tome el objeto params para que pueda generar su consulta. En cualquiera de los dos casos, la persona que llama tiene que saber un poco sobre la realización de la llamada http.

this.apiService.post(''/api/Dashboard/GetAssetListByCompany'', null, {companyId: selectedCompany.id}, null, // the rest of the code remains unchanged so I did not include it post(url, config, data, params, success, failure) { return this.$http({ url: url, config: config, data: data, params: params, method: "POST" }) .then(result => { this.handleResponse(result, success); }, result => { this.handleError(result, failure) }); }

Opción 3

Actualice su modelo de vista para tomar un tipo complejo, esto no requiere cambios en su código angular.

public class ListByCompanyModel { public int CompanyId {get;set;} } [HttpPost] // change to HttpGet [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromBody] ListByCompanyModel model) // use FromQuery

Estoy usando Angular JS con TypeScript y ASP.NET Core MVC / API.

Tengo un apiService que trata con todas las POST y GET al servidor, que se ve así:

module TBApp { export class apiService { static $inject = [''$http'', ''notificationService'']; constructor(private $http, private notificationService: notificationService) { } get(url, config, success, failure) { return this.$http.get(url, config) .then(result => { this.handleResponse(result, success); }, result => { this.handleError(result, failure) }); } post(url, data, success, failure) { return this.$http.post(url,data) .then(result => { this.handleResponse(result, success); }, result => { this.handleError(result, failure) }); } handleResponse(result, success) { alert(''success''); success(result); } handleError(result, failure) { if (result.status === ''401'') { this.notificationService.displayError(''Authentication required.''); //this.$rootScope.previousState = this.$location.path(); //this.$location.path(''/login''); } else if (failure !== null) { failure(result); } } } }

Ahora cuando envío esta solicitud:

onCompanyChanged(selectedCompany, model, companyName) { this.apiService.post(''/api/Dashboard/GetAssetListByCompany'', { companyId: selectedCompany.id }, response => { this.assetListViewModel = response.data.data; }, response => { this.notificationService.displayError(response.data.message); }); }

No es vinculante para la companyId en el controlador

Aquí está el controlador:

[Route("api/[controller]")] public class DashboardController : BaseController { [HttpPost] [Route("GetAssetListByCompany")] public IActionResult GetAssetListByCompany([FromBody]int companyId) { return CreateJsonResult(() => { if (companyId == 0) { return new xPTJsonResult(null, xPTStatusCodesEnum.Success, "Company Id is 0"); } //var treeModel = _dashboardProvider.GetTreeModelByCompany(companyId, userModel); return new xPTJsonResult(null, xPTStatusCodesEnum.Success, "Loaded assets successfully"); }); } }

a pesar de que cuando miro la Solicitud en el navegador, en muestra que la Id empresa está en la Carga útil.

NOTA: la misma función funciona cuando publico un ViewModel

EDITAR

En el escenario anterior, solo estoy pasando un parámetro al controlador, pero en algunos casos deseo poder pasar 2 o 3 parámetros sin usar un ViewModel.

p.ej

public IActionResult GetAssetListByCompany([FromBody]int companyId, [FromBody]int assetId) {....

O

public IActionResult GetAssetListByCompany([FromBody]int companyId, [FromBody]int assetId, [FromBody]bool canEdit = false) {.....

y luego en el lado del cliente puedo hacer esto:

this.apiService.post(''/api/Dashboard/GetAssetListByCompany'', { companyId: selectedCompany.id, assetId: 123 }.....

O

this.apiService.post(''/api/Dashboard/GetAssetListByCompany'', { companyId: selectedCompany.id, canEdit: true, assetId: 22 }....


Siempre es mejor hacer un GET en lugar de POST para obtener solicitudes. Si desea cambiarlo a un método GET, luego haga $ http.get y en el atributo api, haga que tenga el siguiente aspecto:

[HttpGet] //not required, this will be get as per naming convention [Route("GetAssetListByCompany/{companyId}")] public IActionResult GetAssetListByCompany(int companyId)

Pero si aún necesita hacer una POST, entonces sus datos en $ http.post deberían verse como datos: ''"123456"''

$http.post("/api/Dashboard/GetAssetListByCompany", ''"123456"'' )

La solución anterior es necesaria cuando pasa datos primitivos a la API y eso explica por qué funcionó bien cuando aprobó su modelo de vista.

ACTUALIZACIÓN : después de una discusión posterior, OP necesita enviar múltiples tipos primitivos a la API y necesita acceder a los datos usando una clave sin tener dependencia con el orden en el que se está vinculando el modelo.

Una opción es usar Diccionario como tipo de parámetro de entrada

[HttpPost] [Route("GetAssetListByCompany")] public IHttpActionResult GetAssetListByCompany(Dictionary<string,int> data) { return Ok(); }

y en el lado del cliente:

var data = {}; data["CustomerId1"] = 123; data["CustomerId2"] = 345; data["CustomerId3"] = 1623; data["CustomerId4"] = 7655; $http.post("/api/Dashboard/GetAssetListByCompany", data);

Resultado


{ companyId: selectedCompany.id } que es un objeto con un campo companyId que tiene el valor selectedCompany.id ;

Cambie a una solicitud GET como dicha respuesta o cree una clase contenedora que tenga un campo entero companyId y úselo como entrada para su función en el lado del servidor.

Otra cosa que puedes probar:

  • envíe solo el número entero en lugar de un objeto
  • envía el entero como una cadena, el negine puede analizarlo como un int.