erp-platform/api/src/Kurs.Platform.Application/DeveloperKit/DynamicServiceAppService.cs
2025-11-05 09:37:04 +03:00

339 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Kurs.Platform.DynamicServices;
using Kurs.Platform.Entities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
using static Kurs.Platform.PlatformConsts;
namespace Kurs.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)
{
Logger.LogInformation("Test compile başlatıldı. Tenant: {TenantId}", CurrentTenant.Id);
try
{
var result = await _compiler.CompileAndValidateAsync(request.Code, CurrentTenant.Id);
Logger.LogInformation("Test compile tamamlandı. Başarılı: {Success}, Tenant: {TenantId}",
result.Success, CurrentTenant.Id);
return result;
}
catch (Exception ex)
{
Logger.LogError(ex, "Test compile sırasında hata. Tenant: {TenantId}", CurrentTenant.Id);
throw;
}
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Publish)]
public virtual async Task<PublishResultDto> PublishAsync(PublishAppServiceRequestDto request)
{
Logger.LogInformation("AppService yayınlama başlatıldı. Ad: {Name}, Tenant: {TenantId}",
request.Name, CurrentTenant.Id);
try
{
// Önce kodu test compile et
var compileResult = await _compiler.CompileAndValidateAsync(request.Code, CurrentTenant.Id);
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 && x.TenantId == CurrentTenant.Id);
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;
appService = await _dynamicAppServiceRepository.UpdateAsync(existingService);
Logger.LogInformation("Mevcut AppService güncellendi. ID: {Id}", appService.Id);
}
else
{
// Yeni servis oluştur
appService = new DynamicService(
GuidGenerator.Create(),
request.Name,
request.Code,
CurrentTenant.Id)
{
DisplayName = request.DisplayName,
Description = request.Description,
PrimaryEntityType = request.PrimaryEntityType,
ControllerName = GenerateControllerName(request.Name)
};
appService = await _dynamicAppServiceRepository.InsertAsync(appService);
Logger.LogInformation("Yeni AppService oluşturuldu. ID: {Id}", appService.Id);
}
// Runtime'da derle ve yükle
var assemblyName = $"DynamicAppService_{appService.Id}_{appService.Version}";
var loadResult = await _compiler.CompileAndRegisterForTenantAsync(
CurrentTenant.Id ?? Guid.Empty,
request.Code,
assemblyName);
if (loadResult.Success)
{
// Başarılı derleme durumunu kaydet
appService.MarkCompilationSuccess();
await _dynamicAppServiceRepository.UpdateAsync(appService);
var result = new PublishResultDto
{
Success = true,
AppServiceId = appService.Id,
ControllerName = appService.ControllerName,
SwaggerUrl = "/swagger/index.html",
GeneratedEndpoints = GenerateEndpointList(request.Name)
};
Logger.LogInformation("AppService başarıyla yayınlandı. ID: {Id}, Controller: {Controller}",
appService.Id, appService.ControllerName);
return result;
}
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, "AppService yayınlama sırasında hata. Ad: {Name}, Tenant: {TenantId}",
request.Name, CurrentTenant.Id);
return new PublishResultDto
{
Success = false,
ErrorMessage = $"Yayınlama sırasında beklenmeyen hata: {ex.Message}"
};
}
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.DynamicService)]
public virtual async Task<PagedResultDto<DynamicServiceDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{
Logger.LogDebug("AppService listesi istendi. Tenant: {TenantId}", CurrentTenant.Id);
var queryable = await _dynamicAppServiceRepository.GetQueryableAsync();
// Tenant filtresi otomatik uygulanır (IMultiTenant)
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);
Logger.LogDebug("AppService listesi döndürüldü. Toplam: {Total}, Dönen: {Count}",
totalCount, dtos.Count);
return new PagedResultDto<DynamicServiceDto>(totalCount, dtos);
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.ViewCode)]
public virtual async Task<DynamicServiceDto> GetAsync(Guid id)
{
Logger.LogDebug("AppService detayı istendi. ID: {Id}, Tenant: {TenantId}", id, CurrentTenant.Id);
var appService = await _dynamicAppServiceRepository.GetAsync(id);
var dto = ObjectMapper.Map<DynamicService, DynamicServiceDto>(appService);
return dto;
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Delete)]
public virtual async Task DeleteAsync(Guid id)
{
Logger.LogInformation("AppService silme işlemi başlatıldı. ID: {Id}, Tenant: {TenantId}",
id, CurrentTenant.Id);
var appService = await _dynamicAppServiceRepository.GetAsync(id);
// TODO: Runtime'dan assembly'yi kaldırma işlemi
// (AssemblyLoadContext.Unload() çağrısı)
await _dynamicAppServiceRepository.DeleteAsync(id);
Logger.LogInformation("AppService silindi. ID: {Id}", id);
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
public virtual async Task SetActiveAsync(Guid id, bool isActive)
{
Logger.LogInformation("AppService aktiflik durumu değiştiriliyor. ID: {Id}, Aktif: {Active}",
id, isActive);
var appService = await _dynamicAppServiceRepository.GetAsync(id);
appService.IsActive = isActive;
await _dynamicAppServiceRepository.UpdateAsync(appService);
Logger.LogInformation("AppService aktiflik durumu güncellendi. ID: {Id}, Aktif: {Active}",
id, isActive);
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
public virtual async Task ReloadAllActiveServicesAsync()
{
Logger.LogInformation("Tüm aktif AppService'ler yeniden yükleniyor. Tenant: {TenantId}",
CurrentTenant.Id);
var activeServices = await _dynamicAppServiceRepository
.GetListAsync(x => x.IsActive && x.CompilationStatus == CompilationStatus.Success);
var successCount = 0;
var errorCount = 0;
foreach (var service in activeServices)
{
try
{
var assemblyName = $"DynamicAppService_{service.Id}_{service.Version}";
var result = await _compiler.CompileAndRegisterForTenantAsync(
CurrentTenant.Id ?? Guid.Empty,
service.Code,
assemblyName);
if (result.Success)
{
successCount++;
Logger.LogDebug("AppService yeniden yüklendi. ID: {Id}, Ad: {Name}",
service.Id, service.Name);
}
else
{
errorCount++;
service.MarkCompilationError(result.ErrorMessage);
await _dynamicAppServiceRepository.UpdateAsync(service);
Logger.LogWarning("AppService yeniden yüklenemedi. ID: {Id}, Hata: {Error}",
service.Id, result.ErrorMessage);
}
}
catch (Exception ex)
{
errorCount++;
Logger.LogError(ex, "AppService yeniden yükleme hatası. ID: {Id}", service.Id);
service.MarkCompilationError(ex.Message);
await _dynamicAppServiceRepository.UpdateAsync(service);
}
}
Logger.LogInformation("AppService yeniden yükleme tamamlandı. Başarılı: {Success}, Hatalı: {Error}, Toplam: {Total}",
successCount, errorCount, activeServices.Count);
}
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
public virtual async Task<CompileResultDto> RecompileAsync(Guid id)
{
Logger.LogInformation("AppService yeniden derleniyor. ID: {Id}", id);
var appService = await _dynamicAppServiceRepository.GetAsync(id);
var assemblyName = $"DynamicAppService_{appService.Id}_{appService.Version + 1}";
var result = await _compiler.CompileAndRegisterForTenantAsync(
CurrentTenant.Id ?? Guid.Empty,
appService.Code,
assemblyName);
if (result.Success)
{
appService.MarkCompilationSuccess();
appService.Version++;
}
else
{
appService.MarkCompilationError(result.ErrorMessage);
}
await _dynamicAppServiceRepository.UpdateAsync(appService);
Logger.LogInformation("AppService yeniden derleme tamamlandı. ID: {Id}, Başarılı: {Success}",
id, result.Success);
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;
}
private List<string> GenerateEndpointList(string serviceName)
{
var controllerName = GenerateControllerName(serviceName);
return
[
$"/api/app/{controllerName.ToLowerInvariant()}",
$"/api/app/{controllerName.ToLowerInvariant()}/{{id}}",
$"/api/app/{controllerName.ToLowerInvariant()}/list"
];
}
}