cancel
Showing results for 
Search instead for 
Did you mean: 

.net connector 2 bug?

Former Member
0 Kudos

I've implemented a wrapper class for the SAPClient object which takes care of opening and closing connections in a custom SAPInvoke() function. I've modified the SAP generated files to inherit from the new wrapper class rather than from SAPClient. Everything works as it should so far.

After an indeterminate amount of time, the connector throws a:

Missing R3NAME=... or ASHOST=... in connect_param in RfcOpenEx

error.

Attached is my custom SAPCLIENTWRAPPER class

public class SAPCLIENTWRAPPER : SAPClient

{

private string ConnString;

public SAPCLIENTWRAPPER() : base()

{

ConnString = TDM.SAPConnectionString;

}

public SAPCLIENTWRAPPER(string ConnectionString) : base(ConnectionString)

{

ConnString = ConnectionString;

}

public SAPCLIENTWRAPPER(System.ComponentModel.IContainer container) : base(container) {}

/// <summary>

/// This method hides the existing SAPInvoke methods from the SAP

/// </summary>

/// <param name="method">The method to call</param>

/// <param name="methodParamsIn">The parameters</param>

/// <returns>The SAP response</returns>

protected new object[] SAPInvoke(string method, object[] methodParamsIn)

{

object[] retVal;

try

{

this.Connection = SAPConnectionPool.GetConnectionFromPool(ConnString);

}

catch (Exception ex)

{

ERRORHANDLER.LogError(ex);

ERRORHANDLER.SendEmail(ex, ERRORHANDLER.TDM_SYS_ADMIN);

throw ex;

}

try

{

retVal = base.SAPInvoke(method, methodParamsIn);

}

catch (RfcAbapException ex)

{

// The ABAP Exceptions are handled by the SAP Accessor class up the call stack.

// These typically contain information for an end user, such as correcting

// data of some sort. The TDM wraps these into the return_status SOAP header

// and provides it to the calling application.

this.Connection.Close();

SAPConnectionPool.ReturnConnection(this.Connection);

throw ex;

}

catch (Exception ex)

{

ERRORHANDLER.LogError(ex);

ERRORHANDLER.SendEmail(ex, ERRORHANDLER.TDM_SYS_ADMIN);

this.Connection.Close();

SAPConnectionPool.ReturnConnection(this.Connection);

throw ex;

}

// If there are no errors then we need to Commit the work to SAP and then disconnect

this.CommitWork();

this.Connection.Close();

SAPConnectionPool.ReturnConnection(this.Connection);

return retVal;

}

}

Accepted Solutions (0)

Answers (1)

Answers (1)

reiner_hille-doering
Active Contributor
0 Kudos

I don't know what exactly goes wrong here, but we can clearly not support this approach. You should never change generated code by hand not replace SAP's generation tools with your own. You can freely inherit your classes from generated classes, but not vice versa.

If you think there is something missing in our base class, please let us know. If you had reported this kind of request during beta phase, there would have been also a chance to incorporate them in final product, but now it's clearly too late for 2.0.

Former Member
0 Kudos

I would suggest that the system should allow for this kind of simple tweeking. I simplified the code somewhat for the purposes of the post but there is other custom coding developed such as request queuing & throttling and high performance timing which make best sense within the custom SAPInvoke method.

I don't believe there is anything "technically" wrong in this implementation of inheritance because it works 95% of the time. Here is the simple change I made to the SAP generated code:

/// <summary>

/// Client SAP proxy class

/// </summary>

[WebServiceBinding(Name="dummy.Binding", Namespace="urn:sap-com:document:sap:rfc:functions")]

[Serializable]

public class SAPInquiryFromDat2 : SAPCLIENTWRAPPER

{

.

.

.

results = this.SAPInvoke("Bapi_Inquiry_Createfromdata2",new object[] {

Behave_When_Error,Binary_Relationshiptype,Convert,Inquiry_Header_In,Inquiry_Header_Inx,Int_Number_Assignment,Logic_Switch,Salesdocumentin,Sender,Testrun,Extensionin,Inquiry_Cfgs_Blob,Inquiry_Cfgs_Inst,Inquiry_Cfgs_Part_Of,Inquiry_Cfgs_Ref,Inquiry_Cfgs_Refinst,Inquiry_Cfgs_Value,Inquiry_Cfgs_Vk,Inquiry_Conditions_In,Inquiry_Conditions_Inx,Inquiry_Items_In,Inquiry_Items_Inx,Inquiry_Keys,Inquiry_Partners,Inquiry_Schedules_In,Inquiry_Schedules_Inx,Inquiry_Text,Partneraddresses,Return0 );

.

.

.

}

Former Member
0 Kudos

Hi Craig,

I agree with Reiner on that what you are doing is not the recommended way of using the .NET Connector, although technically nothing can stop you from doing that.

Furthermore, I have some remarks on your code:

- Including the calls for connection pool handling into the SAPInvoke method means that you are forcing the client of your modified proxy class to use the connection pool and to get a new connection from the pool for each call, even in the case that it is not necessary or not suitable to do so. Thinking of the case that the client needs to make more than one calls sequentially over the same proxy, the unnecessary calls to connection pool will result in some performance overhead.

- Similarly, including CommitWork is not always necessary, sometimes is wrong.

- Closing a connection before returning it back to the connection pool for reuse makes the use of connection pool meaningless.

- The base class SAPClient has a "ConnectionString" property, so introducing a new private member for the same purpose is not necessary. I suppose that the error you got is somehow related to this member.

- A pure C# language issue: It is recommended to use

throw

instead of

throw ex

to re-throw an exception caught inside a catch block.

Regards,

Guangwei

Former Member
0 Kudos

Thanks,

The use of the connection pool was a last resort in an attempt to get around the R3NAME issue.

Your observation about the existance of a ConnectionString is noted and I will use that instance instead of the new one, see if that helps. Will get back to you.

On the issue of closing the connections before returning them to the pool. Originally in the 1.x version of the connector this was not necessary. In the implementation of the connection pool in 2.0 if I do not close the connection before returning it, eventually all connections in SAP fill up and the limit of 100 is reached. Don't ask me why this has changed.

reiner_hille-doering
Active Contributor
0 Kudos

Hi Craig,

does this mean that the exactly same version you originally posted did work with 1.x?

In NCo 2.0, if you want to use the connection pool,

your need to do it like this:

this.Connection = SAP.Connector.Connection.GetConnectionFromPool(this.ConnectionString);

base.SAPInvoke(...)

SAP.Connector.Connection.ReturnConnection(this.Connection);

this.Connection = null;

If you turn AutoPooling on, you could save some of the calls, but this version is the safest.

Former Member
0 Kudos

Give it a shot using the implementation I've provided. You will see the error crop up as well as be able to reproduce the connection pooling issue.

Since I do not know about the "innards" of the .net connector I cannot comment on the reason why it fails.

I have resolved the issue by relying on the Destination object. It seems to always work where other methods did not. Very wierd.