How to pass parameters from Classic ASP to a com component - c#

I am developing an asp.net component that requires many parameters. It will be called from classic ASP. I can of course pass in 10-20 parameters, but I'd love to be a bit tidier.
I'm fairly confident I could pass in an array, but ideally I'd like to be able to pass in an object.
Is this possible?
I decided to do a little test.
The Classic ASP:
Dim objDictionary
Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.Add "startDate", startDate
objDictionary.Add "endDate", endDate
MyComponent.checkObj(objDictionary)
In my ASP.net component I have:
public string checkObj(object config)
{
return "StartDate is " + config.startDate;
}
Edit:
I have progressed the issue so I'm changing this:
I created an abstract class and now it's checking against that and building perfectly. At run time I am now getting and error - Microsoft VBScript runtime error: Invalid procedure call or argument: 'checkObj' .
Is it possible to pass a collection into a com assembly?
Perhaps the problem is that the com component is receiving an object of type Scripting.Dictionary, and not the abstract class I created, but such a thing doesn't exist in .net?

you could try using a .net object in your asp page like System.Collections.ArrayList or System.Collections.Hashtable instead of that dictionary...
<%# LANGUAGE="VBSCRIPT" %>
<%
dim netObj
set netObj = server.createobject("System.Collections.Hashtable")
' or:
'set netObj = server.createobject("System.Collections.ArrayList")
%>
that should make things easier in your .net component

I wanted to do something similar and so created a wrapper class for .NET DataRow. You could use a HasTable/Dictionairy/Other Custom Implementation as your backing store if you want.
I expose my "properties" using an Indexer Property on my wrapper object, so working with a property in asp-classic would look like this:
Dim lngCustomerId
lngCustomerID = CLng(objectWrapper("CustomerId"))
I expose my wrapper using a COM Registered .NET assembly. My wrapper inherits from DynamicObject and exposes the following by a COM visible interface:
[ComVisible(true)]
[Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IDynamicModel
{
dynamic this[string propertyName] { get; set; }
bool TryGetMember(GetMemberBinder binder, out object result);
bool TrySetMember(SetMemberBinder binder, object value);
}
I would think that TryGetMember and TrySetMember will not be necessary for your needs.
My wrapper class implementation looks like this:
[ComVisible(true)]
[Guid("YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY")]
[ProgId("COMLIB.DynamicModel")]
[ClassInterface(ClassInterfaceType.None)]
public sealed class DynamicModel : DynamicObject, IDynamicModel
{
#region indexer
public dynamic this[string propertyName]
{
get
{
dynamic propertyValue;
if (TryGetMember(propertyName, out propertyValue) != true)
{
propertyValue = null;
}
return propertyValue;
}
set
{
if (TrySetMember(propertyName, value) != true)
{
throw new ArgumentException("Cannot set property value");
}
}
}
#endregion indexer
#region Fields
private DataRow dataRow;
#endregion Fields
#region Properties
public dynamic GetAsDynamic { get { return this; } }
#endregion Properties
#region CTOR Methods
public DynamicModel()
: base()
{
DataTable dataTable = new DataTable();
this.dataRow = dataTable.NewRow();
}
public DynamicModel(DataRow dataRow)
: base()
{
this.dataRow = dataRow;
}
#endregion CTOR Methods
#region Dynamic Object Member Overrides
public override bool TryGetMember(GetMemberBinder binder, out object columnValue)
{
bool result = false;
columnValue = null;
result = TryGetMember(binder.Name, out columnValue);
return result;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
bool result = false;
result = TrySetMember(binder.Name, value);
return result;
}
#endregion Dynamic Object Member Overrides
#region Operations
public bool TryGetMember(string columnName, out dynamic columnValue)
{
bool result = false;
columnValue = null;
if (dataRow != null && dataRow.Table.Columns.Contains(columnName))
{
columnValue = dataRow[columnName];
result = true;
}
return result;
}
public bool TrySetMember(string columnName, dynamic columnValue)
{
bool result = false;
if (dataRow != null && dataRow.Table.Columns.Contains(columnName) == true)
{
dataRow[columnName] = columnValue;
result = true;
}
else
{
Type type = columnValue.GetType();
DataColumn dataColumn = new DataColumn(columnName, type);
result = TrySetDataColumn(dataColumn, type, columnValue);
}
return result;
}
private bool TrySetDataColumn(DataColumn dataColumn, Type type, object value)
{
bool result = false;
dataRow.Table.Columns.Add(dataColumn);
result = TrySetMember(dataColumn.ColumnName, value);
return result;
}
#endregion Operations
}
I hope this helps.

Related

WPF c# DynamicObject. how to enforce type checking on the added properties?

I define a DynamicObject.
I have created a list of DynamicObjects with the same structure and link them to a WPF GridView.
I allow editing of some of the properties via the grid.
As the DynamicObjects present the property data as objects, how can I enforce Type restrictions?
if the user types alphabet into a cell that I would like as an int how can I get the DynamicObject to refuse the input?
You could use a TryParse wherever you're taking the cell input:
int result;
if(int.TryParse(cellText, out result))
{
// Is an integer
}
else
{
}
bool and other value types also have a TryParse if you're taking those values as well.
See also:
Comparing Types in this question
The DynamicDictionary example in the docs for a more verbose implementation on adding and editing properties.
In the constructor of my DynamicObject, I pass in with the properties definition, a dictionary of the types.
I then override the TrySetMember method to convert the value from the string supplied by the grid into its required type.
The issue I now have is sending a error message back to the grid if the conversion fails.
Here is My DynamicObject definition:
public sealed class FwDynamicObject : DynamicObject
{
private readonly Dictionary<string, object> _properties;
private readonly Dictionary<string, Type> _propertyTypes;
public FwDynamicObject(Dictionary<string, object> properties, Dictionary<string, Type> propertyTypes = null)
{
_properties = properties;
_propertyTypes = propertyTypes;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _properties.Keys;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_properties.ContainsKey(binder.Name))
{
result = _properties[binder.Name];
return true;
}
else
{
result = null;
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (_properties.ContainsKey(binder.Name))
{
var t = GetMemberType(binder.Name);
if (t != null)
{
try
{
value = Convert.ChangeType(value, t);
}
catch(Exception e)
{
return false;
}
}
_properties[binder.Name] = value;
return true;
}
else
{
return false;
}
}
private Type GetMemberType(string name)
{
if (_propertyTypes.ContainsKey(name))
{
return _propertyTypes[name];
}
return null;
}
}

Let DynamicObect's TryGetMember and TrySetMember return a class in C#

I have a class inheriting from DynamicObject
In this class I have a TryGetMember that I try to evaluate to a static class.
How can TryGetMember overriden from DynamicObject result in a static class?
TL;DR
Calling code:
dynamic sut = new ReachIn();
sut.myclass.MyInnerStaticClass.MyProperty= "fortytwo";
My DynamicObject class tries to return myclass as the MyClass instance.
internal class ReachIn : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = MyClass; // Does not compile.
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
value = MyClass // Does not compile;
return true;
}
}
and what is returned is here:
internal class MyClass
{
internal static class MyInnerStaticClass
{
public static string MyProperty { get; set; }
}
}
This example is a bit forced. It is just a very simplified example of a dynamic object making private fields, properties, methods (and (not yet) classes) visible for testing purpose. I also know one should not write tests this way but I have an esoteric reason. or because I can.
Regardless of your class design I am going to show that what you are trying to achieve is possible with dynamic types and reflection. Firstly a dynamic object is just an object that can take some string name in method like TryGetMember to perform some action. Secondly with string names and reflection you can perform any operation on your objects. So simple dynamic object implementation that will work with your example looks like this:
internal class ReachIn : DynamicObject
{
private readonly Type type;
private readonly string #namespace;
public ReachIn(Type type = null, string #namespace = null)
{
this.type = type;
this.#namespace = #namespace;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (type == null)
{
result = new ReachIn(Type.GetType($"{#namespace}.{binder.Name}".Trim('.')));
return true;
}
var member = type.GetMember(binder.Name).Single();
if (member.MemberType == MemberTypes.NestedType)
{
result = new ReachIn((Type)member);
}
else if (member.MemberType == MemberTypes.Property)
{
result = ((PropertyInfo)member).GetValue(null);
}
else
{
result = null;
return false;
}
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var member = type.GetMember(binder.Name).Single();
if (member.MemberType == MemberTypes.Property)
{
((PropertyInfo)member).SetValue(null, value);
return true;
}
return false;
}
}
So it will work for a sample class with public modifiers:
public class MyClass
{
public static class MyInnerStaticClass
{
public static string MyProperty { get; set; }
}
}
With this you can set your static property like:
dynamic sut = new ReachIn(#namespace: "ConsoleApp8");
sut.MyClass.MyInnerStaticClass.MyProperty = "safd";
It's tested only with your example so for other cases you would need to provide some additional implementation. Not to mention the performance of it would be very bad because of reflection.

C# dynamic classes

I'm talking about something similar to dynamic. This didn't answer my question, hence this question. I want to have a class that I can add properties to at runtime. It needs to be inherited from the type object.
I've seen inheriting from DynamicObject, but it didn't state how to add properties at run-time. Could some light be shed on this for me pls?
I have a class like this:
public class SomeModel : DynamicObject {
public string SomeMandatoryProperty {get; set;}
}
I'd like to add all properties from another class to this class at runtime. So eg.
SomeModel m = new SomeModel();
m = someOtherClass;
string hi = m.otherClassProp; //Property from other class is added.
string mandatory = m.SomeMandatoryProperty; //From the mandatory property set previously.
I think you are looking for ExpandoObject:
The ExpandoObject class enables you to
add and delete members of its
instances at run time and also to set
and get values of these members. This
class supports dynamic binding, which
enables you to use standard syntax
like sampleObject.sampleMember instead
of more complex syntax like
sampleObject.GetAttribute("sampleMember").
dynamic manager;
manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;
You should be able to make use of ExpandoObject instead. An ExpandoObject can have members added or removed at runtime and has very nice support if you want to convert to XML etc.
From MSDN Documentation:
dynamic employee, manager;
employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
manager = new ExpandoObject();
manager.Name = "Allison Brown";
manager.Age = 42;
manager.TeamSize = 10;
You'd want to use the ExpandoObject as you can dynamically add properties as needed. There isn't however a direct way to populate an instance with the values from another object easily. You'll have to add it manually using reflection.
Do you want to write a wrapper object where you could add properties to while still accessing the inner? You may want to consider it that way you don't have to manage two copies of values between two different object instances. I wrote a test class to wrap string objects to demonstrate how you can do this (similar to how the ExpandoObject works). It should give you an idea on how you can do this for your types.
class DynamicString : DynamicObject
{
static readonly Type strType = typeof(string);
private string instance;
private Dictionary<string, object> dynProperties;
public DynamicString(string instance)
{
this.instance = instance;
dynProperties = new Dictionary<string, object>();
}
public string GetPrefixString(string prefix)
{
return String.Concat(prefix, instance);
}
public string GetSuffixString(string suffix)
{
return String.Concat(instance, suffix);
}
public override string ToString()
{
return instance;
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (binder.Type != typeof(string))
return base.TryConvert(binder, out result);
result = instance;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var method = strType.GetMethod(binder.Name, args.Select(a => a.GetType()).ToArray());
if (method == null)
{
result = null;
return false;
}
result = method.Invoke(instance, args);
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var members = strType.GetMember(binder.Name);
if (members.Length > 0)
{
var member = members.Single();
switch (member.MemberType)
{
case MemberTypes.Property:
result = ((PropertyInfo)member).GetValue(instance, null);
return true;
break;
case MemberTypes.Field:
result = ((FieldInfo)member).GetValue(instance);
return true;
break;
}
}
return dynProperties.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var ret = base.TrySetMember(binder, value);
if (ret) return true;
dynProperties[binder.Name] = value;
return true;
}
}
If you want to be adventurous, you can define your own meta objects to handle the bindings. You could end up with reusable meta objects for different types and simplify your code immensely. I've been playing with this for a while and have this so far. It doesn't handle dynamically adding properties yet. I won't be working on this any further but I'll just leave it here for reference.
class DynamicString : DynamicObject
{
class DynamicStringMetaObject : DynamicMetaObject
{
public DynamicStringMetaObject(Expression parameter, object value)
: base(parameter, BindingRestrictions.Empty, value)
{
}
public override DynamicMetaObject BindConvert(ConvertBinder binder)
{
if (binder.Type == typeof(string))
{
var valueType = Value.GetType();
return new DynamicMetaObject(
Expression.MakeMemberAccess(
Expression.Convert(Expression, valueType),
valueType.GetProperty("Instance")),
BindingRestrictions.GetTypeRestriction(Expression, valueType));
}
return base.BindConvert(binder);
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
System.Diagnostics.Trace.WriteLine(String.Format("BindGetMember: {0}", binder.Name));
var valueType = Value.GetType();
var self = Expression.Convert(Expression, valueType);
var valueMembers = valueType.GetMember(binder.Name);
if (valueMembers.Length > 0)
{
return BindGetMember(self, valueMembers.Single());
}
var members = typeof(string).GetMember(binder.Name);
if (members.Length > 0)
{
var instance =
Expression.MakeMemberAccess(
self,
valueType.GetProperty("Instance"));
return BindGetMember(instance, members.Single());
}
return base.BindGetMember(binder);
}
private DynamicMetaObject BindGetMember(Expression instance, MemberInfo member)
{
return new DynamicMetaObject(
Expression.Convert(
Expression.MakeMemberAccess(instance, member),
typeof(object)),
BindingRestrictions.GetTypeRestriction(Expression, Value.GetType())
);
}
}
public string Instance { get; private set; }
public DynamicString(string instance)
{
Instance = instance;
}
public override DynamicMetaObject GetMetaObject(Expression parameter)
{
return new DynamicStringMetaObject(parameter, this);
}
public override string ToString()
{
return Instance;
}
public string GetPrefixString(string prefix)
{
return String.Concat(prefix, Instance);
}
public string GetSuffixString(string suffix)
{
return String.Concat(Instance, suffix);
}
}

c# - How to deserialize a generic list<T> when I don't know the type of (T)?

for auditory reasons I stores the arguments of the business methods serialized into the database using the binaryformatter.
The problem is that when an argument is a generic list I don't find the way to cast the deserialized object because I don't know the type, or If I will know the type I don't know how to cast the object at runtime.
Anybody knows how to cast an object containing a generic list dinamically at runtime?
I need to do this because I need to show the deserialized data in a property grid:
object objArg = bformatter.Deserialize(memStr);
//If the type is a clr type (int, string, etc)
if (objArg.GetType().Module.Name == "mscorlib.dll")
{
//If the type is a generic type (List<>, etc)
//(I'm only use List for these cases)
if (objArg.GetType().IsGenericType)
{
// here is the problem
pgArgsIn.SelectedObject = new { Value = objArg};
//In the previous line I need to do something like...
//new { Value = (List<objArg.GetYpe()>) objArg};
}
else
{
pgArgsIn.SelectedObject = new { Value = objArg.ToString() };
}
}
else
{
//An entity object
pgArgsIn.SelectedObject = objArg;
}
With BinaryFormatter you don't need to know the type; the metadata is included in the stream (making it bigger, but hey!). However, you can't cast unless you know the type. Often in this scenario you have to use common known interfaces (non-generic IList etc) and reflection. And lots of it.
I also can't think of a huge requirement to know the type to show in a PropertyGrid - since this accepts object, just give it what BinaryFormatter provides. Is there a specific issue you are seeing there? Again, you might want to check for IList (non-generic) - but it isn't worth worrying about IList<T>, since this isn't what PropertyGrid checks for!
You can of course find the T if you want (like so) - and use MakeGenericType() and Activator.CreateInstance - not pretty.
OK; here's a way using custom descriptors that doesn't involve knowing anything about the object or the list type; if you really want it is possible to expand the list items directly into the properties, so in this example you'd see 2 fake properties ("Fred" and "Wilma") - that is extra work, though ;-p
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
class Person
{
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public override string ToString() {
return Name;
}
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Person fred = new Person();
fred.Name = "Fred";
fred.DateOfBirth = DateTime.Today.AddYears(-23);
Person wilma = new Person();
wilma.Name = "Wilma";
wilma.DateOfBirth = DateTime.Today.AddYears(-20);
ShowUnknownObject(fred, "Single object");
List<Person> list = new List<Person>();
list.Add(fred);
list.Add(wilma);
ShowUnknownObject(list, "List");
}
static void ShowUnknownObject(object obj, string caption)
{
using(Form form = new Form())
using (PropertyGrid grid = new PropertyGrid())
{
form.Text = caption;
grid.Dock = DockStyle.Fill;
form.Controls.Add(grid);
grid.SelectedObject = ListWrapper.Wrap(obj);
Application.Run(form);
}
}
}
[TypeConverter(typeof(ListWrapperConverter))]
public class ListWrapper
{
public static object Wrap(object obj)
{
IListSource ls = obj as IListSource;
if (ls != null) obj = ls.GetList(); // list expansions
IList list = obj as IList;
return list == null ? obj : new ListWrapper(list);
}
private readonly IList list;
private ListWrapper(IList list)
{
if (list == null) throw new ArgumentNullException("list");
this.list = list;
}
internal class ListWrapperConverter : TypeConverter
{
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
public override PropertyDescriptorCollection GetProperties(
ITypeDescriptorContext context, object value, Attribute[] attributes) {
return new PropertyDescriptorCollection(
new PropertyDescriptor[] { new ListWrapperDescriptor(value as ListWrapper) });
}
}
internal class ListWrapperDescriptor : PropertyDescriptor {
private readonly ListWrapper wrapper;
internal ListWrapperDescriptor(ListWrapper wrapper) : base("Wrapper", null)
{
if (wrapper == null) throw new ArgumentNullException("wrapper");
this.wrapper = wrapper;
}
public override bool ShouldSerializeValue(object component) { return false; }
public override void ResetValue(object component) {
throw new NotSupportedException();
}
public override bool CanResetValue(object component) { return false; }
public override bool IsReadOnly {get {return true;}}
public override void SetValue(object component, object value) {
throw new NotSupportedException();
}
public override object GetValue(object component) {
return ((ListWrapper)component).list;
}
public override Type ComponentType {
get { return typeof(ListWrapper); }
}
public override Type PropertyType {
get { return wrapper.list.GetType(); }
}
public override string DisplayName {
get {
IList list = wrapper.list;
if (list.Count == 0) return "Empty list";
return "List of " + list.Count
+ " " + list[0].GetType().Name;
}
}
}
}
If the serializer you are using does not retain the type - at the least, you must store the type of T along with the data, and use that to create the generic list reflectively:
//during storage:
Type elementType = myList.GetType().GetGenericTypeDefinition().GetGenericArguments[0];
string typeNameToSave = elementType.FullName;
//during retrieval
string typeNameFromDatabase = GetTypeNameFromDB();
Type elementType = Type.GetType(typeNameFromDatabase);
Type listType = typeof(List<>).MakeGenericType(new Type[] { elementType });
Now you have listType, which is the exact List<T> you used (say, List<Foo>). You can pass that type into your deserialization routine.

.Net Property Grid. Is there a way to let the Grid manipulate object in different way

As I understood , The property grid is given an object which it can manipulate by extracting its Properties using reflections.
My problem is that I have a set of Parameters that is determined during run-time , thus I can't staticly compose a class with properties to represent this set.
I have two idea in mind to solve this problem but both are complex and will probably consume lot of time , infact i will say they are not practical under my time constraints. One is to use Reflection Emit in order to define a class dynamically and the other is to dynamiclly build a C# source file and then compile it using CodeDom.
Can Property grid behave in a different manner( other then extracting the Properties of an object using reflections ) that can suite my problem?
If no do you know any other control that can do the job for me?
I want to say that the reason I went to the property grid from the begining was its ability to provide realy nice Data Retrieval UI for common types.For color you autometically get a palette , For dataTime you automatically have a nice calender. I would like to get those things automatically , If possible.
Yes, PropertyGrid can display things other than just the compile-time properties, by using any of TypeConverter, ICustomTypeDescriptor or TypeDescriptionProvider to provide runtime pseudo-properties. Can you give an example of what your parameters look like? I should be able to provide an example...
here's a basic example (everything is string, etc) based on an earlier reply (related but different):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
class PropertyBagPropertyDescriptor : PropertyDescriptor {
public PropertyBagPropertyDescriptor(string name) : base(name, null) { }
public override object GetValue(object component) {
return ((PropertyBag)component)[Name];
}
public override void SetValue(object component, object value) {
((PropertyBag)component)[Name] = (string)value;
}
public override void ResetValue(object component) {
((PropertyBag)component)[Name] = null;
}
public override bool CanResetValue(object component) {
return true;
}
public override bool ShouldSerializeValue(object component)
{ // *** this controls whether it appears bold or not; you could compare
// *** to a default value, or the last saved value...
return ((PropertyBag)component)[Name] != null;
}
public override Type PropertyType {
get { return typeof(string); }
}
public override bool IsReadOnly {
get { return false; }
}
public override Type ComponentType {
get { return typeof(PropertyBag); }
}
}
[TypeConverter(typeof(PropertyBagConverter))]
class PropertyBag {
public string[] GetKeys() {
string[] keys = new string[values.Keys.Count];
values.Keys.CopyTo(keys, 0);
Array.Sort(keys);
return keys;
}
private readonly Dictionary<string, string> values
= new Dictionary<string, string>();
public string this[string key] {
get {
string value;
values.TryGetValue(key, out value);
return value;
}
set {
if (value == null) values.Remove(key);
else values[key] = value;
}
}
}
// has the job of (among other things) providing properties to the PropertyGrid
class PropertyBagConverter : TypeConverter {
public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
return true; // are we providing custom properties from here?
}
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, System.Attribute[] attributes) {
// get the pseudo-properties
PropertyBag bag = (PropertyBag)value;
string[] keys = bag.GetKeys();
PropertyDescriptor[] props = Array.ConvertAll(
keys, key => new PropertyBagPropertyDescriptor(key));
return new PropertyDescriptorCollection(props, true);
}
}
static class Program {
[STAThread]
static void Main() { // demo form app
PropertyBag bag = new PropertyBag();
bag["abc"] = "def";
bag["ghi"] = "jkl";
bag["mno"] = "pqr";
Application.EnableVisualStyles();
Application.Run(
new Form {
Controls = { new PropertyGrid {
Dock = DockStyle.Fill,
SelectedObject = bag
}}
});
}
}

Categories

Resources