/// <summary> /// Sends a multipart HTTP POST request (useful for posting files) but doesn't call GetResponse on it. /// </summary> /// <param name="request">The HTTP request.</param> /// <param name="requestHandler">The request handler.</param> /// <param name="parts">The parts to include in the POST entity.</param> internal static void PostMultipartNoGetResponse(this HttpWebRequest request, IDirectWebRequestHandler requestHandler, IEnumerable <MultipartPostPart> parts) { Contract.Requires <ArgumentNullException>(request != null); Contract.Requires <ArgumentNullException>(requestHandler != null); Contract.Requires <ArgumentNullException>(parts != null); Reporting.RecordFeatureUse("MessagingUtilities.PostMultipart"); parts = parts.CacheGeneratedResults(); string boundary = Guid.NewGuid().ToString(); string initialPartLeadingBoundary = string.Format(CultureInfo.InvariantCulture, "--{0}\r\n", boundary); string partLeadingBoundary = string.Format(CultureInfo.InvariantCulture, "\r\n--{0}\r\n", boundary); string finalTrailingBoundary = string.Format(CultureInfo.InvariantCulture, "\r\n--{0}--\r\n", boundary); var contentType = new ContentType("multipart/form-data") { Boundary = boundary, CharSet = Channel.PostEntityEncoding.WebName, }; request.Method = "POST"; request.ContentType = contentType.ToString(); long contentLength = parts.Sum(p => partLeadingBoundary.Length + p.Length) + finalTrailingBoundary.Length; if (parts.Any()) { contentLength -= 2; // the initial part leading boundary has no leading \r\n } request.ContentLength = contentLength; var requestStream = requestHandler.GetRequestStream(request); try { StreamWriter writer = new StreamWriter(requestStream, Channel.PostEntityEncoding); bool firstPart = true; foreach (var part in parts) { writer.Write(firstPart ? initialPartLeadingBoundary : partLeadingBoundary); firstPart = false; part.Serialize(writer); part.Dispose(); } writer.Write(finalTrailingBoundary); writer.Flush(); } finally { // We need to be sure to close the request stream... // unless it is a MemoryStream, which is a clue that we're in // a mock stream situation and closing it would preclude reading it later. if (!(requestStream is MemoryStream)) { requestStream.Dispose(); } } }
/// <summary> /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity. /// </summary> /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param> /// <returns> /// The stream the caller should write out the entity data to. /// </returns> /// <exception cref="ProtocolException">Thrown for any network error.</exception> /// <remarks> /// <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/> /// and any other appropriate properties <i>before</i> calling this method. /// Callers <i>must</i> close and dispose of the request stream when they are done /// writing to it to avoid taking up the connection too long and causing long waits on /// subsequent requests.</para> /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a /// <see cref="ProtocolException"/> to abstract away the transport and provide /// a single exception type for hosts to catch.</para> /// </remarks> public Stream GetRequestStream(HttpWebRequest request) { _action(request); return(_wrappedHandler.GetRequestStream(request)); }