/// <summary>
        /// Uploads a document to the validator service for validation.  This is the
        /// "uploaded_file" method.
        /// </summary>
        /// <param name="documentData">the document to upload</param>
        /// <param name="options">configuration options</param>
        /// <returns>a MarkupValidatorResponse object</returns>
        public MarkupValidatorResponse CheckByUpload(byte[] documentData, MarkupValidatorOptions options)
        {
            if (options == null)
                options = new MarkupValidatorOptions();

            var request = this.ConstructPostRequest(
                options,
                writer => writer.Write("uploaded_file", "document.html", "text/html", documentData));

            return ThrottledParseResponse(request);
        }
        /// <summary>
        /// Asks the validator service to download and validate the document at specified public
        /// uri.  This is the "uri" method.
        /// </summary>
        /// <param name="documentUri">the location of the document to be validated</param>
        /// <param name="options">configuration options</param>
        /// <returns>a MarkupValidatorResponse object</returns>
        public MarkupValidatorResponse CheckByUri(Uri documentUri, MarkupValidatorOptions options)
        {
            if (options == null)
                options = new MarkupValidatorOptions();

            var queryStrings = options.ToDictionary();
            queryStrings.Add("uri", documentUri.ToString());
            var request = WebRequest.Create(AppendQueryString(_validator, queryStrings));

            return ThrottledParseResponse(request);
        }
        private WebRequest ConstructPostRequest(MarkupValidatorOptions options, Action<MultipartFormDataWriter> writePayload)
        {
            var request = WebRequest.Create(this._validator);
            var boundary = Guid.NewGuid().ToString();
            request.Method = "POST";
            request.ContentType = string.Concat("multipart/form-data; boundary=", boundary);

            using (var contents = new MemoryStream())
            {
                using (var writer = new MultipartFormDataWriter(contents, boundary))
                {
                    foreach (var pair in options.ToDictionary())
                    {
                        writer.Write(pair.Key, pair.Value);
                    }

                    writePayload(writer);
                }

                contents.Flush();
                request.ContentLength = contents.Length;

                using (var requestStream = request.GetRequestStream())
                {
                    contents.WriteTo(requestStream);
                }
            }
            return request;
        }
        /// <summary>
        /// Posts a document to the validator service for validation.  This is the "fragment"
        /// method.
        /// </summary>
        /// <param name="documentFragment">the document to upload</param>
        /// <param name="options">configuration options</param>
        /// <returns>a MarkupValidatorResponse object</returns>
        public MarkupValidatorResponse CheckByFragment(string documentFragment, MarkupValidatorOptions options)
        {
            if (options == null)
                options = new MarkupValidatorOptions();

            var request = this.ConstructPostRequest(
                options,
                writer => writer.Write("fragment", documentFragment));

            return ThrottledParseResponse(request);
        }