Bluestopher
Bluestopher
Explore posts from servers
CC#
Created by Bluestopher on 11/17/2023 in #help
Design Pattern for mapping generic class type to implementation
Hey all, I'm working on an executor service that maps an executor record of a generic type to an executor that can handle performing operations on that type. Currently, I'm receiving errors on a type conversion in my executor methods for being unable to convert a type and I am not sure how to fix it in my design. I believe this design pattern is similar to mapping a command to a handler, but I am just having trouble implementing it. If you can give me feedback on how to my design or how to do it properly it would help a ton, I have been stuck on this for a bit trying different things. To start off, I have a ExecutorService thats job is to take an executor record and map it to an executor and return the results. Each executor has it's own implementation with a catch all "object" executor as default. This requires a few components: 1. ExecutorService, which is my service that my controller uses. 2. ExecutorManager, which is my executor manager that registers all executors from DI and allows the executor service to get a executor by key and pass the executor record to that executor to perform an operation. 3. Executor, which is a handler for performing basic crud operations on executor records of a specific type. 4. ExecutorRecord, which is class for storing generic types of data while containing basic information about that data that is common across executors. 5. ExampleRepository, which is a repository that ExecutorRecords will get from DI for what repository to call for basic CRUD operations. I use my executor service in my controller by creating a record of a specific type and passing it to my ExecutorService with a executor key to map to an specific executor. This approach works well and gives the consumers a nice generic API to work with.
c#
[ApiController]
[Route("[controller]")]
public class ExecutorController : ControllerBase
{
private readonly ILogger<ExecutorController> _logger;

private readonly IExecutorService _executorService;

public ExecutorController(ILogger<ExecutorController> logger, IExecutorService executorService)
{
Requires.NotNull(logger, nameof(logger));
Requires.NotNull(executorService, nameof(executorService));

_logger = logger;
_executorService = executorService;
}

[HttpPost(Name = "CreateRecord")]
public IActionResult Create()
{
ExampleExecutorData exampleExecutorData = new ExampleExecutorData();
ExecutorRecord<object> executorRecord = new ExecutorRecord<object>(Guid.NewGuid(), exampleExecutorData);

IExecutorRecord<object> createdRecord = _executorService.Create(executorRecord, ExecutorKey.Default).Result;

return new JsonResult(createdRecord);
}
}
c#
[ApiController]
[Route("[controller]")]
public class ExecutorController : ControllerBase
{
private readonly ILogger<ExecutorController> _logger;

private readonly IExecutorService _executorService;

public ExecutorController(ILogger<ExecutorController> logger, IExecutorService executorService)
{
Requires.NotNull(logger, nameof(logger));
Requires.NotNull(executorService, nameof(executorService));

_logger = logger;
_executorService = executorService;
}

[HttpPost(Name = "CreateRecord")]
public IActionResult Create()
{
ExampleExecutorData exampleExecutorData = new ExampleExecutorData();
ExecutorRecord<object> executorRecord = new ExecutorRecord<object>(Guid.NewGuid(), exampleExecutorData);

IExecutorRecord<object> createdRecord = _executorService.Create(executorRecord, ExecutorKey.Default).Result;

return new JsonResult(createdRecord);
}
}
227 replies
CC#
Created by Bluestopher on 11/15/2023 in #help
Generic Class Help
Hello, I am working on a PluginManager that contains a dictionary of plugins, which are accessed via keys based off the plugin name. Plugins are generic and have a constraint that the type implements IRecord. I am having an issue with my GetPlugin method because it expects to return IPlugin<IRecord> and not the generic IPlugin<IRecord>. I’m not to sure how to define this since my dictionary of IPlugins is meant to be generic (IPlugin<T>). Does anyone have any ideas on how to fix this or implement it? Also, all my plugins are registered at startup and resolved via DI, which is why I use IRecord as my type of IPlugin since all plugins work on data that implements IRecord. I am a bit stuck currently and tried a bunch of different approaches.
public class PluginManager : IPluginManager
{
private readonly Dictionary<string, IPlugin<IRecord>> _plugins = new();

public PluginManager(IEnumerable<IPlugin<IRecord>> plugins)
{
Requires.NotNull(plugins, nameof(plugins));

plugins.ForEach(RegisterPlugin);
}

private void RegisterPlugin(IPlugin<IRecord> plugin)
{
Requires.NotNull(plugin, nameof(plugin));

if (_plugins.ContainsKey(plugin.Name))
{
throw new ArgumentException($"Unable to register plugin. A plugin with Key: \"{plugin.Name}\" is already registered.");
}

_plugins.Add(plugin.Name, plugin);
}

public IPlugin<T> GetPlugin<T>(string key)
where T : class, IRecord
{
if (!_plugins.ContainsKey(key))
{
throw new ArgumentException($"Plugin with key \"{key}\" is not registered.");
}

return _plugins[key]; // This gives me an error since it cannot return IPlugin<T> since it expects to return IPlugin<IRecord>.
}
}
public class PluginManager : IPluginManager
{
private readonly Dictionary<string, IPlugin<IRecord>> _plugins = new();

public PluginManager(IEnumerable<IPlugin<IRecord>> plugins)
{
Requires.NotNull(plugins, nameof(plugins));

plugins.ForEach(RegisterPlugin);
}

private void RegisterPlugin(IPlugin<IRecord> plugin)
{
Requires.NotNull(plugin, nameof(plugin));

if (_plugins.ContainsKey(plugin.Name))
{
throw new ArgumentException($"Unable to register plugin. A plugin with Key: \"{plugin.Name}\" is already registered.");
}

_plugins.Add(plugin.Name, plugin);
}

public IPlugin<T> GetPlugin<T>(string key)
where T : class, IRecord
{
if (!_plugins.ContainsKey(key))
{
throw new ArgumentException($"Plugin with key \"{key}\" is not registered.");
}

return _plugins[key]; // This gives me an error since it cannot return IPlugin<T> since it expects to return IPlugin<IRecord>.
}
}
3 replies
CC#
Created by Bluestopher on 11/7/2023 in #help
❔ Business Logic Validation in Service Layer
Hey all, I’m working on validating my domain objects that are passed from my framework and drivers (controllers, gRPC service, ect) in my service layer. I’m not sure what the best approach is to apply business logic on my domain entity and have chose to pickup fluentvalidation. This feels a bit overkill, but I’m not sure on what other approaches people use currently. I do not want to throw an exception for business logic validation since it is quite expensive and I would rather return a detailed message that valid failed with a list of errors for all of the validations that failed. Does anyone have any recommendations on patterns for performing validation in the service layer so I can return detailed error responses back to the controller without throwing an exception? I heard about return errors apart of a task, but I have not seen any examples of how this is accomplished.
43 replies
CC#
Created by Bluestopher on 10/19/2023 in #help
❔ C# Design Pattern to Map to Implementation
Hey all, I’m working on a service that executes requests with a specific plug-in based on the plugin key the caller passes. Currently, I create a service class that contains a plug-in manager. The plugin manager registers all the plugins and manages executing the request by the specified plugin. Here is a simple example of how my service is structured: https://dotnetfiddle.net/5fwu23. I’m not sure if there is a better way to do this or specific design pattern to map to the correct implementation by a key. If you have any feedback on how I could design this better or a design pattern that fits this usecase let me know. If this is confusing let me know and I can give a better example.
9 replies