WCF restful service, server did not provide a meaningful reply - vb.net

I am creating a restful service using WCF, I keep getting the error:
The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
It is a time clock application, which takes in the username and the current time and stores it in a database for logging in/out.
I am new to the REST world can anyone help me?
My service interface:
ServiceContract(Namespace:="WCFRESTService")> _
Public Interface IService1
<OperationContract()> _
<WebInvoke(UriTemplate:="/login", Method:="PUT")> _
Function InsertUserDetails(ByVal username As String, ByVal time As DateTime) As String
End Interface
Service code:
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Required)> _
<ServiceBehavior(Namespace:="WCFRESTService")> _
Public Class Service1
Implements IService1
Private con As New SqlConnection("Data Source=TE-LAPTOP-001\SQL2008R2;Initial Catalog=timeClock;Integrated Security=True")
Public Function InsertUserDetails(ByVal username As String, ByVal time As DateTime) As String Implements IService1.InsertUserDetails
Dim strMessage As String = String.Empty
Dim errorMessage As String = String.Empty
Dim numcount As Integer = 0
numcount = getusercount(username)
If (numcount = 0) Then
Try
con.Open()
Dim cmd As New SqlCommand("spInsertLog", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#username", username)
cmd.Parameters.AddWithValue("#timein", time)
cmd.ExecuteNonQuery()
Catch ex As Exception
errorMessage = ex.ToString
Finally
con.Close()
End Try
strMessage = "You have Signed In at: " + time
ElseIf (numcount = 1) Then
strMessage = "Error: You need to SignOut before you can SignIn"
End If
Return errorMessage + strMessage
End Function
Public Function getusercount(ByVal username As String) As Integer
Dim count As Int32 = 0
Try
con.Open()
Dim cmd As New SqlCommand("spgetcount", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#username", username)
count = Convert.ToInt32(cmd.ExecuteScalar())
Catch ex As Exception
Finally
con.Close()
End Try
Return count
End Function
End Class
My client code
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim objervice As New ServiceReference1.Service1Client()
Dim result As String = objervice.InsertUserDetails("User1", DateTime.Now)
MsgBox(result)
End Sub
Service webconfig:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service name="WcfRESTService1.Service1" behaviorConfiguration="WcfRESTService1.Service1Behavior">
<!-- Service Endpoints -->
<endpoint address="http://localhost:62131/Service1.svc" binding="webHttpBinding" contract="WcfRESTService1.IService1" behaviorConfiguration="web">
<!--
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>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WcfRESTService1.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="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Client config:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="WebHttpBinding_IService1">
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap12" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpTransport/>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:62131/Service1.svc" binding="customBinding" bindingConfiguration="WebHttpBinding_IService1"
contract="ServiceReference1.IService1" name="WebHttpBinding_IService1" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="test">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>

You don't need REST here (for such kind of client).
But if you want - try use stream for WebGet-responding from from REST method:
[OperationContract, WebGet(UriTemplate = "/SendMessage?login={login}&password={password}&phoneNum={phoneNum}&message={message}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
System.IO.Stream SendMessage(string login, string password, string phoneNum, string message, TimeSpan timeout);
//..
public Stream SendMessage(string login, string password, string phoneNum, string message, TimeSpan timeout)
{
//..
return new MemoryStream(Encoding.Default.GetBytes(jsonString));
}

Related

WCF REST WebInvoke POST returns bad response

May anybody help me I am tired of doing all the thing, but service returns bad return if string length exceeds more than 10000 characters.
Thanks.
This is my .svc file:
<%# ServiceHost Language="VB" Debug="true" Service="BPMMobile"
CodeBehind="~/App_Code/BPMMobile.svc.vb" Factory="MyServiceHostFactory" %>
My contract:
<OperationContract()> _
<WebInvoke(UriTemplate:="/SaveData?
Data={Data}", BodyStyle:=WebMessageBodyStyle.Bare, Method:="POST", ResponseFormat:=WebMessageFormat.Xml)> _
Function SaveData(Data As String) As String
Here is my web.config file:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="MobileBinding" maxReceivedMessageSize="5242880">
<readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="BPMMobile">
<endpoint
behaviorConfiguration="webHttp"
binding="webHttpBinding"
bindingConfiguration="MobileBinding"
contract="IBPMMobile" />
</service>
<service name="DMSService">
<endpoint
behaviorConfiguration="webHttp"
binding="webHttpBinding"
contract="IDMSService" />
</service>
<service name="ImportMaster">
<endpoint
behaviorConfiguration="webHttp"
binding="webHttpBinding"
contract="IImportMaster" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>`
Here is my Custom service host
Public Class MyServiceHost
Inherits WebServiceHost
Public Sub New()
End Sub
Public Sub New(singletonInstance As Object, ParamArray baseAddresses As Uri())
MyBase.New(singletonInstance, baseAddresses)
End Sub
Public Sub New(serviceType As Type, ParamArray baseAddresses As Uri())
MyBase.New(serviceType, baseAddresses)
End Sub
Protected Overrides Sub OnOpening()
MyBase.OnOpening()
If MyBase.Description IsNot Nothing Then
For Each endpoint In MyBase.Description.Endpoints
Dim transport = endpoint.Binding.CreateBindingElements().Find(Of TransportBindingElement)()
If transport IsNot Nothing Then
transport.MaxReceivedMessageSize = 5242880
transport.MaxBufferPoolSize = 5242880
transport.MaxBufferPoolSize = 5242880
End If
Next
End If
End Sub
End Class
Class MyWebServiceHostFactory
Inherits WebServiceHostFactory
Protected Overrides Function CreateServiceHost(serviceType As Type, baseAddresses As Uri()) As ServiceHost
Return New MyServiceHost(serviceType, baseAddresses)
End Function
End Class
Public NotInheritable Class MyServiceHostFactory
Inherits System.ServiceModel.Activation.ServiceHostFactory
Public Overrides Function CreateServiceHost(constructorString As String, baseAddresses As Uri()) As System.ServiceModel.ServiceHostBase
Return MyBase.CreateServiceHost(constructorString, baseAddresses)
End Function
Protected Overrides Function CreateServiceHost(serviceType As Type, baseAddresses As Uri()) As System.ServiceModel.ServiceHost
Return New MyServiceHost(serviceType, baseAddresses)
End Function
End Class

How to invoke web service in client which has CustomBinding endpoints?

I have WCF web service with custombinding as endpoint. I would like to invoke this web service (hosted on IIS) from my client application.
The service contract looks as below:
[ServiceContract(Namespace = "http://schemas.microsoft.com/windows/management/2012/01/enrollment")]
[XmlSerializerFormat]
public interface IDiscoveryService
{
[OperationContract(Name = "Get")]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat=WebMessageFormat.Xml, ResponseFormat=WebMessageFormat.Xml)]
string DiscoveryGet();
}
The Web.COnfig file contents looks like:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="NewBinding0">
<textMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
<services>
<service name="DiscoveryWebService.DiscoveryService">
<endpoint address="" binding="customBinding" bindingConfiguration="NewBinding0"
contract="DiscoveryWebService.IDiscoveryService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false 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>
The client application codes looks like:
string uri = " http://localhost/EnrollmentServer/Discovery.svc";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
req.ContentType = "unknown";
req.Method = "GET";
WebResponse response = req.GetResponse();
StreamReader loResponseStream = new StreamReader(response.GetResponseStream(), false);
string responseString = loResponseStream.ReadToEnd();
I am getting HTML content of WSDL file instead of the string returned by Get method. I am not getting whether I am doing it in the right way or not?
I would appreciate the help in this regard.
The [WebGet] (and [WebInvoke]) attribute is only honored for an endpoint which uses the webMessageEncoding binding element; with a HTTP transport with the manualAddressing property set to true, and also the <webHttp/> endpoint behavior - which your service doesn't have. If you make the changes listed below, it should work:
Service contract:
[ServiceContract(Namespace = "http://schemas.microsoft.com/windows/management/2012/01/enrollment")]
[XmlSerializerFormat]
public interface IDiscoveryService
{
[WebGet(BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
string DiscoveryGet();
}
Web.config:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="NewBinding0">
<webMessageEncoding />
<httpTransport manualAddressing="true" />
</binding>
</customBinding>
</bindings>
<services>
<service name="DiscoveryWebService.DiscoveryService">
<endpoint address="" binding="customBinding" bindingConfiguration="NewBinding0"
contract="DiscoveryWebService.IDiscoveryService" behaviorConfiguration="Web" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="Web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Client code:
string uri = "http://localhost/EnrollmentServer/Discovery.svc/DiscoveryGet";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
req.Method = "GET";
WebResponse response = req.GetResponse();
StreamReader loResponseStream = new StreamReader(response.GetResponseStream(), false);
string responseString = loResponseStream.ReadToEnd();

wcf rest service consumption in c# console application

I made wcf rest service by going New->projects->WCF Service Application
I am unable to use methods in console application while i have hosted wcf rest service and referenced wcf rest service in application
My Application code is below :
IRestServiceImpL
[ServiceContract]
public interface IRestServiceImpL
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Xml, UriTemplate = "XmlData/{id}")]
string XmlData(string id);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json, UriTemplate = "JsonData/{id}")]
string JsonData(string id);
}
RestServiceImpL.svc.cs
[AspNetCompatibilityRequirements(RequirementsMode
= AspNetCompatibilityRequirementsMode.Allowed)]
public class RestServiceImpL : IRestServiceImpL
{
public string XmlData(string id)
{
return "you requested for " + id;
}
public string JsonData(string id)
{
return "you requested for " + id;
}
}
Config File
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="StreamedRequestWebBinding"
bypassProxyOnLocal="true"
useDefaultWebProxy="false"
hostNameComparisonMode="WeakWildcard"
sendTimeout="10:15:00"
openTimeout="10:15:00"
receiveTimeout="10:15:00"
maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647"
maxBufferPoolSize="2147483647"
transferMode="StreamedRequest"
crossDomainScriptAccessEnabled="true"
>
<readerQuotas maxArrayLength="2147483647"
maxStringContentLength="2147483647" />
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="RestService.RestServiceImpL" behaviorConfiguration="ServiceBehaviour">
<!--<endpoint address="" binding="basicHttpBinding" contract="RestService.IRestServiceImpL"></endpoint>-->
<endpoint address="" binding="webHttpBinding" name="StreamedRequestWebBinding" bindingConfiguration="StreamedRequestWebBinding" contract="RestService.IRestServiceImpL" behaviorConfiguration="web"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<!-- 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>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*"/>
</customHeaders>
</httpProtocol>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
I host this service application in IIS
Now after giving reference to console application when i call its methods
by using proxy class then i got error of Invalid Operation Contract Exception
that endpoint not specified
calling code is below :
ServiceClient oServiceClient = new ServiceClient();<br/>
oServiceClient.JsonData("123");
Please suggest what is problem in the code.
Thanks stack overflow for support...I did it..
The calling Wcf Rest Service code is written below :
//code for xml Response consumption from WCF rest Service[Start]
WebRequest req = WebRequest.Create(#"http://RestService.com/WcfRestService/RestServiceImpL.svc/XmlData/sad");
req.Method = "GET";
req.ContentType = #"application/xml; charset=utf-8";
HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
if (resp.StatusCode == HttpStatusCode.OK)
{
XmlDocument myXMLDocument = new XmlDocument();
XmlReader myXMLReader = new XmlTextReader(resp.GetResponseStream());
myXMLDocument.Load(myXMLReader);
Console.WriteLine(myXMLDocument.InnerText);
}
//code for xml Response consumption from WCF rest Service[END]
//****************************************************************************
//code for json Response consumption from WCF rest Service[Start]
WebRequest req2 = WebRequest.Create(#"http://RestService.com/WcfRestService/RestServiceImpL.svc/JsonData/as");
req2.Method = "GET";
req2.ContentType = #"application/json; charset=utf-8";
HttpWebResponse response = (HttpWebResponse)req2.GetResponse();
string jsonResponse = string.Empty;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
jsonResponse = sr.ReadToEnd();
Console.WriteLine(jsonResponse);
}
//code for json Response consumption from WCF rest Service[END]

The remote server returned an error: (400) Bad Request

I am trying to consume the WCF Restful Service. The Service config is as follows
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttp" maxReceivedMessageSize ="50000000" maxBufferPoolSize="50000000" >
<readerQuotas maxDepth="500000000" maxArrayLength="500000000" maxBytesPerRead="500000000" maxNameTableCharCount="500000000" maxStringContentLength="500000000"/>
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ItemTracker.ItemTrackerServiceBehavior" name="ItemTracker.ItemTrackerService">
<endpoint address="http://localhost:8003/ItemTracker/ItemTrackerService.svc" binding="wsHttpBinding" contract="ItemTracker.IItemTrackerService" bindingConfiguration="wsHttp">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ItemTracker.ItemTrackerServiceBehavior">
<!-- 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>
The Interface is defined as follows
Imports System.ServiceModel.Web
<ServiceContract([Namespace]:="http://localhost:8003/ItemTracker/")> _
Public Interface IItemTrackerService
<OperationContract()> _
<WebInvoke(Method:="POST", RequestFormat:=WebMessageFormat.Xml, ResponseFormat:=WebMessageFormat.Xml, UriTemplate:="GetItemTrackingDetails")> _
Function GetItemTrackingDetails(ByVal TrackingNo As String) As String
End Interface
The Calling of Restful service in client application is as follows
Dim req As HttpWebRequest = Nothing
Dim res As HttpWebResponse = Nothing
Dim url As String = "http://localhost:8003/ItemTracker/ItemTrackerService.svc?wsdl/GetItemTrackingDetails/"
req = DirectCast(WebRequest.Create(url), HttpWebRequest)
req.Method = "POST"
req.ContentType = "application/soap+xml; charset=utf-8"
req.Timeout = 30000
req.Headers.Add("SOAPAction", url)
Dim xmlDoc As New System.Xml.XmlDocument()
xmlDoc.XmlResolver = Nothing
xmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory & "\test.xml")
Dim sXML As String = xmlDoc.InnerXml
req.ContentLength = sXML.Length
Dim sw As New System.IO.StreamWriter(req.GetRequestStream())
sw.Write(sXML)
sw.Close()
res = DirectCast(req.GetResponse(), HttpWebResponse)
The input xml is this.
<GetItemTrackingDetails xmlns="http://localhost:8003/ItemTracker/">
<TrackingNo>A10001</TrackingNo>
</GetItemTrackingDetails>
Instead of localhost system name is used
The output of GetItemTrackingDetails is xml. With this I am getting bad request 400 instead of xml
Is there anyone to help me out.
This url looks strange:
Dim url As String = "http://localhost:8003/ItemTracker/ItemTrackerService.svc?wsdl/GetItemTrackingDetails/"
Does it work better if you remove ?wsdl?
Dim url As String = "http://localhost:8003/ItemTracker/ItemTrackerService.svc/GetItemTrackingDetails/"
You don't need to specify the url to the actual service, just the url mask:
http://localhost:8003/ItemTracker/GetItemTrackingDetails/
Furthermore you have to add a placeholder into your url mask to contain the input parameter to your operation:
UriTemplate:="GetItemTrackingDetails/{0}"
This allows you to call the actual url and pass the TrackingNo variable at the end of the url:
http://localhost:8003/ItemTracker/GetItemTrackingDetails/999AAA

WCF Service TcpNetBinding StreamRequest not receiving stream

My first question so be gentle =)
The following is all .Net 4, VB.Net, in VS2010. The end goal is to receive a (complete) stream from the client over Tcp binding, to an IIS Hosted WCF Service. The problem I am facing is that the service is not able to read any bytes from the provided stream. Now with the nitty gritty... I've removed a fair amount for brevity but, let me know if I've omitted something important.
The service contract is as follows:
<ServiceContract(Namespace:="ImageSystem")> _
Public Interface IUploadService
<OperationContract()> _
Function UploadFile(ByVal file As ImageUpload) As ImageUpload
End Interface
The data contract ImageUpload is as follows:
<MessageContract()> _
Public Class ImageUpload
#Region " Message Header "
Private _ImageID As Nullable(Of Long)
<MessageHeader()> _
Public Property ImageID() As Nullable(Of Long)
Get
Return _ImageID
End Get
Set(ByVal value As Nullable(Of Long))
_ImageID = value
End Set
End Property
'... a few other value type properties
#End Region
#Region " Message Body"
' Do not add any more members to the message body or streaming support will be disabled!
<MessageBodyMember()> _
Public Data As System.IO.Stream
#End Region
End Class
The relevant server config/bindings are as follows (these are obviously dev environment settings only):
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="netTcpStreamBinding" transferMode="Streamed" maxBufferSize="20971520" maxReceivedMessageSize="20971520"/>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="UploadServiceBehaviour"
name="ImageSystem.SVC.UploadService">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="netTcpStreamBinding"
contract="ImageSystem.SVC.IUploadService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:809/UploadService" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="UploadServiceBehaviour">
<serviceMetadata httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
The WCF Service is a service Library, which is hosted by a Web Application. The Web Application project runs in my local IIS 7.5. IIS has been configured to enable TCP connections, and the application pool identity is configured with relevant permissions to the contract implementation. VS2010 is run as admin to enable debugging in IIS.
To test the contract implementation I have a Windows Console Application set up as a (test) client. The client proxy classes were generated by adding a service reference to the service within the IIS host (http://localhost/ImageSystem/UploadService.svc). The service reference is configured to generate async methods.
The relevant auto-generated client config is as follows (note, I've tried increasing maxBufferPoolSize, maxBufferSize, and maxReceivedMessageSize to match the servers config of "20971520", but to no avail):
[EDIT: reliableSessions section commented out in light of Sixto Saez's suggestion but to no avail]
<system.serviceModel>
<bindings>
<binding name="NetTcpBinding_IUploadService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
transactionFlow="false" transferMode="Streamed" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="20971520"
maxBufferSize="20971520" maxConnections="10" maxReceivedMessageSize="20971520">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<!--<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />-->
<security mode="None">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://mycomputername.mydomain/ImageSystem/UploadService.svc"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IUploadService"
contract="UploadService.Local.IUploadService" name="NetTcpBinding_IUploadService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
The client usage is as follows:
Public Sub Test()
Dim serviceClient As UploadService.Local.UploadServiceClient = New UploadService.Local.UploadServiceClient
AddHandler serviceClient.UploadFileCompleted, AddressOf LocalTestCallback
Dim ms As MemoryStream = New MemoryStream
My.Resources.Penguins.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
serviceClient.ClientCredentials.Windows.ClientCredential.Domain = "MYDOMAIN"
serviceClient.ClientCredentials.Windows.ClientCredential.UserName = "User"
serviceClient.ClientCredentials.Windows.ClientCredential.Domain = "Password123"
serviceClient.UploadFileAsync(Nothing, ..., ms, ms) '"..." is obviously not actually here, other values omitted. "ms" is passed as UserState object in addition to fulfilling the 'Data' parameter
End Sub
In case you wonder (or it matters), the penguins image is the one provided with Windows 7 in the sample pictures directory. The image is 777,835 bytes (should be within the relevant request/buffer max sizes).
I have tried two approaches to read the image on the server side.
Approach 1:
Public Function UploadFile(ByVal file As ImageUpload) As ImageUpload Implements IUploadService.UploadFile
Dim uploadBuffer(Helper.Settings.AppSettings(Of Integer)("UploadBufferSize", True) - 1) As Byte
Dim ms As MemoryStream = New MemoryStream()
Dim bytesRead As Integer
Do
bytesRead = file.Data.Read(uploadBuffer, 0, uploadBuffer.Length)
ms.Write(uploadBuffer, 0, bytesRead)
Loop Until bytesRead = 0
End Function
Approach 2:
Public Function UploadFile(ByVal file As ImageUpload) As ImageUpload Implements IUploadService.UploadFile
Dim reader As StreamReader = New StreamReader(file.Data)
Dim imageB64 As String = reader.ReadToEnd
ms = New MemoryStream(Convert.FromBase64String(imageB64))
End Function
In both cases, ms.Length = 0. More clearly, in the second approach, imageB64 = "" (empty string).
Why aren't I receiving anything from the stream? Also, as a sneaky sub-question, why does the generated proxy class not provide an overload that accepts an object of type ImageUpload?
Thank you in advance!!
it seemed strange to me that you would have the problems you mentioned, so I was curious and put together an implementation using your service contract. That one actually worked straight away. I don't actually know what went wrong in your case (it's not obvious), but let me just post a working solution here hoping that this will help you to solve your problem.
Unfortunately, as I abandoned VB many years ago, I can only provide C# code. Hope that's alright.
Server Web.config (tested in IIS, with net.tcp binding):
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding transferMode="Streamed" maxReceivedMessageSize="1000000">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="ImageSystem.SVC.UploadService">
<endpoint address="" binding="netTcpBinding" contract="ImageSystem.SVC.IUploadService">
</endpoint>
<endpoint address="mex" kind="mexEndpoint" binding="mexTcpBinding"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Client app.config (console test app):
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding transferMode="Streamed" maxReceivedMessageSize="1000000">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint
address="net.tcp://localhost/WcfService1/UploadService.svc"
binding="netTcpBinding"
contract="ImageServices.IUploadService"
name="NetTcpBinding_IUploadService">
</endpoint>
</client>
</system.serviceModel>
Service contract & implementation:
[ServiceContract(Namespace="urn:ImageSystem")]
public interface IUploadService
{
[OperationContract]
ImageUpload UploadFile(ImageUpload file);
}
[MessageContract]
public class ImageUpload
{
[MessageHeader]
public long? ImageID { get; set; }
[MessageBodyMember]
public Stream Data;
}
public class UploadService : IUploadService
{
public ImageUpload UploadFile(ImageUpload file)
{
long length;
using (var ms = new MemoryStream())
{
file.Data.CopyTo(ms);
length = ms.Length;
}
return new ImageUpload { ImageID = length, Data = new MemoryStream() };
}
}
Test app:
private static readonly string imgPath = #"C:\Pictures\somepicture.jpg";
private static readonly EventWaitHandle waitHandle = new AutoResetEvent(false);
static void Main()
{
long? result;
using (var service = new ImageServices.UploadServiceClient("NetTcpBinding_IUploadService"))
{
var image = new ImageServices.ImageUpload();
using (var imgStream = File.OpenRead(imgPath))
{
image.Data = imgStream;
service.UploadFileCompleted += (sender, e) =>
{
result = e.Result;
if (e.Data != null) image.Data.Dispose();
waitHandle.Set();
};
service.UploadFileAsync(null, imgStream);
waitHandle.WaitOne();
}
}
}
First of all, as you can see, the config files can be a lot simpler. Especially the large BufferSize value is not necessary. Then, with regard to the service contract, it's not clear to me why the Upload operation would receive AND return an ImageUpload message. In my implementation, I'm returning the uploaded file size in the ImageID parameter just for demo purposes, of course. I don't know what your reasoning behind that contract was, and what you actually would want to return.
Actually, was just about to click "Send" when I had an idea why your code could have failed. In your test client, before you call serviceClient.UploadFileAsync(), add this line to your code: ms.Seek(0, SeekOrigin.Begin).
This resets the position of the MemoryStream back to its beginning. If you don't do that, the MemoryStream will be consumed only from its current position, which is its end - and which explains the Length = 0 of the stream received on the service side!
You may have already seen the information in this MSDN article but you should review the section called Streaming Data and the restrictions it lists. Your client config shows the reliableSession element having the ordered attribute set to "true" which is not supported for streaming.
I don't know if that is specifically the cause of your issue but it is a start. That article also layouts pretty well the basic config required for streaming so you should ensure your config complies with its recommendations.