Search code examples
c#.netasp.netwcfwcf-streaming

WCF Streaming File Transfer ON .NET 4


I need a good example on WCF Streaming File Transfer.

I have found several and tried them but the posts are old and I am wokding on .net 4 and IIS 7 so there are some problems.

Can you gives me a good and up-to-date example on that.


Solution

  • The following answers detail using a few techniques for a posting binary data to a restful service.

    The following code is a sample of how you could write a RESTful WCF service and is by no means complete but does give you an indication on where you could start.

    Sample Service, note that this is NOT production ready code.

    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class FileService
    {
        private IncomingWebRequestContext m_Request;
        private OutgoingWebResponseContext m_Response;
    
        [WebGet(UriTemplate = "{appName}/{id}?action={action}")]
        public Stream GetFile(string appName, string id, string action)
        {
            var repository = new FileRepository();
            var response = WebOperationContext.Current.OutgoingResponse;
            var result = repository.GetById(int.Parse(id));
    
            if (action != null && action.Equals("download", StringComparison.InvariantCultureIgnoreCase))
            {
                response.Headers.Add("Content-Disposition", string.Format("attachment; filename={0}", result.Name));
            }
    
            response.Headers.Add(HttpResponseHeader.ContentType, result.ContentType);
            response.Headers.Add("X-Filename", result.Name);
    
            return result.Content;
        }
    
        [WebInvoke(UriTemplate = "{appName}", Method = "POST")]
        public void Save(string appName, Stream fileContent)
        {
            try
            {
                if (WebOperationContext.Current == null) throw new InvalidOperationException("WebOperationContext is null.");
    
                m_Request = WebOperationContext.Current.IncomingRequest;
                m_Response = WebOperationContext.Current.OutgoingResponse;
    
                var file = CreateFileResource(fileContent, appName);
    
                if (!FileIsValid(file)) throw new WebFaultException(HttpStatusCode.BadRequest);
    
                SaveFile(file);
    
                SetStatusAsCreated(file);
            }
            catch (Exception ex)
            {
                if (ex.GetType() == typeof(WebFaultException)) throw;
                if (ex.GetType().IsGenericType && ex.GetType().GetGenericTypeDefinition() == typeof(WebFaultException<>)) throw;
    
                throw new WebFaultException<string>("An unexpected error occurred.", HttpStatusCode.InternalServerError);
            }
        }
    
        private FileResource CreateFileResource(Stream fileContent, string appName)
        {
            var result = new FileResource();
    
            fileContent.CopyTo(result.Content);
            result.ApplicationName = appName;
            result.Name = m_Request.Headers["X-Filename"];
            result.Location = @"C:\SomeFolder\" + result.Name;
            result.ContentType = m_Request.Headers[HttpRequestHeader.ContentType] ?? this.GetContentType(result.Name);
            result.DateUploaded = DateTime.Now;
    
            return result;
        }
    
        private string GetContentType(string filename)
        {
            // this should be replaced with some form of logic to determine the correct file content type (I.E., use registry, extension, xml file, etc.,)
            return "application/octet-stream";
        }
    
        private bool FileIsValid(FileResource file)
        {
            var validator = new FileResourceValidator();
            var clientHash = m_Request.Headers[HttpRequestHeader.ContentMd5];
    
            return validator.IsValid(file, clientHash);
        }
    
        private void SaveFile(FileResource file)
        {
            // This will persist the meta data about the file to a database (I.E., size, filename, file location, etc)
            new FileRepository().AddFile(file);
        }
    
        private void SetStatusAsCreated(FileResource file)
        {
            var location = new Uri(m_Request.UriTemplateMatch.RequestUri.AbsoluteUri + "/" + file.Id);
            m_Response.SetStatusAsCreated(location);
        }
    }
    

    Sample Client, note that this is NOT production ready code.

    // *********************************
    // Sample Client
    // *********************************
    private void UploadButton_Click(object sender, EventArgs e)
    {
        var uri = "http://dev-fileservice/SampleApplication"
        var fullFilename = @"C:\somefile.txt";
        var fileContent = File.ReadAllBytes(fullFilename);
    
        using (var webClient = new WebClient())
        {
            try
            {
                webClient.Proxy = null;
                webClient.Headers.Add(HttpRequestHeader.ContentMd5, this.CalculateFileHash());
                webClient.Headers.Add("X-DaysToKeep", DurationNumericUpDown.Value.ToString());
                webClient.Headers.Add("X-Filename", Path.GetFileName(fullFilename));
                webClient.UploadData(uri, "POST", fileContent);
    
                var fileUri = webClient.ResponseHeaders[HttpResponseHeader.Location];
                Console.WriteLine("File can be downloaded at" + fileUri);
            }
            catch (Exception ex)
            {
                var exception = ex.Message;
            }
        }
    }
    
    private string CalculateFileHash()
    {
        var hash = MD5.Create().ComputeHash(File.ReadAllBytes(@"C:\somefile.txt"));
        var sb = new StringBuilder();
    
        for (int i = 0; i < hash.Length; i++)
        {
            sb.Append(hash[i].ToString("x2"));
        }
    
        return sb.ToString();
    }
    
    private void DownloadFile()
    {
        var uri = "http://dev-fileservice/SampleApplication/1" // this is the URL returned by the Restful file service
    
        using (var webClient = new WebClient())
        {
            try
            {
                webClient.Proxy = null;
                var fileContent = webClient.DownloadData(uri);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }