当被称为一个WCF服务的析构函数 [英] When is destructor called in a WCF service

查看:120
本文介绍了当被称为一个WCF服务的析构函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要创建将保持WCF会话服务。
在构造函数中我从数据库中读取数据和会话结束时我一定要救回来。



如果我理解正确的会话结束时,我调用Close()的客户端(我的客户ServiceClient与svcutil.exe的创建)。



当我测试它,我看到,它有时也被称为后约。 10分钟,有时20分钟后,有时甚至根本没有。



所以,当析构函数叫什么名字?



服务

  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] 
公共类服务:IService
{
私人用户m_User = NULL;

公共服务()
{
m_User = User.LoadFromDB();
}

〜服务()
{
m_User.SaveToDB();
}

公共无效SETNAME(字符串p_Name)
{
m_User.Name = p_Name;
}
}



Web.config文件

 <?XML版本=1.0>?; 
<结构>
<&的System.Web GT;
<的sessionState超时=2/>
< /system.web>
< system.serviceModel>
< serviceHostingEnvironment multipleSiteBindingsEnabled =真/>
<服务和GT;
<服务名称=Karatasi.Services.B2CbehaviorConfiguration =ServiceBehavior>
<主机>
< baseAddresses>
<添加baseAddress =HTTP://本地主机:19401 / B2C.svc/>
< / baseAddresses>
< /主机>
<终点
地址=
结合=的wsHttpBinding
bindingConfiguration =测试
合同=Karatasi.Services.IB2C
/>
<终点
地址=MEX
结合=mexHttpBinding
合同=IMetadataExchange接口
/>
< /服务>
< /服务>
<&绑定GT;
<&的wsHttpBinding GT;
<绑定名称=测试receiveTimeout =00:01:00>
<启用=的ReliableSession真命令=假inactivityTimeout =00:01:00/>
< /&结合GT;
< /&的wsHttpBinding GT;
< /绑定>
<&行为GT;
< serviceBehaviors>
<行为NAME =ServiceBehavior>
< serviceMetadata httpGetEnabled =真/>
< serviceDebug includeExceptionDetailInFaults =FALSE/>
< /行为>
< / serviceBehaviors>
< /行为>
< /system.serviceModel>
< /结构>



客户端

  serviceClient serviceClient = NULL; 

{
serviceClient =新ServiceClient();
serviceClient.SetName(新名称);
Console.WriteLine(姓名集);
}
赶上(例外p_Exc)
{
Console.WriteLine(p_Exc.Message);
}
终于
{
如果(serviceClient!= NULL)
{
如果(serviceClient.State == CommunicationState.Faulted)
{
serviceClient.Abort();
}
,否则
{
serviceClient.Close();
}
}
Console.ReadKey();
}


解决方案

从的docs




,程序员时,因为这是由垃圾收集器确定的析构函数被调用
无法控制。为对象不再是垃圾
集电极检查正由
的应用程序。如果它认为销毁对象符合条件时,
调用析构函数(如果有的话)并收回用于存储
对象的内存。析构函数也被称为当程序退出。




有与您的实现问题。要保留您所使用的析构函数的数据。这是错误的,因为析构函数不能在一个单独的结束队列被称为确定性,他们正在处理。这意味着,即使你已经摧毁了对象,其析构函数可能不会立即调用。



如何解决这个问题结果
卸下析构函数,并使用IDisposable模式来代替,把节省的逻辑到处置。一旦会话终止,WCF将调用IDisposable.Dispose

 公共类服务:IService,IDisposable的
{
公共无效的Dispose()
{
//你的逻辑保存在这里
}
}

修改

PLS也看到这个答案的评论。其实我同意的IDisposable 不是数据库提交适当的位置,之前没有发生在我身上。另外在注释提供的解决方案可以使用明确划定会议


I need to create a service which will maintain a WCF session. In the constructor I read in data from the DB and when the session ends I have to save it back.

If I understand correctly the session ends when I call Close() on the Client (My client ServiceClient was created with SvcUtil.exe).

When I test it I see that it is sometimes called after approx. 10 minutes, sometimes after 20 minutes and sometimes not at all.

So when is the destructor called?

Service

   [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
   public class Service:IService
   {
     private User m_User = null;

     public  Service()
     {
       m_User = User.LoadFromDB();
     }

     ~Service()
     {
       m_User.SaveToDB();
     }

     public void SetName(string p_Name)
     {
       m_User.Name = p_Name;
     }
    }

Web.config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <sessionState timeout="2" />
  </system.web>
  <system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
      <services>
        <service name="Karatasi.Services.B2C"  behaviorConfiguration="ServiceBehavior">
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost:19401/B2C.svc"/>
            </baseAddresses>
          </host>
        <endpoint
           address=""
           binding="wsHttpBinding"
           bindingConfiguration="test"
           contract="Karatasi.Services.IB2C"
         />
        <endpoint
           address="mex"
           binding="mexHttpBinding"
           contract="IMetadataExchange"
         />
       </service>
     </services>
   <bindings>
     <wsHttpBinding>
       <binding name="test" receiveTimeout="00:01:00" >
         <reliableSession enabled="true" ordered="false" inactivityTimeout="00:01:00"/>
       </binding>
     </wsHttpBinding>
    </bindings>
  <behaviors>
    <serviceBehaviors>
      <behavior name="ServiceBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="false" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>
</configuration>

Client

    ServiceClient serviceClient = null;
    try
    {
      serviceClient = new ServiceClient();
      serviceClient.SetName("NewName");
      Console.WriteLine("Name set");
    }
    catch (Exception p_Exc)
    {
      Console.WriteLine(p_Exc.Message);
    }
    finally
    {
      if (serviceClient != null)
      {
        if (serviceClient.State == CommunicationState.Faulted)
        {
          serviceClient.Abort();
        }
        else
        {
          serviceClient.Close();
        }
      }
      Console.ReadKey();
    }

解决方案

From docs

The programmer has no control over when the destructor is called because this is determined by the garbage collector. The garbage collector checks for objects that are no longer being used by the application. If it considers an object eligible for destruction, it calls the destructor (if any) and reclaims the memory used to store the object. Destructors are also called when the program exits.

There is a problem with your implementation. To persist data you are using destructor. This is wrong because destructors cannot be called deterministically, they are processed in a separate finalization queue. This means that even though you have destroyed the object, its destructor may not be immediately called.

How to fix this
Remove the destructor and use IDisposable pattern instead, put save logic into Dispose. Once the session is terminated, WCF will call IDisposable.Dispose

public class Service:IService, IDisposable
{
    public void Dispose()
    {
        //your save logic here
    }
}

EDIT
Pls also see the comment to this answer. I actually agree that IDisposable isn't the proper place for database commits, didn't occur to me before. Additionally to the solutions provided in the comment you can use explicit session demarcation

这篇关于当被称为一个WCF服务的析构函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆