mirror of https://github.com/abpframework/abp.git
224 changed files with 1054 additions and 782 deletions
@ -0,0 +1,140 @@ |
|||
# Empezando con ABP y una Aplicacion AspNet Core MVC Web |
|||
|
|||
Este tutorial explica como empezar una aplicacion ABP desde cero usando las dependencias minimas. Uno generalmente desea |
|||
empezar con la **[plantilla de inicio](Getting-Started-AspNetCore-MVC-Template.md)**. |
|||
|
|||
## Crea un Proyecto Nuevo |
|||
|
|||
1. Crea una Aplicacion Web AspNet Core nueva usando Visual Studio 2022 (17.0.0+): |
|||
|
|||
 |
|||
|
|||
2. Configura el nuevo proyecto: |
|||
|
|||
 |
|||
|
|||
3. Presione el boton Create: |
|||
|
|||
 |
|||
|
|||
## Instale el paquete Volo.Abp.AspNetCore.Mvc |
|||
|
|||
Volo.Abp.AspNetCore.Mvc es el paquete de integracion con AspNet Core MVC para ABP. Siendo asi, instalalo en su proyecto: |
|||
|
|||
```` |
|||
Install-Package Volo.Abp.AspNetCore.Mvc |
|||
```` |
|||
|
|||
## Crea el primer modulo ABP |
|||
|
|||
ABP es un marco de referencia modular y require una clase de **inicio (raíz) tipo modulo** derivada de ``AbpModule``: |
|||
|
|||
````C# |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace BasicAspNetCoreApplication |
|||
{ |
|||
[DependsOn(typeof(AbpAspNetCoreMvcModule))] |
|||
public class AppModule : AbpModule |
|||
{ |
|||
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
|||
{ |
|||
var app = context.GetApplicationBuilder(); |
|||
var env = context.GetEnvironment(); |
|||
|
|||
// Configura la canalización de peticiones HTTP. |
|||
if (env.IsDevelopment()) |
|||
{ |
|||
app.UseExceptionHandler("/Error"); |
|||
// El valor por defecto de HSTS es 30 dias. Debes cambiar esto en ambientes productivos. Referencia https://aka.ms/aspnetcore-hsts. |
|||
app.UseHsts(); |
|||
} |
|||
|
|||
app.UseHttpsRedirection(); |
|||
app.UseStaticFiles(); |
|||
app.UseRouting(); |
|||
app.UseConfiguredEndpoints(); |
|||
} |
|||
} |
|||
} |
|||
```` |
|||
|
|||
``AppModule`` es un buen nombre para el modulo de inicio de una aplicacion. |
|||
|
|||
Los paquetes de ABP definen clases de tipo modulo y cada modulo puede depender de otro. |
|||
En el codigo anterior, el ``AppModule`` depende de el modulo ``AbpAspNetCoreMvcModule`` (definido por el paquete [Volo.Abp.AspNetCore.Mvc](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc)). Es comun agregar el atributo ``DependsOn`` despues de instalar un paquete ABP nuevo. |
|||
|
|||
En vez de la clase de inicion Startup, estamos configurando una canalizacion de ASP.NET Core en este modulo. |
|||
|
|||
## La clase Program |
|||
|
|||
El proximo paso es modificar la clase Program para integrate el sistema de modulos ABP: |
|||
|
|||
````C# |
|||
using BasicAspNetCoreApplication; |
|||
|
|||
var builder = WebApplication.CreateBuilder(args); |
|||
|
|||
await builder.Services.AddApplicationAsync<AppModule>(); |
|||
|
|||
var app = builder.Build(); |
|||
|
|||
await app.InitializeApplicationAsync(); |
|||
await app.RunAsync(); |
|||
```` |
|||
|
|||
``builder.Services.AddApplicationAsync<AppModule>();`` Agrega todos los servicios definidos en todos los modulos empezando desde ``AppModule``. |
|||
|
|||
``app.InitializeApplicationAsync()`` inicializa y empieza la aplicacion. |
|||
|
|||
## Ejecutar la Aplicación |
|||
|
|||
Es todo! Ejecuta la aplicación, debe funcionar como esperado. |
|||
|
|||
## Uso de Autofac como Marco de Inyección de Dependencia |
|||
|
|||
Mientras el sistema de Inyección de Dependencia de ASP.NET Core es suficiente para requerimientos basico, [Autofac](https://autofac.org/) proporciona características avanzadas como Inyección de Propiedades e Intercepcion de Metodos, los cuales son necesarios para que ABP pueda llevar a cabo funciones avanzadas. |
|||
|
|||
El acto de remplazar el sistema DI de ASP.NET Core por Autofac e integrarlo con ABP es facil. |
|||
|
|||
1. Instala el paquete [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) |
|||
|
|||
```` |
|||
Install-Package Volo.Abp.Autofac |
|||
```` |
|||
|
|||
2. Agrega la dependencia sobre el modulo ``AbpAutofacModule`` |
|||
|
|||
````C# |
|||
[DependsOn(typeof(AbpAspNetCoreMvcModule))] |
|||
[DependsOn(typeof(AbpAutofacModule))] //Agrega la dependencia sobre el modulo ABP Autofac |
|||
public class AppModule : AbpModule |
|||
{ |
|||
... |
|||
} |
|||
```` |
|||
|
|||
3. Actualiza `Program.cs` para que use Autofac: |
|||
|
|||
````C# |
|||
using BasicAspNetCoreApplication; |
|||
|
|||
var builder = WebApplication.CreateBuilder(args); |
|||
|
|||
builder.Host.UseAutofac(); //Agrega esta linea |
|||
|
|||
await builder.Services.AddApplicationAsync<AppModule>(); |
|||
|
|||
var app = builder.Build(); |
|||
|
|||
await app.InitializeApplicationAsync(); |
|||
await app.RunAsync(); |
|||
```` |
|||
|
|||
## Codigo fuente |
|||
|
|||
Obten el codigo fuente del ejemplo creado en este tutorial de [aqui](https://github.com/abpframework/abp-samples/tree/master/BasicAspNetCoreApplication). |
|||
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 64 KiB |
@ -1,52 +0,0 @@ |
|||
using System; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.AspNetCore.DependencyInjection; |
|||
|
|||
[ExposeServices( |
|||
typeof(IHybridServiceScopeFactory), |
|||
typeof(HttpContextServiceScopeFactory) |
|||
)] |
|||
[Dependency(ReplaceServices = true)] |
|||
public class HttpContextServiceScopeFactory : IHybridServiceScopeFactory, ITransientDependency |
|||
{ |
|||
protected IHttpContextAccessor HttpContextAccessor { get; } |
|||
|
|||
protected IServiceScopeFactory ServiceScopeFactory { get; } |
|||
|
|||
public HttpContextServiceScopeFactory( |
|||
IHttpContextAccessor httpContextAccessor, |
|||
IServiceScopeFactory serviceScopeFactory) |
|||
{ |
|||
HttpContextAccessor = httpContextAccessor; |
|||
ServiceScopeFactory = serviceScopeFactory; |
|||
} |
|||
|
|||
public virtual IServiceScope CreateScope() |
|||
{ |
|||
var httpContext = HttpContextAccessor.HttpContext; |
|||
if (httpContext == null) |
|||
{ |
|||
return ServiceScopeFactory.CreateScope(); |
|||
} |
|||
|
|||
return new NonDisposedHttpContextServiceScope(httpContext.RequestServices); |
|||
} |
|||
|
|||
protected class NonDisposedHttpContextServiceScope : IServiceScope |
|||
{ |
|||
public IServiceProvider ServiceProvider { get; } |
|||
|
|||
public NonDisposedHttpContextServiceScope(IServiceProvider serviceProvider) |
|||
{ |
|||
ServiceProvider = serviceProvider; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.DependencyInjection; |
|||
|
|||
[ExposeServices( |
|||
typeof(IHybridServiceScopeFactory), |
|||
typeof(DefaultServiceScopeFactory) |
|||
)] |
|||
public class DefaultServiceScopeFactory : IHybridServiceScopeFactory, ITransientDependency |
|||
{ |
|||
protected IServiceScopeFactory Factory { get; } |
|||
|
|||
public DefaultServiceScopeFactory(IServiceScopeFactory factory) |
|||
{ |
|||
Factory = factory; |
|||
} |
|||
|
|||
public IServiceScope CreateScope() |
|||
{ |
|||
return Factory.CreateScope(); |
|||
} |
|||
} |
|||
@ -1,8 +0,0 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.DependencyInjection; |
|||
|
|||
public interface IHybridServiceScopeFactory : IServiceScopeFactory |
|||
{ |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.Domain.Entities.Events; |
|||
|
|||
/// <summary>
|
|||
/// Used to pass data for an event when an entity (<see cref="IEntity"/>) is being changed (creating, updating or deleting).
|
|||
/// See <see cref="EntityCreatingEventData{TEntity}"/>, <see cref="EntityDeletingEventData{TEntity}"/> and <see cref="EntityUpdatingEventData{TEntity}"/> classes.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEntity">Entity type</typeparam>
|
|||
[Serializable] |
|||
[Obsolete("This event is no longer needed and identical to EntityChangedEventData. Please use EntityChangedEventData instead.")] |
|||
public class EntityChangingEventData<TEntity> : EntityEventData<TEntity> |
|||
{ |
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="entity">Changing entity in this event</param>
|
|||
public EntityChangingEventData(TEntity entity) |
|||
: base(entity) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.Domain.Entities.Events; |
|||
|
|||
/// <summary>
|
|||
/// This type of event is used to notify just before creation of an Entity.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEntity">Entity type</typeparam>
|
|||
[Serializable] |
|||
[Obsolete("This event is no longer needed and identical to EntityCreatedEventData. Please use EntityCreatedEventData instead.")] |
|||
public class EntityCreatingEventData<TEntity> : EntityChangingEventData<TEntity> |
|||
{ |
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="entity">The entity which is being created</param>
|
|||
public EntityCreatingEventData(TEntity entity) |
|||
: base(entity) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.Domain.Entities.Events; |
|||
|
|||
/// <summary>
|
|||
/// This type of event is used to notify just before deletion of an Entity.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEntity">Entity type</typeparam>
|
|||
[Serializable] |
|||
[Obsolete("This event is no longer needed and identical to EntityDeletedEventData. Please use EntityDeletedEventData instead.")] |
|||
public class EntityDeletingEventData<TEntity> : EntityChangingEventData<TEntity> |
|||
{ |
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="entity">The entity which is being deleted</param>
|
|||
public EntityDeletingEventData(TEntity entity) |
|||
: base(entity) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.Domain.Entities.Events; |
|||
|
|||
/// <summary>
|
|||
/// This type of event is used to notify just before update of an Entity.
|
|||
/// </summary>
|
|||
/// <typeparam name="TEntity">Entity type</typeparam>
|
|||
[Serializable] |
|||
[Obsolete("This event is no longer needed and identical to EntityUpdatedEventData. Please use EntityUpdatedEventData instead.")] |
|||
public class EntityUpdatingEventData<TEntity> : EntityChangingEventData<TEntity> |
|||
{ |
|||
/// <summary>
|
|||
/// Constructor.
|
|||
/// </summary>
|
|||
/// <param name="entity">The entity which is being updated</param>
|
|||
public EntityUpdatingEventData(TEntity entity) |
|||
: base(entity) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -1,71 +0,0 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Shouldly; |
|||
using Volo.Abp.Modularity; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.DependencyInjection; |
|||
|
|||
public class HybridServiceScopeFactory_Tests |
|||
{ |
|||
[Fact] |
|||
public async Task Should_Use_Default_ServiceScopeFactory_By_Default_Async() |
|||
{ |
|||
using (var application = await AbpApplicationFactory.CreateAsync<IndependentEmptyModule>()) |
|||
{ |
|||
application.Services.AddType(typeof(MyServiceAsync)); |
|||
|
|||
await application.InitializeAsync(); |
|||
|
|||
var serviceScopeFactory = application.ServiceProvider.GetRequiredService<IHybridServiceScopeFactory>(); |
|||
|
|||
using (var scope = serviceScopeFactory.CreateScope()) |
|||
{ |
|||
scope.ServiceProvider.GetRequiredService<MyServiceAsync>(); |
|||
} |
|||
|
|||
MyServiceAsync.DisposeCount.ShouldBe(1); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Use_Default_ServiceScopeFactory_By_Default() |
|||
{ |
|||
using (var application = AbpApplicationFactory.Create<IndependentEmptyModule>()) |
|||
{ |
|||
application.Services.AddType(typeof(MyService)); |
|||
|
|||
application.Initialize(); |
|||
|
|||
var serviceScopeFactory = application.ServiceProvider.GetRequiredService<IHybridServiceScopeFactory>(); |
|||
|
|||
using (var scope = serviceScopeFactory.CreateScope()) |
|||
{ |
|||
scope.ServiceProvider.GetRequiredService<MyService>(); |
|||
} |
|||
|
|||
MyService.DisposeCount.ShouldBe(1); |
|||
} |
|||
} |
|||
|
|||
private class MyServiceAsync : ITransientDependency, IDisposable |
|||
{ |
|||
public static int DisposeCount { get; private set; } |
|||
|
|||
public void Dispose() |
|||
{ |
|||
++DisposeCount; |
|||
} |
|||
} |
|||
|
|||
private class MyService : ITransientDependency, IDisposable |
|||
{ |
|||
public static int DisposeCount { get; private set; } |
|||
|
|||
public void Dispose() |
|||
{ |
|||
++DisposeCount; |
|||
} |
|||
} |
|||
} |
|||
@ -1,6 +1,6 @@ |
|||
namespace Volo.Blogging |
|||
{ |
|||
public static class BloggingDbProperties |
|||
public static class AbpBloggingDbProperties |
|||
{ |
|||
/// <summary>
|
|||
/// Default value: "Blg".
|
|||
@ -0,0 +1,8 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.CmsKit.Contents; |
|||
|
|||
public class DefaultContentDto : IContent |
|||
{ |
|||
public List<ContentFragment> ContentFragments { get; set; } |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.CmsKit.Contents; |
|||
public interface IContent |
|||
{ |
|||
public List<ContentFragment> ContentFragments { get; set; } |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace Volo.CmsKit.Contents; |
|||
|
|||
public interface IContentAppService : IApplicationService |
|||
{ |
|||
Task<List<ContentFragment>> ParseAsync(string content); |
|||
} |
|||
@ -1,22 +1,21 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Generic; |
|||
using System; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.CmsKit.Contents; |
|||
|
|||
namespace Volo.CmsKit.Public.Pages; |
|||
namespace Volo.CmsKit.Contents; |
|||
|
|||
[Serializable] |
|||
public class PageDto : EntityDto<Guid> |
|||
public class PageDto : EntityDto<Guid>, IContent |
|||
{ |
|||
public string Title { get; set; } |
|||
|
|||
public string Slug { get; set; } |
|||
|
|||
public string Content { get; set; } |
|||
|
|||
|
|||
public List<ContentFragment> ContentFragments { get; set; } |
|||
|
|||
public string Script { get; set; } |
|||
|
|||
public string Style { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.GlobalFeatures; |
|||
using Volo.CmsKit.GlobalFeatures; |
|||
|
|||
namespace Volo.CmsKit.Contents; |
|||
|
|||
[RequiresGlobalFeature(typeof(PagesFeature))] |
|||
public class ContentAppService : CmsKitAppServiceBase, IContentAppService |
|||
{ |
|||
protected ContentParser ContentParser { get; } |
|||
|
|||
public ContentAppService(ContentParser contentParser) |
|||
{ |
|||
ContentParser = contentParser; |
|||
} |
|||
|
|||
public async Task<List<ContentFragment>> ParseAsync(string content) |
|||
{ |
|||
return await ContentParser.ParseAsync(content); |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.CmsKit.Web.Pages.CmsKit.Components.ContentPreview; |
|||
|
|||
namespace Volo.CmsKit.Web.Controllers; |
|||
|
|||
public class CmsKitCommonWidgetsController : AbpController |
|||
{ |
|||
[HttpPost] |
|||
public IActionResult ContentPreview(ContentPreviewDto dto) |
|||
{ |
|||
return ViewComponent(typeof(ContentPreviewViewComponent), new { content = dto.Content }); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System; |
|||
|
|||
namespace Volo.CmsKit.Web.Pages.CmsKit.Components.ContentPreview; |
|||
|
|||
[Serializable] |
|||
public class ContentPreviewDto |
|||
{ |
|||
public string Content { get; set; } |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.CmsKit.Contents; |
|||
|
|||
namespace Volo.CmsKit.Web.Pages.CmsKit.Components.ContentPreview; |
|||
|
|||
public class ContentPreviewViewComponent : AbpViewComponent |
|||
{ |
|||
protected IContentAppService ContentAppService { get; } |
|||
|
|||
public ContentPreviewViewComponent(IContentAppService contentAppService) |
|||
{ |
|||
ContentAppService = contentAppService; |
|||
} |
|||
|
|||
public virtual async Task<IViewComponentResult> InvokeAsync(string content) |
|||
{ |
|||
var fragments = await ContentAppService.ParseAsync(content); |
|||
|
|||
return View("~/Pages/CmsKit/Components/ContentPreview/Default.cshtml", new DefaultContentDto |
|||
{ |
|||
ContentFragments = fragments |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
@using Volo.CmsKit.Contents |
|||
@using Volo.CmsKit.Web.Pages.CmsKit.Components.Contents |
|||
|
|||
@model DefaultContentDto |
|||
|
|||
<div class="content"> |
|||
|
|||
@await Component.InvokeAsync(typeof(ContentFragmentViewComponent), Model) |
|||
|
|||
</div> |
|||
@ -0,0 +1,20 @@ |
|||
@using System.Dynamic |
|||
@using Volo.Abp.Data |
|||
@using Volo.CmsKit.Web.Renderers; |
|||
@using Volo.CmsKit.Web.Pages.CmsKit.Components.Contents; |
|||
|
|||
@model ContentFragmentViewComponent |
|||
|
|||
@inject IMarkdownToHtmlRenderer MarkdownRenderer |
|||
|
|||
@foreach (var contentFragment in Model.ContentDto.ContentFragments) |
|||
{ |
|||
if (contentFragment.Type == "Markdown") |
|||
{ |
|||
@Html.Raw(await MarkdownRenderer.RenderAsync(contentFragment.GetProperty<string>("Content"))) |
|||
} |
|||
else if (contentFragment.Type == "Widget") |
|||
{ |
|||
@await Component.InvokeAsync(contentFragment.GetProperty<string>("Type"), contentFragment.ExtraProperties.ConvertToDynamicObject()) |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
using Volo.CmsKit.Contents; |
|||
|
|||
namespace Volo.CmsKit.Web.Pages.CmsKit.Components.Contents; |
|||
|
|||
[ViewComponent(Name = "ContentFragment")] |
|||
[Widget( |
|||
AutoInitialize = true |
|||
)] |
|||
public class ContentFragmentViewComponent : AbpViewComponent |
|||
{ |
|||
public IContent ContentDto { get; set; } |
|||
|
|||
public virtual async Task<IViewComponentResult> InvokeAsync(IContent contentDto) |
|||
{ |
|||
return View("~/Pages/CmsKit/Components/Contents/ContentFragment.cshtml", new ContentFragmentViewComponent() { ContentDto = contentDto }); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue