add configs
parent
be609347ed
commit
07e19e7118
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"Postgres": "User ID=postgres;Password=root;Host=localhost;Port=5432;Database=iGarsonDB;",
|
||||
"PostgresServer": "Host=pg-0,pg-1;Username=igarsonAgent;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=BrizcoDB;Load Balance Hosts=true;Target Session Attributes=primary;Application Name=iGLS"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "None",
|
||||
"Microsoft.Hosting.Lifetime": "Information",
|
||||
"Microsoft.AspNetCore.SignalR": "Debug",
|
||||
"Microsoft.AspNetCore.Http.Connections": "Debug"
|
||||
}
|
||||
},
|
||||
"SiteSettings": {
|
||||
"BaseUrl": "http://localhost:32769",
|
||||
"UserSetting": {
|
||||
"Username": "Root",
|
||||
"Email": "info@brizco.io",
|
||||
"Password": "root1234",
|
||||
"Phone": "09211111111",
|
||||
"RoleName": "RootAdmin",
|
||||
"FirstName": "همه کاره",
|
||||
"LastName": "سیستم"
|
||||
},
|
||||
"JwtSettings": {
|
||||
"SecretKey": "pg8mt74/bk5yx2mr23Zvsu/81Z2czAycEo9ewcm34AndD8SFDXGqBiYv_YaHosseinYaAli_ABOOOOOOOOOLFAZL_BIMEH_JAD_NASABE_YA_GHARIBAL_GHORABA_@@@@_06/0CZWyAqy2H6Xpjp0npg8mt74/bk5yx2mr23Zvsu/81Z2czAycEo9ewcm34AndD8SFDXGqBiYvACLB0dED9vjy+h5sK1BnB30=",
|
||||
"Issuer": "Brizco",
|
||||
"Audience": "Brizco",
|
||||
"ExpireAddDay": "15"
|
||||
}
|
||||
},
|
||||
"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": "1m",
|
||||
"Limit": 60
|
||||
},
|
||||
{
|
||||
"Endpoint": "*",
|
||||
"Period": "15m",
|
||||
"Limit": 250
|
||||
}
|
||||
]
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"ConnectionStrings": {
|
||||
"Postgres": "User ID=postgres;Password=root;Host=localhost;Port=5432;Database=iGarsonDB;",
|
||||
"PostgresServer": "Host=pg-0,pg-1;Username=igarsonAgent;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=BrizcoDB;Load Balance Hosts=true;Target Session Attributes=primary;Application Name=iGLS",
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "None",
|
||||
"Microsoft.Hosting.Lifetime": "Information",
|
||||
"Microsoft.AspNetCore.SignalR": "Debug",
|
||||
"Microsoft.AspNetCore.Http.Connections": "Debug"
|
||||
}
|
||||
},
|
||||
"SiteSettings": {
|
||||
"BaseUrl": "http://localhost:32769",
|
||||
"UserSetting": {
|
||||
"Username": "root",
|
||||
"Email": "info@documed.ir",
|
||||
"Password": "i1nLGN86rU/HQgzC",
|
||||
"Phone": "09211111111",
|
||||
"RoleName": "RootAdmin",
|
||||
"FirstName": "همه کاره",
|
||||
"LastName": "سیستم"
|
||||
},
|
||||
"JwtSettings": {
|
||||
"SecretKey": "YaHosseinYaAli_pg8mt74/bk5yx2mr23Zvsu/81Z2czAycEo9ewcm34AndD8SFDXGqBiYv_ABOOOOOOOOOLFAZL_BIMEH_JAD_NASABE_pg8mt74/bk5yx2mr23Zvsu/81Z2czAycEo9ewcm34AndD8SFDXGqBiYv_YA_GHARIBAL_GHORABA_@@@@_06/0CZWyAqy2H6Xpjp0npg8mt74/bk5yx2mr23Zvsu/81Z2czAycEo9ewcm34AndD8SFDXGqBiYvACLB0dED9vjy+h5sK1BnB30=",
|
||||
"Issuer": "Brizco",
|
||||
"Audience": "Brizco",
|
||||
"ExpireAddDay": "15"
|
||||
}
|
||||
},
|
||||
"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": "1m",
|
||||
"Limit": 60
|
||||
},
|
||||
{
|
||||
"Endpoint": "*",
|
||||
"Period": "15m",
|
||||
"Limit": 250
|
||||
}
|
||||
]
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
|
@ -53,4 +53,39 @@
|
|||
<ProjectReference Include="..\DocuMed.Infrastructure\DocuMed.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Autofac" />
|
||||
<Using Include="Autofac.Extensions.DependencyInjection" />
|
||||
<Using Include="Carter" />
|
||||
<Using Include="DocuMed.Api.WebFramework.Configurations" />
|
||||
<Using Include="DocuMed.Api.WebFramework.Swagger" />
|
||||
<Using Include="DocuMed.Common.Extensions" />
|
||||
<Using Include="DocuMed.Common.Models" />
|
||||
<Using Include="DocuMed.Common.Models.Api" />
|
||||
<Using Include="DocuMed.Common.Models.Entity" />
|
||||
<Using Include="DocuMed.Common.Models.Exception" />
|
||||
<Using Include="DocuMed.Common.Models.Mapper" />
|
||||
<Using Include="DocuMed.Core" />
|
||||
<Using Include="DocuMed.Core.Models.Api" />
|
||||
<Using Include="DocuMed.Domain" />
|
||||
<Using Include="DocuMed.Domain.Entities.User" />
|
||||
<Using Include="DocuMed.Domain.Models.Settings" />
|
||||
<Using Include="DocuMed.Infrastructure" />
|
||||
<Using Include="DocuMed.Infrastructure.Models" />
|
||||
<Using Include="DocuMed.Repository" />
|
||||
<Using Include="DocuMed.Repository.Abstracts" />
|
||||
<Using Include="DocuMed.Repository.Extensions" />
|
||||
<Using Include="DocuMed.Repository.Models" />
|
||||
<Using Include="DocuMed.Repository.Repositories.Base.Contracts" />
|
||||
<Using Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
|
||||
<Using Include="Microsoft.AspNetCore.Identity" />
|
||||
<Using Include="Microsoft.AspNetCore.Mvc" />
|
||||
<Using Include="Microsoft.AspNetCore.Mvc.Filters" />
|
||||
<Using Include="Microsoft.Extensions.Options" />
|
||||
<Using Include="Serilog" />
|
||||
<Using Include="Serilog.Events" />
|
||||
<Using Include="Serilog.Sinks.SystemConsole.Themes" />
|
||||
<Using Include="System.Security.Claims" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,23 +1,96 @@
|
|||
using DocuMed.Api.WebFramework.MiddleWares;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
|
||||
builder.Host.UseSerilog();
|
||||
LoggerConfig.ConfigureSerilog();
|
||||
string env = builder.Environment.IsDevelopment() == true ? "Development" : "Production";
|
||||
builder.Host.UseContentRoot(Directory.GetCurrentDirectory());
|
||||
|
||||
if (builder.Environment.IsDevelopment())
|
||||
builder.Configuration
|
||||
.AddJsonFile($"AppSettings/appsettings.json")
|
||||
.AddJsonFile($"AppSettings/appsettings.{env}.json");
|
||||
|
||||
if (builder.Environment.IsProduction())
|
||||
builder.Configuration
|
||||
.AddJsonFile($"AppSettings/Production/appsettings.{env}.json");
|
||||
var configuration = builder.Configuration;
|
||||
var siteSetting = configuration.GetSection(nameof(SiteSettings)).Get<SiteSettings>();
|
||||
builder.Services.Configure<SiteSettings>(configuration.GetSection(nameof(SiteSettings)));
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
builder.Services.AddCustomSwagger(siteSetting.BaseUrl);
|
||||
builder.Services.AddCustomApiVersioning();
|
||||
builder.Services.AddCustomController();
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddCustomResponseCompression();
|
||||
builder.Services.AddCustomMvc();
|
||||
builder.Services.AddCustomAuthorization();
|
||||
builder.Services.AddJwtCustomAuthentication(siteSetting.JwtSettings);
|
||||
builder.Services.AddCustomIdentity();
|
||||
builder.Services.AddCustomDbContext(configuration);
|
||||
builder.Services.AddCarter();
|
||||
|
||||
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
|
||||
{
|
||||
|
||||
var assembly = typeof(CoreConfig).Assembly;
|
||||
builder
|
||||
.RegisterAssemblyTypes(assembly)
|
||||
.AssignableTo<IScopedDependency>()
|
||||
.AsImplementedInterfaces()
|
||||
.InstancePerLifetimeScope();
|
||||
|
||||
var assemblyB = typeof(InfrastructureConfig).Assembly;
|
||||
builder.RegisterAssemblyTypes(assemblyB)
|
||||
.AssignableTo<IScopedDependency>()
|
||||
.AsImplementedInterfaces()
|
||||
.InstancePerLifetimeScope();
|
||||
|
||||
var assemblyC = typeof(RepositoryConfig).Assembly;
|
||||
builder.RegisterAssemblyTypes(assemblyC)
|
||||
.AssignableTo<IScopedDependency>()
|
||||
.AsImplementedInterfaces()
|
||||
.InstancePerLifetimeScope();
|
||||
|
||||
|
||||
var assemblyD = typeof(Program).Assembly;
|
||||
builder.RegisterAssemblyTypes(assemblyD)
|
||||
.AssignableTo<IScopedDependency>()
|
||||
.AsImplementedInterfaces()
|
||||
.InstancePerLifetimeScope();
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseCustomSwagger(siteSetting.BaseUrl);
|
||||
//app.UseSwagger();
|
||||
//app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseAuthorization();
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseCors(x => x
|
||||
.SetIsOriginAllowed(origin => true)
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials());
|
||||
|
||||
app.UseExceptionHandlerMiddleware();
|
||||
|
||||
app.MapCarter();
|
||||
app.UseStaticFiles();
|
||||
await app.InitialDb();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
namespace DocuMed.Api.Services;
|
||||
|
||||
public class CurrentUserService : ICurrentUserService
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public CurrentUserService(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public string? UserId => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
public string? RoleName => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Role);
|
||||
public string? UserName => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name);
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
namespace DocuMed.Api.WebFramework.Bases;
|
||||
|
||||
public class ApiResultFactory
|
||||
{
|
||||
|
||||
}
|
||||
public class ApiResultFilterAttribute : ActionFilterAttribute
|
||||
{
|
||||
public override void OnResultExecuting(ResultExecutingContext context)
|
||||
{
|
||||
if (context.Result is OkObjectResult okObjectResult)
|
||||
{
|
||||
var apiResult = new ApiResult<object>(true, ApiResultStatusCode.Success, okObjectResult.Value);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = okObjectResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is OkResult okResult)
|
||||
{
|
||||
var apiResult = new ApiResult(true, ApiResultStatusCode.Success);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = okResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is BadRequestResult badRequestResult)
|
||||
{
|
||||
var apiResult = new ApiResult(false, ApiResultStatusCode.BadRequest);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = badRequestResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is BadRequestObjectResult badRequestObjectResult)
|
||||
{
|
||||
var message = badRequestObjectResult.Value.ToString();
|
||||
|
||||
if (badRequestObjectResult.Value is SerializableError errors)
|
||||
{
|
||||
var errorMessages = errors.SelectMany(p => (string[])p.Value).Distinct();
|
||||
message = string.Join(" | ", errorMessages);
|
||||
}
|
||||
|
||||
if (badRequestObjectResult.Value is ValidationProblemDetails problemDetails)
|
||||
{
|
||||
var errorMessages = problemDetails.Errors.Values.SelectMany(v => v);
|
||||
message = string.Join(" | ", errorMessages);
|
||||
}
|
||||
|
||||
var apiResult = new ApiResult(false, ApiResultStatusCode.BadRequest, message);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = badRequestObjectResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is ContentResult contentResult)
|
||||
{
|
||||
var apiResult = new ApiResult(true, ApiResultStatusCode.Success, contentResult.Content);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = contentResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is NotFoundResult notFoundResult)
|
||||
{
|
||||
var apiResult = new ApiResult(false, ApiResultStatusCode.NotFound);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = notFoundResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is NotFoundObjectResult notFoundObjectResult)
|
||||
{
|
||||
var apiResult = new ApiResult<object>(false, ApiResultStatusCode.NotFound, notFoundObjectResult.Value);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = notFoundObjectResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is ObjectResult objectResult && objectResult.StatusCode == null
|
||||
&& !(objectResult.Value is ApiResult))
|
||||
{
|
||||
var apiResult = new ApiResult<object>(true, ApiResultStatusCode.Success, objectResult.Value);
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = objectResult.StatusCode };
|
||||
}
|
||||
else if (context.Result is ObjectResult objectResultBad && objectResultBad.Value is ApiResult)
|
||||
{
|
||||
var apiResult = objectResultBad.Value as ApiResult;
|
||||
context.Result = new JsonResult(apiResult) { StatusCode = objectResultBad.StatusCode };
|
||||
}
|
||||
|
||||
base.OnResultExecuting(context);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using System.Net;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace DocuMed.Api.WebFramework.Bases;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class ClaimRequirement : AuthorizeAttribute, IAuthorizationFilter
|
||||
{
|
||||
private readonly string _claimsType;
|
||||
private readonly string _claimsValue;
|
||||
|
||||
public ClaimRequirement(string type,string value)
|
||||
{
|
||||
type = value;
|
||||
}
|
||||
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
var user = context.HttpContext.User;
|
||||
var permissions = user.Claims?.Where(c => c.Type == _claimsType)?.ToList();
|
||||
if (permissions == null)
|
||||
{
|
||||
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isAccepted = permissions.FirstOrDefault(p => p.Value == _claimsValue) != null;
|
||||
if (!isAccepted)
|
||||
context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
using System.Linq.Expressions;
|
||||
using Mapster;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DocuMed.Api.WebFramework.Bases;
|
||||
|
||||
|
||||
public class CrudEndpoint<TEntity,TGetAllQuery,TGetOneQuery,TCreateCommand,TUpdateCommand,TDeleteCommand> where TEntity : ApiEntity, new()
|
||||
{
|
||||
private readonly string _endpointName;
|
||||
|
||||
public CrudEndpoint(string endpointName)
|
||||
{
|
||||
_endpointName = endpointName;
|
||||
}
|
||||
|
||||
public virtual void AddRoutes(IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.NewVersionedApi(_endpointName).MapGroup($"api/{_endpointName}");
|
||||
|
||||
group.MapGet("", GetAllAsync)
|
||||
.WithDisplayName("GetAll")
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapGet("{id}", GetAsync)
|
||||
.WithName("GetOne")
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapPost("", Post)
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapPut("", Put)
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapDelete("", Delete)
|
||||
.HasApiVersion(1.0);
|
||||
}
|
||||
|
||||
// GET:Get All Entity
|
||||
public virtual async Task<IResult> GetAllAsync(ISender sender , CancellationToken cancellationToken)
|
||||
{
|
||||
var res = sender.Send(Activator.CreateInstance<TGetAllQuery>(),cancellationToken);
|
||||
return TypedResults.Ok(res);
|
||||
}
|
||||
|
||||
// GET:Get An Entity By Id
|
||||
public async Task<IResult> GetAsync(Guid id, ISender sender, CancellationToken cancellationToken)
|
||||
=> TypedResults.Ok(sender.Send(Activator.CreateInstance<TGetOneQuery>()));
|
||||
|
||||
// POST:Create Entity
|
||||
public virtual async Task<IResult> Post([FromBody] TCreateCommand ent , ISender mediator , CancellationToken cancellationToken)
|
||||
{
|
||||
return TypedResults.Ok(await mediator.Send(ent, cancellationToken));
|
||||
}
|
||||
|
||||
// PUT:Update Entity
|
||||
public virtual async Task<IResult> Put([FromBody] TEntity ent , IRepositoryWrapper _repositoryWrapper, CancellationToken cancellationToken)
|
||||
{
|
||||
_repositoryWrapper.SetRepository<TEntity>().Update(ent);
|
||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return TypedResults.Ok();
|
||||
}
|
||||
|
||||
// DELETE:Delete Entity
|
||||
public virtual async Task<IResult> Delete(Guid id,IRepositoryWrapper _repositoryWrapper, CancellationToken cancellationToken)
|
||||
{
|
||||
var ent = await _repositoryWrapper.SetRepository<TEntity>().GetByIdAsync(cancellationToken, id);
|
||||
_repositoryWrapper.SetRepository<TEntity>().Delete(ent);
|
||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return TypedResults.Ok();
|
||||
}
|
||||
}
|
||||
|
||||
[ApiController]
|
||||
//[AllowAnonymous]
|
||||
[ApiResultFilter]
|
||||
[Route("api/v{version:apiVersion}/[controller]")] // api/v1/[controller]
|
||||
public class BaseController : ControllerBase
|
||||
{
|
||||
//public UserRepository UserRepository { get; set; } => property injection
|
||||
public bool UserIsAutheticated => HttpContext.User.Identity.IsAuthenticated;
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = "Bearer")]
|
||||
public class CrudController<TDto, TEntity> : BaseController
|
||||
where TDto : BaseDto<TDto, TEntity>, new()
|
||||
where TEntity : ApiEntity, new()
|
||||
{
|
||||
protected readonly IRepositoryWrapper _repositoryWrapper;
|
||||
|
||||
public CrudController(IRepositoryWrapper repositoryWrapper)
|
||||
{
|
||||
_repositoryWrapper = repositoryWrapper;
|
||||
}
|
||||
|
||||
// GET:Get All Entity
|
||||
[HttpGet]
|
||||
public virtual async Task<IActionResult> GetAllAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var projectTo = typeof(TDto).BaseType?.GetProperty("ProjectToDto")?.GetValue(null, null);
|
||||
if (projectTo != null)
|
||||
{
|
||||
var exprss = projectTo as Expression<Func<TEntity, TDto>>;
|
||||
var entites = await _repositoryWrapper
|
||||
.SetRepository<TEntity>()
|
||||
.TableNoTracking
|
||||
.Select(exprss)
|
||||
.ToListAsync(cancellationToken);
|
||||
return Ok(entites);
|
||||
}
|
||||
|
||||
throw new BaseApiException("ProjectTo Not Found");
|
||||
}
|
||||
|
||||
// GET:Get An Entity By Id
|
||||
[HttpGet("{id}")]
|
||||
public virtual async Task<IActionResult> GetAsync(string id, CancellationToken cancellationToken)
|
||||
{
|
||||
var ent = await _repositoryWrapper.SetRepository<TEntity>().GetByIdAsync(cancellationToken, id);
|
||||
var dto = ent.Adapt<TDto>();
|
||||
return Ok(dto);
|
||||
}
|
||||
|
||||
// POST:Add New Entity
|
||||
[HttpPost]
|
||||
public virtual async Task<IActionResult> PostOrginal([FromBody] TEntity ent, CancellationToken cancellationToken)
|
||||
{
|
||||
_repositoryWrapper.SetRepository<TEntity>().Add(ent);
|
||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return Ok(ent);
|
||||
}
|
||||
|
||||
// POST:Add New Entity By Dto
|
||||
[HttpPost("Dto")]
|
||||
public async Task<IActionResult> PostDto([FromBody] TDto dto, CancellationToken cancellationToken)
|
||||
{
|
||||
_repositoryWrapper
|
||||
.SetRepository<TEntity>()
|
||||
.Add(dto.ToEntity());
|
||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// PUT:Update Entity
|
||||
[HttpPut]
|
||||
public virtual async Task<IActionResult> Put([FromBody] TEntity ent, CancellationToken cancellationToken)
|
||||
{
|
||||
_repositoryWrapper
|
||||
.SetRepository<TEntity>()
|
||||
.Update(ent);
|
||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// DELETE:Delete Entity
|
||||
[HttpDelete]
|
||||
[Route("{id:int}")]
|
||||
public virtual async Task<IActionResult> Delete(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
var ent = await _repositoryWrapper
|
||||
.SetRepository<TEntity>()
|
||||
.GetByIdAsync(cancellationToken, id);
|
||||
_repositoryWrapper.SetRepository<TEntity>().Delete(ent);
|
||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize(AuthenticationSchemes = "Bearer")]
|
||||
public class CrudController<TEntity> : BaseController
|
||||
where TEntity : ApiEntity, new()
|
||||
{
|
||||
protected readonly IRepositoryWrapper _repositoryWrapper;
|
||||
|
||||
public CrudController(IRepositoryWrapper repositoryWrapper)
|
||||
{
|
||||
_repositoryWrapper = repositoryWrapper;
|
||||
}
|
||||
|
||||
// GET:Get All Entity
|
||||
[HttpGet]
|
||||
public virtual async Task<IActionResult> GetAllAsync()
|
||||
{
|
||||
return Ok(await _repositoryWrapper.SetRepository<TEntity>().TableNoTracking.ToListAsync());
|
||||
}
|
||||
|
||||
// GET:Get An Entity By Id
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetAsync(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
var ent = await _repositoryWrapper.SetRepository<TEntity>().GetByIdAsync(cancellationToken, id);
|
||||
return Ok(ent);
|
||||
}
|
||||
|
||||
// POST:Add New Entity
|
||||
[HttpPost]
|
||||
public virtual async Task<IActionResult> Post([FromBody] TEntity ent, CancellationToken cancellationToken)
|
||||
{
|
||||
_repositoryWrapper.SetRepository<TEntity>().Add(ent);
|
||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return Ok(ent);
|
||||
}
|
||||
|
||||
// PUT:Update Entity
|
||||
[HttpPut]
|
||||
public virtual async Task<IActionResult> Put([FromBody] TEntity ent, CancellationToken cancellationToken)
|
||||
{
|
||||
_repositoryWrapper.SetRepository<TEntity>().Update(ent);
|
||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// DELETE:Delete Entity
|
||||
[HttpDelete("{id}")]
|
||||
public virtual async Task<IActionResult> Delete(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
var ent = await _repositoryWrapper.SetRepository<TEntity>().GetByIdAsync(cancellationToken, id);
|
||||
_repositoryWrapper.SetRepository<TEntity>().Delete(ent);
|
||||
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
namespace DocuMed.Api.WebFramework.Configurations;
|
||||
|
||||
public class ConfigureJwtBearerOptions : IPostConfigureOptions<JwtBearerOptions>
|
||||
{
|
||||
public void PostConfigure(string name, JwtBearerOptions options)
|
||||
{
|
||||
var originalOnMessageReceived = options.Events.OnMessageReceived;
|
||||
options.Events.OnMessageReceived = async context =>
|
||||
{
|
||||
await originalOnMessageReceived(context);
|
||||
|
||||
if (string.IsNullOrEmpty(context.Token))
|
||||
{
|
||||
var accessToken = context.Request.Query["access_token"];
|
||||
var path = context.HttpContext.Request.Path;
|
||||
|
||||
if (!string.IsNullOrEmpty(accessToken)) context.Token = accessToken;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
namespace DocuMed.Api.WebFramework.Configurations;
|
||||
|
||||
public static class LoggerConfig
|
||||
{
|
||||
public static void ConfigureSerilog()
|
||||
{
|
||||
var logName = $"{DirectoryAddress.Logs}/Log_Server_.log";
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console(theme: AnsiConsoleTheme.Literate)
|
||||
.WriteTo.Sentry(o =>
|
||||
{
|
||||
o.MinimumEventLevel = LogEventLevel.Error;
|
||||
o.Dsn = "https://592b7fbb29464442a8e996247abe857f@watcher.igarson.app/7";
|
||||
})
|
||||
.MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Warning)
|
||||
.CreateLogger();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
namespace DocuMed.Api.WebFramework.Configurations;
|
||||
|
||||
public class PersianIdentityErrorDescriber : IdentityErrorDescriber
|
||||
{
|
||||
public override IdentityError DefaultError()
|
||||
{
|
||||
return new IdentityError { Code = nameof(DefaultError), Description = "ارور ناشناخته ای رخ داده است" };
|
||||
}
|
||||
|
||||
public override IdentityError ConcurrencyFailure()
|
||||
{
|
||||
return new IdentityError
|
||||
{ Code = nameof(ConcurrencyFailure), Description = "در درخواست شما تداخلی ایجاد شده است" };
|
||||
}
|
||||
|
||||
public override IdentityError PasswordMismatch()
|
||||
{
|
||||
return new IdentityError { Code = nameof(PasswordMismatch), Description = "رمز عبور اشتباه است" };
|
||||
}
|
||||
|
||||
public override IdentityError InvalidToken()
|
||||
{
|
||||
return new IdentityError { Code = nameof(InvalidToken), Description = "توکن ارسالی اشتباه است" };
|
||||
}
|
||||
|
||||
public override IdentityError LoginAlreadyAssociated()
|
||||
{
|
||||
return new IdentityError
|
||||
{ Code = nameof(LoginAlreadyAssociated), Description = "یوزری با این مشخصات در حال حاضر لاگین کرده است" };
|
||||
}
|
||||
|
||||
public override IdentityError InvalidUserName(string userName)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(InvalidUserName),
|
||||
Description = $"یوزر نیم '{userName}' صحیح نمی باشد فقط می توانید از حروف و اعداد استفاده کنید"
|
||||
};
|
||||
}
|
||||
|
||||
public override IdentityError InvalidEmail(string email)
|
||||
{
|
||||
return new IdentityError { Code = nameof(InvalidEmail), Description = $"ایمیل '{email}' صحیح نمی باشد" };
|
||||
}
|
||||
|
||||
public override IdentityError DuplicateUserName(string userName)
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(DuplicateUserName),
|
||||
Description = $"یوزرنیم '{userName}' قبلا توسط اکانت دیگری استفاده شده است"
|
||||
};
|
||||
}
|
||||
|
||||
public override IdentityError DuplicateEmail(string email)
|
||||
{
|
||||
return new IdentityError
|
||||
{ Code = nameof(DuplicateEmail), Description = $"ایمیل '{email}' قبل استفاده شده است" };
|
||||
}
|
||||
|
||||
public override IdentityError InvalidRoleName(string role)
|
||||
{
|
||||
return new IdentityError { Code = nameof(InvalidRoleName), Description = $"نقش '{role}' موجود نمی باشد" };
|
||||
}
|
||||
|
||||
public override IdentityError DuplicateRoleName(string role)
|
||||
{
|
||||
return new IdentityError
|
||||
{ Code = nameof(DuplicateRoleName), Description = $"نقش '{role}' قبلا برای این کاربر استفاده شده است" };
|
||||
}
|
||||
|
||||
public override IdentityError UserAlreadyHasPassword()
|
||||
{
|
||||
return new IdentityError
|
||||
{ Code = nameof(UserAlreadyHasPassword), Description = "کاربر قبلا رمز عبوری را استفاده کرده است" };
|
||||
}
|
||||
|
||||
public override IdentityError UserLockoutNotEnabled()
|
||||
{
|
||||
return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "کاربر مورد نظر قفل شده است" };
|
||||
}
|
||||
|
||||
public override IdentityError UserAlreadyInRole(string role)
|
||||
{
|
||||
return new IdentityError
|
||||
{ Code = nameof(UserAlreadyInRole), Description = "نشق مورد نظر برای این کاربر استفاده شده است" };
|
||||
}
|
||||
|
||||
public override IdentityError UserNotInRole(string role)
|
||||
{
|
||||
return new IdentityError { Code = nameof(UserNotInRole), Description = $"کاربر مورد نظر در نقش '{role}' نیست" };
|
||||
}
|
||||
|
||||
public override IdentityError PasswordTooShort(int length)
|
||||
{
|
||||
return new IdentityError
|
||||
{ Code = nameof(PasswordTooShort), Description = $"پسورد حداقل باید {length} کاراکتر باشد" };
|
||||
}
|
||||
|
||||
public override IdentityError PasswordRequiresNonAlphanumeric()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresNonAlphanumeric),
|
||||
Description = "رمز عبور باید حداقل یک کاراکتر غیر عددی داشته باشد"
|
||||
};
|
||||
}
|
||||
|
||||
public override IdentityError PasswordRequiresDigit()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresDigit), Description = "پسور مورد نظر باید حداقل یک عدد داشته باشد ('0'-'9')"
|
||||
};
|
||||
}
|
||||
|
||||
public override IdentityError PasswordRequiresLower()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresLower),
|
||||
Description = "پسورد مورد نظر باید حداقل یکی از حروف ('a'-'z') به صورت کوچک داشته باشد"
|
||||
};
|
||||
}
|
||||
|
||||
public override IdentityError PasswordRequiresUpper()
|
||||
{
|
||||
return new IdentityError
|
||||
{
|
||||
Code = nameof(PasswordRequiresUpper),
|
||||
Description = "پسورد مورد نظر باید حداقل یکی از حروف ('A'-'Z') به صورت بزرگ داشته باشد"
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using Asp.Versioning;
|
||||
using AspNetCoreRateLimit;
|
||||
using AspNetCoreRateLimit.Redis;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.ResponseCompression;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
using StackExchange.Redis.Extensions.Core.Configuration;
|
||||
using StackExchange.Redis.Extensions.Newtonsoft;
|
||||
|
||||
namespace DocuMed.Api.WebFramework.Configurations;
|
||||
|
||||
public static class ServiceExtensions
|
||||
{
|
||||
public static void AddIpRateLimit(this IServiceCollection services, IConfigurationRoot configuration)
|
||||
{
|
||||
|
||||
//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.AddInMemoryRateLimiting();
|
||||
services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>();
|
||||
services.AddSingleton<IRateLimitCounterStore, DistributedCacheRateLimitCounterStore>();
|
||||
services.AddDistributedRateLimiting<AsyncKeyLockProcessingStrategy>();
|
||||
services.AddDistributedRateLimiting<RedisProcessingStrategy>();
|
||||
services.AddRedisRateLimiting();
|
||||
|
||||
// configuration (resolvers, counter key builders)
|
||||
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
|
||||
}
|
||||
public static void AddCustomStackExchangeRedis(this IServiceCollection serviceCollection, SiteSettings siteSettings)
|
||||
{
|
||||
serviceCollection.AddStackExchangeRedisExtensions<NewtonsoftSerializer>(options =>
|
||||
{
|
||||
return new List<RedisConfiguration>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Hosts = new[]
|
||||
{
|
||||
new RedisHost
|
||||
{
|
||||
Port = siteSettings.MasterRedisConfiguration.Port,
|
||||
Host = siteSettings.MasterRedisConfiguration.Host
|
||||
}
|
||||
},
|
||||
Password = siteSettings.MasterRedisConfiguration.Password,
|
||||
Ssl = false
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public static void AddCustomDbContext(this IServiceCollection serviceCollection, IConfigurationRoot Configuration)
|
||||
{
|
||||
serviceCollection.AddDbContextFactory<ApplicationContext>(options =>
|
||||
{
|
||||
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
||||
options.UseNpgsql(Configuration.GetConnectionString("PostgresServer"), b => b.MigrationsAssembly("Brizco.Repository"))
|
||||
.UseProjectAssembly(typeof(ApplicationUser).Assembly);
|
||||
//options.EnableServiceProviderCaching(true);
|
||||
}).BuildServiceProvider();
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
}
|
||||
|
||||
public static void AddCustomResponseCompression(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.Configure<GzipCompressionProviderOptions>(options =>
|
||||
options.Level = CompressionLevel.Fastest);
|
||||
serviceCollection.AddResponseCompression(options =>
|
||||
{
|
||||
options.Providers.Add<GzipCompressionProvider>();
|
||||
options.EnableForHttps = true;
|
||||
});
|
||||
}
|
||||
|
||||
public static void AddCustomCores(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddCors(options => options.AddPolicy("CorsPolicy",
|
||||
builder =>
|
||||
{
|
||||
builder.AllowAnyMethod()
|
||||
.SetPreflightMaxAge(TimeSpan.FromHours(24))
|
||||
.WithExposedHeaders("Access-control-allow-origins")
|
||||
.AllowAnyHeader()
|
||||
.SetIsOriginAllowed(_ => true)
|
||||
.AllowCredentials();
|
||||
}));
|
||||
}
|
||||
|
||||
public static void AddCustomController(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddControllers(options => { options.Filters.Add(new AuthorizeFilter()); })
|
||||
.AddControllersAsServices()
|
||||
.AddNewtonsoftJson(options =>
|
||||
{
|
||||
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
//options.SerializerSettings.ContractResolver = new DefaultContractResolver();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static void AddCustomMvc(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection
|
||||
.AddMvc()
|
||||
.AddNewtonsoftJson(options =>
|
||||
{
|
||||
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
});
|
||||
}
|
||||
|
||||
public static void AddCustomAuthorization(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddAuthorization();
|
||||
}
|
||||
|
||||
public static void AddJwtCustomAuthentication(this IServiceCollection serviceCollection, JwtSettings jwtSettings)
|
||||
{
|
||||
serviceCollection.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
var secretKey = Encoding.UTF8.GetBytes(jwtSettings.SecretKey);
|
||||
var validateParammetrs = new TokenValidationParameters
|
||||
{
|
||||
ClockSkew = TimeSpan.Zero,
|
||||
RequireSignedTokens = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(secretKey),
|
||||
RequireExpirationTime = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateAudience = true,
|
||||
ValidAudience = jwtSettings.Audience,
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = jwtSettings.Issuer
|
||||
};
|
||||
options.RequireHttpsMetadata = true;
|
||||
options.SaveToken = true;
|
||||
options.TokenValidationParameters = validateParammetrs;
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
var accessToken = context.Request.Query["access_token"];
|
||||
|
||||
// If the request is for our hub...
|
||||
var path = context.HttpContext.Request.Path;
|
||||
if (!string.IsNullOrEmpty(accessToken))
|
||||
// Read the token out of the query string
|
||||
context.Token = accessToken.ToString();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public static void AddCustomIdentity(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddIdentity<ApplicationUser, ApplicationRole>(options =>
|
||||
{
|
||||
options.Password.RequireLowercase = false;
|
||||
options.Password.RequireUppercase = false;
|
||||
options.Password.RequireDigit = false;
|
||||
options.Password.RequireNonAlphanumeric = false;
|
||||
options.User.RequireUniqueEmail = false;
|
||||
}).AddEntityFrameworkStores<ApplicationContext>()
|
||||
.AddDefaultTokenProviders()
|
||||
.AddErrorDescriber<PersianIdentityErrorDescriber>();
|
||||
;
|
||||
}
|
||||
|
||||
public static void AddCustomApiVersioning(this IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddApiVersioning(options =>
|
||||
{
|
||||
options.AssumeDefaultVersionWhenUnspecified = true;
|
||||
options.DefaultApiVersion = new ApiVersion(1, 0);
|
||||
options.ApiVersionReader = new HeaderApiVersionReader("api-version");
|
||||
options.ReportApiVersions = true;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace DocuMed.Api.WebFramework.MiddleWares;
|
||||
|
||||
public static class ExceptionHandlerMiddlewareExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseExceptionHandlerMiddleware(this IApplicationBuilder applicationBuilder)
|
||||
{
|
||||
return applicationBuilder.UseMiddleware<ExceptionHandlerMiddleware>();
|
||||
}
|
||||
}
|
||||
|
||||
public class ExceptionHandlerMiddleware
|
||||
{
|
||||
private readonly IWebHostEnvironment _env;
|
||||
private readonly ILogger<ExceptionHandlerMiddleware> _logger;
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public ExceptionHandlerMiddleware(
|
||||
RequestDelegate next,
|
||||
IWebHostEnvironment env,
|
||||
ILogger<ExceptionHandlerMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_env = env;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
string message = null;
|
||||
var httpStatusCode = HttpStatusCode.InternalServerError;
|
||||
var apiStatusCode = ApiResultStatusCode.ServerError;
|
||||
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
catch (BaseApiException exception)
|
||||
{
|
||||
_logger.LogError(exception, exception.Message);
|
||||
httpStatusCode = exception.HttpStatusCode;
|
||||
apiStatusCode = exception.ApiStatusCode;
|
||||
|
||||
if (_env.IsDevelopment())
|
||||
{
|
||||
var dic = new Dictionary<string, string>
|
||||
{
|
||||
["Exception"] = exception.Message,
|
||||
["StackTrace"] = exception.StackTrace
|
||||
};
|
||||
if (exception.InnerException != null)
|
||||
{
|
||||
dic.Add("InnerException.Exception", exception.InnerException.Message);
|
||||
dic.Add("InnerException.StackTrace", exception.InnerException.StackTrace);
|
||||
}
|
||||
|
||||
if (exception.AdditionalData != null)
|
||||
dic.Add("AdditionalData", JsonConvert.SerializeObject(exception.AdditionalData));
|
||||
var contractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy()
|
||||
};
|
||||
|
||||
message = JsonConvert.SerializeObject(dic, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = contractResolver,
|
||||
Formatting = Formatting.Indented
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
message = exception.Message;
|
||||
}
|
||||
if(exception.AdditionalData==null)
|
||||
await WriteToResponseAsync();
|
||||
else
|
||||
await WriteToResponseWithObjectAsync(exception.AdditionalData);
|
||||
}
|
||||
catch (SecurityTokenExpiredException exception)
|
||||
{
|
||||
_logger.LogError(exception, exception.Message);
|
||||
SetUnAuthorizeResponse(exception);
|
||||
await WriteToResponseAsync();
|
||||
}
|
||||
catch (UnauthorizedAccessException exception)
|
||||
{
|
||||
_logger.LogError(exception, exception.Message);
|
||||
SetUnAuthorizeResponse(exception);
|
||||
await WriteToResponseAsync();
|
||||
}
|
||||
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, exception.Message);
|
||||
|
||||
if (_env.IsDevelopment())
|
||||
{
|
||||
var dic = new Dictionary<string, string>
|
||||
{
|
||||
["Exception"] = exception.Message,
|
||||
["InnerException"] = exception.InnerException?.Message,
|
||||
["StackTrace"] = exception.StackTrace
|
||||
};
|
||||
message = JsonConvert.SerializeObject(dic);
|
||||
}
|
||||
|
||||
message = exception.Message;
|
||||
await WriteToResponseAsync();
|
||||
}
|
||||
|
||||
async Task WriteToResponseAsync()
|
||||
{
|
||||
if (context.Response.HasStarted)
|
||||
throw new InvalidOperationException("The response has already started, the http status code middleware will not be executed.");
|
||||
|
||||
var result = new ApiResult(false, apiStatusCode, message);
|
||||
|
||||
var contractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy()
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = contractResolver,
|
||||
Formatting = Formatting.Indented
|
||||
});
|
||||
|
||||
context.Response.StatusCode = (int)httpStatusCode;
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(json);
|
||||
}
|
||||
|
||||
|
||||
|
||||
async Task WriteToResponseWithObjectAsync(object additionalData)
|
||||
{
|
||||
if (context.Response.HasStarted)
|
||||
throw new InvalidOperationException(
|
||||
"The response has already started, the http status code middleware will not be executed.");
|
||||
|
||||
var result = new ApiResult<object>(false, apiStatusCode, additionalData, message);
|
||||
|
||||
var contractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy()
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = contractResolver,
|
||||
Formatting = Formatting.Indented
|
||||
});
|
||||
|
||||
context.Response.StatusCode = (int)httpStatusCode;
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(json);
|
||||
}
|
||||
|
||||
void SetUnAuthorizeResponse(Exception exception)
|
||||
{
|
||||
httpStatusCode = HttpStatusCode.Unauthorized;
|
||||
apiStatusCode = ApiResultStatusCode.UnAuthorized;
|
||||
|
||||
if (_env.IsDevelopment())
|
||||
{
|
||||
var dic = new Dictionary<string, string>
|
||||
{
|
||||
["Exception"] = exception.Message,
|
||||
["StackTrace"] = exception.StackTrace
|
||||
};
|
||||
if (exception is SecurityTokenExpiredException tokenException)
|
||||
dic.Add("Expires", tokenException.Expires.ToString());
|
||||
|
||||
message = JsonConvert.SerializeObject(dic);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JwtSecurityToken ReadJwtToken(bool fromHeader = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (fromHeader)
|
||||
{
|
||||
var stream = context.Request.Headers.Values.First(v => v.FirstOrDefault().Contains("Bearer"))
|
||||
.FirstOrDefault();
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var jsonToken = handler.ReadToken(stream.Split(" ").Last());
|
||||
return jsonToken as JwtSecurityToken;
|
||||
}
|
||||
else
|
||||
{
|
||||
string stream = context.Request.Query["access_token"];
|
||||
;
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var jsonToken = handler.ReadToken(stream.Split(" ").Last());
|
||||
return jsonToken as JwtSecurityToken;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new BaseApiException(ApiResultStatusCode.UnAuthorized, e.Message + " Jwt is wrong",
|
||||
HttpStatusCode.Unauthorized);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
namespace DocuMed.Api.WebFramework.MiddleWares;
|
||||
|
||||
public static class PerformanceMiddlewareExtensions
|
||||
{
|
||||
public static IApplicationBuilder UsePerformanceMiddlewar(this IApplicationBuilder applicationBuilder)
|
||||
{
|
||||
return applicationBuilder.UseMiddleware<PerformanceMiddleware>();
|
||||
}
|
||||
}
|
||||
|
||||
public class PerformanceMiddleware
|
||||
{
|
||||
private readonly ILogger<ExceptionHandlerMiddleware> _logger;
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly Stopwatch _timer;
|
||||
|
||||
public PerformanceMiddleware(
|
||||
RequestDelegate next,
|
||||
ILogger<ExceptionHandlerMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_logger = logger;
|
||||
_timer = new Stopwatch();
|
||||
}
|
||||
|
||||
public async System.Threading.Tasks.Task Invoke(HttpContext context)
|
||||
{
|
||||
_timer.Start();
|
||||
await _next(context);
|
||||
_timer.Stop();
|
||||
|
||||
var elapsedMilliseconds = _timer.ElapsedMilliseconds;
|
||||
_logger.LogWarning($"REQUEST TIMER : {elapsedMilliseconds}");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Pluralize.NET;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||
|
||||
namespace DocuMed.Api.WebFramework.Swagger;
|
||||
|
||||
public static class SwaggerConfiguration
|
||||
{
|
||||
public static void AddCustomSwagger(this IServiceCollection services,string baseUrl)
|
||||
{
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
//var xmlDuc = Path.Combine(AppContext.BaseDirectory, "swaggerApi.xml");
|
||||
//options.IncludeXmlComments(xmlDuc,true);
|
||||
options.SwaggerDoc("v1",
|
||||
new OpenApiInfo
|
||||
{
|
||||
Version = "v1",
|
||||
Title = "iGarson Api Dacument",
|
||||
Description = "iGarson api for clients that wana use",
|
||||
License = new OpenApiLicense { Name = "Vira Safir Fanavar " },
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "Amir Hossein Khademi",
|
||||
Email = "avvampier@gmail.com",
|
||||
Url = new Uri("http://amir-khademi.ir/")
|
||||
}
|
||||
});
|
||||
options.EnableAnnotations();
|
||||
options.DescribeAllParametersInCamelCase();
|
||||
options.IgnoreObsoleteActions();
|
||||
|
||||
//#region Versioning
|
||||
|
||||
//// Remove version parameter from all Operations
|
||||
//options.OperationFilter<RemoveVersionParameters>();
|
||||
|
||||
////set version "api/v{version}/[controller]" from current swagger doc verion
|
||||
//options.DocumentFilter<SetVersionInPaths>();
|
||||
|
||||
////Seperate and categorize end-points by doc version
|
||||
//options.DocInclusionPredicate((version, desc) =>
|
||||
//{
|
||||
// if (!desc.TryGetMethodInfo(out var methodInfo)) return false;
|
||||
// var versions = methodInfo.DeclaringType
|
||||
// .GetCustomAttributes(true)
|
||||
// .OfType<ApiVersionAttribute>()
|
||||
// .SelectMany(attr => attr.Versions)
|
||||
// .ToList();
|
||||
|
||||
// return versions.Any(v => $"v{v.ToString()}" == version);
|
||||
//});
|
||||
|
||||
//#endregion
|
||||
|
||||
#region Security
|
||||
|
||||
var url = $"{baseUrl}/api/auth/login/swagger";
|
||||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
Type = SecuritySchemeType.OAuth2,
|
||||
Scheme = "Bearer",
|
||||
Name = "Bearer",
|
||||
Flows = new OpenApiOAuthFlows
|
||||
{
|
||||
Password = new OpenApiOAuthFlow
|
||||
{
|
||||
TokenUrl = new Uri(url)
|
||||
}
|
||||
}
|
||||
});
|
||||
options.OperationFilter<UnauthorizedResponsesOperationFilter>(true, "Bearer");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Customize
|
||||
|
||||
options.OperationFilter<ApplySummariesOperationFilter>();
|
||||
|
||||
#endregion
|
||||
});
|
||||
}
|
||||
|
||||
public static void UseCustomSwagger(this IApplicationBuilder app,string baseUrl)
|
||||
{
|
||||
app.UseSwagger(options =>
|
||||
{
|
||||
options.SerializeAsV2 = true;
|
||||
});
|
||||
|
||||
app.UseSwaggerUI(options =>
|
||||
{
|
||||
options.InjectStylesheet("/assets/swagger-ui/x3/theme-flattop.css");
|
||||
options.DocExpansion(DocExpansion.None);
|
||||
// Display
|
||||
options.DefaultModelExpandDepth(2);
|
||||
options.DefaultModelRendering(ModelRendering.Model);
|
||||
options.DefaultModelsExpandDepth(-1);
|
||||
options.DisplayOperationId();
|
||||
options.DisplayRequestDuration();
|
||||
options.EnableDeepLinking();
|
||||
options.EnableFilter();
|
||||
options.ShowExtensions();
|
||||
|
||||
options.OAuthUseBasicAuthenticationWithAccessCodeGrant();
|
||||
options.SwaggerEndpoint($"{baseUrl}/swagger/v1/swagger.json", "V1 Docs");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class RemoveVersionParameters : IOperationFilter
|
||||
{
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
// Remove version parameter from all Operations
|
||||
var versionParameter = operation.Parameters.SingleOrDefault(p => p.Name == "version");
|
||||
if (versionParameter != null)
|
||||
operation.Parameters.Remove(versionParameter);
|
||||
}
|
||||
}
|
||||
|
||||
public class SetVersionInPaths : IDocumentFilter
|
||||
{
|
||||
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
|
||||
{
|
||||
if (swaggerDoc == null)
|
||||
throw new ArgumentNullException(nameof(swaggerDoc));
|
||||
|
||||
var replacements = new OpenApiPaths();
|
||||
|
||||
foreach (var (key, value) in swaggerDoc.Paths)
|
||||
replacements.Add(key.Replace("v{version}", swaggerDoc.Info.Version, StringComparison.InvariantCulture),
|
||||
value);
|
||||
|
||||
swaggerDoc.Paths = replacements;
|
||||
}
|
||||
}
|
||||
|
||||
public class UnauthorizedResponsesOperationFilter : IOperationFilter
|
||||
{
|
||||
private readonly bool includeUnauthorizedAndForbiddenResponses;
|
||||
private readonly string schemeName;
|
||||
|
||||
public UnauthorizedResponsesOperationFilter(bool includeUnauthorizedAndForbiddenResponses,
|
||||
string schemeName = "Bearer")
|
||||
{
|
||||
this.includeUnauthorizedAndForbiddenResponses = includeUnauthorizedAndForbiddenResponses;
|
||||
this.schemeName = schemeName;
|
||||
}
|
||||
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
var filters = context.ApiDescription.ActionDescriptor.FilterDescriptors;
|
||||
|
||||
var hasAnynomousEndPoint = context.ApiDescription.ActionDescriptor.EndpointMetadata.Any(e =>
|
||||
e.GetType() == typeof(AllowAnonymousAttribute));
|
||||
|
||||
//var hasAnonymous = filters.Any(p => p.Filter is AllowAnonymousFilter);
|
||||
if (hasAnynomousEndPoint)
|
||||
return;
|
||||
|
||||
/*var hasAuthorize = filters.Any(p => p.Filter is AuthorizeFilter);
|
||||
if (!hasAuthorize)
|
||||
return;*/
|
||||
|
||||
if (includeUnauthorizedAndForbiddenResponses)
|
||||
{
|
||||
operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
|
||||
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
|
||||
}
|
||||
|
||||
operation.Security.Add(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
new string[] { }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ApplySummariesOperationFilter : IOperationFilter
|
||||
{
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
var controllerActionDescriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor;
|
||||
if (controllerActionDescriptor == null) return;
|
||||
|
||||
var pluralizer = new Pluralizer();
|
||||
|
||||
var actionName = controllerActionDescriptor.ActionName;
|
||||
var singularizeName = pluralizer.Singularize(controllerActionDescriptor.ControllerName);
|
||||
var pluralizeName = pluralizer.Pluralize(singularizeName);
|
||||
|
||||
var parameterCount = operation.Parameters.Where(p => p.Name != "version" && p.Name != "api-version").Count();
|
||||
|
||||
if (IsGetAllAction())
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Returns all {pluralizeName}";
|
||||
}
|
||||
else if (IsActionName("Post", "Create"))
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Creates a {singularizeName}";
|
||||
|
||||
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
|
||||
operation.Parameters[0].Description = $"A {singularizeName} representation";
|
||||
}
|
||||
else if (IsActionName("Read", "Get"))
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Retrieves a {singularizeName} by unique id";
|
||||
|
||||
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
|
||||
operation.Parameters[0].Description = $"a unique id for the {singularizeName}";
|
||||
}
|
||||
else if (IsActionName("Put", "Edit", "Update"))
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Updates a {singularizeName} by unique id";
|
||||
|
||||
//if (!operation.Parameters[0].OrderDescription.HasValue())
|
||||
// operation.Parameters[0].OrderDescription = $"A unique id for the {singularizeName}";
|
||||
|
||||
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
|
||||
operation.Parameters[0].Description = $"A {singularizeName} representation";
|
||||
}
|
||||
else if (IsActionName("Delete", "Remove"))
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"Deletes a {singularizeName} by unique id";
|
||||
|
||||
if (operation.Parameters.Count > 0 && !operation.Parameters[0].Description.HasValue())
|
||||
operation.Parameters[0].Description = $"A unique id for the {singularizeName}";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!operation.Summary.HasValue())
|
||||
operation.Summary = $"{actionName} {pluralizeName}";
|
||||
}
|
||||
|
||||
#region Local Functions
|
||||
|
||||
bool IsGetAllAction()
|
||||
{
|
||||
foreach (var name in new[] { "Get", "Read", "Select" })
|
||||
if (actionName.Equals(name, StringComparison.OrdinalIgnoreCase) && parameterCount == 0 ||
|
||||
actionName.Equals($"{name}All", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Equals($"{name}{pluralizeName}", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Equals($"{name}All{singularizeName}", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Equals($"{name}All{pluralizeName}", StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsActionName(params string[] names)
|
||||
{
|
||||
foreach (var name in names)
|
||||
if (actionName.Contains(name, StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Contains($"{name}ById", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Contains($"{name}{singularizeName}", StringComparison.OrdinalIgnoreCase) ||
|
||||
actionName.Contains($"{name}{singularizeName}ById", StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace DocuMed.Core
|
||||
{
|
||||
public class Class1
|
||||
public class CoreConfig
|
||||
{
|
||||
|
||||
}
|
|
@ -19,4 +19,15 @@
|
|||
<ProjectReference Include="..\DocuMed.Repository\DocuMed.Repository.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\Api\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="DocuMed.Common.Extensions" />
|
||||
<Using Include="DocuMed.Common.Models.Api" />
|
||||
<Using Include="Microsoft.AspNetCore.Mvc" />
|
||||
<Using Include="Newtonsoft.Json" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
namespace DocuMed.Core.Models.Api;
|
||||
|
||||
public class ApiResult
|
||||
{
|
||||
public ApiResult(bool isSuccess, ApiResultStatusCode statusCode, string message = null)
|
||||
{
|
||||
IsSuccess = isSuccess;
|
||||
StatusCode = statusCode;
|
||||
Message = message ?? statusCode.ToDisplay();
|
||||
}
|
||||
|
||||
public bool IsSuccess { get; set; }
|
||||
public ApiResultStatusCode StatusCode { get; set; }
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string Message { get; set; }
|
||||
|
||||
#region Implicit Operators
|
||||
|
||||
public static implicit operator ApiResult(OkResult result)
|
||||
{
|
||||
return new ApiResult(true, ApiResultStatusCode.Success);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(BadRequestResult result)
|
||||
{
|
||||
return new ApiResult(false, ApiResultStatusCode.BadRequest);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(BadRequestObjectResult result)
|
||||
{
|
||||
var message = result.Value.ToString();
|
||||
if (result.Value is SerializableError errors)
|
||||
{
|
||||
var errorMessages = errors.SelectMany(p => (string[])p.Value).Distinct();
|
||||
message = string.Join(" | ", errorMessages);
|
||||
}
|
||||
|
||||
return new ApiResult(false, ApiResultStatusCode.BadRequest, message);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(ContentResult result)
|
||||
{
|
||||
return new ApiResult(true, ApiResultStatusCode.Success, result.Content);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(NotFoundResult result)
|
||||
{
|
||||
return new ApiResult(false, ApiResultStatusCode.NotFound);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(ForbidResult result)
|
||||
{
|
||||
return new ApiResult(false, ApiResultStatusCode.NotFound);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult(StatusCodeResult result)
|
||||
{
|
||||
return new ApiResult(false, ApiResultStatusCode.NotFound);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class ApiResult<TData> : ApiResult
|
||||
where TData : class
|
||||
{
|
||||
public ApiResult(bool isSuccess, ApiResultStatusCode statusCode, TData data, string message = null)
|
||||
: base(isSuccess, statusCode, message)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public TData Data { get; set; }
|
||||
|
||||
#region Implicit Operators
|
||||
|
||||
public static implicit operator ApiResult<TData>(TData data)
|
||||
{
|
||||
return new ApiResult<TData>(true, ApiResultStatusCode.Success, data);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(OkResult result)
|
||||
{
|
||||
return new ApiResult<TData>(true, ApiResultStatusCode.Success, null);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(OkObjectResult result)
|
||||
{
|
||||
return new ApiResult<TData>(true, ApiResultStatusCode.Success, (TData)result.Value);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(BadRequestResult result)
|
||||
{
|
||||
return new ApiResult<TData>(false, ApiResultStatusCode.BadRequest, null);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(BadRequestObjectResult result)
|
||||
{
|
||||
var message = result.Value.ToString();
|
||||
if (result.Value is SerializableError errors)
|
||||
{
|
||||
var errorMessages = errors.SelectMany(p => (string[])p.Value).Distinct();
|
||||
message = string.Join(" | ", errorMessages);
|
||||
}
|
||||
|
||||
return new ApiResult<TData>(false, ApiResultStatusCode.BadRequest, null, message);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(ContentResult result)
|
||||
{
|
||||
return new ApiResult<TData>(true, ApiResultStatusCode.Success, null, result.Content);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(NotFoundResult result)
|
||||
{
|
||||
return new ApiResult<TData>(false, ApiResultStatusCode.NotFound, null);
|
||||
}
|
||||
|
||||
public static implicit operator ApiResult<TData>(NotFoundObjectResult result)
|
||||
{
|
||||
return new ApiResult<TData>(false, ApiResultStatusCode.NotFound, (TData)result.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
|
@ -14,4 +14,8 @@
|
|||
<ProjectReference Include="..\DocuMed.Core\DocuMed.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace DocuMed.Infrastructure
|
||||
{
|
||||
public class Class1
|
||||
public class InfrastructureConfig
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace DocuMed.Infrastructure.Models;
|
||||
public static class DirectoryAddress
|
||||
{
|
||||
private static readonly string BaseDire = $"{Directory.GetCurrentDirectory()}/wwwroot";
|
||||
public static string Logs = $"{BaseDire}/logs";
|
||||
}
|
|
@ -4,6 +4,5 @@ public interface ICurrentUserService : IScopedDependency
|
|||
{
|
||||
string? UserId { get; }
|
||||
string? RoleName { get; }
|
||||
string? ComplexId { get; }
|
||||
string? UserName { get; }
|
||||
}
|
|
@ -34,6 +34,7 @@
|
|||
<Using Include="DocuMed.Common.Models.Claims" />
|
||||
<Using Include="DocuMed.Common.Models.Entity" />
|
||||
<Using Include="DocuMed.Domain.Entities.User" />
|
||||
<Using Include="DocuMed.Domain.Enums" />
|
||||
<Using Include="DocuMed.Domain.Models.Settings" />
|
||||
<Using Include="DocuMed.Repository.Extensions" />
|
||||
<Using Include="DocuMed.Repository.Models" />
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
namespace DocuMed.Repository;
|
||||
public class RepositoryConfig
|
||||
{
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
}
|
||||
namespace DocuMed.Repository;
|
||||
public static class RepositoryConfig
|
||||
{
|
||||
public static async Task InitialDb(this IApplicationBuilder app)
|
||||
{
|
||||
var scopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
|
||||
using (var scope = scopeFactory.CreateScope())
|
||||
{
|
||||
var identityDbInitialize = scope.ServiceProvider.GetService<IDbInitializerService>();
|
||||
if (identityDbInitialize != null)
|
||||
{
|
||||
identityDbInitialize.Initialize();
|
||||
await identityDbInitialize.SeedDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue