Stored Procedure List Run Time Conversion - c#

Inside My 'MyOtherViewModel' I have the below code that is
Throwing Error: Argument Type myStoredProcedure not Assignable to parameter type MyDbTable
It is throwing # (this, c) Compile Time Error
var query = myWCFClient.myStoredProcedure();
//Some Other Stuff
query.ToList().ForEach(c => myCollection.Add(new MyViewModel(this, c)));
Inside MyViewModel I have :
public MyViewModel(MyOtherViewModel owner, MyDbTable table)
:base(owner, "String")
{
//other stuff
}
Then I try
var t = ((IEnumerable)query).Cast<MyDbTable>().ToList();
t.ToList().ForEach(c => mCollection.Add(new MyViewModel(this, c)));
And Get: Unable to cast object of type 'myStoredProcedure' to type 'MyDbTable'. Run Time Error
What is the best way to handle this in VS 2012, c# .Net 4.5 using WCF.
Procedure is myStoredProcedure[] and this is returning a count of 0
var t = query.OfType<MyDbTable>().ToList();

In your first piece of code you are putting objects of type myStoredProcedure in the constructor of MyViewModel while that constructor expects an object of type MyDbTable. That's why you get a compile time error on that piece of code.
The second piece of code you try to cast the myStoredProcedure to a MyDbTable. That's why you get a run time exception on that piece of code.
Your WCF-service is returning other objects than you expect. Investigate the service or change the constructor of MyViewModel to accept objects of class myStoredProcedure.

Related

Noob Issue with Activate.CreateInstance

I am working on being able to dynamically invoke an instantiation of a class dynamically at run time.
I have spent the better part of this morning searching Google for an answer but I am pretty green in this world so I am sure the answers make sense, but they do not to me.
public class MSD : IGBRule
{
public MSD(GoverningBodyRulesGet_Result GBRule, int UserID)
{}
The line error and the error are both below
object v = Activator.CreateInstance(Type.GetType("RulesEngine.Rules.MSD, RulesEngine.Rules"), UserID, GBRules);
System.MissingMethodException: 'Constructor on type 'RulesEngine.Rules.MSD' not found.'
If you want to create an object and pass arguments to the constructor, you will have to provide the arguments in the correct order, matching the order you have specified in your constructor. So in your case, you want to pass the rule before the user id:
var type = Type.GetType("RulesEngine.Rules.MSD, RulesEngine.Rules");
object v = Activator.CreateInstance(type, GBRules, UserID);
If you pass the constructor arguments directly to the CreateInstance method, you will have to be careful with common types as it is possible that you are accidentally selecting a different overload that doesn’t call the correct constructor. You can avoid that by passing an object array with the arguments you want to pass:
var type = Type.GetType("RulesEngine.Rules.MSD, RulesEngine.Rules");
object[] args = new object[] { GBRules, UserID };
object v = Activator.CreateInstance(type, args);

dynamic casting Json doesn't create the same object as an explicit cast

I had this issue I was working through where I needed to deserialize my JSON into a dynamic type and I've got that worked out with this now,
var typeObject = System.Reflection.Assembly.GetExecutingAssembly().GetType("SalesForceEndpoints.Models.BaseAccount");
var accountToCreate = JsonConvert.DeserializeObject(body.Data.ToString(), typeObject);
var result = client.Create(accountToCreate); // This line fails because of the type
I can see that it successfully creates an object of my custom BaseAccount type. However when I am trying to pass it to the API I am using in Salesforce it fails. I tested explicitly casting to the type and it works fine like this,
var stronglyTypedAccountToCreate = JsonConvert.DeserializeObject<BaseAccount>(body.Data.ToString());
var result2 = client.Create(stronglyTypedAccountToCreate); // This succeeds
When looking at both of my objects in Visual Studio they appear to be the same at first glance,
And then I noticed this on my watch under the Type column,
The dynamically cast object is being listed as
object {SalesForceEndpoints.Models.BaseAccount}
and the explicitly cast object is being listed as
SalesForceEndpoints.Models.BaseAccount
I'm almost positive this is what is preventing me from executing my call succesfully, any ideas what is going wrong here and how I can execute the dynamic runtime cast to simulate an explicit compile time cast?
--- EDIT ---
I found out part of the issue. When I was calling into the Create function the create function was trying to extract the generic type and when it was dynamically cast it came through as object here instead of Account.
public IResponse<string> Create<T>(T obj) where T : new()
{
try
{
var typeName = typeof(T).Name.Replace("Base", "");
var result = _api.Create(typeName, obj);
return new SuccessResponse<string>(ResponseResult.Success, result);
}
catch (Exception ex)
{
return new FailureResponse<string>(ResponseResult.Failure, $"Unable to create record. | {ex.Message}");
}
}
Still a little curious if anyone knows why as to how a dynamic cast to an object comes through as object {ModelObject} rather than just ModelObject.
You should change it
var typeName = typeof(T).Name.Replace("Base", "");
to
var typeName = obj.GetType().Name.Replace("Base", "");
Because T will be evaluated as System.Object, you are not passing a known type to generic function and T stays with System.Object. If want to use generics, you should specify T in the compiler time.

Why DapperRow.GetType() return null?

As far as I knew, Object.GetType() should never return null. (related discussion)
Dapper .Query() return private class DapperRow instances to be treated as dynamic objects. I found a strange thing: DapperRow's .GetType() return null.
Here's the sample code to reproduce the problem. Create a C# project, reference Dapper and open a connection to SQL Server (or other database), use .Query() to execute simple select query and retrieve the first row of result. Use GetType() to get the type of result object, the return value is null.
using (SqlConnection cn = new SqlConnection(csSql))
{
var rec = cn.Query("select getdate() as D").Single();
var t = rec.GetType(); // t == null
Console.WriteLine(t.Name); // null reference exception
}
I suspect that dynamic or private type is the cause of null, so I write my class library for test:
namespace Lib
{
public class Blah
{
public static dynamic SecretObject;
static Blah()
{
SecretObject = new PrivateType();
}
}
class PrivateType
{
}
}
In another project, get the dynamic type static field and call GetType():
dynamic obj = Lib.Blah.SecretObject;
Console.WriteLine(obj.GetType().Name); // "Lib.PrivateType"
According to the test result, even cast private type as dynamic, I still can get the private type information from GetType(), why DapperRow.GetType() return null?
DapperRow is specifically built and utilized within Dapper to provide highly optimized row returns without reiterating header information. This is to help condense the size of the object and reduce redundant data, making it more efficient.
However, it would appear that the StackExchange team took the meta programming even further than a first glance would indicate.
DapperRow implements the System.Dynamic.IDynamicMetaObjectProvide interface, which requires that the GetMetaObject method be implemented:
System.Dynamic.DynamicMetaObject System.Dynamic.IDynamicMetaObjectProvider.GetMetaObject(
System.Linq.Expressions.Expression parameter)
{
return new DapperRowMetaObject(parameter,
System.Dynamic.BindingRestrictions.Empty, this);
}
DapperRowMetaObject is a custom implementation of DynamicMetaObject that essentially hijacks and overrides what methods can be invoked against the dynamic type and what those calls should translate to. In this case, calls to anything other than the DapperRow's IDictionary.Item getter or the DapperRow.SetValue will fail since they are always routed to those two calls, but the value will be defaulted to null for any "get" calls where the target property does not exist in the table.
public bool TryGetValue(string name, out object value)
{
var index = table.IndexOfName(name);
if (index < 0)
{ // doesn't exist
value = null;
return false;
}
...
}
At that point, any methods invoked on a null dynamic value will throw a RuntimeBinderException:
RuntimeBinderException: Cannot perform runtime binding on a null
reference
You can easily test this hypothesis by replacing GetType() with another call that will throw the exact same exception:
var rec = cn.Query("select getdate() as D").Single();
var t = rec.AsEnumerable();
Console.WriteLine(t.ToList());
Keep in mind, the underlying type information of any properties on the dynamic object itself can still be accessed directly:
var rec = cn.Query("select getdate() as D").Single();
var t = rec.D.GetType();
Console.WriteLine(t.Name);

C# Reflection Invoke - Returns Generic Object { Type } - Need Type

I have a stored procedure call interface that I'm using to handle results from stored procedures with entity (using Translate method to translate the results of our stored procedure into entities that can be tracked and used in EF as normal)
Here's the basic code...
List<object> current = new List<object>();
object item = ((Type)currenttype.Current).GetConstructor(System.Type.EmptyTypes).Invoke(new object[0]);
ObjectContext actualContext = ((IObjectContextAdapter)context).ObjectContext;
string className = "";
EntityContainer container = null;
string setName = "";
className = ((Type)currenttype.Current).ToString();
container = actualContext.MetadataWorkspace.GetEntityContainer(((IObjectContextAdapter)context).ObjectContext.DefaultContainerName, DataSpace.CSpace);
setName = (from meta in container.BaseEntitySets
where meta.ElementType.FullName == className
select meta.Name).FirstOrDefault();
var t = typeof(ObjectContext).GetMethod("Translate", new Type[] { typeof(DbDataReader), typeof(string), typeof(MergeOption) }).MakeGenericMethod(item.GetType()).Invoke(actualContext, new object[] { reader, setName, MergeOption.AppendOnly });
The issue is that I can't do anything with 't' that I want, it's type is listed as
object {System.Data.Entity.Core.Objects.ObjectResult<POCOClass>}. I can't call any of the normal methods that I can normally on the ObjectResult type such as ToArray or ToList.
I need a way to convert it into System.Data.Entity.Core.Objects.ObjectResult<POCOClass>. The difference being that 't' is listed as type object first.
I cannot use any strongly typed casts because the types will change depending on the stored procedure. I've tried using the dynamic keyword instead of var for t and I've also tried using Convert.ChangeType. It never changes from the object base type. dynamic t returns this the following error:
'System.Data.Entity.Core.Objects.ObjectResult<POCOClass>' does not contain a definition for 'ToList'
Thought I know for a fact it does...
To clear up confusion, here's a watch screenshot. The first line is what's being returned, I want it to be like the second (see Type column).
Edit: might be getting closer... I added this:
var listedT = typeof(Enumerable).GetMethod("ToList").MakeGenericMethod(item.GetType()).Invoke(null, new object[] { t });
current.AddRange(listedT); // Error here...
listedT becomes a object {System.Collections.Generic.List<ReportCatalog.Models.Catalog_Reports>} and I get the error, cannot convert from object to System.Collections.Generic.IEnumerable<object>.
Since ObjectResult<T> implements also the non-generic IEnumerable interface, cast it to this type and enumerate it.
var e = (IEnumerable)t;
foreach (object o in e) {
//TODO: use o
}

Error executing code: Wrong argument type for function

I have some code in c# which uses the AX Business connector, and its like this:
AxaptaRecord OrderRecord = (AxaptaRecord)ax.CallStaticClassMethod("BTNOnlineOrder", "getSalesOrder", salesRef);
if (OrderRecord.Found)
{
AxaptaObject Lines = (AxaptaObject)OrderRecord.Call("querySalesLine");
AxaptaObject qrLines = (AxaptaObject)ax.CreateAxaptaObject("QueryRun", Lines);
while ((bool)qrLines.Call("next"))
{
int tableid = (int)ax.CallStaticClassMethod("Global", "tableName2Id", "InventTable");
AxaptaRecord r = (AxaptaRecord)qrLines.Call("get", tableid);
}
}
I get the following error when I try to call the "get" method:
Error executing code: Wrong argument type for function.
tableid returns an int value, 175, so it's not due to tableid being null or something.
Any help would be appreciated
If the query that you use does not have a datasource pointing to InventTable you will get this (confusing) error. I've verified this code throws this exception on the default SalesLine query in the Ax sys layer. I agree, it is a confusing error.
If you need InventTable in your consuming code you will need to define a custom query and return that from querySalesLine method.
I got this to work by using the getNo method and passing 1 as the parameter. I'm not sure if it's the correct way or not but it worked for me:
http://msdn.microsoft.com/en-us/library/aa612609(v=ax.50).aspx

Categories