I have seen references on how to cast to a proxy such as:
((IContextChannel)client.InnerChannel).OperationTimeout = new TimeSpan(0,0,240);
to set an operationtimeout but I am using client = channelFactory.CreateChannel();
How do I cast the channel to IContextChannel? I hope this makes sense. I don't have a complete grasp on channels in WCF.
Thanks
Alexei,
Not sure how to implement your suggestion.
In this code how would I set an operationtimeout?
try
{
Binding multipleTokensBinding = MultiAuthenticationFactorBinding.CreateMultiFactorAuthenticationBinding();
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
EndpointAddress endpointaddress = new EndpointAddress(new Uri("https://justsomeservice"), EndpointIdentity.CreateDnsIdentity("someone.com"));
ChannelFactory<TransActionSvc.TransactionPortType> channelFactory = null;
TransActionSvc.TransactionPortType client = null;
channelFactory = new ChannelFactory<TransActionSvc.TransactionPortType>(multipleTokensBinding, endpointaddress);
BindingElementCollection elements = channelFactory.Endpoint.Binding.CreateBindingElements();
elements.Find<SecurityBindingElement>().IncludeTimestamp = true;
channelFactory.Endpoint.Binding = new CustomBinding(elements);
channelFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.Root, X509FindType.FindBySerialNumber, "xxx");
channelFactory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.CurrentUser, StoreName.Root, X509FindType.FindBySerialNumber, "xxx");
channelFactory.Credentials.UserName.UserName = Properties.Settings.Default.UserName;
channelFactory.Credentials.UserName.Password = Properties.Settings.Default.Password;
TransActionSvc.fetchTranDataAsAttachmentRequest req = new WF_Prod_Svc.TransActionSvc.fetchTranDataAsAttachmentRequest();
TransActionSvc.fetchTranDataAsAttachmentResponse res = new WF_Prod_Svc.TransActionSvc.fetchTranDataAsAttachmentResponse();
TransActionSvc.FetchTranDataAsAttachmentRq_Type reqtype = new WF_Prod_Svc.TransActionSvc.FetchTranDataAsAttachmentRq_Type();
TransActionSvc.FetchTranDataAsAttachmentRs_Type restype = new WF_Prod_Svc.TransActionSvc.FetchTranDataAsAttachmentRs_Type();
TransActionSvc.EndpointReferenceType endpntref = new WF_Prod_Svc.TransActionSvc.EndpointReferenceType();
XmlAttribute actionAttrib1 = doc.CreateAttribute("soapenv", "mustUnderstand", "http://schemas.xmlsoap.org/soap/envelope/");
actionAttrib1.Value = "0";
XmlAttribute actionAttrib2 = doc.CreateAttribute("xmlns");
actionAttrib2.Value = "http://schemas.xmlsoap.org/ws/2003/03/addressing";
XmlAttribute[] objAcctionAtrb = new XmlAttribute[2];
objAcctionAtrb.SetValue(actionAttrib1, 0);
objAcctionAtrb.SetValue(actionAttrib2, 1);
TransActionSvc.AttributedURI action = new WF_Prod_Svc.TransActionSvc.AttributedURI();
action.AnyAttr = objAcctionAtrb;
action.Value = "Transaction";
TransActionSvc.AttributedURI messageid = new WF_Prod_Svc.TransActionSvc.AttributedURI();
messageid.AnyAttr = objAcctionAtrb;
messageid.Value = System.Guid.NewGuid().ToString();
TransActionSvc.AttributedURI to = new WF_Prod_Svc.TransActionSvc.AttributedURI();
to.AnyAttr = objAcctionAtrb;
to.Value = "XGI";
TransActionSvc.EndpointReferenceType endpointreference = new WF_Prod_Svc.TransActionSvc.EndpointReferenceType();
TransActionSvc.ReferencePropertiesType referenceproperties = new WF_Prod_Svc.TransActionSvc.ReferencePropertiesType();
if (Svc_Division.Parsed) { reqtype.division = Svc_Division.StringValue; }
try{reqtype.startDate = Convert.ToDateTime(Svc_StartDate.StringValue);}
catch (FormatException ex){LogMessageToFile("Invalid Start date. " + ex.Message);}
try{reqtype.endDate = Convert.ToDateTime(Svc_EndDate.StringValue);}
catch (FormatException ex){LogMessageToFile("Invalid End date. " + ex.Message);}
if (Svc_DateType.StringValue == "T")
{
reqtype.transactionDateType = TransActionSvc.TransactionDateType_Enum.TransactionDate;
}
else
{
reqtype.transactionDateType = TransActionSvc.TransactionDateType_Enum.PostingDate;
}
switch (Svc_TransType.StringValue)
{
case "OOP":
reqtype.transactionType = TransActionSvc.TransactionType_Enum.OOP;
break;
case "CHARGES":
reqtype.transactionType = TransActionSvc.TransactionType_Enum.CHARGES;
break;
default:
reqtype.transactionType = TransActionSvc.TransactionType_Enum.ALL;
break;
}
System.Xml.XmlElement companyid = doc.CreateElement("companyId");
companyid.InnerText = Properties.Settings.Default.CompanyID;
System.Xml.XmlElement[] objectarray = new System.Xml.XmlElement[1];
objectarray.SetValue(companyid, 0);
referenceproperties.Any = objectarray;
endpointreference.ReferenceProperties = referenceproperties;
req.Action = action;
req.MessageID = messageid;
req.To = to;
req.ReplyTo = endpointreference;
req.fetchTranDataAsAttachment = reqtype;
try
{
client = channelFactory.CreateChannel();
//THIS DOES NOT WORK
client.OperationTimeout = new TimeSpan(0,10,0);
res = client.fetchTranDataAsAttachment(req);
if (res.fetchTranDataAsAttachmentResponse1.WFFaultList != null)
{
LogLine = string.Format("FaultCode({0});FaultType({1});FaultReason({2});Severity({3})",
res.fetchTranDataAsAttachmentResponse1.WFFaultList[0].faultCode,
res.fetchTranDataAsAttachmentResponse1.WFFaultList[0].faultType,
res.fetchTranDataAsAttachmentResponse1.WFFaultList[0].faultReasonText,
res.fetchTranDataAsAttachmentResponse1.WFFaultList[0].severity);
}
if (res.fetchTranDataAsAttachmentResponse1.attachment != null)
{
string attachFileName = res.fetchTranDataAsAttachmentResponse1.attachment.fileName;
byte[] filebytes = res.fetchTranDataAsAttachmentResponse1.attachment.binaryData.Value;
FileStream fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + "..\\..\\" + res.fetchTranDataAsAttachmentResponse1.attachment.fileName, FileMode.CreateNew, FileAccess.Write, FileShare.None);
fs.Write(filebytes, 0, filebytes.Length);
fs.Close();
DateTime EndReceive = DateTime.Now;
TimeSpan elapsed = EndReceive.Subtract(BeginReceive);
LogLine = string.Format("Arguments: [{0}]; FileName: {1}; FileSize: {2} bytes; ElapsedTime: {3} seconds", arguments.Trim(), attachFileName, filebytes.Length.ToString(), elapsed.TotalSeconds.ToString());
LogMessageToFile(LogLine);
}
}
catch (CommunicationException ex1)
{
Abort((IChannel)client, channelFactory);
FaultException fe = null;
Exception tmp = ex1;
while (tmp != null)
{
fe = tmp as FaultException;
if (fe != null)
{
break;
}
tmp = tmp.InnerException;
}
if (fe != null)
{
string errmsg = string.Format("The server sent back a fault: {0}", fe.CreateMessageFault().Reason.GetMatchingTranslation().Text);
LogMessageToFile(errmsg);
}
else
{
string errmsg = string.Format("The request failed with exception: {0}", ex1.Message.ToString());
LogMessageToFile(errmsg);
}
}
catch (TimeoutException)
{
Abort((IChannel)client, channelFactory);
string errmsg = string.Format("The request timed out ");
DateTime EndReceive = DateTime.Now;
TimeSpan elapsed = EndReceive.Subtract(BeginReceive);
LogLine = string.Format("Arguments: [{0}]; Exception: {1}; ElapsedTime: {2} seconds", arguments.Trim(), errmsg, elapsed.TotalSeconds.ToString());
LogMessageToFile(LogLine);
}
catch (Exception ex)
{
Abort((IChannel)client, channelFactory);
string errmsg = string.Format("The request failed with unexpected exception: {0}", ex.Message.ToString());
LogMessageToFile(errmsg);
}
finally
{
((IChannel)client).Close();
channelFactory.Close();
}
}
You will not get any usefuls (non-null/non-exception) result by casting channel factory to channel interface since there is no point for factory to implement any of channel interfaces.
You can cast channel to some other channel interface and likely get useful result if you know what type of channel is used like in the code your refer to.
EDIT: I think ((IContextChannel)channel).OperationTimeout = new TimeSpan(0,10,0); should work.
Note: title of your post does not match your code...
Related
I am scanning QR CODE but the problem is ReceiveDetections method is calling multiple times even after a successful scan.How can I prevent calling the api multiple times after a successful call.
here is the code snippet
public void ReceiveDetections(Detections detections)
{
SparseArray qrcodes = detections.DetectedItems;
if (qrcodes.Size() != 0)
{
txtscankanbancloseResult.Post(async () =>
{
Vibrator vibrator = (Vibrator)GetSystemService(Context.VibratorService);
vibrator.Vibrate(1000);
txtscankanbancloseResult.Text = ((Barcode)qrcodes.ValueAt(0)).RawValue;
try
{
var client = new HttpClient();
var uri = new Uri(string.Format(AppStatics.clsStatic.url + "//Kanban/SaveKanbanStatus"));
List<string> lstskanban = new List<string>();
String myDate = DateTime.Now.ToString("dd-MMM-yyyy");
string adateddate = DateTime.Now.ToString("dd-MMM-yyyy hh:mm:ss");
JsonScankanbanclose objjscan = new JsonScankanbanclose();
lstskanban.Add(txtscankanbancloseResult.Text);
objjscan.UpdateBy = SingletonSession.Instance().getUsername();
objjscan.KANBANNOList = lstskanban;
objjscan.IsKANBANClosed = true;
string jsonData = JsonConvert.SerializeObject(objjscan);
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(uri, content);
var result = await response.Content.ReadAsStringAsync();
if (response.ReasonPhrase == "OK")
{
JArray scanresult = JArray.Parse(result);
Scanlist objscan = new Scanlist();
if (ScanSucessfull.Count == 0)
{
objscan.KanbanID = "Kanban NO";
objscan.KanbanQty = "Kanban Qty";
ScanSucessfull.Add(objscan);
objscan = new Scanlist();
}
// Scanlist item = ScanSucessfull.Find(c => c.KanbanID == scanresult[0]["KANBANID"].ToString());
//int itemPosition = ScanSucessfull.BinarySearch(scanresult[0]["KANBANID"].ToString());
//if (itemPosition.cou=="")
//{
objscan.KanbanID = scanresult[0]["KANBANNumber"].ToString();
objscan.KanbanQty = scanresult[0]["Qty"].ToString();
ScanSucessfull.Add(objscan);
//}
var adapter = new CustomAdapterScan(this, ScanSucessfull);
lstviewscankanbanclose.SetAdapter(adapter);
lstviewscankanbanclose.Clickable = false;
//lstview.Enabled = false;
lstviewscankanbanclose.ItemSelected += null;
mPlayer = Android.Media.MediaPlayer.Create(this, Resource.Raw.successful);
currentSong = Resource.Raw.successful;
mPlayer.SeekTo(1);
mPlayer.Start();
//Toast.MakeText(this, , ToastLength.Short).Show();
Helper.ShowToastMessage(this, Color.DarkGreen, "Data Save Sucessfully..", ToastLength.Short);
_kanbancount++;
txtscankanbanclosekanbancount.Text = "Kanban Count:" + " " + _kanbancount;
txtscankanbanclosekanbancount.Visibility = ViewStates.Visible;
}
else
{
string[] result1 = result.Split(':');
string[] result2 = result1[1].Split('"');
string[] result3 = result2[1].Split('"');
mPlayer = Android.Media.MediaPlayer.Create(this, Resource.Raw.fail);
// mPlayer.SeekTo(2);
currentSong = Resource.Raw.fail;
mPlayer.Start();
//Toast.MakeText(this, result3[0].ToString(), ToastLength.Short).Show();
Helper.ShowToastMessage(this, Color.DarkRed, result3[0].ToString(), ToastLength.Short);
}
// dialog.Hide();
cameraSource.Start(surfaceView.Holder);
//txtResult.Text = "";
}
catch (System.Exception ex)
{
Helper.ShowToastMessage(this, Color.DarkRed, ex.Message, ToastLength.Short);
//Toast.MakeText(this, ex.Message.ToString(), ToastLength.Short).Show();
// txtResult.Text = "";
txtscankanbancloseResult.Visibility = ViewStates.Invisible;
//cameraSource.Start(surfaceView.Holder);
}
});
using (var h = new Handler(Looper.MainLooper))
h.Post(() =>
{
cameraSource.Stop();
// Toast.MakeText(this, "This Kanban Already Scanned....", ToastLength.Short).Show();
});
}
}
Here is the code where I crate and open the camera source to scan the QR code
private void btnkanbanscan_Click(object sender, EventArgs e)
{
try
{
#region validation
if (spnSiteID.SelectedItemPosition < 0)
{
throw new Exception("Please Select Site...");
}
if (spnLocation.SelectedItemPosition < 0)
{
throw new Exception("Please Select Location..");
}
if (spnInspactionType.SelectedItemPosition < 0)
{
throw new Exception("Please Select Inspection Type..");
}
#endregion
LayoutInflater layoutInflater = LayoutInflater.From(this);
View scanview = LayoutInflater.Inflate(Resource.Layout.scan_popup, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.SetView(scanview);
surfaceView = scanview.FindViewById<SurfaceView>(Resource.Id.spvscan);
dialog = alertDialogBuilder.Create();
dialog.SetCanceledOnTouchOutside(false);
dialog.Show();
barcodeDetector = new BarcodeDetector.Builder(this)
.SetBarcodeFormats(BarcodeFormat.Code128 | BarcodeFormat.QrCode)
.Build();
cameraSource = new CameraSource.Builder(this, barcodeDetector)
.SetRequestedPreviewSize(480, 480)
.SetAutoFocusEnabled(true)
.Build();
surfaceView.Holder.AddCallback(this);
barcodeDetector.SetProcessor(this);
surfaceView.Visibility = ViewStates.Visible;
_definemethod = "KANBAN";
}
catch (Exception ex)
{
Helper.ShowToastMessage(this, Color.DarkRed, ex.Message, ToastLength.Short);
//Toast.MakeText(this, ex.Message.ToString(), ToastLength.Short).Show();
}
}
NCTB: I noticed that after opening the dialog to scan the QR CODE the ReceiveDetections method get called frequently and the scanned value comes in detections parameter .which is normal and it supposed to do so.But the problem is after a successful scan it should not call anymore.
I am working on EF. I am trying to insert into a table, the insert function is in a thread.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
int bytes = port.BytesToRead;
//string indata = sp.ReadExisting();
Thread.Sleep(50);
try
{
receivedBytes = port.BaseStream.Read(buffer, 0, (int)buffer.Length);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
var receiveData = BitConverter.ToString(buffer, 0, receivedBytes);
var finalData = receiveData.Replace("-", "");
//Thread.Sleep(100);
Console.WriteLine("Thread Going to Start");
new Thread(() => {
SaveData(finalData);
}).Start(); // starting the thread
port.DiscardOutBuffer();
port.DiscardInBuffer();
}
And this is my save data function
public void SaveData(string finalData)
{
Console.WriteLine(LineNumber() + "Data Transmiting...");
thread = Thread.CurrentThread;
mdc_dbEntities e = new mdc_dbEntities();
var msn = e.mdc_meter_config.Where(m => m.m_hex == sr).Select(s => new { s.msn, s.p_id, s.meter_id }).ToList();
var H = finalData.Substring(0, 2);
using (mdc_dbEntities u = new mdc_dbEntities())
{
foreach (var res in msn)
{
var cust_id = e.mdc_meter_cust_rel.Where(m => m.msn == res.msn)
.Select(s => s.cust_id)
.FirstOrDefault();
mdc_meters_data data = new mdc_meters_data()
{
msn = res.msn,
cust_id = cust_id,
device_id = res.meter_id.ToString(),
kwh = e_val.ToString(),
voltage_p1 = a_vol_val.ToString(),
voltage_p2 = b_vol_val.ToString(),
voltage_p3 = c_vol_val.ToString(),
current_p1 = a_curr_val.ToString(),
current_p2 = b_curr_val.ToString(),
current_p3 = c_curr_val.ToString(),
data_date_time = Convert.ToDateTime(theDate.ToString(format)),
d_type = d_type.ToString(),
pf1 = a_pf_val.ToString(),
pf2 = b_pf_val.ToString(),
pf3 = c_pf_val.ToString(),
p_id = res.p_id,
};
u.mdc_meters_data.Add(data);
}
u.SaveChanges();
}
Console.WriteLine(LineNumber() + "Data Saved");
Thread.Sleep(50);
}
try
{
thread.Abort(); // aborting it after insertion
//Thread.Sleep(50);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
}
The above code runs for some time, but after that I encountered an error at u.SaveChanges();
System.Data.Entity.Core.EntityException: 'An error occurred while closing the provider connection. See the inner exception for details.'
MySqlException: Fatal error encountered during command execution.
MySqlException: Fatal error encountered attempting to read the resultset.
MySqlException: Reading from the stream has failed.
IOException: Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
I have looked into each solution and tried them but still unable to resolve this issue. I must be missing something that I don't know.
Update 1 My whole code
Calling constructor
public CommunicationEngine()
{
port.ReadTimeout = 500;
port.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
port.Open();
Console.WriteLine("Port opened successfully");
Console.WriteLine("I am Recieving");
}
Calling handler
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
int bytes = port.BytesToRead;
Thread.Sleep(50);
Console.WriteLine("Bytes are ok..." + port.BytesToRead + " Recieved ");
try
{
receivedBytes = port.BaseStream.Read(buffer, 0, (int)buffer.Length);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
var receiveData = BitConverter.ToString(buffer, 0, receivedBytes);
var finalData = receiveData.Replace("-", "");
//Thread.Sleep(100);
Console.WriteLine("Thread Going to Start");
try
{
new Thread(() => {
SaveData(finalData);
}).Start();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
port.DiscardOutBuffer(); port.DiscardInBuffer();
}
Saving data into DB
public void SaveData(string finalData)
{
Console.WriteLine(LineNumber() + "Data Transmiting...");
thread = Thread.CurrentThread;
if (finalData.Length == 138)
{
comm = true;
var H = finalData.Substring(0, 2);
var FC = finalData.Substring(2, 9);
var len = finalData.Substring(10, 2);
var sr = finalData.Substring(12, 12);
var energy_tag = finalData.Substring(24, 4);
var e_val = hexToDec(finalData.Substring(28, 8)) / 10;
var a_curr_tag = finalData.Substring(36, 4);
var a_curr_val = hexToDec(finalData.Substring(40, 8)) / 1000;
var b_curr_tag = finalData.Substring(48, 4);
var b_curr_val = hexToDec(finalData.Substring(52, 8)) / 1000;
var c_curr_tag = finalData.Substring(60, 4);
var c_curr_val = hexToDec(finalData.Substring(64, 8)) / 1000;
var a_vol_tag = finalData.Substring(72, 4);
var a_vol_val = hexToDec(finalData.Substring(76, 8)) / 10;
var b_vol_tag = finalData.Substring(84, 4);
var b_vol_val = hexToDec(finalData.Substring(88, 8)) / 10;
var c_vol_tag = finalData.Substring(96, 4);
var c_vol_val = hexToDec(finalData.Substring(100, 8)) / 10;
var a_pf_tag = finalData.Substring(108, 4);
var a_pf_val = hexToDec(finalData.Substring(112, 4)) / 1000;
var b_pf_tag = finalData.Substring(116, 4);
var b_pf_val = hexToDec(finalData.Substring(120, 4)) / 1000;
var c_pf_tag = finalData.Substring(124, 4);
var c_pf_val = hexToDec(finalData.Substring(128, 4)) / 1000;
var crc = finalData.Substring(132, 4);
var ftr = finalData.Substring(136, 2);
var d_type = "600";
DateTime theDate = DateTime.Now;
string format = "yyyy-MM-dd HH:mm:ss";
Console.WriteLine(LineNumber() + "Data Ready to be inserted in DB");
using (mdc_dbEntities u = new mdc_dbEntities())
{
var msnList = u.mdc_meter_config.Where(m => m.m_hex == sr)
.Select(s => new { s.msn, s.p_id, s.meter_id })
.ToList();
foreach (var res in msnList)
{
var cust_id = u.mdc_meter_cust_rel.Where(m => m.msn == res.msn)
.Select(s => s.cust_id)
.FirstOrDefault();
mdc_meters_data data = new mdc_meters_data()
{
msn = res.msn,
cust_id = cust_id,
device_id = res.meter_id.ToString(),
kwh = e_val.ToString(),
voltage_p1 = a_vol_val.ToString(),
voltage_p2 = b_vol_val.ToString(),
voltage_p3 = c_vol_val.ToString(),
current_p1 = a_curr_val.ToString(),
current_p2 = b_curr_val.ToString(),
current_p3 = c_curr_val.ToString(),
data_date_time = Convert.ToDateTime(theDate.ToString(format)),
d_type = d_type.ToString(),
pf1 = a_pf_val.ToString(),
pf2 = b_pf_val.ToString(),
pf3 = c_pf_val.ToString(),
p_id = res.p_id,
};
u.mdc_meters_data.Add(data);
}
try
{
u.SaveChanges();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
}
Console.WriteLine(LineNumber() + "Data Saved");
Thread.Sleep(50);
}
else if(finalData.Length == 30)
{
var msn_no = finalData.Substring(12, 12);
mdc_dbEntities p = new mdc_dbEntities();
var update = p.meter_control.Where(c => (c.comm_executed == 0))
.Where(o => (o.m_hex == msn_no))
.SingleOrDefault();
if(update.comm_sent == "Disconnect")
{
update.comm_executed = 1;
update.comm = 0;
p.SaveChanges();
Console.WriteLine("Meter Disconnected....");
}
else if(update.comm_sent == "Connect")
{
update.comm_executed = 1;
update.comm = 1;
p.SaveChanges();
Console.WriteLine("Meter Connected....");
}
comm = true;
}
else
{
comm = true;
}
try
{
thread.Abort();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
}
Any help would be highly appreciated.
Executing EF related changes in a manually initiated thread is not a good idea. Try to run the EF changes in the same thread. If you are bothered with processing incoming requests, use Async, and Await feature. I have modified your code to accommodate this feature. Please try this.
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
int bytes = port.BytesToRead;
//string indata = sp.ReadExisting();
try
{
receivedBytes = port.BaseStream.Read(buffer, 0, (int)buffer.Length);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message.ToString());
}
var receiveData = BitConverter.ToString(buffer, 0, receivedBytes);
var finalData = receiveData.Replace("-", "");
Console.WriteLine("Thread Going to Start");
SaveDataAsync(finalData).Wait(); // this call will become sync and runs under main thread.
port.DiscardOutBuffer();
port.DiscardInBuffer();
}
public async Task<bool> SaveDataAsync(string finalData)
{
mdc_dbEntities e = new mdc_dbEntities();
var msn = e.mdc_meter_config.Where(m => m.m_hex == sr).Select(s => new { s.msn, s.p_id, s.meter_id }).ToList();
var H = finalData.Substring(0, 2);
var isSaveSuccess = false;
using (mdc_dbEntities u = new mdc_dbEntities())
{
foreach (var res in msn)
{
var cust_id = e.mdc_meter_cust_rel.Where(m => m.msn == res.msn)
.Select(s => s.cust_id)
.FirstOrDefault();
mdc_meters_data data = new mdc_meters_data()
{
msn = res.msn,
cust_id = cust_id,
device_id = res.meter_id.ToString(),
kwh = e_val.ToString(),
voltage_p1 = a_vol_val.ToString(),
voltage_p2 = b_vol_val.ToString(),
voltage_p3 = c_vol_val.ToString(),
current_p1 = a_curr_val.ToString(),
current_p2 = b_curr_val.ToString(),
current_p3 = c_curr_val.ToString(),
data_date_time = Convert.ToDateTime(theDate.ToString(format)),
d_type = d_type.ToString(),
pf1 = a_pf_val.ToString(),
pf2 = b_pf_val.ToString(),
pf3 = c_pf_val.ToString(),
p_id = res.p_id,
};
u.mdc_meters_data.Add(data);
}
isSaveSuccess = (await u.SaveChangesAsync())>0; // if records inserted, the count will be more than 0
}
return isSaveSuccess;
}
}
this is easier to read and may help
saying all this please ensure that you can actually make a connection to the db
double check connectionString
public void SaveData(string finalData)
{
Console.WriteLine(LineNumber() + "Data Transmiting...");
using (mdc_dbEntities dbContext = new mdc_dbEntities())
{
var msnList = dbContext.mdc_meter_config.Where(m => m.m_hex == sr)
.Select(s => new { s.msn, s.p_id, s.meter_id })
.ToList();
//put debug point here and check that msnList is populated
foreach (var item in msnList)
{
//this is slow as it will be a db query for each loop
var cust_id = dbContext.mdc_meter_cust_rel.Where(m => m.msn == item.msn)
.Select(s => s.cust_id)
.FirstOrDefault();
var data = new mdc_meters_data()
{
msn = item.msn,
cust_id = cust_id,
device_id = item.meter_id.ToString(),
kwh = e_val.ToString(),
voltage_p1 = a_vol_val.ToString(),
voltage_p2 = b_vol_val.ToString(),
voltage_p3 = c_vol_val.ToString(),
current_p1 = a_curr_val.ToString(),
current_p2 = b_curr_val.ToString(),
current_p3 = c_curr_val.ToString(),
data_date_time = Convert.ToDateTime(theDate.ToString(format)),
d_type = d_type.ToString(),
pf1 = a_pf_val.ToString(),
pf2 = b_pf_val.ToString(),
pf3 = c_pf_val.ToString(),
p_id = item.p_id,
};
dbContext.mdc_meters_data.Add(data);
}
//depending on how many you added this may take some time.
dbContext.SaveChanges();
}
}
I am running on TestNet. I am trying to add multiple transaction inputs TxIn() so as to spend from these inputs. When I broadcast my transaction, it returns successful but I can't see it on the block-explorer. I have handled a transaction with a single TxIn() and when I broadcast it, it was successful and i could view it on the block-explorer. I have been on this for more than 2 days now. Will greatly appreciate your help guys
var bitcoinPrivateKey = new BitcoinSecret("cNZupUgfs54DmsShwxa1wpomQcszUtuJYFvx9zWPbXrT7KsWtiUd");
var network = bitcoinPrivateKey.Network;
var address = bitcoinPrivateKey.GetAddress();
var client = new QBitNinjaClient(network);
var balance = client.GetBalance(address).Result;
var transactionId = uint256.Parse("06c0aec7543467951abad0c28998a2c1fc1cdc34e01113f8ec1fdb22be854771");
var transactionResponse = client.GetTransaction(transactionId).Result;
var tx = new Transaction();
foreach (var operation in balance.Operations)
{
OutPoint spendOutPoint = null;
var coinsReceived = operation.ReceivedCoins;
foreach (var coin in coinsReceived)
{
if (coin.TxOut.ScriptPubKey == bitcoinPrivateKey.ScriptPubKey)
{
spendOutPoint = coin.Outpoint;
tx.Inputs.Add(new TxIn()
{
PrevOut = spendOutPoint
});
}
}
}
var chimaTestDestinationAddress = new BitcoinPubKeyAddress("mxgN2AiqHjKfGvo6Y57fAe4Y754rPdKf4P");
TxOut chimaTestDestinationAddressTxOut = new TxOut()
{
Value = new Money((decimal)0.50, MoneyUnit.BTC),
ScriptPubKey = chimaTestDestinationAddress.ScriptPubKey
};
TxOut ugoChangeBackTxOut = new TxOut()
{
Value = new Money((decimal)2.98, MoneyUnit.BTC),
ScriptPubKey = bitcoinPrivateKey.ScriptPubKey
};
tx.Outputs.Add(chimaTestDestinationAddressTxOut);
tx.Outputs.Add(ugoChangeBackTxOut);
var msg = "ugo the jedi master";
var msgBytes = Encoding.UTF8.GetBytes(msg);
TxOut txDesc = new TxOut()
{
Value = Money.Zero,
ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(msgBytes)
};
tx.Outputs.Add(txDesc);
tx.Inputs[0].ScriptSig = bitcoinPrivateKey.PubKey.WitHash.ScriptPubKey;
tx.Inputs[1].ScriptSig = bitcoinPrivateKey.PubKey.WitHash.ScriptPubKey;
tx.Inputs[2].ScriptSig = bitcoinPrivateKey.PubKey.WitHash.ScriptPubKey;
tx.Inputs[3].ScriptSig = bitcoinPrivateKey.PubKey.WitHash.ScriptPubKey;
tx.Inputs[4].ScriptSig = bitcoinPrivateKey.PubKey.WitHash.ScriptPubKey;
tx.Sign(bitcoinPrivateKey, false);
BroadcastResponse broadcast = client.Broadcast(tx).Result;
if (!broadcast.Success)
{
Console.WriteLine("ErrorCode: " + broadcast.Error.ErrorCode);
Console.WriteLine("Error message: " + broadcast.Error.Reason);
}
else
{
Console.WriteLine("Success, you can now checkout the transaction in any block explorer");
Console.WriteLine("Hash: " + tx.GetHash());
}
I'm trying to integrate the Royal Mail SOAP API into my .NET Code. I have followed the advice here Consume WCF Royal Mail API in c# Console Application and here C# WCF Namespaces Move To Header & Use NS Prefix.
I have created a custom IClientMessageFormatter to be able to attach the namespaces to the beginning of the soap envelope, but I still can't seem to get this to work. I keep receiving the following error. Could not establish trust relationship for the SSL/TLS secure channel with authority 'api.royalmail.com', and the inner exception is: The remote certificate is invalid according to the validation procedure.
I am using Visual Studio 13 and .Net version 3.5, I've tried numerous other versions but with no further progress. When I debug I can see that the normal message been passed into the RoyalMailMessage but when it runs OnWriteStartEnvelope I can't see any changes to the _message object. I've created a trace to see what soap request is been sent.
I have sent my XML request to Royal Mail support who validate that the reason it is failing is due to the namespaces not been declared in the envelope and the missing prefixes.
RoyalMail.cs
internal class RoyalMail
{
private readonly X509Certificate2 _certificate;
private readonly Config _config;
public RoyalMail()
{
_config = new Config();
_config.LoadConfig();
// Load The SSL Certificate (Check The File Exists)
var certificatePath = (Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + #"\" + _config.GetCertificateName());
if (!File.Exists(certificatePath))
{
throw new Exception(#"The Royal Mail Certificate Is Missing From The Plugins Directory. Please Place The File " + _config.GetCertificateName() + " In The Same Directory As The Plugin DLL File & Relaunch FileMaker.\n\n" + certificatePath);
}
_certificate = new X509Certificate2(certificatePath, _config.GetCertificatePassword());
// Check It's In The Certificate
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
if (!store.Certificates.Contains(_certificate))
{
store.Add(_certificate);
MessageBox.Show("Certificate Was Installed Into Computer Trust Store");
}
store.Close();
}
/*
*
* SOAP Service & Methods
*
*/
private shippingAPIPortTypeClient GetProxy()
{
var myBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport)
{
MaxReceivedMessageSize = 2147483647
};
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var uri = new Uri(_config.GetEndpointUrl());
var endpointIdentity = EndpointIdentity.CreateDnsIdentity("api.royalmail.com");
var shippingClient = new shippingAPIPortTypeClient(myBinding, new EndpointAddress(uri, endpointIdentity, new AddressHeaderCollection()));
if (shippingClient.ClientCredentials != null)
shippingClient.ClientCredentials.ClientCertificate.Certificate = _certificate;
foreach (var od in shippingClient.Endpoint.Contract.Operations)
{
od.Behaviors.Add(new RoyalMailIEndpointBehavior());
}
return shippingClient;
}
private SecurityHeaderType GetSecurityHeaderType()
{
var securityHeader = new SecurityHeaderType();
var creationDate = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
var nonce = (new Random().Next(0, int.MaxValue)).ToString();
var hashedPassword = GetSha1(_config.GetPassword());
var concatednatedDigestInput = string.Concat(nonce, creationDate, Encoding.Default.GetString(hashedPassword));
var digest = GetSha1(concatednatedDigestInput);
var passwordDigest = Convert.ToBase64String(digest);
var encodedNonce = Convert.ToBase64String(Encoding.Default.GetBytes(nonce));
var doc = new XmlDocument();
using (var writer = doc.CreateNavigator().AppendChild())
{
writer.WriteStartDocument();
writer.WriteStartElement("wsse", "Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteStartElement("wsse", "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteElementString("wsse", "Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", _config.GetUsername());
writer.WriteElementString("wsse", "Password", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", passwordDigest);
writer.WriteElementString("wsse", "Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", encodedNonce);
writer.WriteElementString("wsse", "Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", creationDate);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
}
if (doc.DocumentElement != null)
{
doc.DocumentElement.RemoveAllAttributes();
var headers = doc.DocumentElement.ChildNodes.Cast<XmlElement>().ToArray();
securityHeader.Any = headers;
}
return securityHeader;
}
private integrationHeader GetIntegrationHeader()
{
var header = new integrationHeader();
var created = DateTime.Now;
var createdAt = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
header.dateTime = created;
header.version = int.Parse(_config.GetVersion());
header.dateTimeSpecified = true;
header.versionSpecified = true;
var idStructure = new identificationStructure {applicationId = _config.GetApplicationId()};
var nonce = new Random().Next(0, int.MaxValue).ToString();
idStructure.transactionId = CalculateMd5Hash(nonce + createdAt);
header.identification = idStructure;
return header;
}
private static byte[] GetSha1(string input)
{
return SHA1Managed.Create().ComputeHash(Encoding.Default.GetBytes(input));
}
public string CalculateMd5Hash(string input)
{
// step 1, calculate MD5 hash from input
var md5 = MD5.Create();
var inputBytes = Encoding.ASCII.GetBytes(input);
var hash = md5.ComputeHash(inputBytes);
// step 2, convert byte array to hex string
var sb = new StringBuilder();
foreach (var t in hash)
{
sb.Append(t.ToString("X2"));
}
return sb.ToString();
}
/*
* Check Response Footer For Errors & Warnings From Service
* If Error Return True So We Can Inform File maker Of Error
* Ignore Warnings For Now
*
*/
private static void CheckErrorsAndWarnings(integrationFooter integrationFooter)
{
if (integrationFooter != null)
{
if (integrationFooter.errors != null && integrationFooter.errors.Length > 0)
{
var errors = integrationFooter.errors;
foreach (var error in errors)
{
MessageBox.Show("Royal Mail Request Error: " + error.errorDescription + ". " + error.errorResolution, "Royal Mail Request Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
if (errors.Length > 0)
{
return;
}
}
if (integrationFooter.warnings != null && integrationFooter.warnings.Length > 0)
{
var warnings = integrationFooter.warnings;
foreach (var warning in warnings)
{
MessageBox.Show("Royal Mail Request Warning: " + warning.warningDescription + ". " + warning.warningResolution, "Royal Mail Request Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
}
}
}
}
/*
* Show Message Box With SOAP Error If We Receive A Fault Code Back From Service
*
*/
private static void ShowSoapException(FaultException e)
{
var message = e.CreateMessageFault();
var errorDetail = message.GetDetail<XmlElement>();
var errorDetails = errorDetail.ChildNodes;
var fullErrorDetails = "";
for (var i = 0; i < errorDetails.Count; i++)
{
var xmlNode = errorDetails.Item(i);
if (xmlNode != null)
fullErrorDetails += xmlNode.Name + ": " + xmlNode.InnerText + "\n";
}
MessageBox.Show("An Error Occured With Royal Mail Service: " + message.Reason + "\n\n" + fullErrorDetails, "Royal Mail SOAP Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
public createShipmentResponse SendCreateShipmentRequest(CreateShipmentForm shippingForm)
{
var client = GetProxy();
try
{
var request = new createShipmentRequest {integrationHeader = GetIntegrationHeader()};
var shipment = new requestedShipment();
// Shipment Type Code (Delivery or Return)
var shipmentType = new referenceDataType {code = shippingForm.ShippingType};
shipment.shipmentType = shipmentType;
// Service Type Code (1:24H 1st Class, 2: 48H 2nd Class, D: Special Delivery Guaranteed, H: HM Forces (BFPO), I: International, R: Tracked Returns, T: Tracked Domestic)
var serviceType = new referenceDataType {code = shippingForm.ServiceType};
shipment.serviceType = serviceType;
// Service Offering (See Royal Mail Service Offering Type Codes. Too Many To List)
var serviceOfferingTypeContainer = new serviceOfferingType();
var serviceOffering = new referenceDataType {code = shippingForm.ServiceOffering};
serviceOfferingTypeContainer.serviceOfferingCode = serviceOffering;
shipment.serviceOffering = serviceOfferingTypeContainer;
// Service Format Code
var serviceFormatTypeContainer = new serviceFormatType();
var serviceFormat = new referenceDataType {code = shippingForm.ServiceFormat};
serviceFormatTypeContainer.serviceFormatCode = serviceFormat;
shipment.serviceFormat = serviceFormatTypeContainer;
// Shipping Date
shipment.shippingDate = shippingForm.ShippingDate;
shipment.shippingDateSpecified = true;
shipment.signature = true;
shipment.signatureSpecified = true;
// Sender Reference Number (e.g. Invoice Number or RA Number)
shipment.senderReference = shippingForm.InvoiceNumber;
/*
* Service Enhancements
*/
var serviceEnhancements = new List<serviceEnhancementType>();
shipment.serviceEnhancements = serviceEnhancements.ToArray();
/*
* Recipient Contact Details
*/
var recipientContact = new contact();
recipientContact.complementaryName = shippingForm.Company;
recipientContact.name = shippingForm.Name;
if(!shippingForm.EmailAddress.Equals("")) {
var email = new digitalAddress {electronicAddress = shippingForm.EmailAddress};
recipientContact.electronicAddress = email;
}
if(!shippingForm.MobileNumber.Equals("")) {
var tel = new telephoneNumber();
var phoneRegex = new Regex(#"[^\d]");
tel.telephoneNumber1 = phoneRegex.Replace(shippingForm.MobileNumber, "");
tel.countryCode = "00" + shippingForm.CountryDiallingCode;
recipientContact.telephoneNumber = tel;
}
shipment.recipientContact = recipientContact;
/*
* Recipient Address
*
*/
var recipientAddress = new address
{
addressLine1 = shippingForm.AddressLine1,
addressLine2 = shippingForm.AddressLine2,
addressLine3 = shippingForm.AddressLine3,
addressLine4 = shippingForm.County,
postTown = shippingForm.Town
};
var country = new countryType();
var countryCode = new referenceDataType { code = shippingForm.CountryCode };
country.countryCode = countryCode;
recipientAddress.country = country;
recipientAddress.postcode = shippingForm.PostCode;
recipientAddress.stateOrProvince = new stateOrProvinceType {stateOrProvinceCode = new referenceDataType()};
shipment.recipientAddress = recipientAddress;
// Shipment Items
var items = new List<item> ();
foreach(var i in shippingForm.Items) {
var item = new item
{
numberOfItems = i.Products.Count.ToString(),
weight = new dimension
{
value = i.Weight*1000,
unitOfMeasure = new unitOfMeasureType {unitOfMeasureCode = new referenceDataType {code = "g"}}
}
};
items.Add(item);
}
if (shippingForm.ServiceType.Contains("international"))
{
var internationalInfo = new internationalInfo
{
shipperExporterVatNo = _config.GetVatNumber(),
documentsOnly = false,
shipmentDescription = "Invoice Number: " + shippingForm.InvoiceNumber,
invoiceDate = DateTime.Now,
termsOfDelivery = "EXW",
invoiceDateSpecified = true,
purchaseOrderRef = shippingForm.InvoiceNumber
};
var parcels = new List<parcel>();
foreach (var i in shippingForm.Items)
{
var parcel = new parcel
{
weight = new dimension
{
value = i.Weight*1000,
unitOfMeasure = new unitOfMeasureType
{
unitOfMeasureCode = new referenceDataType {code = "g"}
}
},
invoiceNumber = shippingForm.InvoiceNumber,
purposeOfShipment = new referenceDataType {code = "31"}
};
var contents = new List<contentDetail>();
foreach (var product in i.Products)
{
var contentDetail = new contentDetail
{
articleReference = product.Sku,
countryOfManufacture = new countryType
{
countryCode = new referenceDataType
{
code = product.CountryOfManufacture
}
},
currencyCode = new referenceDataType {code = product.CurrencyCode},
description = product.Name,
unitQuantity = product.Qty.ToString(),
unitValue = product.Price,
unitWeight = new dimension
{
value = Convert.ToSingle(product.Weight*1000),
unitOfMeasure = new unitOfMeasureType
{
unitOfMeasureCode = new referenceDataType {code = "g"}
}
}
};
contents.Add(contentDetail);
}
//Parcel.contentDetails = Contents.ToArray();
parcels.Add(parcel);
}
internationalInfo.parcels = parcels.ToArray();
shipment.internationalInfo = internationalInfo;
}
else
{
shipment.items = items.ToArray();
}
request.requestedShipment = shipment;
var response = client.createShipment(GetSecurityHeaderType(), request);
// Show Errors And Warnings
CheckErrorsAndWarnings(response.integrationFooter);
return response;
}
catch (TimeoutException e)
{
client.Abort();
MessageBox.Show("Request Timed Out: " + e.Message, "Request Timeout", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
catch (FaultException e)
{
client.Abort();
ShowSoapException(e);
}
catch (CommunicationException e)
{
client.Abort();
MessageBox.Show("A communication error has occurred: " + e.Message + " - " + e.StackTrace, "Communication Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
catch (Exception e)
{
client.Abort();
MessageBox.Show(e.Message, "Royal Mail Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
return null;
}
}
RoyalmailMessage.cs
class RoyalMailMessage : Message
{
public Message _message;
public RoyalMailMessage(Message message)
{
_message = message;
}
public override MessageHeaders Headers
{
get
{
return _message.Headers;
}
}
public override MessageProperties Properties
{
get
{
return _message.Properties;
}
}
public override MessageVersion Version
{
get
{
return _message.Version;
}
}
protected override void OnWriteStartBody(XmlDictionaryWriter writer)
{
writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/");
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
_message.WriteBodyContents(writer);
}
protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
{
writer.WriteStartElement("soapenv", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
writer.WriteAttributeString("xmlns", "v2", null, "http://www.royalmailgroup.com/api/ship/V2");
writer.WriteAttributeString("xmlns", "v1", null, "http://www.royalmailgroup.com/integration/core/V1");
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
}
}
RoyalMailMessageFormatter.cs
public class RoyalMailMessageFormatter : IClientMessageFormatter
{
private readonly IClientMessageFormatter _formatter;
public RoyalMailMessageFormatter(IClientMessageFormatter formatter)
{
_formatter = formatter;
}
public object DeserializeReply(Message message, object[] parameters)
{
return _formatter.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
var message = _formatter.SerializeRequest(messageVersion, parameters);
return new RoyalMailMessage(message);
}
}
RoyalMailIEndpointBehavior.cs
internal class RoyalMailIEndpointBehavior : IOperationBehavior
{
public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
proxy.Formatter = new RoyalMailMessageFormatter(proxy.Formatter);
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
}
public void Validate(OperationDescription operationDescription)
{
}
}
The error you are getting is basically because of the certificate.
Having said that, I think you should use the v2 of the API as although it is still awful, there are examples out there and you don't need to use a cert.
Rick Strahl has successfully changed the namespaces in the v2 version, see here https://weblog.west-wind.com/posts/2016/Apr/02/Custom-Message-Formatting-in-WCF-to-add-all-Namespaces-to-the-SOAP-Envelope .
There is one new Royal Mail Shipping API 2 available , after I've lost many hours try development the integration with Royal Mail I finally found a way. I'm sharing my project in the git.
https://github.com/americoa/RoyalMailShippingAPIV2
I am trying to consume Royal Mail shipping API in my C# Console Application but I am stuck. When I make a call to the API, it says Invalid Request..
This is what I did so far
RoyalMailMessage.cs
class RoyalMailMessage : Message
{
private readonly Message message;
public RoyalMailMessage(Message message)
{
this.message = message;
}
public override MessageHeaders Headers
{
get
{
return this.message.Headers;
}
}
public override MessageProperties Properties
{
get
{
return this.message.Properties;
}
}
public override MessageVersion Version
{
get
{
return this.message.Version;
}
}
protected override void OnWriteStartBody(XmlDictionaryWriter writer)
{
writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/");
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
this.message.WriteBodyContents(writer);
}
protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
{
writer.WriteStartElement("s", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
writer.WriteAttributeString("xmlns", "v2", null, "http://www.royalmailgroup.com/api/ship/V2");
writer.WriteAttributeString("xmlns", "v1", null, "http://www.royalmailgroup.com/integration/core/V1");
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
}
}
RoyalMailMessageFormatter.cs
public class RoyalMailMessageFormatter : IClientMessageFormatter
{
private readonly IClientMessageFormatter formatter;
public RoyalMailMessageFormatter(IClientMessageFormatter formatter)
{
this.formatter = formatter;
}
public object DeserializeReply(Message message, object[] parameters)
{
return this.formatter.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
var message = this.formatter.SerializeRequest(messageVersion, parameters);
return new RoyalMailMessage(message);
}
}
RoyalMailIEndpointBehavior.cs
class RoyalMailIEndpointBehavior : IOperationBehavior
{
public RoyalMailIEndpointBehavior() { }
public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
{
IClientMessageFormatter currentFormatter = proxy.Formatter;
proxy.Formatter = new RoyalMailMessageFormatter(currentFormatter);
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
}
public void Validate(OperationDescription operationDescription)
{
}
}
Program.cs
class Program
{
static void Main(string[] args)
{
try
{
using (var shippingService = new shippingAPIPortTypeClient())
{
shippingService.ClientCredentials.UserName.UserName = "xxxx";
shippingService.ClientCredentials.UserName.Password = "xxxxx";
foreach (OperationDescription od in shippingService.Endpoint.Contract.Operations)
{
od.Behaviors.Add(new RoyalMailIEndpointBehavior());
}
var createShipment = new createShipmentRequest()
{
integrationHeader = new integrationHeader()
{
dateTime = DateTime.Now,
dateTimeSpecified = true,
debugFlag = false,
debugFlagSpecified = false,
identification = new identificationStructure()
{
applicationId = "xxxx",
endUserId = "Sandra",
intermediaryId = "null",
transactionId = "123456789"
},
performanceFlag = false,
performanceFlagSpecified = false,
testFlag = false,
testFlagSpecified = false,
version = 1,
versionSpecified = false
},
requestedShipment = new requestedShipment()
{
bfpoFormat = new bFPOFormatType()
{
bFPOFormatCode = null,
},
customerReference = "",
departmentReference = "",
}
};
shippingService.createShipment(null, createShipment);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="shippingAPISoapBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://api.royalmail.com/shipping/onboarding" binding="basicHttpBinding"
bindingConfiguration="shippingAPISoapBinding" contract="ShippingService.shippingAPIPortType"
name="shippingAPIPort" behaviorConfiguration="CustomBehavior" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="CustomBehavior">
<clientCredentials>
<clientCertificate findValue="RM10001815" x509FindType="FindBySubjectName"
storeLocation="CurrentUser" storeName="My" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Now, when I make a call to the API, it says "Invalid Request"..I am not sure if I missing anything, may be adding credentials in Soap Envelop header like below?
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>xxxx</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">xxxx</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">xWstjXG0iUxbv3NH/fX+kw==</wsse:Nonce>
<wsu:Created>2014-08-16T15:29:42</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
Firstly you are missing the security header as you have already identified, plus a whole host of other fields in your createShipment request such as address, service code etc. I would strongly suggest using fiddler to capture your SOAP requests and responses, they will give you a lot more insight into what is happening. You can also compare the requests you are generating with the example requests provided by royal mail onboarding.
Looking at your code, you are not attaching the security tokens (the wsse) which needs to be unique for every request you make (The nonce token that is). You are also missing a variety of other required fields for the createShipemt request such as address, service code and type etc.
I had to attach the certificate and key to the request to make it work as well. Below are some fragments of the code I created to make this work, it's not a copy paste solution but better than anything else you will find out there with regards to Royal Mail and C# and should point you in the right direction.
Please note, I have config class which loads a lot of the settings from an sqlite database (not posted). The values for the createShipment request are coming from a form (not posted) which is pre-populated with the data but allows the user in our warehouse to alter and adjust accordingly. You have already made use of my custom message formatter example from post (C# WCF (Royal Mail SOAP API) Declare Namespace In Header) to handle the namespace issue. Royal Mail API is not easy to implement in C#, took me nearly 2 days to get a valid request and response and as I say, you really need to capture the requests and responses to work out what is going on.
private X509Certificate2 certificate;
private Config config;
public RoyalMail() {
// Load The Config
config = new Config();
config.loadConfig();
// Load The SSL Certificate (Check The File Exists)
String certificatePath = (Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + #"\" + config.GetCertificateName());
if (!System.IO.File.Exists(certificatePath))
{
throw new Exception(#"The Royal Mail Certificate Is Missing From The Plugins Directory. Please Place The File " + config.GetCertificateName() + " In The Same Directory As The Plugin DLL File & Relaunch FileMaker.\n\n" + certificatePath);
}
certificate = new X509Certificate2(certificatePath, config.GetCertificatePassword());
// Check It's In The Certificate
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
if (!store.Certificates.Contains(certificate))
{
store.Add(certificate);
MessageBox.Show("Certificate Was Installed Into Computer Trust Store");
}
store.Close();
}
/*
*
* SOAP Service & Methods
*
*/
private shippingAPIPortTypeClient GetProxy()
{
BasicHttpBinding myBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
myBinding.MaxReceivedMessageSize = 2147483647;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
shippingClient = new shippingAPIPortTypeClient(myBinding, new EndpointAddress(new Uri(config.GetEndpointURL()), EndpointIdentity.CreateDnsIdentity("api.royalmail.com"), new AddressHeaderCollection()));
shippingClient.ClientCredentials.ClientCertificate.Certificate = certificate;
foreach (OperationDescription od in shippingClient.Endpoint.Contract.Operations)
{
od.Behaviors.Add(new RoyalMailIEndpointBehavior());
}
return shippingClient;
}
private SecurityHeaderType GetSecurityHeaderType()
{
SecurityHeaderType securityHeader = new SecurityHeaderType();
DateTime created = DateTime.Now;
string creationDate;
creationDate = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
string nonce = nonce = (new Random().Next(0, int.MaxValue)).ToString();
byte[] hashedPassword;
hashedPassword = GetSHA1(config.GetPassword());
string concatednatedDigestInput = string.Concat(nonce, creationDate, Encoding.Default.GetString(hashedPassword));
byte[] digest;
digest = GetSHA1(concatednatedDigestInput);
string passwordDigest;
passwordDigest = Convert.ToBase64String(digest);
string encodedNonce;
encodedNonce = Convert.ToBase64String(Encoding.Default.GetBytes(nonce));
XmlDocument doc = new XmlDocument();
using (XmlWriter writer = doc.CreateNavigator().AppendChild())
{
writer.WriteStartDocument();
writer.WriteStartElement("Security");
writer.WriteStartElement("UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteElementString("Username", config.GetUsername());
writer.WriteElementString("Password", passwordDigest);
writer.WriteElementString("Nonce", encodedNonce);
writer.WriteElementString("Created", creationDate);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
}
doc.DocumentElement.RemoveAllAttributes();
System.Xml.XmlElement[] headers = doc.DocumentElement.ChildNodes.Cast<XmlElement>().ToArray<XmlElement>();
securityHeader.Any = headers;
return securityHeader;
}
private integrationHeader GetIntegrationHeader()
{
integrationHeader header = new integrationHeader();
DateTime created = DateTime.Now;
String createdAt = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
header.dateTime = created;
header.version = Int32.Parse(config.GetVersion());
header.dateTimeSpecified = true;
header.versionSpecified = true;
identificationStructure idStructure = new identificationStructure();
idStructure.applicationId = config.GetApplicationID();
string nonce = nonce = (new Random().Next(0, int.MaxValue)).ToString();
idStructure.transactionId = CalculateMD5Hash(nonce + createdAt);
header.identification = idStructure;
return header;
}
private static byte[] GetSHA1(string input)
{
return SHA1Managed.Create().ComputeHash(Encoding.Default.GetBytes(input));
}
public string CalculateMD5Hash(string input)
{
// step 1, calculate MD5 hash from input
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hash = md5.ComputeHash(inputBytes);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
return sb.ToString();
}
/*
* Check Response Footer For Errors & Warnings From Service
* If Error Return True So We Can Inform Filemaker Of Error
* Ignore Warnings For Now
*
*/
private bool checkErrorsAndWarnings(integrationFooter integrationFooter)
{
if (integrationFooter != null)
{
if (integrationFooter.errors != null && integrationFooter.errors.Length > 0)
{
errorDetail[] errors = integrationFooter.errors;
for (int i = 0; i < errors.Length; i++)
{
errorDetail error = errors[i];
MessageBox.Show("Royal Mail Request Error: " + error.errorDescription + ". " + error.errorResolution, "Royal Mail Request Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
if (errors.Length > 0)
{
return true;
}
}
if (integrationFooter.warnings != null && integrationFooter.warnings.Length > 0)
{
warningDetail[] warnings = integrationFooter.warnings;
for (int i = 0; i < warnings.Length; i++)
{
warningDetail warning = warnings[i];
//MessageBox.Show("Royal Mail Request Warning: " + warning.warningDescription + ". " + warning.warningResolution, "Royal Mail Request Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
}
}
}
return false;
}
/*
* Show Message Box With SOAP Error If We Receive A Fault Code Back From Service
*
*/
private void showSoapException(FaultException e)
{
MessageFault message = e.CreateMessageFault();
XmlElement errorDetail = message.GetDetail<XmlElement>();
XmlNodeList errorDetails = errorDetail.ChildNodes;
String fullErrorDetails = "";
for (int i = 0; i < errorDetails.Count; i++)
{
fullErrorDetails += errorDetails.Item(i).Name + ": " + errorDetails.Item(i).InnerText + "\n";
}
MessageBox.Show("An Error Occured With Royal Mail Service: " + message.Reason.ToString() + "\n\n" + fullErrorDetails, "Royal Mail SOAP Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
public createShipmentResponse SendCreateShipmentRequest(CreateShipmentForm shippingForm)
{
shippingAPIPortTypeClient client = GetProxy();
try
{
createShipmentRequest request = new createShipmentRequest();
request.integrationHeader = GetIntegrationHeader();
requestedShipment shipment = new requestedShipment();
// Shipment Type Code (Delivery or Return)
referenceDataType shipmentType = new referenceDataType();
shipmentType.code = shippingForm.GetShippingType();
shipment.shipmentType = shipmentType;
// Service Occurence (Identifies Agreement on Customers Account) Default to 1. Not Required If There Is There Is Only 1 On Account
shipment.serviceOccurrence = config.GetServiceOccurance();
// Service Type Code (1:24H 1st Class, 2: 48H 2nd Class, D: Special Delivery Guaranteed, H: HM Forces (BFPO), I: International, R: Tracked Returns, T: Tracked Domestic)
referenceDataType serviceType = new referenceDataType();
serviceType.code = shippingForm.GetServiceType().GetServiceTypeCode();
shipment.serviceType = serviceType;
// Service Offering (See Royal Mail Service Offering Type Codes. Too Many To List)
serviceOfferingType serviceOfferingTypeContainer = new serviceOfferingType();
referenceDataType serviceOffering = new referenceDataType();
serviceOffering.code = shippingForm.GetServiceOffering().GetCode();
serviceOfferingTypeContainer.serviceOfferingCode = serviceOffering;
shipment.serviceOffering = serviceOfferingTypeContainer;
// Service Format Code
serviceFormatType serviceFormatTypeContainer = new serviceFormatType();
referenceDataType serviceFormat = new referenceDataType();
serviceFormat.code = shippingForm.GetServiceFormat().GetFormat();
serviceFormatTypeContainer.serviceFormatCode = serviceFormat;
shipment.serviceFormat = serviceFormatTypeContainer;
// Shipping Date
shipment.shippingDate = shippingForm.GetShippingDate();
shipment.shippingDateSpecified = true;
// Signature Required (Only Available On Tracked Services)
if (shippingForm.IsSignatureRequired())
{
shipment.signature = true;
}
else
{
shipment.signature = false;
// Leave In Safe Place (Available On Tracked Non Signature Service Offerings)
shipment.safePlace = shippingForm.GetSafePlaceText();
}
shipment.signatureSpecified = true;
// Sender Reference Number (e.g. Invoice Number or RA Number)
shipment.senderReference = shippingForm.GetInvoiceNumber();
/*
* Service Enhancements
*/
List<serviceEnhancementType> serviceEnhancements = new List<serviceEnhancementType>();
List<dataObjects.ServiceEnhancement> selectedEnhancements = shippingForm.GetServiceEnhancements();
for (int i = 0; i < selectedEnhancements.Count; i++)
{
serviceEnhancementType enhancement = new serviceEnhancementType();
referenceDataType enhancementCode = new referenceDataType();
enhancementCode.code = selectedEnhancements.ElementAt(i).GetEnhancementType().ToString();
enhancement.serviceEnhancementCode = enhancementCode;
serviceEnhancements.Add(enhancement);
}
shipment.serviceEnhancements = serviceEnhancements.ToArray();
/*
* Recipient Contact Details
*/
contact recipientContact = new contact();
recipientContact.complementaryName = shippingForm.GetCompany();
recipientContact.name = shippingForm.GetName();
if(!shippingForm.GetEmailAddress().Equals("")) {
digitalAddress email = new digitalAddress();
email.electronicAddress = shippingForm.GetEmailAddress();
recipientContact.electronicAddress = email;
}
if(!shippingForm.GetMobileNumber().Equals("")) {
telephoneNumber tel = new telephoneNumber();
Regex phoneRegex = new Regex(#"[^\d]");
tel.telephoneNumber1 = phoneRegex.Replace(shippingForm.GetMobileNumber(), "");
tel.countryCode = "00" + shippingForm.GetCountry().GetDialingCode();
recipientContact.telephoneNumber = tel;
}
shipment.recipientContact = recipientContact;
/*
* Recipient Address
*
*/
address recipientAddress = new address();
recipientAddress.addressLine1 = shippingForm.GetAddressLine1();
recipientAddress.addressLine2 = shippingForm.GetAddressLine2();
recipientAddress.addressLine3 = shippingForm.GetAddressLine3();
recipientAddress.addressLine4 = shippingForm.GetCounty();
recipientAddress.postTown = shippingForm.GetTown();
countryType country = new countryType();
referenceDataType countryCode = new referenceDataType();
countryCode.code = shippingForm.GetCountry().getCountryCode();
country.countryCode = countryCode;
recipientAddress.country = country;
recipientAddress.postcode = shippingForm.GetPostCode();
recipientAddress.stateOrProvince = new stateOrProvinceType();
recipientAddress.stateOrProvince.stateOrProvinceCode = new referenceDataType();
shipment.recipientAddress = recipientAddress;
// Shipment Items
List<RoyalMailAPI.RoyalMailShippingAPI.item> items = new List<RoyalMailAPI.RoyalMailShippingAPI.item> ();
foreach(dataObjects.Item i in shippingForm.GetItems()) {
RoyalMailAPI.RoyalMailShippingAPI.item item = new RoyalMailAPI.RoyalMailShippingAPI.item();
item.numberOfItems = i.GetQty().ToString();
item.weight = new dimension();
item.weight.value = (float) (i.GetWeight() * 1000);
item.weight.unitOfMeasure = new unitOfMeasureType();
item.weight.unitOfMeasure.unitOfMeasureCode = new referenceDataType();
item.weight.unitOfMeasure.unitOfMeasureCode.code = "g";
items.Add(item);
}
if (shippingForm.GetServiceType().GetDescription().ToLower().Contains("international"))
{
internationalInfo InternationalInfo = new internationalInfo();
InternationalInfo.shipperExporterVatNo = "GB945777273";
InternationalInfo.documentsOnly = false;
InternationalInfo.shipmentDescription = "Invoice Number: " + shippingForm.GetInvoiceNumber();
InternationalInfo.invoiceDate = DateTime.Now;
InternationalInfo.termsOfDelivery = "EXW";
InternationalInfo.invoiceDateSpecified = true;
InternationalInfo.purchaseOrderRef = shippingForm.GetInvoiceNumber();
List<RoyalMailShippingAPI.parcel> parcels = new List<parcel>();
foreach (dataObjects.Item i in shippingForm.GetItems())
{
parcel Parcel = new parcel();
Parcel.weight = new dimension();
Parcel.weight.value = (float)(i.GetWeight() * 1000);
Parcel.weight.unitOfMeasure = new unitOfMeasureType();
Parcel.weight.unitOfMeasure.unitOfMeasureCode = new referenceDataType();
Parcel.weight.unitOfMeasure.unitOfMeasureCode.code = "g";
Parcel.invoiceNumber = shippingForm.GetInvoiceNumber();
Parcel.purposeOfShipment = new referenceDataType();
Parcel.purposeOfShipment.code = "31";
List<contentDetail> Contents = new List<contentDetail>();
foreach (RoyalMailAPI.dataObjects.ProductDetail product in i.GetProducts())
{
contentDetail ContentDetail = new contentDetail();
ContentDetail.articleReference = product.Sku;
ContentDetail.countryOfManufacture = new countryType();
ContentDetail.countryOfManufacture.countryCode = new referenceDataType();
ContentDetail.countryOfManufacture.countryCode.code = product.CountryOfManufacture;
ContentDetail.currencyCode = new referenceDataType();
ContentDetail.currencyCode.code = product.CurrencyCode;
ContentDetail.description = product.Name;
ContentDetail.unitQuantity = product.Qty.ToString();
ContentDetail.unitValue = Convert.ToDecimal(product.Price);
ContentDetail.unitWeight = new dimension();
ContentDetail.unitWeight.value = Convert.ToSingle(product.Weight * 1000);
ContentDetail.unitWeight.unitOfMeasure = new unitOfMeasureType();
ContentDetail.unitWeight.unitOfMeasure.unitOfMeasureCode = new referenceDataType();
ContentDetail.unitWeight.unitOfMeasure.unitOfMeasureCode.code = "g";
Contents.Add(ContentDetail);
}
//Parcel.contentDetails = Contents.ToArray();
parcels.Add(Parcel);
}
InternationalInfo.parcels = parcels.ToArray();
shipment.internationalInfo = InternationalInfo;
}
else
{
shipment.items = items.ToArray();
}
request.requestedShipment = shipment;
createShipmentResponse response = client.createShipment(GetSecurityHeaderType(), request);
// Show Errors And Warnings
checkErrorsAndWarnings(response.integrationFooter);
return response;
}
catch (TimeoutException e)
{
client.Abort();
MessageBox.Show("Request Timed Out: " + e.Message, "Request Timeout", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
catch (FaultException e)
{
client.Abort();
showSoapException(e);
}
catch (CommunicationException e)
{
client.Abort();
MessageBox.Show("A communication error has occured: " + e.Message + " - " + e.StackTrace, "Communication Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
catch (Exception e)
{
client.Abort();
MessageBox.Show(e.Message, "Royal Mail Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
return null;
}