Applying query options on typeless entity - c#

How can I apply the query options on a non clr type. The .ApplyTo method is throwing an error when I'm using it.
Error:
"The query option is not bound to any CLR type. 'ApplyTo' is only
supported with a query option bound to a CLR type."
var x = (EdmCollectionType)Request.GetODataPath().EdmType;
ODataQueryContext queryContext = new ODataQueryContext(Request.GetEdmModel(), x.ElementType.Definition);
ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, Request);
//codes.....
queryOptions.ApplyTo(Products);

Just as the error said, the query options can't be applied on a non clr type now.
It is because now webapi need the clr type to generate linq expression for query options.
However you can implement the ApplyTo function on a non clr type yourself with the raw values in the query options:
queryOptions.Filter.RawValue
queryOptions.OrderBy.RawValue
...

ODataQueryContext queryContext = new ODataQueryContext(Request.GetEdmModel(), x.ElementType.Definition);
In the above line, we need to explicitly pass the Class Type obj to ODataQueryContext.
Let's assume a type named A which has been created at runtime.
Type a = //Get the type at runtime ;
ODataQueryContext queryContext = new ODataQueryContext(Request.GetEdmModel(), a);
This should resovle the exception.
Now, come to ApplyTo() we can pass an instance of type A to it.
object instance = Activator.CreateInstance(a);
odataQuerySetting.ApplyTo(instance,, new ODataQuerySettings() { });
However, we would like to run ApplyTo() against a list of objects as well as one instance.
Array class could help us to accomplish this. Suppose we need to create 10 instances:
Array values = Array.CreateInstance(a, 10);
for (int i = 0; i < 10; i++)
{
values.SetValue(Activator.CreateInstance(t), i);
}
Needless to say that we can add properties to our instances as we would like to and then pass it to SetValue().
Finally, the ApplyTo() can be executed against our list as follow:
queryOptions.ApplyTo(values.AsQueryable());
Note: if you get the status:406 then one possible cause could be the JsonFormat. use a custom MediaTypeFormatter to resolve that.
I hope that this might help someone.

Related

dynamic.ToString() unexpected behaviour

I'm wondering how does this code work:
dynamic dynaString = 2;
string b = dynaString.ToString();
When this one is not working:
var list = new List<dynamic>();
var liststring = new List<string>();
liststring = list.Select(x => x.ToString()).ToList();
I know I can add Cast<string> after Select statement but that does not explain that behaviour. Why does ToString() on dynamic element work different when called on dynamic variable declared in code than on dynamic variable taken from list in LINQ.
I've looked into method signature of Select and it's:
My guess is that x here is a dynamic variable, so it should behave just like dynaString, but it's not. Intellisense is suggesting me that this x.ToString() returns string:
Anyone got experience with dynamics in C# and can explain me that?
I've also tried this code:
var list = new List<dynamic>();
var liststring = new List<string>();
foreach (dynamic a in list)
{
liststring.Add(a.ToString());
}
It compiles as expected, because again the a is declared as dynamic in foreach statement.
According to dynamic type docs:
The dynamic type indicates that use of the variable and references to its members bypass compile-time type checking. Instead, these operations are resolved at run time.
Type dynamic behaves like type object in most circumstances. In particular, any non-null expression can be converted to the dynamic type. The dynamic type differs from object in that operations that contain expressions of type dynamic are not resolved or type checked by the compiler.
There is no way to infer type from usage in case type checking and/or resolution is bypassed at compile-time.
If you omit generic type parameter it will by default return dynamic type even you call ToString() method. The reason is that any non-null expression can be assigned to dynamic. As dynamic is source, it will be also the result of Select(x => x.ToString()) method call.
On the other hand you can assign dynamic object to string variable as you are calling ToString() which returns string instance.

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
}

Why can't I access properties of an anonymous type returned from a function via the dynamic keyword?

I have a function that returns an anonymous type like so (simplified for illustrative purposes)...
public object GetPropertyInfo()
{
return new {
PropertyName = "Foo",
Value = "Laa"
};
}
When I do this...
dynamic pi = GetPropertyInfo();
Console.WriteLine(pi);
It outputs this (the same as if I did '?pi' in the immediate window)...
{ PropertyName = "A", Value = 44 }
PropertyName: "A"
Value: 44
But if I try doing this...
string propertyName = pi.PropertyName;
...it compiles but throws a runtime exception saying
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in System.Core.dll
Additional information: 'object' does not contain a definition for 'PropertyName'
What gives? What am I missing here?
The problem is that anonymous types are internal, which means that you can't access their properties with dynamic property accessors from projects other than the one they were created in. The dynamic binding treats them as the closest public inherited type it knows about--object.
To fix this, you can declare a public type to represent the values you're expecting to find in your anonymous type. This is probably a good idea anyway, since you're clearly expecting to consume the returned properties in other parts of your code. Using a declared type also enables you to maintain type-safety, avoiding the need for dynamic entirely.
If you absolutely must use dynamics here, the next best option is probably to change your AssemblyInfo.cs file to make internal properties accessible to the project you're trying to access them from:
[assembly:InternalsVisibleTo("MyOtherProject")]
Edit
According to your edit. Apparently you are not required dynamic at all as there are no dynamic properties. Just create a concrete type with your predefined properties. It's better to avoid dynamic when possible anyway.
Old Answer
You need to use an ExpandoObject. Reference here.
In fact, GetPropertyInfo() should return an ExpandoObject.
dynamic foo = this.GetPropertyInfo();
string i = foo.MyPropertyName;
private ExpandoObject GetPropertyInfo()
{
dynamic obj = new ExpandoObject();
obj.PropertyName = "MyPropertyName";
obj.PropertyType = "MyPropertyType";
return obj;
}
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").
Also, you can use System.Reflection
object D = GetPropertyInfo();
Type t = D.GetType(); // get object's type
PropertyInfo p = t.GetProperty("PropertyName"); // look up for the property:
object P = p.GetValue(D, null); // get the value
Fiddle demo

DbSet<TEntity>.Find() - Reflection

Im trying to:
...
int id = 5;
//DB is a instance of DbContext
MethodInfo methodFind = DB.GetType().GetMethod("Find");
var resultFind = methodFind.Invoke(entityCol, new object[]{id});
But an Exception is thrown at "Invoke":
"Object of type 'System.Int32' cannot be converted to type 'System.Object[]'."
Is there a way to call DbSet.Find(params object[] keyValues) with reflection?
ps.
Im using it on a CustomAuthorization attribute, i also accept suggestions to improve this part of code. Im trying to check if a certain register of a certain entity (using an attribute) can be edited by a certain user by its common "CompanyId" property, inherited from a "BaseModel" (so all tables got this property)
Try this:
var resultFind = methodFind.Invoke(entityCol, new object[]{new object[]{id}});
The second parameter to Invoke in an object[] which needs to contains objects the map the parameters of the Find method. The first parameter to Find also happens to be an object[] so you need to nest it.
I solved that using this:
var curEntityPI = DB.GetType().GetProperties().Where(pr => pr.Name == entityName).First();
var curEntityType = curEntityPI.PropertyType.GetGenericArguments().First();
var result = DB.Set(curEntityType ).Find(id);

How to generate an instance of an unknown type at runtime?

i've got the following in C#:
string typename = "System.Int32";
string value = "4";
theses two strings should be taken to generate an object of the specified type with the specified value...
result should be:
object o = CreateUnknownType(typename, value);
...
Int32 test = (Int32)o;
Is this what are you are thinking?
object result = Convert.ChangeType("4", Type.GetType("System.Int32"));
As stated, this is too broad and can not be solved generally.
Here are some options:
Type type = Type.GetType(typename);
object o = Activator.CreateInstance(type);
This will create an instance of the type that typename is describing. It calls the parameterless constructor of that type. (Downside: Not all objects have a parameterless constructor. Further, this does set the state of the object using value.)
Type type = Type.GetType(typename);
object o = Activator.CreateInstance(type, new[] { value });
This will create an instance of the type that typename is describing. It calls a constructor of that type that accepts one parameter of type string. (Downside: Not all objects have such a constructor. For example, Int32 does not have such a constructor so you will experience a runtime exception.)
Type type = Type.GetType(typename);
object o = Convert.ChangeType(value, type);
This will attempt to convert the string value to an instance of the required type. This can lead to InvalidCastExceptions though. For example, Convert.ChangeType("4", typeof(FileStream)) will obviously fail, as it should.
In fact, this last example (create an instance of type FileStream with its initial state determined by the string "4") shows how absurd the general problem is. There are some constructions/conversions that just can not be done.
You might want to rethink the problem you are trying to solve to avoid this morass.
Creating an instance of a type you know by name (and which should have a default constructor):
string typeName = "System.Int32";
Type type = Type.GetType(type);
object o = Activator.CreateInstance(type);
Parsing a value from a string will obviously only work for a limited set of types. You could
use Convert.ChangeType as suggested
by PhilipW
or maybe create a
Dictionary<Type,Func<string,object>>
which maps known types to known parse
functions
or use reflection to invoke the
Parse(string) method on the type,
assuming there is one:
string valueText = "4";
MethodInfo parseMethod = type.GetMethod("Parse");
object value = parseMethod.Invoke(null, new object[] { valueText });
or maybe you can use the
infrastructure provided by the .NET
component model. You can fetch the
type converter of a component and use
it like this:
TypeConverter converter = TypeDescriptor.GetConverter(type);
object value = converter.ConvertFromString(valueText);
Your logic seems a little flawed here. Obviously, if you're directly casting the object at a later time to the actual type it is, then you must know the type to begin with.
If there's something else that is missing from this question please elaborate and maybe there is a more appropriate answer than simply, "This doesn't make much sense."
Perhaps you have a set of different types, all of which implement a known interface?
For example if you have several different user controls and want to load one of them into a container, each one might implement IMyWobblyControl (a known interface) yet you might not know until runtime which of them to load, possibly from reading strings from some form of configuration file.
In that case, you'll need to use reflection to load the actual type from something like the full assembly name, then cast it into your known type to use it.
Of course, you need to make sure that your code handles invalid cast, assembly not found and any of the other exceptions that are likely to come along through something as wobbly as this...
This seems like a job for Int32.Parse(string). But to agree with the others it seems this is "unique" and one should probably think gloves.
Here's a specific example of the problem involving Azure SQL Federations...which splits data into separate db's according to a key range.
The key range types are:
SQL / .Net SQL type / CLR .Net
INT / SqlInt32 / Int32, Nullable
BIGINT / SqlInt64 / Int64, Nullable
UNIQUEIDENTIFIER / SqlGuid /Guid, Nullable
VARBINARY(n), max n 900 / SqlBytes, SqlBinary /Byte[]
Ideally, a C# function param could take either .Net SQL type or CLR .Net type but settling on just one category of type is fine.
Would an "object" type param be the way to go? And, is there a feasible way to identify the type and convert it accordingly?
The concept is something like:
public void fn(object obj, string fedName, string distName, bool filteringOn)
{
...figure out what type obj is to ensure it is one of the acceptable types...
string key = obj.toString();
return string.Format("USE FEDERATION {0} ({1}='{2}') WITH RESET, FILTERING = {3}", fedName, distName, key, (filteringOn ? "ON" : "OFF"));
}
Though the param value is cast to string, it will be recast/checked on the sql server side so validating it on the app side is desired.
After using:
Type type = Type.GetType(typename);
Try this extension method:
public static class ReflectionExtensions
{
public static T CreateInstance<T>(this Type source, params object[] objects)
where T : class
{
var cons = source.GetConstructor(objects.Select(x => x.GetType()).ToArray());
return cons == null ? null : (T)cons.Invoke(objects);
}
}
Hope this helps.

Categories