1
0
mirror of https://github.com/bitwarden/server synced 2025-12-15 15:53:59 +00:00
This commit is contained in:
Hinton
2025-10-07 13:42:59 -07:00
parent d0d6bfb237
commit 2b340b72da
2 changed files with 64 additions and 75 deletions

View File

@@ -1,9 +1,6 @@
namespace Bit.SeederApi.Services;
public class RecipeNotFoundException : Exception
{
public RecipeNotFoundException(string message) : base(message) { }
}
public class RecipeNotFoundException(string recipe) : Exception($"Recipe '{recipe}' not found");
public class RecipeExecutionException : Exception
{

View File

@@ -19,82 +19,17 @@ public class RecipeService : IRecipeService
{
try
{
// Find the recipe class
var recipeTypeName = $"Bit.Seeder.Recipes.{templateName}";
var recipeType = Assembly.Load("Seeder")
.GetTypes()
.FirstOrDefault(t => t.FullName == recipeTypeName);
var recipeType = LoadRecipeType(templateName);
var seedMethod = GetSeedMethod(recipeType, templateName);
var recipeInstance = Activator.CreateInstance(recipeType, _databaseContext)!;
if (recipeType == null)
{
throw new RecipeNotFoundException($"Recipe '{templateName}' not found");
}
// Instantiate the recipe with DatabaseContext
var recipeInstance = Activator.CreateInstance(recipeType, _databaseContext);
if (recipeInstance == null)
{
throw new RecipeExecutionException("Failed to instantiate recipe");
}
// Find the Seed method
var seedMethod = recipeType.GetMethod("Seed");
if (seedMethod == null)
{
throw new RecipeExecutionException($"Seed method not found in recipe '{templateName}'");
}
// Parse arguments and match to method parameters
var parameters = seedMethod.GetParameters();
var methodArguments = new object?[parameters.Length];
if (arguments == null && parameters.Length > 0)
{
throw new RecipeExecutionException("Arguments are required for this recipe");
}
for (var i = 0; i < parameters.Length; i++)
{
var parameter = parameters[i];
var parameterName = parameter.Name!;
if (arguments?.TryGetProperty(parameterName, out JsonElement value) == true)
{
try
{
methodArguments[i] = JsonSerializer.Deserialize(value.GetRawText(), parameter.ParameterType);
}
catch (JsonException ex)
{
throw new RecipeExecutionException(
$"Failed to deserialize parameter '{parameterName}': {ex.Message}", ex);
}
}
else if (!parameter.HasDefaultValue)
{
throw new RecipeExecutionException($"Missing required parameter: {parameterName}");
}
else
{
methodArguments[i] = parameter.DefaultValue;
}
}
// Invoke the Seed method
var methodArguments = ParseMethodArguments(seedMethod, arguments);
var result = seedMethod.Invoke(recipeInstance, methodArguments);
_logger.LogInformation("Successfully executed recipe: {TemplateName}", templateName);
_logger.LogInformation("Successfully executed recipe: {TemplateName}", templateName);
return result;
}
catch (RecipeNotFoundException)
{
throw;
}
catch (RecipeExecutionException)
{
throw;
}
catch (Exception ex)
catch (Exception ex) when (ex is not RecipeNotFoundException and not RecipeExecutionException)
{
_logger.LogError(ex, "Unexpected error executing recipe: {TemplateName}", templateName);
throw new RecipeExecutionException(
@@ -102,4 +37,61 @@ public class RecipeService : IRecipeService
ex.InnerException ?? ex);
}
}
private static Type LoadRecipeType(string templateName)
{
var recipeTypeName = $"Bit.Seeder.Recipes.{templateName}";
var recipeType = Assembly.Load("Seeder")
.GetTypes()
.FirstOrDefault(t => t.FullName == recipeTypeName);
return recipeType ?? throw new RecipeNotFoundException(templateName);
}
private static MethodInfo GetSeedMethod(Type recipeType, string templateName)
{
var seedMethod = recipeType.GetMethod("Seed");
return seedMethod ?? throw new RecipeExecutionException($"Seed method not found in recipe '{templateName}'");
}
private static object?[] ParseMethodArguments(MethodInfo seedMethod, JsonElement? arguments)
{
var parameters = seedMethod.GetParameters();
if (arguments == null && parameters.Length > 0)
{
throw new RecipeExecutionException("Arguments are required for this recipe");
}
var methodArguments = new object?[parameters.Length];
for (var i = 0; i < parameters.Length; i++)
{
var parameter = parameters[i];
var parameterName = parameter.Name!;
if (arguments?.TryGetProperty(parameterName, out var value) == true)
{
try
{
methodArguments[i] = JsonSerializer.Deserialize(value.GetRawText(), parameter.ParameterType);
}
catch (JsonException ex)
{
throw new RecipeExecutionException(
$"Failed to deserialize parameter '{parameterName}': {ex.Message}", ex);
}
}
else if (!parameter.HasDefaultValue)
{
throw new RecipeExecutionException($"Missing required parameter: {parameterName}");
}
else
{
methodArguments[i] = parameter.DefaultValue;
}
}
return methodArguments;
}
}