How to post multipart data in C# via WebRequest

This is a small code sample showing how you can post an image for example to a http server REST API endpoint.

 /// 
    /// Class to show how to do a MultiPartRequest
    /// For more information about MultiPart requests, look for this link : https://code.msdn.microsoft.com/windowsapps/WP8-Post-Multipart-Data-62fbbf72 
    /// 
    class MultipartRequest
    {
        #region Constants

        /// 
        /// The encoding in UTF8
        /// 
        private static readonly Encoding Encoding = Encoding.UTF8;

        /// 
        /// Guid of the cardholder to set the picture to.
        /// 
        private readonly Guid m_cardholderGuid;

        /// 
        /// The image to send.
        /// 
        private readonly Image m_image;

        /// 
        /// The Image Name, extracted from the Path to the image.
        /// 
        private readonly string m_imageName;

        /// 
        /// The server uri. Does not contain any query.
        /// 
        private readonly string m_uriServer;

        /// 
        /// The webSdkStudioWindow
        /// 
        private readonly WebSdkStudioWindow m_webSdkStudioWindow;

        #endregion

        #region Nested Classes and Structures

        public class FileParameter
        {
            #region Properties

            public string ContentType { get; set; }

            public byte[] File { get; set; }

            public string FileName { get; set; }

            #endregion

            #region Constructors

            public FileParameter(byte[] file) : this(file, null) { }

            public FileParameter(byte[] file, string filename) : this(file, filename, null) { }

            public FileParameter(byte[] file, string filename, string contenttype)
            {
                File = file;
                FileName = filename;
                ContentType = contenttype;
            }

            #endregion
        }

        #endregion

        #region Constructors

        public MultipartRequest(string image, string uriServer, Guid cardholderGuid, WebSdkStudioWindow webSdkStudioWindow)
        {
            m_image = Image.FromFile(image);
            m_uriServer = uriServer;
            string[] imageSplit = image.Split('\\');
            m_imageName = imageSplit.Last();
            m_cardholderGuid = cardholderGuid;
            m_webSdkStudioWindow = webSdkStudioWindow;
        }

        #endregion

        #region Public Methods

        public void UploadData()
        {
            // Generate post objects
            Dictionary postParameters = new Dictionary();

            //String parameters
            string myPicture = ImageToBase64String(m_image);
            byte[] myPictureArray = Encoding.GetBytes(myPicture);

            postParameters.Add("$myPicture", new FileParameter(myPictureArray, m_imageName, "image/png"));

            MultipartFormDataPost(
                m_uriServer + "entity?q=entity=" + m_cardholderGuid + ",Picture=$myPicture",
                postParameters);


        }

        #endregion

        #region Private Methods

        private static byte[] GetMultipartFormData(Dictionary postParameters, string boundary)
        {

            Stream formDataStream = new MemoryStream();
            bool needsClrf = false;
            try
            {
                foreach (var param in postParameters)
                {
                    // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added.
                    // Skip it on the first parameter, add it to subsequent parameters.
                    if (needsClrf)
                        formDataStream.Write(Encoding.GetBytes(Environment.NewLine), 0, Encoding.GetByteCount(Environment.NewLine));

                    needsClrf = true;

                    FileParameter value = param.Value as FileParameter;
                    if (value != null)
                    {
                        FileParameter fileToUpload = value;

                        // Add just the first part of this param, since we will write the file data directly to the Stream
                        string header = string.Format(
                            "--{0}Content-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"{3}Content-Type: {4}",
                            new StringBuilder(boundary).Append(Environment.NewLine),
                            param.Key,
                            fileToUpload.FileName ?? param.Key,
                            Environment.NewLine,
                            new StringBuilder(fileToUpload.ContentType ?? "application/octet-stream").Append(Environment.NewLine).Append(Environment.NewLine));

                        formDataStream.Write(Encoding.GetBytes(header), 0, Encoding.GetByteCount(header));

                        // Write the file data directly to the Stream, rather than serializing it to a string.
                        formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
                    }
                    else
                    {
                        string postData = string.Format("--{0}Content-Disposition: form-data; name=\"{1}\"{2}",
                            new StringBuilder(boundary).Append(Environment.NewLine),
                            param.Key,
                            new StringBuilder(Environment.NewLine).Append(Environment.NewLine).Append(param.Value));
                        formDataStream.Write(Encoding.GetBytes(postData), 0, Encoding.GetByteCount(postData));
                    }
                }

                // Add the end of the request.  Start with a newline
                string footer = new StringBuilder(Environment.NewLine).Append("--").Append(boundary).Append("--").Append(Environment.NewLine).ToString();
                formDataStream.Write(Encoding.GetBytes(footer), 0, Encoding.GetByteCount(footer));
            }
            catch (Exception ex)
            {
                throw new Exception("Network Issue : ", ex);
            }
            // Dump the Stream into a byte[]
            formDataStream.Position = 0;
            byte[] formData = new byte[formDataStream.Length];
            formDataStream.Read(formData, 0, formData.Length);
            formDataStream.Close();
            return formData;
        }

        private static string ImageToBase64String(Image image)
        {
            byte[] imageBytes = ImageToByteArray(image);
            return Convert.ToBase64String(imageBytes);
        }

        private static byte[] ImageToByteArray(Image image)
        {
            var ms = new MemoryStream();
            image.Save(ms, ImageFormat.Png);
            return ms.ToArray();
        }

        private void MultipartFormDataPost(string url, Dictionary postParameters)
        {
            string formDataBoundary = string.Format("----------{0:N}", Guid.NewGuid());
            string contentType = "multipart/form-data; boundary=" + formDataBoundary;

            byte[] formData = GetMultipartFormData(postParameters, formDataBoundary);

            PostForm(url, contentType, formData);
        }

        private void PostForm(string url, string contentType, byte[] formData)
        {
            Request request = new Request("POST", url);
            HttpWebRequest httpWebRequest = WebRequest.Create(request.Url) as HttpWebRequest;

            if (httpWebRequest == null)
            {
                throw new NullReferenceException("request is not a http request");
            }

            // Set up the request properties.
            httpWebRequest.Method = request.HttpMethod;
            httpWebRequest.ContentType = contentType;
            httpWebRequest.CookieContainer = new CookieContainer();
            httpWebRequest.ContentLength = formData.Length;
            httpWebRequest.Credentials = request.WebRequestCredentials;

            httpWebRequest.BeginGetRequestStream(result =>
            {
                try
                {
                    HttpWebRequest webRequest = (HttpWebRequest)result.AsyncState;
                    using (Stream requestStream = webRequest.EndGetRequestStream(result))
                    {
                        requestStream.Write(formData, 0, formData.Length);
                        requestStream.Close();
                    }
                    webRequest.BeginGetResponse(ar =>
                    {
                        try
                        {
                            WebResponse response = webRequest.EndGetResponse(ar);
                            Stream responseStream = response.GetResponseStream();
                            if (responseStream != null)
                            {
                                using (StreamReader sr = new StreamReader(responseStream))
                                {
                                    request.Response = sr.ReadToEnd();
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            request.Response = ex.Message;
                        }
                        m_webSdkStudioWindow.OnMultipartResponse(request);
                    }, null);
                }
                catch (Exception ex)
                {
                    request.Response = ex.Message;
                    m_webSdkStudioWindow.OnMultipartResponse(request);
                }
            }, httpWebRequest);

        }

        #endregion
    }

    #endregion
}

ESCAPING SPECIAL CHARS IN LDAP SEARCH FILTERS

When programming against any LDAP backend, it’s good to sanitize any user input that may go into a search filter. A typical case is authentication (login or single sing-on) applications, where an input username or email must be used to resolve a user’s distinct name (DN) in the LDAP directory. Continue reading “ESCAPING SPECIAL CHARS IN LDAP SEARCH FILTERS”

Create an Active Directory Parser based on Organisational Units (OUs)

LDAP queries look like this:

("CN=Dev-UK,OU=Distribution Groups,DC=gp,DC=gl,DC=google,DC=com");

What it means:

  • CN = Common Name
  • OU = Organizational Unit
  • DC = Domain Component

These are all parts of the X.500 Directory Specification, which defines nodes in a LDAP directory.

Each = pair is a search criteria.

With the query

("CN=Dev-UK,OU=Distribution Groups,DC=gp,DC=gl,DC=google,DC=com");

In effect the query is:

From the com Domain Component, find the google Domain Component, and then inside it the glDomain Component and then inside it the gp Domain Component.

In the gp Domain Component, find the Organizational Unit called Distribution Groups and then find the the object that has a common name of Dev-UK.

In order to list all users in this OU, you can write the following function:

public ArrayList EnumerateOU(string domainController, string OuDn, string username, string password)
 {
 ArrayList alObjects = new ArrayList();
 try
 {
 DirectoryEntry directoryObject = new DirectoryEntry("LDAP://" + domainController + "/" + OuDn);
 directoryObject.Username = username;
 directoryObject.Password = password;
 directoryObject.AuthenticationType = AuthenticationTypes.Secure;
 
 foreach (DirectoryEntry child in directoryObject.Children)
 {
 string childPath = child.Path.ToString();
 alObjects.Add(childPath.Remove(0, 7));
 //remove the LDAP prefix from the path
child.Close();
 child.Dispose();
 }
 directoryObject.Close();
 directoryObject.Dispose();
 }
 catch (DirectoryServicesCOMException e)
 {
 Console.WriteLine("An Error Occurred: " + e.Message.ToString());
 }
 return alObjects;
 }

Allow Swagger to return Content Type XML or JSON

At the moment only application/json is available. What is required to add application/xml as option to the selectbox?

Response

The most annoying thing is that two “Response Content Type” dropdowns appear in swagger-ui, one at the top of the operation (above the parameters) and one embedded within my Message Body parameter area (which is redundant and seems to be completely ignored).

For API calls with no Message Body parameter (i.e. a GET as opposed to PUT, POST) the UI works great and I have no complaints.

{
"swaggerVersion": "2.0",
"resourcePath": "/document_list",
"apis": [
{
"path": "/document_list",
"operations": [
{
"httpMethod": "GET",
"summary": "Search for documents based on a set of criteria",
"produces": [
"application/json",
"application/xml",
"application/atom+xml"
],

In App_Start>SwaggerConfig.cs

// Similar to Schema filters, Swashbuckle also supports Operation and Document filters:
//
// Post-modify Operation descriptions once they’ve been generated by wiring up one or more
// Operation filters.
//
c.OperationFilter();

Swagger XML and JSON options

 
public class CustomResponseType : IOperationFilter
        {
            public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
            {
                if (operation.produces.Contains("text/json"))
                {
                    operation.produces.Remove("text/json");
                }
                if (!operation.produces.Contains("application/json"))
                {
                    operation.produces.Add("application/json");
                }
                if (!operation.produces.Contains("application/xml"))
                {
                    operation.produces.Add("application/xml");
                }
              
            }
        }

Using ASMX webservices with HttpWebRequest in c# 4.0

If you want to call a .NET 4.0 C# web service, without using the WSDL or “Add Service Reference” in Microsoft Visual Studio 2015, you can use the following functions written in c#:

/// <summary>
/// Execute a Soap WebService call
/// </summary>
public override void Execute()
{
HttpWebRequest request = CreateWebRequest();
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<soap:Body>
<HelloWorld3 xmlns=""http://tempuri.org/"">
<parameter1>test</parameter1>
<parameter2>23</parameter2>
<parameter3>test</parameter3>
</HelloWorld3>
</soap:Body>
</soap:Envelope>");
using (Stream stream = request.GetRequestStream()) 
{ 
soapEnvelopeXml.Save(stream); 
}
using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream())) 
{ 
string soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
} 
}
}
/// <summary>
/// Create a soap webrequest to [Url]
/// </summary>
/// <returns></returns>
public HttpWebRequest CreateWebRequest()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(@"http://dev.nl/Rvl.Demo.TestWcfServiceApplication/SoapWebService.asmx"); 
webRequest.Headers.Add(@"SOAP:Action"); 
webRequest.ContentType = "text/xml;charset=\"utf-8\""; 
webRequest.Accept = "text/xml"; 
webRequest.Method = "POST"; 
return webRequest; 
}

Result

<?xml version=”1.0″ encoding=”utf-8″?><soap:Envelope xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema”><soap:Body><HelloWorld3Response xmlns=”http://tempuri.org/”><HelloWorld3Result>test</HelloWorld3Result></HelloWorld3Response></soap:Body></soap:Envelope>

 

You can use complex types in you’re request. I use fiddler to get the contents of the soap envelope.

Windows Azure – How to migrate data from SQL Server to a Storage account

Starting from this great article https://azure.microsoft.com/en-gb/documentation/articles/storage-dotnet-how-to-use-tables/ we started by including the required imports:

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Table;
using System.Configuration;
using System.Data.SqlClient;

Continue reading “Windows Azure – How to migrate data from SQL Server to a Storage account”