BizTalk Custom Pipeline Component doesn't load overridden properties - biztalk

I have a custom BizTalk 2013 R2 pipeline component that has several design-time properties defined. For some reason, BizTalk will load the design-time property values set in the VS pipeline designer but it ignores run-time values set in the BizTalk Admin Console. My component implements IPersistPropertyBag and I have verified that it is not throwing any exceptions.
While debugging the pipeline (attached to Isolated Host Instance), I noticed that BizTalk is only calling the Load method when the pipeline is instantiated. This only loads the VS designer values and BizTalk is supposed to then call the Load method again before calling Execute. Unfortunately, this is not happening.
[Edit] I did some more debugging and figured out that this only seems to be happening on the send pipeline for a two-way receive port. The receive pipeline loads both the design-time and run-time properties as expected.
Here is a sample of my code:
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
[ComponentCategory(CategoryTypes.CATID_Encoder)]
[System.Runtime.InteropServices.Guid(COMPONENT_GUID)]
public class RhapsodyMessageEncoder : BasePipelineComponent, IBaseComponent, IComponentUI,
IPersistPropertyBag, Microsoft.BizTalk.Component.Interop.IComponent
{
...
public void Load(IPropertyBag propertyBag, int errorLog)
{
try
{
this.Enabled = Convert.ToBoolean(this.ReadPropertyBag(propertyBag, "Enabled"));
this.UsernameSSOKey = this.ReadPropertyBag(propertyBag, "UsernameSSOKey") as string;
this.PasswordSsoKey = this.ReadPropertyBag(propertyBag, "PasswordSsoKey") as string;
this.AffiliateAppName = this.ReadPropertyBag(propertyBag, "AffiliateAppName") as string;
}
catch (Exception e) { this.WriteErrorLog(e); }
}
public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
{
try
{
this.WritePropertyBag(propertyBag, "Enabled", this.Enabled);
this.WritePropertyBag(propertyBag, "UsernameSSOKey", this.UsernameSSOKey);
this.WritePropertyBag(propertyBag, "PasswordSsoKey", this.PasswordSsoKey);
this.WritePropertyBag(propertyBag, "AffiliateAppName", this.AffiliateAppName);
}
catch (Exception e) { this.WriteErrorLog(e); }
}
...
}
Read / Write Property bag helper methods:
protected virtual object ReadPropertyBag(IPropertyBag pb, string propName)
{
PropertyInfo pInfo = this.GetType().GetProperty(propName);
object currentValue = null;
object val = null;
if (pInfo != null)
currentValue = pInfo.GetValue(this, null);
try
{
pb.Read(propName, out val, 0);
}
catch (System.ArgumentException e)
{
System.Diagnostics.Trace.WriteLine(
"Argument Exception encountered: " + e.Message,
this.Name
);
}
catch (System.Exception e)
{
throw new System.ApplicationException("Can't read design time Properties", e);
}
return val ?? currentValue;
}
protected virtual void WritePropertyBag(IPropertyBag pb, string propName, object val)
{
try
{
object obj = val;
pb.Write(propName, ref obj);
}
catch (System.Exception e)
{
throw new System.ApplicationException("Can't write design time properties", e);
}
}

Related

Access fields of a TestNG test class from a TestListenerAdapter

Background
I have the following situation:
My test-classes implement org.testng.ITest
They all have a Helper containing info on the current test environment (e.g. device-under-test)
For example:
com.company.appundertest.Helper h;
public class TestClass implements org.testng.ITest {
private String testName;
//Helper is initialized externally in Factory + DataProvider
//and passed to Constructor.
public TestClass(com.company.appundertest.Helper hh) {
this.h = hh;
//constructor sets the test-name dynamically
//to distinguish multiple parallel test runs.
this.testName = "some dynamic test name";
}
#Override
public String getTestName() {
return this.testName;
}
#Test
public void failingTest() {
//test that fails...
}
}
These test-classes are executed in parallel using Factory and parallel data-provider.
Upon Test Failure, I need to access variables within the Helper instance of the failing test-class. These will be used to identify the environment at the point of failure (e.g. take screenshot on failing device).
This problem essentially boils down to:
How would I access fields within the TestNG test-class?
References
Access to private inherited fields via reflection in Java
Here's an example method. You can insert this in a Test Listener class (which extends TestListenerAdapter)
public class CustomTestNGListener extends TestListenerAdapter{
//accepts test class as parameter.
//use ITestResult#getInstance()
private void getCurrentTestHelper(Object testClass) {
Class<?> c = testClass.getClass();
try {
//get the field "h" declared in the test-class.
//getDeclaredField() works for protected members.
Field hField = c.getDeclaredField("h");
//get the name and class of the field h.
//(this is just for fun)
String name = hField.getName();
Object thisHelperInstance = hField.get(testClass);
System.out.print(name + ":" + thisHelperInstance.toString() + "\n");
//get fields inside this Helper as follows:
Field innerField = thisHelperInstance.getClass().getDeclaredField("someInnerField");
//get the value of the field corresponding to the above Helper instance.
System.out.println(innerField.get(thisHelperInstance).toString());
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Call this as follows:
#Override
public void onTestFailure(ITestResult tr) {
getCurrentTestHelper(tr.getInstance());
}
The #Vish 's solution is good, but you can avoid reflection with:
interface TestWithHelper {
Helper getHelper();
}
where your TestClass will implement it.
Then:
private void getCurrentTestHelper(Object testClass) {
if (testClass instanceof TestWithHelper) {
Helper helper = ((TestWithHelper) testClass).getHelper();
...
}
}

Error Handling in Web Form

I'm trying to cater for an error in my data access layer, which would return an int of value -1. See below:
protected void FolderBtn_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
try
{
DocsDALC dalc = new DocsDALC();
// Updating two tables here - Folders and FolderAccess tables
// - as an ADO.NET transaction
int folderID = dalc.CreateFolder(...);
if (folderID > 0)
{
Response.Redirect(Request.Url.ToString(), false);
// Re-construct this to include newly-created folderID
}
else
{
// How do I throw error from here?
}
}
catch (Exception ex)
{
HandleErrors(ex);
}
}
}
If data layer returns -1, how can I throw an error from within the try block?
As simply as the following - however, since you are catching errors, if you know it's a problem, it would be better to call an overload of HandleErrors method that you could pass in a string defining the problem, rather than throw the exception (which is costly for what this will do).
If you still want to throw the exception:
if (folderID > 0)
{
Response.Redirect(Request.Url.ToString(), false);
// Re-construct this to include newly-created folderID
}
else
{
throw new Exception("Database returned -1 from CreateFolder method");
}
A possible alternative:
if (folderID > 0)
{
Response.Redirect(Request.Url.ToString(), false);
// Re-construct this to include newly-created folderID
}
else
{
HandleErrors("Database returned -1 from CreateFolder method");
}
With of course an overloaded HandleErrors method.

DatabaseIOException When Executing Query "Delete"

Can anybody help telling me what is wrong with my code? I am trying to connect to SQLite database, and executing some queries. when trying to create and open the database, create and insert the table, no exception returned. but when I try to execute delete statement,
DatabaseIOException: File system error (12)
always returned. I don't know the cause of the exception exactly. would you tell me what usually cause this kind of exception? I don't even know when I need to close the database and when I don't need to. this solution also makes me confused.
here is my code:
public class DatabaseManager {
Logger log = new Logger();
Database db;
public DatabaseManager() {
createDatabase();
}
private void createDatabase() {
// Determine if an SDCard is present
boolean sdCardPresent = false;
String root = null;
Enumeration enum = FileSystemRegistry.listRoots();
while (enum.hasMoreElements()) {
root = (String) enum.nextElement();
if(root.equalsIgnoreCase("sdcard/")) {
sdCardPresent = true;
}
}
if(!sdCardPresent) {
alert("This application requires an SD card to be present. Exiting application...");
}
else {
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.openOrCreate(uri);
db.close();
//alert("Database OK!");
} catch (Exception e) {
// TODO Auto-generated catch block
//alert("Exception in createDatabase(): " + e);
}
}
}
private void alert(final String message) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.inform(message);
System.exit(0);
}
});
}
private void createTableTask() {
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.open(uri);
Statement st = db.createStatement("CREATE TABLE IF NOT EXISTS t_task (id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "client TEXT, task TEXT)");
st.prepare();
st.execute();
st.close();
db.close();
//alert("Table Task created!");
} catch (Exception e) {
// TODO: handle exception
//alert("Exception in createTableTask(): " + e);
}
}
private void insertTableTask() {
String[] clients = { "Budi Setiawan", "Dian Kusuma", "Joko Ahmad", "Titi Haryanto", "Wahyu" };
String[] tasks = {
"Penawaran terhadap instalasi server",
"Follow up untuk keperluan produk terbaru",
"Pendekatan untuk membina relasi",
"Penawaran jasa maintenance",
"Penawaran terhadap instalasi database"
};
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.open(uri);
for(int i = 0; i < clients.length; i++) {
Statement st = db.createStatement("INSERT INTO t_task (client, task) VALUES (?, ?)");
st.prepare();
st.bind(1, clients[i]);
st.bind(2, tasks[i]);
st.execute();
st.close();
}
db.close();
} catch (Exception e) {
// TODO: handle exception
//alert("Exception in insertTableTask(): " + e);
}
}
public void loadInitialData() {
createTableTask();
insertTableTask();
}
public Cursor getTasks() {
// TODO Auto-generated method stub
Cursor results = null;
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.open(uri);
Statement st = db.createStatement("SELECT client, task FROM t_task");
st.prepare();
results = st.getCursor();
return results;
} catch (Exception e) {
// TODO: handle exception
//alert("Exception: " + e);
}
return results;
}
public void delete(String string) {
// TODO Auto-generated method stub
try {
URI uri = URI.create("/SDCard/databases/MyAdvanceUI/myadvanceui.db");
db = DatabaseFactory.open(uri);
Statement st = db.createStatement("DELETE FROM t_task WHERE client=?");
st.prepare();
st.bind(1, string);
st.execute();
} catch (Exception e) {
// TODO: handle exception
alert("Exception: " + e);
}
}
}
thank you for your help.
I don't see that you close the statement and close the database after select and delete actions. Most probably you can't open database because it wasn't closed correctly.
Big warning SD card isn't available when user mounted devices to PC as external drive. Some devices are going without SD card preinstalled. DB operations are really slow on 5 OS devices. Your alert method code wan't close db what could be issue to open it after on the next application start.
Warning As #pankar mentioned in comment you should add finally {} where you will close resources for sure. In your current implementation if you get exception in execution you will never close database.
Big improvements You don't need to create and prepare statement every loop. Just do it before for. Do bind and execute every loop. And close statement after for.
Improvements You could keep one opened db during application run cycle. It will save you some line of code and time for opening closing.
Notation It's bad practice to have parameter named like 'string'. I would rename it to something more meaningful.

interesting service behaviour in silverlight

I have a Silverlight project which takes some encrypted string thru its Service Reference: DataService (service which is done in an ASP.NET project).
The method from TransactionServices.cs to get the encrypted string is:
public void GetEncryptedString(string original)
{
DataService.DataServiceClient dataSvc = WebServiceHelper.Create();
dataSvc.GetEncryptedStringCompleted += new EventHandler<SpendAnalyzer.DataService.GetEncryptedStringCompletedEventArgs>(dataSvc_GetEncryptedStringCompleted);
dataSvc.GetEncryptedStringAsync(original);
}
On completing, put the result in encodedString var (which is initialized with an empty value):
void dataSvc_GetEncryptedStringCompleted(object sender, SpendAnalyzer.DataService.GetEncryptedStringCompletedEventArgs e)
{
if (e.Error == null)
{
try
{
if (e.Result == null) return;
this.encodedString = e.Result;
}
catch (Exception ex)
{
Logger.Error("TransactionService.cs: dataSvc_GetEncryptedStringCompleted: {0} - {1}",
ex.Message, ex.StackTrace);
MessageBox.Show(ex.ToString());
}
}
}
Now I want to get the encoded string from my MainPage.xaml like:
TransactionService ts = new TransactionService();
ts.GetEncryptedString(url);
Console.WriteLine(ts.encodedString);
I do not uderstand why ts.encodedString is empty. When I do the debug I see that it actually prints out empty and AFTER that it goes to the void dataSvc_GetEncryptedStringCompleted to take the result and fill it.
Can you point me what I've done wrong? Is there a way to wait for the encodedString to be fetched and only after that to continue?
Thanks a lot.
When you call the ts.GetEncryptedString(url); you just started async operation. And therefor the value you are accessing is will be set only in the callback method.
But you access it before the value is modified by the callback.
The solution which I am using will looks similar to folowing:
Redefine the GetEncryptedString method signature.
public void GetEncryptedString(string original, Action callback)
{
DataService.DataServiceClient dataSvc = WebServiceHelper.Create();
dataSvc.GetEncryptedStringCompleted += (o,e) =>
{
dataSvc_GetEncryptedStringCompleted(o,e);
callback();
}
dataSvc.GetEncryptedStringAsync(original);
}
Call it like this:
ts.GetEncryptedString(url, OtherLogicDependantOnResult);
where
OtherLogicDependantOnResult is
void OtherLogicDependantOnResult()
{
//... Code
}

Cross-thread operation not valid: accessed from a thread other than the thread it was created on

I want to remove checked items from checklistbox (winform control) in class file method which i am calling asynchronously using deletegate. but it showing me this error message:-
Cross-thread operation not valid: Control 'checkedListBox1' accessed from a thread other than the thread it was created on.
i have tried invoke required but again got the same error. Sample code is below:
private void button1_Click(object sender, EventArgs e)
{
// Create an instance of the test class.
Class1 ad = new Class1();
// Create the delegate.
AsyncMethodCaller1 caller = new AsyncMethodCaller1(ad.TestMethod1);
//callback delegate
IAsyncResult result = caller.BeginInvoke(checkedListBox1,
new AsyncCallback(CallbackMethod)," ");
}
In class file code for TestMethod1 is : -
private delegate void dlgInvoke(CheckedListBox c, Int32 str);
private void Invoke(CheckedListBox c, Int32 str)
{
if (c.InvokeRequired)
{
c.Invoke(new dlgInvoke(Invoke), c, str);
c.Items.RemoveAt(str);
}
else
{
c.Text = "";
}
}
// The method to be executed asynchronously.
public string TestMethod1(CheckedListBox chklist)
{
for (int i = 0; i < 10; i++)
{
string chkValue = chklist.CheckedItems[i].ToString();
//do some other database operation based on checked items.
Int32 index = chklist.FindString(chkValue);
Invoke(chklist, index);
}
return "";
}
Are you sure you are not getting the error from this line of code?
string chkValue = chklist.CheckedItems[i].ToString();

Resources