Link to home
Start Free TrialLog in
Avatar of SimonPrice3376
SimonPrice3376

asked on

WCF multipart / related messages not giving soap message and attachments

I have a WCF application that I am writing that needs to replace a system from an existing company in which we are breaking ties.  In doing so we need to match the output exactly so that when consumers of the service are switched over they see no difference.

As such I need to return a SOAP Message and Attachments in the following format

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 2689848
Content-Type: multipart/related; boundary="----=_Part_232409_5104439565.9228175693507"; type="text/xml"; start="2324051044.3956609228183.xxxxxxv"
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
Request-Context: appId=cid-v1:6f6ba915-178d-414c-ae2d-92a6d8bc22c7
X-Powered-By: ASP.NET
Date: Wed, 24 Jun 2020 10:12:26 GMT



------=_Part_232409_5104439565.9228175693507
Content-Type: text/xml
Content-Transfer-Encoding: 8bit
Content-ID: <2324051044.3956609228183.xxxxxxv>
Content-Length: 39489

<?xml version="1.0" encoding="iso-8859-1"?>
<SOAP-ENV:Envelope .....
<!-- SOAP ENVELOPE HERE -->

</SOAP-ENV:Envelope>
------=_Part_232409_5104439565.9228175693507

<!-- ATTACHMENTS HERE -->
Content-Type: application/octet-stream
Content-Transfer-Encoding: 8bit
Content-ID: 40094398@xxx.xxx.uk
Content-Disposition: attachment; filename=filenamehere.pdf
Content-Length: 816189

...
stream
...
endstream

<!-- continue all other files here -->

------=_Part_232409_5104439565.9228175693507--

Open in new window


What I actually get is

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: multipart/related----------8d818405a5cdabf type="text/xml" <!-- As I am unable to get the soap envelop in here I cant give it a start -->
Server: Microsoft-IIS/10.0
Set-Cookie: ASP.NET_SessionId=cpicytalapjbmqjw4zvbqgdo; path=/; HttpOnly; SameSite=Lax
X-Id: 45625625EFA22AD
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcUHJvamVjdHNcVGVycmFRdWVzdFxQUDJcVFEtTFBBLUNvbm5lY3RvclxUUS5MUEFDb25uZWN0b3JcVFEuTFBBQ29ubmVjdG9yLlNlcnZpY2VcUHJvcG9zYWxTZXJ2aWNlLnN2Yw==?=
X-Powered-By: ASP.NET
Date: Wed, 24 Jun 2020 12:13:16 GMT
Content-Length: 3727403

------------8d818405a5cdabf
Content-Type: application/octet-stream
Content-Transfer-Encoding: 8bit
Content-ID: AttachmentSummary.pdf
Content-Disposition: attachment; filename=AttachmentSummary.pdf
Contnent-Length: 192439

Open in new window


The code that is currently in place is

[WebMethod]
        public getProposalResponse getProposal(getProposalRequest request)
        //public getProposalResponse getProposal(getProposalRequest request)
        {
            if (request == null)
            {
                // Throw fault exception
                ErrorResponseHelper.MalformedResponse();
            }
            var privateKey = _privateKeyService.GetPrivateKey();

            var response = _getProposalService.GetProposal(request.getProposal);

            var fileByteArray = _blobStorageService.DownloadProposalsAsByteArray(response.Proposal.FileAttachments).ToArray();
            var FileStream = _blobStorageService.DownloadProposalsAsStream(response.Proposal.FileAttachments);
            response.Proposal.Attachments = fileByteArray;

            var ctx = WebOperationContext.Current;
            //ctx.OutgoingResponse.ContentType = $"multipart/related";

            var context = HttpContext.Current;
            sendFiles(context, response.Proposal.FileAttachments.ToList(), response);
            return response;
        }

        private void WriteFilePart(FileAttachmentStructure file, byte[] boundarybytes, Stream memStream)
        {

            var sb = new StringBuilder();
            sb.AppendLine($"Content-Type: application/octet-stream");
            sb.AppendLine($"Content-Transfer-Encoding: 8bit");
            sb.AppendLine($"Content-ID: {file.FileName}");
            sb.AppendLine($"Content-Disposition: attachment; filename={file.FileName}");
            sb.AppendLine($"Contnent-Length: {file.Data.Length}");

            memStream.Write(boundarybytes, 0, boundarybytes.Length);
            var headerbytes = System.Text.Encoding.UTF8.GetBytes(sb.ToString());
            memStream.Write(headerbytes, 0, headerbytes.Length);

            memStream.Write(file.Data, 0, file.Data.Length);


        }

        private void sendFiles(HttpContext context, List<FileAttachmentStructure> fileByteArray, getProposalResponse response)
        {
            // I dont like have two different context here 
            // using httpcontext I dont get the multipart/related content type
            var ctx = WebOperationContext.Current;
            ctx.OutgoingResponse.ContentType = $"multipart/related{formDataBoundary} type=\"text/xml\"";

            context.Response.Clear();
            context.Response.StatusCode = (int)HttpStatusCode.OK;

            string formDataBoundary = $"----------{DateTime.Now.Ticks.ToString("x"):N}";
            context.Response.ContentEncoding = System.Text.Encoding.UTF8;


            context.Response.Headers.Add("X-Id", "45625625EFA22AD");

            Stream memStream = new MemoryStream();
            var boundarybytes = System.Text.Encoding.UTF8.GetBytes("--" + formDataBoundary + "\r\n");
            var endBoundaryBytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + formDataBoundary + "--");
            var i = 0;
            foreach (var file in fileByteArray)
            {
                WriteFilePart(file, boundarybytes, memStream);
                boundarybytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + formDataBoundary + "\r\n");
            }

            memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);

            using (Stream ResponseStream = context.Response.OutputStream)
            {
                memStream.Position = 0;
                byte[] tempBuffer = new byte[memStream.Length];
                memStream.Read(tempBuffer, 0, tempBuffer.Length);
                memStream.Close();
                ResponseStream.Write(tempBuffer, 0, tempBuffer.Length);
            }
        }

        public getProposalListResponse getProposalList(GetProposalListRequest request)
        {
            if (request == null)
            {
                // Throw fault exception
                ErrorResponseHelper.MalformedResponse();
            }

            var validationErrors = _modelValidationService.ValidateProposalListRequest(request);
            if (validationErrors.Any())
            {
                ErrorResponseHelper.GetErrorResponse(
                    validationErrors,
                    string.Empty,
                    request.getProposalList.lpaCode,
                    string.Empty,
                    request.getProposalList.version);
            }

            var response = _proposalListService.GetProposalList(request);
            return response;
        }

Open in new window


I would appreciate some help in getting the message and the files attached accordingly in the format that has been described above.

Thanks
This question needs an answer!
Become an EE member today
7 DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.