cancel
Showing results for 
Search instead for 
Did you mean: 

Calling a function module using C#

Former Member
0 Kudos

My task is to write minimal interface code to present report data in an iview. I am using the Portal Development Kit (PDK) and have successfully reverted back to VS2005 (from 2008) and deployed a "hello world" test page. So far so good.

I now have to do something useful and display data from SQL Server using a user id as a parameter. Someone has created a function module and described it thus:

The required function module is now available in DEV:

Function module: ZGET_LOGIN_USER

Function group: ZG201

Here are the details of the function module ZGET_LOGIN_USER:

It takes two optional parameters:

- BEGINDATE (default: today)

- ENDDATE (default: 31.12.9999)

It returns:

- USERNAME u2013 Login ID

- PERNR u2013 Personnel No

- FAMILYID u2013 Family ID

How do I call this from the .Net code, in C# or VB.Net? I can not find anything directly relevant to this anywhere (lots of dead links) yet it must be a staple for anyone using the PDK. Do I need the .Net Connector as well, for example? Any approach to it suggests that I have to use Visual Studio 2003 (!!!!) to make it work!? - surely not, in 2009???? Is there no modern alternative to the .Net Connector which seems to need .Net FX 1.1? Can I use VS2008 and use its ability to target earlier .Net FX versions?

Can someone please point me in the right direction and to the current way of doing such simple things - I can't believe that I have to install Visual Studio 2003, 2005 and 2008 to make this thing work!

Thanks in anticipation,

James.

Accepted Solutions (1)

Accepted Solutions (1)

Former Member
0 Kudos

James,

Just to get the record straight: youu2019re developing an IView portlet within .NET / C#, to have it displayed in SAP Enterprise Portal, and applying the SAP PDK for this. Right ?

Ok, to access from .NET code SAP BAPIu2019s you have several options:

1) Use the SAP .NET Connector (NCo)

As you correctly state, this technology is outdated; and dependent upon .NET 1.1 and VS2003. There is a workaround for using it in .NET 2.0-3.5 and VS2005/2008; but still. Juergen Daiberl advices in another post in this forum ([how do we connect .net|https://www.sdn.sap.com/irj/scn/logon?mode=check&redirect=https%3a//forums.sdn.sap.com/thread.jspa%3fthreadid%3d1298735%26tstart%3d30]) to not use this technology anymore when youu2019re starting something new, and instead go to standards-based webservice way. This can be done either by:

2) Use the BizTalk WCF LOB Adapter for SAP. Despite itu2019s name, this is not dependent on BizTalk, and can be used on itu2019s own. For more information, see [Connecting Line-of-Business (LOB) Systems like SAP and Microsoft Office SharePoint Server |http://blogs.msdn.com/saptech/archive/2009/03/23/connecting-line-of-business-lob-systems-like-sap-and-microsoft-office-sharepoint-server.aspx]and on MSDN Code Gallery the [OBA Sample Application Kit for SAP and Siebel|http://code.msdn.microsoft.com/sapsiebel].

3) Generate in SAP a webservice for the function module ZGET_LOGIN_USER, and access it yourself in custom .NET code via WCF

In a recent Proof-of-Concept project I applied myself the last option. The same WCF service is next integrated and unlocked within various types of front-ends: a (SharePoint / ASP.net) WebPart, a old-fashioned WinForms, and also a cool Silverlight control, running totally within the runtime scope of the browser at the end-user's machine...

Regards, William.

Edited by: WvStrien on Jul 2, 2009 12:21 AM

Former Member
0 Kudos

William:

Your initial assumption was spot on, as was you reply - thanks! It confirms my expectations and thanks for the unexpected LOB/OBA links which are interesting. I think we will go the Web Service route but I have to depend on others to create that.

All useful info is sufficient for this to be called a Solution!

Thanks

James.

Answers (1)

Answers (1)

Former Member
0 Kudos

This might be a bit late.

It might help others if someone face the same situation.

Here is the code I wrote to call function RFC_READ_REPORT

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Runtime.CompilerServices;

using Microsoft.VisualBasic.CompilerServices;

using System.IO;

using System.Runtime.InteropServices;

namespace WpfApplication4

{

public class TMsSap: IDisposable

{

private string fServer;

private string fSystem;

private string fSystemNumber;

private string fUser;

private string fPassword;

private string fClient;

private dynamic fLogonControl;

private dynamic fFunctions;

public static dynamic CreateObject(string ProgId)

{

if (ProgId.Length == 0)

{

throw new Exception("ProgId.Length == 0");

}

return Activator.CreateInstance(Type.GetTypeFromProgID(ProgId));

}

private static object LateGetValue(object obj, string propertyName)

{

return RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(obj, null, propertyName, new object[0], null, null, null));

}

private static void LateSetValue(object obj, string propertyName, object value)

{

NewLateBinding.LateSet(obj, null, propertyName, new[] { value }, null, null);

}

private static void LateCallMethod(object obj, string methodName)

{

NewLateBinding.LateCall(obj, null, methodName, new object[0], null, null, null, true);

}

/// <summary>

/// Release a COM object so that it can be cleaned up.

/// </summary>

/// <param name="comObj"></param>

protected void ReleaseCom(dynamic comObj)

{

Marshal.ReleaseComObject(comObj);

}

/// <summary>

/// Clean up all released COM objects.

/// </summary>

protected void CleanAllReleased()

{

GC.Collect();

GC.WaitForPendingFinalizers();

}

public TMsSap()

{

fLogonControl = CreateObject("SAP.LogonControl.1");

fFunctions = CreateObject("SAP.Functions");

}

~TMsSap()

{

Dispose(false);

}

public void Dispose()

{

Dispose(true);

// tell the GC not to finalize

GC.SuppressFinalize(this);

}

protected virtual void Dispose(bool disposing)

{

if (fLogonControl != null) // only dispose once!

{

if (disposing)

{

Console.WriteLine("Not in destructor, OK to reference other objects");

}

// perform cleanup for this object

Console.WriteLine("Disposing...");

ReleaseCom(fLogonControl);

fLogonControl = null;

ReleaseCom(fFunctions);

fFunctions = null;

}

}

public dynamic getFunction(string aName)

{

object[] varArrayArgument = new object[] { aName };

return RuntimeHelpers.GetObjectValue(NewLateBinding.LateGet(fFunctions, null, "add", varArrayArgument, null, null, null));

}

public Boolean getNewConnection()

{

dynamic varConnection = LateGetValue(fLogonControl, "newConnection");

LateSetValue(fFunctions, "Connection", varConnection);

varConnection.ApplicationServer = fServer;

varConnection.User = fUser;

varConnection.Password = fPassword;

varConnection.System = fSystem;

varConnection.Client = fClient;

varConnection.SystemNumber = fSystemNumber;

varConnection.Language = "";

return varConnection.LogOn(0, true);

}

public string getProperFileName(string aFileName)

{

return aFileName.Replace('/', '_').Replace(':', '_').Replace('>', '_').Replace('<', '_').Replace('%', '_').Replace('?', '_').Replace('$', '_');

}

public string Server

{

get

{

return fServer;

}

set

{

fServer = value;

}

}

public string System

{

get

{

return fSystem;

}

set

{

fSystem = value;

}

}

public string SystemNumber

{

get

{

return fSystemNumber;

}

set

{

fSystemNumber = value;

}

}

public string User

{

get

{

return fUser;

}

set

{

fUser = value;

}

}

public string Password

{

get

{

return fPassword;

}

set

{

fPassword = value;

}

}

public string Client

{

get

{

return fClient;

}

set

{

fClient = value;

}

}

}

}

Former Member
0 Kudos

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using System.Runtime.CompilerServices;

using Microsoft.VisualBasic.CompilerServices;

using System.IO;

namespace WpfApplication4

{

/// <summary>

/// Interaction logic for MainWindow.xaml

/// </summary>

///

public partial class MainWindow : Window

{

private Boolean fCancel;

private string fReportFileStoredDirectory;

public MainWindow()

{

InitializeComponent();

}

private void buttonStop_Click(object sender, RoutedEventArgs e)

{

fCancel = true;

}

private void processReport(TMsSap aSap, string aReportName, dynamic aFunctionReadTable)

{

string sFilePath = fReportFileStoredDirectory + aSap.getProperFileName(aReportName) + ".txt";

if (File.Exists(sFilePath))

{

return;

}

bool bCall;

aFunctionReadTable.exports("PROGRAM").value = aReportName;

try

{

bCall = aFunctionReadTable.call();

}

catch (Exception exception1)

{

listBox.Items.Add(aReportName + " " + exception1.Message);

aSap.getNewConnection();

return;

}

if (!bCall)

{

listBox.Items.Add(aReportName + " " + aFunctionReadTable.exception);

aSap.getNewConnection();

}

listBox.Items.Add(aReportName);

dynamic varTableSourceCode = aFunctionReadTable.tables.item("QTAB");

StreamWriter varStreamWriter = File.CreateText(sFilePath);

int iRowCount = varTableSourceCode.rowcount;

varStreamWriter.WriteLine("* " + aReportName);

for (int iIndex = 1; iIndex <= iRowCount; iIndex++)

{

varStreamWriter.WriteLine(varTableSourceCode.value(iIndex, 1));

}

varStreamWriter.Close();

}

private void buttonRun_Click(object sender, RoutedEventArgs e)

{

fReportFileStoredDirectory = textBoxReportFileStoredDirectory.Text;

fCancel = false;

buttonRun.IsEnabled = true;

buttonStop.IsEnabled = true;

try

{

using (TMsSap varSap = new TMsSap())

{

varSap.Server = textBoxServer.Text;

varSap.System = textBoxSystem.Text;

varSap.Client = textBoxClient.Text;

varSap.SystemNumber = textBoxSystemNumber.Text;

varSap.User = textBoxUser.Text;

varSap.Password = passwordBox.Password;

if (!varSap.getNewConnection())

{

MessageBox.Show("Can not get sap connection.");

}

else

{

dynamic varFunctionReadTable = varSap.getFunction("RFC_READ_REPORT");

StreamReader varStreamReader = File.OpenText(textBoxDatabaseTableFileNameListPath.Text);

while (varStreamReader.Peek() != -1)

{

string sReportName = varStreamReader.ReadLine();

processReport(varSap, sReportName, varFunctionReadTable);

}

varStreamReader.Close();

}

}

}

finally

{

buttonRun.IsEnabled = true;

buttonStop.IsEnabled = false;

MessageBox.Show("Done");

}

}

}

}

Former Member
0 Kudos

Thanks for the help,

I tried the code in a windows application and everything is right, but when use it in a windows service occurs this error "Bad variant type" on varSap.getFunction ("RFC_Function"); Any ideas?