Developer Kits düzenlemesi
This commit is contained in:
parent
ce84b3baac
commit
2ec7f085e4
8 changed files with 397 additions and 137 deletions
|
|
@ -68,6 +68,12 @@ public class CompileResultDto
|
||||||
public bool HasWarnings { get; set; }
|
public bool HasWarnings { get; set; }
|
||||||
[JsonPropertyName("warnings")]
|
[JsonPropertyName("warnings")]
|
||||||
public List<string> Warnings { get; set; }
|
public List<string> Warnings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Yüklenen assembly (sadece server-side kullanım için, JSON'a serialize edilmez)
|
||||||
|
/// </summary>
|
||||||
|
[System.Text.Json.Serialization.JsonIgnore]
|
||||||
|
public System.Reflection.Assembly LoadedAssembly { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -30,16 +30,9 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
[Authorize(AppCodes.DeveloperKits.DynamicServices.TestCompile)]
|
[Authorize(AppCodes.DeveloperKits.DynamicServices.TestCompile)]
|
||||||
public virtual async Task<CompileResultDto> TestCompileAsync(TestCompileRequestDto request)
|
public virtual async Task<CompileResultDto> TestCompileAsync(TestCompileRequestDto request)
|
||||||
{
|
{
|
||||||
Logger.LogInformation("Test compile başlatıldı. Tenant: {TenantId}", CurrentTenant.Id);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await _compiler.CompileAndValidateAsync(request.Code, CurrentTenant.Id);
|
return 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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -51,9 +44,6 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
[Authorize(AppCodes.DeveloperKits.DynamicServices.Publish)]
|
[Authorize(AppCodes.DeveloperKits.DynamicServices.Publish)]
|
||||||
public virtual async Task<PublishResultDto> PublishAsync(PublishAppServiceRequestDto request)
|
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
|
try
|
||||||
{
|
{
|
||||||
// Önce kodu test compile et
|
// Önce kodu test compile et
|
||||||
|
|
@ -82,11 +72,9 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
existingService.PrimaryEntityType = request.PrimaryEntityType;
|
existingService.PrimaryEntityType = request.PrimaryEntityType;
|
||||||
|
|
||||||
appService = await _dynamicAppServiceRepository.UpdateAsync(existingService);
|
appService = await _dynamicAppServiceRepository.UpdateAsync(existingService);
|
||||||
Logger.LogInformation("Mevcut AppService güncellendi. ID: {Id}", appService.Id);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Yeni servis oluştur
|
|
||||||
appService = new DynamicService(
|
appService = new DynamicService(
|
||||||
GuidGenerator.Create(),
|
GuidGenerator.Create(),
|
||||||
request.Name,
|
request.Name,
|
||||||
|
|
@ -100,11 +88,9 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
};
|
};
|
||||||
|
|
||||||
appService = await _dynamicAppServiceRepository.InsertAsync(appService);
|
appService = await _dynamicAppServiceRepository.InsertAsync(appService);
|
||||||
Logger.LogInformation("Yeni AppService oluşturuldu. ID: {Id}", appService.Id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runtime'da derle ve yükle
|
var assemblyName = $"{appService.Name}_{appService.Version}";
|
||||||
var assemblyName = $"DynamicAppService_{appService.Id}_{appService.Version}";
|
|
||||||
var loadResult = await _compiler.CompileAndRegisterForTenantAsync(
|
var loadResult = await _compiler.CompileAndRegisterForTenantAsync(
|
||||||
CurrentTenant.Id ?? Guid.Empty,
|
CurrentTenant.Id ?? Guid.Empty,
|
||||||
request.Code,
|
request.Code,
|
||||||
|
|
@ -112,23 +98,21 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
|
|
||||||
if (loadResult.Success)
|
if (loadResult.Success)
|
||||||
{
|
{
|
||||||
// Başarılı derleme durumunu kaydet
|
|
||||||
appService.MarkCompilationSuccess();
|
appService.MarkCompilationSuccess();
|
||||||
await _dynamicAppServiceRepository.UpdateAsync(appService);
|
await _dynamicAppServiceRepository.UpdateAsync(appService);
|
||||||
|
|
||||||
var result = new PublishResultDto
|
var endpoints = loadResult.LoadedAssembly != null
|
||||||
|
? _compiler.ExtractEndpointsFromAssembly(loadResult.LoadedAssembly, request.Name)
|
||||||
|
: new List<string>();
|
||||||
|
|
||||||
|
return new PublishResultDto
|
||||||
{
|
{
|
||||||
Success = true,
|
Success = true,
|
||||||
AppServiceId = appService.Id,
|
AppServiceId = appService.Id,
|
||||||
ControllerName = appService.ControllerName,
|
ControllerName = appService.ControllerName,
|
||||||
SwaggerUrl = "/swagger/index.html",
|
SwaggerUrl = "/swagger/index.html",
|
||||||
GeneratedEndpoints = GenerateEndpointList(request.Name)
|
GeneratedEndpoints = endpoints
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger.LogInformation("AppService başarıyla yayınlandı. ID: {Id}, Controller: {Controller}",
|
|
||||||
appService.Id, appService.ControllerName);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -178,59 +162,38 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
|
|
||||||
var dtos = ObjectMapper.Map<List<DynamicService>, List<DynamicServiceDto>>(items);
|
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);
|
return new PagedResultDto<DynamicServiceDto>(totalCount, dtos);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(AppCodes.DeveloperKits.DynamicServices.ViewCode)]
|
[Authorize(AppCodes.DeveloperKits.DynamicServices.ViewCode)]
|
||||||
public virtual async Task<DynamicServiceDto> GetAsync(Guid id)
|
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 appService = await _dynamicAppServiceRepository.GetAsync(id);
|
||||||
var dto = ObjectMapper.Map<DynamicService, DynamicServiceDto>(appService);
|
return ObjectMapper.Map<DynamicService, DynamicServiceDto>(appService);
|
||||||
|
|
||||||
return dto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(AppCodes.DeveloperKits.DynamicServices.Delete)]
|
[Authorize(AppCodes.DeveloperKits.DynamicServices.Delete)]
|
||||||
public virtual async Task DeleteAsync(Guid id)
|
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);
|
var appService = await _dynamicAppServiceRepository.GetAsync(id);
|
||||||
|
|
||||||
// TODO: Runtime'dan assembly'yi kaldırma işlemi
|
// TODO: Runtime'dan assembly'yi kaldırma işlemi
|
||||||
// (AssemblyLoadContext.Unload() çağrısı)
|
// (AssemblyLoadContext.Unload() çağrısı)
|
||||||
|
|
||||||
await _dynamicAppServiceRepository.DeleteAsync(id);
|
await _dynamicAppServiceRepository.DeleteAsync(id);
|
||||||
|
|
||||||
Logger.LogInformation("AppService silindi. ID: {Id}", id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
|
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
|
||||||
public virtual async Task SetActiveAsync(Guid id, bool isActive)
|
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);
|
var appService = await _dynamicAppServiceRepository.GetAsync(id);
|
||||||
appService.IsActive = isActive;
|
appService.IsActive = isActive;
|
||||||
|
|
||||||
await _dynamicAppServiceRepository.UpdateAsync(appService);
|
await _dynamicAppServiceRepository.UpdateAsync(appService);
|
||||||
|
|
||||||
Logger.LogInformation("AppService aktiflik durumu güncellendi. ID: {Id}, Aktif: {Active}",
|
|
||||||
id, isActive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
|
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
|
||||||
public virtual async Task ReloadAllActiveServicesAsync()
|
public virtual async Task ReloadAllActiveServicesAsync()
|
||||||
{
|
{
|
||||||
Logger.LogInformation("Tüm aktif AppService'ler yeniden yükleniyor. Tenant: {TenantId}",
|
|
||||||
CurrentTenant.Id);
|
|
||||||
|
|
||||||
var activeServices = await _dynamicAppServiceRepository
|
var activeServices = await _dynamicAppServiceRepository
|
||||||
.GetListAsync(x => x.IsActive && x.CompilationStatus == CompilationStatus.Success);
|
.GetListAsync(x => x.IsActive && x.CompilationStatus == CompilationStatus.Success);
|
||||||
|
|
@ -242,7 +205,8 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var assemblyName = $"DynamicAppService_{service.Id}_{service.Version}";
|
// Service.Name üzerinden assembly adı oluştur
|
||||||
|
var assemblyName = $"{service.Name}_{service.Version}";
|
||||||
var result = await _compiler.CompileAndRegisterForTenantAsync(
|
var result = await _compiler.CompileAndRegisterForTenantAsync(
|
||||||
CurrentTenant.Id ?? Guid.Empty,
|
CurrentTenant.Id ?? Guid.Empty,
|
||||||
service.Code,
|
service.Code,
|
||||||
|
|
@ -251,17 +215,12 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
successCount++;
|
successCount++;
|
||||||
Logger.LogDebug("AppService yeniden yüklendi. ID: {Id}, Ad: {Name}",
|
|
||||||
service.Id, service.Name);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
errorCount++;
|
errorCount++;
|
||||||
service.MarkCompilationError(result.ErrorMessage);
|
service.MarkCompilationError(result.ErrorMessage);
|
||||||
await _dynamicAppServiceRepository.UpdateAsync(service);
|
await _dynamicAppServiceRepository.UpdateAsync(service);
|
||||||
|
|
||||||
Logger.LogWarning("AppService yeniden yüklenemedi. ID: {Id}, Hata: {Error}",
|
|
||||||
service.Id, result.ErrorMessage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -273,19 +232,14 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
await _dynamicAppServiceRepository.UpdateAsync(service);
|
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)]
|
[Authorize(AppCodes.DeveloperKits.DynamicServices.Manage)]
|
||||||
public virtual async Task<CompileResultDto> RecompileAsync(Guid id)
|
public virtual async Task<CompileResultDto> RecompileAsync(Guid id)
|
||||||
{
|
{
|
||||||
Logger.LogInformation("AppService yeniden derleniyor. ID: {Id}", id);
|
|
||||||
|
|
||||||
var appService = await _dynamicAppServiceRepository.GetAsync(id);
|
var appService = await _dynamicAppServiceRepository.GetAsync(id);
|
||||||
|
|
||||||
var assemblyName = $"DynamicAppService_{appService.Id}_{appService.Version + 1}";
|
var assemblyName = $"{appService.Name}_{appService.Version + 1}";
|
||||||
var result = await _compiler.CompileAndRegisterForTenantAsync(
|
var result = await _compiler.CompileAndRegisterForTenantAsync(
|
||||||
CurrentTenant.Id ?? Guid.Empty,
|
CurrentTenant.Id ?? Guid.Empty,
|
||||||
appService.Code,
|
appService.Code,
|
||||||
|
|
@ -303,9 +257,6 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
|
|
||||||
await _dynamicAppServiceRepository.UpdateAsync(appService);
|
await _dynamicAppServiceRepository.UpdateAsync(appService);
|
||||||
|
|
||||||
Logger.LogInformation("AppService yeniden derleme tamamlandı. ID: {Id}, Başarılı: {Success}",
|
|
||||||
id, result.Success);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -324,16 +275,4 @@ public class DynamicAppServiceAppService : PlatformAppService, IDynamicServiceAp
|
||||||
|
|
||||||
return controllerName;
|
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"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,30 +178,21 @@ public class DynamicServiceCompiler : ITransientDependency
|
||||||
|
|
||||||
var assembly = loadContext.LoadFromStream(ms);
|
var assembly = loadContext.LoadFromStream(ms);
|
||||||
|
|
||||||
// ApplicationService türevlerini bul
|
|
||||||
var appServiceTypes = assembly.GetTypes()
|
var appServiceTypes = assembly.GetTypes()
|
||||||
.Where(t => IsApplicationServiceType(t))
|
.Where(t => IsApplicationServiceType(t))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
_logger.LogInformation("Tenant {TenantId} için {Count} ApplicationService bulundu",
|
|
||||||
tenantId, appServiceTypes.Count);
|
|
||||||
|
|
||||||
// Tenant assembly'leri listesine ekle
|
|
||||||
_tenantAssemblies.AddOrUpdate(tenantId,
|
_tenantAssemblies.AddOrUpdate(tenantId,
|
||||||
new List<Assembly> { assembly },
|
new List<Assembly> { assembly },
|
||||||
(key, existing) => { existing.Add(assembly); return existing; });
|
(key, existing) => { existing.Add(assembly); return existing; });
|
||||||
|
|
||||||
// Background service'e assembly kaydı isteği gönder
|
|
||||||
// Bu, DI container ve MVC conventional controller sistemine kaydetmek için
|
|
||||||
NotifyAssemblyRegistration?.Invoke(tenantId, assembly, assemblyName);
|
NotifyAssemblyRegistration?.Invoke(tenantId, assembly, assemblyName);
|
||||||
|
|
||||||
_logger.LogInformation("Tenant {TenantId} için assembly başarıyla yüklendi: {AssemblyName}",
|
|
||||||
tenantId, assemblyName);
|
|
||||||
|
|
||||||
return new CompileResultDto
|
return new CompileResultDto
|
||||||
{
|
{
|
||||||
Success = true,
|
Success = true,
|
||||||
CompilationTimeMs = validateResult.CompilationTimeMs
|
CompilationTimeMs = validateResult.CompilationTimeMs,
|
||||||
|
LoadedAssembly = assembly
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -331,12 +322,9 @@ public class DynamicServiceCompiler : ITransientDependency
|
||||||
{
|
{
|
||||||
references.Add(MetadataReference.CreateFromFile(assembly.Location));
|
references.Add(MetadataReference.CreateFromFile(assembly.Location));
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogDebug("Toplam {Count} referans eklendi", references.Count);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
_logger.LogWarning(ex, "ABP referansları eklenirken hata");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return references;
|
return references;
|
||||||
|
|
@ -355,9 +343,8 @@ public class DynamicServiceCompiler : ITransientDependency
|
||||||
(type.Name.EndsWith("AppService") || type.Name.EndsWith("ApplicationService")) &&
|
(type.Name.EndsWith("AppService") || type.Name.EndsWith("ApplicationService")) &&
|
||||||
HasApplicationServiceBase(type);
|
HasApplicationServiceBase(type);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
_logger.LogWarning(ex, "Tip kontrolü sırasında hata: {Type}", type?.FullName);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -394,4 +381,109 @@ public class DynamicServiceCompiler : ITransientDependency
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assembly içindeki ApplicationService'lerden endpoint listesini çıkarır
|
||||||
|
/// </summary>
|
||||||
|
public List<string> ExtractEndpointsFromAssembly(Assembly assembly, string serviceName)
|
||||||
|
{
|
||||||
|
var endpoints = new List<string>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Assembly içindeki ApplicationService türlerini bul
|
||||||
|
var appServiceTypes = assembly.GetTypes()
|
||||||
|
.Where(t => IsApplicationServiceType(t) && t.Name == serviceName)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var serviceType in appServiceTypes)
|
||||||
|
{
|
||||||
|
// Controller adını oluştur (ABP convention: CustomerAppService -> Customer)
|
||||||
|
var controllerName = serviceType.Name;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABP kebab-case convention (DynamicCustomer -> dynamic-customer)
|
||||||
|
var routePrefix = ToKebabCase(controllerName);
|
||||||
|
|
||||||
|
// Public method'ları bul (async method'lar genelde Async suffix'i ile biter)
|
||||||
|
var methods = serviceType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
|
||||||
|
.Where(m => !m.IsSpecialName) // Property getter/setter'ları hariç tut
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
// Method adından Async suffix'ini kaldır ve kebab-case'e çevir
|
||||||
|
var methodName = method.Name;
|
||||||
|
if (methodName.EndsWith("Async"))
|
||||||
|
{
|
||||||
|
methodName = methodName.Substring(0, methodName.Length - "Async".Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
var methodRoute = ToKebabCase(methodName);
|
||||||
|
|
||||||
|
// HTTP verb'ü belirle (basit heuristic)
|
||||||
|
var httpVerb = DetermineHttpVerb(method);
|
||||||
|
|
||||||
|
// Endpoint'i oluştur
|
||||||
|
var endpoint = $"{httpVerb} /api/app/{routePrefix}/{methodRoute}";
|
||||||
|
endpoints.Add(endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Endpoint çıkarma sırasında hata");
|
||||||
|
}
|
||||||
|
|
||||||
|
return endpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// PascalCase'i kebab-case'e çevirir (DynamicCustomer -> dynamic-customer)
|
||||||
|
/// </summary>
|
||||||
|
private string ToKebabCase(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return string.Concat(
|
||||||
|
value.Select((x, i) => i > 0 && char.IsUpper(x)
|
||||||
|
? "-" + x.ToString()
|
||||||
|
: x.ToString())
|
||||||
|
).ToLower();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Method'un HTTP verb'ünü belirler (ABP convention'a göre)
|
||||||
|
/// </summary>
|
||||||
|
private string DetermineHttpVerb(MethodInfo method)
|
||||||
|
{
|
||||||
|
var methodName = method.Name.ToLowerInvariant();
|
||||||
|
|
||||||
|
// ABP naming convention
|
||||||
|
if (methodName.StartsWith("get") || methodName.StartsWith("find") || methodName.StartsWith("list"))
|
||||||
|
return "GET";
|
||||||
|
if (methodName.StartsWith("create") || methodName.StartsWith("insert") || methodName.StartsWith("add"))
|
||||||
|
return "POST";
|
||||||
|
if (methodName.StartsWith("update") || methodName.StartsWith("edit"))
|
||||||
|
return "PUT";
|
||||||
|
if (methodName.StartsWith("delete") || methodName.StartsWith("remove"))
|
||||||
|
return "DELETE";
|
||||||
|
|
||||||
|
// Default olarak GET (ABP'de parametre yoksa GET, varsa POST)
|
||||||
|
var parameters = method.GetParameters();
|
||||||
|
if (parameters.Length == 0 || parameters.All(p => p.ParameterType.IsValueType || p.ParameterType == typeof(string)))
|
||||||
|
{
|
||||||
|
return "GET";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "POST";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.DynamicServices;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a change token to notify MVC infrastructure (and Swagger/ApiExplorer)
|
||||||
|
/// that action descriptors have changed at runtime.
|
||||||
|
/// </summary>
|
||||||
|
public class ActionDescriptorChangeProvider : IActionDescriptorChangeProvider
|
||||||
|
{
|
||||||
|
private readonly ILogger<ActionDescriptorChangeProvider> _logger;
|
||||||
|
private CancellationTokenSource _cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
public ActionDescriptorChangeProvider(ILogger<ActionDescriptorChangeProvider> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IChangeToken GetChangeToken()
|
||||||
|
{
|
||||||
|
_logger.LogDebug("GetChangeToken çağrıldı");
|
||||||
|
return new CancellationChangeToken(_cts.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Call this method after adding/removing controllers at runtime to notify
|
||||||
|
/// MVC/Swagger that action descriptors must be refreshed.
|
||||||
|
/// </summary>
|
||||||
|
public void NotifyChanges()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("NotifyChanges çağrıldı - MVC/Swagger yenilenecek");
|
||||||
|
var prev = Interlocked.Exchange(ref _cts, new CancellationTokenSource());
|
||||||
|
prev.Cancel();
|
||||||
|
_logger.LogInformation("Change token başarıyla iptal edildi - yenileme tetiklendi");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "NotifyChanges sırasında hata");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,7 @@ namespace Kurs.Platform.DynamicServices
|
||||||
private readonly ILogger<DynamicAssemblyRegistrationService> _logger;
|
private readonly ILogger<DynamicAssemblyRegistrationService> _logger;
|
||||||
private readonly ApplicationPartManager _partManager;
|
private readonly ApplicationPartManager _partManager;
|
||||||
private readonly IOptions<AbpAspNetCoreMvcOptions> _mvcOptions;
|
private readonly IOptions<AbpAspNetCoreMvcOptions> _mvcOptions;
|
||||||
|
private readonly ActionDescriptorChangeProvider _changeProvider;
|
||||||
|
|
||||||
// Bekleyen assembly kayıt istekleri
|
// Bekleyen assembly kayıt istekleri
|
||||||
private static readonly Queue<AssemblyRegistrationRequest> _pendingRegistrations = new();
|
private static readonly Queue<AssemblyRegistrationRequest> _pendingRegistrations = new();
|
||||||
|
|
@ -32,12 +33,14 @@ namespace Kurs.Platform.DynamicServices
|
||||||
IServiceProvider serviceProvider,
|
IServiceProvider serviceProvider,
|
||||||
ILogger<DynamicAssemblyRegistrationService> logger,
|
ILogger<DynamicAssemblyRegistrationService> logger,
|
||||||
ApplicationPartManager partManager,
|
ApplicationPartManager partManager,
|
||||||
IOptions<AbpAspNetCoreMvcOptions> mvcOptions)
|
IOptions<AbpAspNetCoreMvcOptions> mvcOptions,
|
||||||
|
ActionDescriptorChangeProvider changeProvider)
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_partManager = partManager;
|
_partManager = partManager;
|
||||||
_mvcOptions = mvcOptions;
|
_mvcOptions = mvcOptions;
|
||||||
|
_changeProvider = changeProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -59,15 +62,15 @@ namespace Kurs.Platform.DynamicServices
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Dynamic Assembly Registration Service başlatıldı");
|
await Task.Delay(3000, stoppingToken);
|
||||||
|
|
||||||
|
await LoadExistingServicesOnStartup();
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ProcessPendingRegistrations();
|
await ProcessPendingRegistrations();
|
||||||
|
|
||||||
// 5 saniye bekle
|
|
||||||
await Task.Delay(5000, stoppingToken);
|
await Task.Delay(5000, stoppingToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -75,8 +78,44 @@ namespace Kurs.Platform.DynamicServices
|
||||||
_logger.LogError(ex, "Assembly registration service hatası");
|
_logger.LogError(ex, "Assembly registration service hatası");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Dynamic Assembly Registration Service durduruluyor");
|
private async Task LoadExistingServicesOnStartup()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var scope = _serviceProvider.CreateScope();
|
||||||
|
|
||||||
|
var repository = scope.ServiceProvider.GetService<Volo.Abp.Domain.Repositories.IRepository<Kurs.Platform.Entities.DynamicService, Guid>>();
|
||||||
|
var compiler = scope.ServiceProvider.GetService<Kurs.Platform.DynamicServices.DynamicServiceCompiler>();
|
||||||
|
|
||||||
|
if (repository == null || compiler == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var activeServices = await repository.GetListAsync(x => x.IsActive && x.CompilationStatus == Kurs.Platform.Entities.CompilationStatus.Success);
|
||||||
|
|
||||||
|
foreach (var service in activeServices)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var assemblyName = $"{service.Name}_{service.Version}";
|
||||||
|
await compiler.CompileAndRegisterForTenantAsync(
|
||||||
|
service.TenantId ?? Guid.Empty,
|
||||||
|
service.Code,
|
||||||
|
assemblyName);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Servis yükleme hatası: {Name}", service.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Startup servis yükleme hatası");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessPendingRegistrations()
|
private async Task ProcessPendingRegistrations()
|
||||||
|
|
@ -94,8 +133,6 @@ namespace Kurs.Platform.DynamicServices
|
||||||
if (requests.Count == 0)
|
if (requests.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_logger.LogDebug("İşlenecek {Count} assembly kaydı var", requests.Count);
|
|
||||||
|
|
||||||
foreach (var request in requests)
|
foreach (var request in requests)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
@ -112,43 +149,86 @@ namespace Kurs.Platform.DynamicServices
|
||||||
|
|
||||||
private async Task RegisterAssembly(AssemblyRegistrationRequest request)
|
private async Task RegisterAssembly(AssemblyRegistrationRequest request)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Assembly kaydediliyor. Tenant: {TenantId}, Assembly: {Assembly}",
|
var lastUnderscoreIndex = request.AssemblyName.LastIndexOf('_');
|
||||||
request.TenantId, request.AssemblyName);
|
if (lastUnderscoreIndex > 0)
|
||||||
|
{
|
||||||
|
var servicePrefix = request.AssemblyName.Substring(0, lastUnderscoreIndex + 1);
|
||||||
|
|
||||||
|
var oldParts = _partManager.ApplicationParts
|
||||||
|
.OfType<AssemblyPart>()
|
||||||
|
.Where(p => p.Name.StartsWith(servicePrefix) && p.Name != request.AssemblyName)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var oldPart in oldParts)
|
||||||
|
{
|
||||||
|
_partManager.ApplicationParts.Remove(oldPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldSettings = _mvcOptions.Value.ConventionalControllers.ConventionalControllerSettings
|
||||||
|
.Where(s => s.Assembly.GetName().Name?.StartsWith(servicePrefix) == true &&
|
||||||
|
s.Assembly.GetName().Name != request.AssemblyName)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var oldSetting in oldSettings)
|
||||||
|
{
|
||||||
|
_mvcOptions.Value.ConventionalControllers.ConventionalControllerSettings.Remove(oldSetting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ApplicationService türlerini bul
|
|
||||||
var appServiceTypes = request.Assembly.GetTypes()
|
var appServiceTypes = request.Assembly.GetTypes()
|
||||||
.Where(t => IsApplicationServiceType(t))
|
.Where(t => IsApplicationServiceType(t))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (appServiceTypes.Count == 0)
|
if (appServiceTypes.Count == 0)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Assembly'de ApplicationService bulunamadı: {Assembly}", request.AssemblyName);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dependency Injection Container'a ekle
|
foreach (var serviceType in appServiceTypes)
|
||||||
using (var scope = _serviceProvider.CreateScope())
|
|
||||||
{
|
{
|
||||||
var services = scope.ServiceProvider.GetRequiredService<IServiceCollection>();
|
DynamicServiceTypeRegistry.RegisterType(serviceType);
|
||||||
|
|
||||||
foreach (var serviceType in appServiceTypes)
|
|
||||||
{
|
|
||||||
// Transient olarak kaydet
|
|
||||||
services.AddTransient(serviceType);
|
|
||||||
_logger.LogDebug("DI'ya eklendi: {ServiceType}", serviceType.FullName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MVC Application Parts'a ekle (Controllers için)
|
var existingPart = _partManager.ApplicationParts
|
||||||
var assemblyPart = new AssemblyPart(request.Assembly);
|
.OfType<AssemblyPart>()
|
||||||
_partManager.ApplicationParts.Add(assemblyPart);
|
.FirstOrDefault(p => p.Assembly == request.Assembly);
|
||||||
|
|
||||||
|
if (existingPart == null)
|
||||||
|
{
|
||||||
|
var assemblyPart = new AssemblyPart(request.Assembly);
|
||||||
|
_partManager.ApplicationParts.Add(assemblyPart);
|
||||||
|
}
|
||||||
|
|
||||||
// ABP Conventional Controllers'a ekle
|
try
|
||||||
_mvcOptions.Value.ConventionalControllers.Create(request.Assembly);
|
{
|
||||||
|
var isConfigured = _mvcOptions.Value.ConventionalControllers.ConventionalControllerSettings
|
||||||
_logger.LogInformation("Assembly başarıyla kaydedildi. Tenant: {TenantId}, Assembly: {Assembly}, Service Count: {Count}",
|
.Any(s => s.Assembly == request.Assembly);
|
||||||
request.TenantId, request.AssemblyName, appServiceTypes.Count);
|
|
||||||
|
if (!isConfigured)
|
||||||
|
{
|
||||||
|
_mvcOptions.Value.ConventionalControllers.Create(request.Assembly, options =>
|
||||||
|
{
|
||||||
|
options.RootPath = "app";
|
||||||
|
options.RemoteServiceName = "Default";
|
||||||
|
options.TypePredicate = t => appServiceTypes.Contains(t);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Conventional Controllers eklenirken hata");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_changeProvider.NotifyChanges();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "ActionDescriptor notify hatası");
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(100);
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,9 +242,8 @@ namespace Kurs.Platform.DynamicServices
|
||||||
(type.Name.EndsWith("AppService") || type.Name.EndsWith("ApplicationService")) &&
|
(type.Name.EndsWith("AppService") || type.Name.EndsWith("ApplicationService")) &&
|
||||||
HasApplicationServiceBase(type);
|
HasApplicationServiceBase(type);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
_logger.LogWarning(ex, "Tip kontrolü sırasında hata: {Type}", type?.FullName);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.DynamicServices;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registry for dynamically loaded service types
|
||||||
|
/// </summary>
|
||||||
|
public static class DynamicServiceTypeRegistry
|
||||||
|
{
|
||||||
|
private static readonly ConcurrentBag<Type> _registeredTypes = new();
|
||||||
|
|
||||||
|
public static void RegisterType(Type type)
|
||||||
|
{
|
||||||
|
if (!_registeredTypes.Contains(type))
|
||||||
|
{
|
||||||
|
_registeredTypes.Add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsRegistered(Type type)
|
||||||
|
{
|
||||||
|
return _registeredTypes.Contains(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Type> GetAllTypes()
|
||||||
|
{
|
||||||
|
return _registeredTypes.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Custom controller activator that can create instances of dynamically loaded controllers
|
||||||
|
/// </summary>
|
||||||
|
public class DynamicControllerActivator : IControllerActivator
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private readonly ILogger<DynamicControllerActivator> _logger;
|
||||||
|
|
||||||
|
public DynamicControllerActivator(
|
||||||
|
IServiceProvider serviceProvider,
|
||||||
|
ILogger<DynamicControllerActivator> logger)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Create(ControllerContext context)
|
||||||
|
{
|
||||||
|
var controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// First try to get from DI
|
||||||
|
var instance = _serviceProvider.GetService(controllerType);
|
||||||
|
|
||||||
|
if (instance != null)
|
||||||
|
{
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not in DI (dynamic controllers), use ActivatorUtilities
|
||||||
|
if (DynamicServiceTypeRegistry.IsRegistered(controllerType))
|
||||||
|
{
|
||||||
|
instance = ActivatorUtilities.CreateInstance(_serviceProvider, controllerType);
|
||||||
|
|
||||||
|
if (instance != null)
|
||||||
|
{
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last resort - use default activation
|
||||||
|
return ActivatorUtilities.CreateInstance(_serviceProvider, controllerType);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Controller oluşturma hatası: {Type}", controllerType.Name);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Release(ControllerContext context, object controller)
|
||||||
|
{
|
||||||
|
if (controller is IDisposable disposable)
|
||||||
|
{
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ using Kurs.Platform.FileManagement;
|
||||||
using Kurs.Platform.Identity;
|
using Kurs.Platform.Identity;
|
||||||
using Kurs.Platform.Localization;
|
using Kurs.Platform.Localization;
|
||||||
using Kurs.Settings;
|
using Kurs.Settings;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.Extensions.DependencyInjection;
|
using Microsoft.AspNetCore.Extensions.DependencyInjection;
|
||||||
|
|
@ -50,6 +51,7 @@ using Volo.Abp.Swashbuckle;
|
||||||
using Volo.Abp.UI.Navigation.Urls;
|
using Volo.Abp.UI.Navigation.Urls;
|
||||||
using Volo.Abp.VirtualFileSystem;
|
using Volo.Abp.VirtualFileSystem;
|
||||||
using Kurs.Platform.DynamicServices;
|
using Kurs.Platform.DynamicServices;
|
||||||
|
using Kurs.Platform.DeveloperKit;
|
||||||
using static Kurs.Platform.PlatformConsts;
|
using static Kurs.Platform.PlatformConsts;
|
||||||
using static Kurs.Settings.SettingsConsts;
|
using static Kurs.Settings.SettingsConsts;
|
||||||
|
|
||||||
|
|
@ -360,8 +362,15 @@ public class PlatformHttpApiHostModule : AbpModule
|
||||||
// Dynamic AppService Background Service
|
// Dynamic AppService Background Service
|
||||||
context.Services.AddHostedService<DynamicAssemblyRegistrationService>();
|
context.Services.AddHostedService<DynamicAssemblyRegistrationService>();
|
||||||
|
|
||||||
// Roslyn Compiler Servisleri
|
// Roslyn Compiler
|
||||||
context.Services.AddSingleton<DynamicServiceCompiler>();
|
context.Services.AddSingleton<DynamicServiceCompiler>();
|
||||||
|
|
||||||
|
// Action descriptor change provider for runtime controller registration
|
||||||
|
context.Services.AddSingleton<ActionDescriptorChangeProvider>();
|
||||||
|
context.Services.AddSingleton<IActionDescriptorChangeProvider>(sp => sp.GetRequiredService<ActionDescriptorChangeProvider>());
|
||||||
|
|
||||||
|
// Custom controller activator for dynamic dependency injection
|
||||||
|
context.Services.AddSingleton<Microsoft.AspNetCore.Mvc.Controllers.IControllerActivator, DynamicControllerActivator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnApplicationInitialization(ApplicationInitializationContext context)
|
public override void OnApplicationInitialization(ApplicationInitializationContext context)
|
||||||
|
|
@ -369,6 +378,12 @@ public class PlatformHttpApiHostModule : AbpModule
|
||||||
var app = context.GetApplicationBuilder();
|
var app = context.GetApplicationBuilder();
|
||||||
var env = context.GetEnvironment();
|
var env = context.GetEnvironment();
|
||||||
|
|
||||||
|
// Setup delegate for dynamic service registration
|
||||||
|
DynamicServiceCompiler.NotifyAssemblyRegistration = (tenantId, assembly, assemblyName) =>
|
||||||
|
{
|
||||||
|
DynamicAssemblyRegistrationService.RequestAssemblyRegistration(tenantId, assembly, assemblyName);
|
||||||
|
};
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
if (env.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
|
|
|
||||||
|
|
@ -167,10 +167,8 @@ namespace DynamicServices
|
||||||
description: description,
|
description: description,
|
||||||
primaryEntityType: primaryEntityType,
|
primaryEntityType: primaryEntityType,
|
||||||
}
|
}
|
||||||
console.log('Publish request data:', requestData)
|
|
||||||
|
|
||||||
const result = await dynamicServiceService.publish(requestData)
|
const result = await dynamicServiceService.publish(requestData)
|
||||||
|
|
||||||
setPublishResult(result)
|
setPublishResult(result)
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
|
@ -548,9 +546,6 @@ namespace DynamicServices
|
||||||
|
|
||||||
{publishResult.success && (
|
{publishResult.success && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<p className="text-green-700 text-sm">
|
|
||||||
AppService başarıyla yayınlandı ve Swagger'a eklendi.
|
|
||||||
</p>
|
|
||||||
{publishResult.controllerName && (
|
{publishResult.controllerName && (
|
||||||
<p className="text-sm text-gray-600">
|
<p className="text-sm text-gray-600">
|
||||||
Controller:{' '}
|
Controller:{' '}
|
||||||
|
|
@ -574,15 +569,6 @@ namespace DynamicServices
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex gap-2 mt-3">
|
|
||||||
<button
|
|
||||||
onClick={openSwagger}
|
|
||||||
className="flex items-center gap-1 bg-blue-600 text-white px-3 py-1 rounded text-sm hover:bg-blue-700"
|
|
||||||
>
|
|
||||||
<FaExternalLinkAlt className="w-3 h-3" />
|
|
||||||
Swagger'da Gör
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue