when I try to upload file size is more than 47Kb it will display the below error
Error : The remote server returned an unexpected response: (400) Bad Request.
wcf service is hosted in the iis 6 server
Please Help me to rectify this issue
Actual coding as mentioned below.
Regards
Wiraj
web.config codeing ........................................
<?xml version="1.0"?>
<!--
Note: As an alternative to hand editing this file you can use the
web admin tool to configure settings for your application. Use
the Website->Asp.Net Configuration option in Visual Studio.
A full list of settings and comments can be found in
machine.config.comments usually located in
\Windows\Microsoft.Net\Framework\v2.x\Config
-->
<configuration>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483648" />
</requestFiltering>
</security>
</system.webServer>
<appSettings/>
<connectionStrings/>
<system.web>
<!--
Set compilation debug="true" to insert debugging
symbols into the compiled page. Because this
affects performance, set this value to true only
during development.
-->
<compilation debug="true" targetFramework="4.0">
</compilation>
<!--
The <authentication> section enables configuration
of the security authentication mode used by
ASP.NET to identify an incoming user.
-->
<authentication mode="Windows"/>
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
during the execution of a request. Specifically,
it enables developers to configure html error pages
to be displayed in place of a error stack trace.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
<!--<httpRuntime maxRequestLength="920971500" useFullyQualifiedRedirectUrl="true"
executionTimeout="914400" />-->
<httpRuntime
executionTimeout="90"
maxRequestLength="9994096"
useFullyQualifiedRedirectUrl="false"
minFreeThreads="8"
minLocalRequestFreeThreads="4"
appRequestQueueLimit="100"
enableVersionHeader="true"
/>
<pages controlRenderingCompatibilityVersion="4.5" clientIDMode="AutoID"/>
</system.web>
<!--
The system.webServer section is required for running ASP.NET AJAX under Internet
Information Services 7.0. It is not necessary for previous version of IIS.
-->
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ITransferService" closeTimeout="10:01:00"
openTimeout="10:01:00" receiveTimeout="10:10:00" sendTimeout="10:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Mtom" textEncoding="utf-8" transferMode="StreamedRequest"
useDefaultWebProxy="true">
<readerQuotas maxDepth="128" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
<binding name="BasicHttpBinding_ITransferService1" closeTimeout="10:01:00"
openTimeout="10:01:00" receiveTimeout="10:10:00" sendTimeout="10:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" transferMode="StreamedRequest"
useDefaultWebProxy="true">
<readerQuotas maxDepth="128" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://midoc-server-bk.milnetfinity.com/test1/wcfservice.TransferService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITransferService"
contract="wcfservice.ITransferService" name="BasicHttpBinding_ITransferService" />
<endpoint address="http://midoc-server-bk.milnetfinity.com/test1/wcfservice.TransferService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITransferService1"
contract="ITransferService.ITransferService" name="BasicHttpBinding_ITransferService1" />
</client>
<protocolMapping>
<add binding="basicHttpBinding" scheme="http" bindingConfiguration="BasicHttpBinding_ITransferService"/>
</protocolMapping>
</system.serviceModel>
<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>
</configuration>
app.config codes -----------------------------------------------------
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483648" />
</requestFiltering>
</security>
</system.webServer>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<bindings>
<!--<netTcpBinding>
<binding name="netTcpBinding_ITransferService" maxReceivedMessageSize="10485760" transferMode="Streamed" messageEncoding="Mtom"/>
</netTcpBinding>-->
<basicHttpBinding>
<!--<binding name="BasicHttpBinding_ITransferService" maxReceivedMessageSize="910485760" sendTimeout="04:10:00" messageEncoding="Mtom" transferMode="StreamedRequest" />-->
<binding name="BasicHttpBinding_ITransferService" closeTimeout="10:01:00"
openTimeout="10:01:00" receiveTimeout="10:10:00" sendTimeout="10:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Mtom" textEncoding="utf-8" transferMode="StreamedRequest"
useDefaultWebProxy="true">
<readerQuotas maxDepth="128" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<!--<client >
</client >-->
<services>
<!--<service name="wcfservice.Service1">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/wcfservice/Service1/" />
</baseAddresses>
</host>
--><!-- Service Endpoints --><!--
--><!-- Unless fully qualified, address is relative to base address supplied above --><!--
<endpoint address="" binding="basicHttpBinding" contract="wcfservice.IService1">
--><!--
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>-->
<service name="wcfservice.TransferService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/wcfservice/TransferService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="basicHttpBinding" contract="wcfservice.ITransferService" >
<!--
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>
<!-- 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>
</system.serviceModel>
</configuration>
Transfer service.cs codes ----------------------------------------'
public messageout UploadFile(RemoteFileInfo request)
{
messageout strerror = new messageout() ;
strerror.message = "OK";
try
{
strerror.message = "OK1";
FileStream targetStream = null;
Stream sourceStream = request.FileByteStream;
string uploadFolder = #"c:\Uploadfiles\";
string filePath = Path.Combine(uploadFolder, request.FileName);
using (targetStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
//read from the input stream in 6K chunks
//and save to output stream
strerror.message = "OK2";
const int bufferLen = 65000;
byte[] buffer = new byte[bufferLen];
int count = 0;
while ((count = sourceStream.Read(buffer, 0, bufferLen)) > 0)
{
targetStream.Write(buffer, 0, count);
strerror.message = "OK3";
}
targetStream.Close();
sourceStream.Close();
}
strerror.message = "OK4";
}
catch (Exception ex)
{
strerror.message = ex.ToString();
}
return strerror;
}
}
}
ITransferservice.cs --------------------------
[ServiceContract]
public interface ITransferService
{
[OperationContract]
RemoteFileInfo DownloadFile(DownloadRequest request);
[OperationContract]
messageout UploadFile(RemoteFileInfo request);
}
[MessageContract]
public class DownloadRequest
{
[MessageBodyMember]
public string FileName;
}
[MessageContract]
public class RemoteFileInfo : IDisposable
{
[MessageHeader(MustUnderstand = true)]
public string FileName;
[MessageHeader(MustUnderstand = true)]
public long Length;
[MessageBodyMember(Order = 1)]
public System.IO.Stream FileByteStream;
public void Dispose()
{
if (FileByteStream != null)
{
FileByteStream.Close();
FileByteStream = null;
}
}
}
[MessageContract]
public class messageout : IDisposable
{
[MessageHeader(MustUnderstand = true)]
public string message;
public void Dispose()
{
message = "";
}
}
I have one WCF rest service operation contract which internally calls another service.
While making a call to another service, It adds certificate and makes a call to the other service.
My operation contract is like below
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/report/videodata/{component}/{count}")]
ServiceResponse CallcomponentHandler(string component, string count);
and my implementation is like below
public ServiceResponse CallcomponentHandler(string component, string count)
{
//Making HTTP Get Request to another service
return utility.GetResponse(Url);
}
But when I am trying to consume this Operation from internet explorer, This is getting called multiple times.
Please note the other service has async method.
I tried adding maxReceivedMessageSize,maxStringContentLength in web.config file but still not able to resolve this.
Below is my web.config file.
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<httpRuntime/>
</system.web>
<system.serviceModel>
<services>
<service name="Video.GetDetails" behaviorConfiguration="MyServiceBehavior">
<endpoint name="rest" address="" binding="webHttpBinding" contract="Video.IService1" behaviorConfiguration="restBehavior"/>
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="StreamedRequestWebBinding"
bypassProxyOnLocal="true"
useDefaultWebProxy="false"
hostNameComparisonMode="WeakWildcard"
sendTimeout="10:15:00"
openTimeout="10:15:00"
receiveTimeout="10:15:00"
maxReceivedMessageSize="9223372036854775807"
maxBufferPoolSize="9223372036854775807"
maxBufferSize="2147483647"
transferMode="StreamedRequest" >
<readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" />
</binding>
</webHttpBinding>
<basicHttpBinding>
<binding name="Binding1" closeTimeout="04:01:00" openTimeout="04:01:00" receiveTimeout="04:10:00" sendTimeout="04:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="1073741824" maxBufferPoolSize="1073741824" maxReceivedMessageSize="1073741824" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="1073741824" maxStringContentLength="1073741824" maxArrayLength="1073741824" maxBytesPerRead="1073741824" maxNameTableCharCount="1073741824"/>
</binding>
<!-- For Cyber Source bindings-->
<binding name="ITransactionProcessor" closeTimeout="04:01:00" openTimeout="04:01:00" receiveTimeout="04:10:00" sendTimeout="04:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="1073741824" maxBufferPoolSize="1073741824" maxReceivedMessageSize="1073741824" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="1073741824" maxStringContentLength="1073741824" maxArrayLength="1073741824" maxBytesPerRead="1073741824" maxNameTableCharCount="1073741824"/>
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
<!--Cyber Source bindings ends here-->
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="restBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Please help me on this.
I'm coding a webservice at the moment and the usage is as followed:
I got a frontend as dll, means I got a library project with a wpf window.
That library shall be called from other programs.
The Backend WCF-service is hosted on an external IIS and the frontend calls the webservice methods via a controller.dll where the wcf service is referenced.
I've read several post here and from google already about the same issue...but I can't get it fixed.
I got a dummy windows forms, which calls the frontend.dll.
That project got that app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://Hidden-ip/TicketReportService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService"
contract="ServiceReference.IService" name="BasicHttpBinding_IService" />
</client>
</system.serviceModel>
</configuration>
I'm aware, that each program that wants to call my frontend.dll would need to put the binding/endpoint configurations in their own app.config if I proceed like i described here.
Thats just an example though, later I'm doing the binding/endpoint config programaticallly in my controller.dll, so I dont need configuration files...but thats another topic.
If I call my method, that uploads the file via the webservice I got two scenarios:
if file > 16kb and <~30kb I get a protoccol exception, thats telling me that the "MaxArrayLength" (16384) was exceeded.
if I'm trying to upload a file with about 60kb I get a protocoll exception as well, but just with the information: "remoteserver returned unexpected answer.(400) bad request.
If you look in the app.config, the maxarray length is setted to int32.max value.
Also if I check the binding of the object that calls the method, its telling me that the maxarraylength was taken from the app.config....but I'm still getting the error message.
What did I wrong here?
Thats a client side issue, i'snt it?
In my service web.config on the IIS I got following:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="BackendService.Behavior" name="MyNamespaye.Service">
<endpoint address="" binding="basicHttpBinding" contract="MyNamespaye.IService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="BackendService.Behavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<connectionStrings>
<add name="CustomerEntities" connectionString="metadata=res://*/CustomerModel.csdl|res://*/CustomerModel.ssdl|res://*/CustomerModel.msl;provider=MySql.Data.MySqlClient;provider connection string="server=hidden-ip;User Id=root;database=fromcloud;password=hidden-pw;Persist Security Info=True"" providerName="System.Data.EntityClient" />
<add name="DocumentEntities" connectionString="metadata=res://*/DocumentModel.csdl|res://*/DocumentModel.ssdl|res://*/DocumentModel.msl;provider=MySql.Data.MySqlClient;provider connection string="server=hidden-ip;User Id=root;password=hidden-pw;Persist Security Info=True;database=fromcloud"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
...fixed it myself. Didn't know that it has to be configured on the service side as well!
new web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService" closeTimeout="00:10:00"
openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="BackendService.Behavior" name="MyNamespace.Service">
<host>
<baseAddresses>
<add baseAddress="http://localhost:1111/"/>
</baseAddresses>
</host>
<endpoint address="http://MyIP/TicketReportService.svc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService"
contract="Mynamespace.BackendService.IService"
name="ticketReport_endpoint" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="BackendService.Behavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<connectionStrings>
<add name="CustomerEntities" connectionString="metadata=res://*/CustomerModel.csdl|res://*/CustomerModel.ssdl|res://*/CustomerModel.msl;provider=MySql.Data.MySqlClient;provider connection string="server=fwefwef;User Id=root;database=fromcloud;password=fwefw;Persist Security Info=True"" providerName="System.Data.EntityClient" />
<add name="DocumentEntities" connectionString="metadata=res://*/DocumentModel.csdl|res://*/DocumentModel.ssdl|res://*/DocumentModel.msl;provider=MySql.Data.MySqlClient;provider connection string="server=fwefwef;User Id=root;password=fwef;Persist Security Info=True;database=fromcloud"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
...just did another google search and found a proper exampel of a web.config.
Thanks anyway for anyone that read the OP.
I'm using the following code successfully with HTTP but I would like to use SSL. When I change the endpoint address to https and modify the security mode to Transport in the web.config I get the error : "The provided URI scheme 'https' is invalid; expected 'http'."
This is a VB.net test form.
Imports WindowsApplication1.WCFService
Imports System.ServiceModel
Public Class Form1
Private WCFConnection As Service1Client 'Class reference from the ServiceReference
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
If WCFConnection Is Nothing Then
WCFConnection = New Service1Client(New System.ServiceModel.BasicHttpBinding(), New EndpointAddress("https://www.mysite.com/Service1.svc?wsdl"))
End If
Dim NParray As String = WCFConnection.GetNP("8")
TextBox1.Text = NParray
End Sub
End Class
Then here is the web.config
<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="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://www.mysite.com/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1" contract="WCFService.IService1"
name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
I've figured this out.
Here is the web.config that I'm using
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServBehave">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServBehave" name="FILE_WCF.Srv">
<endpoint address="" binding="customBinding" bindingConfiguration="custBind"
contract="FILE_WCF.ISrv" />
</service>
</services>
<bindings>
<customBinding>
<binding name="custBind">
<binaryMessageEncoding></binaryMessageEncoding>
<httpsTransport></httpsTransport>
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Here is the SVC file
<%# ServiceHost Language="VB" Debug="true" Service="FILE_WCF.Srv" CodeBehind="FILE.svc.vb" %>
Instead of
security mode="None"
use
security mode="None"
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";