添加命令数据验证和其他杂项修改

This commit is contained in:
2021-02-24 16:28:08 +08:00
parent 12ecdf3159
commit 41794aa1bc
32 changed files with 310 additions and 484 deletions

View File

@@ -9,7 +9,7 @@ namespace Domain.AggregateModel.AppAggregate
{ {
public interface IAppRepository:IRepository<App> public interface IAppRepository:IRepository<App>
{ {
void Add(App app); App Add(App app);
Task<App> GetAsync(int id); Task<App> GetAsync(int id);
} }
} }

View File

@@ -9,7 +9,7 @@ namespace Domain.AggregateModel.LinkAggregate
{ {
public interface ILinkRepository:IRepository<Link> public interface ILinkRepository:IRepository<Link>
{ {
void Add(Link link); Link Add(Link link);
Task<Link> GetAsync(string shortCode); Task<Link> GetAsync(string shortCode);
} }

View File

@@ -9,9 +9,4 @@
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" /> <PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Events\" />
<Folder Include="Exceptions\" />
</ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,21 @@
using Domain.AggregateModel.AppAggregate;
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Domain.Events
{
//更新了基础地址
public class AppBaseUrlUpdatedDomainEvent: INotification
{
public App App { get; set; }
public string OldBaseUrl { get; set; }
public AppBaseUrlUpdatedDomainEvent(App app,string oldBaseUrl) {
App = app;
OldBaseUrl = oldBaseUrl;
}
}
}

View File

@@ -0,0 +1,21 @@
using Domain.AggregateModel.LinkAggregate;
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Domain.Events
{
//短链接生成通知
public class LinkCreatedDomainEvent:INotification
{
public Link Link { get; set; }
public LinkCreatedDomainEvent(Link link)
{
Link = link;
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
namespace Domain.Exceptions
{
public class DomainException : Exception
{
public DomainException(string message) : base(message)
{ }
public DomainException(string message, Exception innerException) : base(message, innerException)
{ }
}
}

View File

@@ -14,9 +14,10 @@ namespace Infrastructure.EntityConfigurations
public void Configure(EntityTypeBuilder<Link> builder) public void Configure(EntityTypeBuilder<Link> builder)
{ {
builder.ToTable("Link"); builder.ToTable("Link");
builder.HasKey(l => l.Id);
builder.HasIndex(l => l.ShortCode).IsUnique();
builder.Ignore(l => l.DomainEvents); builder.Ignore(l => l.DomainEvents);
builder.HasIndex(l => l.ShortCode).IsUnique();
builder.HasKey(l => l.Id);
builder.Property(l => l.Id).ValueGeneratedOnAdd().IsRequired();
builder.Property(l => l.AppId).IsRequired(); builder.Property(l => l.AppId).IsRequired();
builder.Property(l => l.ShortCode).HasMaxLength(11); builder.Property(l => l.ShortCode).HasMaxLength(11);
} }

View File

@@ -1,5 +1,6 @@
using Domain.AggregateModel.AppAggregate; using Domain.AggregateModel.AppAggregate;
using Domain.SeedWork; using Domain.SeedWork;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -10,16 +11,31 @@ namespace Infrastructure.Repositories
{ {
public class AppRepository : IAppRepository public class AppRepository : IAppRepository
{ {
public IUnitOfWork UnitOfWork => throw new NotImplementedException(); private readonly AppDbContext dbContext;
public void Add(App app) public AppRepository(AppDbContext dbContext)
{ {
throw new NotImplementedException(); this.dbContext = dbContext;
} }
public Task<App> GetAsync(int id) public IUnitOfWork UnitOfWork => dbContext;
public App Add(App app)
{ {
throw new NotImplementedException(); if (app.IsTransient())
{
return dbContext.Apps.Add(app).Entity;
}
else
{
return app;
}
}
public async Task<App> GetAsync(int id)
{
var app = await dbContext.Apps.Where(a => a.Id == id).SingleOrDefaultAsync();
return app;
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using Domain.AggregateModel.LinkAggregate; using Domain.AggregateModel.LinkAggregate;
using Domain.SeedWork; using Domain.SeedWork;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -10,16 +11,33 @@ namespace Infrastructure.Repositories
{ {
public class LinkRepository : ILinkRepository public class LinkRepository : ILinkRepository
{ {
public IUnitOfWork UnitOfWork => throw new NotImplementedException(); private AppDbContext dbContext;
public void Add(Link link) public LinkRepository(AppDbContext dbContext)
{ {
throw new NotImplementedException(); this.dbContext = dbContext;
} }
public Task<Link> GetAsync(string shortCode) public IUnitOfWork UnitOfWork => dbContext;
public Link Add(Link link)
{ {
throw new NotImplementedException(); if (link.IsTransient())
{
return dbContext.Links.Add(link).Entity;
}
else
{
return link;
}
}
public async Task<Link> GetAsync(string shortCode)
{
var link = await dbContext.Links
.Where(l => l.ShortCode==shortCode)
.SingleOrDefaultAsync();
return link;
} }
} }
} }

View File

@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure", "Infrastru
EndProject EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "Docker\docker-compose.dcproj", "{67E556AA-3E56-4B78-9521-6A5ABED7EEEA}" Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "Docker\docker-compose.dcproj", "{67E556AA-3E56-4B78-9521-6A5ABED7EEEA}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F059136F-024F-4DB1-B4E0-FE7C31BC27E4}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU

View File

@@ -1,4 +1,5 @@
using FluentValidation; using Domain.Exceptions;
using FluentValidation;
using MediatR; using MediatR;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using QRCodeService.Extensions; using QRCodeService.Extensions;
@@ -11,11 +12,11 @@ namespace QRCodeService.Application.Behaviors
public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{ {
private readonly ILogger<ValidatorBehavior<TRequest, TResponse>> _logger; private readonly ILogger<ValidatorBehavior<TRequest, TResponse>> _logger;
private readonly IValidator<TRequest>[] _validators; private readonly IValidator<TRequest> _validator;
public ValidatorBehavior(IValidator<TRequest>[] validators, ILogger<ValidatorBehavior<TRequest, TResponse>> logger) public ValidatorBehavior(IValidator<TRequest> validator, ILogger<ValidatorBehavior<TRequest, TResponse>> logger)
{ {
_validators = validators; _validator = validator;
_logger = logger; _logger = logger;
} }
@@ -25,18 +26,14 @@ namespace QRCodeService.Application.Behaviors
_logger.LogInformation("----- Validating command {CommandType}", typeName); _logger.LogInformation("----- Validating command {CommandType}", typeName);
var failures = _validators var failures = _validator.Validate(request).Errors;
.Select(v => v.Validate(request))
.SelectMany(result => result.Errors)
.Where(error => error != null)
.ToList();
if (failures.Any()) if (failures.Any())
{ {
_logger.LogWarning("Validation errors - {CommandType} - Command: {@Command} - Errors: {@ValidationErrors}", typeName, request, failures); _logger.LogWarning("Validation errors - {CommandType} - Command: {@Command} - Errors: {@ValidationErrors}", typeName, request, failures);
//throw new OrderingDomainException( throw new DomainException(
// $"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures)); $"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
} }
return await next(); return await next();

View File

@@ -1,4 +1,5 @@
using MediatR; using Domain.AggregateModel.LinkAggregate;
using MediatR;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -7,8 +8,14 @@ using System.Threading.Tasks;
namespace QRCodeService.Application.Commands namespace QRCodeService.Application.Commands
{ {
public class CreateLinkCommand : IRequest<bool> public class CreateLinkCommand : IRequest<Link>
{ {
public int AppId { get; set; }
public string SuffixUrl { get; set; } public string SuffixUrl { get; set; }
public CreateLinkCommand(string suffixUrl, int appId)
{
SuffixUrl = suffixUrl;
AppId = appId;
}
} }
} }

View File

@@ -1,4 +1,7 @@
using MediatR; using Domain.AggregateModel.AppAggregate;
using Domain.AggregateModel.LinkAggregate;
using Domain.Exceptions;
using MediatR;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -8,11 +11,33 @@ using System.Threading.Tasks;
namespace QRCodeService.Application.Commands namespace QRCodeService.Application.Commands
{ {
public class CreateLinkCommandHandler : IRequestHandler<CreateLinkCommand, bool> public class CreateLinkCommandHandler : IRequestHandler<CreateLinkCommand, Link>
{ {
public Task<bool> Handle(CreateLinkCommand request, CancellationToken cancellationToken) readonly IAppRepository appRepository;
readonly ILinkRepository linkRepository;
public CreateLinkCommandHandler(ILinkRepository linkRepository, IAppRepository appRepository)
{ {
throw new NotImplementedException(); this.linkRepository = linkRepository;
this.appRepository = appRepository;
}
async Task<Link> IRequestHandler<CreateLinkCommand, Link>.Handle(CreateLinkCommand request, CancellationToken cancellationToken)
{
var app = await appRepository.GetAsync(request.AppId);
if (app == null)
{
throw new DomainException("app not found");
}
var link = new Link(app.BaseUrl, request.SuffixUrl, request.AppId);
var dbLink = await linkRepository.GetAsync(link.ShortCode);
if (dbLink != null)
{
throw new DomainException("url has been registed");
}
link = linkRepository.Add(link);
await linkRepository.UnitOfWork.SaveEntitiesAsync();
return link;
} }
} }
} }

View File

@@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dapper; using Dapper;
using MySqlConnector; using MySqlConnector;
using Microsoft.Extensions.Configuration;
namespace QRCodeService.Application.Queries namespace QRCodeService.Application.Queries
{ {
@@ -13,9 +14,9 @@ namespace QRCodeService.Application.Queries
{ {
readonly string _connectionString; readonly string _connectionString;
public LinkQueries(string connectionString) public LinkQueries(IConfiguration configuration)
{ {
_connectionString = connectionString; _connectionString = configuration.GetConnectionString("default");
} }
public async Task<Link> GetLinkAsync(string shortCode) public async Task<Link> GetLinkAsync(string shortCode)

View File

@@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QRCodeService.Controllers.Api
{
[Route("api/v1/[controller]")]
[ApiController]
public class AppController:ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok();
}
[HttpPost]
public IActionResult Create(object input)
{
return Ok();
}
}
}

View File

@@ -0,0 +1,46 @@
using Domain.AggregateModel.AppAggregate;
using Domain.AggregateModel.LinkAggregate;
using Microsoft.AspNetCore.Mvc;
using QRCodeService.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediatR;
using QRCodeService.Application.Queries;
using QRCodeService.Application.Commands;
namespace QRCodeService.Controllers.Api
{
[Route("api/v1/[controller]")]
[ApiController]
public class LinkController:ControllerBase
{
readonly IMediator mediator;
readonly ILinkQueries queries;
public LinkController(IMediator mediator, ILinkQueries queries)
{
this.mediator = mediator;
this.queries = queries;
}
[HttpGet]
public IActionResult Get()
{
return Ok();
}
[HttpPost]
public async Task<IActionResult> Create(CreateLinkModel input)
{
var command = new CreateLinkCommand(input.SuffixUrl,1);
var link = await mediator.Send(command);
if (link==null)
{
return BadRequest();
}
return Ok(link.ShortCode);
}
}
}

View File

@@ -1,15 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QRCodeService.Controllers
{
[Route("api/v1/[controller]")]
public class AppController:ControllerBase
{
}
}

View File

@@ -1,58 +0,0 @@
using Domain.AggregateModel.LinkAggregate;
using Microsoft.AspNetCore.Mvc;
using QRCodeService.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using Domain.AggregateModel.AppAggregate;
using Base62;
using QRCodeService.Extensions;
namespace QRCodeService.Controllers
{
/// <summary>
/// 生成二维码图片
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class GenController:ControllerBase
{
readonly ILinkRepository linkRepository;
readonly IAppRepository appRepository;
public GenController(ILinkRepository linkRepository, IAppRepository appRepository)
{
this.linkRepository = linkRepository;
this.appRepository = appRepository;
}
[HttpPost]
public async Task<IActionResult> CreateLink(GenInputModel model)
{
var app = await appRepository.GetAsync(model.AppId);
if (app == null)
{
return BadRequest();
}
using(var md5 = MD5.Create())
{
var result = md5.ComputeHash(Encoding.UTF8.GetBytes($"{model.AppId}{model.SuffixUrl}{model.Time}{app.AppKey}"));
var sign = BitConverter.ToString(result);
if (sign != model.Sign)
{
return BadRequest();
}
}
var shortCode = $"{model.SuffixUrl}".ToMD5().ToBase62();
var link = new Link(app.BaseUrl, model.SuffixUrl,1);
linkRepository.Add(link);
await linkRepository.UnitOfWork.SaveEntitiesAsync();
return Ok(link.ShortCode);
}
}
}

View File

@@ -1,30 +0,0 @@
using Domain.AggregateModel.LinkAggregate;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QRCodeService.Controllers
{
/// <summary>
/// 跳转url请求的地址
/// </summary>
[Route("{shortCode}")]
public class GoController: Controller
{
//readonly ILinkRepository LinkRepository;
//public GoController(ILinkRepository linkRepository)
//{
// LinkRepository = linkRepository;
//}
[HttpGet]
public async Task<IActionResult> Index(string shortcode)
{
var a = new { Url = "asdasd" };
//var link = await LinkRepository.GetAsync(shortcode);
return View(a);
}
}
}

View File

@@ -14,6 +14,7 @@ namespace QRCodeService.Controllers
public class ImageController : ControllerBase public class ImageController : ControllerBase
{ {
[Route("{shortCode}")] [Route("{shortCode}")]
[HttpGet]
public IActionResult Get(string shortCode) public IActionResult Get(string shortCode)
{ {
var qrCodeGenerator = new QRCodeGenerator(); var qrCodeGenerator = new QRCodeGenerator();

View File

@@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging;
namespace QRCodeService.Controllers namespace QRCodeService.Controllers
{ {
[Route("[controller]/[action]")] [Route("[controller]/[action]")]
[ApiController]
public class PlaygroundController:ControllerBase public class PlaygroundController:ControllerBase
{ {
private readonly ILogger<PlaygroundController> logger; private readonly ILogger<PlaygroundController> logger;
@@ -18,7 +19,7 @@ namespace QRCodeService.Controllers
{ {
this.logger = logger; this.logger = logger;
} }
[HttpGet]
public IActionResult GenShortCode(string url) public IActionResult GenShortCode(string url)
{ {
logger.LogInformation("duduledule"); logger.LogInformation("duduledule");

View File

@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Mvc;
using QRCodeService.Application.Queries;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QRCodeService.Controllers
{
[Route("{shortCode}")]
public class RedirectController:Controller
{
private readonly ILinkQueries queries;
public RedirectController(ILinkQueries queries)
{
this.queries = queries;
}
[HttpGet]
public async Task<IActionResult> Index(string shortCode)
{
var link = await queries.GetLinkAsync(shortCode);
return View(link);
}
}
}

View File

@@ -1,73 +0,0 @@
// <auto-generated />
using System;
using Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace QRCodeService.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20210224014442_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 64)
.HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("Domain.AggregateModel.AppAggregate.App", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("AppKey")
.HasColumnType("longtext");
b.Property<string>("BaseUrl")
.HasColumnType("longtext");
b.Property<string>("Remarks")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("Apps");
});
modelBuilder.Entity("Domain.AggregateModel.LinkAggregate.Link", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("AppId")
.HasColumnType("int");
b.Property<string>("BaseUrl")
.HasColumnType("longtext");
b.Property<string>("FullUrl")
.HasColumnType("longtext");
b.Property<string>("ShortCode")
.HasColumnType("longtext");
b.Property<string>("SuffixUrl")
.HasColumnType("longtext");
b.Property<DateTime>("Time")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.ToTable("Links");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,72 +0,0 @@
// <auto-generated />
using System;
using Infrastructure;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace QRCodeService.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20210224015439_AddConfiguration")]
partial class AddConfiguration
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 64)
.HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("Domain.AggregateModel.AppAggregate.App", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("AppKey")
.HasColumnType("longtext");
b.Property<string>("BaseUrl")
.HasColumnType("longtext");
b.Property<string>("Remarks")
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("App");
});
modelBuilder.Entity("Domain.AggregateModel.LinkAggregate.Link", b =>
{
b.Property<string>("ShortCode")
.HasColumnType("varchar(255)");
b.Property<int>("AppId")
.HasColumnType("int");
b.Property<string>("BaseUrl")
.HasColumnType("longtext");
b.Property<string>("FullUrl")
.HasColumnType("longtext");
b.Property<int>("Id")
.HasColumnType("int");
b.Property<string>("SuffixUrl")
.HasColumnType("longtext");
b.Property<DateTime>("Time")
.HasColumnType("datetime(6)");
b.HasKey("ShortCode");
b.ToTable("Link");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -1,102 +0,0 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
namespace QRCodeService.Migrations
{
public partial class AddConfiguration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_Links",
table: "Links");
migrationBuilder.DropPrimaryKey(
name: "PK_Apps",
table: "Apps");
migrationBuilder.RenameTable(
name: "Links",
newName: "Link");
migrationBuilder.RenameTable(
name: "Apps",
newName: "App");
migrationBuilder.AlterColumn<string>(
name: "ShortCode",
table: "Link",
type: "varchar(255)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "longtext",
oldNullable: true);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "Link",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AddPrimaryKey(
name: "PK_Link",
table: "Link",
column: "ShortCode");
migrationBuilder.AddPrimaryKey(
name: "PK_App",
table: "App",
column: "Id");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_Link",
table: "Link");
migrationBuilder.DropPrimaryKey(
name: "PK_App",
table: "App");
migrationBuilder.RenameTable(
name: "Link",
newName: "Links");
migrationBuilder.RenameTable(
name: "App",
newName: "Apps");
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "Links",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<string>(
name: "ShortCode",
table: "Links",
type: "longtext",
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(255)");
migrationBuilder.AddPrimaryKey(
name: "PK_Links",
table: "Links",
column: "Id");
migrationBuilder.AddPrimaryKey(
name: "PK_Apps",
table: "Apps",
column: "Id");
}
}
}

View File

@@ -1,80 +0,0 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
namespace QRCodeService.Migrations
{
public partial class SetProperty : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_Link",
table: "Link");
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "Link",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AlterColumn<string>(
name: "ShortCode",
table: "Link",
type: "varchar(11)",
maxLength: 11,
nullable: true,
oldClrType: typeof(string),
oldType: "varchar(255)");
migrationBuilder.AddPrimaryKey(
name: "PK_Link",
table: "Link",
column: "Id");
migrationBuilder.CreateIndex(
name: "IX_Link_ShortCode",
table: "Link",
column: "ShortCode",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "PK_Link",
table: "Link");
migrationBuilder.DropIndex(
name: "IX_Link_ShortCode",
table: "Link");
migrationBuilder.AlterColumn<string>(
name: "ShortCode",
table: "Link",
type: "varchar(255)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "varchar(11)",
oldMaxLength: 11,
oldNullable: true);
migrationBuilder.AlterColumn<int>(
name: "Id",
table: "Link",
type: "int",
nullable: false,
oldClrType: typeof(int),
oldType: "int")
.OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn);
migrationBuilder.AddPrimaryKey(
name: "PK_Link",
table: "Link",
column: "ShortCode");
}
}
}

View File

@@ -9,8 +9,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace QRCodeService.Migrations namespace QRCodeService.Migrations
{ {
[DbContext(typeof(AppDbContext))] [DbContext(typeof(AppDbContext))]
[Migration("20210224015858_SetProperty")] [Migration("20210224065420_init")]
partial class SetProperty partial class init
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
{ {

View File

@@ -4,12 +4,12 @@ using Microsoft.EntityFrameworkCore.Migrations;
namespace QRCodeService.Migrations namespace QRCodeService.Migrations
{ {
public partial class InitialCreate : Migration public partial class init : Migration
{ {
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Apps", name: "App",
columns: table => new columns: table => new
{ {
Id = table.Column<int>(type: "int", nullable: false) Id = table.Column<int>(type: "int", nullable: false)
@@ -20,16 +20,16 @@ namespace QRCodeService.Migrations
}, },
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_Apps", x => x.Id); table.PrimaryKey("PK_App", x => x.Id);
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Links", name: "Link",
columns: table => new columns: table => new
{ {
Id = table.Column<int>(type: "int", nullable: false) Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
ShortCode = table.Column<string>(type: "longtext", nullable: true), ShortCode = table.Column<string>(type: "varchar(11)", maxLength: 11, nullable: true),
BaseUrl = table.Column<string>(type: "longtext", nullable: true), BaseUrl = table.Column<string>(type: "longtext", nullable: true),
SuffixUrl = table.Column<string>(type: "longtext", nullable: true), SuffixUrl = table.Column<string>(type: "longtext", nullable: true),
FullUrl = table.Column<string>(type: "longtext", nullable: true), FullUrl = table.Column<string>(type: "longtext", nullable: true),
@@ -38,17 +38,23 @@ namespace QRCodeService.Migrations
}, },
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_Links", x => x.Id); table.PrimaryKey("PK_Link", x => x.Id);
}); });
migrationBuilder.CreateIndex(
name: "IX_Link_ShortCode",
table: "Link",
column: "ShortCode",
unique: true);
} }
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Apps"); name: "App");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Links"); name: "Link");
} }
} }
} }

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace QRCodeService.Models
{
public class CreateLinkModel
{
public string SuffixUrl { get; set; }
public string Time { get; set; }
}
}

View File

@@ -1,4 +1,9 @@
using Domain.AggregateModel.AppAggregate;
using Domain.AggregateModel.LinkAggregate;
using FluentValidation;
using FluentValidation.AspNetCore;
using Infrastructure; using Infrastructure;
using Infrastructure.Repositories;
using MediatR; using MediatR;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@@ -12,6 +17,9 @@ using Microsoft.OpenApi.Models;
using Pomelo.EntityFrameworkCore.MySql; using Pomelo.EntityFrameworkCore.MySql;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure; using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
using QRCodeService.Application.Behaviors; using QRCodeService.Application.Behaviors;
using QRCodeService.Application.Commands;
using QRCodeService.Application.Queries;
using QRCodeService.Application.Validations;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -38,12 +46,14 @@ namespace QRCodeService
{ {
c.SwaggerDoc("v1", new OpenApiInfo { Title = "QRCodeService", Version = "v1" }); c.SwaggerDoc("v1", new OpenApiInfo { Title = "QRCodeService", Version = "v1" });
}); });
//MediatR //validator
services.AddMediatR(Assembly.GetExecutingAssembly()); services.AddTransient<IValidator<CreateLinkCommand>, CreateLinkCommandValidator>();
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(TransactionBehaviour<,>));
//MediatR+
services.AddMediatR(Assembly.GetExecutingAssembly())
.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>))
.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorBehavior<,>))
.AddTransient(typeof(IPipelineBehavior<,>), typeof(TransactionBehaviour<,>));
//EFCore //EFCore
services.AddDbContext<AppDbContext>( services.AddDbContext<AppDbContext>(
dbContextOptions => dbContextOptions dbContextOptions => dbContextOptions
@@ -57,6 +67,12 @@ namespace QRCodeService
.EnableSensitiveDataLogging() .EnableSensitiveDataLogging()
.EnableDetailedErrors() .EnableDetailedErrors()
); );
//Repository
services.AddScoped<IAppRepository, AppRepository>();
services.AddScoped<ILinkRepository, LinkRepository>();
services.AddScoped<ILinkQueries, LinkQueries>();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@@ -7,6 +7,9 @@
} }
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"ConnectionStrings": {
"default": "server=localhost;user=root;password=root;database=qrcode"
},
"Serilog": { "Serilog": {
"Using": [ "SeriLog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.Async" ], "Using": [ "SeriLog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.Async" ],
"MinimumLevel": { "MinimumLevel": {