Introduction:
This article explains file uploading with HTML/JavaScript consuming WCF services exposed with the REST API.
First, we must create the service. As the upload function itself can only have a parameter of type Stream, I return a object with the upload path so I can refer to it after to the server. In my case, I must load a name, read a description, validate a hash but here I will keep it simple.
----------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------
The service behavior is also very straightforward:
---------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------
This article explains file uploading with HTML/JavaScript consuming WCF services exposed with the REST API.
First, we must create the service. As the upload function itself can only have a parameter of type Stream, I return a object with the upload path so I can refer to it after to the server. In my case, I must load a name, read a description, validate a hash but here I will keep it simple.
----------------------------------------------------------------------------------------------------------------------------
[DataContract] public class UploadedFile { [DataMember] public string FilePath { get; set; } [DataMember] public string FileLength { get; set; [DataMember] public string FileName { get; set; } //Other information. On upload only path and size are obvious. //... }
-----------------------------------------------------------------------------------
The service contract consists of a method receiving a stream and returning an object with the path where the file was saved. For example purposes, I included another method where we will include a human readable file name.
---------------------------------------------------------------------------------------------------------------------------
[ServiceContract(Name = "IWCFUploader"] public interface IWCFUploader { [OperationContract(Name = "Upload")] [DataContractFormat] [WebInvoke(Method = "POST", UriTemplate = "Upload/", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)] UploadedFile Upload(Stream Uploading); [OperationContract(Name = "Transform")] [DataContractFormat] [WebInvoke(Method = "POST", UriTemplate = "Transform", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)] UploadedFile Transform(UploadedFile Uploading, string FileName); }---------------------------------------------------------------------------------------------------------------------------
The service behavior is also very straightforward:
---------------------------------------------------------------------------------------------------------------------------
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall, IgnoreExtensionDataObject = true, IncludeExceptionDetailInFaults = true)] public class WCFUploader : IWCFUploader { #region IWCFUploader Members public UploadedFile Upload(Stream Uploading) { UploadedFile upload = new UploadedFile { FilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()) }; int length = 0; using (FileStream writer = new FileStream(upload.FilePath, FileMode.Create)) { int readCount; var buffer = new byte[8192]; while ((readCount = Uploading.Read(buffer, 0, buffer.Length)) != 0) { writer.Write(buffer, 0, readCount); length += readCount; } } upload.FileLength = length; return upload; } public UploadedFile Transform(UploadedFile Uploading, string FileName) { Uploading.FileName = FileName; return Uploading; } #endregion }
----------------------------------------------------------------------------------
In the web.config, you must remember to set the buffer and the maximum received message to a value that allows you to stream your file and, of course, set transfer mode to streamed. webHttp is also necessary in your endpoint behavior. I had an issue where if I named my binding in the service, I would get strange errors so I named all my other bindings and left the binding used for streaming as default, and it worked. You may also have to configure IIS if you want to upload files over 4.5 megabytes, that is if you need it to host the application.
---------------------------------------------------------------------------------------------------------------------------
<configuration> <system.serviceModel> <bindings> <webHttpBinding> <binding maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" transferMode="Streamed" sendTimeout="00:05:00"> <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/> <security mode="None" /> </binding> </webHttpBinding> </bindings> <behaviors> <endpointBehaviors> <behavior name="defaultEndpointBehavior"> <webHttp/> </behavior> </endpointBehaviors> <serviceBehaviors> <behavior name="defaultServiceBehavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="WCFUpload.WCFUploader" behaviorConfiguration="defaultServiceBehavior"> <endpoint address="" behaviorConfiguration="defaultEndpointBehavior" binding="webHttpBinding" contract="WCFUpload.IWCFUploader" /> </service> </services> </system.serviceModel> </configuration>---------------------------------------------------------------------------------------------------------------------------
The JavaScript Code
------------------------------------------------------------------------------------------------------function upload() { var request = new XMLHttpRequest(); request.open('POST', 'wcf/WCFUploader.svc/Upload/'); request.send(filePicker.files[0]); }
----------------------------------------------------------------------------------
The HTMLCode
--------------------------------------------------------------------------------------------------------------------------
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Uploading using WCF REST API</title> <script type="text/javascript"> function uploadBlobOrFile(blobOrFile) { var xhr = new XMLHttpRequest(); xhr.open('POST', 'wcf/WCFUploader.svc/Upload/', true); xhr.setRequestHeader('Content-length', blobOrFile.size); xhr.onload = function (e) { progressBar.value = 0; progressBar.textContent = progressBar.value; }; // Listen to the upload progress. var progressBar = document.querySelector('progress'); xhr.upload.onprogress = function(e) { if (e.lengthComputable) { progressBar.value = (e.loaded / e.total) * 100; progressBar.textContent = progressBar.value; // Fallback. } }; xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } }; xhr.send(blobOrFile); } </script> </head> <body> <input id="filePicker" type="file" name="Package" accept="image/*"/> <br /> <progress min="0" max="100" value="0">0% complete</progress> <br /> <button title="upload" onclick="if (filePicker.files[0]) uploadBlobOrFile(filePicker.files[0])"> <span>Upload</span> </button> </body> </html>
-----------------------------------------------------------------------------------
No comments:
Post a Comment