c# COM Objects issue - c#

Background
I am working on a trading ActiveX API in visual studio 2010 on C#. Since it is an ActiveX API, I simply added the ActiveX as my reference. The api provides three group of things: Method you could use to call API, the Event with which the API updates information for you and some socalled ActiveX COM object.
ISSUE
I asked a related question here: C# boolean int conversion issue Finally, after viewing the exception has been thrown, I know that it is about casting. Here is the description of exception:
*System.InvalidCastException was unhandled Message=Unable to cast object of type
InteractiveBrokersTradingSystem.Forex' to type 'TWSLib.IContract'.
*
And here is my definition for Forex Class:
namespace InteractiveBrokersTradingSystem
{
class Forex:TWSLib.IContract
{
public int conId { get; set; }
public string symbol { get; set; }
public string secType { get; set; }
public string expiry { get; set; }
public double strike { get; set; }
public string right { get; set; }
public string multiplier { get; set; }
public string exchange { get; set; }
public string primaryExchange { get; set; }
public string currency { get; set; }
public string localSymbol { get; set; }
public int includeExpired { get; set; }
public object comboLegs { get; set; }
public object underComp { get; set; }
public string comboLegsDescrip { get;set; }
public string secIdType { get; set; }
public string secId { get; set; }
public Forex(string preCurrency,string baseCurrency)
{
//conId = 0;
//symbol = preCurrency;
//secType = "CASH";
//expiry = null;
//strike = double.Parse("0");
//right = null;
//multiplier = null;
//exchange = "IDEALPRO";
//primaryExchange = "IDEALPRO";
//currency = baseCurrency;
//localSymbol = null;
//includeExpired = 0;
// comboLegs = null;
//underComp = null;
//comboLegsDescrip = null;
//secType = null;
//secId = null;
}
}
}
You could see that I did not assign any value to the properties of the class and the exception is always the same no matter what kind of value I assign or not assign or null.
In the description of the api below as image we can see that some property with () like strike() as doulble and some not with () like secType as string; someone told me that it might be problem. Please, give me any hint related to this COM casting issue:
(source: minus.com)
(source: minus.com)
(source: minus.com)

Can you post some code that actually fails?
I think what's happening is that you're trying to cast a COM object to a plain .NET type and that will not work because the COM object needs to explicitly be mapped to a .NET type either by the Runtime Callable Wrapper or by manual mapping.
One suggestion I would have is to skip explicit casting and use the dynamic type in .NET 4.0 to access the properties of your COM object, then map it to whatever properties/objects you need it to. That way you'll be able to see exactly which part of the object doesn't want to map.

Related

Convert Encoding.ASCII.GetString to Class Model in C#

I am trying to encode a 200+ byte-size word payload (Using M2MQTT) into a Dynamic variable and thereafter convert the encoded string (Dynamic variable) into a JSON object so that it can be mapped to its corresponding Class object so that it can be saved in a SQL Database.
//C#
private void MqttClient_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
{
var message = Encoding.ASCII.GetString(e.Message);
JObject? jsonMessage = JObject.Parse(message);
DataClass? classList= JsonConvert.DeserializeObject<DataClass>((string)jsonMessage);
AddMyItem(classList);
}
public void AddMyItem(DataClass? passedClassList)
{
using (var context = new DataClassDbContext())
{
context.DataClass.Add(passedClassList);
context.SaveChanges();
}
}
Typical Message Format
[{"sn":1027,"nodeId":"n1","MemberData1":1,"MemberData2":2,"MemberData3":3,"MemberData4":4,"MemberData5":5,"MemberData6":6,"MemberData7":7,"MemberData8":8,"MemberData9":9}]
But I am currently stuck at the conversion of message (Dynamic string variable) into a JSON object in order to pass it to classList for Class Model remapping - Not too sure what's the best syntax to implement for this.
The end goal is to map message's member value into a Class object of DataClass but of course, there is an implicit conversion type error when trying to pass the values directly, i.e., vFarm vFarmCo2PdList = message;. Hence, I am wondering if I need to process message variable in some way first.
Your example message indicated that it's collection of entries of type DataClass, which after conversion looks like this:
public class DataClass
{
public int sn { get; set; }
public string nodeId { get; set; }
public int MemberData1 { get; set; }
public int MemberData2 { get; set; }
public int MemberData3 { get; set; }
public int MemberData4 { get; set; }
public int MemberData5 { get; set; }
public int MemberData6 { get; set; }
public int MemberData7 { get; set; }
public int MemberData8 { get; set; }
public int MemberData9 { get; set; }
}
Having said that, you need to try deserializa it to DataClass[], which is array. I also suggest using System.Text.Json library, which is already shipped with .NET :)
Also, you do not need to create JObject. just deserialize from string, like this:
var o = JsonSerializer.Deserialize<DataClass[]>(message);

Send a limited/reduced class to frontend

What I want
I want to send a limited/reduced class/object to frontend (as JSON). I use .NET Core 5.
What I have
I have a model class like this:
namespace Tasks.Models
{
public class Resources
{
public Guid Id { get; set; }
public string Type { get; set; }
public string Url { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? Createdon { get; set; }
public Guid Userid { get; set; }
public Guid Taskid { get; set; }
public int Clicked { get; set; }
public byte Active { get; set; }
+++ many more properties
}
}
Now depending on the which controller that calls this model I want to have different "kind" of models. So if the resource is file I maybe want the properties Id,Type,Name. But if the resource is URL I want Id, Url, Name.
I tried setting up a method that "initialized the fields I wanted, but that also returned all properties
public static Responses FileResponse()
{
var response = new Responses()
{
Id = new Guid(),
Name = "",
Type = "File",
};
return response;
}
Now, when I call the Resources class or this method I get all properties, and returning it to the view presents all properties, but mostly as null, because I only set the three fields in the method.
What is the recommended way of solving this?
If you want to remove the field if it's null instead of showing in json with null value.
public class Resources
{
public Guid Id { get; set; }
public string Type { get; set; }
// if null, dont show it in JSON output
[JsonIgnoreAttribute(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Url { get; set; }
// if null, dont show it in JSON output
[JsonIgnoreAttribute(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Name { get; set; }
public string Description { get; set; }
public DateTime? Createdon { get; set; }
public Guid Userid { get; set; }
public Guid Taskid { get; set; }
public int Clicked { get; set; }
public byte Active { get; set; }
}
PS: Fiddle https://dotnetfiddle.net/hiMAci
It is just limiting the Resource class I am not able to do
Yep, side effect of C# being strongly typed, with object X definitely having properties Y and Z. You need differently shaped objects - either full on classes or records - that name the reduced set of properties because the serializer is going to look a tthe object and ser every property it can find.
You could make a new class for every variation - quick and easy with records, and easy to pass around inside your C#:
public record FileThing(string Id, string Type, string Name);
//make a new one and return it
new FileThing(someResources.Id, someResources.Type, someResources.Name);
Or can consider using an anonymous type if you're literally looking to put a few properties into some json, down a socket to a consuming front end (I can't quite decide what you mean by "view" - it doesn't seem to be an MVC View) that only cares about a few props out of many
So if the resource is file I maybe want the properties Id,Type,Name. But if the resource is URL I want Id, Url, Name.
public ActionResult SomeControllerMethod(){
if(isFile)
return Ok(new { someResources.Id, someResources.Type, someResources.Name });
else if(isUrl)
return Ok(new { someResources.Id, someResources.Url, someResources.Name });
}
Anonymous types are a bit harder to work with because the compiler writes the class for you, so it's tricky to do things like declare return types from methods if the method is returning an AT.. But if you're using it as some fill-in all within one method, such as a "make this and serialize it", they work well..
I think your approach is not the right one here. I tend to follow more general OO guidelines in this situation (note, some consider these a bit dated, and other solutions exist. But they are still commonly used)
You write against an interface. So let's see what you want... A guid, type and name. All other deatils aren't important.
public interface IResourceDetails
{
public Guid Id { get; }
public string Name { get; }
public string Type { get; }
}
And you can have multiple of these interfaces.
You could then implement the interfaces per type. But I would probably combine them in a base class
public abstract class ResourceBase : IResourceDetails
{
public Guid Id { get; } = new ();
public string Name { get; init; }
public string Type { get; }
public ResourceBase(string type)
{
Type = type;
}
}
Each resource type would have it's own implementation
public class FileResource : ResourceBase
{
public FileResource() : base("File") { }
// File-specific properties.
public string Description { get; init; }
public DateTime? Createdon { get; init; }
}
The response method then could be made generic and look like this
public static IActionResult Response(IResourceDetails resource)
{
return Ok(new
{
resource.Id,
resource.Name,
resource.Type,
});
}

dynamic to specific class object conversion

how to convert dynamic variable to specific class.
dynamic variable has the same properties as my specific class.
public class PracovnikHmotZodpovednostDropDownListItem
{
[Column("ZAZNAM_ID")]
public int? ZaznamId { get; set; }
[Column("TEXT")]
public string Text { get; set; }
[Column("VALL")]
public int Value { get; set; }
public bool Disabled { get; set; } = false;
public UpdateStatusEnum UpdateStatus { get; set; }
}
void someMethod(dynamic dtos){
List<PracovnikHmotZodpovednostDropDownListItem> dto =
(List<PracovnikHmotZodpovednostDropDownListItem>)dtos;
}
If all you know is that the properties have the same names, you're in duck typing territory, casting won't help you.
Good news is, it's trivial to do, just tedious:
var dtoList = new List<PracovnikHmotZodpovednostDropDownListItem>();
foreach(var dto in dtos)
dtoList.Add(new()
{
ZaznamId = dto.ZaznamId,
Text = dto.Text,
// etc..
});

Creating class members during run time - C#

I have a simple class defined like this:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
}
In the code, I get some data as list<double> perfdepth; assume this is perfdepth1,perfdepth2,perfdepth3. Of course, this list is dynamic hence, I wouldnt know beforehand to change my class definition to:
public class StickColumns
{
public string wellname { get; set; }
public double WellLength { get; set; }
public double perfdepth1 { get; set; }
public double perfdepth2 { get; set; }
public double perfdepth3 { get; set; }
}
Can these new members be created during run time?
The reason why I think I would need this is because of data binding in WPF. Eventually I need to display "point series"; Perfdepth1 as one series, perfdepth2 as another series and so on, i.e, dynamic number of Perfdepths.
If there is a simpler way to do it, I am all ears!
You might just want to use the dynamic type with ExpandoObject..
dynamic stickColumns = new ExpandoObject();
stickColumns.wellName = "Something";
stickColumns.perfdepth1 = "Something Else";
It has its drawbacks as it does mean you end up with runtime errors etc... but it can be useful for this type of scenario.

Boolean int conversion issue

I am working on a trading API (activex from interactive brokers)which has a method called:
void reqMktDataEx(int tickerId, IContract contract, string generalDetails, int snapshot)
The issue is around the last parameter "int snapshot" which obviously requires an int input which actually indicates that whether trader wanna snapshot market data or not. So I guess that if I set it to non-zero, then the implicit conversion would convert this non-zero to be bool value "true".
However, I am using c# to connect to this api. Everything was fine until this one. I tried this:
A. void reqMktDataEx(1, AUDUSD, "100", 0)
Please ignore the first three parameters "1, AUDUSD, "100"", the only matter is the last one 0 as int. I got paused during debugging and the information is :
"Specified cast is not valid. Invalidcastexception is unhandled" and "when casting from a number, the number must not be infinity".
After this I learned that here is a difficulty for c# to treat 1 as bool true and 0 as bool false IMPLICITLY according this
web http://www.dotnetperls.com/convert-bool-int
B. I tried this
void reqMktDataEx(1, AUDUSD, "100", Convert.ToInt16(false)) I got similar error again.
C. I tried again this one:
void reqMktDataEx(1, AUDUSD, "100", int.Parse("false"))
the complaint is input string was not in a correct format. Make sure that you method arguments are in the right format.
MY GUESS:
Here is a inside configuration of C# which does not treat 0 as false and 1 as true. Is there any way to solve?
First Edit
As suspected by one professional programmer below, I post the contract class and audusd definition here for him.
namespace InteractiveBrokersTradingSystem
{
class Contract:TWSLib.IContract
{
public int conId { get; set; }
public string symbol { get; set; }
public string secType { get; set; }
public string expiry { get; set; }
public double strike { get; set; }
public string right { get; set; }
public string multiplier { get; set; }
public string exchange { get; set; }
public string primaryExchange { get; set; }
public string currency { get; set; }
public string localSymbol { get; set; }
public int includeExpired { get; set; }
public object comboLegs { get; set; }
public object underComp { get; set; }
public string comboLegsDescrip { get; set; }
public string secIdType { get; set; }
public string secId { get; set; }
}
}
namespace InteractiveBrokersTradingSystem
{
class Forex:Contract
{
public Forex(string preCurrency,string baseCurrency)
{
//conId = 14433401;
symbol = preCurrency;
secType = "CASH";
exchange = "IDEALPRO";
currency = baseCurrency;
strike = 0;
includeExpired = 0;
primaryExchange = "IDEALPRO";
}
}
}
The method I use to call the reqMktDataEx:
implementation first, simple inheritance:
public void MyReqMarketData(int tickId, IContract contract, string tickTypes, int snapshot)
{
reqMktDataEx(tickId, contract, tickTypes, snapshot);
}
private void AudButtonItemItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
Forex audusd = new Forex("AUD", "USD");
_myTwsClass.MyReqMarketData(1,audusd, "100", 0);
}
Second Edit:
System.InvalidCastException was unhandled
Message=Unable to cast object of type 'InteractiveBrokersTradingSystem.Forex' to type 'TWSLib.IContract'.
Source=InteractiveBrokersTradingSystem
It seems that here is some casting problem between the forex class I defined and the Icontract com thing. Here is my new definition:
namespace InteractiveBrokersTradingSystem
{
class Forex
{
public int conId { get; set; }
public string symbol { get; set; }
public string secType { get; set; }
public string expiry { get; set; }
public double strike { get; set; }
public string right { get; set; }
public string multiplier { get; set; }
public string exchange { get; set; }
public string primaryExchange { get; set; }
public string currency { get; set; }
public string localSymbol { get; set; }
public int includeExpired { get; set; }
public object comboLegs { get; set; }
public object underComp { get; set; }
public string comboLegsDescrip { get;set; }
public string secIdType { get; set; }
public string secId { get; set; }
public Forex(string preCurrency,string baseCurrency)
{
//conId = 0;
//symbol = preCurrency;
//secType = "CASH";
//expiry = null;
//strike = double.Parse("0");
//right = null;
//multiplier = null;
//exchange = "IDEALPRO";
//primaryExchange = "IDEALPRO";
//currency = baseCurrency;
//localSymbol = null;
//includeExpired = 0;
//comboLegs = null;
//underComp = null;
//comboLegsDescrip = null;
//secType = null;
//secId = null;
}
}
}
As you can see that the Forex class inherits from the TWS.IContract. how it could not be cast to Icontract successively?
There is no implicit conversion of a bool to an int. Only an explicit one:
Convert.ToInt32(someBool)
// or...
someBool ? 1 : 0
From that site you linked:
First, you cannot implicitly convert from bool to int. The C# compiler uses this rule to enforce program correctness. It is the same rule that mandates you cannot test an integer in an if statement.
Edit
int doesn't have a concept of infinity. Only float and double do. This means it won't be related to that parameter, unless that parameter just controls the flow of the code that is actually crashing. Which still means it isn't the conversion causing the problem.
You're getting a different error for int.Parse("false") because it is expecting a number, not a true/false value. This will always throw an exception at runtime, but it will throw in your code, not in the library's code.
I'm starting to think it is the second parameter, contract, for which you've supplied AUDUSD.
One more way is to have extension method:
public static class BooleanExtensions
{
public static int ToInt(this bool value)
{
return value ? 1 : 0;
}
}
then it can be used:
bool result = false;
result.ToInt();
make field tinyint in database
tinyint fieldname;
c# code
convert.toint32(fieldname.tostring());//returns 1 or 0
to get boolean value
covert.tobool(fieldname.tostring()) ;
There's no implicit cast to int from bool. So make your own. Then add them up.
Boolean
byFinancialCenter = false,
byProvider = false,
byServiceSite = false,
byProcedure = false;
int b2i(bool source) => source ? 1 : 0;
int ForeignKeyCount() => b2i(byFinancialCenter) + b2i(byProvider) + b2i(byServiceSite) + b2i(byProcedure);
The b2i is generic, as I needed the specific count in several places, including the last function makes it easy to use. Also, for maintenance, having the embedded function just under the bools makes it more likely that subsequent developers will see what's happening.

Categories