I'm fetching a list of marketing lists. As I do so, it seems to be a successful operation according to my check using intellisense. When I look for ...Entities[0].Attributes["nick"]
I get an object (with the right data somewhere in it). But I can't access it programmatically (instead I have to click around like a monkey via the pluses to fold out the good stuff).
In fact, I'm getting the entities as supposed to using the code below. The problem is that they aren't Strings
according to the computer. They are of type Microsoft.Xrm.Sdk.AliasedValue
and I don't know how to access the actual nick inside them.
new Contact
{
Name = element.Attributes["nick"] as String,
Mail = element.Attributes["mail"] as String
}
Intellisense says that Value
is in there (and it's the correct value too) but I can't access it by typing .Value
. I suspect that I need to use "as" or something like that but at the moment I'm stuck. Any hints? As
'ing it to String
, which is supposed to work, gives me null
...
I've read this article and several others like it and the way I see it, I'm supposed to be able to access all the fun stuff in there. I can't though...
I've noticed that the following code gets me the data I'm so desperately trying to get but this can't be a professional syntax, can it?! Seriously, it looks like a high school student with ADHD and hangover tried to do that...
new Contact
{
Name = ((Microsoft.Xrm.Sdk.AliasedValue)result.Entities[0].Attributes["nick"]).Value,
Mail = ((Microsoft.Xrm.Sdk.AliasedValue)result.Entities[0].Attributes["mail"]).Value
}
I mean, seriously - this is one ugly piece of code... There's got to be a better way! However, I fear there's not because this discussion seems to be using that syntax as well...
Looking at the documention, the Attributes
property of the Entity
object is of type AttributeCollection
, which derives from DataCollection<string,Object>
.
For each attribute in the collection there is a key/value pair.
So for each key ("nick", "mail"), there is a corresponding object
, which could be of any .NET type. You have to cast the object to the correct type (as you've done) to access the properties you're looking for (or else use reflection, which would certainly be uglier, or I suppose in C# 4.0 the dynamic
type, but in that case, you lose compile-time checking); how else would the compiler be able to determine whether an attribute is of type string
/Money
/int
/AliasedValue
/etc.?
As for AliasedValue
, the CRM uses this type to store additional information about the returned value, and since any attribute can be aliased, the Value
property could be of any type (OptionSetValue
, decimal
, string
, Guid
, EntityReference
, etc.). The Value
property is then appropriately also of type object
, so you have to cast this as well to get any additional information about your returned value.
So there's no way around casting, but you can make your code shorter and perhaps cleaner by adding a using
statement at the top of your file and by defining the values of each AliasedValue
prior to the assignment to the Contact
. Regardless, I've included one example of each type of data retrieval; you can judge which is better in your project.
Using casting:
using Microsoft.Xrm.Sdk;
...
var nick = (AliasedValue)result.Entities[0].Attributes["nick"];
var mail = (AliasedValue)result.Entities[0].Attributes["mail"];
var contact = new Contact
{
Name = nick.Value, //Value is of type object; cast again for a more specific type
Mail = mail.Value
};
Using reflection:
var nick = result.Entities[0].Attributes["nick"]
.GetType()
.GetProperty("Value")
.GetValue(result.Entities[0].Attributes["nick"], null);
var mail = result.Entities[0].Attributes["mail"]
.GetType()
.GetProperty("Value")
.GetValue(result.Entities[0].Attributes["mail"], null);
var contact = new Contact
{
Name = nick,
Mail = mail
};
Using dynamic:
dynamic nick = result.Entities[0].Attributes["nick"];
dynamic mail = result.Entities[0].Attributes["mail"];
var contact = new Contact
{
Name = nick.Value, //dynamic figures out the right property at runtime
Mail = mail.Value
};