Использование экземпляров и синглетонов в веб-службе WCF с высокой степенью параллелизма

Я разрабатываю веб-службу WCF, которая возвращает информацию из одной из нескольких баз данных на основе string providerCode.

На самом высоком уровне служба вызывает класс StaticBroker, который проверяет providerCode и возвращает соответствующий подкласс DataManager, скажем, MyDataManager. Затем служба вызывает MyDataManager.getVehicleFetcherForStop(), который возвращает экземпляр класса VehicleInfoFetcher, который используется для получения информации.

Я совершенно новичок во всем этом, и я думаю, что, возможно, неправильно спроектировал это. Вот код того, как я это делаю прямо сейчас (упрощенный):

Service.svc.cs

// Public-facing web service method
public string getRealtimeInfo(String stopID, string providerCode = "UK")
{
    DataManager dm = StaticBroker.Instance.dataManager(stopID);
    return dm.getUpcomingVehicleInfoNow(primaryCode);
}

Статикброкер

public sealed class StaticBroker
{    
  UKDataManager ukDataManager = null;

  // Create one instance of each data manager when the Web Service is started,
  // to save memory
  private StaticBroker()
  {
      ukDataManager = new UKDataManager();
  }

  public DataManager dataManager(string providerCode)
  {
     if (providerCode.Equals(UKDataManager.DEFAULT_PROVIDER_CODE))
        return ukDataManager;
     // else if...
  }

  // Most singleton stuff snipped out
  private static readonly StaticBroker instance = new StaticBroker();
}

UKDataManager

public class UKDataManager : DataManager
{
    public const string DEFAULT_PROVIDER_CODE = "UK";

    public string getUpcomingVehicleInfoNow(string stopID)
    {
        VehicleInfoFetcher infoFetcher;
        if ( shouldCheckDB(stopID))
            VehicleInfoFetcher infoFetcher = new DatabaseVehicleInfoFetcher("UK");
        else 
            fetcher = new UKLiveVehicleInfoFetcher();

            return fetcher.getVehicleInfo(primaryCode).Result;  // This is an async method, but we wait for the result
        }
    }
}

Как видите, у меня есть синглтон StaticBroker, который сам хранит только один экземпляр каждого типа DataManager. Наконец, в диспетчерах данных создается фактический экземпляр класса, выполняющего настоящую работу, SomeVehicleFetcher.

Это разумный способ сделать это? Или эти синглтоны и общие экземпляры приведут к проблемам при высоком параллельном использовании веб-службы? Я беспокоился, что создание множества новых экземпляров может привести к проблемам с памятью. Как видите, я не совсем понимаю, как работает цикл времени жизни/памяти приложения в веб-службе.


person Carlos P    schedule 01.08.2013    source источник


Ответы (1)


Вы пытаетесь решить гипотетическую проблему ("может привести к проблемам с памятью") с помощью проекта, в правильности или необходимости которого вы не уверены. Кроме того, в ADO.NET реализовано множество оптимизаций, которые обеспечивают производительность подключения к базе данных.

Это просто создает больше работы и больше головной боли при тестировании (как вы будете изолировать код, который зависит от этого брокера?).

См. Антишаблоны:

Преждевременная оптимизация, изобретенная не здесь

ИЗМЕНИТЬ:

public interface IVehicleInfoRetriever {
    VehicleInfoResponse getVehicleInfo(string primaryCode);
}

public class DataManager<TVehicleInfoFetcher> 
    where TVehicleInfoFetcher : class, new(), IVehicleInfoRetriever 
{

    private string _providerCode;

    public DataManager() : this("UK") { }

    public DataManager(string providerCode) {
        _providerCode = providerCode;
    }

    public string getUpcomingVehicleInfoNow(string stopID)
    {
        VehicleInfoFetcher infoFetcher;
        if ( shouldCheckDB(stopID))
            VehicleInfoFetcher infoFetcher = new DatabaseVehicleInfoFetcher(_providerCode);
        else 
            fetcher = new TVehicleInfoFetcher();

            return fetcher.getVehicleInfo(primaryCode).Result;  // This is an async method, but we wait for the result
        }
    }

}

Что-то подобное устраняет необходимость в «Брокере».

Кроме того, класс, который вы называете «Брокер», больше похож на фабрику, а фабрики потеряли популярность, потому что они позволяют указывать внедрение зависимостей далеко внизу, а не вверху, и они делают конфигурацию среды для модульного тестирования сложная затея.

Конечно, между разновидностями DataManager может быть гораздо больше различий, чем вы показали. Если дело обстоит именно так и их нельзя централизовать, то я рекомендую вам исследовать один из множества доступных контейнеров Inversion Of Control (на ум приходят AutoFac, Unity, Castle Windsor). Эти контейнеры сохранят логику того, какой вариант DataManager использовать, на основе значения времени выполнения кода поставщика в самом верху.

person Keith Payne    schedule 01.08.2013
comment
Конечно, но я действительно не имею в виду «План А» - вы предлагаете, чтобы не было синглтонов и статических объектов? Было бы полезно, если бы вы разместили хотя бы пару строк кода, чтобы указать, как я должен это делать. - person Carlos P; 01.08.2013
comment
Хорошо, теперь я понимаю, что вы имеете в виду - спасибо за подсказки. С момента написания этого вопроса я также узнал больше о InstanceContextMode службы WCF, а также о некоторых хороших обсуждениях здесь, на SO, о том, когда и следует ли использовать службу Singleton. - person Carlos P; 12.08.2013