2

I want to set property in some injected service in controller for later abusing it when this service will be injected in other place during the same request, so I expect this property not to change as far as service is injected as Scoped.

Is that safe approach or how would you suggest to achive such a behaviour?

MyController(IServiceWithProperty serviceWithProperty) {
  _serviceWithProperty = serviceWithProperty;
}

public IActionResult Get(int settingToSet) {
  _serviceWithProperty.SetProperty(settingToSet);
  return Ok(_anotherService.GetSomething()); 
}

And as I said AnotherService injects ServiceWithProperty as well.

public class AnotherService : IAnotherService {
  public AnotherService(IServiceWithProperty serviceWithProperty) {
    _serviceWithProperty = serviceWithProperty;
  }

  public string GetSomething() {
    int prop = _serviceWithProperty.GetProperty(); //here I expect to get property which has been set in controller, would that work and is it fine to do it like that?
  } 
}
Grigoryants Artem
  • 1,401
  • 2
  • 15
  • 32
  • 3
    Your statement _in controller for later abusing it when this service_ already should give you an answer: Just when you use the word **abuse** should make it clear its a code smell :P To me it sounds more like your API design isn't very well thought. If its a value that's called within the same process it probably means you need it as parameter and should rather pass it as parameter. Or you need an intermediatory service which connects/coordinates the two of your services – Tseng Oct 25 '18 at 15:58
  • Of course passing additional parameter is a better option in terms of security and maintainability, but the problem is that services structure is much more complicated and there are multiple services depending on service which I want to inject property in, so passing additional parameter for all of them looks kinda ugly... – Grigoryants Artem Oct 26 '18 at 06:43

2 Answers2

2

The interaction between those two services is going to be hard to follow once the size of the code base grows. Even given this simple example (good job of reducing the problem to its essence, BTW), I had to look at the code for a few minutes to understand what's going on.

Besides, a design like this seems to be close to violating the Liskov Substitution Principle (LSP), because it'll only work when specific, concrete implementations are in use. According to the LSP, you should be able to exchange one subtype with another without changing the correctness of the system. Is this possible here? Can you replace the IServiceWithProperty implementation you have in mind with another implementation that does nothing?

Instead, follow the Dependency Inversion Principle, from which it follows that clients should define the abstraction. So, if MyController requires an abstraction that can translate an int to something else, then that's the abstraction it requires:

MyController(ITranslator translator) {
  _translator = translator;
}

public IActionResult Get(int setting) {
  return Ok(_translator.Translate(setting)); 
}

The next step, then, is to figure out how to implement the ITranslator interface.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
0

It'll work because both services are singletons within the lifetime of a request, so the property will hold its value also.

However i would recommend to share those values not as properties rather as arguments of your service functions like:

public IActionResult Get(int settingToSet) 
{
    return Ok(_anotherService.GetSomething(settingToSet)); 
}

public class AnotherService : IAnotherService 
{
    public AnotherService(ISomeAnotherService service) 
    {
         _service = service;
    }

    public string GetSomething(int inputValue) 
    {
        int serviceResult = _service.GetSomething(inputValue);
    } 
 }

This makes the code much clearer, and lower your chances that you will end up 5 months later investigating where and whom was that property set to that value you don't expect at that time.

Péter Csajtai
  • 878
  • 6
  • 9