Exemplo n.º 1
0
        /// <summary>
        /// This method is used by both WS and Cloud implementations of AssembleDocument to convert an AssemblyResult to an AssembleDocumentResult.
        /// </summary>
        /// <param name="template">The template associated with the <c>AssemblyResult</c>.</param>
        /// <param name="asmResult">The <c>AssemblyResult</c> to convert.</param>
        /// <param name="docType">The type of document contained in the result.</param>
        /// <returns>An <c>AssembleDocumentResult</c>, which contains the same document as the <c>asmResult</c>.</returns>
        internal static AssembleDocumentResult ConvertAssemblyResult(Template template, AssemblyResult asmResult, DocumentType docType)
        {
            AssembleDocumentResult result          = null;
            MemoryStream           document        = null;
            StreamReader           ansRdr          = null;
            List <NamedStream>     supportingFiles = new List <NamedStream>();

            // Create the list of pending assemblies.
            IEnumerable <Template> pendingAssemblies =
                asmResult.PendingAssemblies == null
                                ? new List <Template>()
                                : from pa in asmResult.PendingAssemblies
                select new Template(
                    Path.GetFileName(pa.TemplateName), template.Location.Duplicate(), pa.Switches);

            for (int i = 0; i < asmResult.Documents.Length; i++)
            {
                switch (asmResult.Documents[i].Format)
                {
                case OutputFormat.Answers:
                    ansRdr = new StreamReader(new MemoryStream(asmResult.Documents[i].Data));
                    break;

                case OutputFormat.JPEG:
                case OutputFormat.PNG:
                    // If the output document is plain HTML, we might also get additional image files in the
                    // AssemblyResult that we need to pass on to the caller.
                    supportingFiles.Add(new NamedStream(asmResult.Documents[i].FileName, new MemoryStream(asmResult.Documents[i].Data)));
                    break;

                default:
                    document = new MemoryStream(asmResult.Documents[i].Data);
                    if (docType == DocumentType.Native)
                    {
                        docType = Document.GetDocumentType(asmResult.Documents[i].FileName);
                    }
                    break;
                }
            }

            if (document != null)
            {
                result = new AssembleDocumentResult(
                    new Document(template, document, docType, supportingFiles.ToArray(), asmResult.UnansweredVariables),
                    ansRdr == null ? null : ansRdr.ReadToEnd(),
                    pendingAssemblies.ToArray(),
                    asmResult.UnansweredVariables
                    );
            }

            return(result);
        }
        /// <summary>
        ///     Assemble a document from the given template, answers and settings.
        /// </summary>
        /// <param name="template">An instance of the Template class.</param>
        /// <param name="answers">
        ///     Either an XML answer string, or a string containing encoded
        ///     interview answers as posted from a HotDocs browser interview.
        /// </param>
        /// <param name="settings">An instance of the AssembleDocumentResult class.</param>
        /// <include file="../Shared/Help.xml" path="Help/string/param[@name='logRef']" />
        /// <returns>An AssemblyResult object containing all the files and data resulting from the request.</returns>
        public AssembleDocumentResult AssembleDocument(Template template, TextReader answers,
                                                       AssembleDocumentSettings settings, string logRef = "")
        {
            if (template == null)
            {
                throw new ArgumentNullException("template");
            }

            using (var client = new HttpClient())
            {
                AssembleDocumentResult adr  = null;
                var packageTemplateLocation = (PackageTemplateLocation)template.Location;
                var packageId = packageTemplateLocation.PackageID;
                var of        = ConvertFormat(settings.Format);
                var timestamp = DateTime.UtcNow;

                var hmac = HMAC.CalculateHMAC(
                    SigningKey,
                    timestamp,
                    SubscriberId,
                    packageId,
                    template.FileName,
                    false,
                    logRef,
                    of,
                    settings.Settings);

                var urlBuilder =
                    new StringBuilder().AppendFormat("{0}/assemble/{1}/{2}/{3}?" +
                                                     "format={4}&" +
                                                     "encodefilenames={5}&" +
                                                     "billingref={6}{7}",
                                                     HostAddress, SubscriberId, packageId, Uri.EscapeDataString(template.FileName),
                                                     of,
                                                     true,
                                                     Uri.EscapeDataString(logRef),
                                                     GetRetrieveFromHubParam());

                if (settings.Settings != null)
                {
                    foreach (var kv in settings.Settings)
                    {
                        urlBuilder.AppendFormat("&{0}={1}", kv.Key, kv.Value ?? "");
                    }
                }

                var request = new HttpRequestMessage
                {
                    RequestUri = new Uri(urlBuilder.ToString()),
                    Method     = HttpMethod.Post
                };

                request.Headers.Add("x-hd-date", timestamp.ToString("yyyy-MM-ddTHH:mm:ssZ"));
                request.Headers.Authorization = new AuthenticationHeaderValue("basic", hmac);

                var stringContent = answers == null
                    ? new StringContent(string.Empty)
                    : new StringContent(answers.ReadToEnd());

                request.Content = stringContent;

                request.Content.Headers.TryAddWithoutValidation("Content-Type", "text/xml");

                var result = client.SendAsync(request).Result;

                var parser = new MultipartMimeParser();

                HandleStatusCode(result);

                var streamResult = result.Content.ReadAsStreamAsync().Result;

                var streams = new List <MemoryStream>();

                using (var resultsStream = new MemoryStream())
                {
                    // Each part is written to a file whose name is specified in the content-disposition
                    // header, except for the AssemblyResult part, which has a file name of "meta0.xml",
                    // and is parsed into an AssemblyResult object.
                    parser.WritePartsToStreams(
                        streamResult,
                        h =>
                    {
                        var fileName = GetFileNameFromHeaders(h);
                        if (fileName == null)
                        {
                            return(Stream.Null);
                        }

                        if (fileName.Equals("meta0.xml", StringComparison.OrdinalIgnoreCase))
                        {
                            return(resultsStream);
                        }

                        var stream = new MemoryStream();
                        streams.Add(stream);
                        return(stream);
                    },
                        (new ContentType(result.Content.Headers.ContentType.ToString())).Boundary);

                    if (resultsStream.Position <= 0)
                    {
                        return(null);
                    }

                    resultsStream.Position = 0;
                    var serializer = new XmlSerializer(typeof(AssemblyResult));
                    var asmResult  = (AssemblyResult)serializer.Deserialize(resultsStream);

                    if (asmResult == null)
                    {
                        return(adr);
                    }

                    for (var i = 0; i < asmResult.Documents.Length; i++)
                    {
                        asmResult.Documents[i].Data = streams[i].ToArray();
                        streams[i].Dispose();
                    }

                    adr = Util.ConvertAssemblyResult(template, asmResult, settings.Format);
                }

                return(adr);
            }
        }