Skip to Content

A Spotlight on the New .NET Connector 3.0

SAP .NET Connector 3.0 is now released and you surely want to know more about it.. In this weblog I want to

  • Give you a very short overview on what is new with the SAP .NET Connector 3.0
  • Show a very simple demo application on how to use the .NET Connector as a stateless client
  • Present a simple example of a stateless NCo server scenario.

By learning some relevant details of the two demo applications you will get some understanding of the new programming model of the .NET Connector 3.0. In addition, I mention some other use cases such as stateful or transactional scenarios without going into any details.

The Benefits of .NET Connector 3.0

For mass transactions or heavy load scenarios the NCo is an important alternative to Web Services or SAP Process Integration. Maybe you are still using NCo 2.0 and do not really know if and why you should upgrade to the next NCo release. So what is the benefit of upgrading to NCo 3.0 and why should you invest in this procedure. After reading this weblog you should be convinced that the payoff for upgrading to NCo 3.0 is worth it. In particular you will learn that NCo 3.0:

  • Is more stable, robust and more secure
  • Enforces a better design of your application by decoupling the connection handling from the .NET application proper
  • Encourages separation of concerns: infrastructure embedding is clearly separated from business application logic
  • Reduces memory consumption
  • Allows dynamic programming without the need for proxy generation
  • Can dynamically look up metadata (so if something changes in the related ABAP system – e.g. if parameters in a function module signatures are added or the ABAP system is switched from Non-Unicode to Unicode, you no longer need to regenerate the proxies and recompile your solution)
  • Is no longer bound to a special Visual Studio version.

NCo 3.0 brings a complete redesign of the NCo API and a new architecture that also requires some redesign of the applications using the NCo. But as you will learn in this weblog, it is worth redesigning your applications so that they can use the new .NET Connector 3.0. The redesign of the NCo is the result of a long experience with NCo 2.0 as well as with SAP Java Connector 2.1 and 3.0. SAP has capitalized on the benefits of the NCo 2.0 and improved its strengths and as a result we have a far more powerful NCo.

This weblog is a spotlight that should give you an impression of what using the new .NET Connector 3.0 is like and a first idea of how to work with this new release of the NCO. If you are interested in some more details look at this overview document on which my weblog is based.

If you want to download the .NET Connector 3.0 and you have a user in the SAP Service Marketplace you can download the new NCo and its documentation here: https://service.sap.com/connectors -> SAP Connector for Microsoft .NET.

The Client Programming Model – Providing the Configuration

SAP has spent quite some effort on making the new NCo more secure and has placed a special emphasis on security concerns. In particular it is now much more difficult for an intruder

  • To read the logon data,
  • To replace the logon data in order to get a backend session on the ABAP server with more authorizations and
  • To get access to an open connection that was opened for another application.

In order to store configuration data in a secure way you can now keep it on a central LDAP server and read it on the fly from an LDAP by using the following approach:

When the .NET Connector needs logon data to open an RFC connection to an Application Server ABAP, it looks into your code for the relevant information. In order to provide it you need to implement the interface IDestinationConfiguration and register an instance of that class with the .NET Connector when you start your application. These are the necessary steps:

  1. Implement the method IDestinationConfiguration.GetParameters( string destinationName). Inside this method you can retrieve the relevant configuration data in any way you like, for example read the necessary logon parameters from a database or LDAP directory or prompt the user to input them in a dialog window. If you don’t know logon parameters for a system called destinationName, then just return null.
  2. Create an instance of the above implementation and register it with the NCo using the method RfcDestinationManager.RegisterDestinationConfiguration().
  3. You can now make client calls to the relevant destinations and NCo will automatically get access to the logon information for each backend system by calling the GetParameters() method mentioned above.

Using this approach you obviously can write simple configurations for demo scenarios that have the configuration in clear text in the code as well as real world configurations that draw the relevant configuration data from an LDAP server, an encrypted file or some other source of your choice.

Once the .NET Connector has initialized a connection pool for a particular RFC destination, there is no further need to provide the configuration data for any connections belonging to this destination. Still if necessary it is possible to change the configuration data and to inform you application about this by using the event

public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged in the interface IDestinationConfiguration.

The Client Programming Model – Creating the Client Code

One main difference to .NET Connector 2.0 is that there is no need to pay any attention on how to handle the connections. The internal technical details of opening, closing, and managing connections are no longer handled by the application developer. Instead, the complete connection management is done by the .NET Connector. You no longer have to worry about this. Another important difference lies in the way the parameters that are exchanged with the ABAP application are handled.

Take a look at the simple application below to get a first impression of what working with the .NET Connector 3.0 is like. This way you will easily grasp many of the advantages of the new NCo 3.0.

As I mentioned, for creating a demo application it is, of course, still possible to store the configuration data including the password in clear text in a configuration file. In our little demo here, we take the password from a simple implementation of the provider method GetParameters of a class that implements the interface IDestinationConfiguration. But you should not do this in a real world application. It is just a handy way to provide the logon information in demo scenarios.

In order to give you an example that runs on your system, I show you a complete small application. So this is what the class providing our configuration data plus some declarations looks like:

As mentioned above, you need a class that implements the relevant interface IDestinationConfiguration and an implementation of the method GetParameters that puts the relevant values in the returning parameter of the method.

Creating the client coding is very simple and straight forward:

Though the example is very simple just some comments on the relevant steps (confer the outcommented digits at the end of the lines):

  1. Register the relevant destination object.
  2. Get the destination corresponding to the ABAP system you want to call.
  3. Next you need a repository for the metadata from the ABAP Dictionary of the corresponding destination system.
  4. Create a function object (that will hold the values of the relevant parameters)
  5. Provide the values for the relevant importing parameters of the function.
  6. Execute the function.
  7. Read the exporting or returning parameters and process them.

If you are familiar with .NET Connector 2.0 two main differences will strike you:

  • You do not open or close any connection yourself. There is no need to do it. And, in general you cannot grab a connection itself. You create a destination and the .NET Connector provides a connection when you need one, keeps it in a pool, closes it after the given idle timeout and takes care of all of the work related to this.
  • There are no proxy classes, but just function classes that serve as containers for the relevant parameters.

If you take care of closing all the brackets in the example, you can copy it to your development environment, reference the relevant .NET Connector libraries and input the configuration data for a real Application Server ABAP that has the BAPI BAPI_COMPANY_GETDETAIL. If the user that you provide in your configuration has the authorization to call this BAPI the program will run on your system and output a result in the console

You wonder why I have not told you which development environment is needed for the .NET Connector 3.0. There is no need to. This release does not support and as a consequence not depend on any particular development environment. To those of you who have worked with the .NET Connector 2.0 this is also new, because this is a major difference.

How to Keep the State

The example I have shown you works with a stateless synchronous RFC which means that the invoke method not only gets a connection from the relevant pool and executes it, but also resets the session on the ABAP system and returns the connection back to the pool.

A stateless call will not do if you need to call two BAPIs and the second BAPI has to run in the same context on the ABAP Application Server as the first one. So you need a way to tell the .NET Connector that you now need a connection that is kept open until you want the .NET Connector to close or return it to the connection pool, in other words you need to inform the .NET Connector that you need a stateful connection.

Still, also in the case of a stateful connection, the technical handling of the connection is left to the .NET Connector. Again there is no need for you to grab a connection yourself. The .NET Connector does all the connection handling and your code looks like this:

RfcSessionManager.BeginContext(destination);

firstBAPI.Invoke(destination);

secondBAPI.Invoke(destination);

RfcSessionManager.EndContext(destination);

With BeginContext() you get an RFC connection for your destination from the connection pool and attach it to the currently executing thread for exclusive usage. In other words with this statement you reserve an RFC connection for your thread.

The two Invoke() calls for the first and second BAPI check, whether there is a connection bound to the current thread, and if they find one, they use it for their call. Also the context of the relevant ABAP session is kept until the EndContext() detaches the exclusive RFC connection from the current thread, performs a backend context reset on that connection and returns the connection to the pool.

If you work in the context of a .NET Server with a session management of its own you just need to create your own ISessionProvider object and register it with the RfcSessionManager. But this is something I will not show or explain in any detail here.

The .NET Connector as a Server

If you use the NCo 3.0 as a server the philosophy behind the programming model is the same as in the client use case: The NCo handles many things for you so that you need not worry about many problems, because the SAP connectivity team has solved these problems for you.

In particular this means: First of all, as in the client case, the management of the connections is done completely by the NCo, and again you can store your configuration data outside the application proper wherever you like in any form you like. Secondly, you need no longer trouble yourself with another quite complex task that you had to take care of with the former release of the NCo: By default, the thread management is done by the NCo 3.0.

Again I will show all relevant steps by guiding you through a simple example that presents a basic stateless NCo server. It consists of three new classes:

  • A class that provides the server configuration
  • A handler class that contains the code that should be executed if the relevant function module is called from the ABAP system.
  • The server class.

In addition the client configuration class from the client configuration is also needed.

Providing the Server Configuration

So let us start with the class providing the server configuration:

As in the client example we first need a class to provide the necessary server configuration, technically this is a class that implements the interface IServerConfiguration and as a consequence has a GetParameters method. In this case we define a configuration with the name PRD_REG_SERVER.

For the server in NCo 3.0 with dynamic metadata lookup, you need two connections: one client connection for the DDIC lookup and a server connection to enable the ABAP system to call the .NET Connector server. And as a consequence you need two sets of configuration data:

As for the client connection we reuse the configuration data from the previous client example PRD_000. This means that you have to include the class MyBackendConfig (but without its main method, because we do not need this method here) if you want to run this server example.

As for the server connection you have to connect to the ABAP system by using an intermediate SAP Gateway. This is shown in the figure below:

image

To those familiar with how to configure an NCo 2.0 server it will be no news how you connect via the intermediate SAP Gateway. Still, I want to spend some words on it for those who don’t know how to do this. You need these three values:

  • Hostname (the host on which the SAP Gateway runs),
  • Gateway service (you can compare this to a port. It has to be sapgwxx where the last double x stands for the system number) and
  • Program ID

in order to identify the server destination uniquely. You must provide the same values for these parameters both when defining the .NET server configuration as shown above in the code example and when defining the RFC destination as a TCP/IP connection in the transaction SM59 as shown below in the next figure:

image

So much for our explanation of how to get the configuration data of our .NET server program. Next we need a class that provides the handler method for a call from an ABAP system that calls a function module STFC_CONNECTION on our .NCo server.

Creating a Handler Method in the Server

In general to provide one or more handler methods, we have to implement one or more methods that will process incoming RFC calls. In our example we choose one static method for each function module. We assign an annotation to the method as shown below:

[RfcServerFunction(Name = “STFC_CONNECTION”, Default = false)]

public static void Function(RfcServerContext context, IRfcFunction function)

The two parameters context and function are provided by the .NET Connector runtime when the method is called.

You could also have one static method as a default for all function modules that don’t have an explicit method assigned to them. Just set the attribute Default in the annotation to true. It is also possible to work with instance methods in the same manner. You should use this if you create a stateful server, but I will not show this in any detail here in this introductory weblog.

So this is what the handler method for the function module STFC_CONNECTION looks like in our example:

We output the parameter REQUTEXT on the console, return the value of this parameter in the parameter ECHOTEXT and put some variation of “Hello World” in the parameter RESPTEXT. Both parameters: ECHOTEXT and RESPTEXT are returned to the ABAP client.

Create and Run the Server

With the configurations defined and a handler class with the relevant handler method prepared we have now all we need at hand to write the server class:

This is what happens in this method (see the commented-out digits at the ends of the lines):

  1. Register the destination for the DDIC lookups.
  2. Register the server configuration.
  3. Register the handler(s) and create a server instance by passing the server name and an array with the handler(s) to the constructor method.
  4. Start the server.

That’s all. This simple code suffices to set up a server that can not only handle calls of the function module STFC_CONNECTION, but handle up to 5 parallel calls because we have set the RegistrationCount to 5 in the MyServerConfig class.

Just remember: To make the program run, copy the code of all four classes MyBackendConfig (without its main method), MyServerConfig, MyServerHandler, MyServerDemo plus the information on used name spaces to your .NET development environment. You must also adapt the configuration data accordingly so that you can connect to a real SAP Gateway and a real ABAP Application Server.

And Much More

Of course there is much more that you can do with the new .NET Connector 3.0 and much of it is described in the overview document I have already linked above. Just to mention a few more scenarios that are possible with NCo 3.0:

  • When creating a NCo client you can use transactional RFC tRFC/qRFC/bgRFC to make sure that the remote call is executed exactly once.
  • In an analogous manner you can also use tRFC/qRFC/bgRFC in the server use case.
  • You can write a stateful NCo server program interacting with .NET programs that have their own user session handling and with .NET programs that do not have this.

Apart from any details, all these use cases have one feature in common: You need not directly interact with connections, that is, open and release them. Instead all connection handling is done transparently from you by the .NET Connector 3.0. All you have to do is to provide the relevant configuration data. Of course the tRFC/qRFC/bgRFC examples are more complex as they require you to provide the storage of the TID and the payload data and some more code. But this is another story and as many other details beyond the scope of this introductory weblog.

Summary

You have now seen how easily you can write a stateless client and stateless server scenario using the .NET Connector 3.0. You certainly have realized that the code is far more transparent because of the separation of concerns realized in the new .NET Connector architecture:

  • The configuration is left to an administrator and can easily be stored outside the application proper. This makes the application code more straightforward and easier to maintain. Moreover you can adapt or change the destination without touching the application code.
  • As an application developer you do not need to fiddle with the connections, but leave the complete connection management to the .NET Connector.
  • This is true even for stateful scenarios. You just have to tell the NCo for which lines of code you need a stateful connection. And this is all. Again you work only with destinations and leave the handling of the connections proper to the .NET Connector.

As mentioned, other scenarios such as transactional calls are also possible in the server and the client case. They are sketched elsewhere. I hope this weblog has shown you some of the many advantages of the NCo 3.0 and inspires you to try out the new .NET Connector 3.0. I am sure that sooner or later, you will adapt your existing applications for NCo 2.0 to NCo 3.0 and thereby make them more transparent and secure and profit from the better design that comes with the separation of concerns.

 

 

145 Comments
You must be Logged on to comment or reply to a post.
    • I sucessfully replicated the c# example here.

      I totally failed to recreate the same example in .net VB.

      I in need to connect to R/3 from Excel VBA and there is no example anywhere. Is it even possible?

      Thank you

      Juraj

    • Hello Huseyin,

      yesterday we have uploaded a new version of JCo 3.0 that works with .NET Framework 4.0.

      I propose you should use this version.

      Regards

      Thomas

      • Hi Thomas,

        When I checked checked version of Nco, there are two different versions; one for framework 2.0 and second is framework 4. I want to ask that will you produce a new version for each framework?

        Thanks.

        Huseyin Akturk

        • Hello Huseyin,

          there is one version for .NET framework 2.0 to 3.5 and another version for .NET framework 4.0, because .NET framework 4.0 contains incompatible changes.

          Regards

          Thomas

    • Hello Rodrigo,
      we have tested the download and it worked. It might be that you tried to download the file just at the time when we  substituted the files yesterday. Let us know if the problem persists.

      Thomas

    • Hello Rodrigo,
      we have tested the download and it worked. It might be that you tried to download the file just at the time when we  substituted the files yesterday. Let us know if the problem persists.

      Thomas

  • According to the 2010 SAP Guidelines for Best-Built Applications That Integrate with SAP Business Suite …

    “.NET Tools SOA-NET-1.

    SAP recommends that .NET developers use the SAP Enterprise Services Explorer tool for Microsoft .NET. SAP does not recommend using .NET connector.”

    Maybe they need to update this guideline too.

  • Hi Thomas,

    in order to process IDoc’s on a Server component,Iam I correct to assume we need to call the IDOC_INBOUIND_ASYNCHRONOUS rfc.

    Many Thanks

    • Hello Alan,

      it is possible to use the function module IDOC_INBOUND_ASYNCHRONOUS, but it might be easier to process IDOCs if you use the SAP Business Connector. Use this link to find information on the SAP Business Connector: https://service.sap.com/connectors menu entry SAP Business Connector.

      Regards

      Thomas

      • Hi Thomas,

        currently we are using the SAPIDocReciver and IDocSender class’s from the SAP .Net Connector V.2. This has been incorporated into a Custom BizTalk Adapter. Ideally we would be looking to replace the SAP .Net Connetor Ver 2 layer with Ver 3 of the SAP .Net Connector. Use of the SAP Business Connector would require a much greater change.

        If we use the new version of the SAP .Net Connector, will we need to check the DDIC to ascertain what paramters are required for calling IDOC_INBOUND_ASYNCHRONOUS rfc.

        I am a .Net/BizTalk programmer but do have full SAP support on site

        Many Thanks

        Alan

      • Hi Thomas,

        just to let you know, I have a prototype program processing inbound/outbound Idocs to/from SAP using Nco 3.

        Very impressed with new connector, highly adaptable and dynamic.

  • Hi Tomas,

    Congratulations, great job!!!!

    I have two questions.

    1) There are support on 64 bits plataform?

    2) Does The new version support the code/implementation of .NET Connector 2.0?

  • Dear Thomas,

    We are using SAP.NET Connector 3.0 within a web service to execute different BAPI’s from a Visual Studio environment. So far we have succesfully registered a Customer Quotation in SAP from our web service. However, when consuming the web service for a second time (creating a new quotation) we have encountered the following error: “Destination configuration already initialized”. We have made the following steps:

    1. Implementation of the IDestinationConfiguration.
    2. The web method for creating the quotation registers the destination configuration.
    3. We use the repository in order to invoke and commit the required BAPI.

    Are we missing something? Are we on the wrong track when using SAP.NET Connector 3.0 with web services? We appreciate any help you can give us on this subject.

  • Hi Thomas,
    in NCo 2.0 I was able to detect a broken communication with overriding SAPServerHost->OnServerException. How I can do this in NCo 3.0? RFCServer events(RfcServerApplicationError/RfcServerError) will not fire in that case.

    Kind Regards
    Kai

  • Hello:
    When SAP Nco gets data into its data structures, an execution time is consumed. When I need to show this data into a .NET DataGrid, It is necessary to transfer data from the SAP structures toward the .Net dataGrid and, another execution time is consumed. Is there a way to avoid this overload situation?
    Thanks!!
      • I created a library related to connections with SAP Nco 3,I show a part of this:        <DataGrid AutoGenerateColumns=”False” Height=”342″ HorizontalAlignment=”Left” Margin=”0,32,0,0″ Name=”dataGrid1″ VerticalAlignment=”Top” Width=”625″ ItemsSource=””  >Hope it helps.

      • Tha SAPFields class is:
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;

        namespace LibEGA.LibSAP
        {
            public class SAPFields
            {
                public SAPFields()
                {
                }

                public string FieldName {get; set;}
                public int Offset {get; set;}
                public int Length {get; set;}
                public char Type {get; set;}
                public string FieldText {get; set;}
            }
        }

  • Hello,

    I want to use the NCo3 in an asp.net application wich works quite fine, even with a sso logon via kereros and gsskrb5.dll.

    But the NCo uses always the session and credentials of the first user who logs in. A second user gets the first connection and can fetch data from sap, although this user does not exist in sap.

    How to create different sessions for different web users?
    I think I have to implement ISessionProvider but in the NCo3 overview document it is not described how to do it and also not in the help file.

    Any ideas?

    With kind regards

    Daniel Kasimirowicz

    • Hello Daniel,

      Yes, you need to implement an ISessionProvider. It should ensure to return the appropriate session ID that is associated with the current request. Regarding the backend session: There you need to make sure to use a custom destination that is overriding the credentials per user. Otherwise only the configured user will be used.

      Regards,
      Markus

      Regards,
      Markus

  • Hi Thomas;
    Firstly Thanks for sharing.
    I’m using C# VS.net 2010 on the Framework 4.0, WinXP and 32Bits.
    I downloaded new NCO 3.
    I’m writing WinApplication program at .Net with NCO 3.
    But My programs don’t work.
    I’m taking following link error messages.
    Are .net 2010  and framework 4 compatible?
    If uncompatible can you suggest me diffrent way?
    Thanks for interest.

    My problems details:
    Framework 4.0 Problem at .net Connector 3.0

    • Hello,

      it appears you are using the .Net 2.0 version of NCO3. Please download the 4.0 DLLs and use those. That should fix your issue.

      Regards,
      Matthias Fuchs, NCO3 Development

  • When you try to look use one of API’s to look at a function meta-data the “Documentation” for parameter is not always correct. If a parameter does not a description in SAP it comes back incorrectly – has description of previous parameter. For example look at results of

    “repository.GetFunctionMetadata(“RFC_CREATE_FUNC_LOC_MASTER”)

    Sorry not correct forum to report bugs but I do not have access to report bugs.

    • Hello,

      this function module does not seem to be standard. I tried to reproduce the issue with RFC_CHECK_DESTINATION which has one import parameter (MYDEST, the first one) that has a short text and one without a short text (MYTYPE, the second one). I get the expected result for the second parameter’s documentation, namely null. Is there an SAP-delivered function module that can be used to reproduce the issue?

      It is of course also possible that the issue was resolved since we released the current version.

      Best Regards,
      Matthias Fuchs, NCO3 Development

    • Hi,

      NCO3 does not directly support this feature, but it can certainly be achieved as you pointed out by reading saplogon.ini and then creating a RfcDestination or a RfcCustomDestination based on RfcConfigParameters produced from saplogon.ini.

      Regards,
      Matthias Fuchs, Development

    • Ok, there is no support but is there any guide to understand which parameter in the RfcParameters is equivalent to the saplogon.ini and in which case (group logon)?
  • Hello Thomas,

    I’m implementing NCo 3.0 in a windows application which makes RFC calls in different threads, just for downloading master data from SAP and for creating documents in SAP. With the downloading of master data I have no problems, but with those RFC functions which needs to call the BAPI_TRANSACTION_COMMIT function, so they need the use of the BeginContext method, I receive, after more or less 10 minutes, an exception error out of my code, so I cannot manage it. The exception message is ‘Collection was modified; enumeration operation may not execute’, in the object SAP.Middleware.Connector.RfcSessionManager.UpdateSessions. The thing is that, if I don’t use the BeginContext method, it works fine, at least I have no error, but I suppose this does not guarantee the transaction commit.

    I’m using the BAPI invoke and the Commit invoke in the same thread, for example:

    public XmlDocument CreateBillingDocuments(string DestinationName, BILLINGDATAINS Documents)
    {

    SAPRfcDestination = RfcDestinationManager.GetDestination(DestinationName);
    RfcRepository SAPRfcRepository = SAPRfcDestination.Repository;
    IRfcFunction RFCCreateBillingDocuments = SAPRfcRepository.CreateFunction(“BAPI_BILLINGDOC_CREATEMULTIPLE”);

    RfcSessionManager.BeginContext(SAPRfcDestination);
    RFCCreateBillingDocuments.Invoke(SAPRfcDestination);
    IRfcFunction RFCTransactionCommit = SAPRfcRepository.CreateFunction(“BAPI_TRANSACTION_COMMIT”);
    RFCTransactionCommit.SetValue(“WAIT”, “X”);
    RFCTransactionCommit.Invoke(SAPRfcDestination);
    RfcSessionManager.EndContext(SAPRfcDestination);

    }

    So I suppose I don’t need the implementation of the ISessionProvider interface.

    I don’t know, maybe is the way I set the destination parameters, but it seems something is trying to change the session collection.

    Regards.

    • Hello,<br/><br/>you found a bug in our session clean-up mechanism. We’ll fix it right away. A workaround requires implementing your own session provider. I suggest the following:<br/><br/>class WorkaroundSessionProvider : ISessionProvider<br/>    {<br/>        <br/>        private Dictionary<string, Thread> rfcThreads;<br/><br/>        internal WorkaroundSessionProvider()<br/>        {<br/>            rfcThreads = new Dictionary<string, Thread>();<br/>        }<br/><br/>        public String GetCurrentSession()<br/>        {<br/>            string sessionID = Thread.CurrentThread.ManagedThreadId.ToString();<br/>            if (!rfcThreads.ContainsKey(sessionID))<br/>            {<br/>                rfcThreads[sessionID] = Thread.CurrentThread;<br/>            }<br/>            return sessionID;<br/>        }<br/><br/>        public void ContextStarted()<br/>        {<br/>        }<br/><br/>        public void ContextFinished()<br/>        {<br/>        }<br/><br/>        public String CreateSession()<br/>        {<br/>            return string.Empty;<br/>        }<br/><br/>        public void PassivateSession(String sessionID)<br/>        {<br/>        }<br/><br/>        public void ActivateSession(String sessionID)<br/>        {<br/>        }<br/><br/>        public void DestroySession(String sessionID)<br/>        {<br/>            lock (rfcThreads)<br/>            {<br/>                if (rfcThreads.ContainsKey(sessionID))<br/>                {<br/>                    rfcThreads.Remove(sessionID);<br/>                }<br/>                // fire a session DESTROYED event to clean up the session cache<br/>                SessionChanged(new RfcSessionEventArgs(RfcSessionManager.EventType.DESTROYED, sessionID));<br/>            }<br/>        }<br/><br/>        public bool IsAlive(String sessionID)<br/>        {<br/>            // always return true here to prevent currently flawed clean-up routine to trigger a concurrent modification exception<br/>            return true;<br/>        }<br/><br/>        public bool ChangeEventsSupported()<br/>        {<br/>            // return true here to ensure SessionChanged events are handled<br/>            return true;<br/>        }<br/><br/>        public event RfcSessionManager.SessionChangeHandler SessionChanged;<br/>    }<br/><br/>Register an instance, say sp, of that session provider through RfcSessionManager.RegisterSessionProvider(sp) before the first call to RfcSessionManager.BeginContext(). After each RfcSessionManager.EndContext() (or whenever you find it appropriate) do your own clean up by calling sp.DestroySession(sp.GetCurrentSession()).<br/><br/>I tested the proposed workaround and it appears to do the trick. Let me know if you have any issues with it.<br/><br/>I’d like to point out that there would normally indeed be no reason to implement your own session provider. The purpose of this session provider strictly is to bypass the periodic clean-up activities that are not working properly. Note that it puts the responsibility for removing expired sessions into your hands. So I recommend to remove the workaround as soon as you upgrade to a patch level (presumably the next one) that fixes this issue.<br/><br/>Regards,<br/>Matthias Fuchs, NCo3 Development<br/>

      • Hello Matthias,

        I’ve implemented your workaround and, after one hour executing RFC calls every two seconds, it has raised an IndexOutOfRangeException in the line rfcThreads[sessionID] = Thread.CurrentThread; of the GetCurrentSession() method, but at least I can manage it. I’ve substituted it by:

        try
        {
           rfcThreads.Add(sessionID, Thread.CurrentThread);
        }
        catch
        {
        }

        Thanks so much, I was getting crazy.

        • Hello Ana,

          that’s most likely a synchronization issue. I should have synchronized GetCurrentSession. So I suggest you use the following:

          public String GetCurrentSession()
          {
          string sessionID = Thread.CurrentThread.ManagedThreadId.ToString();
          lock (rfcThreads)
          {
          if (!rfcThreads.ContainsKey(sessionID))
          {
          rfcThreads[sessionID] = Thread.CurrentThread;
          }
          }
          return sessionID;
          }

          Regards,
          Matthias

          • Hello again Matthias,

            I’ve got another issue. After more than 2 hours of calling RFCs, in all those RFCs where I don’t need to use the BeginContext() method, because they don’t use the Transaction Commit, in the RFC Invoke method I start to receive the next exception:

            ‘SAP.Middleware.Connector.RfcSerializationException’

            Message
               RfcCompressor: CsRGetHandle failed

            Source
               sapnco_utils

            StackTrace
               at SAP.Middleware.Connector.RfcCompressor..ctor(Int32 totalLength, Int32 lzLength, Boolean compress)
               at SAP.Middleware.Connector.RfcTable.RfcDeserialize(RfcConnection conn, Int32 srcLength, Int32 rowLength, TableCompression compression)
               at SAP.Middleware.Connector.RfcConnection.ReadUpTo(RFCGET readState, RfcFunction function, RFCID toRid)
               at SAP.Middleware.Connector.RfcConnection.RfcReceive(RfcFunction function)
               at SAP.Middleware.Connector.RfcFunction.RfcDeserialize(RfcConnection conn, IRfcIOStream stream)
               at SAP.Middleware.Connector.RfcFunction.RfcCallReceive(RfcConnection conn, IRfcIOStream stream, RFCID rid)
               at SAP.Middleware.Connector.RfcFunction.RfcCallReceive(RfcConnection conn)
               at SAP.Middleware.Connector.RfcFunction.Invoke(RfcDestination destination)
               at SAPNETConnector.Core.GetVendors(String DestinationName, String Company) in C:\OZZ\BAS\NET\Classes\SAPNETConnector\SAPNETConnector\SAPNETConnector\Core.cs:line 930

            So I must restart the application. Any ideas?

            Best regards.

          • Hi,

            this looks like something for which you should open a customer message. It will need deeper investigation and the communication over blog comments is not appropriate in that case.

            Best regards,
            Markus

      • Hi Matthias:

        The bug still exists in 3.0.2.0. Same exception happens after about 5-10 minutes when using RfcSessionManager.BeginContext / RfcSessionManager.EndcContext.

        Do you have any idea when this will be fixed? How can a bug of such magnitude be even present in the release connector that was there since April?!

        Regards,

        Michael

    • It’s so strange, because although apparently the exception is raised in the object SAP.Middleware.Connector.RfcSessionManager.UpdateSessions, I’ve commented the afterwards management of the xml I receive from the RFC calls, so I’ve only executed RFC calls, and after 1 hour it haven’t crash, so the collection modified must be a xml nodes or tree nodes in different threads.

      Regards.

      • I’m not aware of the details of your coding, but I can tell you that our default session provider works similar to what I suggested as a work around in that it associates sessions with threads. A session is not removed as long as the thread associated with it is alive. The issue only occurs if a session is considered expired because the associated thread is not alive anymore. Then removing that session from an internal collection incurs the concurrent modification exception. That means as long as the thread that started a context is kept alive, the session will not be removed, and hence there will be no problem.

        Best Regards.

  • Hi Thomas,
    I need to implement web portal with real time data in SAP.
    1. Can I use connector directly to access the Data from SAP?
    2. If I am going to use portal DB as SQL Server, how I am going to integrate my portal DB with real time data from SAP??

    Swapnil

    • Hi Swapril,

      1. This is exactly the purpose of the .NET Connector: Accessing data of an SAP system.
      2. It heavily depends on what you want to do exactly. It is certainly possible that you do an integration of portal DB with real time data from an SAP system. Your description is pretty general so that I cannot explain what to do.

      Regards,
      Markus

      • Hi Markus,

        Thanks..

        Markus,Due to consideration of request and response time from .net portal to SAP, I am going to use my portal DB separately. But now thing is that How I have to develope a framework which will keep my portal DB in real time with SAP. Means Data fetching/sending to/from SAP with a prticular time slot.

        regards,

        Swapnil

  • Hi
    i translate the C# Example in a VB.NET Version

    Imports System
    Imports System.Collections.Generic
    Imports System.Linq
    Imports System.Text
    Imports SAP.Middleware.Connector
    Public Class Form1
    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    End Sub
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    Dim objDestConfig As New InMemoryDestinationConfiguration()
    RfcDestinationManager.RegisterDestinationConfiguration(objDestConfig)
    Console.WriteLine(“Registered own configuration”)
    objDestConfig.AddOrEditDestination(“TESTW47”, 1, “User”, “Password”, “DE”, “000”, “100.100.200.200”, “00”)
    Dim destination1 As RfcDestination = RfcDestinationManager.GetDestination(“TESTW47”)
    Try
    destination1.Ping()
    objDestConfig.RemoveDestination(“TESTW47”)
    Catch ex As Exception
    MsgBox(ex.Message)
    End Try
    End Sub
    End Class
    Public Class InMemoryDestinationConfiguration : Implements IDestinationConfiguration
    Private availableDestinations As Dictionary(Of String, RfcConfigParameters)
    Private changeHandler As RfcDestinationManager.ConfigurationChangeHandler
    Dim eventtype As Object

    Public Event ConfigurationChanged(ByVal destinationName As String, ByVal args As RfcConfigurationEventArgs) Implements IDestinationConfiguration.ConfigurationChanged
    Public Sub New()
    availableDestinations = New Dictionary(Of String, RfcConfigParameters)
    End Sub
    Public Function GetParameters(destinationName As String) As RfcConfigParameters Implements IDestinationConfiguration.GetParameters
    Dim foundDestination As RfcConfigParameters
    availableDestinations.TryGetValue(destinationName, foundDestination)
    Return foundDestination
    End Function
    Public Function ChangeEventsSupported() As Boolean Implements IDestinationConfiguration.ChangeEventsSupported
    Return True
    End Function
    Public Sub AddOrEditDestination(name, poolSize, user, password, language, client, applicationServer, systemNumber)
    Dim parameters = New RfcConfigParameters
    parameters.Add(RfcConfigParameters.Name, name)
    parameters.Add(RfcConfigParameters.MaxPoolSize, Convert.ToString(poolSize))
    parameters.Add(RfcConfigParameters.IdleTimeout, Convert.ToString(10))
    parameters.Add(RfcConfigParameters.User, user)
    parameters.Add(RfcConfigParameters.Password, password)
    parameters.Add(RfcConfigParameters.Client, client)
    parameters.Add(RfcConfigParameters.Language, language)
    parameters.Add(RfcConfigParameters.AppServerHost, applicationServer)
    parameters.Add(RfcConfigParameters.SystemNumber, systemNumber)
    Dim existingConfiguration As RfcConfigParameters

    If availableDestinations.TryGetValue(name, existingConfiguration) Then
    availableDestinations(name) = parameters
    ‘C# – RfcConfigurationEventArgs(EventArgs = New RfcConfigurationEventArgs(RfcConfigParameters.EventType.CHANGED, parameters))
    ‘not translated in BV.Net
    changeHandler(name, EventArgs.Empty)
    Else
    availableDestinations(name) = parameters
    Console.WriteLine(“Added application server destination ” + name)
    End If
    End Sub
    Public Sub RemoveDestination(name As String)
    If name <> Nothing AndAlso availableDestinations.Remove(name) Then
    Console.WriteLine(“Successfully removed destination ” + name)
    Console.WriteLine(“Fire deletion event for destination ” + name)
    RaiseEvent ConfigurationChanged(name, New RfcConfigurationEventArgs(RfcConfigParameters.EventType.DELETED))
    End If
    End Sub
    End Class

    • Thank’s a lot for the Example. We’re implemmenting something like that but we’re having some problems with a remote server access and BAPI_GOODSMVT_CREATE. When we work with a bapi that has small structures it works good, but when we try to work with a standard Bapi that has many structures an error like this apears: Lookup of function BAPI_GOODSMVT_CREATE metadata failed for destination GROMERO.
      It seems to be something related with a delay of the communication.
      The detail of the exception is:
      Se detectó SAP.Middleware.Connector.RfcInvalidStateException
        Message=Lookup of function BAPI_GOODSMVT_CREATE metadata failed for destination GROMERO
        Source=sapnco
        StackTrace:
             en SAP.Middleware.Connector.RfcRepository.LookupFunctionMetadataClassic(String name)
             en SAP.Middleware.Connector.RfcRepository.LookupFunctionMetadata(String name)
             en SAP.Middleware.Connector.RfcRepository.GetFunctionMetadata(String name)
             en SAP.Middleware.Connector.RfcRepository.CreateFunction(String name)
             en WebService1.Service1.Crea_Entrada_Mercancias(String FecDoc, String FecCont, String NumNot, String NumPed, String Centro, String Almacen, String Material, Int32 Cantidad, String Proveedor) en C:\Users\rvargas\Desktop\Nuevo Sistema MP\WebService1\WebService1\Service1.asmx.vb:línea 46
        InnerException: SAP.Middleware.Connector.RfcInvalidStateException
             Message=Lookup of StructureOrTable BAPI2017_GM_ITEM_CREATE metadata failed for destination GROMERO
             Source=sapnco
             StackTrace:
                  en SAP.Middleware.Connector.RfcRepository.LookupRecordMetadataClassic(String name, RecordType recordType)
                  en SAP.Middleware.Connector.RfcRepository.LookupRecordMetadata(String name, RecordType recordType)
                  en SAP.Middleware.Connector.RfcRepository.LookupFunctionMetadataClassic(String name)
             InnerException: SAP.Middleware.Connector.RfcCommunicationException
                  Message=destination GROMERO failed when calling DDIF_FIELDINFO_GET — see log for details
                  Source=sapnco
                  StackTrace:
                       en SAP.Middleware.Connector.RfcRepository.Execute(RfcFunction function)
                       en SAP.Middleware.Connector.RfcRepository.LookupRecordMetadataClassic(String name, RecordType recordType)
                  InnerException:
  • Thanks for the detailed article.

    I am trying to upload data into Ztables using a BAPI provided by the client, using C#.

    If you have any e.g on this, it will be helpful.

    Regards,

  • Hi Thomas,

    I examined the documents deal with NCo 3.0. But I can not understand how you are managing Repository. For example:

    …RegisterDestinationConfiguration(Config);
    myRFCDestination = …GetDestination(“X”);
    myRepository = myRFCDestination.Repository;
    myRepository.CreateFunction(“ZXXX”);

    When the CreateFunction called, I see that the metadata is created in Repository. Firstly, I want to ask why? And also, when the Repository metadata is cleaned? Can you explain the logic usage of Repository.

    Thanks.

    • Hello,

      function metadata acts as a blueprint for functions, since it holds the information on which parameters are available, what their names are, etc. Before you can create a function, you’ll need its metadata so NCO3 knows what to create. Calling CreateFunction on the Repository is simply a shortcut for getting the function metadata (RfcRepository.GetFunctionMetadata) and then creating the function from its metadata (RfcFunctionMetadata.Create). NCO3 automatically creates the metadata (i.e., looks it up from the respective backend, typically identified by the destination) if its not yet in the repository.

      The purpose of storing metadata in a repository is to increase efficiency so that metadata is retrieved from the backend only once (which can be relatively time-consuming). The repository is not cleared unless you tell it so. There are a variety of Clear methods for RfcRepository. Typically, however, there is no need for the repository to be cleared, with the notable exception of changing the signature of a function module in the backend while NCO3 is running. Then the repository needs to be cleared to enforce loading the modified metadata. But this is a rare case.

      Regards,
      Matthias Fuchs, NCO3 Development

      • Hi,

        Firstly, thanks for your answer.

        As I understand;

        Repository.CreateFunction has two mission:

        1. Repository.GetFunctionMetadata looks for the function name whether its metadata information is exist in repository. If not, it will bring the metadata from SAP regarding to connection information. If metadata is already in repository, then it will get the current metadata in repository.

        2. Function object will created according to function metadata object that is returned in step 1.

        So, we can say that Repository.CreateFunction(“ZF1”) is equal to Repository.GetFunctionMetadata(“ZF1”).CreateFunction()

        Can you verify me?

        On the other hand, I want to ask a question about RfcDestinationManager.RegisterDestinationConfiguration method. What will happen if several clients call this method with same configuration or with different configuration.

        Thanks.

        • Hello,

          your understanding of the repository and its purpose with respect to metadata and functions is correct.

          As for destination configurations, keep in mind that a default configuration can be defined through a destination section in your app.config. A default configuration can be overridden any time by registering an IDestinationConfiguration. However, another configuration can only be registered if the previous configuration is unregistered. Otherwise a RfcInvalidStateException is thrown. (Re-registering the same configuration has no effect and does in particular not throw an exception.) By the way, unregistering a registered configuration reinstates the default configuration.

          To answer your question, several clients using the same configuration is not a problem. However, several clients requiring different configurations can be a problem. The question here is, do you really need different configurations, or would the usage of custom destinations (RfcCustomDestination) be appropriate?

          In a nutshell, a custom destination can be derived from a configured destination, inherits everything from that destination, but allows to modify certain properties, such as user or password, for instance. That way, the configuration can provide the basis, or in other words the “common denominator” of a set of destinations, whereas the custom destination(s) derived from the configured destinations can do the “fine-tuning” required for a given client.

          Regards.

  • Hi,
    I’m trying to create a server using .NET Connector 3.0(version 3.0.2, framework 2 and x64) for receiving Idocs from SAP ALE.
    First I tried create a report just for test a function module with destination ‘my_nco_server’ and it worked.
    Now I’m trying send IDOC type HRMD_A from SAP using ALE for RFC server and I have this error on server: Non ABAP RFC Client not supported.

    StackTrace
    SAP.Middleware.Connector.RfcServerApplicationException: Uncaught exception SAP.Middleware.Connector.RfcUnsupportedPartnerException thrown in SAP.Middleware.Connector.RfcServer.ARfcDestShipImp when executing RFC server function ARFC_DEST_SHIP —> SAP.Middleware.Connector.RfcUnsupportedPartnerException: Non ABAP RFC Client not supported.
       at SAP.Middleware.Connector.RfcConnection.ReadUpTo(RFCGET readState, RfcFunction function, RFCID toRid)
       at SAP.Middleware.Connector.RfcConnection.Dispatch()
       at SAP.Middleware.Connector.RfcTransaction.Playback()
       at SAP.Middleware.Connector.RfcServer.ARfcDestShipImp(RfcServerContext ctx, IRfcFunction func)
       at SAP.Middleware.Connector.RfcServer.InvokeServerFunction(RfcConnection conn, ServerFunctionInfo serverFuncInfo, RfcServerFunction functionImp)

    Any ideas how to solve this problem?
    Do I need to do some “special configuration” because i´m sending from SAP ALE to my server??

  • I’m using the Framework4.0  in VS 2010, I have a project where I am using RFC for read information, however I want to make a insert of a report to the RFC “RPY_PROGRAM_INSERT. “

    The problem is that as the RCF has an output screen, the method falls, that does not support that.

    SAP.Middleware.Connector.RfcAbapRuntimeException: Screen output without connection to user. en SAP.Middleware.Connector.RfcConnection.ThrowRfcErrorMsg() en SAP.Middleware.Connector.RfcConnection.ReadBytes(Byte* buffer, Int32 count) en SAP.Middleware.Connector.RfcConnection.ReadRfcIDBegin(Int32& length) en SAP.Middleware.Connector.RfcConnection.ReadUpTo(RFCGET readState, RfcFunction function, RFCID toRid) en SAP.Middleware.Connector.RfcConnection.RfcReceive(RfcFunction function) en SAP.Middleware.Connector.RfcFunction.RfcDeserialize(RfcConnection conn, IRfcIOStream stream) en SAP.Middleware.Connector.RfcFunction.RfcCallReceive(RfcConnection conn, IRfcIOStream stream, RFCID rid) en SAP.Middleware.Connector.RfcFunction.RfcCallReceive(RfcConnection conn) en SAP.Middleware.Connector.RfcFunction.Invoke(RfcDestination destination)

    I wonder if it is possible to prevent attempt to lift the window, and I give the parameters that this new window comes to ask. Or know if it is quite impossible for SAP NCO support this.

    • Please use USE_SAPGUI=”1″ or USE_SAPGUI=”2″ as an additional attribute for the destination employed in your scenario. This should enable SAP GUI access.

      As for your second question, we assume that you are looking for a possibility to bypass a SAP GUI dialog by supplying the data that would otherwise be obtained through the dialog. That is not supported, which is not a limitation of NCO, but a general impossibility, as it would in a way corrupt the purpose of a dialog and possibly introduce security risks.

      • thank you very much.

        specifically for this function “RPY_PROGRAM_INSERT”
        using these parameters
        WITH_INCLUDELIST = X
        ONLY_SOURCE = X
        READ_LATEST_VERSION = X
        WITH_LOWERCASE = X

        no problems with screen output.

  • Hi,

    NCo 3.0 can process in parallel tRFC?

    I´m using the class MyTidHandler that came on tutorial with the download of the connector.
    Do I need to do some extra implementation in class MyTidHandler or in class MyServerHandler? If so, can you give me an idea how to implement? Or the parallel process should work just fine and probably is a problem on my code?

    • Hello,

      The examples in the tutorial are not meant to be used in a productive environment. We are currently revising those examples, but they are still going to be just that: examples. Most likely these examples are not thread-safe, so to answer your question: yes, you’ll have to put in some effort, in particular if you want to achieve thread safety.

      I could try and give you an idea of how to implement those classes (if indeed that is necessary), but I don’t know what the problem is with the current implementation, nor what exactly it is you have in mind.

      • Hi,
        Firstly, thanks for your answer.

        I know they are just examples, this is all new for me and I’m trying to start from the basic and then evolving on the implementation.
        If you could give me an idea of the key steps how to implement that would be great.

        Thanks.

        • Hi,

          here’s the revised example for tRFC, possibly not its final version, but hopefully more useful than the old version of it. It’s a lot of coding I copied from our sources that will be available with the next patch (3.0.3). It should give you a clearer understanding of what is required for NCo to implement a tRFC-enabled server. If I inadvertently omitted crucial details, let me know.

          /*
                     * This example demonstrates how to implement a TID handler and dispatch transactional calls (i.e., “call function in background task”).
                     *
                     * The following coding on the ABAP side will submit a request for execution of STFC_CONNECTION in a background task.
                     * (Set up a destination NCO_SERVER – or whichever name you choose – as described above.)
                     *
                     * CALL FUNCTION ‘STFC_CONNECTION’ IN BACKGROUND TASK DESTINATION ‘NCO_SERVER’.
                     * COMMIT WORK.
                     */
                    public static void ExampleTRfcServer()
                  {
                      // Creates a server instance using the NCO_SERVER configuration and the function handler for STFC_CONNECTION
                      RfcServer server = RfcServerManager.GetServer(NCO_SERVER_CONFIG_NAME, new Type[] { typeof(ServerFunctionStaticImpl) });
                      // Register event handlers for internal and application errors
                      server.RfcServerError += OnRfcServerError;
                      server.RfcServerApplicationError += OnRfcServerApplicationError;
                      // Register transaction ID handler
                         if (server.TransactionIDHandler == null) server.TransactionIDHandler = new MyTidHandler();
                      // Start the server instance, i.e. open the connection(s) as defined by parameter REG_COUNT (RfcConfigParameters.RegCount)
                      server.Start();
                      Console.WriteLine();
                      Console.WriteLine(“Server started: {0}”, server.Parameters.ToString());
                      Console.WriteLine(“You can now send requests for STFC_CONNECTION (synchronous or in background task) — press X to stop the server”);
                      while (Console.ReadLine() != “X”);
                      Console.WriteLine(“Server shutting down…”);
                      // Shut down the server, aborting any active calls
                      server.Shutdown(true);
                      // Remove error and TID handlers so that other examples using the same server can start from scratch
                      server.RfcServerError -= OnRfcServerError;
                      server.RfcServerApplicationError -= OnRfcServerApplicationError;
                      server.TransactionIDHandler = null;
                  }

                  /**
                   * This class represents a static function handler that can be used by a server to handle stateless calls.
                   * It implements one function, namely STFC_CONNECTION. If more functions were to be handled
                   * more static methods analogous to the available method could be implemented.
                   */
                  class ServerFunctionStaticImpl
                  {
                      // The annotation binds the function (name) to its implementation
                      [RfcServerFunction(Name = “STFC_CONNECTION”)]
                      public static void StfcConnection(RfcServerContext serverContext, IRfcFunction function)
                      {
                          MethodBase method = MethodInfo.GetCurrentMethod();
                          Console.WriteLine();
                          Console.WriteLine(“Method {2}.{0} processing RFC call {1}”, method.Name, function.Metadata.Name, method.DeclaringType.ToString());
                          Console.WriteLine(“System Attributes:”);
                          Console.WriteLine(AttributesToString(serverContext.SystemAttributes));

                          function.SetValue(“ECHOTEXT”, function.GetString(“REQUTEXT”));
                          function.SetValue(“RESPTEXT”, “NCO3: Hello world.”);

                              /* This class is also used in our tRFC Server example, so let’s do some more stuff here to make this more interesting…
                               */
                              if (serverContext.InTransaction) {
                                   Console.WriteLine(“Currently running in tRFC LUW {0}”, serverContext.TransactionID.TID);
                                   Console.WriteLine(“Do you want to abort this LUW with an error?”);
                                   if (Console.ReadLine().ToUpper().Equals(“Y”)){
                                        String errorMessage = “Not in the mood for tRFC. Try again later…”;
                                        MyTidHandler.SetError(serverContext.TransactionID, errorMessage);
                                        throw new RfcAbapMessageException(errorMessage, “E”);
                                   }
                              }
                      }
                  }

                  class MyTidHandler : ITransactionIDHandler
                  {
                      // Only for tests. In real life scenarios, use a database to store the transaction state!
                         private static TidStore tidStore = new TidStore(“sampleTidStore”, false);

                      public bool CheckTransactionID(RfcServerContextInfo serverContext, RfcTID tid)
                      {
                          Console.WriteLine();
                          Console.Write(“TRFC: Checking transaction ID {0} –> “, tid.TID);
                              TidStatus status = tidStore.CreateEntry(tid.TID);

                              switch (status) {
                                   case TidStatus.Status_Created:
                                   case TidStatus.Status_RolledBack:
                                        // In these case we have to execute the tRFC LUW.
                                        Console.WriteLine(“New transaction or one that had failed previously”);
                                        return true;
                                   default:
                                        // In the remaining cases we have already executed this LUW successfully, so we
                                        // can (or rather have to) skip a second execution and send an OK code to R/3 immediately.
                                        Console.WriteLine(“Already executed successfully”);
                                        return false;
                              }
                          /* “true” means that NCo will now execute the transaction, “false” means
                           * that we have already executed this transaction previously, so NCo will
                           * skip the function execution step and will immediately return an OK code to R/3.
                               * In a real life scenario, if DB is down/unavailable, throw an exception at this point.
                               * The .Net Connector will then abort the current tRFC request and the R/3 backend will
                               * try again later.
                               */
                         }

                      // Clean up the resources. Backend will never send this transaction again, so no need to
                         // protect against it any longer.
                      public void ConfirmTransactionID(RfcServerContextInfo serverContext, RfcTID tid)
                      {
                          Console.WriteLine();
                              Console.WriteLine(“TRFC: Confirm transaction ID {0}”, tid.TID);
                              tidStore.DeleteEntry(tid.TID);
                      }

                      // React to commit, e.g. commit to the database;
                      // Throw an exception if committing failed
                      public void Commit(RfcServerContextInfo serverContext, RfcTID tid)
                      {
                          Console.WriteLine();
                              Console.WriteLine(“TRFC: Commit transaction ID {0}”, tid.TID);
                              /* Do whatever is necessary to persist the data/changes of the function modules belonging to this LUW.
                               * Throw an exception, if that fails.
                               * If we know, that the LUWs that we are processing, consist of only a single function module,
                               * the processing server function may already persist everything at the end and set the status
                               * for that TID to Executed. */

                              /* No exception after this point */
                          try
                          {
                                   tidStore.SetStatus(tid.TID, TidStatus.Status_Committed, null);
                          }
                              catch (Exception){}
                      }

                      // React to rollback, e.g. rollback on the database
                      public void Rollback(RfcServerContextInfo serverContext, RfcTID tid)
                      {
                          Console.WriteLine();
                              Console.WriteLine(“TRFC: Rollback transaction ID {0}”, tid.TID);
                              /* Roll back all changes of the previous function modules in this LUW.
                               * If this LUW contains only one function module, we could already do this in the processing
                               * server function.
                           * We assume that the error message for this TID has already been added to the TidStore at the
                               * point where the error happened.
                           */
                              tidStore.SetStatus(tid.TID, TidStatus.Status_RolledBack, null);
                      }

                         /* This is only a convenience method, because I like to keep track of the last error, with which
                          * a transaction failed, in the status management. Makes it easier for administrators to fix the
                          * problem and then retry that LUW.
                          */
                         public static void SetError(RfcTID tid, String errorMessage) {
                              try {
                                   tidStore.SetStatus(tid.TID, TidStatus.Status_RolledBack, errorMessage);
                              }
                              catch (Exception){}
                         }

                         public static void ListLUWs() {
                              tidStore.PrintOverview();
                         }
                  }

                  /*
                   * This method is used as the event handler for internal server errors. Internal server errors are errors
                   * that are not caused by the application, but are incurred by NCO3. Such errors include, but are not limited to,
                   * communication errors (e.g., loss of connections), out of memory, etc.
                   */
                  private static void OnRfcServerError(Object server, RfcServerErrorEventArgs errorEventData)
                  {
                      RfcServer rfcServer = server as RfcServer;
                      Console.WriteLine();
                      Console.WriteLine(“>>>>> RfcServerError occurred in RFC server {0}:”, rfcServer.Name);
                      ShowErrorEventData(errorEventData);
                  }

                  /*
                   * This method is used as the event handler for application errors raised while a server processes a requested function.
                   * As opposed to internal errors these errors occur in application coding outside NCO3. Note that the application can throw
                   * whichever type of exception it sees fit. It will be wrapped in a RfcServerApplicationException and made available as its
                   * inner exception.
                   */
                  private static void OnRfcServerApplicationError(Object server, RfcServerErrorEventArgs errorEventData)
                  {
                      RfcServer rfcServer = server as RfcServer;
                      Console.WriteLine();
                      Console.WriteLine(“>>>>> RfcServerApplicationError occurred in RFC server {0}:”, rfcServer.Name);
                      ShowErrorEventData(errorEventData);
                      RfcServerApplicationException appEx = errorEventData.Error as RfcServerApplicationException;
                      if (appEx != null)
                      {
                          Console.WriteLine(“Inner exception type: {0}”, appEx.InnerException.GetType().Name);
                          Console.WriteLine(“Inner exception message: {0}”, appEx.InnerException.Message);
                      }
                      else
                      {
                          Console.WriteLine(“WARNING: errorEventData.Error is not an instance of RfcServerApplicationError”);
                      }
                  }

          • Hi,Thanks for the example.

            Correct me if I’m wrong or missing something in the following:
            In brief, there are the following key scenarios in tRFC:
            CheckTransactionID (database is currently down/other error) -> Connector will then send a SYSTEM_FAILURE back to the SAP system.
            CheckTransactionID (return false) -> Connector  send an OK code to R/3.
            CheckTransactionID (return true) -> function handler (raise exception) -> Rollback -> (2).
            CheckTransactionID (return true) -> function handler -> Commit -> (1) -> ConfirmTransactionID.

            On NCo30APIDocumentation ITransactionIDHandle.ConfirmTransactionID Method  says:” When the backend system finds out that the LUW corresponding to this TID has been executed completely and successfully on the RFC server side, it will trigger a ConfirmTID event. When receiving this event, the .NET Connector will call this API.”
            My questions:
            (1) – How backend system finds out that the LUW corresponding to this TID has been executed completely and successfully on the RFC server? The connector sends after Commit a message to the SAP system? If not, how?
            (2) – After Rollback the connector sends some message back to the SAP system? If not, how SAP system knows that LUW had not been executed completely and successfully?

          • Hi,

            for tRFC the well-known “no news is good news” principle applies. If no exception occurs, then the backend assumes the transaction was completed. If any exception occurs, the transaction is assumed to have failed. In the latter case it can be repeated at a later time.

            Note that the backend application initiating the tRfc call to the NCO server is not notified of success or failure. tRFC is, from the point of view of the application, an asynchronous operation. So COMMIT WORK does not give the application an indication of the state of the transaction. It merely schedules the transaction for execution. The tRFC scheduler, however, executes the scheduled tasks synchronously and records the results (exception = failure, or no exception = success). In case of failure, depending on the configuration of the scheduler, it will retry a number of times or abandon the execution. The application can retrieve the state of the transaction through appropriate APIs, or the user can check using SM58.

  • Using Framework 4, VS 2010, I created a web service that performs a function call RFC different SAP systems, the detail is that there are problems when multiple calls are made to the method of different system.

    I used the following class to change the configuration of the system.

    public class conexion : IDestinationConfiguration
        {
            String host, router, number, clt, us, pass;
            public void parametros(String serverhost, String saprouter, String sysnumber,
                String client, String user, String password)
            {
                host = serverhost;
                router = saprouter;
                number = sysnumber;
                clt = client;
                us = user;
                pass = password;
            }

            public RfcConfigParameters GetParameters(String destinationName)
            {
                if ((“ABAP_AS_POOLED”).Equals(destinationName))
                {
                    RfcConfigParameters parameters = new RfcConfigParameters();

                    parameters.Add(RfcConfigParameters.AppServerHost, host);
                    parameters.Add(RfcConfigParameters.SAPRouter, router);
                    parameters.Add(RfcConfigParameters.SystemNumber, number);
                    parameters.Add(RfcConfigParameters.Client, clt);
                    parameters.Add(RfcConfigParameters.User, us);
                    parameters.Add(RfcConfigParameters.Password, pass);
                    parameters.Add(RfcConfigParameters.Language, “ES”);

                    parameters.Add(RfcConfigParameters.PoolSize, “3”);
                    parameters.Add(RfcConfigParameters.MaxPoolSize, “10”);
                    parameters.Add(RfcConfigParameters.IdleTimeout, “600”);

                    return parameters;
                }
                else return null;
            }

            public bool ChangeEventsSupported()
            {
                return true;
            }

            public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;
        }

    The following code is used to call the RFC, is a program that downloads a code of any report in the specified system configuration.

    public static String DownSource(String prog_name, String serverhost, String saprouter, String sysnumber,
                String client, String user, String password)
            {
                String result = null;
                conexion nueva = new conexion();
                if (go == 0)// does this to avoid error: Destination configuration already initialized
                {
                    nueva.parametros(serverhost, saprouter, sysnumber, client, user, password);
                    RfcDestinationManager.RegisterDestinationConfiguration(nueva);
                }
               
                RfcDestination destination = RfcDestinationManager.GetDestination(“ABAP_AS_POOLED”);
                IRfcFunction function = null;
                go++;
                try
                {
                    function = destination.Repository.CreateFunction(“RPY_PROGRAM_READ”);
                    function.SetValue(“PROGRAM_NAME”, prog_name);
                    function.Invoke(destination);

                    IRfcTable source = function.GetTable(“SOURCE_EXTENDED”);

                    foreach (IRfcStructure row in source)
                    {
                        String field = row.GetString(“LINE”);
                        result = result + field;
                    }
                    //test
                }
         }

    Using this method
    several times with the same report, and various other
         error: no hay ningun error.

    changing system configuration sap
         error: Function module “刀倀夀开倀刀伀䜀刀䄀䴀开刀䔀䄀䐀” not found
         method does not work, that is trying to make it in the previous configuration and does not use the new parameters.

    Using this method with RfcDestinationManager.UnregisterDestinationConfiguration(nueva); in the code comment above “test”

    several times with the same report, and various other
         error: No DestinationConfiguration defined.
         only the first time it works.

    changing system configuration sap
          No DestinationConfiguration defined.

    I need to understand how does SAP.Middleware.Connector to make the call to a function in a configuration and how I can change this by calling again but with different parameters, the same method.

    If someone could help me change my methods to use any SAP configuration, without the method having problems with RfcDestinationManager. That is how I can close the initialization of RfcDestinationManager, so you can get a new one with different parameters.

    • Hello Jeison,

      separate the destination management from your application. An implementation of IDestinationConfiguration is considered as infrastructure coding. Further, you should notice that a destination is not a connection, but only a configuration, and that an implementation of IDestinationConfiguration is not thought for a single destination, but for many. The way you implemented your conexion, does only support a single destination. Have a look at the tutorial code for a CustomDestinationConfiguration.
      For making a function call with a different configuration, you need to return different configurations in conexion.GetParameters() for different values of destinationName.
      RfcDestinationManager.GetDestination(“ABC”) will invoke conexion.GetParameters(“ABC”) internally.
      Hence, if you have code like this
      RfcDestination dest1=RfcDestinationManager.GetDestination(“ABC”);
      RfcDestination dest2=RfcDestinationManager.GetDestination(“XYZ”);
      the two calls function.Invoke(dest1) and function.Invoke(dest2) will result in invocations in different systems, if the parameter sets returned by conexion for those two names are different.
      Why this strange error comes up (with Function module “刀倀夀开倀刀伀䜀刀䄀䴀开刀䔀䄀䐀” not found) I cannot tell you. I would kindly ask you to open a customer message for this so that it can be investigated.

      Regards,
      Markus

      • using the tutorial code  CustomDestinationConfiguration, I could use the function AddOrEditDestination to accept any configuration of SAP.

                    public void AddOrEditDestination(string applicationServer, string saprouter, string systemNumber, string client,string user, string password)

        then when I need to create a new configuration to use the RFC do this.

                    sap_config myDestinationConfiguration = new sap_config();
                    try {
                        RfcDestinationManager.RegisterDestinationConfiguration(myDestinationConfiguration);
                    }
                    catch(Exception e) {
                        myDestinationConfiguration.RemoveDestination(user);
                        RfcDestinationManager.UnregisterDestinationConfiguration(myDestinationConfiguration);
                    }                       
                    myDestinationConfiguration.AddOrEditDestination(serverhost, saprouter, sysnumber, client, user, password);
                    RfcDestination destination = RfcDestinationManager.GetDestination(user);
                    destination.Ping();

        when I have finished using the RFC realize this and nothing more.

                    myDestinationConfiguration.RemoveDestination(user);
                    RfcDestinationManager.UnregisterDestinationConfiguration(myDestinationConfiguration);

        thanks Markus Tolksdorf

  • Hello.
    Thanks for your post. Its remarkable.
    Please, can yo help me with this?

    How can I unregister the RFC Destination? When I run my app for second time, I get a error msg about of my RFCDestinationManager already has registered.

    RfcDestinationManager.RegisterDestinationConfiguration(new MyBackendConfig());//1

    I have found a method for unregister, but I dont know how to use it. This is the C# syntax:

    public static void UnregisterDestinationConfiguration(
         IDestinationConfiguration config
    )

    Parameters
    config
    IDestinationConfiguration
    the configuration to be unregistered

    Can you help me, please?

    Thanks in advance.

    gustavo.barboza@propilco.com

    • Hello Gustavo,

      For unregistering an implementation of IDestinationConfiguration you need to pass the original instance. This means you need to store the reference to the instance safely somewhere in your own infrastructure components. But normally, you don’t unregister an IDestinationConfiguration regularly. You obviously have a misunderstanding how this interface should be used. You need to have only a single implementation for all of your destinations. The implementation than simply has to return the correct configuration when being asked for a certain destination of name “abc” by the RfcDestinationManager. Moreover, you should separate such infrastructure code from the business application code. The infrastructure setup needs only to be run once, application code typically more often within the lifetime of a process.

      Regards,
      Markus

  • Invoke the IRfcFunction of this BAPI thows the exception:

    {“FIELD ENDTIME of STRUCTURE BAPICATS2 (SETTER): cannot convert String into TIME”}
        [SAP.Middleware.Connector.RfcTypeConversionException]: {“FIELD ENDTIME of STRUCTURE BAPICATS2 (SETTER): cannot convert String into TIME”}
        base {System.ApplicationException}: {“FIELD ENDTIME of STRUCTURE BAPICATS2 (SETTER): cannot convert String into TIME”}

    Is that an error in the .Net connector? Or do we need to change the metadata before it can be invoked?

    • That sounds like a topic for a CSS message. Please open a ticket. I’m not sure what is wrong there, but NCo3 is perfectly capable of converting String into TIME. When you do open a ticket, please include the error log dev_nco_rfc.log and a definition of the (relevant parts of) structure BAPICATS2.

      Before you open a ticket make sure you are using the most recent version of NCo3 (in the log, look for “SAP .NET Connector: 3, 0, 2, 0” at the very beginning of that file).

  • Hi,

    I am developing a client with NCO 3.0 to send IDocs from non-SAP system to SAP. I have tried several methods but i have still errors when I call invoke function (The error is “Segment E1ADHDR, segmentnumber ” not correct”).

    This is my code, please tell me what i am doing wrong.

    RfcDestinationManager.RegisterDestinationConfiguration(new SAPIDocDestinationConfiguration(DestinationName));//1
                _rfcDestination = RfcDestinationManager.GetDestination(DestinationName);

                RfcRepository SAPRfcRepository = _rfcDestination.Repository;
                IRfcFunction RFCIdoc_Inbound = SAPRfcRepository.CreateFunction(“IDOC_INBOUND_ASYNCHRONOUS”);//IDOC_INBOUND_ASYNCHRONOUS”);
                RfcSessionManager.BeginContext(_rfcDestination);
                // Process the IDoc DC40 header segment
                IdocControlRec40 = RFCIdoc_Inbound.GetTable(“IDOC_CONTROL_REC_40”);

                structureIdocControlRec40 = IdocControlRec40.Metadata.LineType.CreateStructure();
    structureIdocControlRec40.SetValue(“TABNAM”, “EDI_DC40”.PadRight(structureIdocControlRec40[“TABNAM”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“MANDT”, “100”.PadRight(structureIdocControlRec40[“MANDT”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“DOCNUM”, “0000000000318807”.PadRight(structureIdocControlRec40[“DOCNUM”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“DOCREL”, “700”.PadRight(structureIdocControlRec40[“DOCREL”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“STATUS”, “01”.PadRight(structureIdocControlRec40[“STATUS”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“DIRECT”, “1”.PadRight(structureIdocControlRec40[“DIRECT”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“OUTMOD”, “2”.PadRight(structureIdocControlRec40[“OUTMOD”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“EXPRSS”, “”.PadRight(structureIdocControlRec40[“EXPRSS”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“TEST”, “”.PadRight(structureIdocControlRec40[“TEST”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“IDOCTYP”, “ALEAUD01”.PadRight(structureIdocControlRec40[“IDOCTYP”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“CIMTYP”, “”.PadRight(structureIdocControlRec40[“CIMTYP”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“MESTYP”, “ALEAUD”.PadRight(structureIdocControlRec40[“MESTYP”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“MESCOD”, “”.PadRight(structureIdocControlRec40[“MESCOD”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“STD”, “”.PadRight(structureIdocControlRec40[“STD”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“STDVRS”, “”.PadRight(structureIdocControlRec40[“STDVRS”].Metadata.NucLength, ‘ ‘));          
                structureIdocControlRec40.SetValue(“STDMES”, “ALEAUD”.PadRight(structureIdocControlRec40[“STDMES”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“SNDPOR”, “HBSWHIB01Q”.PadRight(structureIdocControlRec40[“SNDPOR”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“SNDPRT”, “LS”.PadRight(structureIdocControlRec40[“SNDPRT”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“SNDPFC”, “”.PadRight(structureIdocControlRec40[“SNDPFC”].Metadata.NucLength, ‘ ‘));  
                structureIdocControlRec40.SetValue(“SNDPRN”, “HBSWHIB01Q”.PadRight(structureIdocControlRec40[“SNDPRN”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“SNDSAD”, “”.PadRight(structureIdocControlRec40[“SNDSAD”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“SNDLAD”, “”.PadRight(structureIdocControlRec40[“SNDLAD”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“RCVPOR”, “SAPQXC”.PadRight(structureIdocControlRec40[“RCVPOR”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“RCVPRT”, “LS”.PadRight(structureIdocControlRec40[“RCVPRT”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“RCVPFC”, “”.PadRight(structureIdocControlRec40[“RCVPFC”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“RCVPRN”, “DLFSQ0C100”.PadRight(structureIdocControlRec40[“RCVPRN”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“RCVSAD”, “”.PadRight(structureIdocControlRec40[“RCVSAD”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“RCVLAD”, “”.PadRight(structureIdocControlRec40[“RCVLAD”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“CREDAT”, “20110316”.PadRight(structureIdocControlRec40[“CREDAT”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“CRETIM”, “144959”.PadRight(structureIdocControlRec40[“CRETIM”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“REFINT”, “”.PadRight(structureIdocControlRec40[“REFINT”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“REFGRP”, “”.PadRight(structureIdocControlRec40[“REFGRP”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“REFMES”, “”.PadRight(structureIdocControlRec40[“REFMES”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“ARCKEY”, “4D8013A0702F040BE1008000889E09E4 0000000002263837”.PadRight(structureIdocControlRec40[“ARCKEY”].Metadata.NucLength, ‘ ‘));
                structureIdocControlRec40.SetValue(“SERIAL”, “”.PadRight(structureIdocControlRec40[“SERIAL”].Metadata.NucLength, ‘ ‘));
               

                IdocControlRec40.Insert(structureIdocControlRec40);
                RFCIdoc_Inbound.SetValue(“IDOC_CONTROL_REC_40”, IdocControlRec40);
                // Process the IDoc DDR40 data segment
                IdocDataRec40 = RFCIdoc_Inbound.GetTable(“IDOC_DATA_REC_40”);
    structureIdocDataRec40 = IdocDataRec40.Metadata.LineType.CreateStructure();

                            structureIdocDataRec40.SetValue(“SEGNAM”, “E2ADHDR001”.PadRight(structureIdocDataRec40[“SEGNAM”].Metadata.NucLength, ‘ ‘));
                structureIdocDataRec40.SetValue(“MANDT”, “100”.PadRight(structureIdocDataRec40[“MANDT”].Metadata.NucLength, ‘ ‘));
                structureIdocDataRec40.SetValue(“DOCNUM”, “0000000000318807”.PadRight(structureIdocDataRec40[“DOCNUM”].Metadata.NucLength, ‘ ‘));
                structureIdocDataRec40.SetValue(“SEGNUM”, “000001”.PadRight(structureIdocDataRec40[“SEGNUM”].Metadata.NucLength, ‘ ‘));
                structureIdocDataRec40.SetValue(“PSGNUM”, “”.PadRight(structureIdocDataRec40[“PSGNUM”].Metadata.NucLength, ‘0’));
                structureIdocDataRec40.SetValue(“HLEVEL”, “02”.PadRight(structureIdocDataRec40[“HLEVEL”].Metadata.NucLength, ‘ ‘));

    StreamReader str = File.OpenText(“c:\\Aleauditv3.txt”);
                string txtIdocContents;
                txtIdocContents = str.ReadToEnd();

                           
                structureIdocDataRec40.SetValue(“SDATA”, txtIdocContents);
    IdocDataRec40.Insert(structureIdocDataRec40);

                structureIdocDataRec40.SetValue(“SEGNAM”, “E2STATE002”.PadRight(structureIdocDataRec40[“SEGNAM”].Metadata.NucLength, ‘ ‘));
                structureIdocDataRec40.SetValue(“MANDT”, “100”.PadRight(structureIdocDataRec40[“MANDT”].Metadata.NucLength, ‘ ‘));
                structureIdocDataRec40.SetValue(“DOCNUM”, “0000000000318807”.PadRight(structureIdocDataRec40[“DOCNUM”].Metadata.NucLength, ‘ ‘));
                structureIdocDataRec40.SetValue(“SEGNUM”, “000002”.PadRight(structureIdocDataRec40[“SEGNUM”].Metadata.NucLength, ‘ ‘));
                structureIdocDataRec40.SetValue(“PSGNUM”, “000001”.PadRight(structureIdocDataRec40[“PSGNUM”].Metadata.NucLength, ‘0’));
                structureIdocDataRec40.SetValue(“HLEVEL”, “03”.PadRight(structureIdocDataRec40[“HLEVEL”].Metadata.NucLength, ‘ ‘));

                StreamReader str2 = File.OpenText(“c:\\PAleauditv4.txt”);           
                txtIdocContents = str2.ReadToEnd();

                structureIdocDataRec40.SetValue(“SDATA”, txtIdocContents);

                IdocDataRec40.Insert(structureIdocDataRec40);
                RFCIdoc_Inbound.SetValue(“IDOC_DATA_REC_40”, IdocDataRec40);
    RFCIdoc_Inbound.Invoke(_rfcDestination);

    • Hello Joseba,

      Actually, this looks like an error within the IDoc processing in the ABAP backend. At a first glance the IDoc looks fine, but potentially, there is something that needs explanation from the ALE colleagues.
      Some remarks on your coding:
      * Invoking the PadRight method is not necessary. NCo is doing that internally anyway.
      * setting a default value is also not necessary, e.g. setting “” or ”     ” will not change the behavior compared to omitting to do so. You could therefore remove more than 10 of the SetValue statements.
      * IDocs should always be sent as an RfcTransaction and not synchronously via RfcFunction.Invoke …

      Best regards,
      Markus

      • What I don’t understand is that sending the same data with SubmitIDoc procedure of SapiDocSender object in NCO 2.0 works…

        Another doubt is related to SDATA content. Inside this field I have to put only te values of the fields related to the segment specified in the SEGNAM field, no?

        For instance, if i have a row like this in my flat file:
        E2ADHDR001                    1000000000000318807000001      02ALEAUD      ALEAUD

        This info i have to load in IDOC_DATA_REC_40 table like this:

        structureIdocDataRec40.SetValue(“SEGNAM”, “E2ADHDR001”);
                    structureIdocDataRec40.SetValue(“MANDT”, “100”);
                    structureIdocDataRec40.SetValue(“DOCNUM”, “0000000000318807”);
                    structureIdocDataRec40.SetValue(“SEGNUM”, “000001”);                        structureIdocDataRec40.SetValue(“HLEVEL”, “02”);
        structureIdocDataRec40.SetValue(“SDATA”, “ALEAUD      ALEAUD”);

        Please confirm me that because maybe the issue is there!!

        Thanks Markus!!

        • Hello Joseba,

          I guess that there is some difference that we are just not seeing now. Looking at your code, I would assume that this should work, the SDATA field has been filled properly in my eyes. If you don’t succeed open a customer message for it.

          Regards,
          Markus

  • I’m attempting to use the connector from within a WCF service written in VB.NET. However when invoke a method I receive an error regarding the exe path. The code works fine from a standard executeable file. Is there some way to make this work ?
    • This does not seem to be a topic to be discussed in the context of this blog. Please open a CSS message and provide details on the error. We think this issue is a known issue and requires a workaround on your part, but we’ll wait for the details to be sure.
  • My company has a series of interfaces that were created using the .NET Connector and Visual Studio 2003. Is it possible to build a connector object containing a SAP proxy in Visual Studio 2010 with version 3 of the .NET Connector in the same manner?
    • Hello David,

      The programming model has been changed from 2.0 to 3.0. Proxies that need to be generated within Visual Studio are no longer existing with .NET Connector 3.0.

      Best regards,
      Markus

      • Thanks, Markus. So I cannot import the proxy object I created with VS 2003 into VS 2010?

        In that case, how do I go about developing a solution with .Net Connector 3.0 and Visual Studio 2010 that contains the same RFC calls as our previous solution?

        • Hello David,

          NCo 3.0 no longer has a design time, which means that importing a proxy in 2010 would still leave you a lot of manual work to adopt the proxy to use the NCo 3.0 runtmie. Alternatively, you could think of a redesign of your application and rewrite the code that does the real ABAP system communciation.

          Best regards,
          Markus

          • Hello David,

            go to https://service.sap.com/connectors -> SAP Connector for Microsoft .NET. In the section “Download SAP Connector for Microsoft .NET Version 3.0” you can find documentation, e.g. NCo_30_Overview.pdf or
            NCo_30_ProgrammingGuide.pdf. Please keep an eye on them, as they will be updated from time to time.

            Regards,
            Markus

          • Hi,

            I hope you have gone through the samples suggested by Markus.

            In case if you still need a sample code, let me know, I will attach my working sample code. I have written it to export data from my application to SAP Z-tables using a RFC designed client.

            Regards.

  • Hello,

    In the API documentation file of format chm, you mentioned:

    DATE rfc data type should be got with GetString() method. And in the help of GetString() method, there is a sentence for DATE : “returns the external(hyphened) date string”

    When I try to get a date field with GetString() method, format is : “YYYY-MM-DD” (Year-Month-Day). I want to ask that format will be as this all the time? I mean that can this format be changed depending on SAP servers, other servers or any other things? And the separator will be ‘-‘ every time?

    Thanks.

    • Hello Kipuha,

      GetString on a field representing a DATE type will always return the format yyyy-MM-dd. There is no API that allows a different string format.

      Best regards,
      Markus

    • You can use GetCharArray() to obtain yyyyMMdd (without hyphens, but as a char[] of course) if that is of any use to you. Other than that, as Markus said, NCo does not offer alternative input/output conversions for DATE. You’d have to implement that yourself.
  • Hi,
    Our SAP side requires me to create a .NET application that will act as a Server to receive from SAP.

    However, their setting is:
    Activation Type = Start on Front-End Work Station
    Export = C:\Export.exe

    which is different from the setting in your blog.

    I need help on the structure of the EXE(.NET) to be able to get connection from SAP as a server.
    Is this still covered in .NET connector?
    How should I proceed?

    Thanks in advance.

    • Hello,

      server functionality is still covered. For starters, I suggest you consult the documentation and/or tutorial available from the NCo download site.

      Regards,
      Matthias Fuchs

        • I’d say yes. In that case use NCo as a server and submit a request (i.e., a RFC call with the appropriate destination) to NCo upon completion of the batch job. That request represents the event which can contain as little or as much information as you consider appropriate, and can be processed whichever way you see fit.

          You may also want to look into the BGRfc (Background RFC) capabilities of NCo in the context of this particular type of usage.

          • As always with event handling, you need somebody to fire the event. So creating a job won’t be sufficient. When the job completes NCo (as a server) has to be contacted somehow. If there is a way on the ABAP side to be notified of a job’s completion, then that is where you could add some coding to notify NCo as well. Alternatively, the job itself could notify NCo as soon as it is done. In terms of event handling, think of NCo as the listener for the event. So NCo can be configured to listen and process incoming events, but it won’t do a thing unless an event is fired, which is basically what a server does, except in the server context the terminology is slightly different in that we speak of requests rather than events.
  • Dear Mr. Weiss,
    this is my working code(it only can be build with Framework2 not with Framework4).

    Why cant I find the created destination “PRD_000” in my client 800. This is what the documentation for SAP net.connector3 says:
    “Returns the destination object specified by name. The RfcDestinationManager checks whether that destination has already been created, and if not asks the Configuration object for the necessary logon parameters and creates it. If no Configuration object has been registered by the application an exception is thrown…”

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using SAP.Middleware.Connector;

    namespace SAP_NET_Connector_3
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            private void Form1_Load(object sender, EventArgs e)
            {
                txtSAP.ScrollBars = ScrollBars.Both;
                txtSAP.AcceptsTab = true;
                RfcDestinationManager.RegisterDestinationConfiguration(new MyBackendConfig());
                RfcDestination prd = RfcDestinationManager.GetDestination(“PRD_000”);
                try
                { 
                    RfcRepository repo = prd.Repository;
                    //Die BAPI Funktion mit den einzelnen Feldern findet man -> SE37(Functionbuilder) ->  EXPORT -> Langtext                     
                    IRfcFunction companyBapi = repo.CreateFunction(“BAPI_COMPANY_GETDETAIL”);
                    txtSAP.Text = “SAP ECC Client = ” + prd.Client.ToString() + Environment.NewLine + “=============================” + Environment.NewLine;
                    for (int n = 0; n<9; n++)
                    {
                        for (int m = 0; m<9; m++)
                        {
                            companyBapi.SetValue(“COMPANYID”, “00” + n.ToString() + m.ToString() + “00”);
                            companyBapi.Invoke(prd);
                            IRfcStructure detail = companyBapi.GetStructure(“COMPANY_DETAIL”);
                            String companyName = detail.GetString(“COMPANY”);
                            String companyName1 = detail.GetString(“NAME1”);
                            String companyStreet = detail.GetString(“STREET”);
                            String companyPlz = detail.GetString(“POSTL_COD1”);
                            String companyCity = detail.GetString(“CITY”);
                            String companyCountry = detail.GetString(“COUNTRY”);
                            if (companyName != “”)
                            {
                                txtSAP.Text = txtSAP.Text + companyName + Environment.NewLine + companyName1 + Environment.NewLine + companyStreet + Environment.NewLine + companyPlz + ”  ” + companyCity + Environment.NewLine + companyCountry + Environment.NewLine + “——————————–” + Environment.NewLine;
                                //deselect the inserted text
                                txtSAP.Select(0, -1);
                            }
                        }
                    }
                }
             
                catch
                {
                    MessageBox.Show(“RFC Fehler”);
                }
            }
        }
        public class MyBackendConfig : IDestinationConfiguration
        {
            public RfcConfigParameters GetParameters(String destinationName)
            {
                if (“PRD_000”.Equals(destinationName))
                {
                    RfcConfigParameters parms = new RfcConfigParameters();
                    parms.Add(RfcConfigParameters.Name, destinationName);
                    parms.Add(RfcConfigParameters.AppServerHost, “rwth-xxx”);
                    parms.Add(RfcConfigParameters.SystemNumber, “xx”);
                    parms.Add(RfcConfigParameters.SystemID, “ECC”);
                    parms.Add(RfcConfigParameters.User, “SAPUSER”);
                    parms.Add(RfcConfigParameters.Password, “xxx”);
                    parms.Add(RfcConfigParameters.Client, “800”);
                    parms.Add(RfcConfigParameters.Language, “DE”);
                    parms.Add(RfcConfigParameters.PoolSize, “1”);
                    parms.Add(RfcConfigParameters.MaxPoolSize, “1”);
                    parms.Add(RfcConfigParameters.IdleTimeout, “600”);
                    return parms;
                }
                else return null;
            }
            public bool ChangeEventsSupported()
            {
                return false;
            }
            public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;
        }

    }
    Best regards
    Axel Arnold Bangert – Herzogenrath 2011

    • Hello,

      that’s a bit of a mystery. Your code looks alright. Do you get an exception (RfcInvalidParameterException) with the message “Destination PRD_000 does not exist”, or what happens when RfcDestinationManager.GetDestination(“PRD_000”) is called?

      When you debug your application and set a breakpoint in MyBackendConfig.GetParameters at the very first line of that method, I assume the debugger never stops there?

      There isn’t, by any chance, another class MyBackendConfig somewhere that is accidentally used (that’s kind of a long shot)?

      Another thought: You’re running a windows forms application; is this issue reproducible in a console application, too? If it is, please attach that coding.

      Regards,
      Matthias Fuchs, NCo3 Development

      • Hi Mr. Fuchs,
        no I get no exception and the values are all shown in the txtBox. Where exactly do I have to search for the destination?

        Debug:

        • Hello Mr. Bangert,

          in that case I don’t quite see what the problem is. Your destination is right there, in variable prd (type RfcDestination). What else are you looking for?

          Best regards,
          Matthias Fuchs

          • Dear Mr. Fuchs,
            now – perhaps – I begin to understand. I searched below SM59 for the created destination PRG_000.

            So following your words, I guess, that the logical destination is only created in Memory, will never be saved and will set to null after deregistration?

            Is it like that?
            Best regards
            Axel Arnold Bangert – Herzogenrath 2011

      • public static void LocalMain()
                {
                    InMemoryDestinationConfiguration myDestinationConfiguration=new InMemoryDestinationConfiguration();
                    RfcDestinationManager.RegisterDestinationConfiguration(myDestinationConfiguration);
                    Console.WriteLine(“Registered own configuration”);
                    myDestinationConfiguration.AddOrEditDestination(“Demo1”, 5, “SAPUSER”, “xxx”, “DE”, “800”, “RWTH-xxx”, “xx”);

                    RfcDestination destination1=RfcDestinationManager.GetDestination(“Demo1”);
                    destination1.Ping();
                    Console.WriteLine(destination1.SystemAttributes);
                    myDestinationConfiguration.AddOrEditDestination(“Demo1”, 5, “SAPUSER”, “xxx”, “DE”, “800”, “RWTH-xxx”, “xx”);
                    destination1=RfcDestinationManager.GetDestination(“Demo1”);
                    destination1.Ping();
                    Console.WriteLine(destination1.SystemAttributes);
                    try
                    {
                        destination1=RfcDestinationManager.GetDestination(“Demo1”);
                    }
                    catch (RfcInvalidParameterException ipe)
                    {
                        Console.WriteLine(“Caught expected exception: “+ipe.Message);
                    }
                    RfcDestinationManager.UnregisterDestinationConfiguration(myDestinationConfiguration);
                    Console.WriteLine(“Unregistered own configuration successfully”);
                }

  • Can you offer any guidance on how to do SSO from a .Net client to SAP?  I’ve read SNC might work, but can’t find any good docs to give an example.  Our SAP ECC 6.0 system (Netweaver 7.01) runs on AIX and we would like to use our active directory account as a trusted source for the user specific SSO to SAP programatically via NCo call to SAP.  The .Net front-end is a SharePoint 2010 web part.
    • You can try the following approach that uses x509 certificate to realize SSO (no guarantees though):

      – Suppose that your SAP ECC system has been configured to support SNC, and SNC libraries has been installed on the SharePoint server so that
      you can access ECC from the Windows server with SNC/SSO, for example using SAPGUI. As first step,  you need to enable SNC communication
      between your SharePoint/IIS and SAP EEC using ABAP transaction snc0. The purpose of this SNC enabled communication is not for SSO itself, but
      just for securing the communication.

      – Map external users contained in x509 certificates to SAP users by maintaining table VUSREXTID in SAP EEC

      – Access your web application running on SharePointer/IIS only over https, so that your application that uses NCO3 can get a certificate
      from the HTTPS request

      – In your .NET app, use a RfcCustomDestination to set connection parameters, in addition to SNC-related parameters, also, set the
      X509Certificate property with the client certificate of the HTTPs request.

      The document of .NET Connector 2 describes this scenario more in details. Since we changed the API in NCO3, the document doesn’t apply exactly, but principle remains the same. Please have a look at http://help.sap.com/saphelp_nw04/helpdata/EN/da/b7986ad1468b49a8b99b69298fa70a/frameset.htm   -> SAP .Net Connector Programmer’s Reference ->
      SAP .Net Client Programming -> Authentication -> Single Sign-On -> X.509 Certificates

      • Thank you for the insights Matthais, and I want to summarize a simple SSO work around we implemented that might be sufficient.

        We already have SSO implemented via SPNego in our SAP portal to our SAP business systems (ECC, APO, etc.).  Therefore we created a simple iView on our SAP portal that redirects a request back to the caller passing along all request parameters. 

        So the .Net SSO to SAP flow looks like this:
        1 – User logs into active directory network and gets kerberos token.
        2 – User invokes SharePoint webpart that uses NCo to execute SAP ECC function module.
        3 – SP webpart redirects to custom iView in SAP portal thereby generating MYSAPSSO2 logon ticket and redirects back to SP webpart.
        4 – SP webpart confirms MYSAPSSO2 cookie exists and uses it’s encrypted value in NCo API to logon to SAP ECC to perform function module.

        Yes, it’s a bit of redirection and back and forth, but it works.

        Any ideas on further improving and refining this solution?

        • Hello Kevin,

          unfortunately, for your use case I don’t see a an easier way to implement SSO. On the other hand, it is a very common approach if you consider your iView being a secure token service (STS). When lookin at the flow under this aspect, you can consider it ok.

          Best regards,
          Markus

  • Using .Net Connector 3.0\Compiled with .NET Framework 2.0 and MS Visual Studio 2008, C#

    Hello Thomas,

    I created an application where the user can input SAP user name and password in a dialog. Then it connects to SAP and executing some RFC. Working fine.
    When the user put in a wrong SAP username or password I get an exception. OK.

    But what do I have to do, to let him login again with the correct username and password.

    Here is my coding:

    IDestinationConfiguration config = new myBackendConfig(); // provides all connection parameters including user/pwd
    RfcDestination prd = RfcDestinationManager.GetDestination(config.GetParameters(connId));
    RfcRepository repo = prd.Repository;

    When I call this second time with correct user/password, then the prd.Repository will run into an exception with message:
    “Der Wert darf nicht NULL sein.\nParametername: key” (german)
    My translation: “Value must not be NULL.\nParameter name: key”.

    Any help would be appreciated!

    Regards,
    Peter
    • Hello,

      Looking at your coding I’m not sure how this is supposed to work. Do you register your config using RfcDestinationManager.RegisterDestinationConfiguration or what is the purpose of your config? It looks to me as if you only use it to retrieve a destination name.

      Apart from that, the described scenario should be handled with a RfcCustomDestination. Retrieve your basic destination that has everything except user and password, then derive a custom destination from that destination through RfcDestination.CreateCustomDestination(). Such a custom destination allows you to set (and reset) user and password, but is otherwise functionally equivalent to a regular destination.

      Regards,
      Matthias

      • Hi,

        in such a case as described by Matthias, you should consider configuring either a repoitory destination or a repository user/repository password so that this destination can still be used for retrieving metadata information from the associated backend.

        Best regards,
        Markus

      • Thank you Matthias, using RfcDestination.CreateCustomDestination() works as expected.
        Regards, Peter

        Codefragment:
        public class MySapConfig : IDestinationConfiguration

        prd = RfcDestinationManager.GetDestination(connId);
        RfcCustomDestination custDest = prd.CreateCustomDestination();

        // overwrite with dialog values, in case of second login
        MySapConfig sapCfg = new MySapConfig(m_conns, m_sbLastError);
        RfcConfigParameters logonParms = sapCfg.GetParameters(connId);
        custDest.Client = logonParms[“CLIENT”];
        custDest.User = logonParms[“USER”];
        custDest.Password = logonParms[“PASSWD”];
        custDest.Language = logonParms[“LANG”];
        repo = custDest.Repository;

  • Hi Thomas,<br/><br/>I want to implement a ASP.NET 4.0 webservice using Nco 3.0. webservice has a unique method Helloworld:<br/><br/><WebMethod()> _<br/>    Public Function HelloWorld() As String<br/>        Try<br/>            Dim destination As RfcDestination = RfcDestinationManager.GetDestination(“SAP”)<br/>            RfcSessionManager.BeginContext(destination)<br/>            RfcSessionManager.EndContext(destination)<br/>            Return “Hello world”<br/>        Catch ex As Exception<br/>            Return ex.Message & ” ” & ex.InnerException.Message<br/>        End Try<br/>    End Function<br/><br/><br/>In Debug mode all is fine, but when i publish the webservice and invoke the webmethod HelloWorld, IIS Crash with and unhandled .NET framework exception in w3wp.exe process:<br/><br/>The type initializer for ‘SAP.Middleware.Connector.RfcSessionManager’ threw an exception. Event handlers can only be bound to HttpApplication events during IHttpModule initialization<br/><br/>The same code but in winapp exe, works fine.<br/>I don´t know waht i´m missing.<br/><br/>Thanks in advance<br/>rafael

        • Hello Rafael,

          I looked at the our code and now I’m slightly confused as to the cause of your issue, namely the type initializer of RfcSessionManager. I cannot see why that initializer would throw such an exception. So I again propose to open a CSS message. Please append the log file (dev_nco_rfc.log) containing the trace of this exception.

          Regards,
          Matthias

  • Hi Thomas,

    I have a problem with a web services in .Net 3.5 using Nco 3.0.3

    Sometime we received this exception when we call an RFC.

    21/10/2011 15.47.12 – SAP_Zaip_CID – End mark RFCID.??? (0x06CB) expected, but RFCID.NotUsed (0x0000) received
    DATE: 21/10/2011 15.47.12
    SOURCE: sapnco
    TRACE:    at SAP.Middleware.Connector.RfcConnection.ReadRfcIDEnd(RFCID expectedRid, RfcParameter& param, RfcTable& table)
       at SAP.Middleware.Connector.RfcConnection.ReadUpTo(RFCGET readState, RfcFunction function, RFCID toRid)
       at SAP.Middleware.Connector.RfcConnection.RfcReceive(RfcFunction function)
       at SAP.Middleware.Connector.RfcFunction.RfcDeserialize(RfcConnection conn, IRfcIOStream stream)
       at SAP.Middleware.Connector.RfcFunction.RfcCallReceive(RfcConnection conn, IRfcIOStream stream, RFCID rid)
       at SAP.Middleware.Connector.RfcFunction.RfcCallReceive(RfcConnection conn)
       at SAP.Middleware.Connector.RfcFunction.Invoke(RfcDestination destination)
       at WSIITLenno_ODP.SapProxyClient.SAP_Zaip_CID(String Zcdl, String Zwerks)
    MSG: End mark RFCID.??? (0x06CB) expected, but RFCID.NotUsed (0x0000) received
    21/10/2011 15.47.12 – MinPoolSize: 10
    21/10/2011 15.47.12 – MaxPoolSize: 30
    21/10/2011 15.47.12 – MaxUsedCount: 15
    21/10/2011 15.47.12 – PooledConnectionCount: 1
    21/10/2011 15.47.12 – UsedConnectionCount: 13

    21/10/2011 15.57.48 – SAP_Zaip_CID – End mark RFCID.??? (0x06CB) expected, but RFCID.NotUsed (0x0000) received
    DATE: 21/10/2011 15.57.48
    SOURCE: sapnco
    TRACE:    at SAP.Middleware.Connector.RfcConnection.ReadRfcIDEnd(RFCID expectedRid, RfcParameter& param, RfcTable& table)
       at SAP.Middleware.Connector.RfcConnection.ReadUpTo(RFCGET readState, RfcFunction function, RFCID toRid)
       at SAP.Middleware.Connector.RfcConnection.RfcReceive(RfcFunction function)
       at SAP.Middleware.Connector.RfcFunction.RfcDeserialize(RfcConnection conn, IRfcIOStream stream)
       at SAP.Middleware.Connector.RfcFunction.RfcCallReceive(RfcConnection conn, IRfcIOStream stream, RFCID rid)
       at SAP.Middleware.Connector.RfcFunction.RfcCallReceive(RfcConnection conn)
       at SAP.Middleware.Connector.RfcFunction.Invoke(RfcDestination destination)
       at WSIITLenno_ODP.SapProxyClient.SAP_Zaip_CID(String Zcdl, String Zwerks)
    MSG: End mark RFCID.??? (0x06CB) expected, but RFCID.NotUsed (0x0000) received
    21/10/2011 15.57.48 – MinPoolSize: 10
    21/10/2011 15.57.48 – MaxPoolSize: 30
    21/10/2011 15.57.48 – MaxUsedCount: 15
    21/10/2011 15.57.48 – PooledConnectionCount: 1
    21/10/2011 15.57.48 – UsedConnectionCount: 14

    Note that the UsedConnectionCount is increased every time and is not disposed after time out.
    The connection string is stored on web.config:


       
         
           
             
           

         

       

     

     
    This error happen only in web application and web service but not in windows application. 

    Do you have any suggestion?

    Best Regards Sao

    • Hello,

      This issue could be caused by a bug in NCo’s decompression algorithm that is fixed with the upcoming patch release 3.0.4. It is not per se related to web or windows application usage, but occurs under certain conditions. So it is conceivable that your web application runs into exactly that situation that provokes the error, while the windows application does not.

      To make a long story short, we recommend to switch to NCo 3.0.4 as soon as it is available from the download site. The patch is currently being prepared for release, so it shouldn’t take too long barring unforeseen circumstances. If the problem persists despite your using 3.0.4 please open a CSS message for component BC-MID-CON-NCO.

      Regards,
      Matthias Fuchs, NCo 3 Development

  • I try to call an RfcFunction.

    In the logs I see:
    Connection not in callback mode –> EXPORT parameter PE_HEADER was not serialized

    The parameter PE_HEADER is the parameter for the funtion and I am adding it to the function.

    What are I am doing wrong?

    christian

    • Hello,

      there is nothing wrong here. An export parameter is not serialized when sending a call from the client (NCo) to the backend (ABAP). It will be filled by the backend and its data will be available when deserializing (i.e., receiving the response). The message is not an error message, but rather an information message. By the way, I suppose you found that message in a trace file *.trc, not in the log file.

      Regards,
      Matthias

  • Hi Thomas..

    I want to use RFC_READ_TABLE to get the data from SAP db. So is it proper way to make integration by using .Nco 3.0. Please guide for same..

    Thanks in advance..

    Awaiting for reply…

    Regards,

    Swapnil

    • Hello Swapnil,

      Sorry for answering that late, but unfortunately, I have not been notified about new comments for the last 3 months.

      using RFC_READ_TABLE is very bad style. It bypasses authority checks for sensitive data and should not be used, if it can be avoided. And this is not only true in the context of NCo 3.0, this is valid for all connectors. If you want to access certain tables and there is no function module available that allows access to this data remotely, then you should define your own remote-enabled function module that encapsulates the access to the database table and does appropriate authority checks if necessary.After having defined this function module, you can invoke it from your .NET client program via .NET connector

      Best regards,

      Markus

  • Hi,

    Can anyone let me know how to extract the table using NCo 3.0 I was successfully in connecting the SAP Server through C#. I need to know how to extract a table data from SAP.

    Thanks

    Snehal

  • Hello,

      I’m the developer of PLMConnector, a little solution written in VB .NET that integrates Autocad with SAP CDESK.

      I’m using NCO 2.0 because it supports abap DESTINATION BACK callbacks.

      Do you know if NCO 3.0 will support callbacks in the future?

      Best regards,

        Filippo Bottega.

  • Hello Dear Experts,

    We can use .net connector 3.0 or web service for connect to SAP for same scenario.

    What are differences between net connector 3.0 and web service?

    Where use .net connector?

    Where use web service?

    I’m waiting ideas/thoughts of experts.

    Best regards.

    • Hi Melih,

      .Net Connector is using the SAP protocol RFC for communicating with the ABAP system and invokes remote enabled function modules via this protocol. WebServices however are a standard that uses the HTTP protocol underneath.

      NCo should be used for tight integrations with an ABAP backend, WebServices, if you’re not sure if the communication partner will always be the same. Moreover, you should check what kind of interfaces exist at all in the backend in order to determine what protocol could be used. There are more decision criteria, which have been nicely described in a teched presentation of 2011.

      Best regards,

      Markus

      • Hi Markus,

        You are correct.

        But I want to utilize from using 2 method experts. and read compare about two method.

        I use nco 3.0. It very simple, trusted method.

        But I haven little info about web service. Sometimes I ear “web service not call / unknow exception etc.” and xml structure very importend correct process.

        I waiting compare two method from Experts.

        Best regards.