I am facing a problem:
when sending soap query from ssrs to wcf , i am getting :
The remote server returned an error: (405) Method Not Allowed.
he HTTP verb POST used to access path '/Service1' is not allowed.
sending soap messages from ssrs to wcf was working perfect but suddenly it breaks.i didnt changed anything in the code.code below.
soap query very simple:
<Query> <Method Name="GetData" Namespace="http://tempuri.org/" /> <SoapAction>http://tempuri.org/IService1/GetData</SoapAction> <ElementPath IgnoreNamespaces="true">*</ElementPath> </Query>
contract:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
// TODO: Add your service operations here
}
implementation:
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
web.config:
<?xml version="1.0"?> <configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" /> </system.web> <system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> </system.serviceModel> <system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
for the web.config:
this is the new web.config when you create wcfapplication it does not require you to include all the stuff and it will generate internally a web.config which you can see in the wcf test client:
<?xml version="1.0" encoding="utf-8"?> <configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:58539/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1" contract="IService1"
name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel> </configuration>
I have a duplex WCF, it work perfect in local host (connect my application to this WCF when it run locally).
Now I tried to hosted it in my IIS (Server 2008 R2 standard), I create a windows account "GOD", and an application poll in IIS using the "GOD" identity.
I can access this WCF from my pc (other than the server) from web browser and see the XML of the contract, (click on the link inside the page displayed)
When try to access from my application I get the exception:
Client is unable to finish the security negotiation within the
configured timeout (00:00:00). The current negotiation leg is 1
(00:00:00).
Again when the WCF run locally my app work OK.
I tried to use the trace but all I successful to see is the exception about the time out.
My app.config is:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\log\Traces.svclog"/>
</listeners>
</source>
</sources>
</system.diagnostics>
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_I_BridgeWCFService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="256" maxStringContentLength="2147483646"
maxArrayLength="2147483646" maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
<reliableSession ordered="true" inactivityTimeout="01:10:00" />
<security mode="Message" />
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://win-jj/_Bridge1/_BridgeWcfService.svc"
binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_I_BridgeWCFService"
contract="_BridgeWcfServiceReference.I_BridgeWCFService"
name="WSDualHttpBinding_I_BridgeWCFService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
</startup>
</configuration>
I also tried to change the identity section above to: <userPrincipalName value="GOD" />, but then I got another exception.
My service config file: web.config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_I_BridgeWCFService" closeTimeout="01:01:00" openTimeout="01:01:00" receiveTimeout="01:10:00" sendTimeout="01:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="256" maxStringContentLength="2147483646" maxArrayLength="2147483646" maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646"/>
<reliableSession ordered="true" inactivityTimeout="01:10:00"/>
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default"/>
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="_BridgeNameSpace.Service1Behavior" name="_BridgeNameSpace._BridgeWCFService">
<endpoint address="" binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_I_BridgeWCFService" contract="_BridgeNameSpace.I_BridgeWCFService">
<identity>
<userPrincipalName value="GOD" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="_BridgeNameSpace.Service1Behavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
</configuration>
I also tried to change the identity section above to: <dns value="localhost"/>, but nothing change
I connect to my service in my application as following:
MyServiceClientProxy Proxy = null;
MyCallbackProxy myCallbackProxy = null;
myCallbackProxy = new MyCallbackProxy();
InstanceContext cntx = new InstanceContext(myCallbackProxy);
Proxy = new MyServiceClientProxy(cntx, "WSDualHttpBinding_I_BridgeWCFService");
Proxy.ClientCredentials.Windows.ClientCredential.UserName = "GOD";
Proxy.ClientCredentials.Windows.ClientCredential.Password = "yy";
try
{
Proxy.Open();
}
catch { return; }
BTW, when tried to change the security to '' got the following exception (wither or not use the ClientCredential.Username&Password as the code above):
The open operation did not complete within the allotted timeout of 00:00:59.1689524. The time allotted to this operation may have been a portion of a longer timeout.
ANY IDEA ?, PLS help!
wsDualHttpBinding tries to open a connection from server to client which will be blocked by firewalls
My advice would be to switch to netTcpBinding - its much simpler for duplex messaging as I blogged here
My client keep complaining that they are receiving Timeout error but I don't see a trace file generated on my side. Can anybody tell me how to fix this?
I already increase the receiveTimeout to 15 minutes (00:15:00). I did this both on WCF service side and on the client side. My service is not a long running process, the client should receive the response in 0 - 2 minutes max.
Not only receiveTimeout and I set the all timeouts to 00:15:00, also I set the serviceThrottling (maxConcurrentCalls,maxConcurrentInstances,maxConcurrentSessions) to 200.
Note: When ever there is an Timeout error, I don't see anything related to that in Tracing.
Here is my config files,
WCF Service Config:
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime executionTimeout="150" maxRequestLength="8192" />
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="MYWS" name="MYDEMO.MYDEMOCLS">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="SecureBinding" name="wsDemo" contract="MYINTERFACES.ICustomer">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" name="wsMex" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://192.168.0.1/Customer/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MYWS">
<serviceThrottling maxConcurrentCalls="200" maxConcurrentInstances="200" maxConcurrentSessions="200" />
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="SecureBinding" maxBufferPoolSize="2147483647" closeTimeout="00:15:00" openTimeout="00:15:00" receiveTimeout="00:15:00" sendTimeout="00:15:00" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Message">
<transport clientCredentialType="Windows" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
Client Config:
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime executionTimeout="150" />
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsDemo" closeTimeout="00:15:00" openTimeout="00:15:00" receiveTimeout="00:15:00" sendTimeout="00:15:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<reliableSession ordered="true" inactivityTimeout="00:15:00" enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://192.168.0.1/DEMOSVCS/Customer.svc" binding="wsHttpBinding" bindingConfiguration="wsDemo" contract="PROJ.IFACE" name="wsDemo">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Here is a client code
DemoClient client = new DemoClient("wsDemo");
DemoResponse DemoResponse = new DemoResponse();
try
{
DemoResponse = client.CreateProduct(product);
client.Close();
return DemoResponse;
}
catch (Exception ex)
{
try
{
if (client.State == CommunicationState.Faulted)
client.Abort();
else
client.Close();
throw ex;
}
catch
{
client.Abort();
throw ex;
}
}
Thanks
Timeout errors are hard to diagnose. We've had issues that were completely related to WAN latency while passing large datasets across the wire.
However, if you find that once the timeout occurs, no further calls to the web service can be made, I would look into this WCF 3.5 & 4.0 Hotfix
I've been experimenting with the BizTalk Adapter Pack, specifically with the SAP stuff.
I'm able to connect to SAP and run an RFC from a client app (e.g. Console, Windows, Web site) using the SAP binding directly, no problem at all. I've also got it all working in BizTalk Server 2009 using orchestration, send port, receive port, etc.
However, I want to expose SAP functionality to internal users as a standard HTTP web service, without requiring them to have the SAP binding stuff installed on their PC.
So, I created a "WCF Adapter Service" project in Visual Studio, and followed the wizard. I then created a standard web app for the client end, and added a proxy using "Add service reference". It all worked OK, in that it found the service and added the proxy code, but when I try to invoke the service I get the error SapErrorMessage=Incomplete logon data.
What I don't know how to do is pass SAP credentials from my client web app to the Basic HTTP service and then on the the SAP binding. If I put the SAP credentials into the SAP connection string it all works OK, but this is not very secure and also I want to supply the credentials from the client (i.e. ask the user to provide their SAP credentials).
In some examples I've seen, e.g. http://msdn.microsoft.com/en-us/library/dd788594(BTS.10).aspx, the SAP credentials are passed in HTTP headers. Unfortunately, all the examples I've seen of this go on to show how to invoke the service from SharePoint, where there's a dialog window for setting the headers. I'm not using SharePoint! I've tried adding a "" section to my client endpoint configuration, but this didn't seem to work.
So, what is the recommended way to pass SAP credentials to a Basic HTTP web service created via the "WCF Adapter Service" wizard?
For information, this is the relevant part of the web.config on my client web app:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="RfcEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://xxxxxx/SAP_Service_1/Rfc.svc" binding="basicHttpBinding" bindingConfiguration="RfcEndpoint" contract="ServiceReference1.Rfc" name="RfcEndpoint">
<headers>
<SAP_Username>username</SAP_Username>
<SAP_Password>password</SAP_Password>
</headers>
</endpoint>
</client>
</system.serviceModel>
And this is the web.config generated by the WCF Adapter Service project wizard:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="customServiceBehavior" name="RfcClient">
<endpoint address="" behaviorConfiguration="customEndpointBehavior" binding="basicHttpBinding" bindingConfiguration="RfcClientBindingConfig" name="RfcEndpoint" contract="Rfc"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="customEndpointBehavior">
<endpointBehavior usernameHttpHeader="SAP_Username" passwordHttpHeader="SAP_Password" adapterSecurityBridgeType="HTTPUsernamePassword"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="customServiceBehavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials type="Microsoft.ServiceModel.Channels.AdapterServiceCredentials, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<serviceAuthorization serviceAuthorizationManagerType="Microsoft.ServiceModel.Channels.AdapterServiceAuthorizationManager, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<authorizationPolicies>
<add policyType="Microsoft.ServiceModel.Channels.AdapterAuthorizationPolicy, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="endpointBehavior" type="Microsoft.ServiceModel.Channels.AdapterEndpointBehavior, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</behaviorExtensions>
</extensions>
<bindings>
<basicHttpBinding>
<binding name="RfcClientBindingConfig">
<security mode="None">
<transport clientCredentialType="None"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
<sapBinding>
<binding name="SAPBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" enableBizTalkCompatibilityMode="false" receiveIdocFormat="Typed" enableSafeTyping="false" generateFlatFileCompatibleIdocSchema="true" maxConnectionsPerSystem="50" enableConnectionPooling="true" idleConnectionTimeout="00:15:00" flatFileSegmentIndicator="SegmentDefinition" enablePerformanceCounters="false" autoConfirmSentIdocs="false" acceptCredentialsInUri="true" padReceivedIdocWithSpaces="false" sncLibrary="" sncPartnerName="" rfcAllowStartProgram="">
<dataTypesBehavior datsMinToDateTime="NULL" datsMaxToDateTime="NULL" invalidDatsToDateTime="ERROR" emptyDatsToDateTime="0001-01-01T00:00:00" emptyTimsToDateTime="0001-01-01T00:00:00" dateTimeMaxToDats="99991231" dateTimeMinToDats="00010101" timsMaxToDateTime="NULL" invalidTimsToDateTime="ERROR" dateTimeMaxToTims="235959" dateTimeMinToTims="000000" invalidNumcToInt="0" emptyNumcToInt="0" dateTimeNullToDats="SKIP" dateTimeNullToTims="SKIP"/>
</binding>
</sapBinding>
</bindings>
<client>
<endpoint address="sap://CLIENT=300;LANG=EN;#a/XXXXXX/00?RfcSdkTrace=False&AbapDebug=False" binding="sapBinding" bindingConfiguration="SAPBinding" contract="Rfc" name="SAPBinding_Rfc"/>
</client>
</system.serviceModel>
</configuration>
I'm a bit new to WCF, so any help or pointers gratefully received!
Thanks
Doug
Got it working at last!
First, I needed to get the SAP username and password added as HTTP headers in the request. I tried the simple solution of editing the config file first, as some have suggested:
<endpoint ....
<headers>
<HeaderName1>Header Value 1</HeaderName1>
<HeaderName2>Header Value 2</HeaderName2>
</headers>
</endpoint>
But this does not add HTTP headers, or at least I wasn't able to get it to work.
I looked at the excellent article here http://ericphan.info/blog/2010/6/3/adding-custom-http-header-to-all-wcf-requests.html, which explains how to user a MessageInspector to add HTTP headers to the outgoing request. It works brilliantly, but headers are defined in the config file. I needed a way to set the headers in code. Perhaps there would be a way of adapting this code, but I'm not that clever!
Instead, I found some other examples and distilled it down to this:
using (RfcClient client = new RfcClient("RfcEndpoint"))
{
try
{
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
HttpRequestMessageProperty httpRequestProperty;
if (OperationContext.Current.OutgoingMessageProperties.ContainsKey(HttpRequestMessageProperty.Name))
{
httpRequestProperty = (HttpRequestMessageProperty)OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name];
}
else
{
httpRequestProperty = new HttpRequestMessageProperty();
}
httpRequestProperty.Headers.Add("SAP_Username", "dXNlcm5hbWU=");
httpRequestProperty.Headers.Add("SAP_Password", "cGFzc3dvcmQ=");
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
ret = client.BAPI_SALESORDER_GETLIST(cust, null, null, null, po, null, salesOrg, transGroup, ref orders);
GridView1.DataSource = orders;
GridView1.DataBind();
}
client.Close();
Label1.Text = DateTime.Now.ToString();
}
catch (CommunicationException ex)
{
StringBuilder sb = new StringBuilder();
sb.Append(ex.Message);
if (ex.InnerException != null) sb.Append("~" + ex.InnerException.Message);
Label1.Text = sb.ToString();
client.Abort();
}
catch (TimeoutException ex)
{
Label1.Text = ex.Message;
client.Abort();
}
catch (Exception ex)
{
Label1.Text = ex.Message;
client.Abort();
throw;
}
}
For completeness, this is the web.config file for the service:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="customServiceBehavior" name="RfcClient">
<endpoint address="" behaviorConfiguration="customEndpointBehavior"
binding="basicHttpBinding" bindingConfiguration="RfcClientBindingConfig"
name="RfcEndpoint" contract="Rfc" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="customEndpointBehavior">
<endpointBehavior usernameHttpHeader="SAP_Username" passwordHttpHeader="SAP_Password"
adapterSecurityBridgeType="HTTPUsernamePassword" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="customServiceBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials type="Microsoft.ServiceModel.Channels.AdapterServiceCredentials, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<serviceCertificate findValue="servername" storeLocation="LocalMachine"
storeName="My" x509FindType="FindBySubjectName" />
</serviceCredentials>
<serviceAuthorization serviceAuthorizationManagerType="Microsoft.ServiceModel.Channels.AdapterServiceAuthorizationManager, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<authorizationPolicies>
<add policyType="Microsoft.ServiceModel.Channels.AdapterAuthorizationPolicy, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="endpointBehavior" type="Microsoft.ServiceModel.Channels.AdapterEndpointBehavior, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</behaviorExtensions>
</extensions>
<bindings>
<basicHttpBinding>
<binding name="RfcClientBindingConfig">
<security mode="Transport">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
<sapBinding>
<binding name="SAPBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" enableBizTalkCompatibilityMode="false"
receiveIdocFormat="Typed" enableSafeTyping="false" generateFlatFileCompatibleIdocSchema="true"
maxConnectionsPerSystem="50" enableConnectionPooling="true"
idleConnectionTimeout="00:15:00" flatFileSegmentIndicator="SegmentDefinition"
enablePerformanceCounters="false" autoConfirmSentIdocs="false"
acceptCredentialsInUri="false" padReceivedIdocWithSpaces="false"
sncLibrary="" sncPartnerName="" rfcAllowStartProgram="">
<dataTypesBehavior datsMinToDateTime="NULL" datsMaxToDateTime="NULL"
invalidDatsToDateTime="ERROR" emptyDatsToDateTime="0001-01-01T00:00:00"
emptyTimsToDateTime="0001-01-01T00:00:00" dateTimeMaxToDats="99991231"
dateTimeMinToDats="00010101" timsMaxToDateTime="NULL" invalidTimsToDateTime="ERROR"
dateTimeMaxToTims="235959" dateTimeMinToTims="000000" invalidNumcToInt="0"
emptyNumcToInt="0" dateTimeNullToDats="SKIP" dateTimeNullToTims="SKIP" />
</binding>
</sapBinding>
</bindings>
<client>
<endpoint address="sap://CLIENT=300;LANG=EN;#a/XXXXXX/00?RfcSdkTrace=False&AbapDebug=False"
binding="sapBinding" bindingConfiguration="SAPBinding" contract="Rfc"
name="SAPBinding_Rfc" />
</client>
</system.serviceModel>
</configuration>
And for the web client app:
<system.serviceModel>
<behaviors />
<extensions />
<bindings>
<basicHttpBinding>
<binding name="RfcEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://servername/SAP_Service_HTTP/Rfc.svc"
binding="basicHttpBinding" bindingConfiguration="RfcEndpoint"
contract="ServiceReference1.Rfc" name="RfcEndpoint" >
</endpoint>>
</client>
</system.serviceModel>
This uses transport security (SSL) to protect the headers, but it works without also.
Note the final twist to the exercise. The HTTP header values needed to be Base64 encoded! I've no idea why, but it must be that the SAP adapter is expecting them to be.
Doug
Found an even easier solution!
WCF is happy to send the Username / Password credentials in the message body providing the message is protected. Don't know why I didn't think of it before, but setting security like this:
<security mode="TransportWithMessageCredential">
means that Rohit's suggestion now works.
So, the service web.config expects the credentials in the message and uses transport security:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="customServiceBehavior" name="RfcClient">
<endpoint address="" behaviorConfiguration="customEndpointBehavior"
binding="basicHttpBinding" bindingConfiguration="RfcClientBindingConfig"
name="RfcEndpoint" contract="Rfc" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="customEndpointBehavior">
<endpointBehavior adapterSecurityBridgeType="ClientCredentialUsernamePassword" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="customServiceBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials type="Microsoft.ServiceModel.Channels.AdapterServiceCredentials, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<serviceCertificate findValue="servername" storeLocation="LocalMachine"
storeName="My" x509FindType="FindBySubjectName" />
</serviceCredentials>
<serviceAuthorization serviceAuthorizationManagerType="Microsoft.ServiceModel.Channels.AdapterServiceAuthorizationManager, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<authorizationPolicies>
<add policyType="Microsoft.ServiceModel.Channels.AdapterAuthorizationPolicy, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="endpointBehavior" type="Microsoft.ServiceModel.Channels.AdapterEndpointBehavior, Microsoft.ServiceModel.Channels, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</behaviorExtensions>
</extensions>
<bindings>
<basicHttpBinding>
<binding name="RfcClientBindingConfig">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
<sapBinding>
<binding name="SAPBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" enableBizTalkCompatibilityMode="false"
receiveIdocFormat="Typed" enableSafeTyping="false" generateFlatFileCompatibleIdocSchema="true"
maxConnectionsPerSystem="50" enableConnectionPooling="true"
idleConnectionTimeout="00:15:00" flatFileSegmentIndicator="SegmentDefinition"
enablePerformanceCounters="false" autoConfirmSentIdocs="false"
acceptCredentialsInUri="false" padReceivedIdocWithSpaces="false"
sncLibrary="" sncPartnerName="" rfcAllowStartProgram="">
<dataTypesBehavior datsMinToDateTime="NULL" datsMaxToDateTime="NULL"
invalidDatsToDateTime="ERROR" emptyDatsToDateTime="0001-01-01T00:00:00"
emptyTimsToDateTime="0001-01-01T00:00:00" dateTimeMaxToDats="99991231"
dateTimeMinToDats="00010101" timsMaxToDateTime="NULL" invalidTimsToDateTime="ERROR"
dateTimeMaxToTims="235959" dateTimeMinToTims="000000" invalidNumcToInt="0"
emptyNumcToInt="0" dateTimeNullToDats="SKIP" dateTimeNullToTims="SKIP" />
</binding>
</sapBinding>
</bindings>
<client>
<endpoint address="sap://CLIENT=300;LANG=EN;#a/XXXXXX/00?RfcSdkTrace=False&AbapDebug=False"
binding="sapBinding" bindingConfiguration="SAPBinding" contract="Rfc"
name="SAPBinding_Rfc" />
</client>
</system.serviceModel>
</configuration>
And the client web.config is similarly configured:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="RfcEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://servername/SAP_Service_BASIC/Rfc.svc" binding="basicHttpBinding" bindingConfiguration="RfcEndpoint" contract="ServiceReference1.Rfc" name="RfcEndpoint"/>
</client>
</system.serviceModel>
Then the client code is simply:
string cust = "12345";
string po = "12345";
string salesOrg = "1234";
string transGroup = "0";
BAPIORDERS[] orders = new BAPIORDERS[0];
BAPIRETURN ret = new BAPIRETURN();
using (RfcClient client = new RfcClient("RfcEndpoint"))
{
client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "password";
try
{
ret = client.BAPI_SALESORDER_GETLIST(cust, null, null, null, po, null, salesOrg, transGroup, ref orders);
GridView1.DataSource = orders;
GridView1.DataBind();
Label1.Text = DateTime.Now.ToString();
client.Close();
}
catch (CommunicationException ex)
{
StringBuilder sb = new StringBuilder();
sb.Append(ex.Message);
if (ex.InnerException != null) sb.Append("~" + ex.InnerException.Message);
Label1.Text = sb.ToString();
client.Abort();
}
catch (TimeoutException ex)
{
Label1.Text = ex.Message;
client.Abort();
}
catch (Exception ex)
{
Label1.Text = ex.Message;
client.Abort();
throw;
}
}
Perfect!
Doesn't adding the following to the client app work for you?
RfcClient client = new RfcClient();
client.ClientCredentials.UserName.UserName = "myusername";
client.ClientCredentials.UserName.Password = "mypassword";
I have problem with WCF service. When I am downloading 2 files everything works fine ( less than 1 minute), but when I'm trying downloading more than 3 files there is going something bad . I'm waiting and waiting and nothing :/ Every file has about 1 MB.
Dictionary<FileIdentifier, Stream> data = new Dictionary<FileIdentifier, Stream>();
foreach (string path in paths)
{
using (var client = new ServiceClient())
{
var stream = client.GetFile(path);
data[fileIdentifier] = stream;
}
}
Method at WCF Service:
public Stream GetFile(string path)
{
FileStream fs = new FileStream(stream, FileMode.Open);
fs.Close();
return fs;
}
config of WCF service:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<client />
<bindings>
<basicHttpBinding>
<binding name="basicHttpBindingConfiguration" closeTimeout="00:10:00"
openTimeout="00:15:00" receiveTimeout="00:15:00" sendTimeout="00:15:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2097152000" maxBufferPoolSize="524288000" maxReceivedMessageSize="2097152000"
messageEncoding="Text" textEncoding="utf-8" transferMode="Streamed"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="524288000"
maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="FileServer.Service" behaviorConfiguration="FileServer.Service1Behavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8731/Design_Time_Addresses/Server.FileServer/Service/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" contract="FileServer.IService" binding="basicHttpBinding" bindingConfiguration="basicHttpBindingConfiguration">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="FileServer.Service1Behavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True" />
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true" />
<httpRuntime maxRequestLength="2097151" executionTimeout="1000" />
<customErrors mode="RemoteOnly" />
</system.web>
<system.webServer>
<directoryBrowse enabled="false" />
</system.webServer>
</configuration>
You should not close the stream on the service side.
Here is how you would do:
Open stream on service
Return stream to client
Read the stream on the client
Close the stream on the client
WCF will take care of closing the service stream for you
Instead of returning a stream, read the stream into a byte array and then return the byte array.