sozsoft-platform/api/src/Sozsoft.Platform.Application/DeveloperKit/DynamicServiceAppService.cs

312 lines
11 KiB
C#
Raw Normal View History

2026-02-24 20:44:16 +00:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using Sozsoft.Platform.DynamicServices;
using Sozsoft.Platform.Entities;
2026-02-24 20:44:16 +00:00
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
using static Sozsoft.Platform.PlatformConsts;
namespace Sozsoft.Platform.DeveloperKit;
[Authorize]
public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAppService
{
private readonly IRepository<DynamicService, Guid> _dynamicAppServiceRepository;
private readonly DynamicServiceCompiler _compiler;
public DynamicAppServiceAppService(
IRepository<DynamicService, Guid> dynamicAppServiceRepository,
DynamicServiceCompiler compiler
)
{
_dynamicAppServiceRepository = dynamicAppServiceRepository;
_compiler = compiler;
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.TestCompile)]
public virtual async Task<CompileResultDto> TestCompileAsync(TestCompileRequestDto request)
{
try
{
return await _compiler.CompileAndValidateAsync(request.Code);
2026-02-24 20:44:16 +00:00
}
catch (Exception ex)
{
Logger.LogError(ex, "Failed to test compile dynamic service");
2026-02-24 20:44:16 +00:00
throw;
}
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Publish)]
public virtual async Task<PublishResultDto> PublishAsync(PublishAppServiceRequestDto request)
{
try
{
// Önce kodu test compile et
var compileResult = await _compiler.CompileAndValidateAsync(request.Code);
2026-02-24 20:44:16 +00:00
if (!compileResult.Success)
{
return new PublishResultDto
{
Success = false,
ErrorMessage = compileResult.ErrorMessage
};
}
// Aynı isimde AppService var mı kontrol et
var existingService = await _dynamicAppServiceRepository.FirstOrDefaultAsync(x => x.Name == request.Name);
2026-02-24 20:44:16 +00:00
DynamicService appService;
if (existingService != null)
{
// Mevcut servisi güncelle
existingService.UpdateCode(request.Code);
existingService.DisplayName = request.DisplayName;
existingService.Description = request.Description;
existingService.PrimaryEntityType = request.PrimaryEntityType;
2026-03-02 07:36:38 +00:00
existingService.IsActive = request.IsActive;
2026-02-24 20:44:16 +00:00
appService = await _dynamicAppServiceRepository.UpdateAsync(existingService);
}
else
{
appService = new DynamicService(
GuidGenerator.Create(),
request.Name,
request.Code)
2026-02-24 20:44:16 +00:00
{
DisplayName = request.DisplayName,
Description = request.Description,
PrimaryEntityType = request.PrimaryEntityType,
2026-03-02 07:36:38 +00:00
ControllerName = GenerateControllerName(request.Name),
IsActive = request.IsActive
2026-02-24 20:44:16 +00:00
};
appService = await _dynamicAppServiceRepository.InsertAsync(appService);
}
var assemblyName = $"{appService.Name}_{appService.Version}";
2026-03-02 07:36:38 +00:00
// Pasif olarak yayınlanıyorsa mevcut kaydı kaldır, assembly yükleme
if (!request.IsActive)
{
DynamicServiceCompiler.NotifyAssemblyUnregistration?.Invoke(appService.Name);
2026-03-02 07:36:38 +00:00
appService.MarkCompilationSuccess();
await _dynamicAppServiceRepository.UpdateAsync(appService);
return new PublishResultDto
{
Success = true,
AppServiceId = appService.Id,
ControllerName = appService.ControllerName,
GeneratedEndpoints = new List<string>()
};
}
var loadResult = await _compiler.CompileAndRegisterAsync(
2026-02-24 20:44:16 +00:00
request.Code,
assemblyName);
if (loadResult.Success)
{
appService.MarkCompilationSuccess();
await _dynamicAppServiceRepository.UpdateAsync(appService);
var endpoints = loadResult.LoadedAssembly != null
? _compiler.ExtractEndpointsFromAssembly(loadResult.LoadedAssembly, request.Name)
: new List<string>();
return new PublishResultDto
{
Success = true,
AppServiceId = appService.Id,
ControllerName = appService.ControllerName,
SwaggerUrl = "/swagger/index.html",
GeneratedEndpoints = endpoints
};
}
else
{
// Derleme hatası durumunu kaydet
appService.MarkCompilationError(loadResult.ErrorMessage);
await _dynamicAppServiceRepository.UpdateAsync(appService);
return new PublishResultDto
{
Success = false,
ErrorMessage = loadResult.ErrorMessage,
AppServiceId = appService.Id
};
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Failed to publish dynamic service. Name: {Name}", request.Name);
2026-02-24 20:44:16 +00:00
return new PublishResultDto
{
Success = false,
ErrorMessage = $"Failed to publish dynamic service: {ex.Message}"
2026-02-24 20:44:16 +00:00
};
}
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.DynamicService)]
public virtual async Task<PagedResultDto<DynamicServiceDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{
var queryable = await _dynamicAppServiceRepository.GetQueryableAsync();
var query = queryable.WhereIf(!string.IsNullOrEmpty(input.Sorting),
x => x.CreationTime.ToString().Contains(input.Sorting ?? ""));
var totalCount = await AsyncExecuter.CountAsync(query);
var items = await AsyncExecuter.ToListAsync(
query.OrderByDescending(x => x.CreationTime)
.Skip(input.SkipCount)
.Take(input.MaxResultCount)
);
var dtos = ObjectMapper.Map<List<DynamicService>, List<DynamicServiceDto>>(items);
return new PagedResultDto<DynamicServiceDto>(totalCount, dtos);
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.ViewCode)]
public virtual async Task<DynamicServiceDto> GetAsync(Guid id)
{
var appService = await _dynamicAppServiceRepository.GetAsync(id);
return ObjectMapper.Map<DynamicService, DynamicServiceDto>(appService);
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Delete)]
public virtual async Task DeleteAsync(Guid id)
{
var appService = await _dynamicAppServiceRepository.GetAsync(id);
2026-03-02 07:36:38 +00:00
// Runtime'dan assembly ve Swagger endpoint'ini kaldır
DynamicServiceCompiler.NotifyAssemblyUnregistration?.Invoke(appService.Name);
2026-02-24 20:44:16 +00:00
await _dynamicAppServiceRepository.DeleteAsync(id);
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
public virtual async Task SetActiveAsync(Guid id, bool isActive)
{
var appService = await _dynamicAppServiceRepository.GetAsync(id);
appService.IsActive = isActive;
await _dynamicAppServiceRepository.UpdateAsync(appService);
2026-03-02 07:36:38 +00:00
if (!isActive)
{
// Pasif yapılınca Swagger/MVC'den endpoint'i kaldır
DynamicServiceCompiler.NotifyAssemblyUnregistration?.Invoke(appService.Name);
2026-03-02 07:36:38 +00:00
}
else if (appService.CompilationStatus == CompilationStatus.Success)
{
// Aktif yapılınca yeniden derle ve yayınla
var assemblyName = $"{appService.Name}_{appService.Version}";
var result = await _compiler.CompileAndRegisterAsync(
2026-03-02 07:36:38 +00:00
appService.Code,
assemblyName);
if (!result.Success)
{
Logger.LogWarning(
"Failed to recompile and register dynamic service. Name: {Name}, Error: {Error}",
2026-03-02 07:36:38 +00:00
appService.Name, result.ErrorMessage);
}
}
2026-02-24 20:44:16 +00:00
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
public virtual async Task ReloadAllActiveServicesAsync()
{
var activeServices = await _dynamicAppServiceRepository
.GetListAsync(x => x.IsActive && x.CompilationStatus == CompilationStatus.Success);
var successCount = 0;
var errorCount = 0;
foreach (var service in activeServices)
{
try
{
// Service.Name üzerinden assembly adı oluştur
var assemblyName = $"{service.Name}_{service.Version}";
var result = await _compiler.CompileAndRegisterAsync(
2026-02-24 20:44:16 +00:00
service.Code,
assemblyName);
if (result.Success)
{
successCount++;
}
else
{
errorCount++;
service.MarkCompilationError(result.ErrorMessage);
await _dynamicAppServiceRepository.UpdateAsync(service);
}
}
catch (Exception ex)
{
errorCount++;
Logger.LogError(ex, "Failed to recompile dynamic service. ID: {Id}", service.Id);
2026-02-24 20:44:16 +00:00
service.MarkCompilationError(ex.Message);
await _dynamicAppServiceRepository.UpdateAsync(service);
}
}
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
public virtual async Task<CompileResultDto> RecompileAsync(Guid id)
{
var appService = await _dynamicAppServiceRepository.GetAsync(id);
var assemblyName = $"{appService.Name}_{appService.Version + 1}";
var result = await _compiler.CompileAndRegisterAsync(
2026-02-24 20:44:16 +00:00
appService.Code,
assemblyName);
if (result.Success)
{
appService.MarkCompilationSuccess();
appService.Version++;
}
else
{
appService.MarkCompilationError(result.ErrorMessage);
}
await _dynamicAppServiceRepository.UpdateAsync(appService);
return result;
}
private string GenerateControllerName(string serviceName)
{
// DynamicCustomerAppService -> DynamicCustomer
var controllerName = serviceName;
if (controllerName.EndsWith("AppService"))
{
controllerName = controllerName.Substring(0, controllerName.Length - "AppService".Length);
}
else if (controllerName.EndsWith("ApplicationService"))
{
controllerName = controllerName.Substring(0, controllerName.Length - "ApplicationService".Length);
}
return controllerName;
}
}