Wednesday, May 16, 2018

ASP.NET WebAPI2 multipart/formdata upload error

If the following error looks familiar please check the info below !


Error writing MIME multipart body part to output stream
System.IO.IOException

According to the internet it can have many reasons, in my case it was a simple semicolon. 

The problem is actually in the client code. It is a semicolon after the form data !
i marked it red ! if it's in the code the servers throws an exception at:

  • await Request.Content.ReadAsMultipartAsync(provider);

if you remove it it works perfectly. other server implementation don't have a problem with the semicolon.....

UseCases:


  • C# Client to upload files and formdata
  • C# Self hostet WebApi2 rest server
Client code:
---------------------------------------------------------------------------------------

       private static string UploadFiles(string url, NameValueCollection values, NameValueCollection files = null)
        {
            string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
            // The first boundary
            byte[] boundaryBytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            // The last boundary
            byte[] trailer = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
            // The first time it itereates, we need to make sure it doesn't put too many new paragraphs down or it completely messes up poor webbrick
            byte[] boundaryBytesF = System.Text.Encoding.ASCII.GetBytes("--" + boundary + "\r\n");

            try
            {
                // Create the request and set parameters
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.ContentType = "multipart/form-data; boundary=" + boundary;
                request.Method = "POST";
                request.KeepAlive = true;
                request.SendChunked = true;


                // Get request stream
                Stream requestStream = request.GetRequestStream();

                foreach (string key in values.Keys)
                {
                    // Write item to stream
                    byte[] formItemBytes =              System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}", key, values[key]));
                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                    requestStream.Write(formItemBytes, 0, formItemBytes.Length);
                }

                if (files != null)
                {
                    foreach (string key in files.Keys)
                    {
                        if (File.Exists(files[key]))
                        {
                            int bytesRead = 0;
                            byte[] buffer = new byte[2048];
                            string filename = new FileInfo(files[key]).Name;
                            byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", key, filename));
                            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                            requestStream.Write(formItemBytes, 0, formItemBytes.Length);

                            using (FileStream fileStream = new FileStream(files[key], FileMode.Open, FileAccess.Read))
                            {
                                while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                                {
                                    // Write file content to stream, byte by byte
                                    requestStream.Write(buffer, 0, bytesRead);
                                }

                                fileStream.Close();
                            }
                        }
                    }
                }

                // Write trailer and close stream
                requestStream.Write(trailer, 0, trailer.Length);
                requestStream.Close();

                using (StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream()))
                {
                    return reader.ReadToEnd();
                };

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return "";
        }

Server Code:
--------------------------------------------------------------------------------------------------------------
public class UploadController : UtilityController
{      
        [HttpPost]
        public async Task PostFormData()
        {
            // Check if the request contains multipart/form-data.
            if (!Request.Content.IsMimeMultipartContent())
            {
                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
            }

            string root = Parameters.Get("UploadPath", Path.GetTempPath().EnsureBS(), "Files");
            var provider = new MultipartFormDataStreamProvider(root);

            try
            {
                // throws exception next line !!!!
                await Request.Content.ReadAsMultipartAsync(provider);

                // This illustrates how to get the file names.
                foreach (MultipartFileData file in provider.FileData)
                {
                    Trace.WriteLine(file.Headers.ContentDisposition.FileName);
                    Trace.WriteLine("Server file path: " + file.LocalFileName);
                }
                return Request.CreateResponse(HttpStatusCode.OK);
            }
            catch (System.Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
            }
        }
}

Wednesday, April 20, 2016

Enable Http(S) Ports for self hosted webservices on windows

HTTP:
netsh http add urlacl url=http://+:8080/ user=DOMAIN\user

HTTPS:
netsh http add urlacl url=https://+:443/ user=DOMAIN\user
netsh http add sslcert ipport=0.0.0.0:443 certhash=HASH appid={GUID} 

HASH = Zertifikat->Details->Fingerabdruck im SSL Serverzertifikat
COPY/PASTE Leerzeichen entfernen 
‎df25040067c714e1de83574f3e953a8220c88dfc ‎
df 25 04 00 67 c7 14 e1 de 83 57 4f 3e 95 3a 82 20 c8 8d fc

appid = GUID der Applikation
Properties->Application->Assembly Information->

GUID: (ist eher zur Info wird nicht abgeprüft) 88538482-54d6-4c3a-922d-1fbb0d5367b2

Beispiel: netsh http add sslcert ipport=0.0.0.0:443 certhash=df25040067c714e1de83574f3e953a8220c88dfc
appid={88538482-54d6-4c3a-922d-1fbb0d5367b2}

Tuesday, August 2, 2011

XBMC, ZBox und Bong.TV

Ich habe schon vor längerem meinen Sitecom-Player durch einen XBMC-Player ersetzt. XBMC ist eine Open-Source MediaCenter Software, die sich wunderbar zum Abspielen von Bong.TV Content eignet. Hauptgrund für mich ist das 'fast' perfekte Überspringen von uninteressantem Material. Bei Bong.TV sind ja schon mal die ersten 5 Minuten zu früh aufgenommen (Besser natürlich, als wenn 5 Minuten fehlen), aber mit manchen Playern ist das Springen an den Anfang der eigentlichen Aufnahme eine Geduldsprobe. Entweder das Positionieren dauert viel zu lange, oder die Schritte sind viel zu groß. Wie z.B. bei meinem Sitecom Player, der nicht in X-Sekunden, sondern in X-Prozent springt. Dies hat zur Folge, dass man bei sehr langen Aufnahmen nur etwa +- 8 Minuten überspringen kann. Nicht So bei XBMC. Einmal drücken auf der Fensteuerung und man ist um 30 Sekunden weiter, und dass ohne gefühlte Verzögerung. Das 'Vorspulen' zum Sendungsanfang geht damit sehr schnell und 'nervt' fast gar nicht mehr. Natürlich funktioniert das auch bei Werbeblöcken sehr gut. Zum Abspielen verwende ich noch ein altes Apple-TV Gerät. Ich habe aber mittlerweile für meine Schwester ein System mit einer ZBox AD01 aufgebaut. Die ZBox unter Ubuntu, dient als Server, übernimmt gleichzeitig den automatischen Download und spielt das ganze auch noch via XBMC ab. Im nächsten Eintrag stelle den Aufbau und ich die Installation etwas genauer vor.

Wednesday, June 8, 2011

Update für den BongParser

Es gibt ein Update für den "Synology"-BongParser - V 1.1
(Läuft natürlich unter allem, was .NET oder Mono hat ;-).

Hinzugekommen sind ein paar neue Möglichkeiten in der Filenamengenerierung.


Zusätzlich zu {Title} {ID} {Channel} und {Date} gibt es jetzt noch {Subtitle} und {Genre}, wobei Subtitle auf maximal 20 Zeichen beschränkt ist.

Die Serieninformationen werden jetzt automatisch nach dem Title erzeugt. Von Bong.TV werden maximal 3 Felder mitgeliefert

  • Die Staffel (series_season)
  • Die Folge (series_number)
  • Anzahl der Folgen der Staffel (series_count)
Bei Spielfilmen sind diese Felder leer, bei Serien meist gefüllt, wobei auch schon mal series_season und series_count fehlen. Die Info wird jetzt nach folgendem Muster aufgebaut:

S[series_season](series_number[@series_count])

Beispiele:

Alle 3 Felder vorhanden: S3(14@24)

Nur 2 Felder vorhanden: S3(14)

Nur 1 Feld vorhanden: S(34)

Wenn keines der Felder vorhanden ist, fehlt die Info komplett.






Saturday, April 2, 2011

Update für Bong Lite

Es gibt ein Update für BongLite  (Version 1.2)

"BongLite dient zum automatischen Download der Aufnahmen von Bong.TV. Der Dateiname lässt sich automatisch generieren und nach dem Download werden die Dateien auf dem Server gelöscht ! "



Einfach das Setup herunterladen und ausführen. Das Setup funktioniert auch als Update und überschreibt die bestehenden Einstellungen und Daten nicht.

Was ist neu ?

  • Es gibt einen neuen Platzhalter für 'Description' also die Beschreibung zu einer Aufnahme. Dieser sollte dann so {Description} angegeben werden.
  • Damit es da nicht zu beliebigen (File)-Längen kommt kann man hinter die Platzhalter Title, Subtitle und Description die maximale Länge angeben Bsp: {Description:20}. Die ersten 20 Zeichen werden übernommen. Die Längenangabe funktioniert nur bei diesen Feldern ! 

Details zur Filenamengenerierung hier Welche Platzhalter sind erlaubt ?

Thursday, February 10, 2011

Update BongLoader

Es gibt ein kleines Update für den BongLoader. Er lädt jetzt alle anstehenden Downloads auf einmal, und nicht nur ein File pro Aufruf. Ich habe das aus Energiespargründen implementiert. Ingesamt gibts jetzt (bei meiner Konfiguration) nur noch einen Check alle 4-5 Stunden und wenn nichts zu laden ist, hat meine DS209 Pause. Das kann aber natürlich jeder halten wie er will !


Achtung: Im Zip-File findet man nur das File BongLoader.exe. Bitte über die alte Version kopieren.

Wednesday, February 9, 2011

Update für Bong Lite

Es gibt eine neue Version von BongLite !





Installation:

Zip-Datei entpacken und setup.exe ausführen.
Danach Anleitung hier beachten !


Update bei bereits installierter Applikation BongLite V 1.0:

BongUpdate-Zip File in das BongLite Programmverzeichnis entpacken - fertig ! Das Setup nur bei einer Neuinstallation ausführen, denn die Parameter und Datenbank werden neu geschrieben.
Was ist neu ?
  • Anzeige von zusätzlichen Metadaten in der Liste
    • Dauer
    • Subtitle
    • Season
    • Episode 
  • Zusätzliche Platzhalter für den Filenamen
    • Sendezeit
    • Subtitle
    • Season
    • Episode
    • Genre
  • Direktes Abspielen eines Videos aus der Liste
Hinweise für die Platzhalter:

{Title}  Wird ersetzt durch den Titel des Videos z.B. Tagesthemen
{ID}    Wird ersetzt durch die Bong-ID. Diese ist eindeutig und garantiert unterschiedliche Filenamen. z.B. 12345
{Channel} Wird ersetzt durch den Sender z.B. Pro7
{Date} Wird ersetzt durch das Datum z.B. 20110209
{Season} Wird ersetzt durch die Staffelnummer z.B. S1
{Subtitle} Wird ersetzt durch den Subtitel z.B. Ein Frage der Ehre
{Time} Wird ersetzt durch den Zeitpunkt der Austrahlung z.B. 1500
{Episode} Wird ersetzt durch die Nummer der Folge z.B. 2_24
{Genre} Wird ersetzt durch das Genre z.B. Info

Es kann vorkommen, das Subtitle oder Episode keine Daten enthalten. Dann wird der Platzhalter entfernt. Zusätzlich wird auch nach unnützen Bindestrich-Kombinationen gesucht und diese werden auch entfernt.
Bsp.   {Title} - {Subtitle} - {Date} wird mit den obigen Daten zu
Tagesthemen - Ein Frage der Ehre - 20110209
Da aber eine Sendung wie Tagesthemen keinen Subtitel hat, käme
Tagesthemen - - 20110209 heraus. Durch das automatische Entfernen der Bindestriche wird daraus
Tagesthemen - 20110209. Dies funktioniert nur, wenn man zwischen den Platzhaltern die Kombination
[Leerzeichen][Bindestrich][Leerzeichen] eingibt.

Folgendes ist noch wichtig: Bestimmte Zeichen darf man nicht in Filenamen verwenden. Diese sind: / \ : * ? " < > |. Das Programm filtert diese auf jeden Fall heraus. Andernfalls kann das File nicht erzeugt werden.

Das Programm macht ja gar nix ?
Der Download und auch die Anzeige der Files erfolgt im Hintergrund. Es ist also normal wenn nach dem Starten erst mal nichts passiert. Einfach abwarten ! Das Update Interval liegt bei etwa 2 Minuten.