Hi TerryLee:
经常读你写的Blog,从你的文章中学到不少东西,谢谢。
有个关于WCF的问题想请教你一下。我在使用WCF从客户端控制事务的时候,发现必须客户端和服务器端同时配置MSDTC才行,配置如下:
To configure the Microsoft Distributed Transaction Coordinator (MSDTC) to support running the sample across machines
On the service machine, configure MSDTC to allow incoming network transactions.
From the Start menu, navigate to Control Panel, then Administrative Tools, and then Component Services.
Right-click My Computer and select Properties.
On the MSDTC tab, click Security Configuration.
Check Network DTC Access and Allow Inbound.
Click Yes to restart the MSDTC service and then click OK.
Click OK to close the dialog box.
On the service machine and the client machine, configure the Windows Firewall to include the Microsoft Distributed Transaction Coordinator (MSDTC) to the list of excepted applications:
Run the Windows Firewall application from Control Panel.
From the Exceptions tab, click Add Program.
Browse to the folder C:\WINDOWS\System32.
Select Msdtc.exe and click Open.
Click OK to close the Add Program dialog box, and click OK again to close the Windows Firewall applet.
On the client machine, configure MSDTC to allow outgoing network transactions:
From the Start menu, navigate to Control Panel, then Administrative Tools, and then Component Services.
Right-click My Computer and select Properties.
On the MSDTC tab, click Security Configuration.
Check Network DTC Access and Allow Outbound.
Click Yes to restart the MS DTC service and then click OK.
Click OK to close the dialog box.
而且MSDTC还不能像Web Service那样穿透防火墙,我不知道是我代码的原因还是怎么的?怎么样才能脱离MSDTC来使用Transaction?麻烦你帮我看看,代码如下:
服务器端CS:
[ServiceContract(SessionMode=SessionMode.Required)]
public interface IAccountActivities
{
#region Interface for service
[OperationContract]
string HelloWorld(string strUserName);
[OperationContract]
int GetBalance(string strAccountNumber);
[OperationContract]
int DebitBalance(string strAccountNumber, int nAmount);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
int CreditBalance(string strAccountNumber, int nAmount);
[OperationContract]
int WriteLog(string strAccountNumber, string strOperationType);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
void transferFunds(string strFromAccountNumber, string strToAccountNumber, int nAmount);
#endregion
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class AccountActivities : IAccountActivities
{
#region IAccountActivities Members
public string HelloWorld(string strUserName)
{
return "Hello World, " + strUserName;
}
public int GetBalance(string strAccountNumber)
{
string strSQL = "select Amount from ATMAccount where AccountNumber = '" + strAccountNumber + "'";
return Convert.ToInt32(SqlHelper.ExecuteScalar(CommandType.Text, strSQL));
}
public int DebitBalance(string strAccountNumber, int nAmount)
{
string strSQL = "update ATMAccount set Amount = Amount - " + nAmount + " where AccountNumber='" + strAccountNumber + "'";
return SqlHelper.ExecuteNonQuery(CommandType.Text, strSQL);
}
[OperationBehavior(TransactionScopeRequired=true)]
public int CreditBalance(string strAccountNumber, int nAmount)
{
string strSQL = "update ATMAccount set Amount = Amount + " + nAmount + " where AccountNumber='" + strAccountNumber + "'";
return SqlHelper.ExecuteNonQuery(CommandType.Text, strSQL);
}
public int WriteLog(string strAccountNumber, string strOperationType)
{
string strSQL = "insert into ATMLog (AccountNumber,OperationType) values ('" + strAccountNumber + "','" + strOperationType + "')";
return SqlHelper.ExecuteNonQuery(CommandType.Text, strSQL);
}
[OperationBehavior(TransactionScopeRequired=true)]
public void transferFunds(string strFromAccountNumber, string strToAccountNumber, int nAmount)
{
DebitBalance(strFromAccountNumber, nAmount);
CreditBalance(strToAccountNumber, nAmount);
WriteLog(strFromAccountNumber, "Transfer From");
WriteLog(strToAccountNumber, "Transfer To");
if (GetBalance(strFromAccountNumber) < 0)
{
throw new Exception("Transaction Rollback : There is not so much money in account" + strFromAccountNumber);
}
}
#endregion
服务器端WebConfig:
<configuration xmlns="
http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="ATMwsHttpBinding" transactionFlow="true" />
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="BankServicesBehavior" name="Aegis.BankServices.AccountActivities">
<endpoint binding="wsHttpBinding" bindingConfiguration="ATMwsHttpBinding"
contract="Aegis.BankServices.IAccountActivities" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="BankServicesBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
客户端使用Service代码:
using (TransactionScope objTransactionScope = new TransactionScope())
{
try
{
nTemp = m_ATMService.CreditBalance(m_strAccountNumber, Convert.ToInt32(strTransactionAmount));
m_ATMService.WriteLog(m_strAccountNumber, "Credit");
objTransactionScope.Complete();
}
catch (Exception ex)
{
MessageBox.Show("error:" + ex.Message);
}
}
if (m_ATMService.State != System.ServiceModel.CommunicationState.Faulted)
{
nReturnedBalance = nTemp;
}
else
{
ATMServices.AccountActivitiesClient myService = new ATMClient.ATMServices.AccountActivitiesClient();
myService.WriteLog("001", "error");
}
不胜感激。