Accept UTF-8 encoded strings in ASP.NET WebService - asp.net

I've got a ASP.NET WebService that looks something like this:
[WebMethod]
public static void DoSomethingWithStrings(string stringA, string stringB)
{
// and so on
}
An third party application should call this webservice. However this application encodes strings as UTF-8 and all umlauts are replaced by '??'. I can view the call and the special characters are formatted well:
<?xml version="1.0" encoding="utf-8" ?>
<!-- ... -->
<SoapCall>
<DoSomethingWithStrings>
<stringA>Ä - Ö - Ü</stringA>
<stringB>This is a test</stringB>
</DoSomethingWithStrings>
</SoapCall>
This produces the following output, when I simply print the strings inside the webservice method:
?? - ?? - ??
This is a test
How can I configure the WebService to accept UTF-8 encoded strings?
Update
Fiddler also tells me that the content-type charset of the http request is UTF-8.
Update 2
I tried to add following code to global.asax for debugging purposes:
public void Application_BeginRequest(object sender, EventArgs e)
{
using (var reader = new System.IO.StreamReader(Request.InputStream))
{
string str = reader.ReadToEnd();
}
}
This reads the actual SOAP call. The StreamReaders encoding is set to UTF-8. The SOAP call looks correct:
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<DoSomethingWithStrings xmlns="http://www.tempuri.org/">
<stringA>Ä - Ö - Ü</stringA>
<stringB>This is a test!</stringB>
</DoSomethingWithStrings>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In the web.config file the globalization settings are set correctly:
<globalization requestEncoding="UTF-8" responseEncoding="UTF-8" culture="de-DE" uiCulture="de-DE" />
So it looks like something that deserializes the SOAP message does not use UTF-8 but ASCII encoding.

Finally it turns out that something went wrong within accepting HTTP-Messages. I don't actually know what manipulates the HTTP-Request, but I found a workaround for this. Eventhough Fiddler showed me the correct content type (text/xml; charset=utf-8) in my Application_BeginRequest the Request.RequestContext.HttpContext.Request.ContentType was just text/xml, which lead to a fallback to default (ASCII) encoding within the ASMX serializer. I've added the following code to the Application_BeginRequest handler and everything works for now.
if (Request.RequestContext.HttpContext.Request.ContentType.Equals("text/xml"))
{
Request.RequestContext.HttpContext.Request.ContentType = "text/xml; charset=UTF-8";
}
Thanks for your help!

Try this:-
byte[] bytes=Encoding.UTF8.GetBytes(yourString);
NOTE:-
Strings never contain anything utf-* or anything else encoded

The SOAP call is being decoded as ASCII somewhere - each of the umlauts are 2 bytes with high bit being set, which turns into ?? when decoded as ASCII.
So, something like this is happening:
byte[] bytesSentFromClient = Encoding.UTF8.GetBytes("Ä - Ö - Ü");
string theStringIThenReceiveInMyMethod = Encoding.ASCII.GetString(bytesSentFromClient);
Console.WriteLine(theStringIThenReceiveInMyMethod);
//?? - ?? - ??
To verify this is happening for sure, you should compare stringA == "Ä - Ö - Ü" rather than printing it somewhere.
I guess you could start by doing a project-wide search for "ASCII" and then work from there if you find anything.
You could also try
<globalization requestEncoding="utf-8" responseEncoding="utf-8"/>
Under the <system.web> tag in Web.config file.

I had the same problem. Asmx web service converted my UTF-8 to ASCII or, better to say to ??????. Your post helped me a lot.
The solution I found was to change version of SOAP protocol from 1.1 to 1.2
I mean:
POST /WebService1.asmx HTTP/1.1
Host: www.tempuri.org
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.tempuri.org/HelloWorld"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<HelloWorld xmlns="http://www.tempuri.org/">
<inputParam>Привет</inputParam>
</HelloWorld>
</soap:Body>
</soap:Envelope>
had the problem. But when I changed my request to SOAP 1.2:
POST /WebService1.asmx HTTP/1.1
Host: www.tempuri.org
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<HelloWorld xmlns="http://www.tempuri.org/">
<inputParam>Привет</inputParam>
</HelloWorld>
</soap12:Body>
</soap12:Envelope>
The issue was solved.

Related

No package.xml not found despite it is presented

I want to deploy an Apex class via REST API in a "single package" way. The deployment process begins and then fails with "No package.xml found" error. The manifest file is put directly in the root of the archive, however the API tells me that there is no manifest.
My request body looks in the following way
----------------------------BOUNDARY
Content-Disposition: form-data; name="entity_content"
Content-Type: application/json
{
"deployOptions": {
"allowMissingFiles": false,
"autoUpdatePackage": false,
"checkOnly": false,
"ignoreWarnings": false,
"performRetrieve": false,
"purgeOnDelete": false,
"rollbackOnError": true,
"runTests": [],
"singlePackage": true,
"testLevel": "NoTestRun"
}
}
----------------------------BOUNDARY
Content-Disposition: form-data; name="file"; filename="deploy.zip"
Content-Type: application/zip
UEsDBAoAAAAAAM4EL1Zi1oXYuQAAALkAAAALAAAAcGFja2FnZS54bWw8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYtOCI/PjxQYWNrYWdlIHhtbG5zPSJodHRwOi8vc29hcC5zZm9yY2UuY29tLzIwMDYvMDQvbWV0YWRhdGEiPjx0eXBlcz48bWVtYmVycz5BPC9tZW1iZXJzPjxuYW1lPkFwZXhDbGFzczwvbmFtZT48L3R5cGVzPjx2ZXJzaW9uPjU2LjA8L3ZlcnNpb24+PC9QYWNrYWdlPlBLAwQKAAAAAADOBC9WAAAAAAAAAAAAAAAACAAAAGNsYXNzZXMvUEsDBAoAAAAAAM4EL1aRdfeXigAAAIoAAAAWAAAAY2xhc3Nlcy9BLmNscy1tZXRhLnhtbDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04Ij8+PEFwZXhDbGFzcyB4bWxucz0iaHR0cDovL3NvYXAuc2ZvcmNlLmNvbS8yMDA2LzA0L21ldGFkYXRhIj48YXBpVmVyc2lvbj41Ni4wPC9hcGlWZXJzaW9uPjwvQXBleENsYXNzPlBLAwQKAAAAAADOBC9WnojzmRIAAAASAAAADQAAAGNsYXNzZXMvQS5jbHNwdWJsaWMgY2xhc3MgQSB7IH1QSwECFAAKAAAAAADOBC9WYtaF2LkAAAC5AAAACwAAAAAAAAAAAAAAAAAAAAAAcGFja2FnZS54bWxQSwECFAAKAAAAAADOBC9WAAAAAAAAAAAAAAAACAAAAAAAAAAAABAAAADiAAAAY2xhc3Nlcy9QSwECFAAKAAAAAADOBC9WkXX3l4oAAACKAAAAFgAAAAAAAAAAAAAAAAAIAQAAY2xhc3Nlcy9BLmNscy1tZXRhLnhtbFBLAQIUAAoAAAAAAM4EL1aeiPOZEgAAABIAAAANAAAAAAAAAAAAAAAAAMYBAABjbGFzc2VzL0EuY2xzUEsFBgAAAAAEAAQA7gAAAAMCAAAAAA==
----------------------------BOUNDARY--
where Base64-encoded Zip file has the following structure
package.xml
classes/
A.cls
A.cls-meta.xml
and those three files look in the following way.
(package.xml)
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>A</members>
<name>ApexClass</name>
</types>
<version>56.0</version>
</Package>
(A.cls)
public class A { }
(a.cls-meta.xml)
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>56.0</apiVersion>
</ApexClass>
I've also tried to set singlePackage to false and use unpackaged folder as a wrapper but I doesn't work, too.
There is a possibility that "No package.xml found" is a catch-all error that makes solving the problem harder than it should be.

How can I delete backslash in r?

I want to remove the backslashes from the soap service response.
Is there any way to remove the single backslashes?
string;
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">

ASP.NET MVC Sitemap.xml error

I have a valid sitemap.xml file. The problem arises when I try to serve this file as a sitemap.xml. I get the following error:
This page contains the following errors:
error on line 1 at column 95: Extra content at the end of the document
Below is a rendering of the page up to the first error.
When I inspect /sitemap.xml from browser each element tag gets this added to it.
<url xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
the rest
</url>
Here is how I return the file from the controller:
XmlDocument xml = new XmlDocument();
xml.Load(#"C:\sitemap.xml");
return Content(xml.DocumentElement.InnerXml, "application/xml");
Here is an example of the file I have and trying to return
<?xml version="1.0" encoding="utf-8"?>
<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>LINK</loc>
</url>
THE REST OF URLS
</urlset>
I have tried switching the "application/xml" to "text/xml" but didn't solve this problem. Am I not using XmlDocument correctly or am I not fully understanding what happens with return Content()?
Any help is appreciated.
Thank you
What ended up fixed this was a simple fix.
XmlDocument xml = new XmlDocument();
xml.Load(#"C:\sitemap.xml");
return Content(xml.DocumentElement.InnerXml, "application/xml");
Changed to
XmlDocument xml = new XmlDocument();
xml.Load(#"C:\sitemap.xml");
return Content(xml.DocumentElement.OuterXml, "application/xml");
Hope this helps someone later.

How to Set up SOAP Request via ASP.NET to url as a service?

Have the following code in my Default.aspx file, located at http://localhost/idss/Default.aspx:
<%# Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head id="Head1" runat="server">
<title>Testing IDSS Return Values</title>
</head>
<body>
<%#
// how we do it
XmlDocument doc = new XmlDocument();
doc.Load(Server.MapPath("idss/requests/categoryList.xml"));
// create the request to your URL
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost/idss/Default.aspx");
// add the headers
// the SOAPACtion determines what action the web service should use
// YOU MUST KNOW THIS and SET IT HERE
request.Headers.Add("SOAPAction", "http://ws.idssasp.com/Members.asmx/GetCategoryList");
// set the request type
// we use utf-8 but set the content type here
request.ContentType = "text/xml;charset=\"utf-8\"";
request.Accept = "text/xml";
request.Method = "POST";
// add our body to the request
Stream stream = request.GetRequestStream();
doc.Save( stream );
stream.Close();
// get the response back
using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
request.Write(response);
}//end using
%>
</body>
</html>
The xml file located at: http://localhost/idss/requests/categoryList.xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthorizeHeader xmlns="http://ws.idssasp.com/Members.asmx">
<UserName>MyUsername</UserName>
<Password>MyPassword</Password>
</AuthorizeHeader>
</soap:Header>
<soap:Body>
<GetCategoryList xmlns="http://ws.idssasp.com/Members.asmx" />
</soap:Body>
</soap:Envelope>
Where MyUsername and MyPassword is filled in with the correct username and password. The URL located here: http://ws.idssasp.com/members.asmx?op=GetCategoryList&pn=0 tells me that SOAP should send a request like this:
POST /members.asmx HTTP/1.1
Host: ws.idssasp.com
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://ws.idssasp.com/Members.asmx/GetCategoryList"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<AuthorizeHeader xmlns="http://ws.idssasp.com/Members.asmx">
<UserName>string</UserName>
<Password>string</Password>
</AuthorizeHeader>
</soap:Header>
<soap:Body>
<GetCategoryList xmlns="http://ws.idssasp.com/Members.asmx" />
</soap:Body>
</soap:Envelope>
But when I browse to http://localhost/idss/Default.aspx I get an Internal Server Error (500). What exactly am I doing wrong here? Do I need to add namespaces? Or other References somewhere in the Default.aspx file? If so, which one's are needed? Also, am I pointing to the correct in (HttpWebRequest)WebRequest.Create("http://localhost/idss/Default.aspx");?
Am I doing this correctly? I just feel like something is missing here.

Determine if a HTTP request is a soap request on HttpApplication.AuthenticateRequest

I there a way to know if a request is a soap request on AuthenticateRequest event for HttpApplication? Checking ServerVariables["HTTP_SOAPACTION"] seems to not be working all the time.
public void Init(HttpApplication context) {
context.AuthenticateRequest += new EventHandler(AuthenticateRequest);
}
protected void AuthenticateRequest(object sender, EventArgs e) {
app = sender as HttpApplication;
if (app.Request.ServerVariables["HTTP_SOAPACTION"] != null) {
// a few requests do not enter here, but my webservice class still executing
// ...
}
}
I have disabled HTTP POST and HTTP GET for webservices in my web.config file.
<webServices>
<protocols>
<remove name="HttpGet" />
<remove name="HttpPost" />
<add name="AnyHttpSoap" />
</protocols>
</webServices>
Looking at ContentType for soap+xml only partially solves my problem. For example,
Cache-Control: no-cache
Connection: Keep-Alive
Content-Length: 1131
Content-Type: text/xml
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: ro
Host: localhost
mymethod: urn:http://www.wsnamespace.com/myservice
Some clients instead of having the standard header SOAPAction: "http://www.wsnamespace.com/myservice/mymethod", have someting like in example above. "mymethod" represents the method in my web service class with [WebMethod] attribute on it and "http://www.wsnamespace.com/myservice" is the namespace of the webservice. Still the service works perfectly normal.
The consumers use different frameworks (NuSOAP from PHP, .NET, Java, etc).
You could look at Request.ContentType property, which if properly set by the client should be
application/soap+xml; charset=utf-8
The utf-8 part may not be present.
Aside from that, surely you can just check the URL, and if it's a webservice one then that tells you what it is.
I always give web services their own port. That way I don't have to filter every HTTP request that comes across port 80. Or rather, I can filter port 80 for browser-oriented issues, and SOAP/SOA ports for other types of attacks.
IMAO, mixing (potentially) sensitive business data with public data just so you don't have to open another hole in the firewall is thumbing your nose at the very reason you have a firewall in the first place.
You could also go down the harder route and figure things out based on everything else that's below HTTP headers. What I mean by that is, to analyze things like below, which is the SOAP request body - part of the request...
<soap:Envelope xmlns:soap="..." soap:encodingStyle="...">
IBM
Have you tested the System.Web.HttpContext.Current.Request.CurrentExecutionFilePathExtension ??
Normally this would be .asmx for webservices (json and xml), as long as you handle the service of course.
I am using following code to identify the request type. Try this if it match your requirment. Mark as answer if it help you.
if (request.Headers["SOAPAction"] != null || request.ContentType.StartsWith("application/soap+xml"))
return ServiceRequestTypes.SoapRequest;
else if ("POST".Equals(request.RequestType, StringComparison.InvariantCultureIgnoreCase) && request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.InvariantCultureIgnoreCase))
return ServiceRequestTypes.HttpPostRequest;
else if ("POST".Equals(request.RequestType, StringComparison.InvariantCultureIgnoreCase) && request.ContentType.StartsWith("application/json", StringComparison.InvariantCultureIgnoreCase))
return ServiceRequestTypes.AjaxScriptServiceRequest;
return ServiceRequestTypes.Unknown;

Resources