Venura Goonatillake
Venura Goonatillake

Reputation: 31

Can not call wcf nettcp operation in a loop in client side, which returns a byte array?

I tried all possible ways to resolve my issue. I will explain my question.

I am trying to create a file transfer mechanism using WCF NetTCP service. Client can request a file from service which running in another machine. File transfer happens in three stages.

BeginFileTranfer - operation in server side, will open the file and get ready for transfer, this will initiate the session;

[OperationContract(IsInitiating = true, IsTerminating = false)]
string BeginFileTransfer(TrnsferType oType, string strFileName,string strFilePath);

GetFileData - operation in server side, will send 1024 (for the time being) bytes per call from opened file

[OperationContract(IsInitiating = false, IsTerminating = false)]
CFileTransferData GetFileData(string strRequestId);

EndFileTransfer - operation in server side, will close the file. Will terminate the session

[OperationContract(IsInitiating = false, IsTerminating = true)]
bool EndFileTranser(string strRequestId);

In client side I call the function to get a file from remote service

private void btnGet_Click(object sender, EventArgs e)
{

    string strId = _AgentService.BeginFileTransfer(iVayagerAgent.TrnsferType.GET,"contacts.csv","D:");
    iVayagerAgent.CFileTransferData oData = null;
    FileStream oFile = null;
    do
    {
         oData = _AgentService.GetFileData(strId);
         if (oData.State == iVayagerAgent.TransferState.OPEN)
         {
             oFile = File.Create("C:\\123\\contacts.csv");
             oFile.Write(oData.Data, 0, oData.Data.Length);
         }
         else if (oData.State == iVayagerAgent.TransferState.PENDING)
         {
             oFile.Write(oData.Data, 0, oData.Data.Length);
         }
         else
         {
             oFile.Close();
         }
    }while(oData.State != iVayagerAgent.TransferState.CLOSE);
}

iVayagerAgent.CFileTransferData

is a class being used to send file data to client side

[DataContract]
public enum TransferState : int
{
    [EnumMember]
    OPEN = 0,
    PENDING = 1,
    CLOSE = 2
}
[DataContract]
public class CFileTransferData
{
    [DataMember]
    public TransferState State{get; set;}
    [DataMember]
    public byte[] Data;
    [DataMember]
    public string Status;
    [DataMember]
    public string StatusDescription;
}

Problem arises when I calling GetFileData in the loop. very first call for GetFileData works fine. Next subsequent call give following error

The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.9679982'.

This is only happens when I send byte array with data. If I send nothing in that array it works fine. It is great If you could point out some areas I could look into. I will show my configuration files as well.

Server config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
      <behaviors>
        <serviceBehaviors>
          <behavior name="serviceBehavior">
            <serviceMetadata />
            <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
            <serviceDebug includeExceptionDetailInFaults="false" />
          </behavior>
        </serviceBehaviors>
      </behaviors>
      <bindings>
        <netTcpBinding>
          <binding name="iVoyagerAgentServiceBinding" receiveTimeout="00:30:00">
            <security mode="None"></security>
            <readerQuotas maxDepth="32"
              maxStringContentLength="5242880"
              maxArrayLength="2147483646"
              maxBytesPerRead="4096"
              maxNameTableCharCount="5242880" />
          </binding>
        </netTcpBinding>
      </bindings>
      <services>
          <service name="iVayagerAgent.iVoyagerAgentService" behaviorConfiguration="">
              <endpoint address="net.tcp://192.168.1.48:9020/IiVoyagerAgentService"
                  binding="netTcpBinding" bindingConfiguration="iVoyagerAgentServiceBinding" contract="iVayagerAgent.IiVoyagerAgentService" >
              </endpoint>
          </service>
      </services>
    </system.serviceModel>
</configuration>

Client Config (I do this at run time, its not picking its configuration from config file)

EndpointAddress oEndPointAddress = new EndpointAddress("net.tcp://" + tbIP.Text + ":" + tbPort.Text + "/IiVoyagerAgentService");

NetTcpBinding oBinding = new NetTcpBinding();
oBinding.Name = "iVoyagerAgentServiceBinding";
XmlDictionaryReaderQuotas myReaderQuotas = new XmlDictionaryReaderQuotas();
myReaderQuotas.MaxStringContentLength = 5242880;
myReaderQuotas.MaxArrayLength = 2147483646;
myReaderQuotas.MaxBytesPerRead = 4096;
myReaderQuotas.MaxDepth = 32;
myReaderQuotas.MaxNameTableCharCount = 5242880;

oBinding.GetType().GetProperty("ReaderQuotas").SetValue(oBinding, myReaderQuotas, null);


oBinding.Security.Mode = SecurityMode.None;
oBinding.ReceiveTimeout = new TimeSpan(0,10,0);
_ChannelFactory = new ChannelFactory<iVayagerAgent.IiVoyagerAgentService>(oBinding, oEndPointAddress);


_ChannelFactory.Opened += new EventHandler(_ChannelFactory_Opened);
_ChannelFactory.Closed += new EventHandler(_ChannelFactory_Closed);

_ChannelFactory.Open();


_AgentService= _ChannelFactory.CreateChannel();

This is the function which build the response for GetFileData

[DataContract]
public enum TransferState : int
{
    [EnumMember]
    OPEN = 0,
    PENDING = 1,
    CLOSE = 2
}
[DataContract]
public class CFileTransferData
{
    [DataMember]
    public TransferState State{get; set;}
    [DataMember]
    public byte[] Data;
    [DataMember]
    public string Status;
    [DataMember]
    public string StatusDescription;
}

public CFileTransferData Get()
{
    int  bNum = 0;
    byte[] bData = new byte[BufferSize];
    CFileTransferData oData = new CFileTransferData();
    oData.Status = "1";
    oData.StatusDescription = "Success"; 

    try
    {
          if(Type == TrnsferType.GET)
          {
              bNum = File.Read(bData, 0, (Int32)BufferSize);
              if (BytesRead == 0)
              {
                  oData.State = TransferState.OPEN;
              }
              else
              {
                  if (bNum != 0)
                  {
                      oData.State = TransferState.PENDING;
                  }
                  else
                  {
                      oData.State = TransferState.CLOSE;
                  }
              }
              oData.Data = bData;
              BytesRead += bNum;
              BytesToRead -= bNum;
          }
          else
          {
              oData.Status = "0";
              oData.StatusDescription = "Invalid Transfer Type";
          }
    }
    catch
    {
        oData.Status = "0";
        oData.StatusDescription = "Critical Error";
    }
    return oData;
}

Please help me to find where I am going wrong. Thank you in advance...

Upvotes: 1

Views: 421

Answers (1)

Venura Goonatillake
Venura Goonatillake

Reputation: 31

Special thanks for asafrob for his efforts of trying to helping me out and also for my friend Roshen. After doing days of coding I would able to figure out where I am going wrong. Finally it's happening in [EnumMembers]

[DataContract]
public enum TransferState : int
{
    [EnumMember]
    OPEN = 0,
    PENDING = 1,
    CLOSE = 2
}

This declaration is wrong if we are using in PENDING and CLOSE Enum members in our response. Because we have not mentioned that PENDING and CLOSE members as [EnumMembers], in the serialization process it goes out and throws an exception. If you are using any member you have to declare it. It will make serialization process smooth.

This is the correct format... (This is all because of lacking of fundamentals :D)

[DataContract]
public enum TransferState : int
{
    [EnumMember]
    OPEN = 0,
    [EnumMember]
    PENDING = 1,
    [EnumMember]
    CLOSE = 2
}

In my question I told the scenario. Now I can explain it why it behaves like that. Problem arises when I calling GetFileData in the loop. very first call for GetFileData works fine. Next subsequent call give following error

Why it is working in very first call is, OPEN enum I have mentioned the attribute as [EnumMember] so its get serialize it normally and work fine, next call I set response status as PENDING. this cause serialization issue.

So thank you very much for your all of your support and for the stackoverflow. Hope this will help many other.

-Venura

Upvotes: 2

Related Questions