Sei sulla pagina 1di 146

asp.

net-core

#asp.net-
core
Tabla de contenido
Acerca de 1

Capítulo 1: Empezando con asp.net-core 2

Observaciones 2

Versiones 2

Examples 2

Instalación y configuración 2

Instalando Visual Studio 2

Creando una aplicación ASP.NET Core MVC. 3

Crear un nuevo proyecto desde la línea de comando. 5

API web principal de ASP.NET mínima con ASP.NET Core MVC 5

Controladores 6

Conclusión 7

Usando el código de Visual Studio para desarrollar la aplicación principal de plataforma d 7

Configuración de la variable de entorno en ASP.NET Core [Windows] 11

Capítulo 2: Almacenamiento en caché 16

Introducción 16

Examples 16

Usando el caché de InMemory en la aplicación Core de ASP.NET 16

Caché distribuido 17

Capítulo 3: Angular2 y .Net Core 18

Examples 18

Tutorial rápido para un Angular 2 Hello World! Aplicación con .Net Core en Visual Studio 2 18

Errores esperados al generar componentes de Angular 2 en el proyecto .NET Core (versión 0. 43

Capítulo 4: ASP.NET Core: registre tanto la solicitud como la respuesta utilizando Middlew 45

Introducción 45

Observaciones 45

Examples 45

Logger Middleware 45

Capítulo 5: Autorización 48

Examples 48
Autorización simple 48

Capítulo 6: Ayudantes de etiquetas 50

Parámetros 50

Examples 50

Ayudante de etiqueta de formulario - Ejemplo básico 50

Ayudante de etiqueta de formulario - Con atributos de ruta personalizados 50

Ayudante de etiqueta de entrada 50

Seleccione Tag Helper 51

Ayudante de etiqueta personalizada 53

Asistente de ejemplo de etiqueta personalizada 54

Etiqueta de etiqueta de ayuda 55

Ayudante de la etiqueta del ancla 55

Capítulo 7: Configuración 57

Introducción 57

Sintaxis 57

Examples 57

Acceso a la configuración mediante la inyección de dependencias 57

Empezando 57

Trabajar con variables de entorno 58

Opción modelo y configuración 59

En la fuente de configuración de memoria 59

Capítulo 8: Configurando entornos múltiples 60

Examples 60

Tener apariciones por entorno 60

Obtener / verificar el nombre del entorno desde el código 60

Configurando múltiples entornos 61

Representar contenido específico del entorno a la vista 63

Establecer la variable de entorno desde la línea de comando 63

Establecer variable de entorno desde PowerShell 63

Usando ASPNETCORE_ENVIRONMENT desde web.config 63

Capítulo 9: Empaquetado y Minificación 65

Examples 65
Gruñido y gulp 65

Extensión Bundler y Minifier 66

Construyendo tus paquetes 66

Reducir sus paquetes 67

Automatiza tus paquetes 67

El comando dotnet bundle 68

Usando BundlerMinifier.Core 68

Configurando tus paquetes 68

Creación / actualización de paquetes 69

Bundling automatizado 69

Comandos disponibles 69

Capítulo 10: Enrutamiento 71

Examples 71

Enrutamiento básico 71

Restricciones de enrutamiento 71

Usándolo en los controladores 71

Usándolo en Acciones 72

Usándolo en rutas predeterminadas 72

Capítulo 11: Envío de correo electrónico en aplicaciones .Net Core utilizando MailKit 73

Introducción 73

Examples 73

Instalación del paquete nuget 73

Implementación simple para el envío de correos electrónicos. 73

Capítulo 12: Explotación florestal 75

Examples 75

Usando NLog Logger 75

Añadir Logger al controlador 75

Usando Serilog en la aplicación ASP.NET core 1.0 75

Capítulo 13: Inyección de dependencia 77

Introducción 77

Sintaxis 77
Observaciones 77

Examples 78

Registrarse y resolver manualmente 78

Registrar dependencias 78

Control de por vida 79

Dependencias enumerables 79

Dependencias genéricas 79

Recuperar dependencias en un controlador 80

Inyectar una dependencia en una acción del controlador 80

El patrón de opciones / opciones de inyección en servicios 81

Observaciones 82

Uso de servicios de ámbito durante el inicio de la aplicación / Secuencias de base de dato 82

Resolver controladores, ViewComponents y TagHelpers mediante inyección de dependencia 83

Ejemplo de inyección de dependencia simple (sin Startup.cs) 84

Funcionamiento interno de Microsoft.Extensions.DependencyInjection 85

IServiceCollection 85

IServiceProvider 85

Resultado 86

Capítulo 14: Inyectando servicios en vistas. 87

Sintaxis 87

Examples 87

La directiva @inject 87

Ejemplo de uso 87

Configuración requerida 87

Capítulo 15: Límite de velocidad 88

Observaciones 88

Examples 88

Limitación de tarifas basada en la IP del cliente 88

Preparar 88

Definir reglas de límite de velocidad. 91

Comportamiento 92
Actualizar los límites de la tasa en tiempo de ejecución 92

Limitación de tarifas basada en la identificación del cliente 93

Preparar 93

Definir reglas de límite de velocidad. 96

Comportamiento 97

Actualizar los límites de la tasa en tiempo de ejecución 98

Capítulo 16: Localización 100

Examples 100

Localización utilizando recursos de lenguaje JSON 100

Establecer cultura de solicitud a través de la ruta url 108

Registro de middleware 109

Restricciones de ruta personalizadas 110

Registro de la ruta 110

Capítulo 17: Manejo de errores 111

Examples 111

Redirigir a página de error personalizada 111

Manejo global de excepciones en ASP.NET Core 111

Capítulo 18: Middleware 113

Observaciones 113

Examples 113

Uso del middleware ExceptionHandler para enviar un error JSON personalizado al cliente 113

Middleware para establecer la respuesta ContentType 114

Pasar datos a través de la cadena de middleware. 114

Ejecutar, Mapa, Uso 115

Capítulo 19: Modelos 118

Examples 118

Validación del modelo con atributos de validación 118

Validación del modelo con atributo personalizado 118

Capítulo 20: proyecto.json 120

Introducción 120

Examples 120

Ejemplo de proyecto de biblioteca simple 120


Archivo json completo: 120

Proyecto de inicio simple 123

Capítulo 21: Publicación y despliegue 124

Examples 124

Cernícalo. Configurando la dirección de escucha 124

Capítulo 22: Sesiones en ASP.NET Core 1.0 126

Introducción 126

Examples 126

Ejemplo básico de manejo de sesión. 126

Capítulo 23: Solicitudes de Origen Cruzado (CORS) 128

Observaciones 128

Examples 128

Habilitar CORS para todas las solicitudes 128

Habilitar la política CORS para controladores específicos 128

Políticas de CORS más sofisticadas 129

Habilitar la política CORS para todos los controladores 129

Capítulo 24: Trabajando con JavascriptServices 131

Introducción 131

Examples 131

Habilitar webpack-dev-middleware para el proyecto asp.net-core 131

Prerrequisitos 131

NuGet 131

npm 131

Configurando 131

Añadir reemplazo de módulo caliente (HMR) 132

Prerrequisitos 132

Configuración 132

Generando una aplicación de muestra de una sola página con el núcleo de asp.net 132

Capítulo 25: Ver componentes 134

Examples 134

Crear un componente de vista 134


Iniciar sesión Ver componente 134

Regreso de la acción del controlador 135

Creditos 137
Acerca de
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: asp-net-core

It is an unofficial and free asp.net-core ebook created for educational purposes. All the content is
extracted from Stack Overflow Documentation, which is written by many hardworking individuals at
Stack Overflow. It is neither affiliated with Stack Overflow nor official asp.net-core.

The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.

Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to info@zzzprojects.com

https://riptutorial.com/es/home 1
Capítulo 1: Empezando con asp.net-core
Observaciones
.NET Core es una plataforma de desarrollo de propósito general mantenida por Microsoft y la
comunidad .NET en GitHub. Es multiplataforma, es compatible con Windows, macOS y Linux, y
puede usarse en dispositivos, en la nube y en escenarios integrados / IoT.

Las siguientes características definen mejor .NET Core:

• Implementación flexible: se puede incluir en su aplicación o puede instalarse de lado a lado


en toda la máquina.
• Multiplataforma: se ejecuta en Windows, macOS y Linux; Puede ser portado a otros
sistemas operativos. Los sistemas operativos (OS), las CPU y los escenarios de
aplicaciones compatibles crecerán con el tiempo, proporcionados por Microsoft, otras
compañías y personas.
• Herramientas de línea de comandos: todos los escenarios de productos se pueden ejercer
en la línea de comandos.
• Compatible: .NET Core es compatible con .NET Framework, Xamarin y Mono, a través de la
biblioteca estándar de .NET.
• Código abierto: la plataforma .NET Core es de código abierto, con licencias MIT y Apache 2.
La documentación está licenciada bajo CC-BY. .NET Core es un proyecto de la Fundación
.NET.
• Compatible con Microsoft: .NET Core es compatible con Microsoft, por .NET Core Support

Versiones

Versión Notas de lanzamiento Fecha de lanzamiento

RC1 * 1.0.0-rc1 2015-11-18

RC2 * 1.0.0-rc2 2016-05-16

1.0.0 1.0.0 2016-06-27

1.0.1 1.0.1 2016-09-13

1.1 1.1 2016-11-16

Examples
Instalación y configuración

Instalando Visual Studio

https://riptutorial.com/es/home 2
Si no tiene instalado Visual Studio, puede descargar la Edición de comunidad de Visual Studio
gratis aquí . Si ya lo tiene instalado, puede continuar con el siguiente paso.

Creando una aplicación ASP.NET Core MVC.


1. Abra Visual Studio.
2. Seleccione Archivo> Nuevo proyecto.
3. Seleccione Web en el idioma de su elección dentro de la sección Plantillas a la izquierda.
4. Elija un tipo de proyecto preferido dentro del diálogo.
5. Opcional: elija un .NET Framework al que le gustaría apuntar
6. Nombre su proyecto e indique si desea crear una solución para el proyecto.
7. Haga clic en Aceptar para crear el proyecto.

Se le presentará otro cuadro de diálogo para seleccionar la plantilla que desea utilizar para el
proyecto:

https://riptutorial.com/es/home 3
Cada una de las descripciones se explica por sí misma. Para este primer proyecto, seleccione
Aplicación Web , que contendrá todas las configuraciones predeterminadas, la autenticación y
algunos contenidos existentes.

Dado que se trata de una aplicación de introducción y no requiere seguridad ni autenticación,


puede cambiar la opción de autenticación a Sin autenticación en el lado derecho del cuadro
de diálogo y hacer clic en Aceptar para crear el proyecto .

Entonces debería ver el nuevo proyecto dentro del Explorador de soluciones:

Presione la tecla F5 para ejecutar la aplicación y comenzar una sesión de depuración, que
iniciará la aplicación dentro de su navegador predeterminado:

https://riptutorial.com/es/home 4
Ahora puede ver que su proyecto está funcionando y funcionando localmente y está listo como un
punto de partida para que construya su aplicación.

Crear un nuevo proyecto desde la línea de comando.

Es posible crear un nuevo proyecto ASP.NET Core completamente desde la línea de comandos
usando el comando dotnet .

dotnet new web


dotnet restore
dotnet run

dotnet new web andamios un nuevo proyecto web "vacío". El parámetro web le dice a la herramienta
dotnet que use la plantilla ASP.NET Core Empty . Use dotnet new -all para mostrar todas las
plantillas disponibles actualmente instaladas. Otras plantillas clave incluyen console , classlib , mvc
y xunit .

Una vez que la plantilla se ha distribuido, puede restaurar los paquetes necesarios para ejecutar
el proyecto ( dotnet restore ), y compilarlo e iniciarlo ( dotnet run ).

Una vez que el proyecto esté en ejecución, estará disponible en el puerto predeterminado: http: //
localhost: 5000

API web principal de ASP.NET mínima con ASP.NET Core MVC

https://riptutorial.com/es/home 5
Con ASP.NET Core 1.0, el marco MVC y la API web se fusionaron en un marco denominado
ASP.NET Core MVC. Esto es bueno, ya que MVC y la API web comparten muchas
funcionalidades, pero siempre hubo diferencias sutiles y duplicación de código.

Sin embargo, la combinación de estos dos en el marco uno también hizo más difícil distinguir uno
de otro. Por ejemplo, Microsoft.AspNet.WebApi representa el marco de trabajo de la API web 5.xx,
no el nuevo. Pero, cuando incluye Microsoft.AspNetCore.Mvc (versión 1.0.0 ), obtiene el paquete
completo. Esto contendrá todas las características listas para usar que ofrece el marco MVC.
Tales como Razor, tag helpers y modelos de enlace.

Cuando solo desea crear una API web, no necesitamos todas estas características. Entonces,
¿cómo construimos una API web minimalista? La respuesta es: Microsoft.AspNetCore.Mvc.Core . En
el nuevo mundo, MVC se divide en varios paquetes y este paquete contiene solo los
componentes centrales del marco MVC, como el enrutamiento y la autorización.

Para este ejemplo, vamos a crear una API de MVC mínima. Incluyendo un formateador JSON y
CORS. Cree una aplicación web ASP.NET Core 1.0 vacía y agregue estos paquetes a su
project.json:

"Microsoft.AspNetCore.Mvc.Core": "1.0.0",
"Microsoft.AspNetCore.Mvc.Cors": "1.0.0",
"Microsoft.AspNetCore.Mvc.Formatters.Json": "1.0.0"

Ahora podemos registrar MVC usando AddMvcCore() en la clase de inicio:

public void ConfigureServices(IServiceCollection services)


{
services.AddMvcCore()
.AddCors()
.AddJsonFormatters();
}

AddMvcCore devuelve una instancia de IMvcCoreBuilder que permite la construcción posterior. La


configuración del middleware es la misma que la habitual:

public void Configure(IApplicationBuilder app)


{
app.UseCors(policy =>
{
policy.AllowAnyOrigin();
});
app.UseMvc();
}

Controladores
La API web 'antigua' viene con su propia clase base de controlador: ApiController . En el nuevo
mundo no existe tal cosa, solo la clase predeterminada del Controller . Desafortunadamente, esta
es una clase base bastante grande y está vinculada al modelado de enlaces, vistas y JSON.NET.

https://riptutorial.com/es/home 6
Afortunadamente, en el nuevo marco, las clases del controlador no tienen que derivar del
Controller para ser recogidas por el mecanismo de enrutamiento. Basta con añadir el nombre con
el Controller . Esto nos permite construir nuestra propia clase base de controlador. Llamémoslo
ApiController , solo por los viejos tiempos:

/// <summary>
/// Base class for an API controller.
/// </summary>
[Controller]
public abstract class ApiController
{
[ActionContext]
public ActionContext ActionContext { get; set; }

public HttpContext HttpContext => ActionContext?.HttpContext;

public HttpRequest Request => ActionContext?.HttpContext?.Request;

public HttpResponse Response => ActionContext?.HttpContext?.Response;

public IServiceProvider Resolver => ActionContext?.HttpContext?.RequestServices;


}

El atributo [Controller] indica que el mecanismo de descubrimiento predeterminado del


controlador considera el tipo o cualquier tipo derivado. El atributo [ActionContext] especifica que la
propiedad debe establecerse con el ActionContext actual cuando MVC crea el controlador. El
ActionContext proporciona información sobre la solicitud actual.

ASP.NET Core MVC también ofrece una clase ControllerBase que proporciona una
clase base de controlador simplemente sin compatibilidad con vistas. Aún así es
mucho más grande que el nuestro. Úsalo si lo encuentras conveniente.

Conclusión
Ahora podemos crear una API web mínima utilizando el nuevo marco ASP.NET Core MVC. La
estructura modular del paquete nos permite simplemente jalar los paquetes que necesitamos y
crear una aplicación simple y eficiente.

Usando el código de Visual Studio para desarrollar la aplicación principal de


plataforma de plataforma aspnet

Con AspNetCore puede desarrollar la aplicación en cualquier plataforma, incluyendo Mac, Linux,
Window y Docker.

Instalación y configuración

1. Instale Visual Studio Code desde aquí


2. Añadir C # extesnion
3. Instalar dot net core sdk. Puedes instalar desde aquí

Ahora tienes todas las herramientas disponibles. Para desarrollar la aplicación. Ahora necesitas

https://riptutorial.com/es/home 7
alguna opción de andamios. Para eso debes considerar usar Yeoman. Para instalar Yeoman

1. Instale NPM. Para esto necesitas Node en tu máquina. Instalar desde aqui

2. Instala Yeoman usando NPM

npm install -g yo

3. Ahora instale el generador de aspnet

npm instalar -g generador-aspnet

Ahora tenemos toda la configuración en su máquina. Primero creamos un nuevo proyecto con el
comando básico DotNetCore y luego creamos un nuevo proyecto usando Yo.

Nuevo proyecto usando línea de comando

1. Crear una nueva carpeta de proyectos

mkdir CoreApplication cd CoreApplication

2. Scaffold un proyecto dotnet muy básico usando la opción de línea de comando


predeterminada

dotnet Nuevo

1. Restaura los paquetes y ejecuta la aplicación.

dotNet restaurar dotnet ejecutar

https://riptutorial.com/es/home 8
Utilice Yeoman como opción de andamios

Crear carpeta de proyectos y ejecutar el comando yo

yo aspnet

Yeoman le pedirá algunas entradas como Tipo de proyecto, Nombre del proyecto, etc.

https://riptutorial.com/es/home 9
Ahora restaure los paquetes ejecutando el comando de restauración de dotnet y ejecute la
aplicación

Usa VS Code para desarrollar la aplicación

Ejecutar el código de estudio visual como

https://riptutorial.com/es/home 10
Ahora abre los archivos y ejecuta la aplicación. También puede buscar la extensión para su
ayuda.

Configuración de la variable de entorno en ASP.NET Core [Windows]

=> Mensaje original <=

ASP.NET Core utiliza la variable de entorno ASPNETCORE_ENVIRONMENT para determinar el entorno

https://riptutorial.com/es/home 11
actual. De forma predeterminada, si ejecuta su aplicación sin establecer este valor, se establecerá
automáticamente el valor predeterminado para el entorno de Production .

> dotnet run


Project TestApp (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.

Hosting environment: Production


Content root path: C:\Projects\TestApp
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.

Configurando la variable de entorno en Windows

En la linea de comando

Puede configurar fácilmente una variable de entorno desde un símbolo del sistema utilizando el
comando setx.exe incluido en Windows. Puedes usarlo para establecer fácilmente una variable de
usuario:

>setx ASPNETCORE_ENVIRONMENT "Development"

SUCCESS: Specified value was saved.

Tenga en cuenta que la variable de entorno no está configurada en la ventana abierta actual.
Deberá abrir un nuevo símbolo del sistema para ver el entorno actualizado. También es posible
establecer variables del sistema (en lugar de solo variables de usuario) si abre un símbolo del
sistema administrativo y agrega el modificador / M:

>setx ASPNETCORE_ENVIRONMENT "Development" /M

SUCCESS: Specified value was saved.

Usando PowerShell Alternativamente, puede usar PowerShell para establecer la variable. En


PowerShell, así como en las variables normales del usuario y del sistema, también puede crear
una variable temporal usando el comando $Env: :

$Env:ASPNETCORE_ENVIRONMENT = "Development"

La variable creada dura solo durante la duración de su sesión de PowerShell: una vez que cierra
la ventana, el entorno vuelve a su valor predeterminado.

Alternativamente, puede configurar las variables de entorno del usuario o del sistema
directamente. Este método no cambia las variables de entorno en la sesión actual, por lo que
tendrá que abrir una nueva ventana de PowerShell para ver sus cambios. Como antes, cambiar
las variables del sistema (Máquina) requerirá acceso administrativo

[Environment]::SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development", "User")


[Environment]::SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development", "Machine")

Uso del panel de control de Windows Si no es un fanático de la línea de comandos, puede

https://riptutorial.com/es/home 12
actualizar fácilmente sus variables con el mouse. Haga clic en el botón del menú de inicio de
Windows (o presione la tecla de Windows), busque environment variables y elija Editar entorno

variables para su cuenta:

Al seleccionar esta opción, se abrirá el cuadro de diálogo Propiedades del sistema.

https://riptutorial.com/es/home 13
Haga clic en Variables de entorno para ver la lista de variables de entorno actuales en su sistema.

https://riptutorial.com/es/home 14
Suponiendo que no tiene una variable llamada ASPNETCORE_ENVIRONMENT , haga clic en el botón
Nuevo ... y agregue una nueva variable de entorno de cuenta:

Haga
clic en Aceptar para guardar todos los cambios. Deberá volver a abrir las ventanas de comandos
para asegurarse de que se carguen las nuevas variables de entorno.

Lea Empezando con asp.net-core en línea: https://riptutorial.com/es/asp-net-


core/topic/810/empezando-con-asp-net-core

https://riptutorial.com/es/home 15
Capítulo 2: Almacenamiento en caché
Introducción
El almacenamiento en caché ayuda a mejorar el rendimiento de una aplicación al mantener una
copia de los datos de fácil acceso. Aspnet Core viene con dos abstracciones fáciles de usar y de
prueba de almacenamiento en caché.

La memoria caché almacenará los datos en la memoria caché del servidor local.

La memoria caché distribuida mantendrá la memoria caché de datos en una ubicación


centralizada a la que pueden acceder los servidores en clúster. Viene con tres implementaciones
listas para usar: In Memory (para pruebas de unidad y desarrollo local), Redis y Sql Server.

Examples
Usando el caché de InMemory en la aplicación Core de ASP.NET

Para usar un caché en memoria en su aplicación ASP.NET, agregue las siguientes dependencias
a su archivo project.json :

"Microsoft.Extensions.Caching.Memory": "1.0.0-rc2-final",

agregue el servicio de caché (de Microsoft.Extensions.Caching.Memory) al método


ConfigureServices en la clase de inicio

services.AddMemoryCache();

Para agregar elementos al caché en nuestra aplicación, usaremos IMemoryCache que se puede
inyectar a cualquier clase (por ejemplo, el Controlador) como se muestra a continuación.

private IMemoryCache _memoryCache;


public HomeController(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}

Get devolverá el valor si existe, pero de lo contrario devuelve null .

// try to get the cached item; null if not found


// greeting = _memoryCache.Get(cacheKey) as string;

// alternately, TryGet returns true if the cache entry was found


if(!_memoryCache.TryGetValue(cacheKey, out greeting))

Utilice el método Set para escribir en el caché. Set acepta la clave que se utilizará para buscar el
valor, el valor que se almacenará en caché y un conjunto de MemoryCacheEntryOptions .

https://riptutorial.com/es/home 16
MemoryCacheEntryOptions permite especificar la caducidad de caché basada en el tiempo absoluta o
deslizante, la prioridad de caché, las devoluciones de llamada y las dependencias. Una de las
siguientes muestras.

_memoryCache.Set(cacheKey, greeting,
new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(1)));

Caché distribuido

Para aprovechar el caché distribuido, deberá hacer referencia a una de las implementaciones
disponibles:

• Redis
• Servidor SQL

Por ejemplo, registrará la implementación de Redis de la siguiente manera:

public void ConfigureServices(IServiceCollection services)


{
services.AddDistributedRedisCache(options =>
{
options.Configuration = "ServerAdress";
options.InstanceName = "InstanceName";
});
}

Requiera la dependencia de IDistributedCache donde la necesite:

public class BooksController {


private IDistributedCache distributedCache;

public BooksController(IDistributedCache distributedCache) {


this.distributedCache = distributedCache;
}

[HttpGet]
public async Task<Books[]> GetAllBooks() {
var serialized = this.distributedCache.GetStringAsync($"allbooks");
Books[] books = null;
if (string.IsNullOrEmpty(serialized)) {
books = await Books.FetchAllAsync();
this.distributedCache.SetStringAsync($"allbooks",
JsonConvert.SerializeObject(books));
} else {
books = JsonConvert.DeserializeObject<Books[]>(serialized);
}
return books;
}
}

Lea Almacenamiento en caché en línea: https://riptutorial.com/es/asp-net-


core/topic/8090/almacenamiento-en-cache

https://riptutorial.com/es/home 17
Capítulo 3: Angular2 y .Net Core
Examples
Tutorial rápido para un Angular 2 Hello World! Aplicación con .Net Core en
Visual Studio 2015

Pasos:

1. Crear una aplicación web .Net Core vacía:

https://riptutorial.com/es/home 18
2. Vaya a wwwroot y cree una página html normal llamada Index.html:

https://riptutorial.com/es/home 19
3. Configure Startup.cs para aceptar archivos estáticos (esto requerirá agregar la biblioteca
"Microsoft.AspNetCore.StaticFiles": "1.0.0" en el archivo “project.json”):

https://riptutorial.com/es/home 20
4. Añadir archivo NPN:

• Haga clic derecho en el proyecto WebUi y agregue el archivo de configuración NPN


(package.json):

https://riptutorial.com/es/home 21
• Verifique las últimas versiones de los paquetes:

https://riptutorial.com/es/home 22
Nota: si Visual Studio no detecta las versiones de los paquetes (verifique todos los
paquetes, ya que algunos de ellos muestran la versión y otros no), puede ser que la
versión de Node que viene en Visual Studio no funciona correctamente. , por lo que
probablemente se requiera instalar el nodo js externamente y luego vincular esa
instalación con Visual Studio.

yo. Descargue e instale el nodo js: https://nodejs.org/es/download/

ii. Enlace la instalación con Visual Studio: https://ryanhayes.net/synchronize-node-js-


install-version-with-visual-studio-2015/ :

https://riptutorial.com/es/home 23
iii. (Opcional) después de guardar package.json, se instalarán las dependencias en el
proyecto; de lo contrario, ejecute "npm install" utilizando un símbolo del sistema desde
la misma ubicación que el archivo package.json.

https://riptutorial.com/es/home 24
Nota: se recomienda instalar "Abrir línea de comandos", una extensión que se puede
agregar a Visual Studio:

5. Añadir mecanografiado:

• Cree una carpeta TsScript dentro del proyecto WebUi, solo para la organización (los
TypeScripts no irán al navegador, serán transpilados a un archivo JS normal, y este
archivo JS será el que vaya al codificador wwwroot usando gulp, este se explicará más
adelante):

https://riptutorial.com/es/home 25
• Dentro de esa carpeta, agregue "Archivo de configuración JSON de TypeScript"
(tsconfig.json):

https://riptutorial.com/es/home 26
Y añada el siguiente código:

https://riptutorial.com/es/home 27
• En la raíz del Proyecto WebUi, agregue un nuevo archivo llamado typings.json:

https://riptutorial.com/es/home 28
Y añada el siguiente código:

https://riptutorial.com/es/home 29
• En la raíz del Proyecto Web, abra una línea de comando y ejecute "typings install",
esto creará una carpeta de tipos (Esto requiere "Abrir línea de comando" explicado
como un paso opcional en la Nota dentro del Paso 4, numeral iii).

https://riptutorial.com/es/home 30
https://riptutorial.com/es/home 31
https://riptutorial.com/es/home 32
6. Añadir gulp para mover archivos:

• Agregue "Gulp Configuration File" (gulpfile.js) en la raíz del proyecto web:

https://riptutorial.com/es/home 33
• Añadir código:

https://riptutorial.com/es/home 34
7. Agregue los archivos de arranque Angular 2 dentro de la carpeta "tsScripts":

https://riptutorial.com/es/home 35
app.component.ts

https://riptutorial.com/es/home 36
app.module.ts

main.ts

8. Dentro de wwwroot, crea la siguiente estructura de archivos:

9. Dentro de la carpeta de scripts (pero fuera de la aplicación), agregue systemjs.config.js:

https://riptutorial.com/es/home 37
Y añada el siguiente código:

https://riptutorial.com/es/home 38
10. Ejecute Gulp Task para generar los scripts en wwwroot.

• Haga clic derecho en gulpfile.js


• Explorador de tareas Runner

https://riptutorial.com/es/home 39
yo. Si las tareas no están cargadas ("Fallo al cargar. Consulte la ventana de
resultados") Vaya a la ventana de resultados y observe los errores, la mayoría de las
veces son errores de sintaxis en el archivo de errores.
• Haga clic con el botón derecho en la tarea "predeterminada" y "Ejecutar" (tomará un
tiempo, y los mensajes de confirmación no son muy precisos, muestra que terminó,
pero el proceso todavía se está ejecutando, tenga eso en cuenta):

https://riptutorial.com/es/home 40
11. Modificar Index.html como:

https://riptutorial.com/es/home 41
12. Ahora corre y disfruta.

Notas:

• En caso de que haya errores de compilación con mecanografiado, por ejemplo,


"Proyecto Virtual de TypeScript", es un indicador de que la versión de TypeScript para
Visual Studio no se actualiza de acuerdo con la versión que seleccionamos en el
"package.json". Si esto sucede, instálelo. : https://www.microsoft.com/en-
us/download/details.aspx?id=48593

Referencias:

https://riptutorial.com/es/home 42
• El curso "Angular 2: Getting Started" de Deborah Kurata en Pluralsight:

https://www.pluralsight.com/courses/angular-2-getting-started-update

• Documentación Oficial Angular 2:

https://angular.io/

• Artículos por Mithun Pattankar:

http://www.mithunvp.com/angular-2-in-asp-net-5-typescript-visual-studio-2015/

http://www.mithunvp.com/using-angular-2-asp-net-mvc-5-visual-studio/

Errores esperados al generar componentes de Angular 2 en el proyecto .NET


Core (versión 0.8.3)

Al generar nuevos componentes de Angular 2 en un proyecto .NET Core, puede encontrarse con
los siguientes errores (a partir de la versión 0.8.3):

Error locating module for declaration


SilentError: No module files found

No app module found. Please add your new Class to your component.
Identical ClientApp/app/app.module.ts

[SOLUCIÓN]

1. Cambie el nombre de app.module.client.ts a app.client.module.ts

2. Abra app.client.module.ts: anteponga la declaración con 3 puntos "..." y envuelva la


declaración entre paréntesis.

Por ejemplo: [...sharedConfig.declarations, <MyComponent>]

3. Abra boot-client.ts: actualice su importación para usar la nueva referencia app.client.module.

Por ejemplo: import { AppModule } from './app/app.client.module';

4. Ahora intenta generar el nuevo componente: ng g component my-component

[EXPLICACIÓN]

Angular CLI busca un archivo llamado app.module.ts en su proyecto e intenta encontrar una
referencia para la propiedad de declaraciones para importar el componente. Esto debería ser una
matriz (como lo es sharedConfig.declarations), pero los cambios no se aplican

[FUENTES]

https://riptutorial.com/es/home 43
• https://github.com/angular/angular-cli/issues/2962
• https://www.udemy.com/aspnet-core-angular/learn/v4/t/lecture/6848548 (sección 3.33
colaborador de la conferencia Bryan Garzon)

Lea Angular2 y .Net Core en línea: https://riptutorial.com/es/asp-net-core/topic/9352/angular2-y--


net-core

https://riptutorial.com/es/home 44
Capítulo 4: ASP.NET Core: registre tanto la
solicitud como la respuesta utilizando
Middleware
Introducción
Durante algún tiempo he buscado la mejor manera de registrar solicitudes y respuestas en un
Core de ASP.Net. Estaba desarrollando servicios y uno de los requisitos era registrar la solicitud
con su respuesta en un registro de la base de datos. Tantos temas por ahí pero ninguno me
funcionó. Es solo por solicitud, solo por respuesta o simplemente no funcionó. Cuando finalmente
pude hacerlo, y evolucionó durante mi proyecto para mejorar el manejo de errores y el registro de
excepciones, así que pensé en compartir.

Observaciones
Algunos de los temas que me ayudaron:

• http://www.sulhome.com/blog/10/log-asp-net-core-request-and-response-using-middleware
• http://dotnetliberty.com/index.php/2016/01/07/logging-asp-net-5-requests-using-middleware/
• Cómo registrar el cuerpo de respuesta HTTP en ASP.NET Core 1.0

Examples
Logger Middleware

using Microsoft.AspNetCore.Http;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNetCore.Http.Internal;

public class LoggerMiddleware


{
private readonly RequestDelegate _next;

public LoggerMiddleware(RequestDelegate next)


{
_next = next;
}

public async Task Invoke(HttpContext context)


{
using (MemoryStream requestBodyStream = new MemoryStream())
{

https://riptutorial.com/es/home 45
using (MemoryStream responseBodyStream = new MemoryStream())
{
Stream originalRequestBody = context.Request.Body;
context.Request.EnableRewind();
Stream originalResponseBody = context.Response.Body;

try
{
await context.Request.Body.CopyToAsync(requestBodyStream);
requestBodyStream.Seek(0, SeekOrigin.Begin);

string requestBodyText = new


StreamReader(requestBodyStream).ReadToEnd();

requestBodyStream.Seek(0, SeekOrigin.Begin);
context.Request.Body = requestBodyStream;

string responseBody = "";

context.Response.Body = responseBodyStream;

Stopwatch watch = Stopwatch.StartNew();


await _next(context);
watch.Stop();

responseBodyStream.Seek(0, SeekOrigin.Begin);
responseBody = new StreamReader(responseBodyStream).ReadToEnd();
AuditLogger.LogToAudit(context.Request.Host.Host,
context.Request.Path, context.Request.QueryString.ToString(),
context.Connection.RemoteIpAddress.MapToIPv4().ToString(),
string.Join(",", context.Request.Headers.Select(he => he.Key +
":[" + he.Value + "]").ToList()),
requestBodyText, responseBody, DateTime.Now,
watch.ElapsedMilliseconds);

responseBodyStream.Seek(0, SeekOrigin.Begin);

await responseBodyStream.CopyToAsync(originalResponseBody);
}
catch (Exception ex)
{
ExceptionLogger.LogToDatabse(ex);
byte[] data = System.Text.Encoding.UTF8.GetBytes("Unhandled Error
occured, the error has been logged and the persons concerned are notified!! Please, try again
in a while.");
originalResponseBody.Write(data, 0, data.Length);
}
finally
{
context.Request.Body = originalRequestBody;
context.Response.Body = originalResponseBody;
}
}
}
}
}

Lea ASP.NET Core: registre tanto la solicitud como la respuesta utilizando Middleware en línea:
https://riptutorial.com/es/asp-net-core/topic/9510/asp-net-core--registre-tanto-la-solicitud-como-la-

https://riptutorial.com/es/home 46
respuesta-utilizando-middleware

https://riptutorial.com/es/home 47
Capítulo 5: Autorización
Examples
Autorización simple

La autorización en el núcleo de asp.net es simplemente AuthorizeAttribute

[Authorize]
public class SomeController : Controller
{
public IActionResult Get()
{
}

public IActionResult Post()


{
}
}

Esto solo permitirá que un usuario registrado acceda a estas acciones.

o usa lo siguiente para limitar solo una acción

public class SomeController : Controller


{
public IActionResult Get()
{
}

[Authorize]
public IActionResult Post()
{
}
}

Si desea permitir que todos los usuarios accedan a una de las acciones, puede usar
AllowAnonymousAttribute

[Authorize]
public class SomeController: Controller
{
public IActionResult Get()
{
}

[AllowAnonymous]
public IActionResult Post()
{
}
}

Ahora se puede acceder a la Post por cualquier usuario. AllowAnonymous siempre es una prioridad

https://riptutorial.com/es/home 48
para autorizar, por lo que si un controlador está configurado en AllowAnonymous , todas sus
acciones son públicas, independientemente de si tienen un AllowAnonymous AuthorizeAttribute o
no.

Hay una opción para configurar todos los controladores para que requieran solicitudes
autorizadas -

services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
})

Esto se hace agregando una política de autorización predeterminada a cada controlador:


cualquier atributo Authorize / AllowAnonymous sobre un controlador / acción anulará esta
configuración.

Lea Autorización en línea: https://riptutorial.com/es/asp-net-core/topic/6914/autorizacion

https://riptutorial.com/es/home 49
Capítulo 6: Ayudantes de etiquetas
Parámetros

Nombre Información

asp-action El nombre del método de acción al que se debe enviar el formulario.

controlador El nombre del controlador donde existe el método de acción especificado en


asp asp-action

Los valores de ruta personalizados que desea agregar como una cadena de
asp-route- * consulta al valor del atributo de acción de formulario. Reemplaza 8 con el
nombre de la cadena de consulta que deseas

Examples
Ayudante de etiqueta de formulario - Ejemplo básico

<form asp-action="create" asp-controller="Home">


<!--Your form elements goes here-->
</form>

Ayudante de etiqueta de formulario - Con atributos de ruta personalizados

<form asp-action="create"
asp-controller="Home"
asp-route-returnurl="dashboard"
asp-route-from="google">
<!--Your form elements goes here-->
</form>

Esto generará el siguiente marcado

<form action="/Home/create?returnurl=dashboard&amp;from=google" method="post">


<!--Your form elements goes here-->
</form>

Ayudante de etiqueta de entrada

Asumiendo que su vista está fuertemente escrita en un modelo de vista como

public class CreateProduct


{
public string Name { set; get; }
}

https://riptutorial.com/es/home 50
Y estás pasando un objeto de esto a la vista desde tu método de acción.

@model CreateProduct
<form asp-action="create" asp-controller="Home" >

<input type="text" asp-for="Name"/>


<input type="submit"/>

</form>

Esto generará el siguiente marcado.

<form action="/Home/create" method="post">

<input type="text" id="Name" name="Name" value="" />


<input type="submit"/>
<input name="__RequestVerificationToken" type="hidden" value="ThisWillBeAUniqueToken" />

</form>

Si desea que el campo de entrada se represente con un valor predeterminado, puede establecer
el valor de la propiedad Nombre de su modelo de vista en el método de acción.

public IActionResult Create()


{
var vm = new CreateProduct { Name="IPhone"};
return View(vm);
}

Envío de formulario y enlace de modelo

El enlace del modelo funcionará bien si utiliza CreateProduct como su parámetro del método de
acción HttpPost / un parámetro llamado name

Seleccione Tag Helper

Asumiendo que su vista está fuertemente escrita en un modelo de vista como este

public class CreateProduct


{
public IEnumerable<SelectListItem> Categories { set; get; }
public int SelectedCategory { set; get; }
}

Y en su método de acción GET, está creando un objeto de este modelo de vista, configurando la
propiedad Categorías y enviando a la vista

public IActionResult Create()


{
var vm = new CreateProduct();
vm.Categories = new List<SelectListItem>
{
new SelectListItem {Text = "Books", Value = "1"},

https://riptutorial.com/es/home 51
new SelectListItem {Text = "Furniture", Value = "2"}
};
return View(vm);
}

y en su opinión

@model CreateProduct

<form asp-action="create" asp-controller="Home">


<select asp-for="SelectedCategory" asp-items="@Model.Categories">
<option>Select one</option>
</select>
<input type="submit"/>
</form>

Esto representará el marcado a continuación ( incluido solo las partes relevantes del formulario /
campos )

<form action="/Home/create" method="post">


<select data-val="true" id="SelectedCategory" name="SelectedCategory">
<option>Select one</option>
<option value="1">Shyju</option>
<option value="2">Sean</option>
</select>
<input type="submit"/>
</form>

Obtención del valor desplegable seleccionado en el envío del formulario

Puede usar el mismo modelo de vista que su parámetro de método de acción HttpPost

[HttpPost]
public ActionResult Create(CreateProduct model)
{
//check model.SelectedCategory value
/ /to do : return something
}

Establecer una opción como la seleccionada.

Si desea establecer una opción como la opción seleccionada, simplemente puede configurar el
valor de la propiedad SelectedCategory .

public IActionResult Create()


{
var vm = new CreateProduct();
vm.Categories = new List<SelectListItem>
{
new SelectListItem {Text = "Books", Value = "1"},
new SelectListItem {Text = "Furniture", Value = "2"},
new SelectListItem {Text = "Music", Value = "3"}
};
vm.SelectedCategory = 2;

https://riptutorial.com/es/home 52
return View(vm);
}

Renderizando un menú desplegable de selección múltiple / ListBox

Si desea representar un menú desplegable de selección múltiple, simplemente puede cambiar la


propiedad del modelo de vista que utiliza asp-for atributo asp-for en su vista a un tipo de matriz.

public class CreateProduct


{
public IEnumerable<SelectListItem> Categories { set; get; }
public int[] SelectedCategories { set; get; }
}

En la vista

@model CreateProduct

<form asp-action="create" asp-controller="Home" >


<select asp-for="SelectedCategories" asp-items="@Model.Categories">
<option>Select one</option>
</select>
<input type="submit"/>
</form>

Esto generará el elemento SELECT con multiple atributos.

<form action="/Home/create" method="post">


<select id="SelectedCategories" multiple="multiple" name="SelectedCategories">
<option>Select one</option>
<option value="1">Shyju</option>
<option value="2">Sean</option>
</select>
<input type="submit"/>
</form>

Ayudante de etiqueta personalizada

Puede crear sus propios ayudantes de etiquetas implementando ITagHelper o derivando de la


clase de conveniencia TagHelper .

• La convención predeterminada es apuntar a una etiqueta html que coincida con el nombre
del ayudante sin el sufijo opcional TagHelper. Por ejemplo, WidgetTagHelper apuntará a una
etiqueta <widget> .
• El atributo [HtmlTargetElement] se puede usar para controlar aún más la etiqueta a la que se
dirige
• A cualquier propiedad pública de la clase se le puede asignar un valor como atributo en el
marcado de afeitar. Por ejemplo, una propiedad public string Title {get; set;} se le puede
dar un valor como <widget title="my title">
• De forma predeterminada, los ayudantes de etiquetas traducen los nombres y las
propiedades de las clases de C # en cascos de Pascal para los ayudantes de etiquetas en

https://riptutorial.com/es/home 53
casos de kebab inferiores. Por ejemplo, si omite el uso de [HtmlTargetElement] y el nombre
de la clase es WidgetBoxTagHelper , entonces en Razor escribirá <widget-box></widget-box> .
• Process y ProcessAsync contienen la lógica de representación. Ambos reciben un parámetro
de contexto con información sobre la etiqueta actual que se está representando y un
parámetro de salida utilizado para personalizar el resultado representado.

Cualquier conjunto que contenga ayudantes de etiquetas personalizadas debe agregarse al


archivo _ViewImports.cshtml ( tenga en cuenta que es el conjunto que se está registrando, no
el espacio de nombres):

@addTagHelper *, MyAssembly

Asistente de ejemplo de etiqueta


personalizada
El siguiente ejemplo crea un ayudante de etiqueta de widget personalizado que se enfocará en el
marcado de maquinilla de afeitar como:

<widget-box title="My Title">This is my content: @ViewData["Message"]</widget-box>

El cual será rendido como:

<div class="widget-box">
<div class="widget-header">My Title</div>
<div class="widget-body">This is my content: some message</div>
</div>

El código necesario para crear tal ayudante de etiquetas es el siguiente:

[HtmlTargetElement("widget-box")]
public class WidgetTagHelper : TagHelper
{
public string Title { get; set; }

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)


{
var outerTag = new TagBuilder("div");
outerTag.Attributes.Add("class", output.TagName);
output.MergeAttributes(outerTag);
output.TagName = outerTag.TagName;

//Create the header


var header = new TagBuilder("div");
header.Attributes.Add("class", "widget-header");
header.InnerHtml.Append(this.Title);
output.PreContent.SetHtmlContent(header);

//Create the body and replace original tag helper content


var body = new TagBuilder("div");
body.Attributes.Add("class", "widget-body");

https://riptutorial.com/es/home 54
var originalContents = await output.GetChildContentAsync();
body.InnerHtml.Append(originalContents.GetContent());
output.Content.SetHtmlContent(body);
}
}

Etiqueta de etiqueta de ayuda

Label Tag Helper se puede usar para representar label para una propiedad de modelo.
Reemplaza el método Html.LabelFor en versiones anteriores de MVC.

Digamos que tienes un modelo:

public class FormViewModel


{
public string Name { get; set; }
}

En la vista que se puede utilizar label elemento HTML y asp-for Asistente de etiquetas:

<form>
<label asp-for="Name"></label>
<input asp-for="Name" type="text" />
</form>

Esto es equivalente al siguiente código en versiones anteriores de MVC:

<form>
@Html.LabelFor(x => x.Name)
@Html.TextBoxFor(x => x.Name)
</form>

Los dos fragmentos de código anteriores representan el mismo HTML:

<form>
<label for="Name">Name</label>
<input name="Name" id="Name" type="text" value="">
</form>

Ayudante de la etiqueta del ancla

El ayudante de la etiqueta de anclaje se utiliza para generar atributos href para vincular a una
acción de controlador particular o ruta MVC. Ejemplo basico

<a asp-controller="Products" asp-action="Index">Login</a>

A veces, necesitamos especificar parámetros adicionales para la acción del controlador a la que
está vinculado. Podemos especificar valores para estos parámetros agregando atributos con el
prefijo asp-route-.

https://riptutorial.com/es/home 55
<a asp-controller="Products" asp-action="Details" asp-route-id="@Model.ProductId">
View Details
</a>

Lea Ayudantes de etiquetas en línea: https://riptutorial.com/es/asp-net-core/topic/2665/ayudantes-


de-etiquetas

https://riptutorial.com/es/home 56
Capítulo 7: Configuración
Introducción
El núcleo de Asp.net proporciona abstracciones de configuración. Le permiten cargar ajustes de
configuración de varias fuentes y construir un modelo de configuración final que luego puede ser
consumido por su aplicación.

Sintaxis
• IConfiguration
• string this[string key] { get; set; }
• IEnumerable<IConfigurationSection> GetChildren();
• IConfigurationSection GetSection(string key);

Examples
Acceso a la configuración mediante la inyección de dependencias

El enfoque recomendado sería evitar hacerlo y, más bien, utilizar IOptions<TOptions> e


IServiceCollection.Configure<TOptions> .

Dicho esto, esto todavía es bastante sencillo para hacer que IConfigurationRoot esté disponible en
toda la aplicación.

En el constructor Startup.cs, debe tener el siguiente código para construir la configuración,

Configuration = builder.Build();

Aquí la Configuration es una instancia de IConfigurationRoot , y agrega esta instancia como


Singleton a la colección de servicios en el método ConfigureServices, Startup.cs,

public void ConfigureServices(IServiceCollection services)


{
services.AddSingleton<IConfigurationRoot>(provider => Configuration);

Por ejemplo, ahora puede acceder a la configuración en un Controlador / Servicio

public MyController(IConfigurationRoot config){


var setting1= config.GetValue<string>("Setting1")
}

Empezando

En este ejemplo, describiremos lo que sucede cuando subyace un nuevo proyecto.

https://riptutorial.com/es/home 57
En primer lugar, se agregarán las siguientes dependencias a su proyecto (actualmente el archivo
project.json ):

"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",

También creará un constructor en su archivo Startup.cs que se encargará de construir la


configuración utilizando la API fluida de ConfigurationBuilder :

1. Primero crea un nuevo ConfigurationBuilder .


2. A continuación, establece una ruta base que se utilizará para calcular la ruta absoluta de
otros archivos.
3. Agrega un appsettings.json opcional al generador de configuración y monitorea sus cambios
4. Agrega un archivo de configuración appsettings.environementName.json relacionado con el
entorno opcional
5. A continuación, añade variables de entorno.

public Startup(IHostingEnvironment env)


{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();

Configuration = builder.Build();
}

Si se establece una misma configuración en varias fuentes, se ganará la última fuente agregada y
se seleccionará su valor.

La configuración puede entonces ser consumida usando la propiedad del indexador. Los dos
puntos : carácter sirve un delimitador de camino.

Configuration["AzureLogger:ConnectionString"]

Esto buscará un valor de configuración ConnectionString en una sección de AzureLogger .

Trabajar con variables de entorno

Puede obtener la configuración de las variables de entorno llamando a .AddEnvironmentVariables()


en su ConfigurationBuilder .

APPSETTING_variables de entorno con el prefijo APPSETTING_ A continuación, utilizará dos puntos :


como el separador de ruta clave.

Esto significa que: siguientes ajustes de entorno:

APPSETTING_Security:Authentication:UserName = a_user_name
APPSETTING_Security:Authentication:Password = a_user_password

https://riptutorial.com/es/home 58
Será el equivalente a este json:

{
"Security" : {
"Authentication" : {
"UserName" : "a_user_name",
"Password" : "a_user_password"
}
}
}

** Tenga en cuenta que el Servicio de Azure transmitirá la configuración como variables de


entorno. Prefijo se establecerá para usted de forma transparente. Entonces, para hacer lo mismo
en Azure, simplemente configure dos Configuraciones de aplicaciones en la hoja de
Configuración de aplicaciones:

Security:Authentication:UserName a_user_name
Security:Authentication:Password a_user_password

Opción modelo y configuración

Cuando se trata de grandes conjuntos de configuración de valor, puede resultar poco práctico
cargarlos uno compre uno.

El modelo de opción que viene con asp.net ofrece una manera conveniente de asignar una
section a una dotnet poco : por ejemplo, uno podría hidratar las StorageOptions directamente desde
una sección de configuración b agregando Microsoft.Extensions.Options.ConfigurationExtensions y
llamando al Configure<TOptions>(IConfiguration config) Método de extensión
Configure<TOptions>(IConfiguration config) .

services.Configure<StorageOptions>(Configuration.GetSection("Storage"));

En la fuente de configuración de memoria

También puede generar la configuración desde un objeto en memoria, como un


Dictionary<string,string>

.AddInMemoryCollection(new Dictionary<string, string>


{
["akey"] = "a value"
})

Esto puede revelarse útil en escenarios de integración / pruebas de unidad.

Lea Configuración en línea: https://riptutorial.com/es/asp-net-core/topic/8660/configuracion

https://riptutorial.com/es/home 59
Capítulo 8: Configurando entornos múltiples
Examples
Tener apariciones por entorno

Para cada entorno, debe crear una configuración de aplicaciones separada. {EnvironmentName}
.json files:

• appsettings.Development.json
• appsettings.Staging.json
• appsettings.Production.json

Luego abra el archivo project.json e inclúyalos en "incluir" en la sección "publishOptions". Esto


enumera todos los archivos y carpetas que se incluirán cuando publique:

"publishOptions": {
"include": [
"appsettings.Development.json",
"appsettings.Staging.json",
"appsettings.Production.json"
...
]
}

El paso final. En su clase de inicio agregue:

.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

en el constructor donde configuras las fuentes de configuración:

var builder = new ConfigurationBuilder()


.SetBasePath(env.ContentRootPath)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();

Obtener / verificar el nombre del entorno desde el código

Todo lo que necesita es una variable de tipo IHostingEnvironment :

• obtener el nombre del entorno:

env.EnvironmentName

• para predefinida Development , Staging , Production entornos de la mejor manera es utilizar


métodos de extensión de HostingEnvironmentExtensions clase

https://riptutorial.com/es/home 60
env.IsDevelopment()
env.IsStaging()
env.IsProduction()

• ignorar correctamente el caso (otro método de extensión de HostingEnvironmentExtensions


:

env.IsEnvironment("environmentname")

• variante sensible a mayúsculas y minúsculas:

env.EnvironmentName == "Development"

Configurando múltiples entornos

Este ejemplo muestra cómo configurar múltiples entornos con diferentes configuraciones de
inyección de dependencia y middlewares separados en una clase de Startup .

Junto con public void Configure(IApplicationBuilder app) y public void


Configure(IApplicationBuilder app) public void ConfigureServices(IServiceCollection services) se
pueden usar Configure{EnvironmentName} y Configure{EnvironmentName}Services para tener una
configuración dependiente del entorno.

El uso de este patrón evita poner mucha lógica if/else dentro de un solo método / clase de
Startup y mantenerlo limpio y separado.

public class Startup


{
public void ConfigureServices(IServiceCollection services) { }
public void ConfigureStaggingServices(IServiceCollection services) { }
public void ConfigureProductionServices(IServiceCollection services) { }

public void Configure(IApplicationBuilder app) { }


public void ConfigureStagging(IApplicationBuilder app) { }
public void ConfigureProduction(IApplicationBuilder app) { }
}

Cuando no se encuentran los Configure{Environmentname}Services Configure{Environmentname} o


Configure{Environmentname}Services , volverá a Configure o ConfigureServices respectivamente.

La misma semántica también se aplica a la clase de Startup . StartupProduction será utilizado


cuando el ASPNETCORE_ENVIRONMENT variable se establece en Production y se caerá de nuevo a
Startup cuando es Stagging o Development

Un ejemplo completo:

public class Startup


{
public Startup(IHostingEnvironment hostEnv)
{

https://riptutorial.com/es/home 61
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.SetBasePath(hostEnv.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{hostEnv.EnvironmentName}.json", optional: true,
reloadOnChange: true);

if (hostEnv.IsDevelopment())
{
// This will push telemetry data through Application Insights pipeline faster,
allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}

builder.AddEnvironmentVariables();
Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; set; }

// This method gets called by the runtime. Use this method to add services to the
container
public static void RegisterCommonServices(IServiceCollection services)
{
services.AddScoped<ICommonService, CommonService>();
services.AddScoped<ICommonRepository, CommonRepository>();
}

public void ConfigureServices(IServiceCollection services)


{
RegisterCommonServices(services);

services.AddOptions();
services.AddMvc();
}

public void ConfigureDevelopment(IApplicationBuilder app, IHostingEnvironment env,


ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();

app.UseBrowserLink();
app.UseDeveloperExceptionPage();

app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseStaticFiles();
app.UseMvc();
}

// No console Logger and debugging tools in this configuration


public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory
loggerFactory)
{
loggerFactory.AddDebug();

app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseStaticFiles();
app.UseMvc();

https://riptutorial.com/es/home 62
}
}

Representar contenido específico del entorno a la vista

Es posible que tenga que mostrar cierto contenido a la vista, que es específico de un entorno
solamente. Para lograr este objetivo, puede utilizar el ayudante de etiqueta de entorno:

<environment names="Development">
<h1>This is heading for development environment</h1>
</environment>
<environment names="Staging,Production">
<h1>This is heading for Staging or production environment</h1>
</environment>

El ayudante de la etiqueta Entorno solo representará su contenido si el entorno actual coincide


con uno de los entornos especificados utilizando el atributo de names .

Establecer la variable de entorno desde la línea de comando

Establecer el entorno para el Development

SET ASPNETCORE_ENVIRONMENT=Development

Ahora, ejecutar una aplicación Asp.Net Core estará en el entorno definido.

Nota

1. No debe haber espacio antes y después del signo de igualdad = .


2. El símbolo del sistema no debe cerrarse antes de ejecutar la aplicación porque la
configuración no se mantiene.

Establecer variable de entorno desde PowerShell

Cuando use PowerShell, puede usar setx.exe para establecer variables de entorno de forma
permanente.

1. Iniciar PowerShell

2. Escriba uno de los siguientes:

setx ASPNETCORE_ENVIRONMENT "desarrollo"

setx ASPNETCORE_ENVIRONMENT "puesta en escena"

3. Reinicie PowerShell

Usando ASPNETCORE_ENVIRONMENT desde web.config

Si no desea utilizar ASPNETCORE_ENVIRONMENT de las variables de entorno y utilizarlo desde

https://riptutorial.com/es/home 63
web.config de su aplicación, modifique web.config como este:

<aspNetCore processPath=".\WebApplication.exe" arguments="" stdoutLogEnabled="false"


stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
</environmentVariables>
</aspNetCore>

Lea Configurando entornos múltiples en línea: https://riptutorial.com/es/asp-net-


core/topic/2292/configurando-entornos-multiples

https://riptutorial.com/es/home 64
Capítulo 9: Empaquetado y Minificación
Examples
Gruñido y gulp

En las aplicaciones de ASP.NET Core, agrupa y minimiza los recursos del lado del cliente durante
el tiempo de diseño utilizando herramientas de terceros, como Gulp y Grunt . Al utilizar la
agrupación y minimización en tiempo de diseño, los archivos minificados se crean antes del
despliegue de la aplicación. Agrupar y minimizar antes de la implementación proporciona la
ventaja de una carga de servidor reducida. Sin embargo, es importante reconocer que la
agrupación en tiempo de diseño y la minificación aumentan la complejidad de construcción y solo
funcionan con archivos estáticos.

Esto se hace en ASP.NET Core configurando Gulp a través de un archivo gulpfile.js dentro de
su proyecto:

// Defining dependencies
var gulp = require("gulp"),
rimraf = require("rimraf"),
concat = require("gulp-concat"),
cssmin = require("gulp-cssmin"),
uglify = require("gulp-uglify");

// Define web root


var webroot = "./wwwroot/"

// Defining paths
var paths = {
js: webroot + "js/**/*.js",
minJs: webroot + "js/**/*.min.js",
css: webroot + "css/**/*.css",
minCss: webroot + "css/**/*.min.css",
concatJsDest: webroot + "js/site.min.js",
concatCssDest: webroot + "css/site.min.css"
};

// Bundling (via concat()) and minifying (via uglify()) Javascript


gulp.task("min:js", function () {
return gulp.src([paths.js, "!" + paths.minJs], { base: "." })
.pipe(concat(paths.concatJsDest))
.pipe(uglify())
.pipe(gulp.dest("."));
});

// Bundling (via concat()) and minifying (via cssmin()) Javascript


gulp.task("min:css", function () {
return gulp.src([paths.css, "!" + paths.minCss])
.pipe(concat(paths.concatCssDest))
.pipe(cssmin())
.pipe(gulp.dest("."));
});

https://riptutorial.com/es/home 65
Este enfoque agrupará y minimizará adecuadamente sus archivos Javascript y CSS existentes,
respectivamente, de acuerdo con los directorios y los patrones globales que se utilizan.

Extensión Bundler y Minifier

Visual Studio también cuenta con una extensión Bundler y Minifier disponible que es capaz de
manejar este proceso por usted. La extensión le permite seleccionar y agrupar fácilmente los
archivos que necesita sin escribir una línea de código.

Construyendo tus paquetes


Después de instalar la extensión, selecciona todos los archivos específicos que deseas
incluir dentro de un paquete y usas la opción Bundle and Minify Files de la extensión:

Esto le pedirá que nombre su paquete y elija una ubicación para guardarlo. Luego notará un
nuevo archivo dentro de su proyecto llamado bundleconfig.json que se parece a lo siguiente:

https://riptutorial.com/es/home 66
[
{
"outputFileName": "wwwroot/app/bundle.js",
"inputFiles": [
"wwwroot/lib/jquery/dist/jquery.js",
"wwwroot/lib/bootstrap/dist/js/bootstrap.js",
"wwwroot/lib/jquery-validation/dist/jquery.validate.js",
"wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"
]
}
]

NOTA: El orden en el que se seleccionan los archivos determinará el orden en el que


aparecerán dentro del paquete, por lo que, si tiene dependencias, asegúrese de
tenerlo en cuenta.

Reducir sus paquetes


Ahora, el paso anterior simplemente agrupará sus archivos, si desea reducir el tamaño del
paquete, debe indicar eso dentro del archivo bundleconfig.json. Simplemente agregue un
bloque minify como el siguiente a su paquete existente para indicar que desea que se
minimice:

[
{
"outputFileName": "wwwroot/app/bundle.js",
"inputFiles": [
"wwwroot/lib/jquery/dist/jquery.js",
"wwwroot/lib/bootstrap/dist/js/bootstrap.js",
"wwwroot/lib/jquery-validation/dist/jquery.validate.js",
"wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"
],
"minify": {
"enabled": true
}
}
]

Automatiza tus paquetes


Finalmente, si desea automatizar este proceso, puede programar una tarea para que se ejecute
siempre que su aplicación esté diseñada para garantizar que sus paquetes reflejen cualquier
cambio dentro de su aplicación.

Para hacer esto, necesitarás hacer lo siguiente:

• Abra el Explorador de tareas Runner (a través de Herramientas> Explorador de tareas


Runner).
• Haga clic derecho en la opción Actualizar todos los archivos debajo de
bundleconfig.json .
• Seleccione su enlace preferido en el menú contextual de enlaces.

https://riptutorial.com/es/home 67
Después de hacer esto, sus paquetes se actualizarán automáticamente en el paso preferido que
seleccionó.

El comando dotnet bundle

El lanzamiento de ASP.NET Core RTM presentó BundlerMinifier.Core , una nueva herramienta de


empaquetado y minificación que se puede integrar fácilmente en las aplicaciones existentes de
ASP.NET Core y no requiere extensiones externas ni archivos de script.

Usando BundlerMinifier.Core
Para usar esta herramienta, simplemente agregue una referencia a BundlerMinifier.Core dentro
de la sección de tools de su archivo project.json existente como se ve a continuación:

"tools": {
"BundlerMinifier.Core": "2.0.238",
"Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
}

Configurando tus paquetes


Después de agregar la herramienta, deberá agregar un archivo bundleconfig.json en su
proyecto que se usará para configurar los archivos que desea incluir dentro de sus paquetes.
Una configuración mínima se puede ver a continuación:

[
{
"outputFileName": "wwwroot/css/site.min.css",
"inputFiles": [
"wwwroot/css/site.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
"minify": {

https://riptutorial.com/es/home 68
"enabled": true,
"renameLocals": true
},
"sourceMap": false
},
{
"outputFileName": "wwwroot/js/semantic.validation.min.js",
"inputFiles": [
"wwwroot/js/semantic.validation.js"
],
"minify": {
"enabled": true,
"renameLocals": true
}
}
]

Creación / actualización de paquetes


Una vez que se hayan configurado sus paquetes, puede agrupar y minimizar sus archivos
existentes mediante el siguiente comando:

dotnet bundle

Bundling automatizado
El proceso de Bundling and Minification se puede automatizar como parte del proceso de
compilación agregando el comando dotnet bundle en la sección de precompilación de su archivo
project.json existente:

"scripts": {
"precompile": [
"dotnet bundle"
]
}

Comandos disponibles
Puede ver una lista de todos los comandos disponibles y sus descripciones a continuación:

• dotnet bundle : ejecuta el comando bundle utilizando el archivo bundleconfig.json para


agrupar y minimizar los archivos especificados.
• dotnet bundle clean : borra todos los archivos de salida existentes del disco.
• dotnet bundle watch : crea un observador que ejecutará automáticamente el dotnet bundle
cada vez que un archivo de entrada existente desde la configuración de bundleconfig.json
sus archivos.
• Ayuda de dotnet bundle : muestra todas las opciones de ayuda disponibles e instrucciones
para usar la interfaz de línea de comandos.

Lea Empaquetado y Minificación en línea: https://riptutorial.com/es/asp-net-

https://riptutorial.com/es/home 69
core/topic/4051/empaquetado-y-minificacion

https://riptutorial.com/es/home 70
Capítulo 10: Enrutamiento
Examples
Enrutamiento básico

app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});

Esto coincidirá con las solicitudes de /Home/Index , /Home/Index/123 y /

Restricciones de enrutamiento

Es posible crear una restricción de enrutamiento personalizada que se puede usar dentro de las
rutas para restringir un parámetro a valores o patrones específicos.

Esta restricción coincidirá con un patrón típico de cultura / ubicación, como en-US, de-DE, zh-
CHT, zh-Hant.

public class LocaleConstraint : IRouteConstraint


{
private static readonly Regex LocalePattern = new Regex(@"^[a-z]{2}(-[a-z]{2,4})?$",
RegexOptions.Compiled | RegexOptions.IgnoreCase);

public bool Match(HttpContext httpContext, IRouter route, string routeKey,


RouteValueDictionary values, RouteDirection routeDirection)
{
if (!values.ContainsKey(routeKey))
return false;

string locale = values[routeKey] as string;


if (string.IsNullOrWhiteSpace(locale))
return false;

return LocalePattern.IsMatch(locale);
}
}

Posteriormente, la restricción debe registrarse antes de que se pueda utilizar en las rutas.

services.Configure<RouteOptions>(options =>
{
options.ConstraintMap.Add("locale", typeof(LocaleConstraint));
});

Ahora se puede utilizar dentro de las rutas.

https://riptutorial.com/es/home 71
Usándolo en los controladores
[Route("api/{culture:locale}/[controller]")]
public class ProductController : Controller { }

Usándolo en Acciones
[HttpGet("api/{culture:locale}/[controller]/{productId}"]
public Task<IActionResult> GetProductAsync(string productId) { }

Usándolo en rutas predeterminadas


app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "api/{culture:locale}/{controller}/{id?}");
routes.MapRoute(
name: "default",
template: "api/{controller}/{id?}");
});

Lea Enrutamiento en línea: https://riptutorial.com/es/asp-net-core/topic/2863/enrutamiento

https://riptutorial.com/es/home 72
Capítulo 11: Envío de correo electrónico en
aplicaciones .Net Core utilizando MailKit
Introducción
Actualmente .Net Core no incluye soporte para enviar correos electrónicos como System.Net.Mail
desde .Net. El proyecto MailKit (que está disponible en nuget ) es una buena biblioteca para este
propósito.

Examples
Instalación del paquete nuget

Install-Package MailKit

Implementación simple para el envío de correos electrónicos.

using MailKit.Net.Smtp;
using MimeKit;
using MimeKit.Text;
using System.Threading.Tasks;

namespace Project.Services
{
/// Using a static class to store sensitive credentials
/// for simplicity. Ideally these should be stored in
/// configuration files
public static class Constants
{
public static string SenderName => "<sender_name>";
public static string SenderEmail => "<sender_email>";
public static string EmailPassword => "email_password";
public static string SmtpHost => "<smtp_host>";
public static int SmtpPort => "smtp_port";
}
public class EmailService : IEmailSender
{
public Task SendEmailAsync(string recipientEmail, string subject, string message)
{
MimeMessage mimeMessage = new MimeMessage();
mimeMessage.From.Add(new MailboxAddress(Constants.SenderName,
Constants.SenderEmail));
mimeMessage.To.Add(new MailboxAddress("", recipientEmail));
mimeMessage.Subject = subject;

mimeMessage.Body = new TextPart(TextFormat.Html)


{
Text = message,
};

using (var client = new SmtpClient())

https://riptutorial.com/es/home 73
{

client.ServerCertificateValidationCallback = (s, c, h, e) => true;

client.Connect(Constants.SmtpHost, Constants.SmtpPort, false);

client.AuthenticationMechanisms.Remove("XOAUTH2");

// Note: only needed if the SMTP server requires authentication


client.Authenticate(Constants.SenderEmail, Constants.EmailPassword);

client.Send(mimeMessage);

client.Disconnect(true);
return Task.FromResult(0);
}
}
}

Lea Envío de correo electrónico en aplicaciones .Net Core utilizando MailKit en línea:
https://riptutorial.com/es/asp-net-core/topic/8831/envio-de-correo-electronico-en-aplicaciones--net-
core-utilizando-mailkit

https://riptutorial.com/es/home 74
Capítulo 12: Explotación florestal
Examples
Usando NLog Logger

NLog.Extensions.Logging es el proveedor oficial de NLog para Microsoft en .NET Core y


ASP.NET Core. Aquí y aquí están la instrucción y el ejemplo respectivamente.

Añadir Logger al controlador

En lugar de solicitar un ILoggerFactory y crear una instancia de ILogger explícitamente, puede


solicitar un ILogger (donde T es la clase que solicita el registrador).

public class TodoController : Controller


{
private readonly ILogger _logger;

public TodoController(ILogger<TodoController> logger)


{
_logger = logger;
}
}

Usando Serilog en la aplicación ASP.NET core 1.0

1) En project.json, agregue las dependencias a continuación

"Serilog": "2.2.0",
"Serilog.Extensions.Logging": "1.2.0",
"Serilog.Sinks.RollingFile": "2.0.0",
"Serilog.Sinks.File": "3.0.0"

2) En Startup.cs, agregue las siguientes líneas en constructor-

Log.Logger = new LoggerConfiguration()


.MinimumLevel.Debug()
.WriteTo.RollingFile(Path.Combine(env.ContentRootPath, "Serilog-{Date}.txt"))
.CreateLogger();

3) En el método de configuración de la clase de inicio

loggerFactory.AddSerilog();

4) En Controller, crea una instancia de ILogger como esta:

public class HomeController : Controller


{

https://riptutorial.com/es/home 75
ILogger<HomeController> _logger = null;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}

5) Registro de muestras abajo

try
{
throw new Exception("Serilog Testing");
}
catch (System.Exception ex)
{
this._logger.LogError(ex.Message);
}

Lea Explotación florestal en línea: https://riptutorial.com/es/asp-net-core/topic/1946/explotacion-


florestal

https://riptutorial.com/es/home 76
Capítulo 13: Inyección de dependencia
Introducción
El núcleo de Aspnet se construye con la inyección de dependencia como uno de sus conceptos
clave. Introduce una abstracción de contenedor conforme para que pueda reemplazar la
incorporada con un contenedor de terceros de su elección.

Sintaxis
• IServiceCollection.Add(ServiceDescriptor item);
• IServiceCollection.AddScoped(Type serviceType);
• IServiceCollection.AddScoped(Type serviceType, Type implementationType);
• IServiceCollection.AddScoped(Type serviceType, Func<IServiceProvider, object>
implementationFactory);
• IServiceCollection.AddScoped<TService>()
• IServiceCollection.AddScoped<TService>(Func<IServiceProvider, TService>
implementationFactory)
• IServiceCollection.AddScoped<TService, TImplementation>()
• IServiceCollection.AddScoped<TService, TImplementation>(Func<IServiceProvider,
TImplementation> implementationFactory)
• IServiceCollection.AddSingleton(Type serviceType);
• IServiceCollection.AddSingleton(Type serviceType, Func<IServiceProvider, object>
implementationFactory);
• IServiceCollection.AddSingleton(Type serviceType, Type implementationType);
• IServiceCollection.AddSingleton(Type serviceType, object implementationInstance);
• IServiceCollection.AddSingleton<TService>()
• IServiceCollection.AddSingleton<TService>(Func<IServiceProvider, TService>
implementationFactory)
• IServiceCollection.AddSingleton<TService>(TService implementationInstance)
• IServiceCollection.AddSingleton<TService, TImplementation>()
• IServiceCollection.AddSingleton<TService, TImplementation>(Func<IServiceProvider,
TImplementation> implementationFactory)
• IServiceCollection.AddTransient(Type serviceType);
• IServiceCollection.AddTransient(Type serviceType, Func<IServiceProvider, object>
implementationFactory);
• IServiceCollection.AddTransient(Type serviceType, Type implementationType);
• IServiceCollection.AddTransient<TService>()
• IServiceCollection.AddTransient<TService>(Func<IServiceProvider, TService>
implementationFactory)
• IServiceCollection.AddTransient<TService, TImplementation>()
• IServiceCollection.AddTransient<TService, TImplementation>(Func<IServiceProvider,
TImplementation> implementationFactory)
• IServiceProvider.GetService(Type serviceType)
• IServiceProvider.GetService<T>()
• IServiceProvider.GetServices(Type serviceType)
• IServiceProvider.GetServices<T>()

Observaciones
Para usar variantes genéricas de los métodos IServiceProvider , debe incluir el siguiente espacio
de nombres:

https://riptutorial.com/es/home 77
using Microsoft.Extensions.DependencyInjection;

Examples
Registrarse y resolver manualmente

La forma preferida de describir las dependencias es mediante el uso de la inyección de


constructor que sigue el Principio de Dependencias Explícitas :

ITestService.cs

public interface ITestService


{
int GenerateRandom();
}

TestService.cs

public class TestService : ITestService


{
public int GenerateRandom()
{
return 4;
}
}

Startup.cs (ConfigureServices)

public void ConfigureServices(IServiceCollection services)


{
// ...

services.AddTransient<ITestService, TestService>();
}

HomeController.cs

using Microsoft.Extensions.DependencyInjection;

namespace Core.Controllers
{
public class HomeController : Controller
{
public HomeController(ITestService service)
{
int rnd = service.GenerateRandom();
}
}
}

Registrar dependencias

https://riptutorial.com/es/home 78
El contenedor incorporado viene con un conjunto de características incorporadas:

Control de por vida


public void ConfigureServices(IServiceCollection services)
{
// ...

services.AddTransient<ITestService, TestService>();
// or
services.AddScoped<ITestService, TestService>();
// or
services.AddSingleton<ITestService, TestService>();
// or
services.AddSingleton<ITestService>(new TestService());
}

• AddTransient : Creado cada vez que se resuelve


• AddScoped : creado una vez por solicitud
• AddSingleton : Lazily creado una vez por aplicación
• AddSingleton (instancia) : proporciona una instancia creada previamente por aplicación

Dependencias enumerables
También es posible registrar dependencias enumerables:

services.TryAddEnumerable(ServiceDescriptor.Transient<ITestService, TestServiceImpl1>());
services.TryAddEnumerable(ServiceDescriptor.Transient<ITestService, TestServiceImpl2>());

A continuación, puede consumirlos de la siguiente manera:

public class HomeController : Controller


{
public HomeController(IEnumerable<ITestService> services)
{
// do something with services.
}
}

Dependencias genéricas
También puedes registrar dependencias genéricas:

services.Add(ServiceDescriptor.Singleton(typeof(IKeyValueStore<>), typeof(KeyValueStore<>)));

Y luego consumirlo de la siguiente manera:

https://riptutorial.com/es/home 79
public class HomeController : Controller
{
public HomeController(IKeyValueStore<UserSettings> userSettings)
{
// do something with services.
}
}

Recuperar dependencias en un controlador

Una vez registrada, se puede recuperar una dependencia agregando parámetros en el


constructor del controlador.

// ...
using System;
using Microsoft.Extensions.DependencyInjection;

namespace Core.Controllers
{
public class HomeController : Controller
{
public HomeController(ITestService service)
{
int rnd = service.GenerateRandom();
}
}
}

Inyectar una dependencia en una acción del controlador

Una característica incorporada menos conocida es la inyección de acción del controlador que
utiliza el FromServicesAttribute .

[HttpGet]
public async Task<IActionResult> GetAllAsync([FromServices]IProductService products)
{
return Ok(await products.GetAllAsync());
}

Una nota importante es que el [FromServices] no se puede utilizar como mecanismo general de
"Inyección de propiedades" o "Inyección de métodos". Solo se puede usar en los parámetros de
método de una acción de controlador o constructor de controlador (aunque en el constructor está
obsoleto, ya que el sistema ASP.NET Core DI ya usa inyección de constructor y no se requieren
marcadores adicionales).

No se puede utilizar en ningún lugar fuera de un controlador, acción del controlador .


También es muy específico para ASP.NET Core MVC y reside en el ensamblado
Microsoft.AspNetCore.Mvc.Core .

Cita original del problema de ASP.NET Core MVC GitHub ( Limitar [FromServices] para aplicar
solo a parámetros ) con respecto a este atributo:

https://riptutorial.com/es/home 80
@rynowak:

@Eilon:

El problema con las propiedades es que a muchas personas les parece


que se puede aplicar a cualquier propiedad de cualquier objeto.

De acuerdo, hemos tenido una serie de problemas publicados por los usuarios con
confusión acerca de cómo se debe utilizar esta función. Realmente ha habido una
gran cantidad de comentarios de ambos tipos "[FromServices] es raro y no me gusta"
y "[FromServices] me ha confundido". Se siente como una trampa, y algo que el
equipo todavía estaría respondiendo a las preguntas en los próximos años.

Creemos que el escenario más valioso para [FromServices] es el parámetro del


método para una acción para un servicio que solo necesita en ese lugar.

/ cc @ danroth27 - docs cambios

A cualquier persona enamorada del [FromServices] actual, le recomiendo


encarecidamente que busque un sistema DI que pueda inyectar propiedades (por
ejemplo, Autofac).

Notas:

• Cualquier servicio registrado con .NET Core Dependency Injection se puede inyectar dentro
de la acción de un controlador usando el atributo [FromServices] .

• El caso más relevante es cuando necesita un servicio solo en un método de acción simple y
no desea saturar el constructor de su controlador con otra dependencia, que solo se usará
una vez.

• No se puede utilizar fuera de ASP.NET Core MVC (es decir, aplicaciones puras de .NET
Framework o .NET Core consola), ya que reside en Microsoft.AspNetCore.Mvc.Core
ensamblado de Microsoft.AspNetCore.Mvc.Core .

• Para la inyección de propiedad o método, debe utilizar uno de los contenedores de IoC de
terceros disponibles (Autofac, Unity, etc.).

El patrón de opciones / opciones de inyección en servicios

Con ASP.NET Core, el equipo de Microsoft también introdujo el patrón de Opciones, que permite
tener opciones tipificadas y una vez configurada la capacidad de inyectar las opciones en sus
servicios.

Primero comenzamos con una clase fuerte, que mantendrá nuestra configuración.

public class MySettings


{
public string Value1 { get; set; }
public string Value2 { get; set; }

https://riptutorial.com/es/home 81
}

Y una entrada en el appsettings.json .

{
"mysettings" : {
"value1": "Hello",
"value2": "World"
}
}

A continuación lo inicializamos en la clase de inicio. Hay dos maneras de hacer esto

1. appsettings.json directamente desde la appsettings.json "mysettings" de appsettings.json

services.Configure<MySettings>(Configuration.GetSection("mysettings"));

2. Hacerlo manualmente

services.Configure<MySettings>(new MySettings
{
Value1 = "Hello",
Value2 = Configuration["mysettings:value2"]
});

Cada nivel de jerarquía de appsettings.json está separado por : Dado que value2 es una
propiedad del objeto mysettings , accedemos a él a través de mysettings:value2 .

Finalmente, podemos insertar las opciones en nuestros servicios, usando la IOptions<T>

public class MyService : IMyService


{
private readonly MySettings settings;

public MyService(IOptions<MySettings> mysettings)


{
this.settings = mySettings.Value;
}
}

Observaciones
Si las IOptions<T> no están configuradas durante el inicio, inyectar IOptions<T> inyectará la
instancia predeterminada de la clase T

Uso de servicios de ámbito durante el inicio de la aplicación / Secuencias de


base de datos

Resolver los servicios de ámbito durante el inicio de la aplicación puede ser difícil, ya que no hay

https://riptutorial.com/es/home 82
solicitud y, por lo tanto, no hay servicio de ámbito.

Resolver un servicio con ámbito durante el inicio de la aplicación a través de


app.ApplicationServices.GetService<AppDbContext>() puede causar problemas, ya que se creará en
el ámbito del contenedor global, lo que lo convierte en un singleton con la vida útil de la
aplicación, lo que puede llevar a excepciones como Cannot access a disposed object in ASP.NET
Core when injecting DbContext .

El siguiente patrón resuelve el problema creando primero un nuevo alcance y luego resolviendo
los servicios con ámbito desde él, luego, una vez que se realiza el trabajo, se desecha el
contenedor con ámbito.

public Configure(IApplicationBuilder app)


{
// serviceProvider is app.ApplicationServices from Configure(IApplicationBuilder app)
method
using (var serviceScope =
app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var db = serviceScope.ServiceProvider.GetService<AppDbContext>();

if (await db.Database.EnsureCreatedAsync())
{
await SeedDatabase(db);
}
}
}

Esta es una forma semioficial del equipo central de Entity Framework para generar datos durante
el inicio de la aplicación y se refleja en la aplicación de ejemplo MusicStore .

Resolver controladores, ViewComponents y TagHelpers mediante inyección


de dependencia

Por defecto, los controladores, ViewComponents y TagHelpers no se registran y resuelven a


través del contenedor de inyección de dependencias. Esto resulta en la incapacidad de hacer, por
ejemplo, la inyección de propiedades cuando se utiliza un contenedor de Inversión de Control
(IoC) de terceros como AutoFac.

Para que ASP.NET Core MVC resuelva estos tipos también a través de IoC, es necesario agregar
los siguientes registros en Startup.cs (tomado de la muestra oficial ControllersFromService en
GitHub)

public void ConfigureServices(IServiceCollection services)


{
var builder = services
.AddMvc()
.ConfigureApplicationPartManager(manager => manager.ApplicationParts.Clear())
.AddApplicationPart(typeof(TimeScheduleController).GetTypeInfo().Assembly)
.ConfigureApplicationPartManager(manager =>
{
manager.ApplicationParts.Add(new TypesPart(
typeof(AnotherController),

https://riptutorial.com/es/home 83
typeof(ComponentFromServicesViewComponent),
typeof(InServicesTagHelper)));

manager.FeatureProviders.Add(new AssemblyMetadataReferenceFeatureProvider());
})
.AddControllersAsServices()
.AddViewComponentsAsServices()
.AddTagHelpersAsServices();

services.AddTransient<QueryValueService>();
services.AddTransient<ValueService>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

Ejemplo de inyección de dependencia simple (sin Startup.cs)

Esto le muestra cómo usar el paquete de nuget Microsoft.Extensions.DependencyInjection sin el


uso del WebHostBuilder de WebHostBuilder (por ejemplo, cuando desea construir algo más que una
aplicación web):

internal class Program


{
public static void Main(string[] args)
{
var services = new ServiceCollection(); //Creates the service registry
services.AddTransient<IMyInterface, MyClass>(); //Add registration of IMyInterface
(should create an new instance of MyClass every time)
var serviceProvider = services.BuildServiceProvider(); //Build dependencies into an
IOC container
var implementation = serviceProvider.GetService<IMyInterface>(); //Gets a dependency

//serviceProvider.GetService<ServiceDependingOnIMyInterface>(); //Would throw an error


since ServiceDependingOnIMyInterface is not registered
var manualyInstaniate = new ServiceDependingOnIMyInterface(implementation);

services.AddTransient<ServiceDependingOnIMyInterface>();
var spWithService = services.BuildServiceProvider(); //Generaly its bad practise to
rebuild the container because its heavey and promotes use of anti-pattern.
spWithService.GetService<ServiceDependingOnIMyInterface>(); //only now i can resolve
}
}

interface IMyInterface
{
}

class MyClass : IMyInterface


{
}

class ServiceDependingOnIMyInterface
{
private readonly IMyInterface _dependency;

public ServiceDependingOnIMyInterface(IMyInterface dependency)


{
_dependency = dependency;
}

https://riptutorial.com/es/home 84
}

Funcionamiento interno de Microsoft.Extensions.DependencyInjection

IServiceCollection
Para comenzar a construir un contenedor IOC con el paquete de nuget DI de Microsoft, comience
con la creación de una IServiceCollection . Puedes usar la colección ya provista:
ServiceCollection :

var services = new ServiceCollection();

Este IServiceCollection no es más que una implementación de: IList<ServiceDescriptor>,


ICollection<ServiceDescriptor>, IEnumerable<ServiceDescriptor>, IEnumerable

Todos los métodos siguientes son solo métodos de extensión para agregar instancias de
ServiceDescriptor a la lista:

services.AddTransient<Class>(); //add registration that is always recreated


services.AddSingleton<Class>(); // add registration that is only created once and then re-used
services.AddTransient<Abstract, Implementation>(); //specify implementation for interface
services.AddTransient<Interface>(serviceProvider=> new
Class(serviceProvider.GetService<IDependency>())); //specify your own resolve function/
factory method.
services.AddMvc(); //extension method by the MVC nuget package, to add a whole bunch of
registrations.
// etc..

//when not using an extension method:


services.Add(new ServiceDescriptor(typeof(Interface), typeof(Class)));

IServiceProvider
El proveedor de servicios es el que 'compila' todos los registros para que puedan usarse
rápidamente, esto se puede hacer con services.BuildServiceProvider() que es básicamente una
extensión de mehtod para:

var provider = new ServiceProvider( services, false); //false is if it should validate scopes

Tras bambalinas, cada ServiceDescriptor en IServiceCollection se compila a un método de fábrica


Func<ServiceProvider, object> donde object es el tipo de retorno y es: la instancia creada del tipo
de implementación, el Singleton o su propio método de fábrica definido.

Estos registros se agregan a ServiceTable que es básicamente un ConcurrentDictionary con la


clave que es ServiceType y el valor del método de fábrica definido anteriormente.

https://riptutorial.com/es/home 85
Resultado
Ahora tenemos un ConcurrentDictionary<Type, Func<ServiceProvider, object>> que podemos usar
al mismo tiempo para solicitar la creación de Servicios para nosotros. Para mostrar un ejemplo
básico de cómo podría haberse visto esto.

var serviceProvider = new ConcurrentDictionary<Type, Func<ServiceProvider, object>>();


var factoryMethod = serviceProvider[typeof(MyService)];
var myServiceInstance = factoryMethod(serviceProvider)

¡Asi no es como funciona esto!

Este ConcurrentDictionary es una propiedad de ServiceTable que es una propiedad de


ServiceProvider

Lea Inyección de dependencia en línea: https://riptutorial.com/es/asp-net-


core/topic/1949/inyeccion-de-dependencia

https://riptutorial.com/es/home 86
Capítulo 14: Inyectando servicios en vistas.
Sintaxis
• @inject<NameOfService><Identifier>
• @<Identifier>.Foo()
• @inyectar <tipo> <nombre>

Examples
La directiva @inject

ASP.NET Core introduce el concepto de inyección de dependencia en vistas a través de la


directiva @inject través de la siguiente sintaxis:

@inject <type> <name>

Ejemplo de uso
Agregar esta directiva a su Vista básicamente generará una propiedad del tipo dado usando el
nombre dado dentro de su Vista usando la inyección de dependencia adecuada, como se muestra
en el siguiente ejemplo:

@inject YourWidgetServiceClass WidgetService

<!-- This would call the service, which is already populated and output the results -->
There are <b>@WidgetService.GetWidgetCount()</b> Widgets here.

Configuración requerida
Los servicios que utilizan la inyección de dependencia aún deben registrarse dentro del método
ConfigureServices() del archivo Startup.cs y deben tener el alcance correspondiente:

public void ConfigureServices(IServiceCollection services)


{
// Other stuff omitted for brevity

services.AddTransient<IWidgetService, WidgetService>();
}

Lea Inyectando servicios en vistas. en línea: https://riptutorial.com/es/asp-net-


core/topic/4284/inyectando-servicios-en-vistas-

https://riptutorial.com/es/home 87
Capítulo 15: Límite de velocidad
Observaciones
AspNetCoreRateLimit es una solución de código abierto de ASP.NET Core limitadora de la
velocidad diseñada para controlar la tasa de solicitudes que los clientes pueden hacer a una
aplicación de API o MVC web basada en la dirección IP o la identificación del cliente.

Examples
Limitación de tarifas basada en la IP del cliente

Con el middleware IpRateLimit puede establecer múltiples límites para diferentes escenarios,
como permitir que un IP o rango de IP realice un número máximo de llamadas en un intervalo de
tiempo como por segundo, 15 minutos, etc. Puede definir estos límites para abordar todas las
solicitudes realizadas a un API o puede extender los límites a cada ruta URL o verbo y ruta HTTP.

Preparar

Instalación de NuGet :

Install-Package AspNetCoreRateLimit

Código de inicio.cs :

public void ConfigureServices(IServiceCollection services)


{
// needed to load configuration from appsettings.json
services.AddOptions();

// needed to store rate limit counters and ip rules


services.AddMemoryCache();

//load general configuration from appsettings.json


services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));

//load ip rules from appsettings.json


services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));

// inject counter and rules stores


services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();

// Add framework services.


services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory


loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));

https://riptutorial.com/es/home 88
loggerFactory.AddDebug();

app.UseIpRateLimiting();

app.UseMvc();
}

Debe registrar el middleware antes que cualquier otro componente, excepto loggerFactory.

si carga el saldo de su aplicación, deberá usar IDistributedCache con Redis o SQLServer para que
todas las instancias de kestrel tengan el mismo almacén de límite de velocidad. En lugar de en las
tiendas de memoria, debe inyectar las tiendas distribuidas de esta manera:

// inject counter and rules distributed cache stores


services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();

Configuración y reglas generales appsettings.json :

"IpRateLimiting": {
"EnableEndpointRateLimiting": false,
"StackBlockedRequests": false,
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ],
"EndpointWhitelist": [ "get:/api/license", "*:/api/status" ],
"ClientWhitelist": [ "dev-id-1", "dev-id-2" ],
"GeneralRules": [
{
"Endpoint": "*",
"Period": "1s",
"Limit": 2
},
{
"Endpoint": "*",
"Period": "15m",
"Limit": 100
},
{
"Endpoint": "*",
"Period": "12h",
"Limit": 1000
},
{
"Endpoint": "*",
"Period": "7d",
"Limit": 10000
}
]
}

Si EnableEndpointRateLimiting se establece en false , los límites se aplicarán globalmente y solo se


aplicarán las reglas que tengan como punto final * . Por ejemplo, si establece un límite de 5
llamadas por segundo, cualquier llamada HTTP a cualquier punto final contará hacia ese límite.

https://riptutorial.com/es/home 89
Si EnableEndpointRateLimiting se establece en true , los límites se aplicarán a cada punto final
como en {HTTP_Verb}{PATH} . Por ejemplo, si establece un límite de 5 llamadas por segundo para
*:/api/values un cliente puede llamar a GET /api/values 5 veces por segundo, pero también 5
veces PUT /api/values .

Si StackBlockedRequests está configurado como false llamadas rechazadas no se agregan al


contador del acelerador. Si un cliente hace 3 solicitudes por segundo y ha establecido un límite de
una llamada por segundo, otros límites como los contadores por minuto o por día solo registrarán
la primera llamada, la que no se bloqueó. Si desea que las solicitudes rechazadas cuenten hacia
los otros límites, tendrá que establecer StackBlockedRequests en true .

RealIpHeader se usa para extraer la IP del cliente cuando su servidor Kestrel está detrás de un
proxy inverso, si su proxy usa un encabezado diferente, entonces X-Real-IP usa esta opción para
configurarlo.

ClientIdHeader se utiliza para extraer el ID de cliente para la lista blanca, si un ID de cliente está
presente en este encabezado y coincide con un valor especificado en ClientWhitelist, entonces no
se aplican límites de tasa.

Reemplace las reglas generales para IPs específicas appsettings.json :

"IpRateLimitPolicies": {
"IpRules": [
{
"Ip": "84.247.85.224",
"Rules": [
{
"Endpoint": "*",
"Period": "1s",
"Limit": 10
},
{
"Endpoint": "*",
"Period": "15m",
"Limit": 200
}
]
},
{
"Ip": "192.168.3.22/25",
"Rules": [
{
"Endpoint": "*",
"Period": "1s",
"Limit": 5
},
{
"Endpoint": "*",
"Period": "15m",
"Limit": 150
},
{
"Endpoint": "*",
"Period": "12h",
"Limit": 500
}

https://riptutorial.com/es/home 90
]
}
]
}

El campo IP admite valores de IP v4 y v6 y rangos como "192.168.0.0/24", "fe80 :: / 10" o


"192.168.0.0-192.168.0.255".

Definir reglas de límite de velocidad.

Una regla se compone de un punto final, un período y un límite.

El formato del punto final es {HTTP_Verb}:{PATH} , puede apuntar a cualquier verbo HTTP usando el
símbolo de asterisco.

El formato del período es {INT}{PERIOD_TYPE} , puede usar uno de los siguientes tipos de período:
s, m, h, d .

El formato límite es {LONG} .

Ejemplos :

Límite de velocidad de todos los puntos finales a 2 llamadas por segundo:

{
"Endpoint": "*",
"Period": "1s",
"Limit": 2
}

Si, desde la misma IP, en el mismo segundo, hará 3 llamadas GET a api / valores, la última
llamada se bloqueará. Pero si en el mismo segundo también llama PUT api / valores, la solicitud
se procesará porque es un punto final diferente. Cuando se habilita la limitación de la velocidad
del punto final, cada llamada está limitada en función de {HTTP_Verb}{PATH} .

Limite las llamadas con cualquier verbo HTTP a /api/values a 5 llamadas por 15 minutos:

{
"Endpoint": "*:/api/values",
"Period": "15m",
"Limit": 5
}

Límite de velocidad GET llamada a /api/values a 5 llamadas por hora:

{
"Endpoint": "get:/api/values",
"Period": "1h",
"Limit": 5
}

https://riptutorial.com/es/home 91
Si, desde la misma IP, en una hora, hará 6 llamadas GET a api / valores, la última llamada se
bloqueará. Pero si en la misma hora también llama a GET api / values / 1, la solicitud se realizará
porque es un punto final diferente.

Comportamiento

Cuando un cliente realiza una llamada HTTP, IpRateLimitMiddleware hace lo siguiente:

• extrae la IP, el ID del cliente, el verbo HTTP y la URL del objeto de solicitud; si desea
implementar su propia lógica de extracción, puede anular IpRateLimitMiddleware.SetIdentity
• busca la IP, el ID del cliente y la URL en las listas blancas, si hay alguna coincidencia, no se
realiza ninguna acción
• busca en las reglas de IP para una coincidencia, todas las reglas que aplican se agrupan
por período, para cada período se usa la regla más restrictiva
• busca en las reglas generales una coincidencia, si una regla general que coincide tiene un
período definido que no está presente en las reglas de IP, esta regla general también se usa
• para cada regla coincidente, el contador del límite de la tasa se incrementa, si el valor del
contador es mayor que el límite de la regla, la solicitud se bloquea

Si la solicitud se bloquea, el cliente recibe una respuesta de texto como esta:

Status Code: 429


Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.

Puede personalizar la respuesta cambiando estas opciones HttpStatusCode y QuotaExceededMessage


. Si desea implementar su propia respuesta, puede anular
IpRateLimitMiddleware.ReturnQuotaExceededResponse . El valor del encabezado Retry-After se
expresa en segundos.

Si la solicitud no obtiene una tasa limitada, el período más largo definido en las reglas de
coincidencia se usa para componer los encabezados de X-Rate-Limit, estos encabezados se
inyectan en la respuesta:

X-Rate-Limit-Limit: the rate limit period (eg. 1m, 12h, 1d)


X-Rate-Limit-Remaining: number of request remaining
X-Rate-Limit-Reset: UTC date time when the limits resets

De forma predeterminada, las solicitudes bloqueadas se registran con


Microsoft.Extensions.Logging.ILogger . Si desea implementar su propio registro, puede anular
IpRateLimitMiddleware.LogBlockedRequest . El registrador predeterminado emite la siguiente
información cuando una solicitud obtiene una tasa limitada:

info: AspNetCoreRateLimit.IpRateLimitMiddleware[0]
Request get:/api/values from IP 84.247.85.224 has been blocked, quota 2/1m exceeded by
3. Blocked by rule *:/api/value, TraceIdentifier 0HKTLISQQVV9D.

Actualizar los límites de la tasa en tiempo de ejecución

https://riptutorial.com/es/home 92
Al inicio de la aplicación, las reglas de límite de velocidad de IP definidas en appsettings.json se
cargan en la memoria caché por MemoryCacheClientPolicyStore o DistributedCacheIpPolicyStore
dependiendo del tipo de proveedor de memoria caché que esté utilizando. Puede acceder al
almacén de políticas de IP dentro de un controlador y modificar las reglas de IP de la siguiente
manera:

public class IpRateLimitController : Controller


{
private readonly IpRateLimitOptions _options;
private readonly IIpPolicyStore _ipPolicyStore;

public IpRateLimitController(IOptions<IpRateLimitOptions> optionsAccessor, IIpPolicyStore


ipPolicyStore)
{
_options = optionsAccessor.Value;
_ipPolicyStore = ipPolicyStore;
}

[HttpGet]
public IpRateLimitPolicies Get()
{
return _ipPolicyStore.Get(_options.IpPolicyPrefix);
}

[HttpPost]
public void Post()
{
var pol = _ipPolicyStore.Get(_options.IpPolicyPrefix);

pol.IpRules.Add(new IpRateLimitPolicy
{
Ip = "8.8.4.4",
Rules = new List<RateLimitRule>(new RateLimitRule[] {
new RateLimitRule {
Endpoint = "*:/api/testupdate",
Limit = 100,
Period = "1d" }
})
});

_ipPolicyStore.Set(_options.IpPolicyPrefix, pol);
}
}

De esta manera, puede almacenar los límites de velocidad de IP en una base de datos y
empujarlos en el caché después de que se inicie cada aplicación.

Limitación de tarifas basada en la identificación del cliente

Con el middleware ClientRateLimit puede establecer múltiples límites para diferentes escenarios,
como permitir que un Cliente realice un número máximo de llamadas en un intervalo de tiempo
como por segundo, 15 minutos, etc. Puede definir estos límites para abordar todas las solicitudes
realizadas a una API o puede abarcar los límites de cada ruta URL o verbo y ruta HTTP.

Preparar

https://riptutorial.com/es/home 93
Instalación de NuGet :

Install-Package AspNetCoreRateLimit

Código de inicio.cs :

public void ConfigureServices(IServiceCollection services)


{
// needed to load configuration from appsettings.json
services.AddOptions();

// needed to store rate limit counters and ip rules


services.AddMemoryCache();

//load general configuration from appsettings.json

services.Configure<ClientRateLimitOptions>(Configuration.GetSection("ClientRateLimiting"));

//load client rules from appsettings.json

services.Configure<ClientRateLimitPolicies>(Configuration.GetSection("ClientRateLimitPolicies"));

// inject counter and rules stores


services.AddSingleton<IClientPolicyStore, MemoryCacheClientPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();

// Add framework services.


services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory


loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();

app.UseClientRateLimiting();

app.UseMvc();
}

Debe registrar el middleware antes que cualquier otro componente, excepto loggerFactory.

si carga el saldo de su aplicación, deberá usar IDistributedCache con Redis o SQLServer para que
todas las instancias de kestrel tengan el mismo almacén de límite de velocidad. En lugar de en las
tiendas de memoria, debe inyectar las tiendas distribuidas de esta manera:

// inject counter and rules distributed cache stores


services.AddSingleton<IClientPolicyStore, DistributedCacheClientPolicyStore>();
services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();

Configuración y reglas generales appsettings.json :

"ClientRateLimiting": {
"EnableEndpointRateLimiting": false,
"StackBlockedRequests": false,

https://riptutorial.com/es/home 94
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"EndpointWhitelist": [ "get:/api/license", "*:/api/status" ],
"ClientWhitelist": [ "dev-id-1", "dev-id-2" ],
"GeneralRules": [
{
"Endpoint": "*",
"Period": "1s",
"Limit": 2
},
{
"Endpoint": "*",
"Period": "15m",
"Limit": 100
},
{
"Endpoint": "*",
"Period": "12h",
"Limit": 1000
},
{
"Endpoint": "*",
"Period": "7d",
"Limit": 10000
}
]
}

Si EnableEndpointRateLimiting se establece en false , los límites se aplicarán globalmente y solo se


aplicarán las reglas que tengan como punto final * . Por ejemplo, si establece un límite de 5
llamadas por segundo, cualquier llamada HTTP a cualquier punto final contará hacia ese límite.

Si EnableEndpointRateLimiting se establece en true , los límites se aplicarán a cada punto final


como en {HTTP_Verb}{PATH} . Por ejemplo, si establece un límite de 5 llamadas por segundo para
*:/api/values un cliente puede llamar a GET /api/values 5 veces por segundo, pero también 5
veces PUT /api/values .

Si StackBlockedRequests está configurado como false llamadas rechazadas no se agregan al


contador del acelerador. Si un cliente hace 3 solicitudes por segundo y ha establecido un límite de
una llamada por segundo, otros límites como los contadores por minuto o por día solo registrarán
la primera llamada, la que no se bloqueó. Si desea que las solicitudes rechazadas cuenten hacia
los otros límites, tendrá que establecer StackBlockedRequests en true .

El ClientIdHeader se usa para extraer el ID de cliente, si un ID de cliente está presente en este


encabezado y coincide con un valor especificado en ClientWhitelist, entonces no se aplican
límites de tasa.

Reemplace las reglas generales para clientes específicos appsettings.json :

"ClientRateLimitPolicies": {
"ClientRules": [
{
"ClientId": "client-id-1",
"Rules": [
{

https://riptutorial.com/es/home 95
"Endpoint": "*",
"Period": "1s",
"Limit": 10
},
{
"Endpoint": "*",
"Period": "15m",
"Limit": 200
}
]
},
{
"Client": "client-id-2",
"Rules": [
{
"Endpoint": "*",
"Period": "1s",
"Limit": 5
},
{
"Endpoint": "*",
"Period": "15m",
"Limit": 150
},
{
"Endpoint": "*",
"Period": "12h",
"Limit": 500
}
]
}
]
}

Definir reglas de límite de velocidad.

Una regla se compone de un punto final, un período y un límite.

El formato del punto final es {HTTP_Verb}:{PATH} , puede apuntar a cualquier verbo HTTP usando el
símbolo de asterisco.

El formato del período es {INT}{PERIOD_TYPE} , puede usar uno de los siguientes tipos de período:
s, m, h, d .

El formato límite es {LONG} .

Ejemplos :

Límite de velocidad de todos los puntos finales a 2 llamadas por segundo:

{
"Endpoint": "*",
"Period": "1s",
"Limit": 2
}

https://riptutorial.com/es/home 96
Si en el mismo segundo, un cliente realiza 3 llamadas GET a api / valores, la última llamada se
bloqueará. Pero si en el mismo segundo también llama PUT api / valores, la solicitud se realizará
porque es un punto final diferente. Cuando se habilita la limitación de la velocidad del punto final,
cada llamada está limitada en función de {HTTP_Verb}{PATH} .

Limite las llamadas con cualquier verbo HTTP a /api/values a 5 llamadas por 15 minutos:

{
"Endpoint": "*:/api/values",
"Period": "15m",
"Limit": 5
}

Límite de velocidad GET llamada a /api/values a 5 llamadas por hora:

{
"Endpoint": "get:/api/values",
"Period": "1h",
"Limit": 5
}

Si en una hora, un cliente realiza 6 llamadas GET a api / valores, la última llamada se bloqueará.
Pero si en la misma hora también llama a GET api / values / 1, la solicitud se realizará porque es
un punto final diferente.

Comportamiento

Cuando un cliente realiza una llamada HTTP, ClientRateLimitMiddleware hace lo siguiente:

• extrae el ID del cliente, el verbo HTTP y la URL del objeto de solicitud. Si desea
implementar su propia lógica de extracción, puede anular el
ClientRateLimitMiddleware.SetIdentity
• busca el ID del cliente y la URL en las listas blancas, si hay alguna coincidencia, no se
realiza ninguna acción
• busca en las reglas del Cliente una coincidencia, todas las reglas que aplican se agrupan
por período, para cada período se usa la regla más restrictiva
• busca en las reglas generales una coincidencia, si una regla general que coincida tiene un
período definido que no está presente en las reglas del cliente, esta regla general también
se usa
• para cada regla coincidente, el contador del límite de la tasa se incrementa, si el valor del
contador es mayor que el límite de la regla, la solicitud se bloquea

Si la solicitud se bloquea, el cliente recibe una respuesta de texto como esta:

Status Code: 429


Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.

Puede personalizar la respuesta cambiando estas opciones HttpStatusCode y QuotaExceededMessage


. Si desea implementar su propia respuesta, puede anular el

https://riptutorial.com/es/home 97
ClientRateLimitMiddleware.ReturnQuotaExceededResponse . El valor del encabezado Retry-After se
expresa en segundos.

Si la solicitud no obtiene una tasa limitada, el período más largo definido en las reglas de
coincidencia se usa para componer los encabezados de X-Rate-Limit, estos encabezados se
inyectan en la respuesta:

X-Rate-Limit-Limit: the rate limit period (eg. 1m, 12h, 1d)


X-Rate-Limit-Remaining: number of request remaining
X-Rate-Limit-Reset: UTC date time when the limits resets

De forma predeterminada, las solicitudes bloqueadas se registran con


Microsoft.Extensions.Logging.ILogger . Si desea implementar su propio registro, puede anular el
ClientRateLimitMiddleware.LogBlockedRequest . El registrador predeterminado emite la siguiente
información cuando una solicitud obtiene una tasa limitada:

info: AspNetCoreRateLimit.ClientRateLimitMiddleware[0]
Request get:/api/values from ClientId client-id-1 has been blocked, quota 2/1m exceeded
by 3. Blocked by rule *:/api/value, TraceIdentifier 0HKTLISQQVV9D.

Actualizar los límites de la tasa en tiempo de ejecución

Al inicio de la aplicación, las reglas de límite de frecuencia del cliente definidas en


appsettings.json se cargan en la memoria caché por MemoryCacheClientPolicyStore o
DistributedCacheClientPolicyStore dependiendo del tipo de proveedor de memoria caché que esté
utilizando. Puede acceder al almacén de políticas del cliente dentro de un controlador y modificar
las reglas así:

public class ClientRateLimitController : Controller


{
private readonly ClientRateLimitOptions _options;
private readonly IClientPolicyStore _clientPolicyStore;

public ClientRateLimitController(IOptions<ClientRateLimitOptions> optionsAccessor,


IClientPolicyStore clientPolicyStore)
{
_options = optionsAccessor.Value;
_clientPolicyStore = clientPolicyStore;
}

[HttpGet]
public ClientRateLimitPolicy Get()
{
return _clientPolicyStore.Get($"{_options.ClientPolicyPrefix}_cl-key-1");
}

[HttpPost]
public void Post()
{
var id = $"{_options.ClientPolicyPrefix}_cl-key-1";
var clPolicy = _clientPolicyStore.Get(id);
clPolicy.Rules.Add(new RateLimitRule
{

https://riptutorial.com/es/home 98
Endpoint = "*/api/testpolicyupdate",
Period = "1h",
Limit = 100
});
_clientPolicyStore.Set(id, clPolicy);
}
}

De esta manera, puede almacenar los límites de velocidad de los clientes en una base de datos y
empujarlos en el caché después de que se inicie cada aplicación.

Lea Límite de velocidad en línea: https://riptutorial.com/es/asp-net-core/topic/5240/limite-de-


velocidad

https://riptutorial.com/es/home 99
Capítulo 16: Localización
Examples
Localización utilizando recursos de lenguaje JSON

En ASP.NET Core hay varias maneras diferentes en que podemos localizar / globalizar nuestra
aplicación. Es importante elegir una manera que se adapte a sus necesidades. En este ejemplo,
verá cómo podemos crear una aplicación de ASP.NET Core multilingüe que lea cadenas
específicas del .json archivos .json y almacenarlas en la memoria para proporcionar localización
en todas las secciones de la aplicación, así como mantener un alto rendimiento.

La forma en que lo hacemos es mediante el uso del paquete


Microsoft.EntityFrameworkCore.InMemory .

Notas:

1. El espacio de nombres para este proyecto es DigitalShop que puede cambiar al espacio de
nombres propio de sus proyectos.
2. Considera crear un nuevo proyecto para que no te encuentres con errores extraños
3. De ninguna manera este ejemplo muestra las mejores prácticas, así que si cree que puede
mejorarse, por favor edítelo.

Para comenzar, agreguemos los siguientes paquetes a la sección de dependencies existentes en


el archivo project.json :

"Microsoft.EntityFrameworkCore": "1.0.0",
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
"Microsoft.EntityFrameworkCore.InMemory": "1.0.0"

Ahora reemplacemos el archivo Startup.cs con: ( using declaraciones se eliminan, ya que se


pueden agregar fácilmente más adelante)

Startup.cs

namespace DigitalShop
{
public class Startup
{
public static string UiCulture;
public static string CultureDirection;
public static IStringLocalizer _e; // This is how we access language strings

public static IConfiguration LocalConfig;

public Startup(IHostingEnvironment env)


{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) //

https://riptutorial.com/es/home 100
this is where we store apps configuration including language
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();

Configuration = builder.Build();
LocalConfig = Configuration;
}

public IConfigurationRoot 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().AddViewLocalization().AddDataAnnotationsLocalization();

// IoC Container
// Add application services.
services.AddTransient<EFStringLocalizerFactory>();
services.AddSingleton<IConfiguration>(Configuration);
}

// This method gets called by the runtime. Use this method to configure the HTTP
request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory
loggerFactory, EFStringLocalizerFactory localizerFactory)
{
_e = localizerFactory.Create(null);

// a list of all available languages


var supportedCultures = new List<CultureInfo>
{
new CultureInfo("en-US"),
new CultureInfo("fa-IR")
};

var requestLocalizationOptions = new RequestLocalizationOptions


{
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures,
};
requestLocalizationOptions.RequestCultureProviders.Insert(0, new
JsonRequestCultureProvider());
app.UseRequestLocalization(requestLocalizationOptions);

app.UseStaticFiles();

app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}

public class JsonRequestCultureProvider : RequestCultureProvider


{
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext
httpContext)
{

https://riptutorial.com/es/home 101
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}

var config = Startup.LocalConfig;

string culture = config["AppOptions:Culture"];


string uiCulture = config["AppOptions:UICulture"];
string culturedirection = config["AppOptions:CultureDirection"];

culture = culture ?? "fa-IR"; // Use the value defined in config files or the
default value
uiCulture = uiCulture ?? culture;

Startup.UiCulture = uiCulture;

culturedirection = culturedirection ?? "rlt"; // rtl is set to be the default


value in case culturedirection is null
Startup.CultureDirection = culturedirection;

return Task.FromResult(new ProviderCultureResult(culture, uiCulture));


}
}
}

En el código anterior, primero agregamos tres variables public static campo public static que
luego inicializaremos usando los valores leídos en el archivo de configuración.

En el constructor para la clase de Startup , agregamos un archivo de configuración json a la


variable del builder . El primer archivo es necesario para que la aplicación funcione, así que
adelante, cree appsettings.json en la raíz de su proyecto si aún no existe. Usando Visual Studio
2015, este archivo se crea automáticamente, así que solo cambie su contenido a: (Si no lo usa,
puede omitir la sección de Logging )

appsettings.json

{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"AppOptions": {
"Culture": "en-US", // fa-IR for Persian
"UICulture": "en-US", // same as above
"CultureDirection": "ltr" // rtl for Persian/Arabic/Hebrew
}
}

En el futuro, crea tres carpetas en la raíz de tu proyecto:

Models , Services e Languages . En la carpeta Models cree otra carpeta llamada Localization .

https://riptutorial.com/es/home 102
En la carpeta Services , creamos un nuevo archivo .cs llamado EFLocalization . El contenido sería:
(Nuevamente using declaraciones no se incluyen)

EFLocalization.cs

namespace DigitalShop.Services
{
public class EFStringLocalizerFactory : IStringLocalizerFactory
{
private readonly LocalizationDbContext _db;

public EFStringLocalizerFactory()
{
_db = new LocalizationDbContext();
// Here we define all available languages to the app
// available languages are those that have a json and cs file in
// the Languages folder
_db.AddRange(
new Culture
{
Name = "en-US",
Resources = en_US.GetList()
},
new Culture
{
Name = "fa-IR",
Resources = fa_IR.GetList()
}
);
_db.SaveChanges();
}

public IStringLocalizer Create(Type resourceSource)


{
return new EFStringLocalizer(_db);
}

public IStringLocalizer Create(string baseName, string location)


{
return new EFStringLocalizer(_db);
}
}

public class EFStringLocalizer : IStringLocalizer


{
private readonly LocalizationDbContext _db;

public EFStringLocalizer(LocalizationDbContext db)


{
_db = db;
}

public LocalizedString this[string name]


{
get
{
var value = GetString(name);
return new LocalizedString(name, value ?? name, resourceNotFound: value ==
null);
}

https://riptutorial.com/es/home 103
}

public LocalizedString this[string name, params object[] arguments]


{
get
{
var format = GetString(name);
var value = string.Format(format ?? name, arguments);
return new LocalizedString(name, value, resourceNotFound: format == null);
}
}

public IStringLocalizer WithCulture(CultureInfo culture)


{
CultureInfo.DefaultThreadCurrentCulture = culture;
return new EFStringLocalizer(_db);
}

public IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures)


{
return _db.Resources
.Include(r => r.Culture)
.Where(r => r.Culture.Name == CultureInfo.CurrentCulture.Name)
.Select(r => new LocalizedString(r.Key, r.Value, true));
}

private string GetString(string name)


{
return _db.Resources
.Include(r => r.Culture)
.Where(r => r.Culture.Name == CultureInfo.CurrentCulture.Name)
.FirstOrDefault(r => r.Key == name)?.Value;
}
}

public class EFStringLocalizer<T> : IStringLocalizer<T>


{
private readonly LocalizationDbContext _db;

public EFStringLocalizer(LocalizationDbContext db)


{
_db = db;
}

public LocalizedString this[string name]


{
get
{
var value = GetString(name);
return new LocalizedString(name, value ?? name, resourceNotFound: value ==
null);
}
}

public LocalizedString this[string name, params object[] arguments]


{
get
{
var format = GetString(name);
var value = string.Format(format ?? name, arguments);
return new LocalizedString(name, value, resourceNotFound: format == null);

https://riptutorial.com/es/home 104
}
}

public IStringLocalizer WithCulture(CultureInfo culture)


{
CultureInfo.DefaultThreadCurrentCulture = culture;
return new EFStringLocalizer(_db);
}

public IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures)


{
return _db.Resources
.Include(r => r.Culture)
.Where(r => r.Culture.Name == CultureInfo.CurrentCulture.Name)
.Select(r => new LocalizedString(r.Key, r.Value, true));
}

private string GetString(string name)


{
return _db.Resources
.Include(r => r.Culture)
.Where(r => r.Culture.Name == CultureInfo.CurrentCulture.Name)
.FirstOrDefault(r => r.Key == name)?.Value;
}
}
}

En el archivo anterior implementamos la interfaz IStringLocalizerFactory desde Entity Framework


Core para poder crear un servicio de localizador personalizado. La parte importante es el
constructor de EFStringLocalizerFactory donde hacemos una lista de todos los idiomas disponibles
y lo agregamos al contexto de la base de datos. Cada uno de estos archivos de idioma actúa
como una base de datos separada.

Ahora agregue cada uno de los siguientes archivos a la carpeta Models/Localization :

Cultura.cs

namespace DigitalShop.Models.Localization
{
public class Culture
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Resource> Resources { get; set; }
}
}

Resource.cs

namespace DigitalShop.Models.Localization
{
public class Resource
{
public int Id { get; set; }
public string Key { get; set; }
public string Value { get; set; }
public virtual Culture Culture { get; set; }

https://riptutorial.com/es/home 105
}
}

LocalizationDbContext.cs

namespace DigitalShop.Models.Localization
{
public class LocalizationDbContext : DbContext
{
public DbSet<Culture> Cultures { get; set; }
public DbSet<Resource> Resources { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)


{
optionsBuilder.UseInMemoryDatabase();
}
}
}

Los archivos anteriores son solo modelos que se rellenarán con recursos lingüísticos, culturas y
también hay un DBContext típico utilizado por EF Core.

Lo último que necesitamos para hacer que todo este trabajo sea crear los archivos de recursos de
idioma. Los archivos JSON utilizados para almacenar un par clave-valor para diferentes idiomas
disponibles en su aplicación.

En este ejemplo, nuestra aplicación solo tiene dos idiomas disponibles. Inglés y persa. Para cada
uno de los idiomas necesitamos dos archivos. Un archivo JSON que contiene pares clave-valor y
un archivo .cs que contiene una clase con el mismo nombre que el archivo JSON. Esa clase tiene
un método, GetList que deserializa el archivo JSON y lo devuelve. Este método se llama en el
constructor de EFStringLocalizerFactory que creamos anteriormente.

Entonces, crea estos cuatro archivos en tu carpeta de Languages :

en-US.cs

namespace DigitalShop.Languages
{
public static class en_US
{
public static List<Resource> GetList()
{
var jsonSerializerSettings = new JsonSerializerSettings();
jsonSerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore;
return
JsonConvert.DeserializeObject<List<Resource>>(File.ReadAllText("Languages/en-US.json"),
jsonSerializerSettings);
}
}
}

en-US.json

https://riptutorial.com/es/home 106
{
"Key": "Welcome",
"Value": "Welcome"
},
{
"Key": "Hello",
"Value": "Hello"
},
]

fa-IR.cs

public static class fa_IR


{
public static List<Resource> GetList()
{
var jsonSerializerSettings = new JsonSerializerSettings();
jsonSerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore;
return JsonConvert.DeserializeObject<List<Resource>>(File.ReadAllText("Languages/fa-
IR.json", Encoding.UTF8), jsonSerializerSettings);
}
}

fa-IR.json

[
{
"Key": "Welcome",
"Value": "‫"دیدمآ شوخ‬
},
{
"Key": "Hello",
"Value": "‫"مالس‬
},
]

Todos hemos terminado. Ahora, para acceder a las cadenas de idioma (pares clave-valor) en
cualquier parte de su código ( .cs o .cshtml ) puede hacer lo siguiente:

en un archivo .cs (sea controlador o no, no importa):

// Returns "Welcome" for en-US and "‫ "دیدمآ شوخ‬for fa-IR


var welcome = Startup._e["Welcome"];

en un archivo de vista de Razor ( .cshtml ):

<h1>@Startup._e["Welcome"]</h1>

Pocas cosas a tener en cuenta:

• Si intenta acceder a una Key que no existe en el archivo JSON o está cargada, solo obtendrá
la clave literal (en el ejemplo anterior, al intentar acceder a Startup._e["How are you"] volverá
How are you No importa la configuración de idioma porque no existe

https://riptutorial.com/es/home 107
• Si cambia el valor de una cadena en un archivo .json idioma, deberá REINICIAR la
aplicación. De lo contrario, solo mostrará el valor predeterminado (nombre de clave). Esto
es especialmente importante cuando está ejecutando su aplicación sin depurar.
• appsettings.json puede usarse para almacenar todo tipo de configuraciones que su
aplicación pueda necesitar.
• No es necesario reiniciar la aplicación si solo desea cambiar la configuración de idioma /
cultura del archivo appsettings.json . Esto significa que puede tener una opción en la
interfaz de su aplicación para permitir a los usuarios cambiar el idioma / cultura en tiempo de
ejecución.

Aquí está la estructura final del proyecto:

Establecer cultura de solicitud a través de la ruta url

De forma predeterminada, el middleware de localización de solicitudes incorporado solo admite la


configuración de la cultura mediante consulta, cookie o encabezado Accept-Language . Este
ejemplo muestra cómo crear un middleware que permita establecer la cultura como parte de la
ruta como en /api/en-US/products .

Este middleware de ejemplo asume que la configuración regional está en el segundo segmento
de la ruta.

public class UrlRequestCultureProvider : RequestCultureProvider

https://riptutorial.com/es/home 108
{
private static readonly Regex LocalePattern = new Regex(@"^[a-z]{2}(-[a-z]{2,4})?$",
RegexOptions.IgnoreCase);

public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext


httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}

var url = httpContext.Request.Path;

// Right now it's not possible to use httpContext.GetRouteData()


// since it uses IRoutingFeature placed in httpContext.Features when
// Routing Middleware registers. It's not set when the Localization Middleware
// is called, so this example simply assumes the locale will always
// be located in the second segment of a path, like in /api/en-US/products
var parts = httpContext.Request.Path.Value.Split('/');
if (parts.Length < 3)
{
return Task.FromResult<ProviderCultureResult>(null);
}

if (!LocalePattern.IsMatch(parts[2]))
{
return Task.FromResult<ProviderCultureResult>(null);
}

var culture = parts[2];


return Task.FromResult(new ProviderCultureResult(culture));
}
}

Registro de middleware
var localizationOptions = new RequestLocalizationOptions
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("de-DE"),
new CultureInfo("en-US"),
new CultureInfo("en-GB")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("de-DE"),
new CultureInfo("en-US"),
new CultureInfo("en-GB")
},
DefaultRequestCulture = new RequestCulture("en-US")
};

// Adding our UrlRequestCultureProvider as first object in the list


localizationOptions.RequestCultureProviders.Insert(0, new UrlRequestCultureProvider
{
Options = localizationOptions

https://riptutorial.com/es/home 109
});

app.UseRequestLocalization(localizationOptions);

Restricciones de ruta personalizadas


Agregar y crear restricciones de ruta personalizadas se muestran en el ejemplo Restricciones de
ruta . El uso de restricciones simplifica el uso de restricciones de ruta personalizadas.

Registro de la ruta
Ejemplo de registro de rutas sin utilizar restricciones personalizadas.

app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "api/{culture::regex(^[a-z]{{2}}-[A-Za-z]{{4}}$)}}/{controller}/{id?}");
routes.MapRoute(
name: "default",
template: "api/{controller}/{id?}");
});

Lea Localización en línea: https://riptutorial.com/es/asp-net-core/topic/2869/localizacion

https://riptutorial.com/es/home 110
Capítulo 17: Manejo de errores
Examples
Redirigir a página de error personalizada

ASP.NET Core proporciona el middleware de páginas de códigos de estado , que admite varios
métodos de extensión diferentes, pero estamos interesados en UseStatusCodePages y
UseStatusCodePagesWithRedirects :

• UseStatusCodePages agrega un middleware StatusCodePages con las opciones dadas que


comprueba las respuestas con códigos de estado entre 400 y 599 que no tienen un cuerpo.
Ejemplo de uso para redireccionar:

app.UseStatusCodePages(async context => {


//context.HttpContext.Response.StatusCode contains the status code

// your redirect logic

});

• UseStatusCodePagesWithRedirects agrega un middleware StatusCodePages a la


canalización. Especifica que las respuestas deben manejarse mediante la redirección con la
plantilla de URL de ubicación dada. Esto puede incluir un marcador de posición '{0}' para el
código de estado. Las URL que comiencen con '~' incluirán PathBase, donde se usará
cualquier otra URL tal como está. Por ejemplo, lo siguiente se redireccionará a ~ / errors /
<error_code> (por ejemplo ~ / errors / 403 para el error 403):

app.UseStatusCodePagesWithRedirects("~/errors/{0}");

Manejo global de excepciones en ASP.NET Core

UseExceptionHandler se puede usar para manejar excepciones de manera global. Puede obtener
todos los detalles del objeto de excepción como Stack Trace, Inner exception y otros. Y luego
puedes mostrarlos en pantalla. Puede implementar fácilmente como esto.

app.UseExceptionHandler(
options => {
options.Run(
async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/html";
var ex = context.Features.Get<IExceptionHandlerFeature>();
if (ex != null)
{
var err = $"<h1>Error: {ex.Error.Message}</h1>{ex.Error.StackTrace }";
await context.Response.WriteAsync(err).ConfigureAwait(false);
}

https://riptutorial.com/es/home 111
});
}
);

Necesitas poner esto dentro de configure () del archivo startup.cs.

Lea Manejo de errores en línea: https://riptutorial.com/es/asp-net-core/topic/6581/manejo-de-


errores

https://riptutorial.com/es/home 112
Capítulo 18: Middleware
Observaciones
Middleware es un componente de software que determinará cómo procesar la solicitud y decidirá
si se pasa al siguiente componente en la canalización de la aplicación. Cada middleware tiene
una función y acciones específicas diferentes para realizar en la solicitud.

Examples
Uso del middleware ExceptionHandler para enviar un error JSON
personalizado al cliente

Defina su clase que representará su error personalizado.

public class ErrorDto


{
public int Code { get; set; }
public string Message { get; set; }

// other fields

public override string ToString()


{
return JsonConvert.SerializeObject(this);
}
}

Luego ponga el siguiente middleware de ExceptionHandler en el método de configuración. Preste


atención a que el orden de middleware es importante.

app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
context.Response.StatusCode = 500; // or another Status
context.Response.ContentType = "application/json";

var error = context.Features.Get<IExceptionHandlerFeature>();


if (error != null)
{
var ex = error.Error;

await context.Response.WriteAsync(new ErrorDto()


{
Code = <your custom code based on Exception Type>,
Message = ex.Message // or your custom message

... // other custom data


}.ToString(), Encoding.UTF8);
}
});

https://riptutorial.com/es/home 113
});

Middleware para establecer la respuesta ContentType

La idea es usar HttpContext.Response.OnStarting callback, ya que este es el último evento que se


dispara antes de que se envíen los encabezados. Agregue lo siguiente a su método de Invoke
middleware.

public async Task Invoke(HttpContext context)


{
context.Response.OnStarting((state) =>
{
if (context.Response.StatusCode == (int)HttpStatusCode.OK)
{
if (context.Request.Path.Value.EndsWith(".map"))
{
context.Response.ContentType = "application/json";
}
}
return Task.FromResult(0);
}, null);

await nextMiddleware.Invoke(context);
}

Pasar datos a través de la cadena de middleware.

De la documentación :

La colección HttpContext.Items es la mejor ubicación para almacenar datos que solo


se necesitan al procesar una solicitud determinada. Su contenido se desecha después
de cada solicitud. Se utiliza mejor como medio de comunicación entre componentes o
middleware que operan en diferentes puntos en el tiempo durante una solicitud y no
tienen una relación directa entre ellos a través de la cual pasar parámetros o valores
de retorno.

HttpContext.Items es una simple colección de diccionarios del tipo IDictionary<object, object> .


Esta coleccion es

• disponible desde el inicio de un HttpRequest


• y se desecha al final de cada solicitud.

Puede acceder a él simplemente asignando un valor a una entrada con clave, o solicitando el
valor para una clave determinada.

Por ejemplo, algún Middleware simple podría agregar algo a la colección de Artículos:

app.Use(async (context, next) =>


{
// perform some verification
context.Items["isVerified"] = true;
await next.Invoke();

https://riptutorial.com/es/home 114
});

y más tarde en la tubería, otra pieza de middleware podría acceder a él:

app.Run(async (context) =>


{
await context.Response.WriteAsync("Verified request? " + context.Items["isVerified"]);
});

Ejecutar, Mapa, Uso

correr

Termina la cadena. Ningún otro método de middleware se ejecutará después de esto. Debe
colocarse al final de cualquier tubería.

app.Run(async context =>


{
await context.Response.WriteAsync("Hello from " + _environment);
});

Utilizar

Realiza la acción antes y después del próximo delegado.

app.Use(async (context, next) =>


{
//action before next delegate
await next.Invoke(); //call next middleware
//action after called middleware
});

Ilustración de cómo funciona:

https://riptutorial.com/es/home 115
Mapa cuando

Habilita ramificación de tubería. Ejecuta el middleware especificado si se cumple la condición.

private static void HandleBranch(IApplicationBuilder app)


{
app.Run(async context =>
{
await context.Response.WriteAsync("Condition is fulfilled");
});
}

public void ConfigureMapWhen(IApplicationBuilder app)


{
app.MapWhen(context => {
return context.Request.Query.ContainsKey("somekey");
}, HandleBranch);
}

Mapa

Similar a MapWhen. Ejecuta middleware si la ruta solicitada por el usuario es igual a la ruta
proporcionada en el parámetro.

private static void HandleMapTest(IApplicationBuilder app)


{
app.Run(async context =>
{
await context.Response.WriteAsync("Map Test Successful");
});
}

public void ConfigureMapping(IApplicationBuilder app)

https://riptutorial.com/es/home 116
{
app.Map("/maptest", HandleMapTest);

Basado en ASP.net Core Docs

Lea Middleware en línea: https://riptutorial.com/es/asp-net-core/topic/1479/middleware

https://riptutorial.com/es/home 117
Capítulo 19: Modelos
Examples
Validación del modelo con atributos de validación

Los atributos de validación se pueden usar para configurar fácilmente la validación del modelo.

public class MyModel


{
public int id { get; set; }

//sets the FirstName to be required, and no longer than 100 characters


[Required]
[StringLength(100)]
public string FirstName { get; set; }
}

Los atributos incorporados son:

• [CreditCard]: valida que la propiedad tenga un formato de tarjeta de crédito.


• [Compare] : valida dos propiedades en una coincidencia de modelo.
• [EmailAddress] : valida que la propiedad tenga un formato de correo electrónico.
• [Phone] : Valida que la propiedad tiene un formato telefónico.
• [Range] : valida el valor de la propiedad dentro del rango dado.
• [RegularExpression] : valida que los datos coincidan con la expresión regular especificada.
• [Required] : Hace una propiedad requerida.
• [StringLength] : valida que una propiedad de cadena tenga a lo sumo la longitud máxima
dada.
• [Url] : valida que la propiedad tenga un formato de URL.

Validación del modelo con atributo personalizado

Si los atributos incorporados no son suficientes para validar los datos de su modelo, entonces
puede colocar su lógica de validación en una clase derivada de ValidationAttribute. En este
ejemplo, solo los números impares son valores válidos para un miembro modelo.

Atributo de validación personalizado

public class OddNumberAttribute : ValidationAttribute


{
protected override ValidationResult IsValid(object value, ValidationContext
validationContext)
{
try
{
var number = (int) value;
if (number % 2 == 1)
return ValidationResult.Success;

https://riptutorial.com/es/home 118
else
return new ValidationResult("Only odd numbers are valid.");
}
catch (Exception)
{
return new ValidationResult("Not a number.");
}
}
}

Clase de modelo

public class MyModel


{
[OddNumber]
public int Number { get; set; }
}

Lea Modelos en línea: https://riptutorial.com/es/asp-net-core/topic/4625/modelos

https://riptutorial.com/es/home 119
Capítulo 20: proyecto.json
Introducción
Project json es una estructura de archivos de configuración de proyectos, utilizada temporalmente
por proyectos asp.net-core, antes de que Microsoft vuelva a los archivos csproj en favor de
msbuild.

Examples
Ejemplo de proyecto de biblioteca simple

Una biblioteca basada en NETStandard 1.6 se vería así:

{
"version": "1.0.0",
"dependencies": {
"NETStandard.Library": "1.6.1", //nuget dependency
},
"frameworks": { //frameworks the library is build for
"netstandard1.6": {}
},
"buildOptions": {
"debugType": "portable"
}
}

Archivo json completo:

Tomado de la página github de microsoft con documentación oficial.

{
"name": String, //The name of the project, used for the assembly name as well as the name of
the package. The top level folder name is used if this property is not specified.
"version": String, //The Semver version of the project, also used for the NuGet package.
"description": String, //A longer description of the project. Used in the assembly properties.
"copyright": String, //The copyright information for the project. Used in the assembly
properties.
"title": String, //The friendly name of the project, can contain spaces and special characters
not allowed when using the `name` property. Used in the assembly properties.
"entryPoint": String, //The entrypoint method for the project. `Main` by default.
"testRunner": String, //The name of the test runner, such as NUnit or xUnit, to use with this
project. Setting this also marks the project as a test project.
"authors": String[], // An array of strings with the names of the authors of the project.
"language": String, //The (human) language of the project. Corresponds to the "neutral-
language" compiler argument.
"embedInteropTypes": Boolean, //`true` to embed COM interop types in the assembly; otherwise,
`false`.
"preprocess": String or String[], //Specifies which files are included in preprocessing.
"shared": String or String[], //Specifies which files are shared, this is used for library
export.
"dependencies": Object { //project and nuget dependencies

https://riptutorial.com/es/home 120
version: String, //Specifies the version or version range of the dependency. Use the \*
wildcard to specify a floating dependency version.
type: String, //type of dependency: build
target: String, //Restricts the dependency to match only a `project` or a `package`.
include: String,
exclude: String,
suppressParent: String
},
"tools": Object, //An object that defines package dependencies that are used as tools for the
current project, not as references. Packages defined here are available in scripts that run
during the build process, but they are not accessible to the code in the project itself. Tools
can for example include code generators or post-build tools that perform tasks related to
packing.
"scripts": Object, // commandline scripts: precompile, postcompile, prepublish & postpublish
"buildOptions": Object {
"define": String[], //A list of defines such as "DEBUG" or "TRACE" that can be used in
conditional compilation in the code.
"nowarn": String[], //A list of warnings to ignore.
"additionalArguments": String[], //A list of extra arguments that will be passed to the
compiler.
"warningsAsErrors": Boolean,
"allowUnsafe": Boolean,
"emitEntryPoint": Boolean,
"optimize": Boolean,
"platform": String,
"languageVersion": String,
"keyFile": String,
"delaySign": Boolean,
"publicSign": Boolean,
"debugType": String,
"xmlDoc": Boolean,
"preserveCompilationContext": Boolean,
"outputName": String,
"compilerName": String,
"compile": Object {
"include": String or String[],
"exclude": String or String[],
"includeFiles": String or String[],
"excludeFiles": String or String[],
"builtIns": Object,
"mappings": Object
},
"embed": Object {
"include": String or String[],
"exclude": String or String[],
"includeFiles": String or String[],
"excludeFiles": String or String[],
"builtIns": Object,
"mappings": Object
},
"copyToOutput": Object {
"include": String or String[],
"exclude": String or String[],
"includeFiles": String or String[],
"excludeFiles": String or String[],
"builtIns": Object,
"mappings": Object
}
},
"publishOptions": Object {
"include": String or String[],

https://riptutorial.com/es/home 121
"exclude": String or String[],
"includeFiles": String or String[],
"excludeFiles": String or String[],
"builtIns": Object,
"mappings": Object
},
"runtimeOptions": Object {
"configProperties": Object {
"System.GC.Server": Boolean,
"System.GC.Concurrent": Boolean,
"System.GC.RetainVM": Boolean,
"System.Threading.ThreadPool.MinThreads": Integer,
"System.Threading.ThreadPool.MaxThreads": Integer
},
"framework": Object {
"name": String,
"version": String,
},
"applyPatches": Boolean
},
"packOptions": Object {
"summary": String,
"tags": String[],
"owners": String[],
"releaseNotes": String,
"iconUrl": String,
"projectUrl": String,
"licenseUrl": String,
"requireLicenseAcceptance": Boolean,
"repository": Object {
"type": String,
"url": String
},
"files": Object {
"include": String or String[],
"exclude": String or String[],
"includeFiles": String or String[],
"excludeFiles": String or String[],
"builtIns": Object,
"mappings": Object
}
},
"analyzerOptions": Object {
"languageId": String
},
"configurations": Object,
"frameworks": Object {
"dependencies": Object {
version: String,
type: String,
target: String,
include: String,
exclude: String,
suppressParent: String
},
"frameworkAssemblies": Object,
"wrappedProject": String,
"bin": Object {
assembly: String
}
},

https://riptutorial.com/es/home 122
"runtimes": Object,
"userSecretsId": String
}

Proyecto de inicio simple

Un ejemplo simple de la configuración del proyecto para una aplicación de consola .NetCore 1.1

{
"version": "1.0.0",
"buildOptions": {
"emitEntryPoint": true // make sure entry point is emitted.
},
"dependencies": {
},
"tools": {
},
"frameworks": {
"netcoreapp1.1": { // run as console app
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.1.0"
}
},
"imports": "dnxcore50"
}
},
}

Lea proyecto.json en línea: https://riptutorial.com/es/asp-net-core/topic/9364/proyecto-json

https://riptutorial.com/es/home 123
Capítulo 21: Publicación y despliegue
Examples
Cernícalo. Configurando la dirección de escucha

Usando Kestrel puedes especificar el puerto usando los siguientes enfoques:

1. Definiendo la variable de entorno ASPNETCORE_URLS .

Windows

SET ASPNETCORE_URLS=https://0.0.0.0:5001

OS X

export ASPNETCORE_URLS=https://0.0.0.0:5001

2. A través de la línea de comando pasando el parámetro --server.urls

dotnet run --server.urls=http://0.0.0.0:5001

3. Usando el método UseUrls()

var builder = new WebHostBuilder()


.UseKestrel()
.UseUrls("http://0.0.0.0:5001")

4. Definiendo la configuración de server.urls en la fuente de configuración.

El siguiente ejemplo usa el archivo hosting.json, por ejemplo.

Add `hosting.json` with the following content to you project:

{
"server.urls": "http://<ip address>:<port>"
}

Ejemplos de valores posibles:

• Escuche 5000 en cualquier dirección IP4 e IP6 desde cualquier interfaz:

"server.urls": "http://*:5000"

"server.urls": "http://::5000;http://0.0.0.0:5000"

https://riptutorial.com/es/home 124
• Escucha 5000 en cada dirección IP4:

"server.urls": "http://0.0.0.0:5000"

Se debe tener cuidado y no usar http://*:5000;http://::5000 ,


http://::5000;http://*:5000 , http://*:5000;http://0.0.0.0:5000 o
http://*:5000;http://0.0.0.0:5000 porque requerirá registrar la dirección IP6 :: o la
dirección IP4 0.0.0.0 dos veces

Añadir archivo a publishOptions en project.json

"publishOptions": {
"include": [
"hosting.json",
...
]
}

y en el punto de entrada para la llamada a la aplicación .UseConfiguration(config) al crear


WebHostBuilder:

public static void Main(string[] args)


{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", optional: true)
.Build();

var host = new WebHostBuilder()


.UseConfiguration(config)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();

host.Run();
}

Lea Publicación y despliegue en línea: https://riptutorial.com/es/asp-net-


core/topic/2262/publicacion-y-despliegue

https://riptutorial.com/es/home 125
Capítulo 22: Sesiones en ASP.NET Core 1.0
Introducción
Usando Sesiones en ASP.NET Core 1.0

Examples
Ejemplo básico de manejo de sesión.

1) Primero, agregue la dependencia en project.json - "Microsoft.AspNetCore.Session": "1.1.0",

2) En startup.cs y agregue las AddSession() y AddDistributedMemoryCache() a los servicios de


ConfigureServices como este:

services.AddDistributedMemoryCache(); //This way ASP.NET Core will use a Memory Cache to store
session variables
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromDays(1); // It depends on user requirements.
options.CookieName = ".My.Session"; // Give a cookie name for session which will
be visible in request payloads.
});

3) Agregue la llamada UseSession() en Configurar método de inicio como este:

app.UseSession(); //make sure add this line before UseMvc()

4) En el controlador, el objeto Session se puede utilizar de esta forma:

using Microsoft.AspNetCore.Http;

public class HomeController : Controller


{
public IActionResult Index()
{
HttpContext.Session.SetString("SessionVariable1", "Testing123");
return View();
}

public IActionResult About()


{
ViewBag.Message = HttpContext.Session.GetString("SessionVariable1");

return View();
}
}

5. Si está utilizando la política de cors, a veces puede dar errores, después de habilitar
sesión con respecto a los encabezados sobre la habilitación del encabezado

https://riptutorial.com/es/home 126
AllowCredentials y el uso de
WithOrigins encabezado en lugar de AllowAllOrigins .

Lea Sesiones en ASP.NET Core 1.0 en línea: https://riptutorial.com/es/asp-net-


core/topic/8067/sesiones-en-asp-net-core-1-0

https://riptutorial.com/es/home 127
Capítulo 23: Solicitudes de Origen Cruzado
(CORS)
Observaciones
La seguridad del navegador impide que una página web realice solicitudes AJAX a otro dominio.
Esta restricción se denomina política del mismo origen e impide que un sitio malintencionado lea
datos confidenciales de otro sitio. Sin embargo, a veces es posible que desee permitir que otros
sitios realicen solicitudes de origen cruzado a su aplicación web.

El intercambio de recursos de origen cruzado (CORS) es un estándar de W3C que permite a un


servidor relajar la política del mismo origen. Usando CORS, un servidor puede permitir
explícitamente algunas solicitudes de origen cruzado mientras rechaza otras. CORS es más
seguro y más flexible que las técnicas anteriores, como JSONP.

Examples
Habilitar CORS para todas las solicitudes

Use el método de extensión UseCors() en IApplicationBuilder en el método Configure para aplicar


la política CORS a todas las solicitudes.

public void ConfigureServices(IServiceCollection services)


{
services.AddMvc();
services.AddCors();
}

public void Configure(IApplicationBuilder app)


{
// Other middleware..

app.UseCors(builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});

// Other middleware..

app.UseMvc();
}

Habilitar la política CORS para controladores específicos

Para habilitar una determinada política de CORS para controladores específicos, debe crear la
política en la extensión AddCors dentro del método ConfigureServices :

https://riptutorial.com/es/home 128
services.AddCors(cors => cors.AddPolicy("AllowAll", policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));

Esto le permite aplicar la política a un controlador:

[EnableCors("AllowAll")]
public class HomeController : Controller
{
// ...
}

Políticas de CORS más sofisticadas

El generador de políticas le permite crear políticas sofisticadas.

app.UseCors(builder =>
{
builder.WithOrigins("http://localhost:5000", "http://myproductionapp.com")
.WithMethods("GET", "POST", "HEAD")
.WithHeaders("accept", "content-type", "origin")
.SetPreflightMaxAge(TimeSpan.FromDays(7));
});

Esta política solo permite los orígenes http://localhost:5000 y http://myproductionapp.com con solo
los métodos GET , POST y HEAD y solo acepta los encabezados HTTP de accept , content-type y
origin . El método SetPreflightMaxAge hace que los navegadores SetPreflightMaxAge en caché el
resultado de la solicitud de verificación previa ( OPTIONS ) para que se almacene en caché durante
el tiempo especificado.

Habilitar la política CORS para todos los controladores

Para habilitar una política CORS en todos sus controladores MVC, debe crear la política en la
extensión AddCors dentro del método ConfigureServices y luego configurar la política en
CorsAuthorizationFilterFactory

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Cors.Internal;
...
public void ConfigureServices(IServiceCollection services) {
// Add AllowAll policy just like in single controller example.
services.AddCors(options => {
options.AddPolicy("AllowAll",
builder => {
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});

// Add framework services.

https://riptutorial.com/es/home 129
services.AddMvc();

services.Configure<MvcOptions>(options => {
options.Filters.Add(new CorsAuthorizationFilterFactory("AllowAll"));
});
}

public void Configure(IApplicationBuilder app) {


app.useMvc();
// For content not managed within MVC. You may want to set the Cors middleware
// to use the same policy.
app.UseCors("AllowAll");
}

Esta política de CORS se puede sobrescribir en un controlador o acción, pero esto puede
establecer el valor predeterminado para toda la aplicación.

Lea Solicitudes de Origen Cruzado (CORS) en línea: https://riptutorial.com/es/asp-net-


core/topic/2556/solicitudes-de-origen-cruzado--cors-

https://riptutorial.com/es/home 130
Capítulo 24: Trabajando con
JavascriptServices
Introducción
Según la documentación oficial:

JavaScriptServices es un conjunto de tecnologías para desarrolladores de ASP.NET Core.


Proporciona una infraestructura que le resultará útil si usa Angular 2 / React / Knockout / etc. en el
cliente, o si construye sus recursos del lado del cliente con Webpack, o si desea ejecutar
JavaScript en el servidor en tiempo de ejecución.

Examples
Habilitar webpack-dev-middleware para el proyecto asp.net-core

Digamos que utiliza Webpack para agrupar front-end. Puede agregar webpack-dev-middleware para
servir sus estadísticas a través de un servidor pequeño y rápido. Le permite recargar
automáticamente sus activos cuando el contenido ha cambiado, servir estadísticas en la memoria
sin escribir continuamente versiones intermedias en el disco.

Prerrequisitos
NuGet
Paquete de instalación Microsoft.AspNetCore.SpaServices

npm
npm install --save-dev aspnet-webpack, webpack-dev-middleware, webpack-dev-server

Configurando
Extienda el método de Configure en su clase de Startup

if (env.IsDevelopment())
{
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions()
{
ConfigFile = "webpack.config.js" //this is defualt value
});
}

https://riptutorial.com/es/home 131
Añadir reemplazo de módulo caliente (HMR)

El reemplazo del módulo en caliente permite agregar, cambiar o eliminar el módulo de la


aplicación cuando la aplicación se está ejecutando. La recarga de la página no es necesaria en
este caso.

Prerrequisitos
Además de los webpack-dev-middleware :

npm install --save-dev webpack-hot-middleware

Configuración
Simplemente actualice la configuración de UseWebpackDevMiddleware con nuevas opciones:

app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions()
{
ConfigFile = "webpack.config.js", //this is defualt value
HotModuleReplacement = true,
ReactHotModuleReplacement = true, //for React only
});

También necesita aceptar módulos calientes en su código de aplicación.

HMR es compatible con Angular 2, React, Knockout y Vue.

Generando una aplicación de muestra de una sola página con el núcleo de


asp.net

Puede usar el generador aspnetcore-spa para Yeoman para crear una aplicación de página única
completamente nueva con el núcleo de asp.net.

Esto le permite elegir uno de los marcos frontales populares y generar proyectos con webpack,
dev server, reemplazo de módulo en caliente y funciones de representación del lado del servidor.

Solo corre

npm install -g yo generator-aspnetcore-spa


cd newproject
yo aspnetcore-spa

y elige tu marco favorito

https://riptutorial.com/es/home 132
Lea Trabajando con JavascriptServices en línea: https://riptutorial.com/es/asp-net-
core/topic/9621/trabajando-con-javascriptservices

https://riptutorial.com/es/home 133
Capítulo 25: Ver componentes
Examples
Crear un componente de vista

Los componentes de vista encapsulan piezas reutilizables de lógica y vistas. Están definidos por:

• Una clase ViewComponent que contiene la lógica para obtener y preparar los datos para la
vista y decidir qué vista se va a representar.
• Una o mas vistas

Ya que contienen lógica, son más flexibles que las visiones parciales y al mismo tiempo
promueven una buena separación de preocupaciones.

Un componente de vista personalizado simple se define como:

public class MyCustomViewComponent : ViewComponent


{
public async Task<IViewComponentResult> InvokeAsync(string param1, int param2)
{
//some business logic

//renders ~/Views/Shared/Components/MyCustom/Default.cshtml
return View(new MyCustomModel{ ... });
}
}

@*View file located in ~/Views/Shared/Components/MyCustom/Default.cshtml*@


@model WebApplication1.Models.MyCustomModel
<p>Hello @Model.UserName!</p>

Se pueden invocar desde cualquier vista (o incluso un controlador devolviendo un


ViewComponentResult )

@await Component.InvokeAsync("MyCustom", new {param1 = "foo", param2 = 42})

Iniciar sesión Ver componente

La plantilla de proyecto predeterminada crea una vista parcial _LoginPartial.cshtml que contiene
un poco de lógica para averiguar si el usuario ha iniciado sesión o no y averiguar su nombre de
usuario.

Dado que un componente de vista podría ser un mejor ajuste (ya que hay lógica involucrada e
incluso 2 servicios inyectados), el siguiente ejemplo muestra cómo convertir el LoginPartial en un
componente de vista.

Ver clase de componente

https://riptutorial.com/es/home 134
public class LoginViewComponent : ViewComponent
{
private readonly SignInManager<ApplicationUser> signInManager;
private readonly UserManager<ApplicationUser> userManager;

public LoginViewComponent(SignInManager<ApplicationUser> signInManager,


UserManager<ApplicationUser> userManager)
{
this.signInManager = signInManager;
this.userManager = userManager;
}

public async Task<IViewComponentResult> InvokeAsync()


{
if (signInManager.IsSignedIn(this.User as ClaimsPrincipal))
{
return View("SignedIn", await userManager.GetUserAsync(this.User as
ClaimsPrincipal));
}
return View("SignedOut");
}
}

Vista SignedIn (en ~ / Vistas / Compartido / Componentes / Login / SignedIn.cshtml)

@model WebApplication1.Models.ApplicationUser

<form asp-area="" asp-controller="Account" asp-action="LogOff" method="post" id="logoutForm"


class="navbar-right">
<ul class="nav navbar-nav navbar-right">
<li>
<a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello
@Model.UserName!</a>
</li>
<li>
<button type="submit" class="btn btn-link navbar-btn navbar-link">Log off</button>
</li>
</ul>
</form>

Vista SignedOut (en ~ / Vistas / Compartido / Componentes / Login / SignedOut.cshtml)

<ul class="nav navbar-nav navbar-right">


<li><a asp-area="" asp-controller="Account" asp-action="Register">Register</a></li>
<li><a asp-area="" asp-controller="Account" asp-action="Login">Log in</a></li>
</ul>

Invocación desde _Layout.cshtml

@await Component.InvokeAsync("Login")

Regreso de la acción del controlador

Cuando se hereda de la clase de Controller base proporcionada por el marco, puede usar el
método de conveniencia ViewComponent() para devolver un componente de vista desde la acción:

https://riptutorial.com/es/home 135
public IActionResult GetMyComponent()
{
return ViewComponent("Login", new { param1 = "foo", param2 = 42 });
}

Si utiliza una clase POCO como controlador, puede crear manualmente una instancia de la clase
ViewComponentResult . Esto sería equivalente al código anterior:

public IActionResult GetMyComponent()


{
return new ViewComponentResult
{
ViewComponentName = "Login",
Arguments = new { param1 = "foo", param2 = 42 }
};
}

Lea Ver componentes en línea: https://riptutorial.com/es/asp-net-core/topic/3248/ver-componentes

https://riptutorial.com/es/home 136
Creditos
S.
Capítulos Contributors
No

Alex Logan, Alexan, Ashish Rajput, Ashley Medway, Bogdan


Empezando con Stefanjuk, BrunoLM, ChadT, Community, gbellmann, Henk
1
asp.net-core Mollema, Nate Barbettini, Rion Williams, Shog9, Shyju, Svek,
Tseng, VSG24, Zach Becknell

Almacenamiento en
2 Cyprien Autexier, Sanket
caché

3 Angular2 y .Net Core Alejandro Tobón, Sentient Entities

ASP.NET Core:
registre tanto la
4 solicitud como la Gubr
respuesta utilizando
Middleware

5 Autorización gilmishal, RamenChef

Ayudantes de
6 Ali, Daniel J.G., dotnetom, Shyju, tmg, Zach Becknell
etiquetas

7 Configuración Cyprien Autexier, Jayantha Lal Sirisena

Configurando
8 dotnetom, Johnny, Robert Paulsen, Sanket, Set, Tseng
entornos múltiples

Empaquetado y
9 Rion Williams, Zach Becknell
Minificación

10 Enrutamiento ChadT, Tseng

Envío de correo
electrónico en
11 aplicaciones .Net Ankit
Core utilizando
MailKit

12 Explotación florestal Dmitry, Sanket, Set, Tseng

Alexan, BrunoLM, Cyprien Autexier, Dan Soper, Darren Evans,


Inyección de
13 gilmishal, Gurgen Hakobyan, Jayantha Lal Sirisena, Joel
dependencia
Harkes, maztt, Tseng, Zach Becknell

https://riptutorial.com/es/home 137
Inyectando servicios
14 Alex Logan, Rion Williams
en vistas.

15 Límite de velocidad Stefan P.

16 Localización Tseng, VSG24, Zach Becknell

17 Manejo de errores Sanket, Set

18 Middleware Ali, Piotrek, Set, VSG24, Zach Becknell

19 Modelos Alex Logan, Ralf Bönning

20 proyecto.json Joel Harkes

Publicación y
21 Set
despliegue

Sesiones en
22 ravindra, Sanket
ASP.NET Core 1.0

Solicitudes de
23 Origen Cruzado Henk Mollema, Sanket, Saqib Rokadia, Tseng
(CORS)

Trabajando con
24 hmnzr
JavascriptServices

25 Ver componentes Daniel J.G.

https://riptutorial.com/es/home 138

Potrebbero piacerti anche