C# powershell objects as a datasource - c#

Bare bones of the problem:
I am trying to populate a ComboBox, or even a ListBox for Windows Forms and for standard arrays and class definitions, it works great using DataSources and the related ValueMember and DisplayMember.
The problem arises when I attempt to utilise a returned Collection of PSObjects (powershell objects).
Here is the code section that I have tried:
private void PopulateGroups()
{
// DistributionGroups is a Collection<PSObject>
DistributionGroups.Clear();
DistributionGroups = GroupADConnection.GroupsInOU("OU=Distribution Groups,OU=Resources,OU=Groups,DC=Domain,DC=MadeUp");
cmbDistributionGroups.DataSource = DistributionGroups;
string test = DistributionGroups[5].Members["DistinguishedName"].Value.ToString();
cmbDistributionGroups.DisplayMember = #"Members[""SamAccountName""].Value.ToString()";
cmbDistributionGroups.ValueMember = "Members[\"DistinguishedName\"].Value.ToString()";
}
Basic background is that DistributionGroups is a Collection<PSObject> which has the members DistinguishedName and SamAccountName.
With the code displayed here, the DisplayMember will show the whole PSObject value through the ToString method, giving me: #{SamAccountName=AA_ Officer; DistinguishedName=CN=AA\+ Officer,OU=Administration,OU=Distribution Groups,OU=Resources,OU=Groups,DC=Domain,DC=MadeUp}
I have tried both methods of getting a quote character into the string so it will get the correct property. The test String object will correctly get the required member of the PSObject.
Is there something I am missing or is there no way to effectively do this without self defining an array with the PSObject members individually transferred?
Update:
After some more testing, it seems that the DataSource, more specifically the Value/Display Members only take the LAST argument. As in for the given: "Members[\"DistinguishedName\"].Value.ToString()" it only actually uses the ToString() part.
Is this the intended behaviour of the Value/Display Member attributes? Is there a way for me to make it use the full definition?

Related

Is it possible to use a string value to specify the name of a parameter's string accessor?

I'm feeling like I'm missing something very important from my past experiences, however, here it is:
I am designing an end-user report designer using DevExpress for clients within my corporation. Since these are being generated dynamically, I would like to give clients the opportunity to have free range over what they are putting on the report. Instead of hard-coding all of the available values, I'm using a StartsWith and a Substring to retrieve the name of the control. I would like to use this string value to specify which parameter field they would need. I'm not sure if I'm thinking about this correctly or if I'm way off track, hoping someone can take another look and give me some suggestions.
Any information will be appreciated.
Maybe I need a dictionary or some sort of interface? Code snippet of what I currently have is below:
private static void BuildReportHeader(Notice notice, XRControl control)
{
if (control.Name.StartsWith("lbl"))
{
string elementName = control.Name.Substring(3);
XRLabel label = (XRLabel)control;
label.Text = notice.{elementName};
}
}
Obviously, this doesn't work or compile as it currently sits, just looking for a solution to the {elementName} bit so that I can access any field on that specific parameter.
You can use reflection to perform this dynamic value lookup: notice.{elementName}.
The bellow sample codes assumed that elementName exist and it's public.
If elementName is a property
var propertyValue = typeof(Notice).GetProperty(elementName).GetValue(notice);
Please bear in mind that GetValue returns an object
The above code assumed that the elementName property has a getter
If it does not have then you will receive an ArgumentException
If elementName is a field
var propertyValue = typeof(Notice).GetField(elementName).GetValue(notice);
The above code assumed that the elementName points to a field
If you provide a non-existing field name or a property/method name then you would receive a NullReferenceException because GetField would return null

C# Get an array to convert to a PSObject

I'm trying to use the System.Management.Automation namespace to use the built-in gridviewer from PowerShell in c#, however I can't seem to be able to get it to display my list of items, it always just returns it as one line as if I was trying to get the info of the array instead of it's members.
SomeClass[] list; //let's say I have a simple array of one object type
PowerShell posh = PowerShell.Create();
posh.AddCommand("Out-Gridview");
posh.AddArgument(list); //this inputs the list as first argument for the command
posh.Invoke(); //this now just opens a gridview with information about the list itself (length, syncroot, ...)
So what I would like is a way to translate my already existing list into a powershell-compatible object inside my C# code, preferably using only the automation library and other default .NET classes.

How do I handle variations in HTMLControl Inner Text in a Page Object Pattern?

Here is a little background on the specifications of my project:
We use Specflow and Microsoft CodedUI Framework for UI Automation
I have built a PageFactory that combines three Abstract Base Classes : BasePage, BaseMap, and BaseValidator that all Maps, Pages, and Validators inherit
Our Application that we are automating has numerous workflows that make defined HTML Controls have different InnerText Values (HTMLComboBoxes for example)
Everything is and needs to be abstracted from the actual Specflow Test Code in the Page Object Pattern, no unique code can exist within a Specflow Step
In my Maps I have certain controls like a combobox that has an InnerText change if a certain workflow is selected. I need to build assertion and verification statements to make sure the InnerText is correct for the workflow that is selected. This is not a problem. However, I do not want to just define a new variable for every InnerText change(There are A LOT).
Is there any way I can account for the InnerText variations in the Page Object Pattern and not have to code a new variable for every single one?
Here is an example of a Map Entry:
public HtmlComboBox NextActionControlDropDownList()
{
var NextActionControlDropDownList = new PropertyExpressionCollection {
new PropertyExpression(HtmlComboBox.PropertyNames.Id, "MEDCHARTContent_EmmpsContent_nextActionControl_ActionDropDownList", PropertyExpressionOperator.EqualTo)
};
return Window.Find<HtmlComboBox>(NextActionControlDropDownList);
}
This is the Base Control definition. It can also be this:
public HtmlComboBox NextActionControlARFormalComplReview()
{
var NextActionControlARFormalComplReview = new PropertyExpressionCollection {
new PropertyExpression(HtmlComboBox.PropertyNames.Id, "MEDCHARTContent_EmmpsContent_nextActionControl_ActionDropDownList", PropertyExpressionOperator.EqualTo),
new PropertyExpression(HtmlComboBox.PropertyNames.InnerText, "--Select Action-- Return to USARC ", PropertyExpressionOperator.EqualTo)
};
return Window.Find<HtmlComboBox>(NextActionControlARFormalComplReview);
}
My thoughts so far were to maybe make another map and inherit it? But that wouldn't solve my initial problem of too many variables for a single control. I don't see how If statements would help either because it needs to be defined for the framework to find the control. Maybe I could store the differing values in a collection of sorts and have a parameter key value to access them... but that seems like I would run into a lot of issues.
If you try and see the methods under PropertyExpressionOperator you would see something called Contains.
new PropertyExpression(HtmlComboBox.PropertyNames.InnerText, "--Select Action--", PropertyExpressionOperator.Contains)

C# Cast works only in debugger

I’m developing a mobile application which among other things, it receives data from medical devices via Bluetooth. To this end, I’m using an Android SDK in JAR via binding to my Xamarin project. Here’s the class that holds the returned data from the decompiled JAR:
package com.contec.jar.contec08a;
import java.util.ArrayList;
public class DeviceData
{
public ArrayList<byte[]> mData_blood = new ArrayList();
public ArrayList<byte[]> mData_oxygen = new ArrayList();
public ArrayList<byte[]> mData_normal_blood = new ArrayList();
}
What is of interest is the mData_blood. Each element of the array list corresponds to a patient. Each byte array is the medical data for each patient. The Xamarin framework makes some changes, i.e. the name of the property becomes MDataBlood.
Problem: when I receive the above class and property, the casting fails BUT NOT in the debugger. Here’s what I mean: the ‘as’ operator that implement the cast fails (returns null) but in the debugger the very same expression correctly shows the data.
What’s more, the ‘is’ operator returns false in runtime (the canDo variable is false) but true in the debugger. I’ve tried all methods of casting I’m familiar with, even using –but not mixing – Android objects. The highlighted line which casts the IList to List produces a nice exception. I’m at a total loss. Any suggestions would be greatly appreciated.
Here's the screenshot from the debugger which illustrates all the above:
Edit1: The MDataBlood[0] evaluates as generic Java object. When reviewing its properties, its isArray is set to true. By checking the decompiled source of the SDK, I determined that is indeed byte array.
In Xamarin, there are some castings that might fail when the objects come from java types. In that cases you should use JavaCast<TResult> instead of a regular casting.
Try this, instead of your current approach:
// Since MDataBlood is exposed as an IList property of MDeviceData,
// we first need to cast it to IJavaObject
var dataBloodRaw = (IJavaObject)dm.MDeviceData.MDataBlood;
// Then we have access to its JavaCast method
var dataBlood = dataBloodRaw.JavaCast<JavaList<byte[]>>();
JavaList<T> extends Java.Lang.Object, so it can be used as the TResult parameter for JavaCast<TResult>. Also, it implements IList, so you should be able to loop through it.
Anyway, if you need a List<byte[]> you can use the casted JavaList for creating it:
var dataBloodList = dataBlood.ToList();
Or, alternatively
var dataBloodList = new List<byte[]>(dataBlood);
Yet another thing you could just try is to Java-cast dataBloodRaw to a JavaList<object> and then loop through its objects, trying to cast each one of them as a byte[].
Plan B
If none of the above works, I suggest you to take a look at this answer where it is suggested to disable linking for Release, which can be done in your project properties:
Keep in mind that a side effect of this last option will be the impact on the final size of your application.

How to solve cast issues in ValidationRule classes' properties?

I need to create a few tests for the user roles in a web application. To minimize the description, one of the tests involves checking if a menu entry is displayed or not for an user.
For this test, I use a table called UserRoles, that looks like this:
sUserName bDoesntHaveMenuX
User1 1
User2 0
User3 1
bDoesntHaveMenuX is of type bit.
I have a class derived from ValidationRule that checks if a certain text is present in a page, based on a XPath expression to locate the node where to look for the text.
The public properties of this class are:
string XPathExpression
string Text
bool FailIfFound
The last one dictates if the rule should fail if the text is found or not found.
In the test I added a datasource for the table mentioned in the beginning, called DS.
For the request I'm interested in I added a new instance of my validation rule class, with the following values:
Text=MenuX
XPathExpression=//div[#id='menu']//td
FailIfFound={{DS.UserRoles.bDoesntHaveMenuX}}
Unfortunately, this doesn't work.
The reason seems to be that the data binding process creates a context variable
DS.UserRoles.bDoesntHaveMenuX has the value "False" or "True". The value is a string, so the binding results in a casting error.
My options, as far as I can think of, are:
Change the validation rule to accept strings for FailIfFound. Not a valid
option, for 2 reasons: it's a hack and the same rule is used in
other places.
Make a new validation rule that will use the above mentioned one,
and implement the FailIfFound as string. I also don't like this, for
the same reason as above. It's a hack.
Make the test coded and do the proper cast before passing the data
to the validation rule. I don't like this one because I prefer to
have the test as coded only if there is no other way.
Which brings me to the question. Is there another way?
Thank you.
So the fundamental issue is that you have no control over how the data-binding treats the 'bit' data type, and it's getting converted to string instead of bool.
The only solution I can think of (which is sadly still a bit of a hack, but not so egregious as changing FailIfFound to string) is to create a WebTestPlugin, and in the PreRequestDataBinding or PreRequest event, convert the value from string to bool. Don't forget to add the plugin to your test(s) (easy mistake I have made).
Then when the validation rule is created it should pick up the nice new bool value and work correctly.
e.g.
string val = e.WebTest.Context["DS.UserRoles.bDoesntHaveMenuX"].ToString();
e.WebTest.Context["DS.UserRoles.bDoesntHaveMenuX"] = (val == "True");
I didn't actually try this... hope it works.
EDIT: round two... a better solution
Change the FailIfFound property to string (in a subclass as you mentioned), so it can work properly with data-binding.
Implement a TypeConverter that provides a dropdown list of valid values for the property in the rule's PropertyGrid (True, False), so in the GUI it looks identical to the rule having FailIfFound as a bool. You can still type your own value into the box when necessary (e.g. for data-binding).
Add the path of the .dll containing the TypeConverter code to your test project's References section.
This is what I have started doing and it is much more satisfying than having to type 'True' or 'False' in the property's edit box.

Categories

Resources