SAP Connector for Microsoft .Net v3 - SAPIDocSender class missing

585 Views Asked by At

I have used SAP Connector for Microsoft .Net v2 to successfully send already formatted IDOCS to SAP.

Today I upgraded to the latest version of the connector. Unfortunately, this SAPIDocSender is not there anymore.

How should I now send those IDOCS to SAP?

Thanks for your help!

EDIT: Thanks! Unfortunately I want to avoid building the IDOC like it is described in the other Thread.

In v2 there was an option to send the whole IDOC string including all segments:

private static void SendIdoc()
{     
    SAP.Connector.RfcTID myTid = SAP.Connector.RfcTID.NewTID();  
    string connectionString = "ASHOST=xxxx SYSNR=xx CLIENT=xxx USER=xxx PASSWD=xxx LANG=xx";
    string upperString = connectionString.ToUpper();
    SAP.Connector.SAPIDocSender sapiDocSender = new SAPIDocSender(upperString);
    sapiDocSender.SubmitIDoc(@"C:\Users\xxx\Documents\testidoc.txt", myTid);
    sapiDocSender.ConfirmTID(myTid);
}
3

There are 3 best solutions below

1
On BEST ANSWER

as far as I know there is now idoc helper in the current Net Connector 3. But if you have a file containing a valid idoc, you already have all the information you need.

The basics about sending Idocs to the SAP system are described here already, so I won't go into detail about that in this answer. To send your idoc file, you have to manually fill the control record (first line of your idoc) and the data records.

The control table requires some manual labor. Fortunately the control record is the same on all idocs, so you don't have to consider the idoc type your sending.

var fileStream = System.IO.File.OpenRead(fullFilepath);
var streamReader = new System.IO.StreamReader(fileStream);
string control = streamReader.ReadLine();

controlTable.Append();
controlTable.CurrentRow.SetValue("TABNAM", control.Substring(0, 10));
controlTable.CurrentRow.SetValue("MANDT", control.Substring(10, 3));
controlTable.CurrentRow.SetValue("DOCNUM", control.Substring(13, 16));
controlTable.CurrentRow.SetValue("DOCREL", control.Substring(29, 4));
controlTable.CurrentRow.SetValue("STATUS", control.Substring(33, 2));
controlTable.CurrentRow.SetValue("DIRECT", control.Substring(35, 1));
controlTable.CurrentRow.SetValue("OUTMOD", control.Substring(36, 1));
controlTable.CurrentRow.SetValue("EXPRSS", control.Substring(37, 1));
controlTable.CurrentRow.SetValue("TEST", control.Substring(38, 1));
controlTable.CurrentRow.SetValue("IDOCTYP", control.Substring(39, 30));
controlTable.CurrentRow.SetValue("CIMTYP", control.Substring(69, 30));
controlTable.CurrentRow.SetValue("MESTYP", control.Substring(99, 30));
controlTable.CurrentRow.SetValue("MESCOD", control.Substring(129, 3));
controlTable.CurrentRow.SetValue("MESFCT", control.Substring(132, 3));
controlTable.CurrentRow.SetValue("STD", control.Substring(135, 1));
controlTable.CurrentRow.SetValue("STDVRS", control.Substring(136, 6));
controlTable.CurrentRow.SetValue("STDMES", control.Substring(142, 6));
controlTable.CurrentRow.SetValue("SNDPOR", control.Substring(148, 10));
controlTable.CurrentRow.SetValue("SNDPRT", control.Substring(158, 2));
controlTable.CurrentRow.SetValue("SNDPFC", control.Substring(160, 2));
controlTable.CurrentRow.SetValue("SNDPRN", control.Substring(162, 10));
controlTable.CurrentRow.SetValue("SNDSAD", control.Substring(172, 21));
controlTable.CurrentRow.SetValue("SNDLAD", control.Substring(193, 70));
controlTable.CurrentRow.SetValue("RCVPOR", control.Substring(263, 10));
controlTable.CurrentRow.SetValue("RCVPRT", control.Substring(273, 2));
controlTable.CurrentRow.SetValue("RCVPFC", control.Substring(275, 2));
controlTable.CurrentRow.SetValue("RCVPRN", control.Substring(277, 10));
controlTable.CurrentRow.SetValue("RCVSAD", control.Substring(287, 21));
controlTable.CurrentRow.SetValue("RCVLAD", control.Substring(308, 70));
controlTable.CurrentRow.SetValue("REFMES", control.Substring(420, 14));

var dataLine = streamReader.ReadLine();
while (dataLine != null) {

    dataTable.Append();
    dataTable.CurrentRow.SetValue("SEGNAM", dataLine.SubString(0, 30));
    dataTable.CurrentRow.SetValue("MANDT", dataLine.SubString(30, 3));
    dataTable.CurrentRow.SetValue("DOCNUM", dataLine.SubString(33, 16));
    dataTable.CurrentRow.SetValue("SEGNUM", dataLine.SubString(49, 6));
    dataTable.CurrentRow.SetValue("PSGNUM", dataLine.SubString(55, 6));
    dataTable.CurrentRow.SetValue("HLEVEL", dataLine.SubString(61, 2));
    dataTable.CurrentRow.SetValue("SDATA", dataLine.SubString(63, dataLine.Length - 63));

    dataLine = streamReader.ReadLine();
}

this snippet expects a single idoc in the file. If you have multiple idocs in one file, you need to split them by looking for the control record (the control record line usually starts with "EDI_DC40").

0
On

Based on Dirk's answer I just created 2 Methods to fill the control & data tables dynamically by using the Metadata available :

    private static void AddControlToIdocTable(ref IRfcTable control, string controlLine)
    {
        var lineType = control.Metadata.LineType;

        //Append a new Control Row
        control.Append();

        //Creates an empty array with the Count of the different fields the RfcTable consists of
        string[] columns = new string[control.Metadata.LineType.FieldCount];

        for (int i = 0; i < columns.Length; i++)
        {
            //Get the Type containg the structure of the field
            var type = lineType[i];

            //If NucOffset + NucLength is not bigger then the length of the current control line
            //we append the substring of the control line using those values (Offset + Length)
            if(controlLine.Length >= (type.NucOffset + type.NucLength))
                control.CurrentRow.SetValue(type.Name, controlLine.Substring(type.NucOffset, type.NucLength));
        }
    }

    private static void AddDataToIdocTable(ref IRfcTable records, List<string> dataLines)
    {
        var lineType = records.Metadata.LineType;

        //Creates an empty array with the Count of the different fields the RfcTable consists of
        string[] columns = new string[records.Metadata.LineType.FieldCount];

        foreach (string dataLine in dataLines)
        {
            //Append a new Data Row for every data line
            records.Append();
            for (int i = 0; i < columns.Length; i++)
            {
                //Get the Type containg the structure of the field
                var type = lineType[i];

                //If NucOffset + NucLength is not bigger then the length of the current control line
                //we append the substring of the control line using those values (Offset + Length)
                if (dataLine.Length >= (type.NucOffset + type.NucLength))
                    records.CurrentRow.SetValue(type.Name, dataLine.Substring(type.NucOffset, type.NucLength));
            }
        }
    }

Will post some further details after testing. Thanks!

0
On

I worked with Fabio's code for a few minutes, and read the SAP documentation, and came up with this method of populating the tables. (The control and data tables are of the same class)

    private void AppendRecordToTable(IRfcTable idocTable, string textRecord)
    {
        var structure = idocTable.Metadata.LineType.CreateStructure();
        foreach (var field in structure)
        {
            var fieldMeta = field.Metadata;
            var fieldValue = CreateFieldValue(fieldMeta, textRecord);
            structure.SetValue(fieldMeta.Name, fieldValue);
        }
        idocTable.Append(structure);
    }

    private string CreateFieldValue(RfcFieldMetadata fieldMeta, string record)
    {
        if (record.Length < fieldMeta.NucOffset)
            return new string(' ', fieldMeta.NucLength);
        if (record.Length < fieldMeta.NucOffset + fieldMeta.NucLength)
            return record.Substring(fieldMeta.NucOffset).PadRight(fieldMeta.NucLength);
        return record.Substring(fieldMeta.NucOffset, fieldMeta.NucLength);
    }