I used a WCF client to send msmq message to WCF Service, before WCF Service process the msmq message, I want to check the body of the message.
After checking the content of msmq message body, I got below result.
But, I failed to get the exact string.
Below is definition of WCF Service
[ServiceContract]
public interface IMSMQService
{
[OperationContract(IsOneWay = true)]
void ShowMessage(string msg);
}
I used below method to retrieve message body, and it output empty, if I add watch on ms, I could get
"\0\u0001\0\u0001\u0004\u0002(net.msmq://vdi-v-tazho/private/TestQueue\u0003\aV\u0002\v\u0001s\u0004\v\u0001a\u0006V\bD\n\u001e\0��+http://tempuri.org/IMSMQService/ShowMessage#\u0017VsDebuggerCausalityData\bAhttp://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink�<��ϣ-lN��FoJ�0�u\u0006�\"\0\0\0\0\u0017�\0i8�C�I\7�^Q�A\u0012�w}\f�A�\u000f\rޮ�pe\0\t\0\0D\f\u001e\0��(net.msmq://vdi-v-tazho/private/TestQueue\u0001V\u000e#\vShowMessage\b\u0013http://tempuri.org/#\u0003msg�\u0004test\u0001\u0001\u0001"
//message.Formatter = new XmlMessageFormatter(new String[] { });
//StreamReader sr = new StreamReader(message.BodyStream);
string ms = "";
//while (sr.Peek() >= 0)
//{
// ms += sr.ReadLine();
//}
message.Formatter = new ActiveXMessageFormatter();
string result = System.Text.Encoding.UTF8.GetString(message.Body as byte[]);
StreamReader reader = new StreamReader(message.BodyStream);
ms = reader.ReadToEnd();
MessageBox.Show(ms);
I got below code to achieve my requirement.
private void MSMQStringBody_Click(object sender, EventArgs e)
{
System.Messaging.MessageQueue[] queueList = System.Messaging.MessageQueue.GetPrivateQueuesByMachine(Environment.MachineName);
MessageQueue myQueue = queueList[1];
List<System.Messaging.Message> messages = myQueue.GetAllMessages().ToList();
foreach (System.Messaging.Message message in messages)
{
System.Xml.XmlDocument result = ConvertToXMLDoc(message);
MessageBox.Show(result.InnerText);
}
}
public System.Xml.XmlDocument ConvertToXMLDoc(System.Messaging.Message msg)
{
byte[] buffer = new byte[msg.BodyStream.Length];
msg.BodyStream.Read(buffer, 0, (int)msg.BodyStream.Length);
int envelopeStart = FindEnvolopeStart(buffer);
System.IO.MemoryStream stream = new System.IO.MemoryStream(buffer, envelopeStart, buffer.Length - envelopeStart);
System.ServiceModel.Channels.BinaryMessageEncodingBindingElement elm = new System.ServiceModel.Channels.BinaryMessageEncodingBindingElement();
System.ServiceModel.Channels.Message msg1 = elm.CreateMessageEncoderFactory().Encoder.ReadMessage(stream, Int32.MaxValue);
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(msg1.GetReaderAtBodyContents());
msg.BodyStream.Position = 0;
return doc;
}
private int FindEnvolopeStart(byte[] stream)
{
int i = 0;
byte prevByte = stream[i];
byte curByte = (byte)0;
for (i = 0; i < stream.Length; i++)
{
curByte = stream[i];
if (curByte == (byte)0x02 &&
prevByte == (byte)0x56)
break;
prevByte = curByte;
}
return i - 1;
}
When you send/retrieve a message body into/from MSMQ, you should use the same "type". see generic type "T" below. T could be any of your custom class.
public T GetQueueMessage()
{
Message message = queue.Receive(new TimeSpan(0, 0, 0, 1, 0));
return (T)message.Body;
}
public void InsertQueueMessage(T message)
{
using (Message msg = new Message((object)message))
{
queue.Send(msg, MessageQueueTransactionType.Single);
}
}
I know the question is C# code, but I am including Powershell script here for those of us that like to quickly inspect MSMQ contents using the shell. Using Edward's code I also made this work with Powershell, if anybody is looking for a script that can extract these WCF messages that is sent as payload to the WCF service with endpoints using the protocol binding NetMsmqbinding or NetMsmqIntegrationBinding.
Instead of using Int32.MaxValue, I used another large integer value that I know would suffice in most cases. It would be nice to know the logic behind finding the Soap Envelope start by the way.
Here is the Powershell script:
[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.ServiceModel") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.IO") | Out-Null
$queuePath = ".\private$\demoqueue4"
Write-Host "Powershell MSMQ queue WCF inspector v0.1. Inspecting queue contents of the queue: $queuePath"
Write-Host ""
Run-MainDemoIterateMsmq $queuePath
Function Get-XmlFromWcfMessage([System.Messaging.Message] $msg) {
$doc = New-Object System.Xml.XmlDocument;
$messageLength = [int] $msg.BodyStream.Length
$buffer = New-Object byte[] $messageLength
$msg.BodyStream.Read($buffer, 0, $messageLength)
$envelopeStart = Find-SoapEnvelopeStart($buffer)
$envelopeStart = $envelopeStart - 0
$envelopeLength = $($buffer.Length - $envelopeStart)
#Write-Host $envelopeStart
$stream = New-Object System.IO.MemoryStream($buffer, $envelopeStart, $envelopeLength)
$elm = New-Object System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
$elm.ReaderQuotas.MaxStringContentLength = 10000000
$elm.ReaderQuotas.MaxBytesPerRead = 10000000
$msg1 = $elm.CreateMessageEncoderFactory().Encoder.ReadMessage($stream, 10000000);
$doc.Load($msg1.GetReaderAtBodyContents());
$msg.BodyStream.Position = 0;
return $doc;
}
Function Find-SoapEnvelopeStart([byte[]] $stream)
{
$i = 0;
$j = 0;
$prevByte = $stream[$i];
$curByte = [byte]$j;
for ($i = 0; $i -lt $stream.Length; $i++)
{
$curByte = $stream[$i];
if ($curByte -eq [byte] 0x02 -and $prevByte -eq [byte] 0x56) {
break;
}
$prevByte = $curByte;
}
return $i - 1;
}
Function Run-MainDemoIterateMsmq([string] $queuePath) {
$queue = New-Object System.Messaging.MessageQueue $queuePath
foreach ($message in $queue.GetAllMessages()){
$xmlDoc = Get-XmlFromWcfMessage $message
Write-Host $xmlDoc.OuterXml
}
}
The output can then look like this for example:
<SendMessage xmlns="http://tempuri.org/"><message>this is another test!</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>why hello srmp</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>test</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>my message to msmq</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>This is a new message!</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>Another message to MSMQ! </message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>another test here</message></SendMessage>
<SendMessage xmlns="http://tempuri.org/"><message>This is a test message that will be sent using NetMsmqBinding. </message></SendMessage>
<SendMessageDataContract xmlns="http://tempuri.org/"><message xmlns:b="http://schemas.datacontract.org/2004/07/WcfDemoNetMsmqBinding.Host" xmlns:i="http://www.w3.org/2001
/XMLSchema-instance"><b:BoolValue>true</b:BoolValue><b:StringValue>This is a test of a stringvalue for a CompositeType</b:StringValue></message></SendMessageDataContract>
Related
I am using this SMBLibrary. Related to this closed issue, I sometimes get ntStatus = 3221226071 when I attempt to FileStore.CreateFile(). What does "DFS pathname not on local server" mean? If I keep trying, eventually it will work. Leads me to believe some resources are being held or not released/disconnected. Any ideas here?
"SMBLibrary" Version="1.4.8"
Here is my code:
[Fact]
public void Unit_Test_To_Test_SMBLibrary()
{
var server = "myRemoteServer";
var shareName = "shareddir";
var windowsPath = "Data\\Folder1\\unittest";
var random = new System.Random();
var filename = "createdBySmbclient" + random.Next(1, 10).ToString() + ".txt";
var domain = "my.domain";
var username = "myUser";
var password = "--put secret password here--";
var client = new SMB2Client();
bool isConnected = client.Connect(server, SMBTransportType.DirectTCPTransport);
if(isConnected)
{
try
{
NTStatus ntStatus = client.Login(domain, username, password);
if (ntStatus == NTStatus.STATUS_SUCCESS)
{
ISMBFileStore fileStore = client.TreeConnect(shareName, out ntStatus);
object fileHandle;
FileStatus fileStatus;
var windowsPathWithFile = Path.Combine(windowsPath, filename);
// 1st, create empty file.
ntStatus = fileStore.CreateFile(
out fileHandle,
out fileStatus,
windowsPathWithFile,
AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE,
0,
ShareAccess.None,
CreateDisposition.FILE_OPEN_IF,
CreateOptions.FILE_NON_DIRECTORY_FILE,
null
);
// create file contents and get the bytes
byte[] filebytes = Encoding.ASCII.GetBytes("hello world");
// 2nd, write data to the newly created file
if (ntStatus == NTStatus.STATUS_SUCCESS && fileStatus == FileStatus.FILE_CREATED)
{
int numberOfBytesWritten;
ntStatus = fileStore.WriteFile(out numberOfBytesWritten, fileHandle, 0, filebytes);
fileStore.FlushFileBuffers(fileHandle);
fileStore.CloseFile(fileHandle);
fileStore.Disconnect();
_logger.LogDebug(string.Format("Export successful: {0}", windowsPathWithFile));
}
else
{
throw new Exception(string.Format("ERROR: ntStatus = {0}, fileStatus = {1}", ntStatus, fileStatus));
}
}
}
finally
{
client.Logoff();
client.Disconnect();
}
}
}
I use the same code in custom action wix and console app. In custom action it dont return polish symbol "ł" and "ą" in custom action. Replaces them with other symbols or spaces. In console app it works well.
Already in the "message" variable there isnt polish letters.
private static void RunTest(Session session)
{
try
{
Process p = CreateProcess();
p.StartInfo.FileName = "....exe"; ;
p.StartInfo.Arguments = "-t";
string message = "";
int errorCount = 0;
p.OutputDataReceived += (sender, args) =>
{
if (args.Data == null)
return;
message += args.Data;
message += "\n";
};
p.ErrorDataReceived += (sender, args) =>
{
if (args.Data == null)
return;
errorCount++;
message += args.Data;
message += "\n";
};
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
SaveNewRtf(session, message);
}
catch (Exception)
{
}
}
private static Process CreateProcess()
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
return p;
}
Edit:
This is happen because Massages from Process are in Unicode. But unfortunately I don't know how repair that. I changed encoding to utf-8 for messages in Program I run by Process and still the message are download in Unicode.
I solved it by
p.StartInfo.StandardOutputEncoding = OemEncoding.GetDefaultOemCodePageEncoding();
and
public static class OemEncoding
{
private const Int32 MAX_DEFAULTCHAR = 2;
private const Int32 MAX_LEADBYTES = 12;
private const Int32 MAX_PATH = 260;
private const UInt32 CP_OEMCP = 1;
public static Encoding GetDefaultOemCodePageEncoding()
{
CPINFOEX cpInfoEx;
if (GetCPInfoEx(CP_OEMCP, 0, out cpInfoEx) == 0)
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
"GetCPInfoEx() failed with error code {0}",
Marshal.GetLastWin32Error()));
return Encoding.GetEncoding((int)cpInfoEx.CodePage);
}
[DllImport("Kernel32.dll", EntryPoint = "GetCPInfoExW", SetLastError = true)]
private static extern Int32 GetCPInfoEx(UInt32 CodePage, UInt32 dwFlags, out CPINFOEX lpCPInfoEx);
[StructLayout(LayoutKind.Sequential)]
private unsafe struct CPINFOEX
{
internal UInt32 MaxCharSize;
internal fixed Byte DefaultChar[MAX_DEFAULTCHAR];
internal fixed Byte LeadByte[MAX_LEADBYTES];
internal Char UnicodeDefaultChar;
internal UInt32 CodePage;
internal fixed Char CodePageName[MAX_PATH];
}
}
I am working on a VCL application and I have to integrate Twilio using its REST API:
https://www.twilio.com/docs/usage/your-request-to-twilio
Here is my code:
pair<bool, String> SMSTwilio::SendMessage(TComponent* Owner,
String ToNumber, String FromNumber, String Message)
{
if(Message.Length() > MESSAGE_LIMIT) {
ShowMessage("Message must have " + IntToStr(MESSAGE_LIMIT) +
" or fewer characters. Cannot send message with " +
IntToStr(Message.Length()) + "characters.");
}
AccountSID = "AC2d48*****************0deb52";
AuthToken = "9e28ec***************c0126e";
Message = "Hi";
FromNumber = "+1740****95";
ToNumber = "+9*****791";
String URI = "https://api.twilio.com/2010-04-01/Accounts/"
+ AccountSID +
"/Messages";
TStringList* params = new TStringList();
params->Add("From=" + FromNumber);
params->Add("To=" + ToNumber);
params->Add("Body=" + Message);
TIdHTTP* HTTP = new TIdHTTP(Owner);
HTTP->Request->Connection = "Keep-Alive";
HTTP->Request->ContentType = "application/x-www-form-urlencoded";
HTTP->Request->BasicAuthentication = true;
HTTP->Request->Username = AccountSID;
HTTP->Request->Password = AuthToken;
TIdSSLIOHandlerSocketOpenSSL* Handler = new TIdSSLIOHandlerSocketOpenSSL(Owner);
Handler->SSLOptions->Method = sslvTLSv1;
HTTP->IOHandler = Handler;
bool isSuccess = false;
String Result = "";
__try {
try {
HTTP->ReadTimeout = 5000;
HTTP->ConnectTimeout = 5000;
Result = HTTP->Post(URI, params);
isSuccess = true;
} catch(Exception &e) {
isSuccess = false;
Result = e.Message;
}
}
__finally {
delete HTTP;
delete params;
}
return make_pair(isSuccess, Result);
}
I am getting an EIdHTTPProtocolException with message "HTTP/1.1 400 BAD REQUEST" thrown by Result = HTTP->Post(URI, params);.
You are posting to the wrong URL.
You are posting to .../Messages but you need to post to .../Messages.json instead (notice the .json at the end), per Twilio's Message Resource documentation:
Create a Message resource
POST https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json
To send a new outgoing message, make an HTTP POST to this Messages list resource URI.
Also, although not errors per-say, there are some other issues with your code:
your Owner parameter is unnecessary. Since you are creating and destroying your TIdHTTP object in the same function, there is no need to assign an Owner to it at all. And it would be more useful to assign that TIdHTTP object as the Owner for the TIdSSLIOHandlerSocketOpenSSL object, instead of some unknown external Owner.
you are not returning an error to the caller if the Message is too long to send.
you are not adequately protecting your objects from leaks if something bad happens (why not use C++ smart pointers instead of try..finally?).
your catch() should be catching the Exception object by const reference.
you don't need Request->Connection = "Keep-Alive" since you are closing the connection after the Post() is finished, you are not actually using a keep-alive.
you should be using the SSLOptions->SSLVersions property instead of the SSLOptions->Method property. That will then allow you to enable sslvTLSv1_1 and sslvTLSv1_2, since many servers are phasing out TLS 1.0 nowadays, so you should prepare for that sooner rather than later.
With that said, try something more like this:
#include <utility>
#include <memory>
std::pair<bool, String> SMSTwilio::SendMessage(
String ToNumber, String FromNumber, String Message)
{
if (Message.Length() > MESSAGE_LIMIT) {
String msg = Format(_D("Message must have %d or fewer characters. Cannot send message with %d characters."), ARRAYOFCONST(( MESSAGE_LIMIT, Message.Length() )) );
//ShowMessage(msg);
return std::make_pair(false, msg);
}
String AccountSID = _D("AC2d48*****************0deb52");
String AuthToken = _D("9e28ec***************c0126e");
//Message = _D("Hi");
//FromNumber = _D("+1740****95");
//ToNumber = _D("+9*****791");
String URI = Format(_D("https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json"), ARRAYOFCONST(( AccountSID )) );
std::unique_ptr<TStringList> params(new TStringList); // or std::auto_ptr prior to C++11
params->Add(_D("From=") + FromNumber);
params->Add(_D("To=") + ToNumber);
params->Add(_D("Body=") + Message);
std::unique_ptr<TIdHTTP> HTTP(new TIdHTTP(nullptr)); // or std::auto_ptr prior to C++11
HTTP->ReadTimeout = 5000;
HTTP->ConnectTimeout = 5000;
//HTTP->Request->Connection = _D("Keep-Alive");
HTTP->Request->ContentType = _D("application/x-www-form-urlencoded");
HTTP->Request->BasicAuthentication = true;
HTTP->Request->Username = AccountSID;
HTTP->Request->Password = AuthToken;
TIdSSLIOHandlerSocketOpenSSL* Handler = new TIdSSLIOHandlerSocketOpenSSL(HTTP.get());
Handler->SSLOptions->SSLVersions = TIdSSLVersions() << sslvTLSv1 << sslvTLSv1_1 << sslvTLSv1_2;
HTTP->IOHandler = Handler;
bool isSuccess = false;
String Result;
try {
Result = HTTP->Post(URI, params);
isSuccess = true;
}
catch (const Exception &e) {
isSuccess = false;
Result = e.Message;
}
return std::make_pair(isSuccess, Result);
}
var importSolutionRequest = new ImportSolutionRequest
{
ImportJobId = Guid.NewGuid(),
CustomizationFile = fileBytes,
OverwriteUnmanagedCustomizations = true,
PublishWorkflows = true,
SkipProductUpdateDependencies = true,
};
var response = (ImportSolutionResponse)Service.Execute(importSolutionRequest);
I am not getting any useful information in this response object. What changes should I do to get warnings in this object, which occured while importing solution?
You have to query the ImportJob to get the results you want (https://msdn.microsoft.com/en-us/library/gg327847.aspx).
From the SDK (https://msdn.microsoft.com/en-us/library/gg509050.aspx):
// Monitor import success
byte[] fileBytesWithMonitoring = File.ReadAllBytes(ManagedSolutionLocation);
ImportSolutionRequest impSolReqWithMonitoring = new ImportSolutionRequest()
{
CustomizationFile = fileBytes,
ImportJobId = Guid.NewGuid()
};
_serviceProxy.Execute(impSolReqWithMonitoring);
Console.WriteLine("Imported Solution with Monitoring from {0}", ManagedSolutionLocation);
ImportJob job = (ImportJob)_serviceProxy.Retrieve(ImportJob.EntityLogicalName, impSolReqWithMonitoring.ImportJobId, new ColumnSet(new System.String[] { "data", "solutionname" }));
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(job.Data);
String ImportedSolutionName = doc.SelectSingleNode("//solutionManifest/UniqueName").InnerText;
String SolutionImportResult = doc.SelectSingleNode("//solutionManifest/result/#result").Value;
Console.WriteLine("Report from the ImportJob data");
Console.WriteLine("Solution Unique name: {0}", ImportedSolutionName);
Console.WriteLine("Solution Import Result: {0}", SolutionImportResult);
Console.WriteLine("");
// This code displays the results for Global Option sets installed as part of a solution.
System.Xml.XmlNodeList optionSets = doc.SelectNodes("//optionSets/optionSet");
foreach (System.Xml.XmlNode node in optionSets)
{
string OptionSetName = node.Attributes["LocalizedName"].Value;
string result = node.FirstChild.Attributes["result"].Value;
if (result == "success")
{
Console.WriteLine("{0} result: {1}",OptionSetName, result);
}
else
{
string errorCode = node.FirstChild.Attributes["errorcode"].Value;
string errorText = node.FirstChild.Attributes["errortext"].Value;
Console.WriteLine("{0} result: {1} Code: {2} Description: {3}",OptionSetName, result, errorCode, errorText);
}
}
Using .Net framework 4, I have following input string
String s = "9330e655-63d4-4aee-be79-505554256bd3"
I want to write a function that will return true or false as to whether or not any input string is a valid SqlGuid:
Method 1:
' Parse to validate ...
ok = true
try
s_uid = SqlGuid.Parse( s )
catch e as Exception
ok = false
end try
return ok
However, the ASP.Net framework also provides the Guid.TryParse() method, ie:
Method 2:
' Parse to validate ...
ok = Guid.TryParse( s )
My question: Which is more efficient and what do most use to validate SQL GUIDs (Method 1 or 2)?
If you're just checking validity then you can use either method, and Guid.TryParse will allow you to validate without doing expensive exception handling.
Be aware, however, that the string representations of Guid and SqlGuid are not the same, so a string generated from a Guid should not be used to create a SqlGuid since it will result in a different GUID value.
best practice would be to use the build-in TryParse but if you want to look at the speed/performance itself here some quick benchmark.
don't forget to build as Release and don't run it from visual studio.
using System;
using System.Data.SqlTypes;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var regex = new Regex(#"\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b", RegexOptions.IgnoreCase);
string s = "9330e655-63d4-4aee-be79-505554256bd3";
SqlGuid resultSql;
Guid result;
var sw = System.Diagnostics.Stopwatch.StartNew();
bool valid;
valid = true;
for (int i = 0; i < 500000; ++i)
{
try
{
resultSql = SqlGuid.Parse(s);
valid &= true;
}
catch
{
valid = false;
}
}
sw.Stop();
Console.WriteLine("sql try-catch {0}ms all valid {1}", sw.ElapsedMilliseconds, valid);
sw = System.Diagnostics.Stopwatch.StartNew();
valid = true;
for (int i = 0; i < 500000; ++i)
{
try
{
result = Guid.Parse(s);
valid &= true;
}
catch
{
valid = false;
}
}
sw.Stop();
Console.WriteLine("guid try-catch {0}ms all valid {1}", sw.ElapsedMilliseconds, valid);
sw = System.Diagnostics.Stopwatch.StartNew();
valid = true;
for (int i = 0; i < 500000; ++i)
{
valid &= Guid.TryParse(s, out result);
}
sw.Stop();
Console.WriteLine("tryparse {0}ms all valid {1}", sw.ElapsedMilliseconds, valid);
sw = System.Diagnostics.Stopwatch.StartNew();
valid = true;
for (int i = 0; i < 500000; ++i)
{
valid &= regex.IsMatch(s);
}
sw.Stop();
Console.WriteLine("regex {0}ms all valid {1}", sw.ElapsedMilliseconds, valid);
Console.ReadKey();
}
}
}