Mostrando entradas con la etiqueta webapi. Mostrar todas las entradas
Mostrando entradas con la etiqueta webapi. Mostrar todas las entradas

Controlar Authorization en WebApi C#

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());





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);

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());
        }
    }
}


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());
}

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

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);

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