1

I am currently writing an api for a custom application my company is writing. Part of this involves getting published content out in JSON format. When I try serializing ipublishedcontent directly it obviously attempts to serialize all of the umbraco data and relations that I simply don't need (in fact it fails with a stack overflow). Is there a way to get just the custom properties from an item of content without specifying the fields?

I am using webapi and passing it objects to serialize itself and I'm using a dynamic to manually specify the fields. The Product type which I'm initially selecting into is from modelsbuilder. My code currently looks a little like this:

public object Get(string keywords = "")
{
    // Get Data from Umbraco
    var allProducts = Umbraco.TypedContent(1100).Children.Select(x => new Product(x));
    if (keywords != "")
    {
        allProducts = allProducts.Where(x => x.Name.Contains(keywords));
    }


    return allProducts.Select(x => new
    {
        id = x.Id,
        name = x.Name,
        price = x.Price
    });
}

It seems to me that there should be a simple way to do this without having to create a dynamic with just the fields I want but I can't work it out. I just don't want to have to change my code every time the document type in umbraco changes!

Chris Foot
  • 343
  • 1
  • 5
  • 17

2 Answers2

0

You can use Ditto to map your data into an object.

Create an object with properties that match the alias's of your fields (case insensitive)

 public class Product{ 
    public int id {get;set;} 
    public string name {get;set;} 
    public string price {get;set;} 
 }

Then map a single or collection of IPublishedContent objects using .As

return allProducts.As<Product>();

You can use the UmbracoProperty attribute to specify the alias too if it is different than you need for your json or use the JsonProperty attribute to change the name on serialize.

Community
  • 1
  • 1
Sam Sussman
  • 1,005
  • 8
  • 27
  • Wouldn't that require me recreating a class every time a field on the document type changed? The point is to dynamically output any useful fields on the document without having to recompile the project every time the document type is changed. – Chris Foot Mar 31 '16 at 13:14
  • You could use the Model Builder that is packaged with 7.4. It creates classes for each document type automatically. – Sam Sussman Mar 31 '16 at 13:16
  • Another option would be to loop through the properties collection of IPublishedContent and add the aliases + values to a dictionary. Which would be outputting like an object in json. – Sam Sussman Mar 31 '16 at 13:18
  • Yes, as mentioned in the question, I'm already using modelsbuilder (.Select(x => new Product(x))) in the hope that it would do what I wanted but it too includes all of the extraneous umbraco fields and references. I did attempt just outputting the properties collection from the document but that also has lots of unneeded stuff in it. I guess the only option may be to loop through the properties and compare them to a list of types that i'm interested in but that seems a little long winded for something that seems like it should be simple. – Chris Foot Mar 31 '16 at 13:22
  • I guess I can't read this morning... I know if you used the Services (not cached) it will give you all properties directly off the content type using Content.ContentType.PropertieTypes or Content.ContentType.ComposedPropertyTypes. This doesn't return any internal fields. It might not be too much of a performance hit to make one request for the aliases of the prop types and use them against the IPublsihedContent collection. – Sam Sussman Mar 31 '16 at 13:31
0

Take a look at the code in the MemberListView - it does a similar thing while retrieving Members without knowing in advance what the properties on the MemberType will be:

https://github.com/robertjf/umbMemberListView/blob/master/MemberListView/Models/MemberListItem.cs

For example:

[DataContract(Name = "content", Namespace = "")]
public class MemberListItem
{
    // The following properties are "known" - common to all IPublishedContent
    [DataMember(Name = "id")]
    public int Id { get; set; }

    [DataMember(Name = "name")]
    public string Name { get; set; }

    [DataMember(Name = "contentType")]
    public IContentType ContentType { get; set; }

    // This one contains a list of all other custom properties.
    private Dictionary<string, string> properties;
    [DataMember(Name = "properties")]
    public IDictionary<string, string> Properties
    {
        get
        {
            if (properties == null)
                properties = new Dictionary<string, string>();
            return properties;
        }
    }
}

MemberListView converts to this from a list of SearchResult using AutoMapper, but you could just as easily map it from IPublishedContent.

Robert Foster
  • 2,317
  • 18
  • 28