'C# Web API Runtime Data with Dependency Injection

If I have a service that relies on data obtained through runtime, what is the best way to inject it into a class?

I have an Order class:

class Order {
   string OrderID { get; set; }
   string CustomerName { get; set; }
   ...
}

I want to encapsulate a lot of logic from the database, so I have a service:

class OrderService {
    private readonly IOrderRepository _orderRepository;
    private readonly IOrder _order;

    public OrderService(IOrderRepository orderRepository, IOrder order) {
        _orderRepository = orderRepository;
        _order = order;
    }

    // some methods that compile data from the repository
    public bool CheckAlreadyExists() { ... }
    public string GetLatestShippingStatus() { ... }
    ...
    ...
    public void Create() { ... }
}

Controller logic:

public class OrderController {
    private readonly IOrderRepository _orderRepository

    public OrderController(IOrderRepository orderRepository)
    {
         orderRepository = _orderRepository
    }

    public IActionResult Create(Order order)
        // this is bad because now I have a dependency on IOrderRepository and OrderService
        OrderService orderService = new OrderService(orderRepository, order)

        if (!orderService.CheckAlreadyExists()) {
            orderService.Create();
        }
    end
}

The two options I am aware of:

  1. Refactor the code to pass runtime data into each of the functions instead
  2. Create a factory OrderServiceFactory

I do not want to have to pass the parameter into every method which all rely on the same object. It seems like overkill to create a factory for every time I need this pattern, which seems like it should be a common use-case.

I think I'm fundamentally misunderstanding something.

  • Is there a pattern that I'm unaware of?
  • Could I create a service that keeps track of the runtime data?
  • Or am I just being stubborn and should create a factory?


Solution 1:[1]

I would simply comment but I don't have the reputation. Long story short, you need to be passing runtime data to OrderService. Read the link provided by Nkosi.

Having OrderService instantiated with a particular Order does not make sense. That means that you have to new up OrderService for every Order you get. Instead, OrderService should have per-lifetime scope. Ie - you can use the same instance of OrderService with multiple Orders. It's not overkill to pass runtime data to every method of a service; it's standard. You're overcomplicating things by forcing your service to rely on an instance of the object it is servicing. And your OrderRepository should not be injected in your controller at all. Use the service to call repository methods.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1