Skip to content
Geovanni Perez edited this page Oct 13, 2016 · 24 revisions

How to receive a Multi-part request

You can receive multi-part request if you include this static method (from http://stackoverflow.com/questions/7460088/reading-file-input-from-a-multipart-form-data-post):

private static async Task ParseFiles(Stream data, string contentType, Action<string, Stream> fileProcessor)
        {
            var streamContent = new StreamContent(data);
            streamContent.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType);

            var provider = await streamContent.ReadAsMultipartAsync();

            foreach (var httpContent in provider.Contents)
            {
                var fileName = httpContent.Headers.ContentDisposition.FileName;

                if (string.IsNullOrWhiteSpace(fileName))
                {
                    continue;
                }

                using (var fileContents = await httpContent.ReadAsStreamAsync())
                {
                    fileProcessor(fileName.Replace("\"", ""), fileContents);
                }
            }
        }

You need to include WebApi Client Nuget.

Also you can check the HttpMultipartParser Nuget and connect the Request input directly to the HttpMultipartParser, very helpful and small.

Random Port selection demo (@waynebloss)

I just wanted to share with you a random port choosing demo that I created for myself. Perhaps you will want to build this feature into your project one day, but the example below is working fine for me and it may serve as a helpful example for other readers.

The wrapper class (StaticWebServer) is shown last. Here is how I now use it from my WinForms demo:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    using (var webServer = new StaticWebServer())
    {
        webServer.RunAsync();
        Application.Run(new Views.MainView(webServer.UsingBaseAddress));
    }
}

...and in the main view:

public MainView(string webViewUrl = "about:blank")
{
    InitializeComponent();
    browser.Url = new Uri(webViewUrl);
    mainStatusLabel.Text = "";
}

And finally, here is the StaticWebServer class, which chooses the port to use dynamically:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unosquare.Labs.EmbedIO;
using Unosquare.Labs.EmbedIO.Log;
using Unosquare.Labs.EmbedIO.Modules;

namespace YourOwnNamespace
{
    class StaticWebServer : IDisposable
    {
        public StaticWebServer() { }

        static Random _portGenerator = new Random();
        static List<int> _portsUsed = new List<int>();
        
        /// <summary>
        /// An instance of the (awesome!) EmbedIO WebServer.
        /// </summary>
        WebServer _server;

        /// <summary>
        /// String format template to merge the randomly generated port into.
        /// Default: "http://127.0.0.1:{0}/"
        /// </summary>
        public string BaseAddressTemplate { get; set; } = "http://127.0.0.1:{0}/";
        public int PortRangeMin { get; set; } = 51001;
        public int PortRangeMax { get; set; } = 65001;
        /// <summary>
        /// Relative or absolute path to serve static files from.
        /// </summary>
        public string RootFilesystemPath { get; set; } = "browse";

        /// <summary>
        /// The base address currently being used by the server.
        /// </summary>
        public string UsingBaseAddress { get; private set; }
        /// <summary>
        /// The port currently being used by the server.
        /// </summary>
        public int UsingPort { get; private set; }
        /// <summary>
        /// The root filesystem path currently being used by the server.
        /// </summary>
        public string UsingRootFilesystemPath { get; private set; }

        WebServer CreateServer(string baseAddress, string rootPath)
        {
            var logger = new DebugLogger();
            var server = new WebServer(baseAddress, logger);

            var headers = new Dictionary<string, string>()
            {
#if DEBUG
                // The following is mostly useful for debugging.
                { Constants.HeaderCacheControl, "no-cache, no-store, must-revalidate" },
                { Constants.HeaderPragma, "no-cache" },
                { Constants.HeaderExpires, "0" }
#endif
            };

            var staticFileMod = new StaticFilesModule(rootPath, headers);
            staticFileMod.DefaultExtension = ".html";
            server.RegisterModule(staticFileMod);

            return server;
        }

        string GetAbsoluteRootDirectoryPath()
        {
            if (Path.IsPathRooted(RootFilesystemPath))
                return RootFilesystemPath;
            var baseDir = Path.GetDirectoryName(
                System.Reflection.Assembly.GetEntryAssembly()
                .Location);
            return Path.Combine(baseDir, RootFilesystemPath);
        }

        public void RunAsync()
        {
            UsingRootFilesystemPath = GetAbsoluteRootDirectoryPath();
            Debug.Print("Serving static files from: {0}", UsingRootFilesystemPath);

            // Random port selection adapted from http://stackoverflow.com/a/223188/16387
            UsingPort = -1;
            UsingBaseAddress = null;
            while (true)
            {
                UsingPort = _portGenerator.Next(PortRangeMin, PortRangeMax);
                if (_portsUsed.Contains(UsingPort))
                    continue;

                UsingBaseAddress = String.Format(BaseAddressTemplate, UsingPort.ToString());
                _server = CreateServer(UsingBaseAddress, UsingRootFilesystemPath);
                try
                {
                    _server.RunAsync();
                } catch (System.Net.HttpListenerException)
                {
                    _server.Dispose();
                    _server = null;
                    continue;
                }
                _portsUsed.Add(UsingPort);
                break;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        void Dispose(bool disposing)
        {
            if (!disposing)
                return;

            var server = _server;
            _server = null;

            if (server == null)
                return;
            server.Dispose();
        }

        #region DebugLogger

        /// <summary>
        /// Provides a simple logger for Debug output.
        /// </summary>
        class DebugLogger : ILog
        {
            private static void WriteLine(string format, params object[] args)
            {
                var d = DateTime.Now;
                var dateTimeString = string.Format("{0}-{1}-{2} {3}:{4}:{5}.{6}",
                    d.Year.ToString("0000"), d.Month.ToString("00"), d.Day.ToString("00"), d.Hour.ToString("00"),
                    d.Minute.ToString("00"), d.Second.ToString("00"), d.Millisecond.ToString("000"));

                format = dateTimeString + "\t" + format;
                
                if (args != null)
                    Debug.Print(format, args);
                else
                    Debug.Print(format);
            }
            
            public virtual void Info(object message)
            {
                InfoFormat(message.ToString(), null);
            }
            
            public virtual void Error(object message)
            {
                ErrorFormat(message.ToString(), null);
            }
            
            public virtual void Error(object message, Exception exception)
            {
                ErrorFormat(message.ToString(), null);
                ErrorFormat(exception.ToString(), null);
            }
            
            public virtual void InfoFormat(string format, params object[] args)
            {
                WriteLine(format, args);
            }
            
            public virtual void WarnFormat(string format, params object[] args)
            {
                WriteLine(format, args);
            }
            
            public virtual void ErrorFormat(string format, params object[] args)
            {
                WriteLine(format, args);
            }
            
            public virtual void DebugFormat(string format, params object[] args)
            {
                WriteLine(format, args);
            }
        }

        #endregion
    }
}