streaming big file to azure over wcf failed - c#

I need to upload a big file to Azure storage. As a first step, I am trying to upload the file to web service folder via wcf service. I followed the steps in this link Streaming files over WCF. My service code:
namespace MilkboxGames.Services
{
[ServiceContract]
public interface IFileUploadService
{
[OperationContract]
UploadResponse Upload(UploadRequest request);
}
[MessageContract]
public class UploadRequest
{
[MessageHeader(MustUnderstand = true)]
public string BlobUrl { get; set; }
[MessageBodyMember(Order = 1)]
public Stream data { get; set; }
}
[MessageContract]
public class UploadResponse
{
[MessageBodyMember(Order = 1)]
public bool UploadSucceeded { get; set; }
}
}
And
namespace MilkboxGames.Services
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
public class FileUploadService : IFileUploadService
{
#region IFileUploadService Members
public UploadResponse Upload(UploadRequest request)
{
try
{
string uploadDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
string path = Path.Combine(uploadDirectory, "zacharyxu1234567890.txt");
if (File.Exists(path))
{
File.Delete(path);
}
const int bufferSize = 2048;
byte[] buffer = new byte[bufferSize];
using (FileStream outputStream = new FileStream(path, FileMode.Create, FileAccess.Write))
{
int bytesRead = request.data.Read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outputStream.Write(buffer, 0, bytesRead);
bytesRead = request.data.Read(buffer, 0, bufferSize);
}
outputStream.Close();
}
return new UploadResponse
{
UploadSucceeded = true
};
}
catch (Exception ex)
{
return new UploadResponse
{
UploadSucceeded = false
};
}
}
#endregion
}
}
Web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="false" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" executionTimeout="600"
maxRequestLength="2097152" />
<customErrors mode="Off"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="FileUploadServiceBinding" messageEncoding="Mtom" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" receiveTimeout="00:15:00" sendTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00" transferMode="Streamed">
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MilkboxGames.Services.FileUploadService" behaviorConfiguration="FileUploadServiceBehavior">
<endpoint address=""
binding="basicHttpBinding" contract="MilkboxGames.Services.IFileUploadService" bindingConfiguration="FileUploadServiceBinding">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="FileUploadServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483648" />
</requestFiltering>
</security>
</system.webServer>
</configuration>
To consume this service, I created a console application and added the wcf service to Service References. I noticed that the service method becomes 'public bool Upload(string BlobUrl, System.IO.Stream data)' instead of 'public UploadResponse Upload(UploadRequest request)'. Can somebody explain to me why?
Client code:
string blobUrl = "assassinscreedrevelationsandroid/GT-I9100G/assassinscreedrevelationsandroid.apk";
string fileName = "C:\\ws_new\\XuConsoleApplication\\XuConsoleApplication\\bin\\Debug\\motutcimac.myar";
bool bUploadBlobResult;
byte[] buffer = File.ReadAllBytes(fileName);
Console.WriteLine("Size = " + buffer.Length);
Stream fileStream = System.IO.File.OpenRead(fileName);
FileUploadServiceClient objFileUploadServiceClient = new FileUploadServiceClient();
bUploadBlobResult = objFileUploadServiceClient.Upload(blobUrl, fileStream);
I managed to upload a file of 123.8MB. When I try to upload a file of 354.6MB, I got the following exception:
Unhandled Exception: System.InsufficientMemoryException: Failed to allocate
a managed memory buffer of 371848965 bytes. The amount of available memory
may be low. ---> System.OutOfMemoryException: Exception of type
'System.OutOfMemoryException' was thrown.
at System.Runtime.Fx.AllocateByteArray(Int32 size)
--- End of inner exception stack trace ---
I am unable to figure out why this happened. Any help or advice are appreciated.

Unhandled Exception: System.InsufficientMemoryException: Failed to
allocate a managed memory buffer of 371848965 bytes. The amount of
available memory may be low.
above message is indicating your app is using up all the memory that allowed, to increase the limit i think you will need a larger value on attribute "maxReceivedMessageSize"
also from another thread (Failed to allocate a managed memory buffer of 134217728 bytes. The amount of available memory may be low), it recommend to use stream transfer mode for large file upload.
Use Stream property in message contract of WCF operation to transfer
large objects.
[MessageContract]
public class DocumentDescription
{
[MessageBodyMember(Namespace = "http://example.com/App")]
public Stream Stream { get; set; }
}
Configure your binding this way
<binding name="Binding_DocumentService" receiveTimeout="03:00:00"
sendTimeout="02:00:00" transferMode="Streamed" maxReceivedMessageSize="2000000">
<security mode="Transport" />
</binding>

Related

c# stream wcf upload file

I have very little experience in WCF and I want to upload file on server from client machine via WCF service (using streaming). I read few topics and wrote a simple example by myself, but unfortunately it's not working
This is an interface code:
[ServiceContract]
public interface IService1
{
[OperationContract]
string UpStream(FileStream inStream);
}
This is implementation:
public string UpStream(FileStream inStream)
{
using(StreamReader sr = new StreamReader(inStream))
{
var recievedText = sr.ReadToEnd();
if (recievedText != "")
{
return recievedText;
}
else
{
return "nothing";
}
}
}
This is a client code:
private void button3_Click(object sender, EventArgs e)
{
service2.Service1Client sc = new service2.Service1Client();
OpenFileDialog opf = new OpenFileDialog();
opf.ShowDialog();
if (opf.FileName != "")
{
using (FileStream inStream = File.Open(opf.FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
MessageBox.Show(sc.UpStream(inStream));
}
}
}
I think that problem must be somewhere in config file or in Stream. When I start client program and invoke UpStream method, WCF-service is recieving an empty stream
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services />
<bindings>
<basicHttpBinding>
<binding name="NewBinding0" maxBufferPoolSize="52428800" maxBufferSize="65536000"
maxReceivedMessageSize="6553600000" transferMode="Streamed"
useDefaultWebProxy="true" />
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
If anyone can help me with solving my problem, I'll be very grateful
Streaming is very useful but a little tricky to get your head around
this MSDN article provides lots of details https://msdn.microsoft.com/en-us/library/ms733742%28v=vs.110%29.aspx
but doesn't make some of the details very clear
firstly you need to pass messages rather than parameters
this would look something like
[MessageContract]
public class DataTransfer
{
[MessageHeader(MustUnderstand = true)]
public DataContract.HandShake Handshake { get; set; }
[MessageBodyMember(Order = 1)]
public Stream Data { get; set; }
//notice that it is using the default stream not a file stream, this is because the filestream you pass in has to be changed to a network stream to be sent via WCF
}
where the HandShake class provides the parameters you need to include along with your stream
public SaveResponse SaveData(DataTransfer request)
{
using (var stream = new System.IO.MemoryStream())
{
request.Data.CopyTo(stream);
stream.Position = 0;
//this is because you have less control of a stream over a network than one held locally, so by copying from the network to a local stream you then have more control
next is configuration: you have to configure for streaming on both the server and client
which requires something like this
<bindings>
<basicHttpBinding>
<binding name="ServiceBinding" transferMode="Streamed" messageEncoding="Mtom" maxReceivedMessageSize="67108864" maxBufferSize="65536" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00">
</binding>
</basicHttpBinding>
</bindings>

Uploading files above 50KB via WCF service fails

I am trying to get a file upload/download via a WCF service working. The transfer protocol is HTTP. I have set the binding up to user Streaming as transfer mode and have tried for days now to get it working properly, without success. I have managed to get it working for small files. When uploading large files, the file is created on the server, a number of bytes are written and then the transaction fails.
The service is hosted in a Windows Azure WebRole environment scaled to a degree which must definitely be sufficient for the task.
When inspecting the trace log with (e2e-file) with SvcTraceViewer.exe, the problem seems to be this:
An exception has been thrown when reading the stream.
with the call stack:
System.ServiceModel.Dispatcher.StreamFormatter.MessageBodyStream.Read(Byte[] buffer, Int32 offset, Int32 count)
DataService.TransferService.UploadFile(RemoteFileInfo request)
SyncInvokeUploadImage(Object , Object[] , Object[] )
System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
The service contract looks like this:
[ServiceContract]
public interface ITransferService
{
[OperationContract]
RemoteFileInfo DownloadImage(DownloadRequest request);
[OperationContract(IsOneWay = true)]
void UploadImage(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;
}
}
}
Here is the service implementation:
public class TransferService : ITransferService
{
public RemoteFileInfo DownloadImage(DownloadRequest request)
{
return DownloadFile(request);
}
public void UploadImage(RemoteFileInfo request)
{
UploadFile(request);
}
public RemoteFileInfo DownloadFile(DownloadRequest request)
{
var result = new RemoteFileInfo();
try
{
var filePath = Path.Combine(RoleEnvironment.GetLocalResource("TempStorage").RootPath, request.FileName);
var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists)
throw new FileNotFoundException("File not found", request.FileName);
var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
result.FileName = request.FileName;
result.Length = fileInfo.Length;
result.FileByteStream = stream;
}
catch (Exception ex)
{
}
return result;
}
public void UploadFile(RemoteFileInfo request)
{
FileStream targetStream;
var sourceStream = request.FileByteStream;
var filePath = Path.Combine(RoleEnvironment.GetLocalResource("TempStorage").RootPath, request.FileName);
using (targetStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
const int bufferLen = 65000;
var buffer = new byte[bufferLen];
var count = 0;
while ((count = sourceStream.Read(buffer, 0, bufferLen)) > 0)
{
targetStream.Write(buffer, 0, count);
}
targetStream.Close();
sourceStream.Close();
}
}
}
I've set the web.config of the WCF service up like this to enable streaming, increase the relevant size limitations (or at least the ones I know of) and the timeouts:
<?xml version="1.0"?>
<configuration>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add type="Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=2.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="AzureDiagnostics">
<filter type="" />
</add>
</listeners>
</trace>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="sdt"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "log.e2e" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.web>
<customErrors mode="Off" />
<compilation debug="true" targetFramework="4.0" />
<httpRuntime maxRequestLength="2097151" useFullyQualifiedRedirectUrl="true" executionTimeout="14400" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00"
maxReceivedMessageSize="2147483647"
maxBufferSize="2147483647"
transferMode="Streamed" >
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
The client side is a WPF application. The calling code is this:
private void UploadImage(byte[] data, Guid guid)
{
using (var transferService = new TransferServiceClient())
using (var stream = new MemoryStream(data))
{
var uploadRequestInfo = new RemoteFileInfo();
uploadRequestInfo.FileName = guid.ToString();
uploadRequestInfo.Length = data.Length;
uploadRequestInfo.FileByteStream = stream;
transferService.UploadImage(uploadRequestInfo);
}
}
private byte[] DownloadImage(Guid guid)
{
using (var transferService = new TransferServiceClient())
{
try
{
var request = new DownloadRequest(guid.ToString());
var iconFile = transferService.DownloadImage(request);
var data = ByteArrayOperations.FromStream(iconFile.FileByteStream);
return data;
}
catch (Exception)
{
return null;
}
}
}
and - finally - the client side app.config:
<?xml version="1.0"?>
<configuration>
<configSections>
<system.web>
<httpRuntime maxRequestLength="2097150"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ITransferService"
closeTimeout="04:01:00"
openTimeout="04:01:00"
receiveTimeout="04:10:00"
sendTimeout="04:01:00"
allowCookies="false"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647"
maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647"
messageEncoding="Text"
textEncoding="utf-8"
transferMode="Streamed"
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="xxx/TransferService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITransferService"
contract="Transfer.ITransferService" name="BasicHttpBinding_ITransferService" />
</client>
</system.serviceModel>
</configuration>
Note that out of desparation I've added this section:
<system.web>
<httpRuntime maxRequestLength="2097150"/>
</system.web>
without any effect.
In the error log there is one more exception being thrown directly after starting up the service. I neither know what it means nor whether it is related to the problem at all:
System.ServiceModel.ProtocolException
Content Type multipart/related;
type="application/xop+xml";start="<http://tempuri.org/0>";boundary="uuid:b230e809-500b-4217-a08e-32ff49e13bac+id=5";start-info="text/xml"
was sent to a service expecting text/xml; charset=utf-8. The client
and service bindings may be mismatched.
I've spent days getting this to work and really don't know what else I can try. I would be really really happy if somebody could have a look at the configs and maybe give a hint what else to try. So, the question is:
What could be the cause for the transfer to fail and what can I do to solve this?
I would also be happy for further advice on
What to do to find the root problem here, if it cannot be identified based on the information given in the question?
Appendix: I don't think the client side exception is of any use but I would like to include it in the question to make it easier for others with the same problem to find the answers to come (hopefully):
A first chance exception of type 'System.Net.Sockets.SocketException'
occurred in System.dll
Additional information: An existing connection was forcibly closed by
the remote host
I do not see where the service binding is being specified in the serivce config file. I suspect that the configuration values are not being read and this to be the cause of why.
So I propose specifying the name of the binding in the service config file as BasicHttpBinding_ITransferService (same name used in the client config) and then adding the following under the system.serviceModel node of the configuration file:
<services>
<service name="TransferService" >
<endpoint
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ITransferService"
contract="Transfer.ITransferService" />
</service>
</services>

Difficulty invoking WCF POST service running on localhost in a test project in same solution as service

I am having trouble developing and testing a POST web service which both receives and returns JSON.
I am testing it (or trying/wanting to test it) by calling it from a form in a test project within the same
solution as the web service. However it seems that no matter what I do, I'm getting either a "Bad Request", or
a "Not Found" error when invoking the service.
There are oodles of posts on the web in relation to these things, and WCF in general, with examples etc, but I
cannot seem to solve the problem and it's quite disheartening :-((.
I am using VS 2010 on (don't laugh) win XP. However I don't see why an outdated OS should matter.
The single method's signature is
public Stream ReceiveCardStatusInfo(Stream request)
I have generated a proxy via svcutil, but I'm not using it. I have tried referencing the webservice project as
both an ordinary and a service reference (currently a service reference). The properties of the projects are
pretty much the defaults, but in trying to resolve the issues, the web page of the WS project currently shows
"Use Visual Studio Development Server" with "Specific Port" selected, port number 1318. (Virtual Path is the
default "/").
As I'm not really sure exactly what the problem is, I am providing all my code and config files;
the Form's logic first (used to invoke the service) and the app.config for that project, with the service
components following:
Form1:
public Form1() {
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e) {
var request = (HttpWebRequest)WebRequest.Create("http://localhost:1318/ReceiveData.svc/ReceiveCardStatusInfo"); // /ReceiveCardStatusInfo
request.ContentType = "text/json";
request.Method = "POST";
string json = new JavaScriptSerializer().Serialize(new {
AuthenticationToken = "...",
Campus = "Te Awamutu",
StudentID = "200122327",
EnrolmentEndDate = "11/06/2015",
CardStatus = "Suspended",
SuspendedDate = "18/08/2014",
OrderedDate = "20/09/2014",
ReprintDate = "07/10/2014"
});
using (var sW = new StreamWriter(request.GetRequestStream())) {
sW.Write(json);
sW.Flush();
sW.Close();
}
var response = (HttpWebResponse)request.GetResponse();
string result;
using (var streamReader = new StreamReader(response.GetResponseStream())) {
result = streamReader.ReadToEnd();
}
MessageBox.Show(result);
}
app.config (I don't really understand exactly what needs to be in this file, but I've had trouble finding a
clear answer to this, so it contains what it does):
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="StudentCardStatusData.ReceiveData" behaviorConfiguration="serviceBehaviour">
<endpoint address="" binding="webHttpBinding" contract="StudentCardStatusData.IReceiveData" behaviorConfiguration="web"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehaviour">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpBinding_IReceiveData" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</webHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:1318/ReceiveData.svc" binding="webHttpBinding" bindingConfiguration="webHttpBinding_IReceiveData" contract="IReceiveData" name="webHttpBinding_IReceiveData"/>
<!-- endpoint address="..." binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IReceiveData" contract="IReceiveData"
name="BasicHttpBinding_IReceiveData" / -->
</client>
</system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>
</configuration>
Web Service:
IReceiveData:
namespace StudentCardStatusData {
[DataContract]
public class StatusInfo {
private string _Authent;
private string _Campus;
private string _StudentID;
private string _EnrolmentEndDate;
private string _CardStatus;
private string _SuspendedDate;
private string _OrderedDate;
private string _ReprintDate;
[DataMember(Name="AuthenticationToken")]
public string AuthenticationToken {
get { return _Authent; }
set { _Authent = value; }
}
[DataMember(Name="Campus")]
public String Campus {
get { return _Campus; }
set { _Campus = value; }
}
[DataMember(Name="StudentID")]
public String StudentID {
get { return _StudentID; }
set { _StudentID = value; }
}
[DataMember(Name="EnrolmentEndDate")]
public String EnrolmentEndDate {
get { return _EnrolmentEndDate; }
set { _EnrolmentEndDate = value; }
}
[DataMember(Name="CardStatus")]
public String CardStatus {
get { return _CardStatus; }
set { _CardStatus = value; }
}
[DataMember(Name="SuspendedDate")]
public String SuspendedDate {
get { return _SuspendedDate; }
set { _SuspendedDate = value; }
}
[DataMember(Name = "OrderedDate")]
public String OrderedDate {
get { return _OrderedDate; }
set { _OrderedDate = value; }
}
[DataMember(Name = "ReprintDate")]
public String ReprintDate {
get { return _ReprintDate; }
set { _ReprintDate = value; }
}
}
[ServiceContract]
public interface IReceiveData {
[OperationContract]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "ReceiveCardStatusInfo")]
Stream ReceiveCardStatusInfo(Stream request);
}
}
ReceiveData.svc:
namespace StudentCardStatusData {
public class ReceiveData : IReceiveData {
public Stream ReceiveCardStatusInfo(Stream request) {
Stream res = new MemoryStream();
StreamWriter sw = new StreamWriter(res);
try {
ConnectionStringSettings _DefaultSetting = ConfigurationManager.ConnectionStrings["Take2"];
SqlConnection cnn = new SqlConnection(_DefaultSetting.ConnectionString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
//
if (request != null) {
StreamReader sr = new StreamReader(request);
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
List<StatusInfo> allitems = serializer.Deserialize<List<StatusInfo>>(sr.ReadToEnd());
bool isFirst = true;
foreach (var item in allitems) {
if (isFirst) {
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "SELECT Cast(AuthenticationKey as varchar(50)) FROM IDCardAuthentication";
cmd.Connection.Open();
object o = cmd.ExecuteScalar();
cmd.Connection.Close();
if ((string)o != item.AuthenticationToken.ToUpper()) {
sw.Write("[{\"Result\":\"Undefined Failure\"}]");
return res;
}
isFirst = false;
}
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "dbo.spSaveStudentCardStatus";
cmd.Parameters.Add(new SqlParameter("#Campus", item.Campus));
cmd.Parameters.Add(new SqlParameter("#PerID", item.StudentID));
cmd.Parameters.Add(new SqlParameter("#EndDate", item.EnrolmentEndDate));
cmd.Parameters.Add(new SqlParameter("#Status", item.CardStatus));
cmd.Parameters.Add(new SqlParameter("#Upload", item.SuspendedDate));
cmd.Parameters.Add(new SqlParameter("#Ordered", item.OrderedDate));
cmd.Parameters.Add(new SqlParameter("#Reprint", item.ReprintDate));
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
}
}
sw.Write("[{\"Result\":\"Success\"}]");
return res;
}
catch (Exception ex) {
sw.Write("[{\"Result\":\"" + ex.Message + "\"}]");
return res;
}
}
}
}
Web.Config:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="Take2"
connectionString="..."
providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="StudentCardStatusData.ReceiveData" behaviorConfiguration="StudentCardStatusData.ReceiveDataBehavior">
<endpoint address="" behaviorConfiguration="web" binding="webHttpBinding" contract="StudentCardStatusData.IReceiveData" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="https://localhost:1318/ReceiveData.svc" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="StudentCardStatusData.ReceiveDataBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Very first requirement to consume any service is that “Service is Up and Running on Service” here in local ISS in your case.
The reason for getting "Bad Request", or a "Not Found" error when invoking the service is possibility that it is not running on server (localhost).
Are you able to view service page from browser by HTTP request of page "ReceiveData.svc" on your endpoints.
If not then you have to make sure that your service is all ready running before you start consuming it.
As you said that you are running it from same solutions, I am sure you are stating multiple application at the same time. I mean that the Service Application and Consuming Application.
If not you can run multiple start up application from same solution by settings in
Go to Solution properties -> Common properties -> Start up Project and select Multiple start up projects.
So now when you run the solution your both application will start and you should be able to use service.
EDIT
I created test application with all your given code..!!
And it gave me same error..!!!!
So I changed;
request.ContentType = "'text/json; charset=utf-8'";
and it worked..!!! ;)
So please try that.
Hope it helps..!!

Silverlight not sending byte array to WCF service

I have webcam in a silverlight app. I capture the image and convert it to byte array and send to WCF service. Here is the image capture code:
MessageBox.Show("about to capture");
cs.CaptureImageAsync();
cs is the camera source and is configured correctly (as is the imagecapturecompleted event). On image capture completion, this code executes:
MessageBox.Show("Image Caputred");
var img = e.Result.ToImage();
var encoder = new PngEncoder();
Stream stream = img.ToStreamByExtension("png");
byte[] file = null;
if (stream.Length > 512000)
{
img = ExtendedImage.Resize(img, 240, new NearestNeighborResizer());
stream = img.ToStreamByExtension("png");
}
if (stream.Length < 512000)
{
BinaryReader binary = new BinaryReader(stream);
file = binary.ReadBytes((int)stream.Length);
MessageBox.Show("Stream read into file with length: " + file.Length);
}
else
{
MessageBox.Show("file size too large");
}
MessageBox.Show("Process done");
cs.Stop();
label1.Content = "and answer is : " + file!= null ? file.Length.ToString() : "ERROR";
ServiceReference1.Service1Client obj = new ServiceReference1.Service1Client();
ServiceReference1.ITEM i = new ServiceReference1.ITEM { Image = file };
obj.DoWorkCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(obj_DoWorkCompleted);
obj.DoWorkAsync(i);
This is my web.config in the asp.net project that configures the service:
<system.serviceModel>
<services>
<service name ="AttendanceSystem.IService1" behaviorConfiguration="BasicHttpBinding_IService1">
<endpoint address="" binding="basicHttpBinding" contract="AttendanceSystem.IService1"/>
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="BasicHttpBinding_IService1">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
And here is the reference to the service in the silverlight app
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:48886/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IService1"
name="default" />
</client>
</system.serviceModel>
Fiddler returns the following message on the call to my .svc service file:
HTTP/1.1 400 Bad Request
Server: ASP.NET Development Server/10.0.0.0
Date: Wed, 15 Jan 2014 09:17:26 GMT
X-AspNet-Version: 4.0.30319
Cache-Control: private
Content-Length: 0
Connection: Close
So what is going on?
UPDATE: the service seems to be working without error when I pass a smaller byte array (for example BitConverter.GetBytes(123) but fails when the image is sent which is clearly within the max limits)
Try to configure the binding server-side (maxReceivedMessageSize and reader quotas)
<bindings>
<basicHttpBinding>
<binding maxReceivedMessageSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>

Problem consuming a REST service from Silverlight

In my web project I have a TestStreamingService.svc file containing a REST service.
The service contract :
[ServiceContract(Namespace = "")]
public interface ITestStreamingService
{
[OperationContract]
[WebGet(UriTemplate = "Download?file={file}&size={size}")] //file irrelevant, size = returned size of the download
Stream Download(string file, long size);
[OperationContract]
[WebInvoke(UriTemplate= "Upload?file={file}&size={size}", Method = "POST")]
void Upload(string file, long size, Stream fileContent);
[OperationContract(AsyncPattern=true)]
[WebInvoke(UriTemplate = "BeginAsyncUpload?file={file}", Method = "POST")]
IAsyncResult BeginAsyncUpload(string file, Stream data, AsyncCallback callback, object asyncState);
void EndAsyncUpload(IAsyncResult ar);
}
The service implementation (the *.svc file)
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Activation;
using ICode.SHF.Tests;
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class TestStreamingService : ITestStreamingService
{
public Stream Download(string file, long size)
{
return new SHFTestStream(size);
}
public void Upload(string file, long size, Stream fileContent)
{
FileInfo f = new FileInfo(String.Format(#"C:\{0}", file));
using (FileStream fs = f.Create())
{
CopyStream(fileContent, fs);
fs.Flush();
fs.Close();
}
}
public IAsyncResult BeginAsyncUpload(string file, Stream data, AsyncCallback callback, object asyncState)
{
return new CompletedAsyncResult<Stream>(data, file);
}
public void EndAsyncUpload(IAsyncResult ar)
{
Stream data = ((CompletedAsyncResult<Stream>)ar).Data;
string file = ((CompletedAsyncResult<Stream>)ar).File;
StreamToFile(data, file);
}
private void StreamToFile(Stream data, string file)
{
string subDir = Guid.NewGuid().ToString("N");
string uploadDir = Path.Combine(Path.GetDirectoryName(typeof(TestStreamingService).Assembly.Location), subDir);
Directory.CreateDirectory(uploadDir);
byte[] buff = new byte[0x10000];
using (FileStream fs = new FileStream(Path.Combine(uploadDir, file), FileMode.Create))
{
int bytesRead = data.Read(buff, 0, buff.Length);
while (bytesRead > 0)
{
fs.Write(buff, 0, bytesRead);
bytesRead = data.Read(buff, 0, buff.Length);
}
}
}
}
public class CompletedAsyncResult : IAsyncResult
{
T data;
string file;
public CompletedAsyncResult(T data, string file)
{ this.data = data; this.file = file; }
public T Data
{ get { return data; } }
public string File
{ get { return file; } }
#region IAsyncResult Members
public object AsyncState
{
get { return (object)data; }
}
public System.Threading.WaitHandle AsyncWaitHandle
{
get { throw new NotImplementedException(); }
}
public bool CompletedSynchronously
{
get { return true; }
}
public bool IsCompleted
{
get { return true; }
}
#endregion
}
My Web.Config
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="REST">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="ICode.SHF.SL.Tests.Web.TestStreamingService.customBinding0"/>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
/>
<services>
<service name="ICode.SHF.SL.Tests.Web.TestStreamingService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:40000/Streaming"/>
</baseAddresses>
</host>
<endpoint name="TestStreamingEndpoint" address="RESTService" binding="webHttpBinding" bindingConfiguration="ICode.SHF.SL.Tests.Web.TestStreamingService.customBinding0"
contract="ICode.SHF.SL.Tests.Web.ITestStreamingService" behaviorConfiguration="REST"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
I'm trying to consume the service from silverlight (the web project contains a clientaccesspolicy.xml) via a WebClient however I seem to fail, Fiddler doesn't show any calls being made.
(using WebClient.OpenWriteAsync (for upload) & OpenReadAsync (for download))
The uri used for the Client is : "http://localhost:40000/Streaming/Service/Download?file=xxx&size=65536"
When I use the following uri in IE : "http://localhost:40000/TestStreamingService.svc/Download?file=xxx&size=65536" a download operation begins and the downloaded file matches the size passed.
I'm not having success with the IE uri in the WebClient though.
Could anyone please explain to me what am I doing wrong? It seems I've missed something fundamental...
Do your site require authentication? As for fiddler, try connecting your webclient to:
http://localhost.:40000/Streaming/Service/Download?file=xxx&size=65536
(note the extra dot after localhost)
It would appear that I've managed to solve my problem regarding the Downloading capability from Silverlight via. WebClient.
Here's what I did.
Moved the service contract and implementation to a separate project MyWCFLibrary (WCF Service Library)
Added a reference of the said library to the ASP.NET website hosting the project
Added a text file "Service.svc" and edited it :
<%# ServiceHost Language="C#" Debug="true" Service="MyWCFLibrary.TestStreamingService" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
Modified the WebClient operation's uri to match the *.svc file
Seems that it worked.
I'm still attemptring to figure one thing out, so comments are welcome :
I can perform an operation on the service via the Webclient like this :
WebClient wc = new WebClient();
string uri = String.Format("http://localhost.:40000/Service.svc/Download?file=xxx&size={0}", size);
wc.OpenReadAsync(new Uri(uri));
but not like this :
string uri = String.Format("http://localhost.:40000/Services/StreamingService/Download?file=xxx&size={0}", size);
wc.OpenReadAsync(new Uri(uri));
Where : localhost:40000/Services is the base address of the service and StreamingService is the address of the endpoint (latest changes in my WebConfig)
Can anyone explain why? or am I stuck with using the 1st uri by default?

Categories