Documentation Coverage Report
Current view: top level - Cqrs.WebApi/Formatters/FormMultipart/Converters - ObjectToMultipartDataByteArrayConverter.cs Hit Total Coverage
Version: 2.2 Artefacts: 3 3 100.0 %
Date: 2017-09-22

          Line data    Source code
       1             : #region Copyright
       2             : // // -----------------------------------------------------------------------
       3             : // // <copyright company="Chinchilla Software Limited">
       4             : // //   Copyright Chinchilla Software Limited. All rights reserved.
       5             : // // </copyright>
       6             : // // -----------------------------------------------------------------------
       7             : #endregion
       8             : 
       9             : using System;
      10             : using System.Collections;
      11             : using System.Collections.Generic;
      12             : using System.Linq;
      13             : using System.Runtime.Serialization;
      14             : using System.Text;
      15             : using Cqrs.WebApi.Formatters.FormMultipart.Infrastructure;
      16             : using Cqrs.WebApi.Formatters.FormMultipart.Infrastructure.Extensions;
      17             : 
      18             : namespace Cqrs.WebApi.Formatters.FormMultipart.Converters
      19             : {
      20             :         /// <summary>
      21             :         /// Converts <see cref="object">objects</see> to multi-part form-data.
      22             :         /// </summary>
      23             :         public class ObjectToMultipartDataByteArrayConverter
      24           1 :         {
      25             :                 private MultipartFormatterSettings Settings { get; set; }
      26             : 
      27             :                 /// <summary>
      28             :                 /// Instantiate and initialise a new instance of <see cref="ObjectToMultipartDataByteArrayConverter"/>
      29             :                 /// </summary>
      30             :                 /// <param name="settings">The <see cref="MultipartFormatterSettings"/> to use.</param>
      31           1 :                 public ObjectToMultipartDataByteArrayConverter(MultipartFormatterSettings settings)
      32             :                 {
      33             :                         if (settings == null)
      34             :                                 throw new ArgumentNullException("settings");
      35             : 
      36             :                         Settings = settings;
      37             :                 }
      38             : 
      39             :                 /// <summary>
      40             :                 /// Converts the provided <paramref name="value"/> to multi-part form-data using the provided <paramref name="boundary"/>.
      41             :                 /// </summary>
      42           1 :                 public byte[] Convert(object value, string boundary)
      43             :                 {
      44             :                         if(value == null)
      45             :                                 throw new ArgumentNullException("value");
      46             :                         if (String.IsNullOrWhiteSpace(boundary))
      47             :                                 throw new ArgumentNullException("boundary");
      48             : 
      49             :                         List<KeyValuePair<string, object>> propertiesList = ConvertObjectToFlatPropertiesList(value);
      50             : 
      51             :                         byte[] buffer = GetMultipartFormDataBytes(propertiesList, boundary);
      52             :                         return buffer;
      53             :                 }
      54             : 
      55             :                 private List<KeyValuePair<string, object>> ConvertObjectToFlatPropertiesList(object value)
      56             :                 {
      57             :                         var propertiesList = new List<KeyValuePair<string, object>>();
      58             :                         if (value is FormData)
      59             :                         {
      60             :                                 FillFlatPropertiesListFromFormData((FormData) value, propertiesList);
      61             :                         }
      62             :                         else
      63             :                         {
      64             :                                 FillFlatPropertiesListFromObject(value, "", propertiesList);   
      65             :                         }
      66             : 
      67             :                         return propertiesList;
      68             :                 }
      69             : 
      70             :                 private void FillFlatPropertiesListFromFormData(FormData formData, List<KeyValuePair<string, object>> propertiesList)
      71             :                 {
      72             :                         foreach (var field in formData.Fields)
      73             :                         {
      74             :                                 propertiesList.Add(new KeyValuePair<string, object>(field.Name, field.Value));
      75             :                         }
      76             :                         foreach (var field in formData.Files)
      77             :                         {
      78             :                                 propertiesList.Add(new KeyValuePair<string, object>(field.Name, field.Value));
      79             :                         }
      80             :                 }
      81             : 
      82             :                 private void FillFlatPropertiesListFromObject(object obj, string prefix, List<KeyValuePair<string, object>> propertiesList)
      83             :                 {
      84             :                         if (obj != null)
      85             :                         {
      86             :                                 Type type = obj.GetType();
      87             : 
      88             :                                 if (obj is IDictionary)
      89             :                                 {
      90             :                                         var dict = obj as IDictionary;
      91             :                                         int index = 0;
      92             :                                         foreach (var key in dict.Keys)
      93             :                                         {
      94             :                                                 string indexedKeyPropName = String.Format("{0}[{1}].Key", prefix, index);
      95             :                                                 FillFlatPropertiesListFromObject(key, indexedKeyPropName, propertiesList);
      96             : 
      97             :                                                 string indexedValuePropName = String.Format("{0}[{1}].Value", prefix, index);
      98             :                                                 FillFlatPropertiesListFromObject(dict[key], indexedValuePropName, propertiesList);
      99             : 
     100             :                                                 index++;
     101             :                                         }
     102             :                                 }
     103             :                                 else if (obj is ICollection && !IsByteArrayConvertableToHttpFile(obj))
     104             :                                 {
     105             :                                         var list = obj as ICollection;
     106             :                                         int index = 0;
     107             :                                         foreach (var indexedPropValue in list)
     108             :                                         {
     109             :                                                 string indexedPropName = String.Format("{0}[{1}]", prefix, index);
     110             :                                                 FillFlatPropertiesListFromObject(indexedPropValue, indexedPropName, propertiesList);
     111             : 
     112             :                                                 index++;
     113             :                                         }
     114             :                                 }
     115             :                                 else if (type.IsCustomNonEnumerableType())
     116             :                                 {
     117             :                                         foreach (var propertyInfo in type.GetProperties())
     118             :                                         {
     119             :                                                 if (propertyInfo.CustomAttributes.Any(attribute => attribute.AttributeType == typeof(IgnoreDataMemberAttribute)))
     120             :                                                         continue;
     121             :                                                 string propName = string.IsNullOrWhiteSpace(prefix)
     122             :                                                         ? propertyInfo.Name
     123             :                                                         : String.Format("{0}.{1}", prefix, propertyInfo.Name);
     124             :                                                 object propValue = propertyInfo.GetValue(obj);
     125             : 
     126             :                                                 FillFlatPropertiesListFromObject(propValue, propName, propertiesList);
     127             :                                         }
     128             :                                 }
     129             :                                 else
     130             :                                 {
     131             :                                         propertiesList.Add(new KeyValuePair<string, object>(prefix, obj));
     132             :                                 }
     133             :                         }
     134             :                 }
     135             : 
     136             :                 private byte[] GetMultipartFormDataBytes(List<KeyValuePair<string, object>> postParameters, string boundary)
     137             :                 {
     138             :                         if (postParameters == null || !postParameters.Any())
     139             :                                 throw new Exception("Cannot convert data to multipart/form-data format. No data found.");
     140             : 
     141             :                         Encoding encoding = Encoding.UTF8;
     142             : 
     143             :                         using (var formDataStream = new System.IO.MemoryStream())
     144             :                         {
     145             :                                 bool needsClrf = false;
     146             : 
     147             :                                 foreach (var param in postParameters)
     148             :                                 {
     149             :                                         // Add a CRLF to allow multiple parameters to be added.
     150             :                                         // Skip it on the first parameter, add it to subsequent parameters.
     151             :                                         if (needsClrf)
     152             :                                                 formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));
     153             : 
     154             :                                         needsClrf = true;
     155             : 
     156             :                                         if (param.Value is HttpFile || IsByteArrayConvertableToHttpFile(param.Value))
     157             :                                         {
     158             :                                                 HttpFile httpFileToUpload = param.Value is HttpFile
     159             :                                                         ? (HttpFile) param.Value
     160             :                                                         : new HttpFile(null, null, (byte[]) param.Value);
     161             : 
     162             :                                                 // Add just the first part of this param, since we will write the file data directly to the Stream
     163             :                                                 string header = string.Format
     164             :                                                 (
     165             :                                                         "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
     166             :                                                         boundary,
     167             :                                                         param.Key,
     168             :                                                         httpFileToUpload.FileName ?? param.Key,
     169             :                                                         httpFileToUpload.MediaType ?? "application/octet-stream"
     170             :                                                 );
     171             : 
     172             :                                                 formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));
     173             : 
     174             :                                                 // Write the file data directly to the Stream, rather than serializing it to a string.
     175             :                                                 formDataStream.Write(httpFileToUpload.Buffer, 0, httpFileToUpload.Buffer.Length);
     176             :                                         }
     177             :                                         else
     178             :                                         {
     179             :                                                 string objString = "";
     180             :                                                 if (param.Value != null)
     181             :                                                 {
     182             :                                                         var typeConverter = param.Value.GetType().GetToStringConverter();
     183             :                                                         if (typeConverter != null)
     184             :                                                         {
     185             :                                                                 objString = typeConverter.ConvertToString(null, Settings.CultureInfo, param.Value);
     186             :                                                         }
     187             :                                                         else
     188             :                                                         {
     189             :                                                                 throw new Exception(String.Format("Type \"{0}\" cannot be converted to string", param.Value.GetType().FullName));
     190             :                                                         }
     191             :                                                 }
     192             : 
     193             :                                                 string postData = string.Format
     194             :                                                 (
     195             :                                                         "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
     196             :                                                         boundary,
     197             :                                                         param.Key,
     198             :                                                         objString
     199             :                                                 );
     200             :                                                 formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
     201             :                                         }
     202             :                                 }
     203             : 
     204             :                                 // Add the end of the request.  Start with a newline
     205             :                                 string footer = "\r\n--" + boundary + "--\r\n";
     206             :                                 formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));
     207             : 
     208             :                                 byte[] formData = formDataStream.ToArray();
     209             : 
     210             :                                 return formData;
     211             :                         }
     212             :                 }
     213             : 
     214             :                 private bool IsByteArrayConvertableToHttpFile(object value)
     215             :                 {
     216             :                         return value is byte[] && Settings.SerializeByteArrayAsHttpFile;
     217             :                 }
     218             :         }
     219             : }

Generated by: LCOV version 1.10