1

I am writing a service, which is to be consumed by API and Web controllers. The result of each call depends on a UserContext state. Should I pass this UserContext with each method, which includes a lot of repetition, or include it as a property of the class, which requires the programmer to properly initialise the class?

What programming principles and patterns should I have in mind here? All feedback is welcome.

Without a property on the class:

public interface IAppService
{
    Task<InitialAppStateDTO> GetInitialAppState(UserContext userContext);

    Task<SearchResultDTO> Search(UserContext userContext, SearchRequest request);

    Task<StatsDTO> GetStats(UserContext userContext);

    Task<List<NotificationDTO>> GetNotifications(UserContext userContext);
}

With a property on the class:

public interface IAppService
{
    UserContext UserContext { get; set; }

    Task<InitialAppStateDTO> GetInitialAppState();

    Task<SearchResultDTO> Search(SearchRequest request);

    Task<StatsDTO> GetStats();

    Task<List<NotificationDTO>> GetNotifications();
}
  • 6
    None. UserContext is the service's implementation details. The consumers of the service should know nothing about how the service retrieves the user's tasks – Laiv Mar 18 at 11:34
4

IAppService interface is your business service interface and there is no need to know about your context. So, do not depend your interface to the context. Because your service class, which implements the interface, may not use your context to get required data or may not need any context(maybe call a web service). Doing your way makes your project monolithic and probably you are doing this to use same transaction scope.

Better way is just letting your interface having your business function(s) and/or properties.

public interface IAppService
{
    Task<InitialAppStateRequestDTO> GetInitialAppState();

    Task<SearchResultDTO> Search(SearchRequest request);

    Task<StatsDTO> GetStats();

    Task<List<NotificationDTO>> GetNotifications();
}

Then inject your context into concrete class if needed

public class AppService : IAppService
{
   private readonly UserContext _userContext;

   public AppService(UserContext userContext)
   {
       _userContext = userContext;
   }

   // interface implementations
}
  • Thanks, I'm using a lot of DI already, question though: If I'm hiding the UserContext from the interface, then that interface conveys nothing about the service being based on UserContext, this will get magically injected at request scope, which you argue is a good thing. Isn't this too magical? – Lunster Mar 18 at 11:21
  • 1
    @Lunster This is really good magic that I know we can use by engineering :) – Engineert Mar 18 at 11:47
  • 1
    It would be magic if you had no constructors nor setters to inject UserContext. As soon as you enable the right interfaces to inject the dependency the design should be "right". Or at least, healthy enough. – Laiv Mar 18 at 12:02
  • 1
    @Lunster The service not conveying anything about what it's based on is a good thing. It means that while the service uses UserContext today, who's to say it will forever? If you expose the UserContext directly then you're guaranteeing its availability. Without that guarantee, you're free to refactor the inner workings. Today that's in the context, tomorrow it might pull that data from a database, later it may be an external service that the AppService makes HTTP calls to. These changes to internal workings need not modify the exposed interface. – Delioth Mar 18 at 18:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.