如何在Web API中共享昂贵的资源

时间:2014-04-14 07:49:04

标签: c# architecture asp.net-web-api

我有一个使用昂贵的后端资源的WebAPI项目 - 在设置,内存使用等方面花费的时间很长(在我的实现中是Azure存储队列和表连接)。

显然,多个API调用可以通过使用锁来共享相同的连接(如果他们这样做会很好),从而避免每次启动成本。

我的问题是:建筑的最佳模式是什么?

我知道使用WebAPI你不能真正依赖任何运行的代码 - 因为它对传入的请求作出反应......并且每个调用都有自己的控制器实例。我考虑过有一个静态类,可能在global.ascx中创建它 - 但是保证保留在那里而不是被收集?或者有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

不会收集静态字段(静态类是托管内存根之一),因此除非您手动删除引用,否则它只会在进程(可能是应用程序域)重启时死亡。当然,这可能经常发生,具体取决于您的服务器配置,但这取决于配置:)

请确保您不要在该静态对象上使用事件 - 这是导致大量内存泄漏的好方法之一:)

答案 1 :(得分:2)

我解决这个问题的方法是创建一个封装此行为并通过接口公开它的服务。您可以在服务中执行任何锁定,以确保它始终发生(例如):

public class ExpensiveService : IExpensiveService
{
    private object locker = new object();

    public void SendMessage(Message message)
    {
        lock (this.locker)
        {
            ...
        }
    }
}

始终锁定私有对象,只有需要进行锁定的类才能看到 - 永远不会锁定this

然后,您将服务作为构造函数arg公开给需要它的每个控制器:

public class SomeController
{
    private IExpensiveService expensiveService;

    public SomeController(IExpensiveService expensiveService)
    {
        this.expensiveService = expensiveService;
    }
}

最后,您应该使用IOC容器(Ninject,Autofac,SimpleInjector等)并将ExpensiveService的单个实例注册为容器中的单个实例。这意味着每次创建一个新控制器时,它将获得与每个其他控制器相同的ExpensiveService实例。

这种方法的优点在于它允许您轻松测试控制器,因为您可以模拟IExpensiveService。控制器没有与某些静态对象或单例紧密耦合。