Accessing Url of a MediaPicker field

Topics: Writing modules
Apr 16, 2013 at 3:26 PM
I am having difficulty in accessing the Url of a MediaPicker field. I know there have been lots of posts on here about that but I am still unable to do this.

I am using the Nwazet.Commerce module. There is a part called ProductPart in there and is defined so in it's migration:
public int Create() {
            SchemaBuilder.CreateTable("ProductPartRecord", table => table
                .ContentPartRecord()
                .Column("Sku", DbType.String)
                .Column("Price", DbType.Double)
                .Column("ShippingCost", DbType.Single, column => column.Nullable())
                .Column("Weight", DbType.Single)
                .Column("IsDigital", DbType.Boolean, column => column.WithDefault(false))
            );

            ContentDefinitionManager.AlterPartDefinition("ProductPart",
              builder => builder.Attachable());

            ContentDefinitionManager.AlterTypeDefinition("Product", cfg => cfg
              .WithPart("Product")
              .WithPart("CommonPart")
              .WithPart("TitlePart")
              .WithPart("AutoroutePart", builder => builder
                  .WithSetting("AutorouteSettings.AllowCustomPattern", "true")
                  .WithSetting("AutorouteSettings.AutomaticAdjustmentOnEdit", "false")
                  .WithSetting("AutorouteSettings.PatternDefinitions", "[{Name:'Title', Pattern: '{Content.Slug}', Description: 'my-product'}]")
                  .WithSetting("AutorouteSettings.DefaultPatternIndex", "0"))
              .WithPart("BodyPart")
              .WithPart("ProductPart")
              .WithPart("TagsPart")
              .Creatable()
              .Indexed());

            ContentDefinitionManager.AlterPartDefinition("Product",
              builder => builder.WithField("ProductImage", fieldBuilder => fieldBuilder.OfType("MediaPickerField").WithDisplayName("Product Image")));
            return 1;
        }
So in my controller, I use the contentmanager to query for ProductParts. I want to be able to loop through that collection and get the link to the image.

I'd post my bad code for getting the Url, but I'm at work right now. I wrote it after reading through some other posts about it. It's something to the effect of:
var theprods = _query(....blah blah...getting the productparts);
foreach(prod in theprods)
{
  var url = prod.ContentItem.Product.ProductImage.Url;
}
Any tips?
Apr 17, 2013 at 12:30 AM
var url = prod.ContentItem.Product.ProductImage.Url;
Assuming Product is the name of the ContentType, that should work.
Apr 17, 2013 at 3:06 PM
Hazza,

Thanks. I'll try that tonight. Is it really as easy as that? Why does the intellisense not show 'Product'? Is 'Product' somehow dynamic or something?
Apr 17, 2013 at 3:13 PM
Yes :)

When you think about it, Orchards ability to add and remove bit and pieces from everything meant using some form of dynamic objects was the only real option. So yes, it is dynamic and hence no intellisense. Once you get used to the syntax of "keep adding dots", you can pretty much find everything you ever want about content items.
Apr 17, 2013 at 3:32 PM
Great! I can't wait to get home and try this! :-)

Yes, it does take some time to wrap your head around it but when you do, it's SO powerful!
Apr 17, 2013 at 5:33 PM
Agreed! Good luck :)
Coordinator
Apr 17, 2013 at 5:50 PM
FYI, here is a list of available properties for several fields: http://sebastienros.github.io/CheatSheet/
Apr 17, 2013 at 6:06 PM
Edited Apr 17, 2013 at 6:07 PM
Ah yes, forgot about this, favourited so I won't forget it again.

Cheers!
Apr 18, 2013 at 2:41 AM
Edited Apr 18, 2013 at 2:43 AM
So I gave that a try. My code is:
var products = _productService.GetProducts();
var productItems = from product in products
                             select new ProductInfo()
                               {
                                   ProductContentItemId = product.Id,
                                   Sku = product.Sku,
                                   UnitPrice = product.Price,
                                   WholesaleUnitPrice = product.PriceWholesale,
                                   ProductTitle = product.As<TitlePart>().Title,
                                   Summary = product.As<BodyPart>().Text,
                                   MinimumOrderQuantity = product.MinimumOrderQuantity,
                                   OutOfStockMessage = product.OutOfStockMessage,
                                   ImageUrl = product.ContentItem.Product.ProductImage.Url
                               };
ProductInfo is just a POCO wrapper so I can more easily process the products in the frontend. The line of interest is the product.ContentItem.Product.ProductImage.Url. When I went to compile the module, I got the error:
Error   10  'Orchard.ContentManagement.ContentItem' does not contain a definition for 'Product' and no extension method 'Product' accepting a first argument of type 'Orchard.ContentManagement.ContentItem' could be found (are you missing a using directive or an assembly reference?)   C:\Business\Development\Clients\EricaZap\Orchard.Source.1.6\src\Orchard.Web\Modules\nwazet.commerce\Controllers\ProductCatalogController.cs 84  67  Nwazet.Commerce
Is there something that I am missing?
Apr 18, 2013 at 2:51 AM
Strange. You may need to cast it as dynamic. Possibly...
dynamic item = product.ContentItem;
Apr 18, 2013 at 3:11 AM
I have this code, for a User content type.
var user = _authenticationService.GetAuthenticatedUser();
dynamic item = user.ContentItem;
var FieldValue = item.User.MyField.Value;
Apr 18, 2013 at 3:29 AM
Edited Apr 18, 2013 at 3:30 AM
Hazza,

I was thinking about casting it to dynamic. This is what I ended up with that worked:
var ImageUrl = ((dynamic)product.ContentItem).Product.ProductImage.Url;
Thanks for your help!! If you're ever in Rhode Island, USA, I owe you a beer!
Apr 18, 2013 at 3:30 AM
No worries, good to see it all working :)
Apr 18, 2013 at 3:39 AM
Now that it's all working, can someone please explain to me why casting to dynamic works? :-)
Apr 18, 2013 at 4:08 AM
Edited Apr 18, 2013 at 4:14 AM
Well, as a dynamic you just get improved accessors. I'm not quite sure why this is. You can still get the field without casting to dynamic. For example:
var user = _authenticationService.GetAuthenticatedUser();
var g = user.ContentItem.Parts.FirstOrDefault(x => x.PartDefinition.Name == "User");
var f = g.Fields.FirstOrDefault(c => c.Name == "MyField").Storage.Get<string>("");
So yeah, sorry, cant really help you with this. I only know the basics of Orchard ^_^ And if I'm ever in Rhode Island, I will happily take you up on such an offer.