简体   繁体   English

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

[英]Using XML Webservices in ASP.Net statically or as a singleton

I have an ASP.Net site that consumes ASP.Net XML webservices.我有一个使用 ASP.Net XML webservices 的 ASP.Net 站点。 To communicate with each webmethod in the webservice I have a static class with static business methods, one for each webmethod in the webservice.为了与 webservice 中的每个 webmethod 进行通信,我有一个带有静态业务方法的静态类,一个用于 webservice 中的每个 webmethod。 The static business methods create a new instance of the webreference class each time they are called.每次调用静态业务方法时,都会创建 webreference 类的新实例。 The new instance of the webreference class is used to only call the webmethod, none of the properties in the instance of the webreference are changed from their defaults. webreference 类的新实例仅用于调用 webmethod,webreference 实例中的任何属性都不会更改其默认值。

My question is can I create just a global static instance of the webreference class to use by all of the static business methods instead of creating a new one each time a static business method is called?我的问题是我可以只创建 webreference 类的全局静态实例以供所有静态业务方法使用,而不是每次调用静态业务方法时都创建一个新实例吗? (Basically are instances of a webreference class thread safe?) (基本上是 webreference 类线程安全的实例?)

My concern here is that the instance of the webreference class has some properties that are not thread safe and since the code is for a web site, multiple threads calling the same static business methods at the same time would cause issues between the threads.我在这里担心的是 webreference 类的实例具有一些不是线程安全的属性,并且由于代码是针对网站的,因此多个线程同时调用相同的静态业务方法会导致线程之间出现问题。

The reason I'm asking is to try and find additional changes I can make to increase the site's performance.我要求的原因是尝试找到我可以进行的其他更改以提高网站的性能。 In tracing the site's performance I see a fair amount of time being spent on creating an instance of the webreference class.在跟踪站点的性能时,我发现在创建 webreference 类的实例上花费了相当多的时间。 Additionally based on the garbage collection counters I'm seeing a lot of time being spent there too.此外,根据垃圾收集计数器,我也看到很多时间都花在了那里。

Example Code:示例代码:

This is what I'm currently doing这就是我目前正在做的

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));
       }
    }
}

This is what I'd like to do这就是我想做的

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));
    }
}

My question is can I create just a global static instance of the webreference class to use by all of the static business methods instead of creating a new one each time a static business method is called?我的问题是我可以只创建 webreference 类的全局静态实例以供所有静态业务方法使用,而不是每次调用静态业务方法时都创建一个新实例吗? (Basically are instances of a webreference class thread safe?) (基本上是 webreference 类线程安全的实例?)

My concern here is that the instance of the webreference class has some properties that are not thread safe and since the code is for a web site, multiple threads calling the same static business methods at the same time would cause issues between the threads.我在这里担心的是 webreference 类的实例具有一些不是线程安全的属性,并且由于代码是针对网站的,因此多个线程同时调用相同的静态业务方法会导致线程之间出现问题。

A jolly good question to which it seems you are well on the way to answering.一个有趣的好问题,您似乎已经准备好回答了。 I agree you should probably stick with your current approach where each static method creates its own local copy of the service client.我同意您可能应该坚持使用当前的方法,其中每个静态方法都会创建自己的服务客户端本地副本。 This encourages thread-safety not only from the point of view of the client, but also guarantees that remote calls to the service are done so using unique proxies - where results are not potentially multiplexed with other requests.这不仅从客户端的角度鼓励线程安全,而且还保证使用唯一代理完成对服务的远程调用 - 结果不会与其他请求多路复用。

If you went down the other route of using a shared instance, then you have to take into consideration those scenarios where the service faults in one thread.如果您使用共享实例的另一条路线,那么您必须考虑服务在一个线程中出现故障的那些场景。

  • Maybe there was a timeout?也许有超时?
  • Maybe some remote business logic failed?也许某些远程业务逻辑失败了?
  • Maybe the network failed because your room-mate is downloading the latest episode of Game of Thrones exceeding your download quota?也许网络失败是因为您的室友正在下载最新一集的《权力游戏》,超出了您的下载配额?

You would then need to invalidate that client and recreate a new one .然后,您需要使该客户端无效并重新创建一个新客户端。 All of this would need to be safely thread-locked .所有这些都需要安全的线程锁定 It sort of becomes quite complex to manage this orchestration.管理这种编排变得相当复杂

Let's consider your alternative code:让我们考虑您的替代代码:

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

Let's say this was successfully called the first time.假设这是第一次成功调用。 Now imagine you need to call this 5 mins 5 seconds later but sadly by this time the server has severed the connection because it has a timeout of 5 mins .现在假设您需要在 5 分钟 5 秒后调用它,但遗憾的是此时服务器已经切断了连接,因为它的超时时间为5 分钟 Your second call faults .你的第二个调用错误 The above code would need to be adjusted to allow for those scenarios.需要调整上述代码以允许这些情况。 In our simple example below we recreate the client during a failure and try once more.在下面的简单示例中,我们在失败期间重新创建客户端并再次尝试。

Perhaps:也许:

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;
        }
    }
}

All of this could be wrapped-up in some generic service client cache that could maintain a collection of ready-to-go clients in a connection pool?所有这些都可以包含在一些通用服务客户端缓存中,这些缓存可以在连接池中维护一组准备就绪的客户端? Maybe a background thread periodically pings each client to keep them alive ?也许后台线程会定期 ping 每个客户端以使它们保持活动状态 An exercise for the reader perhaps.也许是给读者的练习。

Then again, sharing the same proxy instance between threads may not be a good idea from the service point of view, unless your service is marked as per-call which may or may not impact your design or performance.再说一次,从服务的角度来看,在线程之间共享相同的代理实例可能不是一个好主意,除非您的服务被标记为每次调用,这可能会也可能不会影响您的设计或性能。

Conclusion结论

Your current code is arguably safer and less complex.您当前的代码可以说更安全、更简单。

Good luck!祝你好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM