Sending XML from C# Server and receiving it it in Android Java client
This is what the received XML look likes:
<?xml version="1.0" encoding="utf-8"?>.....
This is the c# send code
// convert the class WorkItem to xml
MemoryStream memoryStream = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(WorkItem));
XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
xs.Serialize(xmlTextWriter, p);
// send the xml version of WorkItem to client
byte[] data = memoryStream.ToArray();
clientStream.Write(data, 0, data.Length);
Console.WriteLine(" send.." + data);
clientStream.Close();
In Java i just do:
in = new DataInputStream(skt.getInputStream());
String XMlString = in.readLine();
Everything is working if i every time remove the 3 first characters from XMlString.
I would really like to do this in a better way if it's possible
*UPDATE adding the Android java client
#Override
protected String doInBackground(Long... params) {
textTopInfo.setText("Loading workitems..");
DataOutputStream out = null;
DataInputStream in = null;
try {
Socket skt = new Socket(Consts.SERVER_URL_1, Consts.SERVER_PORT_1);
skt.setSoTimeout(10000); //10 sec timout
out = new DataOutputStream(skt.getOutputStream());
in = new DataInputStream(skt.getInputStream());
// check valid user id
String id = prefs.getString("id", "");
if(id.equals(""))
return "Open menu and enter User Id";
String theString = Consts.PUSH_GET_WORKITEM + ":" + id ;
out.write(theString.getBytes());
BufferedReader d = new BufferedReader
(new InputStreamReader(skt.getInputStream()));
String XMlString = d.readLine();
// here I remove the BOM
XMlString = XMlString.substring(3);
Log.d(TAG, "GF");
XStream xstream = new XStream();
xstream.alias("WorkItem", WorkItem.class);
xstream.alias("OneItem", OneItem.class);
pl = (WorkItem)xstream.fromXML(XMlString);
} catch (Exception e) {
return "cannot connect to server " + e.toString();
}finally{
//kill out/in
try {
if(out != null)
out.close();
if(in!=null)
in.close();
} catch (IOException e) {
}
}
return "here is the list";
}
the method readLine is deprecated in Java 1.7; from the javadocs:
readLine()
Deprecated.
This method does not properly convert bytes to characters. As of JDK 1.1, the preferred way to read lines of text is via the BufferedReader.readLine() method. Programs that use the DataInputStream class to read lines can be converted to use the BufferedReader class by replacing code of the form:
DataInputStream d = new DataInputStream(in);
with:
BufferedReader d
= new BufferedReader(new InputStreamReader(in));
The three initial bytes is the UTF8 BOM (Byte ordering mark). You will need to tell your Java code to use the same encoding.
Related
This question already has an answer here:
FromBase64String/UTF Encoding
(1 answer)
Closed 2 years ago.
I am trying to download a PDF file and encode it in UTF-8 format and then transform it back into a Base64 to attach it to a MailMessage, however I get an exception when passing the string to Base64.
exception
The input is not a valid Base-64 string as it contains a non-base 64 character...
my code...
try
{
if (attachment.Uri.Contains("http") || attachment.Uri.Contains("https"))
{
byte[] contentByte = null;
using (var webClient = new WebClient())
{
webClient.UseDefaultCredentials = true;
Uri uri = new Uri(attachment.Uri);
contentByte = webClient.DownloadData(uri);
}
MemoryStream memStream = new MemoryStream(contentByte);
String fullString = Encoding.UTF8.GetString(memStream.ToArray());
String stringData = fullString.Split(',')[1];
byte[] byteData = System.Convert.FromBase64String(stringData);
MemoryStream streamData = new MemoryStream(byteData);
Attachment attachmentDoc = new Attachment(streamData, fileName);
mail.Attachments.Add(attachmentDoc);
}
}
catch (Exception ex)
{
notificationLog.Error.Write(String.Format("Sendmail error. Attachment not found: " + attachment.FileName));
}
You are going about this the wrong way.
You are trying to decode the PDF as UTF-8 (which it is not) to UTF-16, and then decode that UTF-16 as Base64 (which it is not) to a byte array, then attach those bytes to the email. That is the complete opposite of what you need.
Base64 operates on bytes, not strings/characters. There is no need to encode a PDF (a binary file) to UTF-8 before encoding it in Base64. Just encode the PDF bytes as-is straight to Base64, eg:
try
{
if (attachment.Uri.StartsWith("http:") || attachment.Uri.StartsWith("https:"))
{
byte[] contentByte = null;
using (var webClient = new WebClient())
{
webClient.UseDefaultCredentials = true;
Uri uri = new Uri(attachment.Uri);
contentByte = webClient.DownloadData(uri);
}
String stringData = System.Convert.ToBase64String(contentByte);
MemoryStream memStream = new MemoryStream(Encoding.ASCII.GetBytes(stringData));
Attachment attachmentDoc = new Attachment(memStream, fileName);
mail.Attachments.Add(attachmentDoc);
}
}
catch (Exception ex)
{
notificationLog.Error.Write(String.Format("Sendmail error. Attachment not found: " + attachment.FileName));
}
However, using this approach, the receiver won't be able to decode the PDF correctly, because it won't know the PDF bytes were encoded in Base64.
Fortunately, the Attachment class can handle the Base64 for you, and notify the receiver of the encoding. Just give the Attachment the raw PDF bytes as-is, and set its TransferEncoding property to Base64, eg:
try
{
if (attachment.Uri.StartsWith("http:") || attachment.Uri.StartsWith("https:"))
{
byte[] contentByte = null;
using (var webClient = new WebClient())
{
webClient.UseDefaultCredentials = true;
Uri uri = new Uri(attachment.Uri);
contentByte = webClient.DownloadData(uri);
}
MemoryStream memStream = new MemoryStream(contentByte);
Attachment attachmentDoc = new Attachment(memStream, fileName);
attachmentDoc.TransferEncoding = TransferEncoding.Base64;
mail.Attachments.Add(attachmentDoc);
}
}
catch (Exception ex)
{
notificationLog.Error.Write(String.Format("Sendmail error. Attachment not found: " + attachment.FileName));
}
I wrote a function to create a mime message and encrypt the content with users public cert that's stored in the cert store while the private keys are stored on my smart card. My function simply saves the pkcs7mime content to a file.
I have another test function, which simply reads the file and tries to decrypt the content. However, when I try to decrypt, I get the error: ASN1 bad tag value met.
My encryption function code:
private static void EncryptMime()
{
MimeMessage mm = new MimeMessage();
var ctx = new WindowsSecureMimeContext();
mm.From.Add(new MailboxAddress("Bob", "Bob#diamondsg.onmicrosoft.com"));
mm.To.Add(new MailboxAddress("Alice", "Alice#diamondsg.onmicrosoft.com"));
mm.Subject = "Smime Test";
mm.Body = new TextPart("plain")
{
Text = #"This is a test."
};
var signer = mm.From.Mailboxes.FirstOrDefault();
var recipients = mm.To.Mailboxes.AsEnumerable();
ApplicationPkcs7Mime p7m = ApplicationPkcs7Mime.SignAndEncrypt(ctx, signer, DigestAlgorithm.Sha1, recipients, mm.Body);
MemoryStream ms = new MemoryStream();
p7m.WriteTo(ms, true);
byte[] bytes = ms.GetBuffer();
File.WriteAllBytes("smime.p7m", bytes);
}
Here is my decrypt function:
private static void DecryptMime()
{
CryptographyContext.Register(typeof(WindowsSecureMimeContext));
string messagetext = "";
// Read the p7m file
byte[] bytes =
File.ReadAllBytes("smime.p7m");
MemoryStream ms = new MemoryStream(bytes);
ApplicationPkcs7Mime p7m = new ApplicationPkcs7Mime(SecureMimeType.EnvelopedData, ms);
// WindowsSecureMimeContext ctx = new WindowsSecureMimeContext(StoreLocation.CurrentUser);
if (p7m != null && p7m.SecureMimeType == SecureMimeType.EnvelopedData)
{
Console.WriteLine("Decrypting message...");
try
{
p7m = p7m.Decrypt() as ApplicationPkcs7Mime;
}
catch (Exception ex)
{
Console.WriteLine("Error decrypting: " + ex.Message);
}
}
if (p7m != null && p7m.SecureMimeType == SecureMimeType.CompressedData)
{
Console.WriteLine("Decompressing message...");
p7m = p7m.Decompress() as ApplicationPkcs7Mime;
}
if (p7m != null && p7m.SecureMimeType == SecureMimeType.SignedData)
{
Console.WriteLine("Verifying message...");
p7m.Verify(out MimeEntity entity);
MimeMessage mm = new MimeMessage(entity);
messagetext = mm.GetTextBody(MimeKit.Text.TextFormat.Text);
Console.WriteLine("Decrypted Message: " + messagetext);
}
}
Edit:
I tried isolating the issue by using the following code:
MemoryStream ms = new MemoryStream();
p7m.WriteTo(ms);
ApplicationPkcs7Mime new_p7m = new ApplicationPkcs7Mime(SecureMimeType.EnvelopedData, ms);
if (new_p7m != null && new_p7m.SecureMimeType == SecureMimeType.EnvelopedData)
{
Console.WriteLine("Decrypting message...");
try
{
new_p7m = new_p7m.Decrypt() as ApplicationPkcs7Mime;
}
catch (Exception ex)
{
Console.WriteLine("Error decrypting: " + ex.Message);
}
}
So the problem seems to start as early as the WriteTo() function...
Update #2:
Ok, so I did a toString on both the p7m and the new_p7m object. Apparently, the content is different...
p7m: Content-Type: application/pkcs7-mime; smime-type=enveloped-data;
name=smime.p7m
Content-Disposition: attachment; filename=smime.p7m
Content-Transfer-Encoding: base64
MIIOOwYJKoZIhvcNAQcDoIIOLDCCDigCAQIxggEwMIIBLAIBAoAU2NQqDvYHJuMeC27IpyiV
....
New p7m: Content-Type: application/pkcs7-mime; smime-type=enveloped-data;
name=smime.p7m
Content-Disposition: attachment; filename=smime.p7m
Content-Transfer-Encoding: base64
Q29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9wa2NzNy1taW1lOyBzbWltZS10eXBlPWVudmVs
....
To, somehow the actual content is changing... very strange...
I'm betting that your code to save the content to disk is writing a corrupt file:
MemoryStream ms = new MemoryStream();
p7m.WriteTo(ms, true);
byte[] bytes = ms.GetBuffer();
File.WriteAllBytes("smime.p7m", bytes);
The problem with the above code is that GetBuffer() returns more bytes than are actually used by the memory stream in most cases. The above logic will also save the content in base64 which is probably not what you want. The following code snippet will decode the base64 content into the smime.p7m file:
using (var stream = File.Create ("smime.p7m"))
p7m.Content.DecodeTo (stream);
Then, to reconstruct the MIME part back for decrypting, do this:
var bytes = File.ReadAllBytes ("smime.p7m");
var ms = new MemoryStream (bytes);
var p7m = new ApplicationPkcs7Mime (SecureMimeType.EnvelopedData, ms);
The problem you were facing is that the content was base64 encoded before and it should not have been.
Of course, unless there's really a need to save just the raw content and then re-construct the application/pkcs7-mime part the hard way, why not just save the entire MIME part like this?
using (var stream = File.Create ("smime.p7m"))
p7m.WriteTo (stream);
And then re-load it like this:
using (var stream = File.OpenRead ("smime.p7m"))
p7m = (ApplicationPkcs7Mime) MimeEntity.Load (stream);
Then you don't have to worry about getting things wrong.
This is a very strange question.
I using C# to create a pass.json and save it to memoryStream, it work normally. After that I create the manifest.json SHA1 data which including that pass.json, the string of manifest.json like this and it is totally correct.
{"icon.png": "9423bd00e2b01c59a3265c38b5062fac7da0752d",
"icon#2x.png": "4d1db55bdaca70b685c013529a1c0dcbd7046524",
"logo.png": "ee5b053e63dbfe3b78378c15d163331d68a0ede8",
"logo#2x.png": "2f9e3a55bded1163620719a4d6c1ad496ed40c17",
"pass.json": "fd68bf77757d3057263a9aca0e5110ddd933934a"}
After generate pkpass as my phone, it can't open. I change the pass.json SHA1 code as "fd68bf77757d3057263a9aca0e5110ddd933934a" without using a value to save it, it work.
The coding like following:
// This version run success
var strPass = JavascriptSerialize(details);
var sw = new StreamWriter(assetsFolder + #"pass.json");
sw.Write(strPass);
sw.Close();
manifest.passjson = GetSha1Hash(assetsFolder + manifest.GetAssetBoardingPass(libPkPass_object_boardingPass.JsonObjects.AssetTypes.passjson));
//manifest.passjson = "2f9e3a55bded1163620719a4d6c1ad496ed40c17"
// end
// This version run fail
var strPass = JavascriptSerialize(details);
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(strPass);
writer.Write(s);
writer.Flush();
stream.Position = 0;
var a = GetSha1HashMemory(passStream);
private static string GetSha1HashMemory(Stream passStream)
{
//var bs = new BufferedStream(passStream);
using (SHA1Managed sha = new SHA1Managed())
{
byte[] checksum = sha.ComputeHash(passStream);
string sendCheckSum = BitConverter.ToString(checksum)
.Replace("-", string.Empty);
return sendCheckSum.ToString().ToLower();
}
}
manifest.passjson = a;
//manifest.passjson = "2f9e3a55bded1163620719a4d6c1ad496ed40c17" (same data )
//end
What is going on?????? I can find out any question that string is wrong.
The pkpass provide in here (sendspace).
Can any body told me where is wrong?
Big Thank!
Two mistakes :
ComputeHash(Stream) and using Stream
ComputeHash(Stream) : ComputeHash stream only using System.IO.Stream, but not MemoryStream, change to ComputeHash(bytes[]) can handle it
using Stream: I try to pass the stream to other function, it is not a good example, the stream need to create a new one and it may replace some bytes at your computer stream. In this case, I just need to call this function will out open new one, it will fix
StringBuilder formatted;
using (var sha1 = new SHA1Managed())
{
//var bytePass = ReadFully(passStream);
var bytePass = passStream.ToArray();
var hash = sha1.ComputeHash(bytePass);
formatted = new StringBuilder(2 * hash.Length);
foreach (var b in hash)
{
formatted.AppendFormat("{0:X2}", b);
}
}
manifest.passjson = formatted.ToString().ToLower();
I am sure this is an easy question however I am not finding the solution. I want to save the XML files posted to my .NET Web Service. I am sure it is just a simple method call when the service is invoked but I am not finding it. I would like to save the full XML posted to the service
Any help would be greatly appreciated. Thank you in advance.
Thank you for your help however I found what I was looking for at http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soapextension.aspx
To help anyone else that is new to tring to implement this via WebService's I included the steps that I performed to implement it and modifications so I could save it to the db as well as the file system I performed the following steps. If you have any questions please feel free to aks and I will be happy to answer.
Created a code file in my web service project with the code listed in the in the article
Created a few properties to store values to save to the db
private string _requestXml;
private DateTime _start;
Then I modified the WriteInput method to save values to those variables.
public void WriteInput(SoapMessage message)
{
//Begin Edit
oldStream.Position = 0;
_requestXml = new StreamReader(_oldStream).ReadToEnd();
_start = DateTime.UtcNow;
//End Edit
//Begin Original Code
oldStream.Position = 0;
Copy(oldStream, newStream);
var fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
var w = new StreamWriter(fs);
var soapString = (message is SoapServerMessage) ? "SoapRequest" : "SoapResponse";
w.WriteLine("-----" + soapString + " at " + DateTime.Now);
w.Flush();
newStream.Position = 0;
Copy(newStream, fs);
w.Close();
newStream.Position = 0;
}
Then I modified the WriteOutput to
public void WriteOutput(SoapMessage message)
{
//Begin Edit
var responseXml = new StreamReader(newStream).ReadToEnd();
newStream.Position = 0;
//Start process for saving to DB
//"_requestXml" = Original Request Soap Message
//"responseXml" = Service Returned Response
//"_start" = Request Start Time
//message.MethodInfo.Name = I save this so I know what method from
//message.Url = I save this so I know the original ASMX that was hit
//End Edit
//Begin Original Code
newStream.Position = 0;
var fs = new FileStream(filename, FileMode.Append, FileAccess.Write);
var w = new StreamWriter(fs);
var soapString = (message is SoapServerMessage) ? "SoapResponse" : "SoapRequest";
w.WriteLine("-----" + soapString + " at " + DateTime.Now);
w.Flush();
Copy(newStream, fs);
w.Close();
newStream.Position = 0;
Copy(newStream, oldStream);
}
Now all that's left is to add the following to your service call and you should be good to go
[WebMethod, NameSpace.OfyourTraceExtesionClass.TraceExtension]
public void WebMethod1()
{
//DoSomeStuff
}
If you want to log the http post messages, an elegant way of solving it would be to set up a simple reverse proxy in front of your web services. In this proxy you would have full access to the raw http request.
XML file received as Stream
Convert Stream to byte[]
Convert byte[] to XDocument (System.Xml.Linq)
Read XDocument with LINQ syntax and save to DB
[WebMethod]
public void XMLPersing()
{
var XMLDATA = "";
WriteLogCLS objWriteLog = new WriteLogCLS();
Stream receiveStream = HttpContext.Current.Request.InputStream;
receiveStream.Position = 0;
StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8); //For xml persing..
XMLDATA = readStream.ReadToEnd();
readStream.Close();
objWriteLog.WriteLog(Convert.ToString(XMLDATA));
XmlTextReader xmlreader = new XmlTextReader(Server.MapPath("Log/Exception/Sample.xml"));
DataSet ds = new DataSet();
ds.ReadXml(xmlreader);
xmlreader.Close();
if (ds.Tables.Count != 0)
{
var strCon = string.Empty;
strCon = ConfigurationManager.AppSettings["constring"];
SqlCommand cmdInsertXMLData = new SqlCommand();
SqlConnection SqlConn;
SqlConn = new SqlConnection(strCon);
try
{
cmdInsertXMLData = new SqlCommand("usp_InsertXML", SqlConn);
cmdInsertXMLData.CommandType = CommandType.StoredProcedure;
// cmdInsertLoginDetails.Parameters.Add("#XMLdata", SqlDbType.Xml).Value = ds.GetXml();
cmdInsertXMLData.Parameters.AddWithValue("#XMLdata", SqlDbType.Xml);
if (SqlConn.State == ConnectionState.Closed)
{
SqlConn.Open();
}
cmdInsertXMLData.ExecuteNonQuery();
// response = cmdInsertLoginDetails.Parameters["#Message"].Value.ToString();
}
catch (Exception ex)
{
objWriteLog.WriteLog("Error on XML Persing : " + ex.Message);
// response = "Error";
}
finally
{
if (cmdInsertXMLData != null)
{
cmdInsertXMLData.Dispose();
}
if (SqlConn.State == ConnectionState.Open)
{
SqlConn.Close();
SqlConn.Dispose();
}
objWriteLog = null;
}
// return response ;
}
}
}
I want to send a binary file to .net c# component in the following xml format
<BinaryFileString fileType='pdf'>
<!--binary file data string here-->
</BinaryFileString>
In the called component I will use the above xml string and convert the binary string received within the BinaryFileString tag, into a file as specified by the filetype='' attribute. The file type could be doc/pdf/xls/rtf
I have the code in the calling application to get out the bytes from the file to be sent. How do I prepare it to be sent with xml tags wrapped around it? I want the application to send out a string to the component and not a byte stream. This is because there is no way I can decipher the file type [pdf/doc/xls] just by looking at the byte stream. Hence the xml string with the filetype attribute. Any ideas on this?
method for extracting Bytes below
FileStream fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read);
using (Stream input = fs)
{
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{}
}
return buffer;
Thanks.
Edit:
Just to clarify why I am using an xml string rather than setting properties on my component. Actually my calling app is trying to simulate how Siebel will call my component.
http://download.oracle.com/docs/cd/E05553_01/books/eScript/eScript_JSReference244.html#wp1014380
Im not sure if Siebel can set my components properties as I need it to. So Im working on the angle of it sending the data in xml.
Base64 representation is universaly used to represent binary data.
public void EncodeWithString() {
System.IO.FileStream inFile;
byte[] binaryData;
try {
inFile = new System.IO.FileStream(inputFileName,
System.IO.FileMode.Open,
System.IO.FileAccess.Read);
binaryData = new Byte[inFile.Length];
long bytesRead = inFile.Read(binaryData, 0,
(int)inFile.Length);
inFile.Close();
}
catch (System.Exception exp) {
// Error creating stream or reading from it.
System.Console.WriteLine("{0}", exp.Message);
return;
}
// Convert the binary input into Base64 UUEncoded output.
string base64String;
try {
base64String =
System.Convert.ToBase64String(binaryData,
0,
binaryData.Length);
}
catch (System.ArgumentNullException) {
System.Console.WriteLine("Binary data array is null.");
return;
}
// Write the UUEncoded version to the XML file.
System.IO.StreamWriter outFile;
try {
outFile = new System.IO.StreamWriter(outputFileName,
false,
System.Text.Encoding.ASCII);
outFile.Write("<BinaryFileString fileType='pdf'>");
outFile.Write(base64String);
outFile.Write("</BinaryFileString>");
outFile.Close();
}
catch (System.Exception exp) {
// Error creating stream or writing to it.
System.Console.WriteLine("{0}", exp.Message);
}
}
At the receiving end you can reverse this and get back original file content as mentioned below.
// Convert the Base64 UUEncoded input into binary output.
byte[] binaryData;
try {
binaryData =
System.Convert.FromBase64String(base64String);
}
catch (System.ArgumentNullException) {
System.Console.WriteLine("Base 64 string is null.");
return;
}
catch (System.FormatException) {
System.Console.WriteLine("Base 64 string length is not " +
"4 or is not an even multiple of 4." );
return;
}
Can you BASE64 your bytes? MSDN ref: Convert.ToBase64, Convert.FromBase64String
expanding on #russau's answer it will work like this:
var s = "Hello World";
var b = Encoding.Default.GetBytes(s);
var bstr = Convert.ToBase64String(b);
Console.WriteLine("Original String:" + s);
Console.WriteLine("Base64 String:" + bstr);
var fromBStr = Convert.FromBase64String(bstr);
var st = Encoding.Default.GetString(fromBStr);
Console.WriteLine("Converted string: " + st);
you wont need first two lines:
var s = "Hello World";
var b = Encoding.Default.GetBytes(s);
as you already have a byte array. I've used string to show that you get exactly the same value you started with in the end when you convert byte array from Convert.FromBase64String
You mention that you are calling a C# component. I'm not sure I understand why using this component means you need to create an XML string.
Is it possible to define classes to hold your data instead of using an XML string? e.g.
public enum FileType
{
Word,
Excel,
RichText,
PDF
}
public class FileData
{
public FileType TypeOfFile
{
get;
set;
}
public byte[] Data
{
get;
set;
}
}
Then the caller of the component just sets the FileType and the byte[]. The component's interface would then be more explicitly defined (FileData class as opposed to the more generic string or XmlDocument).