Agregar con NuGet el package: Microsoft.AspNet.WebApi.Cors
En un WebApi:
using System.Web.Http.Cors;
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html"));
config.Filters.Add(new FiltroAuth());
Mostrando entradas con la etiqueta webapi. Mostrar todas las entradas
Mostrando entradas con la etiqueta webapi. Mostrar todas las entradas
Angular en IE - Habilitar custom headers y cors en WebApi (SEC7123)
Proyecto de ejemplo que tiene este cambio: Creditos
A partir de Angular 8 no es necesario modificar el archivo polyfills.
1. Agregar en WebApiConfig.cs
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
<system.webServer>
<httpProtocol>
<customHeaders>
<!-- <add name="Access-Control-Allow-Origin" value="*" /> -->
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
</system.webServer>
A partir de Angular 8 no es necesario modificar el archivo polyfills.
1. Agregar en WebApiConfig.cs
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
2. Agregar en web.config (dentro de
<system.webServer>
<httpProtocol>
<customHeaders>
<!-- <add name="Access-Control-Allow-Origin" value="*" /> -->
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
</system.webServer>
Subir archivos con Angular y WebApi
app.component.html
<form [formGroup]="form" (ngSubmit)="onSubmit()" class="form-horizontal form-control-sm">
<div class="form-row">
<label for="nombre" class="col-sm-1 control-label form-control-sm text-right">Nombre</label>
<div class="col-sm-1">
<input class="form-control form-control-sm" formControlName="nombre">
</div>
</div>
<div class="form-row mb-2">
<label for="foto" class="col-sm-1 control-label form-control-sm text-right">Foto</label>
<div class="col-sm-3">
<img src="./assets/noimage.png" id="previewFoto" name="previewFoto" style="width: 150px; height: 150px;cursor: pointer" onClick="document.getElementById('foto').click();"
/>
</div>
<input class="form-control form-control-sm" id="foto" type="file" accept=".xlsx" (change)="upload($event)"
#fileInput style="display: none">
</div>
<input type="submit" value="Guardar" [disabled]="!form.valid" class="btn btn-primary col-sm-1">
</form>
app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from "@angular/forms";
import { DatosService } from './_servicios/datos.service';
import { Datos } from './_modelos/datos';
import { CustomResponse } from './_modelos/custom-response';
import { ResponseMessageCode } from './_servicios/enumerados';
//import { Archivo } from './_modelos/archivo';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
datos = new Datos();
form: FormGroup;
constructor(private fb: FormBuilder, private data : DatosService) {
this.createForm();
}
createForm() {
this.form = this.fb.group({
nombre: [''],
foto: ['']
});
}
upload(event) {
this.onFileChange(event);
}
onFileChange(event) {
if (event.target.files.length > 0) {
let archivoSeleccionado = event.target.files[0];
let reader = new FileReader();
reader.readAsDataURL(archivoSeleccionado);
let _this = this;
reader.onloadend = function () {
_this.form.patchValue({
foto: (<string>reader.result).split('base64,')[1]
});
}
}
}
onSubmit() {
this.datos.nombre = this.form.get('nombre').value;
if (this.datos.contenido != 'undefined') {
this.datos.contenido = this.form.get('foto').value;
}
this.data.guardar(this.datos).subscribe(
(response: CustomResponse<any>) => {
if (response.messageCode == ResponseMessageCode.OK) {
console.log("todo ok");
} else {
console.log("mal");
}
}
);
}
ngOnInit() {
}
}
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{ path: 'home', component: AppComponent }
]
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule,
RouterModule.forRoot(routes)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
datos.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DatosService {
constructor(public http: HttpClient) { }
public guardar(datos): Observable<any> {
return this.http.post<any>("http://localhost/servicios/api/creditos/subirarchivo", datos);
}
}
custom-response.ts
export class CustomResponse<T> {
messageCode: number;
message: string;
data: T;
}
datos.ts
export class Datos {
nombre: string;
contenido: string;
}
WebApi C#
[AllowAnonymous]
[OverrideAuthentication]
[HttpPost]
public IHttpActionResult SubirArchivo(Arch datos)
{
var path = System.Web.HttpContext.Current.Server.MapPath("~") + @"\xls\archivo.xlsx";
if (File.Exists(path))
File.Delete(path);
File.WriteAllBytes(path, datos.Contenido);
var mensaje = new { error = false, mensaje = "" };
return this.Ok(mensaje);
}
public class Arch
{
[JsonProperty("nombre")]
public string Nombre { get; set; }
[JsonProperty("contenido")]
public byte[] Contenido { get; set; }
}
Authorization en WebApi con ActionFilterAttribute
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace Servicios
{
public class FiltroAuthorization : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// pre-processing
Debug.WriteLine("ACTION 1 DEBUG pre-processing logging");
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
var type = objectContent.ObjectType; //type of the returned object
var value = objectContent.Value; //holding the returned value
}
Debug.WriteLine("ACTION 1 DEBUG OnActionExecuted Response " + actionExecutedContext.Response.StatusCode.ToString());
}
}
}
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace Servicios
{
public class FiltroAuthorization : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// pre-processing
Debug.WriteLine("ACTION 1 DEBUG pre-processing logging");
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
var type = objectContent.ObjectType; //type of the returned object
var value = objectContent.Value; //holding the returned value
}
Debug.WriteLine("ACTION 1 DEBUG OnActionExecuted Response " + actionExecutedContext.Response.StatusCode.ToString());
}
}
}
En WebApiConfig.cs
config.Filters.Add(new FiltroAuthorization());
WebApi - Angular - ejemplo completo con CORS, Authorization, rutas con nombre y JSON [** 100% FUNCIONANDO **]
Instalar con NuGet console:
Install-Package Microsoft.AspNet.WebApi.Cors
WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
//configuracion para que retorne JSON en lugar de XML
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
//habilita CORS para cualquier request
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors();
//permite indicar nombres especificos en las rutas REST, en lugar de los estandares (get, post, put, etc)
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.MessageHandlers.Add(new TokenValidationHandler());
//indica que el filtro debe aplicarse a todos los elementos del WebApi (intercepta todos los requests)
config.Filters.Add(new AuthorizeAttribute());
}
Install-Package Microsoft.AspNet.WebApi.Cors
WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
//configuracion para que retorne JSON en lugar de XML
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
//habilita CORS para cualquier request
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors();
//permite indicar nombres especificos en las rutas REST, en lugar de los estandares (get, post, put, etc)
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.MessageHandlers.Add(new TokenValidationHandler());
//indica que el filtro debe aplicarse a todos los elementos del WebApi (intercepta todos los requests)
config.Filters.Add(new AuthorizeAttribute());
}
LoginController.cs
public class LoginController : ApiController
{
//ej de uso: localhost/servicios/api/login/authenticate
[HttpPost]
[AllowAnonymous] //esto permite evitar que se aplique el filtro, dado que todavia no tenemos el token
public IHttpActionResult Authenticate([FromBody] LoginRequest login)
{
var loginResponse = new LoginResponse { };
LoginRequest loginrequest = new LoginRequest { };
loginrequest.Username = login.Username.ToLower();
loginrequest.Password = login.Password;
IHttpActionResult response;
HttpResponseMessage responseMsg = new HttpResponseMessage();
bool isUsernamePasswordValid = false;
if (login != null)
isUsernamePasswordValid = loginrequest.Password == "admin" ? true : false;
// if credentials are valid
if (isUsernamePasswordValid)
{
string token = createToken(loginrequest.Username);
//return the token
return Ok<string>(token);
}
else
{
// if credentials are not valid send unauthorized status code in response
loginResponse.responseMsg.StatusCode = HttpStatusCode.Unauthorized;
response = ResponseMessage(loginResponse.responseMsg);
return response;
}
}
private string createToken(string username)
{
//Set issued at date
DateTime issuedAt = DateTime.UtcNow;
//set the time when it expires
DateTime expires = DateTime.UtcNow.AddDays(7);
//http://stackoverflow.com/questions/18223868/how-to-encrypt-jwt-security-token
var tokenHandler = new JwtSecurityTokenHandler();
//create a identity and add claims to the user which we want to log in
ClaimsIdentity claimsIdentity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username)
});
const string sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
var now = DateTime.UtcNow;
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature);
//create the jwt
var token =
(JwtSecurityToken)
tokenHandler.CreateJwtSecurityToken(issuer: "http://localhost:50191", audience: "http://localhost:50191",
subject: claimsIdentity, notBefore: issuedAt, expires: expires, signingCredentials: signingCredentials);
var tokenString = tokenHandler.WriteToken(token);
return tokenString;
}
}
ClientesController.cs
public class ClientesController : ApiController
{
[HttpGet]
public IHttpActionResult Lista()
{
var l = new ParametrosLogica();
var pp = l.Listar(5);
return this.Ok(pp);
}
[HttpGet]
public IHttpActionResult Buscar(int id)
{
var l = new ClientesLogica();
var pp = l.Buscar(id);
return this.Ok(pp);
}
}
Routing by action name WebApi
Si se quieren utilizar nombres especificos de rutas, en lugar de los estandares REST (get, post, put, delete), cambiar en WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
y comentar el config.Routes existente.
Fuente: https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
y comentar el config.Routes existente.
Fuente: https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
Habilitar CORS en WebApi C# en forma global
En los packages NuGet del sitio WebApi, agregar el package CORS (Microsoft.AspNet.WebApi.Cors)
Luego, en App_Start / WebApiConfig.cs, agregar lo siguiente:
using System.Web.Http.Cors;
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
Luego, en App_Start / WebApiConfig.cs, agregar lo siguiente:
using System.Web.Http.Cors;
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
Retornar JSON en lugar de XML en un servicio WebApi
en App_Start / WebApiConfig.cs agregar en la primera linea:
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html") );
Fuente: https://stackoverflow.com/questions/9847564/how-do-i-get-asp-net-web-api-to-return-json-instead-of-xml-using-chrome
Suscribirse a:
Entradas (Atom)