0

In my web application I need to cache some data as they are required frequently but changes less often. To hold them I have made a sepearate static class which hold these field as static values. These field get initialized on first call. see a sample below.

public static class gtu
{
  private static string mostsearchpagedata = "";
  public static string getmostsearchpagedata()
   {
    if (mostsearchpagedata == "")
    {
        using (WebClient client = new WebClient())
        {
            mostsearchpagedata = client.DownloadString("https://xxx.yxc");
        }
    }
    return mostsearchpagedata;
}
 }

Here webrequest is only made one time, it works ok but if they are called in quick succession when there are large no. of users and apppool has restarted, webrequest is made multiple times depending upon mostsearchpagedata was initialized or not.

How can I make sure that webrequest happens only one time, and all other request wait till the completion of the first webrequest?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Ratna
  • 2,289
  • 3
  • 26
  • 50
  • You are looking for a singleton, read about it. https://stackoverflow.com/questions/2667024/singleton-pattern-for-c-sharp – Vladimir Arustamian Jul 06 '17 at 12:27
  • 2
    this is not thread safe, so causing errors. You need singleton for this. refer - http://csharpindepth.com/Articles/General/Singleton.aspx – Yogi Jul 06 '17 at 12:27

1 Answers1

4

You could use System.Lazy<T>:

public static class gtu
{
    private static readonly Lazy<string> mostsearchedpagedata =
       new Lazy<string>(
          () => {
                using (WebClient client = new WebClient())
                {
                   mostsearchpagedata = 
                      client.DownloadString("https://xxx.yxc");
                }
          },
          // See https://msdn.microsoft.com/library/system.threading.lazythreadsafetymode(v=vs.110).aspx for more info
          // on the relevance of this.
          // Hint: since fetching a web page is potentially
          // expensive you really want to do it only once.
          LazyThreadSafeMode.ExecutionAndPublication
       );

    // Optional: provide a "wrapper" to hide the fact that Lazy is used.
    public static string MostSearchedPageData => mostsearchedpagedata.Value;

 }

In short, the lambda code (your DownloadString essentially) will be called, when the first thread calls .Value on the Lazy-instance. Other threads will either do the same or wait for the first thread to finish (see LazyThreadSafeMode for more info). Subsequent invocations of the Value-property will get the value already stored in the Lazy-instance.

Christian.K
  • 47,778
  • 10
  • 99
  • 143