locked
Calling a class from other classes RRS feed

  • Question

  • Hi

    In my single project I have an API Wrapper class as below which in turn allows access to various services which get data from remote API;

    class APIWrapper
    {
       var baseUrl = "https://blah-blah/";
    
       AuthenticationService authenticationService = new AuthenticationService(baseUrl);
       
       BookedJobService bookedService = new BookedJobService(baseUrl);
       DocumentService documentService = new DocumentService(baseUrl);
       NotificationService notificationService = new NotificationService(baseUrl);
       // etc.
    }

    My issue is how do I access the initialised API Wrapper class from other classes in the project? After initialising API Wrapper do I setup a public reference to it which I can access everywhere in my project or do I (God forbid) initialise it every time? At present I am handling it as below ie I save the reference to initialised API Wrapper using static value.

    class ApplicationSettings
        {
            private static ApplicationSettings _instance;
    
            public APIWrapper apiwrapper { get; set; }
            
            public static ApplicationSettings Instance()
            {
                if (_instance is null)
                {
                    _instance = new ApplicationSettings();
                }
    
                return _instance;
            }
            protected ApplicationSettings()
            {
            }
        }

    Is this the right way to do it or have I missed something?

    Thanks

    Regards



    • Edited by Y a h y a Monday, August 24, 2020 12:02 PM
    Monday, August 24, 2020 12:01 PM

All replies

  • Seems you would new up apiwrapper in the constructor like I've done in this example. Then your singleton can be used throughout the app via instance.

    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Monday, August 24, 2020 12:14 PM
  • You could learn how to use an IoC and dependency injection.

    https://www.tutorialsteacher.com/ioc/dependency-injection

    Monday, August 24, 2020 2:02 PM
  • Your wrapper looks like an aggregate which, in general, I disagree with as I don't believe they have any value. However I would personally create it each time you need it rather than sharing references. What benefit do you get by sharing the reference. The wrapper is creating a bunch of child services and presumably these are not expensive to create. Surely they shouldn't be doing anything expensive in the constructor. If they are then they need to be changed.

    The wrapper itself is creating them when it is first created but do you really need all those services every time? If not then lazy initialize them using Lazy<T> instead. Now you don't take the hit of initializing the service (even if it is expensive) unless you need it. 

    If you really want to use a shared instance then firstly you better make sure that all those services are thread safe otherwise you're going to have issues. Having a single instance means that functionality can be called on any thread at any time and therefore each service must itself be thread safe. If you cannot guarantee that then the service cannot be part of a global wrapper.

    If the services are thread safe and you want a single instance then make the wrapper a singleton. Alternatively what a lot of code does is allow anyone to create an instance of the type (for whatever reason) but also provide a default instance for the common case of just wanting to use the basic functionality.

    So ultimately, if you really want an aggregate wrapper, then I'd do it this way.

    class APIWrapper
    {
       //Default instance for anybody who doesn't want to create their own
       public static readonly APIWrapper Default = new APIWrapper();
    
       //If this isn't the same for all instances then it needs to be a constructor parameter which limits the usefulness of a global   
       var baseUrl = "https://blah-blah/";
    
       //Lazy init these
       public AuthenticationService AuthenticationService => _authenticationService.Value;
    
       private readonly Lazy<AuthenticationService> _authenticationService = new Lazy<AuthenticationService>();
       ...
    }
    
    //Code that just wants the default instance.
    APIWrapper.Default.AuthenticationService
    
    //Code that wants its own instance
    var wrapper = new APIWrapper();
    wrapper.AuthenticationService
    Note that with Lazy<T> when dealing with a type that requires a constructor parameter you need to pass a lambda. This isn't doable in a field initializer if it needs access to data contained in other fields. In that case I tend to create a private function that returns the initialized value and then pass that function to the Lazy<T> constructor. It's a little extra work but keeps things clean.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, August 24, 2020 2:47 PM
  • Hi 

     protected ApplicationSettings()
      {
      apiwrapper = new APIWrapper(); //default constructor
      }

    //the members of APIWrapper class should be public

    Thanks and regards
    Monday, August 24, 2020 4:17 PM
  • Greetings Y a h a.

    Leaving aside the merits of wrapper classes, generally when you want a static instance of something, you don't have to create a singleton to do it.

    public class ApplicationSettings
    {
       static APIWrapper apiWrapper;
       public static APIWrapper API{get{return apiWrapper;}}
    }
    
    
    // Use like so.
    ApplicationSettings.API.Whatever();
    Another option would be to make the APIWrapper class itself static, like the Math class.

    Tuesday, August 25, 2020 12:41 AM