2026-02-24 20:44:16 +00:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using Sozsoft.Platform.DynamicServices;
|
|
|
|
|
|
using Sozsoft.Platform.Entities;
|
|
|
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
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, CurrentTenant.Id);
|
|
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
|
|
|
|
|
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;
|
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,
|
|
|
|
|
|
CurrentTenant.Id)
|
|
|
|
|
|
{
|
|
|
|
|
|
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(
|
|
|
|
|
|
CurrentTenant.Id ?? Guid.Empty,
|
|
|
|
|
|
appService.Name);
|
|
|
|
|
|
|
|
|
|
|
|
appService.MarkCompilationSuccess();
|
|
|
|
|
|
await _dynamicAppServiceRepository.UpdateAsync(appService);
|
|
|
|
|
|
|
|
|
|
|
|
return new PublishResultDto
|
|
|
|
|
|
{
|
|
|
|
|
|
Success = true,
|
|
|
|
|
|
AppServiceId = appService.Id,
|
|
|
|
|
|
ControllerName = appService.ControllerName,
|
|
|
|
|
|
GeneratedEndpoints = new List<string>()
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-24 20:44:16 +00:00
|
|
|
|
var loadResult = await _compiler.CompileAndRegisterForTenantAsync(
|
|
|
|
|
|
CurrentTenant.Id ?? Guid.Empty,
|
|
|
|
|
|
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, "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);
|
|
|
|
|
|
|
|
|
|
|
|
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(
|
|
|
|
|
|
CurrentTenant.Id ?? Guid.Empty,
|
|
|
|
|
|
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(
|
|
|
|
|
|
CurrentTenant.Id ?? Guid.Empty,
|
|
|
|
|
|
appService.Name);
|
|
|
|
|
|
}
|
|
|
|
|
|
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.CompileAndRegisterForTenantAsync(
|
|
|
|
|
|
CurrentTenant.Id ?? Guid.Empty,
|
|
|
|
|
|
appService.Code,
|
|
|
|
|
|
assemblyName);
|
|
|
|
|
|
|
|
|
|
|
|
if (!result.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.LogWarning(
|
|
|
|
|
|
"Servis aktif edildi ancak yeniden derleme başarısız. Ad: {Name}, Hata: {Error}",
|
|
|
|
|
|
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.CompileAndRegisterForTenantAsync(
|
|
|
|
|
|
CurrentTenant.Id ?? Guid.Empty,
|
|
|
|
|
|
service.Code,
|
|
|
|
|
|
assemblyName);
|
|
|
|
|
|
|
|
|
|
|
|
if (result.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
successCount++;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
errorCount++;
|
|
|
|
|
|
service.MarkCompilationError(result.ErrorMessage);
|
|
|
|
|
|
await _dynamicAppServiceRepository.UpdateAsync(service);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
errorCount++;
|
|
|
|
|
|
Logger.LogError(ex, "AppService yeniden yükleme hatası. ID: {Id}", service.Id);
|
|
|
|
|
|
|
|
|
|
|
|
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.CompileAndRegisterForTenantAsync(
|
|
|
|
|
|
CurrentTenant.Id ?? Guid.Empty,
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|