在高并发的WCF Web服务中使用实例和单例模式

4
我正在开发一个 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的一个实例。在DataManagers内部,最终创建了执行实际工作的类SomeVehicleFetcher的实际实例。
这样做是合理的吗?当Web服务高并发使用时,这些单例和共享实例是否会导致问题?我担心创建大量新实例可能会导致内存问题。正如您所见,我真的不太理解应用程序在Web服务中的生命周期/内存循环如何工作。
1个回答

3
你试图用一个你不确定是否正确或者必要的设计来解决一个假设性问题(“可能导致内存问题”)。而且,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
        }
    }

}

类似这样的方法可以省略'Broker'的需求。

而且,你所称之为'Broker'的类更像是一个工厂。现在工厂已经不太流行了,因为它们会导致依赖注入变得复杂,并使单元测试中的环境配置变得困难。

当然,你所展示的DataManager可能有很多不同之处。如果情况确实如此,它们无法集中管理,那么我建议你研究一下可用的控制反转容器(例如AutoFac、Unity、Castle Windsor)。这些容器将根据运行时provider代码的值,在顶部保持使用哪个flavor的DataManager的逻辑。


当然可以,但我真的没有想好“计划A” - 你是在建议不应该有单例和静态对象吗?如果您能发布至少几行代码以指示我应该如何做将会很有帮助。 - Carlos P
好的,我现在明白你的意思了 - 感谢你的指引。自从写下这个问题后,我还发现了更多关于WCF服务的InstanceContextMode以及一些关于何时/是否使用单例服务的好讨论。 - Carlos P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接