How to send multipart/mime SOAP request from ASP.NET MVC controller

Andrus 121 Reputation points
2024-03-23T07:08:08.8266667+00:00

SOAP server requires multipart SOAP request with XML file like

    Content-type: multipart/related;boundary="MIME_boundary";type="text/xml"; start="<soapPart>"

    	--MIME_boundary
    	Content-Type: text/xml;charset=utf-8
    	Content-Transfer-Encoding: 8bit
    	Content-ID: <soapPart>
    		<env:Envelope
    		xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
    		xmlns:id="http://x-road.eu/xsd/identifiers"
    		xmlns:xrd="http://x-road.eu/xsd/xroad.xsd">
    			<env:Header>
    				<xrd:client id:objectType="SUBSYSTEM">
    					<id:xRoadInstance>EE</id:xRoadInstance>
    					<id:memberClass>COM</id:memberClass>
    					<id:memberCode>00000000</id:memberCode>
    					<id:subsystemCode>misp-client</id:subsystemCode>
    				</xrd:client>
    				<xrd:service id:objectType="SERVICE">
    					<id:xRoadInstance>EE</id:xRoadInstance>
    					<id:memberClass>GOV</id:memberClass>
    					<id:memberCode>70000349</id:memberCode>
    					<id:subsystemCode>mkrliides</id:subsystemCode>
    					<id:serviceCode>uploadMime</id:serviceCode>
    					<id:serviceVersion>v1</id:serviceVersion>
    				</xrd:service>
    				<xrd:userId>EE00000000000</xrd:userId>
    				<xrd:id>4894e35d-bf0f-44a6-867a-8e51f1daa7e1</xrd:id>
    				<xrd:protocolVersion>4.0</xrd:protocolVersion>
    			</env:Header>
    			<env:Body>
    				<mta:uploadMime xmlns:mta="http://emta-v6.x-road.eu">
    					<request>
    						<target>KMD2</target>
    						<operation>Submit</operation>
    						<file href="cid:6f55eb41-7b72-40fe-bb7f-49bffefe9ae4"/>
    						<props>
    							<prop key="lang">et</prop>
    							<prop key="confirmation">TRUE</prop>
    						</props>
    					</request>
    				</mta:uploadMime>
    			</env:Body>
    		</env:Envelope>

--MIME_boundary
Content-Type:application/octet-stream
Content-Transfer-Encoding: binary
Content-Disposition: attachment; flename=test.xml
Content-ID: <6f55eb41-7b72-40fe-bb7f-49bffefe9ae4>
<xml>test</xml>
--MIME_boundary--

Another sample is in https://ncfailid.emta.ee/s/bS2XCJMF3KtErpC/download/example-mime-request.xml

Code to use it is generated from WSDL below in Visual Studio. Trying generated code using

 var cl = new webServiceInterfaceClient(new BasicHttpsBinding(BasicHttpsSecurityMode.Transport), new EndpointAddress("https://example.com"));
var rt = new UploadMimeRequestType()
{
  target = "target",
  operation = "operation",
  file = new UploadMimeRequestTypeFile() { href = "href", Value = Encoding.UTF8.GetBytes("xml content") },
  props = new PropertiesProp[0]
};
var ulreg = new uploadMime() { request = rt };
var tulem = await cl.uploadMimeAsync(new uploadMimeRequest(ulreg,
                                   Encoding.UTF8.GetBytes("xml xml")));

throws SOAP error body must have exactly one child element :

<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
	<SOAP-ENV:Body>
		<SOAP-ENV:Fault>
			<faultcode>Client.InvalidBody</faultcode>
			<faultstring>Malformed SOAP message: body must have exactly one child element</faultstring>
			<faultactor></faultactor>
			<detail>
				<faultDetail>1e2a2727-98f5-4d6d-ba1a-7a34dc6438fc</faultDetail>
			</detail>
		</SOAP-ENV:Fault>
	</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

.NET sends requests with two child elemnts in SOAP body:

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
	<s:Header>
		<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"></Action>
	</s:Header>
	<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
		<uploadMime xmlns="http://emta-v6.x-road.eu">
			<request xmlns="">
				<target>target</target>
				<operation>operation</operation>
				<file href="href">786D6C20636F6E74656E74</file>
				<props />
			</request>
		</uploadMime>
		<attachment>eG1sIHhtbA==</attachment>
	</s:Body>
</s:Envelope>

How to create such request in ASP.NET MVC controller in .NET 8 ?

WSDL of service is in https://ncfailid.emta.ee/s/ad5sNbJtJ5RRfEK/download/uploadmime.wsdl:

<?xml version="1.0" encoding="utf-8"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://emta-v6.x-road.eu" xmlns:xrd="http://x-road.eu/xsd/xroad.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="mkrliides-uploader" targetNamespace="http://emta-v6.x-road.eu">
    <wsdl:types>
        <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://emta-v6.x-road.eu">
            <import namespace="http://x-road.eu/xsd/xroad.xsd" schemaLocation="http://x-road.eu/xsd/xroad.xsd"/>
            <element name="uploadMime">
                <complexType>
                    <sequence>
                        <element name="request" type="tns:UploadMimeRequestType"/>
                    </sequence>
                </complexType>
            </element>
            <complexType name="UploadMimeRequestType">
                <sequence>
                    <element name="target" type="string">
                        <annotation>
                            <appinfo>
                                <xrd:title xml:lang="et">Teenuse nimi</xrd:title>
                                <xrd:notes xml:lang="et">Maksu- ja Tolliameti süsteemi lühinimi (TSD, KMD)</xrd:notes>
                            </appinfo>
                        </annotation>
                    </element>
                    <element minOccurs="0" name="operation" type="string">
                        <annotation>
                            <appinfo>
                                <xrd:title xml:lang="et">Meetodi nimi</xrd:title>
                                <xrd:notes xml:lang="et">Käivitatava meetodi nimi (KinnitaDeklaratsioon)</xrd:notes>
                            </appinfo>
                        </annotation>
                    </element>
                    <element minOccurs="0" name="file">
                        <complexType>
                            <simpleContent>
                                <extension base="hexBinary">
                                    <attribute name="href" type="string"/>
                                </extension>
                            </simpleContent>
                        </complexType>
                    </element>
                    <element minOccurs="0" name="props" type="tns:Properties">
                        <annotation>
                            <appinfo>
                                <xrd:title xml:lang="et">Manuse metaandmed</xrd:title>
                            </appinfo>
                        </annotation>
                    </element>
                </sequence>
            </complexType>
            <complexType name="Properties">
                <sequence>
                    <element maxOccurs="unbounded" name="prop">
                        <annotation>
                            <appinfo>
                                <xrd:title xml:lang="et">Parameetri väärtus</xrd:title>
                            </appinfo>
                        </annotation>
                        <complexType>
                            <simpleContent>
                                <extension base="string">
                                    <attribute name="key" type="string" use="required">
                                        <annotation>
                                            <appinfo>
                                                <xrd:title xml:lang="et">Parameetri nimi</xrd:title>
                                            </appinfo>
                                        </annotation>
                                    </attribute>
                                </extension>
                            </simpleContent>
                        </complexType>
                    </element>
                </sequence>
            </complexType>
            <element name="uploadMimeResponse">
                <complexType>
                    <sequence>
                        <element name="request" type="tns:UploadMimeRequestType"/>
                        <element name="response" type="tns:UploadMimeResponseType"/>
                    </sequence>
                </complexType>
            </element>
            <complexType name="UploadMimeResponseType">
                <sequence>
                    <element name="messages" type="tns:CodeAndDescription">
                        <annotation>
                            <appinfo>
                                <xrd:title xml:lang="et">Kaugsüsteemi vastus</xrd:title>
                            </appinfo>
                        </annotation>
                    </element>
                </sequence>
            </complexType>
            <complexType name="CodeAndDescription">
                <sequence>
                    <element maxOccurs="unbounded" name="item">
                        <complexType>
                            <sequence>
                                <element name="code" type="string">
                                    <annotation>
                                        <appinfo>
                                            <xrd:title xml:lang="et">Kood</xrd:title>
                                        </appinfo>
                                    </annotation>
                                </element>
                                <element name="description" type="string">
                                    <annotation>
                                        <appinfo>
                                            <xrd:title xml:lang="et">Kirjeldus</xrd:title>
                                        </appinfo>
                                    </annotation>
                                </element>
                            </sequence>
                        </complexType>
                    </element>
                </sequence>
            </complexType>
        </schema>
    </wsdl:types>
    <wsdl:message name="uploadMime">
        <wsdl:part element="tns:uploadMime" name="parameters"/>
        <wsdl:part name="attachment" type="xsd:base64Binary"/>
    </wsdl:message>
    <wsdl:message name="uploadMimeResponse">
        <wsdl:part element="tns:uploadMimeResponse" name="parameters"/>
    </wsdl:message>
    <wsdl:message name="xrdHeader">
        <wsdl:part element="xrd:client" name="client"/>
        <wsdl:part element="xrd:service" name="service"/>
        <wsdl:part element="xrd:id" name="id"/>
        <wsdl:part element="xrd:userId" name="userId"/>
        <wsdl:part element="xrd:issue" name="issue"/>
        <wsdl:part element="xrd:protocolVersion" name="protocolVersion"/>
    </wsdl:message>
    <wsdl:portType name="webServiceInterface">
        <wsdl:operation name="uploadMime">
            <wsdl:documentation>
                <xrd:title xml:lang="et">Failide edastamise teenus</xrd:title>
            </wsdl:documentation>
            <wsdl:input message="tns:uploadMime"/>
            <wsdl:output message="tns:uploadMimeResponse"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="soapBindings" type="tns:webServiceInterface">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="uploadMime">
            <soap:operation soapAction=""/>
            <xrd:version>v1</xrd:version>
            <wsdl:input>
                <mime:multipartRelated xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/">
                    <mime:part>
                        <soap:header message="tns:xrdHeader" part="client" use="literal"/>
                        <soap:header message="tns:xrdHeader" part="service" use="literal"/>
                        <soap:header message="tns:xrdHeader" part="id" use="literal"/>
                        <soap:header message="tns:xrdHeader" part="protocolVersion" use="literal"/>
                        <soap:header message="tns:xrdHeader" part="userId" use="literal"/>
                        <soap:body parts="parameters" use="literal"/>
                    </mime:part>
                    <mime:part>
                        <mime:content part="attachment" type="application/octet-stream"/>
                    </mime:part>
                </mime:multipartRelated>
            </wsdl:input>
            <wsdl:output>
                <soap:header message="tns:xrdHeader" part="client" use="literal"/>
                <soap:header message="tns:xrdHeader" part="service" use="literal"/>
                <soap:header message="tns:xrdHeader" part="id" use="literal"/>
                <soap:header message="tns:xrdHeader" part="protocolVersion" use="literal"/>
                <soap:header message="tns:xrdHeader" part="userId" use="literal"/>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="webService">
        <wsdl:port binding="tns:soapBindings" name="port">
            <soap:address location="http://SERVER_URL"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,458 questions
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,237 questions
ASP.NET
ASP.NET
A set of technologies in the .NET Framework for building web applications and XML web services.
3,311 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,375 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Andre Baltieri 160 Reputation points MVP
    2024-03-25T00:31:29.41+00:00

    I'm not the SOAP guy, but here is what Copilot told me👇


    To send a multipart/mime SOAP request from an ASP.NET MVC controller, you can follow these steps:

    1. Create the Multipart/MIME Request: First, construct your SOAP request with the necessary XML content. Next, create a multipart/mime request that includes both the SOAP XML and any additional files (if needed).
    2. Use HttpClient to Send the Request: In your ASP.NET MVC controller, use HttpClient to send the multipart/mime request. Add the SOAP XML as one part of the request and any other files (if applicable) as additional parts.
    3. Example Code: Here’s an example of how you might send a multipart/mime SOAP request using HttpClient:
    using System;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;
    public class MyController : Controller
    {
        public async Task<IActionResult> SendSoapRequest()
        {
            try
            {
                using var client = new HttpClient();
                using var content = new MultipartFormDataContent();
                // Add the SOAP XML
                var soapXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
                                <soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
                                    <!-- Your SOAP content here -->
                                </soap:Envelope>";
                var soapContent = new StringContent(soapXml, Encoding.UTF8, "text/xml");
                content.Add(soapContent, "file", "soap.xml");
                // Add any additional files (if needed)
                // var fileBytes = ... // Read your file content
                // var fileContent = new ByteArrayContent(fileBytes);
                // content.Add(fileContent, "file", "filename.ext");
                // Send the request
                var response = await client.PostAsync("https://example.com/your-soap-endpoint", content);
                if (response.IsSuccessStatusCode)
                {
                    // Process the success response
                    return Ok("SOAP request sent successfully!");
                }
                else
                {
                    // Handle the error response
                    return BadRequest("Error sending SOAP request.");
                }
            }
            catch (Exception ex)
            {
                // Handle exceptions
                return StatusCode(500, $"An error occurred: {ex.Message}");
            }
        }
    }
    
    
    1. Adjust the Code: Replace the placeholder SOAP XML and endpoint URL with your actual values. If you need to include additional files (e.g., attachments), add them as separate parts in the MultipartFormDataContent.

    Remember to handle exceptions appropriately and adjust the code to match your specific SOAP service requirements. 🚀

    For more examples and details, you can refer to the following resources:

    Adjust the Code:

    Replace the placeholder SOAP XML and endpoint URL with your actual values.
    
       If you need to include additional files (e.g., attachments), add them as separate parts in the `MultipartFormDataContent`.
      
    

    Remember to handle exceptions appropriately and adjust the code to match your specific SOAP service requirements. 🚀

    For more examples and details, you can refer to the following resources:

    Stack Overflow: How to send multipart/mime SOAP request

    Send multipart form data to ASP.NET Core Web API

    Medium: Send multi-part content to an API from a .NET Core API (.NET 5.0)