【问题标题】:Is it possible to create stateful web service in C#?是否可以在 C# 中创建有状态的 Web 服务?
【发布时间】:2011-05-06 06:58:57
【问题描述】:

我现在有这样的东西:

public class Service1 : System.Web.Services.WebService
{
    [WebMethod]
    public string Method1()
    {
        SomeObj so = SomeClass.GetSomeObj(); //this executes very long time, 50s and more
        return so.Method1(); //this exetus in a moment 
    }

    [WebMethod]
    public string Method2()
    {
        SomeObj so = SomeClass.GetSomeObj(); //this executes very long time, 50s and more
        return so.Method2(); //this exetus in a moment 
    }

 ...
}

是否可以制作有状态的 Web 服务,以便我可以重用 SomeObj so 并只调用同一个对象上的方法?

因此,将使用此服务的客户端将首先调用 Web 方法,该方法将创建 so 对象并返回一些 ID。 然后在后续调用中,Web 服务将根据 ID 重用相同的 so 对象。

编辑


这是我的实际代码:

[WebMethod]
public List<ProcInfo> GetProcessList(string domain, string machineName)
{
    string userName = "...";
    string password = "...";
    TaskManager tm = new TaskManager(userName, password, domain, machineName);

    return tm.GetRunningProcesses();
}

[WebMethod]
public bool KillProcess(string domain, string machineName, string processName)
{
    string userName = "...";
    string password = "...";
    (new TaskManager(userName, password, domain, machineName);).KillProcess(processName);               
}

【问题讨论】:

    标签: c# web-services persistence object-persistence stateful


    【解决方案1】:

    选项 1

    您可以使用您的 HttpSession。

    //this executes very long time, 50s and more, but only once.
    private SomeObj SessionSomeObj { 
      get 
      { 
        var ret = (SomeObj)Session["SomeObjStore"] ?? SomeClass.GetSomeObj();
        SessionSomeObj = ret;
        return ret; 
      }
      set { Session["SomeObjStore"] = value; }
    }
    
    [WebMethod(EnableSession = true)]
    public string Method1()
    {
        return SessionSomeObj.Method1(); //this exetus in a moment 
    }
    
    [WebMethod(EnableSession = true)]
    public string Method2()
    {
        return SessionSomeObj.Method2(); //this exetus in a moment 
    }
    

    请注意,这仅在每个客户一次拨打一个电话时才有效。

    选项 2

    您可以保持课程不变,但使用不同的 WebMethod。如果您从 .Net 生成的类中调用,则会为这些事件提供 async 方法。基本上,您调用 Method1 开始请求方法并在执行完成时获得回调。您可能需要调整 Web 服务客户端类的超时参数才能使其正常工作。

    选项 3

    您可以使用SixPack librarycaching features 轻松做到这一点! ;-)


    [在评论后编辑] 现在选项 1 中有两个静态字段,以允许两个不同的实例,每个方法一个,根据要求。


    [在进一步解释后编辑] 使用 Session 使调用有状态。

    见:http://msdn.microsoft.com/en-us/library/aa480509.aspx

    还添加了选项 3。

    【讨论】:

    • 选项 1 不可行,因为不同的客户端需要不同的“so”对象来调用方法。
    • 我认为我们有一些误解。 Client1 创建“so”对象的实例,然后在该实例上调用 method1 到 methodN。 Client2 创建另一个“so” oject 实例,并在此实例上再次调用相同或不同的方法。所以每个客户都需要有不同的“so”实例
    • 那么你可以使用字典来代替......这种方法的主要问题是对象不会持续超过 AppDomain 的生命周期。
    • 什么时候结束这个“AppDomain 的生命周期”?
    • 进程终止时的正常应用程序。对于 ASP.net,只要 IIS 决定重新启动它就会发生这种情况,尤其是在配置更改之后。 weblogs.asp.net/owscott/archive/2006/02/21/ASP.NET-v2.0-2D00-AppDomain-recycles_2C00_-more-common-than-before.aspx
    【解决方案2】:

    把你界面的ServiceContract改成:

    [ServiceContract(SessionMode = SessionMode.Required)]
    

    并在你的类上添加以下属性:

    [ServiceBehaviorAttribute(InstanceContextMode = InstanceContextMode.PerSession)]
    

    有关更多信息和示例,请参阅http://msdn.microsoft.com/en-us/library/system.servicemodel.sessionmode.aspx

    【讨论】:

      【解决方案3】:

      有状态的 Web 服务不可扩展,我不推荐它们。相反,您可以将昂贵操作的结果存储在cache 中。此缓存可以通过自定义提供程序分发以获得更好的可扩展性:

      [WebMethod]
      public string Method1()
      {
          SomeObj so = TryGetFromCacheOrStore<SomeObj>(() => SomeClass.GetSomeObj(), "so");
          return so.Method1(); //this exetus in a moment 
      }
      
      [WebMethod]
      public string Method2()
      {
          SomeObj so = TryGetFromCacheOrStore<SomeObj>(() => SomeClass.GetSomeObj(), "so");
          return so.Method2(); //this exetus in a moment 
      }
      
      private T TryGetFromCacheOrStore<T>(Func<T> action, string id)
      {
          var cache = Context.Cache;
          T result = (T)cache[id];
          if (result == null)
          {
              result = action();
              cache[id] = result;
          }
          return result;
      }
      

      【讨论】:

      • 你能把所有对象都存储在缓存中还是有什么限制?我的对象包括与各种计算机的开放 WMI 连接。
      • 默认情况下,缓存存储在内存中,如果您开始在低内存上运行,它将自动被驱逐。所以是的,你可以存储尽可能多的东西,但你应该始终检查对象是否在缓存中,并且永远不要因为你存储了它而依赖它。
      • @Darin Dimitrov,您应该使用锁使您的解决方案类型安全。当一个请求正在执行“result = action();”时行,这需要时间,任何其他请求也会将缓存视为空并重复相同的“result = action();”线。见en.wikipedia.org/wiki/Double-checked_locking
      • 我真的不明白你在说什么。你一定是误会了。写一个测试。 :-)
      • 换句话说:在执行 action() 之前,cache[id] 将为空。任何其他线程测试它也将执行 action()。
      猜你喜欢
      • 1970-01-01
      • 2010-09-22
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多