在ASP.Net中静态使用XML Webservices或作为单例

时间:2015-09-11 07:10:37

标签: c# asp.net multithreading web-services static

我有一个ASP.Net站点,它使用ASP.Net XML webservices。为了与webservice中的每个web方法进行通信,我有一个带有静态业务方法的静态类,一个用于webservice中的每个web方法。静态业务方法每次调用时都会创建webreference类的新实例。 webreference类的新实例仅用于调用webmethod,webreference实例中的所有属性都不会从其默认值更改。

我的问题是,我是否可以创建webreference类的全局静态实例,以供所有静态业务方法使用,而不是每次调用静态业务方法时都创建新的静态业务方法? (基本上是webreference类线程安全的实例?)

我担心的是webreference类的实例有一些不是线程安全的属性,因为代码是针对网站的,多个线程同时调用相同的静态业务方法会导致线程之间出现问题

我问的原因是尝试找到我可以做的其他更改来提高网站的性能。在跟踪网站的性能时,我发现花费了大量时间来创建webreference类的实例。此外,基于垃圾收集计数器,我看到很多时间也在那里度过。

示例代码:

这就是我目前正在做的事情

public static class WebMethodWrapper
{
    public static bool CallMethodA(string p1)
    {
       using(com.mysite.service1 _provider = new com.mysite.service1())
       {
            return(_provider.WebMethodA(p1));
       }
    }
    public static bool CallMethodB(string p1)
    {
       using(com.mysite.service1 _provider = new com.mysite.service1())
       {
            return(_provider.WebMethodB(p1));
       }
    }
}

这就是我想做的事情

public static class WebMethodWrapper
{
    static com.mysite.service1 _Provider = null;
    static WebMethodWrapper()
    {
       _Provider = new com.mysite.service1();
    }


    public static bool CallMethodA(string p1)
    {
       return(_Provider.WebMethodA(p1));  
    }
    public static bool CallMethodB(string p1)
    {
      return(_Provider.WebMethodB(p1));
    }
}

1 个答案:

答案 0 :(得分:1)

  

我的问题是,我是否可以创建webreference类的全局静态实例,以供所有静态业务方法使用,而不是每次调用静态业务方法时都创建新的静态业务方法? (基本上是webreference类线程安全的实例?)

     

我担心的是webreference类的实例有一些不是线程安全的属性,因为代码是针对网站的,多个线程同时调用相同的静态业务方法会导致线程之间出现问题

一个快乐的好问题,你似乎在回答的路上很好。我同意您可能会坚持使用您当前的方法,其中每个静态方法都会创建自己的服务客户端本地副本。这不仅从客户端的角度鼓励线程安全,而且还保证使用唯一代理完成对服务的远程调用 - 其中结果不可能与其他请求多路复用。 / p>

如果您使用共享实例的其他路径,那么您必须考虑服务在一个线程中出错的情况。

  • 也许有超时?
  • 也许某些远程业务逻辑失败了?
  • 也许网络失败是因为你的室友正在下载权力的游戏的最新一集超过你的下载配额?

然后,您需要使该客户端无效,重新创建一个新客户端。所有这些都需要安全线程锁定。管理这个业务流程有点非常复杂

让我们考虑您的替代代码:

public static bool CallMethodA(string p1)
{
   return(_Provider.WebMethodA(p1));  
}

让我们说这是第一次成功召集。现在想象你需要在5秒钟之后调用这5分钟,但遗憾的是此时服务器已断开连接,因为它超时 5分钟。您的第二次电话错误。需要调整上述代码以允许这些场景。在下面的简单示例中,我们在失败期间重新创建客户端并再次尝试。

也许:

public static class WebMethodWrapper
{
    static com.mysite.service1 _Provider = null;
    static object _locker = new object();

    static WebMethodWrapper()
    {
        _Provider = new com.mysite.service1();
    }

    static com.mysite.service1 Client
    {
        get
        {
            lock (_locker)
            {
                return _Provider;
            }
        }
    }

    public static bool CallMethodA(string p1)
    {
        try
        {
            return (Client.WebMethodA(p1));
        }
        catch (Exception ex) // normally just catch the exceptions of interest
        {
            // Excercise for reader - use a single method instead of repeating the below
            // recreate
            var c = RecreateProxy();

            // try once more.  
            return (c.WebMethodA(p1));
        }
    }

    public static bool CallMethodB(string p1)
    {
        try
        {
            return (Client.WebMethodB(p1));
        }
        catch (Exception ex) // normally just catch the exceptions of interest
        {
            // Excercise for reader - use a single method instead of repeating the below
            // recreate
            var c = RecreateProxy();

            // try once more.  
            return (c.WebMethodB(p1));
        }
    }

    static com.mysite.service1 RecreateProxy()
    {
        lock (_locker)
        {
            _Provider = new com.mysite.service1();
            return _Provider;
        }
    }
}

所有这些都可以包含在一些通用服务客户端缓存中,这些缓存可以维护连接池中的现成客户端集合吗?也许后台线程定期ping每个客户端让它们保持活着?也许是读者的练习。

然后,从服务的角度来看,在线程之间共享相同的代理实例可能不是一个好主意,除非您的服务标记为 per-call ,这可能会影响您的设计,也可能不会影响您的设计或表现。

结论

您当前的代码可以说更安全,更简单。

祝你好运!