How to consume an MIME response attachment in C#? - c#

I am working with a java-written web service called JasperServer. I would like to obtain a file from the web service and save it on my local.
The web service provides a get() method; it requests a String of XML, and returns a String, and the target file as a MIME attachment:
public string get(string requestXmlString)
Right now I try to use a string to take in the response:
String res2 = webServiceClient.get(xmlInput);
It gives me an Exception:
Client found response content type of 'multipart/related; type="text/xml"; start="<7817FB68F69B037F5A5DEDE2AC105A65>"; boundary="----=_Part_2_1089980294.1393857885100"', but expected 'text/xml'.
The request failed with the error message:
------=_Part_2_1089980294.1393857885100
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: <7817FB68F69B037F5A5DEDE2AC105A65>
So my question is how to consume an String response with MIME attachment in C# .Net. And how to save it to my local?

You need a component for parsing MIME format described by RFC 822/2045 and extensions.
.NET framework doesn't include built-in classes for that.
I've good experience with Mime4Net component (it is based on port from Apache mime4j):
Stream mimeMsgStream;
var m = new MimeMessage(mimeMsgStream);
MimeMessage provides DOM for MIME structure and attachment content could be easily extracted. Also note that Mime4Net is free only for non-commercial usage.

I have the same problem with consuming Java WS.
On WCF3 config I only add the messageEncoding propery to binding definition and set it to "Mtom".
Something like this:
...
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="e3" messageEncoding="Mtom">

Related

WCF Binding SOAP 1.1 requests with both "application/xml" and "text/xml" ContentTypes

I am attempting to replace a legacy SOAP 1.1 web service with a new WCF service.
There are many existing clients and it is not feasible to change them.
I've successfully created a service and it works most clients with one vexing exception.
Since the old service was SOAP 1.1, I tried used a basicHttpBinding, like:
<bindings>
<basicHttpBinding>
<binding name="Whatever" />
</basicHttpBinding>
</bindings>
Most of my inbound messages are like the following example, and everything works fine:
POST http://MySoapWebServiceUrl/Service.svc HTTP/1.1
SOAPAction: DoSomething
Content-Type: text/xml;charset=UTF-8
Content-Length: 1234
Host: MySoapWebServiceUrl
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<xml:InputStuffHere />
</soap:Body>
</soap:Envelope>
My issue is that a couple of callers are sending exactly the same message except with Content-Type of 'application/xml' in the headers, and receiving this error:
Error: 415 Cannot process the message because the content type 'application/xml' was not the expected type 'text/xml'.
I've tried switching to binding with wsHttpBinding or webHttpBinding.
However, I cannot find a combination of settings on either of those bindings which would allow content types of both 'application/xml' and 'text/xml' and the SOAP 1.1 style "SOAPAction" addressing in the header.
I've also tried to implement a custom Text Message Encoder, starting with Microsoft's WCF example CustomTextMessageEncodingElement.
However, using a custom Text Messaging encoder I can set the MediaType to either 'application/xml' or 'text/xml'. But, not surprisingly, clients sending the specified Content-Type succeed but clients using the other Content-Type fail.
I've also attempted to set the MediaType including a wildcard like '*/xml', but that simply fails for all callers.
Is there a way to create a WCF binding so the service would accept a content type of either 'application/xml' or 'text/xml'?
I believe what I was trying to do is simply impossible.
I have concluded that WCF is an inappropriate technology for implementing a backwards-compatible replacement for a legacy SOAP web service which allowed various Content-Type values in the headers.
Instead, I have implemented a custom HttpModule using System.Web.IHttpModule.
Basic implementation details follow, for anyone else who has found themselves down this rabbit hole and needs a way out.
Code:
public class MyCustomHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += OnBegin;
}
private void OnBegin(object sender, EventArgs e)
{
var app = (HttpApplication) sender;
var context = app.Context;
if (context.Request.HttpMethod == "POST")
{
string soapActionHeader = context.Request.Headers["SOAPAction"];
byte[] buffer = new byte[context.Request.InputStream.Length];
context.Request.InputStream.Read(buffer, 0, buffer.Length);
context.Request.InputStream.Position = 0;
string rawRequest = Encoding.ASCII.GetString(buffer);
var soapEnvelope = new XmlDocument();
soapEnvelope.LoadXml(rawRequest);
string response = DoSomeMagic(soapActionHeader, soapEnvelope);
context.Response.ContentType = "text/xml";
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.Write(response);
}
else
{
//do something else
//returning a WSDL file for an appropriate GET request is nice
}
context.Response.Flush();
context.Response.SuppressContent = true;
context.ApplicationInstance.CompleteRequest();
}
private string DoSomeMagic(string soapActionHeader, XmlDocument soapEnvelope)
{
//magic happens here
}
public void Dispose()
{
//nothing happens here
//a Dispose() implementation is required by the IHttpModule interface
}
}
web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="MyCustomHttpModule" type="AppropriateNamespace.MyCustomHttpModule"/>
</modules>
</system.webServer>

Where does strange MIME types come from?

I have a web service for uploading files written in C#.
Front-end application is written in Javascript / HTML5 (using https://github.com/blueimp/jQuery-File-Upload)
Recently, I was reviewing server logs and found some strange MIME types for PDF files that where sent by client browser, for example:
application/unknown
application/force-download
application/force-download/n
application/force-download\n
[application/pdf]
Some of them are causing .NET framework throwing exception:
MultipartMemoryStreamProvider streamProvider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(streamProvider);
"Message Error parsing MIME multipart body part header byte 156 of data segment System.Byte[]."
I don't have a clue what to do with that.
Try checking the Content-Type in the request.
Content-Disposition:
form-data;
name="imagefile";
filename="C:\Users\Pictures\sid.png"
Content-Type:
(notice the blank Content-Type, it should be Content-Type: image/png )
// within WebAPI you can use code below to log the request body
string requestBody = await Request.Content.ReadAsStringAsync();

accessing php soapservice from C#

well i wanted to make a simple webservice that searches the db and return the data i know i can do it with mysql connector but this is just to learn how to use soaps here is the code for php soap server
require_once ('lib/nusoap.php');
$namespace = "http://localhost/webservice/index.php?wsdl";
$server = new soap_server();
$server->configureWSDL("DBQuery");
$server->wsdl->schemaTargetNamespace = $namespace;
$server->register(
'QueryMsg',
array('name'=>'xsd:string'),
array('return'=>'xsd:string'),
$namespace,
false,
'rpc',
'encoded',
'returns data from database');
function QueryMsg($query)
{
$con=mysqli_connect('localhost','root','','webserivce');
if (mysqli_connect_errno()) {
return "Failed to connect to MySQL: " . mysqli_connect_error();
}
if(!isset($query) or strpos(strtolower($query),'select')<=-1)
{
return "invalid order";
}
else
{
mysqli_real_escape_string($con,$query);
$result = mysqli_query($con,$query);
while($row = mysqli_fetch_array($result)) {
$data[] = $row;}
return json_encode($data);
}
}
// create HTTP listener
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$server->service($HTTP_RAW_POST_DATA);
exit();
?>
it works when i try calling it from a php soap client but when i try adding this http:// localhost /webservice/index.php in visual studio as service refernce to consume it from C# application i get an error here it is
The HTML document does not contain Web service discovery information.
Metadata contains a reference that cannot be resolved: 'http://localhost/webservice/index.php'.
The content type text/xml; charset=ISO-8859-1 of the response message does not match the content type of the binding (application/soap+xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 700 bytes of the response were: '<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body><SOAP-ENV:Fault><faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode><faultactor xsi:type="xsd:string"></faultactor><faultstring xsi:type="xsd:string">Operation &apos;&apos; is not defined in the WSDL for this service</faultstring><detail xsi:type="xsd:string"></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>'.
The remote server returned an error: (500) Internal Server Error.
If the service is defined in the current solution, try building the solution and adding the service reference again.
solved : well it was easy actually there is two ways either use WCF and change encoding to ISO-8859-1
or change encoding of the web service itself by adding this line $server->soap_defencoding = 'UTF-8'; after creating the soap server
I would try adding the service WSDL with a tool like SOAP U.I. and see what kind of errors you get back from that. It's a little more agnostic than adding a web reference with C#, and might disclose more details about why at the client level you can't consume this.
I'm happy to help you troubleshoot this with a little more information. Are you running this service on the same machine where you're running the client from? If it's complaining about being unable to correlate the file http://localhost/webservice/index.php to something I wonder if the discovery process is trying to evaluate a file that can't be found. I.E. an import operation in your source WSDL that points to a URL the client can't resolve.

wcf data service format the response as xml

I have created a wcf data service like this
public class Northwind : DataService< SelfServiceEntities >
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("SMS", EntitySetRights.AllRead
| EntitySetRights.WriteMerge
| EntitySetRights.WriteReplace);
}
}
and when I request this url
http://localhost:2242/Northwind.svc/SMS
I got this response
<?xml version="1.0" encoding="utf-8"?><feed xml:base="http://localhost:2242/Northwind.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><id>http://localhost:2242/Northwind.svc/SMS</id><title type="text">SMS</title><updated>2014-02-05T08:33:49Z</updated><link rel="self" title="SMS" href="SMS" /><entry><id>http://localhost:2242/Northwind.svc/SMS(1)</id><category term="SelfServiceModel.SM" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /><link rel="edit" title="SM" href="SMS(1)" /><title /><updated>2014-02-05T08:33:49Z</updated><author><name /></author><content type="application/xml"><m:properties><d:ID m:type="Edm.Int32">1</d:ID><d:number>1</d:number><d:body_ar>1</d:body_ar><d:body_en>1</d:body_en></m:properties></content></entry><entry><id>http://localhost:2242/Northwind.svc/SMS(2)</id><category term="SelfServiceModel.SM" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /><link rel="edit" title="SM" href="SMS(2)" /><title /><updated>2014-02-05T08:33:49Z</updated><author><name /></author><content type="application/xml"><m:properties><d:ID m:type="Edm.Int32">2</d:ID><d:number>55</d:number><d:body_ar>55</d:body_ar><d:body_en>55</d:body_en></m:properties></content></entry></feed>
my question
How can I make the response formatted as xml?
I made a research and I found this link
http://msdn.microsoft.com/en-us/library/cc668794%28v=vs.110%29.aspx
that states
OData builds on standard Internet protocols to make data services interoperable with applications that do not use the .NET Framework. Because you can use standard URIs to address data, your application can access and change data by using the semantics of representational state transfer (REST), specifically the standard HTTP verbs of GET, PUT, POST, and DELETE. This enables you to access these services from any client that can parse and access data that is transmitted over standard HTTP protocols.
OData defines a set of extensions to the Atom Publishing Protocol (AtomPub). It supports HTTP requests and responses in more than one data format to accommodate various client applications and platforms. An OData feed can represent data in Atom, JavaScript Object Notation (JSON), and as plain XML. While Atom is the default format, the format of the feed is specified in the header of the HTTP request. For more information, see OData: Atom Format and OData: JSON Format.

Getting MIME type from Web Service Response header

I invoke a web service provided by an external partner company. The web service returns files (.pdf, .dox, .png, ...) as a byte array.
If I would need to get the Header information (in detail I am interested in the content-type data) from the code, how can I get this information?
On our side, we are using VS 2010 and C# as language.
Here the code:
var client = new PublicService();
wsRequest request = new wsRequest();
var docInfo = new documentInfo();
docInfo.documentId = HSdocumentID;
docInfo.position = 1;
request.documentInfos = { docInfo };
byte[] doc = client.deliver(deliverRequest); //returns the file as byte array
The RESPONSE header would look like:
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body><ns2:deliverResponse xmlns:ns2="http://www.dalle.com/webservices/record/2012a">
<return>
<Include xmlns="http://www.w3.org/2004/08/xop/include"
href="cid:d3a#example.jaxws.sun.com"/>
</return></ns2:deliverResponse></S:Body></S:Envelope>
Content-Id: <d3a#example.jaxws.sun.com>
Content-Transfer-Encoding: binary
Content-Type: application/pdf <-- THIS IS THE INFO I NEED TO GET
Check out if there are SOAP headers on the Web Method call that answer your question
On the web method I do not have any properties/attributes that refer to the header. Is there a general way to get the Response header or is the web service that should provide features to get it?
(I provided an answer, rather than a comment, due to the code to be copied)

Categories