2

Working on a project where a controller is utilizing a RestSharp client that is instantiated in a Startup class. Is the Startup class invoked multiple times? Do I assume that the Web Server has spawned my controller in a thread and I am running asynchrous or can there be multiple instances of my controller on different threads running at the same time. RestSharp suggests that the client connection be set up and accessed through a Singleton pattern. The Singleton implementation for the RestSharp object is using the Interface approach without a lock on the resource. I am not fully convinced that is correct especially if there multiple threads which may have finite lifetimes. Any thoughts and enlightenment on the server execution concepts are appreciated.

Update

I found this article to be helpful: https://learn.microsoft.com/en-us/aspnet/core/performance/performance-best-practices?view=aspnetcore-6.0

I am going to assume that when my controller is called that I am running concurrently with other asynchronous tasks in a single thread allocated from a thread pool. I will also assume that there could be other threads processing the same request for other users.

I also found that RestSharp makes use of HttpClient. I found help here : Is HttpClient safe to use concurrently?

I also found that although RestSharp is fully asynchronous it is not thread safe. https://github.com/restsharp/RestSharp/issues/951

I need to visit the RestSharp Singleton implementation in my code and figure out how to maintain an instance for each thread to use.

Here is my solution to hold one RestSharp Client Object instance per thread as to block only the current thread when positing to the Rest server:

/// <summary>
/// The purpose of this class to provide applications with Thread Safe
/// instances of objects. An object can be a single instance across
/// all threads or a single instance per thread.
/// </summary>
 public sealed class SafeObjectContainer<T>
 {
  // Make use of .Net's Thread Safe Lazy Loading
  private static readonly Lazy<SafeObjectContainer<T> > lazy =
    new Lazy<SafeObjectContainer<T> >(() => new SafeObjectContainer<T>());

  // Thread Safe Dictionary that will hold the Objects
  private ConcurrentDictionary<String, T > _protectedDictionary;

  // First Access of the object will create the SafeObjectContainer
  // for the specified template Type 
  public static SafeObjectContainer<T> Instance { get { return lazy.Value; } }

  private SafeObjectContainer()
  {
   // Gives us Thread Safe and Concurrency Safe Storage
   _protectedDictionary = new ConcurrentDictionary<string, T >();
  }

  // Manage Objects that will have one Instance per Thread
  public T ThreadInstanceOfObject()
  {
   // Build the Key for this Thread
   var thread = Thread.CurrentThread;
   var key = String.Format("Thread-{0}", thread.ManagedThreadId);

   return GetObjectInstance(key);
  }

  // Manage Objects that will have one Instance per Application
  public T ApplicatioInstanceOfObject()
  {
   // Build the Key for the Application Instance
   var thread = Thread.CurrentThread;
   var key = "Instance";

   return GetObjectInstance(key);
  }

  // Lookup and Create the Object Instance if necessary
  private T GetObjectInstance(String key)
  {
   T protectedObject = default;
   if (_protectedDictionary.TryGetValue(key, out protectedObject) == false)
   {
    protectedObject = (T)Activator.CreateInstance(typeof(T), new object[] { });
    _protectedDictionary.TryAdd(key, protectedObject);
   }

   return protectedObject;
  }
}

 
sfanjoy
  • 640
  • 6
  • 16

0 Answers0