I have WCF service library with this config:
<basicHttpBinding>
<binding name="httpLargeMessageStream"
maxReceivedMessageSize="2147483647"
messageEncoding="Mtom" transferMode="Streamed" />
</basicHttpBinding>
<netTcpBinding>
<binding name="tcpLargeMessageStream" transferMode="Streamed"
maxReceivedMessageSize="2147483647" />
</netTcpBinding>
and from client side if I send request for upload file, then all work fine
public void UploadFile(FileUploadMessage request)
{
try
{
// Gets absolute local storing path
string localPath = Path.Combine(basePath, request.UploadMetadata.StoringPath);
// Create folders in they don't exist
FileInfo file = new System.IO.FileInfo(localPath);
file.Directory.Create();
// Get document path on server
string serverFileName = Path.Combine(localPath, request.UploadMetadata.HashFileName);
// Create a new temp document
using (FileStream outfile = new FileStream(serverFileName, FileMode.Create))
{
// Read buffer
const int bufferSize = 65536;
// Output buffer
Byte[] buffer = new Byte[bufferSize];
int bytesRead;
// Write bytes from source into local file
while ((bytesRead = request.FileByteStream.Read(buffer, 0, bufferSize)) > 0)
{
outfile.Write(buffer, 0, bytesRead);
}
}
}
catch (IOException e)
{
throw new FaultException<IOException>(e);
}
}
but for download request I already got error:
The maximum message size quota for
incoming messages (65536) has been
exceeded. To increase the quota, use
the MaxReceivedMessageSize property on
the appropriate binding element.
public FileDownloadReturnMessage DownloadFile(FileDownloadMessage request)
{
try
{
controlServerAdress = "http://localhost:8080/ControlServer/";
EndpointAddress basicBinding = new EndpointAddress(controlServerAdress + "TokenService/basic");
tokenService = new TokenServiceClient("BasicHttpBinding_ITokenService", basicBinding);
// Get file token form control server
ComDocFile file = tokenService.ResolveToken(request.DownloadMetadata.Token);
// If exist file for token
if (file != null)
{
// Get document path on server
string serverFileName = Path.Combine(basePath, file.FilePath, file.FileName);
// Set fileName
request.DownloadMetadata.FileName = file.FileName;
// Return file stream
return new FileDownloadReturnMessage(new FileStream(serverFileName, FileMode.Open, FileAccess.Read), new ReturnDownloadMetaData(file.FileName, true));
}
return new FileDownloadReturnMessage(null,
new ReturnDownloadMetaData(null, false));
}
catch (IOException e)
{
throw new FaultException<IOException>(e);
}
}
Client calling method:
// Read buffer
const int bufferSize = 65536;
// Output buffer
Byte[] buffer = new Byte[bufferSize];
int bytesRead;
// Prepare download stream
Stream donwloadStream;
ReturnDownloadMetaData file = fileClient.DownloadFile(downloadMetaData, out donwloadStream);
// If file server return valid file stream
if (file.IsValid)
{
// Create a new temp document
using (FileStream outfile = new FileStream("C:\\#ComDocs_FileServer\\" + file.FileName, FileMode.Create))
{
// Write bytes from source into local file
while ((bytesRead = donwloadStream.Read(buffer, 0, bufferSize)) > 0)
{
outfile.Write(buffer, 0, bytesRead);
}
}
}
the maxReceievedMessageSize is how big the data is that the receiver is prepared to accept. In the code above, for download, the client is the receiver. You need to increase the maxReceievedMessageSize in the client as well (you don't appear to be doing this from the code you have shown)
Use this
maxBufferSize ="2147483647" maxReceivedMessageSize="2147483647"
at both sender and receiver end.
Related
My Download function is below. It's in Controller Class:
public void Download(string fileId)
{
// **************************************************
//MAKE FILEPATH
string filePath = makeFilePath(fileId);
string outFileName = _info.FileName;
System.IO.Stream iStream = null;
// Create buffer for reading [intBufferSize] bytes from file
int intBufferSize = 10 * 1024;
byte[] buffer = new System.Byte[intBufferSize];
// Length of the file That Really Has Been Read From The Stream and Total bytes to read
int length; long dataToRead;
// **************************************************
if (System.IO.File.Exists(filePath))
{
try
{
// Open the file.
iStream = new System.IO.FileStream(
path: filePath,
mode: System.IO.FileMode.Open,
access: System.IO.FileAccess.Read,
share: System.IO.FileShare.Read);
// Total bytes to read:
dataToRead = iStream.Length;
// **************************************************
Response.Clear();
// Setting the unknown [ContentType]
// will display the saving dialog for the user
Response.ContentType = "application/octet-stream";
// With setting the file name,
// in the saving dialog, user will see
// the [outFileName] name instead of [download]!
Response.AddHeader("Content-Disposition", "attachment; filename=" + outFileName);
// Notify user (client) the total file length
Response.AddHeader("Content-Length", iStream.Length.ToString());
// **************************************************
// Read the bytes.
while (dataToRead > 0)
{
// Verify that the client is connected.
if (Response.IsClientConnected)
{
// Read the data and put it in the buffer.
length = iStream.Read(buffer: buffer, offset: 0, count: intBufferSize);
// Write the data from buffer to the current output stream.
Response.OutputStream.Write(buffer: buffer, offset: 0, count: length);
// Flush (Send) the data to output
// (Don't buffer in server's RAM!)
Response.Flush();
buffer = new Byte[intBufferSize];
dataToRead = dataToRead - length;
}
else
{
//prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
catch (Exception ex)
{
throw new ApplicationException(ex.Message);
}
finally
{
if (iStream != null)
{
//Close the file.
iStream.Close();
iStream = null;
}
Response.Close();
}
}
}
}
Everything work ok, but when I'm downloading a file, I cannot take other actions in my controller until the download process is finished.
How can I solve that?
I think the problem is that server is too busy to process file. And the Response gate of server is busy, too, so that, when client send a new request, it'll be pending.
I've solved my problem by putting the attribute [SessionState(SessionStateBehavior.ReadOnly)] on the controller.
It worked fine.
I am creating a WCF Rest Service to Upload Images from Mobile application. but i am getting
The remote server returned an error: (400) Bad Request. can any one point me what i have done wrong.
Following are my Definitions :
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "/PostImage",Method ="POST")]
PublicMessage PostImage(Upload obj);
[DataContract]
public class Upload
{
[DataMember]
public Stream File { get; set; }
}
Service Definition :
public PublicMessage PostImage(Upload obj)
{
byte[] buffer = StreamToByte(obj.File); //Function to convert the stream to byte array
FileStream fs = new FileStream(#"D:\ShopMonkeyApp\Desert.jpg", FileMode.Create, FileAccess.ReadWrite);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(buffer);
bw.Close();
return new PublicMessage { Message = "Recieved the image on server" };
}
Client Application :
string filePath = #"D:\ShopMonkeyApp\Desert.jpg";
string url = "http://localhost:50268/shopmonkey.svc/PostImage/"; // Service Hosted in IIS
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "text/xml";
request.Method = "POST";
request.ContentType = "image/jpeg";
using (Stream fileStream = File.OpenRead(filePath))
using (Stream requestStream = request.GetRequestStream())
{
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int byteCount = 0;
while ((byteCount = fileStream.Read(buffer, 0, bufferSize)) > 0)
{
requestStream.Write(buffer, 0, byteCount);
}
}
string result;
using (WebResponse response = request.GetResponse())
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
Console.WriteLine(result);
Web Config :
<system.serviceModel>
<services>
<service name="ShopMonkey.ShopMonkey" behaviorConfiguration="ServiceBehaviour">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="webHttpBinding" contract="ShopMonkey.IShopMonkey" 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.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/>
<dataContractSerializer maxItemsInObjectGraph="10000000"/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
Thanks
Vijay
Increasing the message queue length in web.config solves my issue.
<webHttpBinding>
<binding name="streamWebHttpbinding" transferMode="Streamed" maxReceivedMessageSize="1000000000000" receiveTimeout="01:00:00" sendTimeout="01:00:00" />
</webHttpBinding>
Thanks to all
If you dont have any other properties on the Upload class then change the WCF service method to have a Stream param rather than wrapping it in a class as below:
[OperationContract]
[WebInvoke(UriTemplate = "/PostImage",Method ="POST")]
PublicMessage PostImage(Stream obj);
Then you can use the WebClient class to upload a file directly as shown below:
var c = new System.Net.WebClient();
c.OpenWrite(string.Concat("http://localhost:50268/shopmonkey.svc", "/PostImage"), "POST");
c.Headers[HttpRequestHeader.ContentType] = "image/jpeg";
return c.UploadFile(string.Concat(serviceBaseUrl, resourceUrl), filePath);
Also refer to this link.
UPDATE :
Please find the sample to get your code working below:
[OperationContract]
[WebInvoke(UriTemplate = "/PostImage",Method ="POST")]
PublicMessage PostImage(Upload obj);
[DataContract]
public class Upload
{
[DataMember]
public MemoryStream FileContent { get; set; }
}
Now your method that implements the PostImage looks as follows:
public PublicMessage PostImage(Upload obj)
{
byte[] buffer = new byte[obj.FileContent.Length];
using (FileStream ms = new FileStream(#"D:\ShopMonkeyApp\Temp\Desert.jpg", FileMode.OpenOrCreate))
{
obj.FileContent.Position = 0;
int read = fileInfo.Content.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
}
return new PublicMessage { Message = "Recieved the image on server" };
}
Now since our server side code is complete now moving to the client side part that uploads your file to the server as below:
private string ClientSample()
{
var uploadObject = new Upload();
Image image = Image.FromFile(#"D:\ShopMonkeyApp\Desert.jpg");
MemoryStream ms = new MemoryStream();
uploadObject.FileContent = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.WriteTo(uploadObject.FileContent);
ms.Close();
string responseMessage = null;
var request = WebRequest.Create(http://localhost:50268/shopmonkey.svc/PostImage) as HttpWebRequest;
if (request != null)
{
request.ContentType = "application/xml";
request.Method = method;
}
if(method == "POST" && requestBody != null)
{
byte[] requestBodyBytes;
requestBodyBytes = ToByteArrayUsingDataContractSer<Upload>(requestBody);
request.ContentLength = requestBodyBytes.Length;
using (Stream postStream = request.GetRequestStream())
postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);
}
if (request != null)
{
var response = request.GetResponse() as HttpWebResponse;
if(response.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = response.GetResponseStream();
if (responseStream != null)
{
var reader = new StreamReader(responseStream);
responseMessage = reader.ReadToEnd();
}
}
else
{
responseMessage = response.StatusDescription;
}
}
}
private static byte[] ToByteArrayUsingDataContractSer<T>(T requestBody)
{
byte[] bytes = null;
var serializer1 = new DataContractSerializer(typeof(T));
var ms1 = new MemoryStream();
serializer1.WriteObject(ms1, requestBody);
ms1.Position = 0;
var reader = new StreamReader(ms1);
bytes = ms1.ToArray();
return bytes;
}
NOTE: Make sure that your Upload object both on the client and server have the same namespace and properties defined so that you avoid any deserialization issues.
using wcf/wcf web services to upload a images give me with example?
In my project i want to upload image by using WCF
Basically you should use WCF streaming.
[ServiceContract]
public interface ITransferService
{
[OperationContract]
void UploadFile(RemoteFileInfo request);
}
public void UploadFile(RemoteFileInfo request)
{
FileStream targetStream = null;
Stream sourceStream = request.FileByteStream;
string uploadFolder = #"C:\\upload\\";
string filePath = Path.Combine(uploadFolder, request.FileName);
using (targetStream = new FileStream(filePath, FileMode.Create,
FileAccess.Write, FileShare.None))
{
//read from the input stream in 65000 byte chunks
const int bufferLen = 65000;
byte[] buffer = new byte[bufferLen];
int count = 0;
while ((count = sourceStream.Read(buffer, 0, bufferLen)) > 0)
{
// save to output stream
targetStream.Write(buffer, 0, count);
}
targetStream.Close();
sourceStream.Close();
}
}
The easiest way is to convert the image to a byte array before sending it, and then converting it back to an image on the destination site.
Here are two methods for doing just that:
public byte[] ImageToByteArray( Image image)
{
var ms = new MemoryStream();
image.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
public static Image ByteArrayToImage(byte[] byteArray)
{
var ms = new MemoryStream(byteArray);
return Image.FromStream(ms);
}
That means your web service can have a method something like this:
public void UploadImage( byte[] imageData )
{
var image = ByteArrayToImage( imageData );
//save image to disk here, or do whatever you like with it
}
How to read the .mp3 audio files ?
I wrote the following code.
public static byte[] ReadFully(Stream stream)
{
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0)
return ms.ToArray();
ms.Write(buffer, 0, read);
}
}
It accepts .3gp,.caf foramat streams .why it's not taking .mp3 files?
}
I used the below code to download a mp3 file from my REST WCF Service:
[WebGet]
public Stream GetMp3()
{
byte[] buffer;
WebOperationContext.Current.OutgoingResponse.ContentType = "audio/mp3";
using (FileStream ms = new FileStream(#"C:\Sample.mp3", FileMode.Open))
{
int length = (int)ms.Length;
WebOperationContext.Current.OutgoingResponse.ContentLength = length;
buffer = new byte[length];
int sum = 0;
int count;
while ((count = ms.Read(buffer, sum, length - sum)) > 0)
{
sum += count;
}
ms.Close();
}
return new MemoryStream(buffer);
}
UPDATE: Upload an mp3 file to Restful WCF service
Server side method:
[WebInvoke]
public string RecieveMp3(Stream mp3Stream)
{
byte[] buffer = new byte[5000000];
using (FileStream ms = new FileStream("C:\\Temp\\Test1.mp3", FileMode.OpenOrCreate))
{
int read = mp3Stream.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
}
return "Recieved Mp3 file";
}
NOTE:
1. Make sure that you have permissions on the folder to write the mp3 file for the user associated with the app pool under which the wcf service is running
2. For testing purpose i have hard coded the byte array size to be a large value.
Client to call the service:
private string UseRestSharpApproachForFiles(string serviceBaseUrl, string resourceUrl, Method method, string filepath)
{
var client = new RestClient();
client.BaseUrl = serviceBaseUrl;
var request = new RestRequest(method) { DateFormat = DataFormat.Xml.ToString(), Resource = resourceUrl };
request.AddFile("stream", filepath);
var response = client.Execute(request);
string responseString;
if (response.StatusCode == HttpStatusCode.OK)
{
responseString = HttpUtility.HtmlDecode(response.Content);
}
else
{
responseString = response.StatusDescription + " --------------------" + HttpUtility.HtmlDecode(response.Content);
}
return responseString;
}
Am using the 3rd party dll for invoking the rest service called RestSharp.
I have been trying to design a WCF file upload service and am getting the following error
in my web application:
Type 'System.Web.HttpInputStream'
cannot be serialized. Consider marking
it with the DataContractAttribute
attribute, and marking all of its
members you want serialized with the
DataMemberAttribute attribute. See
the Microsoft .NET Framework
documentation for other supported
types.
Based on this error, I have tried re-marking my FileTransfer
class with DataContractAttribute and DataMemberAttribute
but that didn't do anything:
[DataContractAttribute(Namespace = "FileTransfer")]
public class FileTransfer
{
[DataMemberAttribute]
public string GetUploadStatus;
[DataMemberAttribute]
public Tuple<string, int> DoUpload;
[DataMemberAttribute]
public int UploadFile;
[DataMemberAttribute]
public FileTransferInfo FileInfo;
[DataMemberAttribute]
public Stream FileByteStream;
}
I have tried accessing my Service Trace Log with Service Trace Viewer to
see if I could get some more detail on this error. I found a number of errors
with the following message:
The message with To
'http://localhost:1242/WebProj/filetransfer.svc/mex/mex'
cannot be processed at the receiver,
due to an AddressFilter mismatch at
the EndpointDispatcher. Check that
the sender and receiver's
EndpointAddresses agree.
Which would have been useful to me but I also found the same error for:
'http://localhost:1242/WebProj/auth.svc/mex/mex'
in the same trace and I was able to authenticate just fine without any errors which made me wonder if this error is something that I should be worrying about (if any body has a suggestion as to why there is a mex/mex at my endpoint, that would be great).
So, why can't 'System.Web.HttpInputStream' be serialized? I have provided the other important aspects of my code below. Maybe somebody out there can see something that I have missed?
[DataContract(Namespace = "FileTransfer")]
public class FileTransferInfo
{
private string _guid;
private int _flag;
private long _fileSize;
private string _fileName;
private DateTime _lastUpdate;
private FileTypeEnum _fileType;
//REMOVED GETTERS AND SETTERS FOR SPACE
}
[ServiceContract(Namespace = "FileTransfer")]
public interface IFileTransferService
{
[OperationContract(Name = "DoUpload")]
Tuple<string, int> DoUpload(List<FileTransferInfo> request);
[OperationContract(Action="UploadFile", Name="UploadFile")]
int UploadFile(FileTransfer request);
}
Here is my UploadFile method that is returning the error.
int IFileTransferService.UploadFile(FileTransfer request)
{
string uploadFolder = #"C:\TempMultiFileUploads\";
int errCode = default(int);
// parameters validation omitted for clarity
try
{
string filename = request.FileInfo.FileName;
string filePath = Path.Combine(uploadFolder, filename);
using (FileStream outfile = new FileStream(filePath, FileMode.Create))
{
const int bufferSize = 65536; // 64K
Byte[] buffer = new Byte[bufferSize];
int bytesRead = request.FileByteStream.Read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outfile.Write(buffer, 0, bytesRead);
bytesRead = request.FileByteStream.Read(buffer, 0, bufferSize);
}
}
}
catch (IOException e)
{
//System.IOException
errCode = 800;
}
return errCode;
}
And, below is the endpoint, binding, and bahavior of my FileTransferService:
<endpoint name="MyFileTransferEP"
address=""
binding="basicHttpBinding"
behaviorConfiguration="BasicHttpEPBehavior"
bindingConfiguration="httpLargeDataStream"
contract="FileTransfer.IFileTransferService" />
<binding name="httpLargeDataStream"
closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:10:00"
sendTimeout="00:01:00"
maxBufferSize="65536"
maxReceivedMessageSize="2147483647"
messageEncoding="Mtom"
transferMode="StreamedRequest">
<behavior name="BasicHttpEPBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
</behavior>
Here is the code in my web application that calls the upload method:
FileTransferServiceClient upload = new FileTransferServiceClient();
HttpPostedFile m_objFile = default(HttpPostedFile);
FileTransfer transmit = new FileTransfer();
transmit.FileByteStream = m_objFile.InputStream;
transmit.FileInfo = new FileTransferInfo();
transmit.FileInfo.Guid = Guid.NewGuid().ToString();
transmit.FileInfo.Flag = default(int);
transmit.FileInfo.FileSize = m_objFile.ContentLength;
transmit.FileInfo.FileName = m_objFile.FileName;
transmit.FileInfo.LastUpdate = DateTime.Now;
int retParam = upload.UploadFile(transmit); // THROWS ERROR HERE
Thanks for your help.
You cannot define a data contract with a Stream member. You can either take or return a Stream as single parameter or define a message contract which has a single MessageBodyMember of type Stream, but can have multiple MessageHeaders. For more on large data streaming in WCF, please refer to this section of MSDN.