<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Creating Custom Applications and Content</title><link>https://community.telligent.com/community/11/w/developer-training/65100/creating-custom-applications-and-content</link><description /><dc:language>en-US</dc:language><generator>14.0.0.586 14</generator><item><title>Creating Custom Applications and Content</title><link>https://community.telligent.com/community/11/w/developer-training/65100/creating-custom-applications-and-content</link><pubDate>Wed, 05 Aug 2020 15:09:26 GMT</pubDate><guid isPermaLink="false">9c708778-1984-4d1c-9853-406bc41713cb</guid><dc:creator>Former Member</dc:creator><comments>https://community.telligent.com/community/11/w/developer-training/65100/creating-custom-applications-and-content#comments</comments><description>Current Revision posted to Developer Training by Former Member on 08/05/2020 15:09:26&lt;br /&gt;
&lt;p&gt;The platform&amp;nbsp;provides the ability to create your own types of content and applications.&lt;/p&gt;
&lt;p&gt;[toc]&lt;/p&gt;
&lt;h2&gt;&lt;a id="Why_create_custom_applications_and_content" name="Why_create_custom_applications_and_content"&gt;&lt;/a&gt;Why create custom applications and content?&lt;/h2&gt;
&lt;p&gt;If you are writing a new&amp;nbsp;application&amp;nbsp;or&amp;nbsp;have content (internal or external) that you want to interact with Verint Community&amp;#39;s core services, creating a custom content and application type within the community can be beneficial. &amp;nbsp;Content Types within the community can interact with core services. &amp;nbsp;Likes, Ratings, Comments, Moderation, Mentions and Hashtags are some of the services your content will have access to once registered with the community.&lt;/p&gt;
&lt;p&gt;There is a deeper discussion of how content and applications fit in the community platform in [[The Content Model]]&amp;nbsp;article.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Content_and_Content_Types" name="Content_and_Content_Types"&gt;&lt;/a&gt;Content and Content Types&lt;/h2&gt;
&lt;p&gt;There are two interfaces that are provided in the platform to identify types of content and individual content entities. &amp;nbsp;The [[api-documentation:IContentType Plugin Type|IContentType]]&amp;nbsp;interface is used to identify types of content and the [[api-documentation:IContent Plugin Supplementary Type|IContent]]&amp;nbsp;interface is used to represent the individual content entities. &amp;nbsp;Both of these interfaces are found in the Telligent.Evolution.Core.dll.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Applications_and_Application_Types" name="Applications_and_Application_Types"&gt;&lt;/a&gt;Applications and Application Types&lt;/h2&gt;
&lt;p&gt;Similar to content, the platform provides the [[api-documentation:IApplicationType Plugin Type|IApplicationType]] to identify a type of application and [[api-documentation:IApplication Plugin Supplementary Type|IApplication]] to represent an individual application entity. &amp;nbsp;These interfaces are also found in the&amp;nbsp;Telligent.Evolution.Core.dll.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Creating_an_Application_and_Content" name="Creating_an_Application_and_Content"&gt;&lt;/a&gt;Creating an Application and Content&lt;/h2&gt;
&lt;p&gt;For our example application, we will create a Links Application. &amp;nbsp;The Links Application will be a collection of links to websites. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s outline our entities.&lt;/p&gt;
&lt;h3&gt;&lt;a id="LinksApplication_Entity" name="LinksApplication_Entity"&gt;&lt;/a&gt;LinksApplication Entity&lt;/h3&gt;
&lt;p&gt;Our LinksApplication Entity will implement the IApplication interface and represent an instance of a Links Application.&lt;/p&gt;
&lt;p&gt;ApplicationTypeId is a unique id that represents a type of application in the community, you define this value. In the example, we have a static class where we define our Id, so it can be referenced from&amp;nbsp;multiple locations. ApplicationId is the unique Id for an individual application in the community. &amp;nbsp;We will provide this to the community as well.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Guid ApplicationId { get; set; }

public Guid ApplicationTypeId
{
    get { return ContentTypes.LinksApplicationId; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The Name and Description fields are not required by the IApplication interface, but allow us to store a raw version of the there values. &amp;nbsp;The HtmlName and HtmlDescription methods are then used to provide the output depending on the target. &amp;nbsp;These allow the output to be tailored to those targets, for instance if your target was an email you may not want to display images inline in your content. &amp;nbsp;Our example data just uses text for Name and Descriptions, there is no need to tailor our output to different targets, instead we will just return the text for all targets.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public string Name { get; set; }
public string Description { get; set; }

public string HtmlName(string target)
{
    return Name;
}

public string HtmlDescription(string target)
{
    return Description;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;For this example we won&amp;#39;t allow disabling the application, so the IsEnabled property will always return true. &amp;nbsp;We wont store our applications in different groups, instead they will all be located in the Site Root group so we will always&amp;nbsp;return the Site&amp;nbsp;group for the Application&amp;#39;s Container. &amp;nbsp;Our application won&amp;#39;t have a url to view it or an avatar associated with it, both AvatarUrl and the Url will just return null.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public bool IsEnabled
{
    get { return true; }
}

public IContainer Container
{
    get { return Apis.Get&amp;lt;IGroups&amp;gt;().Root; }
}

string IApplication.AvatarUrl
{
    get { return null; }
}

string IApplication.Url
{
    get { return null; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinksApplication entity source:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksApplication_2E00_cs"&gt;community.telligent.com/.../LinksApplication_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="LinksItem_Entity" name="LinksItem_Entity"&gt;&lt;/a&gt;LinksItem Entity&lt;/h3&gt;
&lt;p&gt;Our LinkItem&amp;nbsp;Entity will implement the IContent interface and represent a single link item in the Links Application.&lt;/p&gt;
&lt;p&gt;ContentTypeId&amp;nbsp;is a unique id that represents a type of content&amp;nbsp;in the community, you define this value when creating your content type. &amp;nbsp;The example uses the same static class that defines the ApplicationTypeId to define this Id. &amp;nbsp;ContentId&amp;nbsp;is the unique Id for an individual content item&amp;nbsp;in the community. &amp;nbsp;We will provide this to the community as well.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Guid ContentId { get; set; }

public Guid ContentTypeId
{
    get { return ContentTypes.LinksItemId; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Each piece of Content is related to an application in the community, &amp;nbsp;we have defined a property to store the ApplicationId for our content&amp;#39;s application. &amp;nbsp;We use this value to return an instance of our application when we implement the Application property on the IContent interface.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Guid ApplicationId { get; set; }

public IApplication Application
{
    get { return LinksData.GetApplication(ApplicationId); }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The Name and Description fields are not required by the IContent&amp;nbsp;interface, but allow use to store a raw version of the there values. &amp;nbsp;The HtmlName and HtmlDescription methods are then used to provide the output depending on the target. &amp;nbsp;These allow the output to be tailored to those targets, for instance if your target was an email you may not want to display images inline in your content.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public string Name { get; set; }
public string Description { get; set; }

public string HtmlName(string target)
{
    return Name;
}

public string HtmlDescription(string target)
{
    return Description;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Each link item has a Url and the IContent interface requires a Url, so we will use that property to store the Url and satisfy the interface.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public string Url { get; set; }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The CreatedDate, IsEnabled, AvatarUrl and CreatedByUserId properties are required by the interface but will be static or are not needed in this example, so we will implement those, but they don&amp;#39;t provide any additional value. &amp;nbsp;If this were a fully functional example that implemented core services or other features of the platform these values would become important to populate correctly.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public DateTime CreatedDate { get; set; }

public bool IsEnabled
{
    get { return true; }
}

string IContent.AvatarUrl
{
    get { return null; }
}

int? IContent.CreatedByUserId
{
    get { return null; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinkItem&amp;nbsp;entity source:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinkItem_2E00_cs"&gt;community.telligent.com/.../LinkItem_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next we will define our Application and Content Types that make use of our entities&amp;nbsp;to register those with the platform.&lt;/p&gt;
&lt;h3&gt;&lt;a id="LinksApplication_Application_Type" name="LinksApplication_Application_Type"&gt;&lt;/a&gt;LinksApplication Application Type&lt;/h3&gt;
&lt;p&gt;The [[api-documentation:IPlugin Plugin Type|IPlugin]]&amp;nbsp;and [[api-documentation:ITranslatablePlugin Plugin Type|ITranslatablePlugin]] interfaces are discussed in other articles, we will skip the explanation of those implementations and focus on the IApplicationType implementation.&lt;/p&gt;
&lt;p&gt;ApplicationTypeId is the same id that was used when defining our IApplication entity. &amp;nbsp;ApplicationName is the name of the application that will be displayed in the community. &amp;nbsp;The example uses a translation so the application name can be translated for each language the community supports. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid IApplicationType.ApplicationTypeId
{
    get { return ContentTypes.LinksApplicationId; ; }
}

string IApplicationType.ApplicationTypeName
{
    get { return _translations.GetLanguageResourceValue(&amp;quot;ApplicationTypeName&amp;quot;); }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The AttachChangeEvents method provides access to an [[api-documentation:IApplicationStateChanges Plugin Supplementary Type|IApplicationStateChanges]]&amp;nbsp;object. &amp;nbsp;This object is used by your application type to inform the platform of changes to your application. &amp;nbsp;For instance, when you application is deleted, informing the platform of the deletion allows the platform to&amp;nbsp;remove data associated with that application. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;void IApplicationType.AttachChangeEvents(IApplicationStateChanges stateChanges)
{
    _applicationState = stateChanges;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The ContainerTypes property should return all the types of containers that can hold this application. &amp;nbsp;In this case the only container is groups, so that Id is returned. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid[] IApplicationType.ContainerTypes
{
    get { return new Guid[] { Apis.Get&amp;lt;IGroups&amp;gt;().ContentTypeId }; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Lastly, the Get method should return an instance of the Application entity.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;IApplication IApplicationType.Get(Guid applicationId)
{
    return LinksData.GetApplication(applicationId);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinksApplicationType source:&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksApplicationType_2E00_cs"&gt;community.telligent.com/.../LinksApplicationType_2E00_cs&lt;/a&gt;&lt;/h3&gt;
&lt;h3&gt;&lt;a id="LinkItem_Content_Type" name="LinkItem_Content_Type"&gt;&lt;/a&gt;LinkItem Content Type&lt;/h3&gt;
&lt;p&gt;Again, the [[api-documentation:IPlugin Plugin Type|IPlugin]]&amp;nbsp;and [[api-documentation:ITranslatablePlugin Plugin Type|ITranslatablePlugin]] interfaces are discussed in other articles, we will skip the explanation of those implementations and focus on the IContentType&amp;nbsp;implementation.&lt;/p&gt;
&lt;p&gt;ContentTypeId&amp;nbsp;is the same id that was used when defining our IContent&amp;nbsp;entity. &amp;nbsp;ContentName&amp;nbsp;is the name of the content&amp;nbsp;that will be displayed in the community. &amp;nbsp;The example uses a translation so the content&amp;nbsp;name can be translated for each language the community supports. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid IContentType.ContentTypeId
{
    get { return ContentTypes.LinksItemId; }
}

string IContentType.ContentTypeName
{
    get { return _translations.GetLanguageResourceValue(&amp;quot;ContentTypeName&amp;quot;); }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The AttachChangeEvents method provides access to an [[api-documentation:IContentStateChanges Plugin Supplementary Type|IContentStateChanges]]&amp;nbsp;object. &amp;nbsp;This object is used by your content&amp;nbsp;type to inform the platform of changes to your content. &amp;nbsp;For instance, when you content&amp;nbsp;is deleted, informing the platform of the deletion allows the platform to&amp;nbsp;remove data associated with that content. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;void IContentType.AttachChangeEvents(IContentStateChanges stateChanges)
{
    _contentState = stateChanges;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The ApplicationTypes&amp;nbsp;property should return all the types of applications&amp;nbsp;that can hold this content. &amp;nbsp;In this case the only application&amp;nbsp;is our LinksApplication, so that Id is returned. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid[] IContentType.ApplicationTypes
{
    get { return new Guid[] { ContentTypes.LinksApplicationId }; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Finally the Get method should return an instance of the Content&amp;nbsp;entity.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;IContent IContentType.Get(Guid contentId)
{
    return LinksData.GetLink(contentId);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinkItemContentType entity source:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/1856_2E00_LinkItemContentType_2E00_cs"&gt;community.telligent.com/.../1856_2E00_LinkItemContentType_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The custom content and application plugins are now completed, but we can add some additional functionality to make this easier to use in a community site.&lt;/p&gt;
&lt;h3&gt;&lt;a id="Widget_Extensions" name="Widget_Extensions"&gt;&lt;/a&gt;Widget Extensions&lt;/h3&gt;
&lt;p&gt;As of now, we won&amp;#39;t be able to interact with our new application or content from a velocity widget, a couple custom [[api-documentation:IScriptedContentFragmentExtension Plugin Type|IScriptedContentFragmentExtension]]s can expose our data methods so they can be called from velocity. &amp;nbsp;We will add an extension that works with the LinksApplication called &lt;em&gt;telligent_v1_links&lt;/em&gt;&amp;nbsp;and an extension for the LinkItem methods called&amp;nbsp;&lt;em&gt;telligent_v1_linkitem.&amp;nbsp;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our extension will expose the LinksApplicationMethods class. &amp;nbsp;$telligent_v1_links.List() will return a list of all the links applications, while&amp;nbsp;telligent_v1_links.Get(Guid applicationId) will return a single links application.&lt;/p&gt;
&lt;p&gt;The source code for the &lt;em&gt;telligent_v1_links&lt;/em&gt;&amp;nbsp;extension:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksApplicationWidgetExtension_2E00_cs"&gt;community.telligent.com/.../LinksApplicationWidgetExtension_2E00_cs&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Similarly, we will use a&amp;nbsp;LinkItemMethods class to expose methods to List all LinkItems in a Link Application and another to Get a single LinkItem. &lt;em&gt;$telligent_v1_linkitem.List(Guid applicationId)&lt;/em&gt; will return the list, while &lt;em&gt;$telligent_v1_linkitem.Get(Guid contentId)&lt;/em&gt; will return a single instance of a LinkItem.&lt;/p&gt;
&lt;p&gt;The source code for the&amp;nbsp;&lt;em&gt;telligent_v1_linkitem &lt;/em&gt;extension:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinkItemWidgetExtension_2E00_cs"&gt;community.telligent.com/.../LinkItemWidgetExtension_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Plugin_Group" name="Plugin_Group"&gt;&lt;/a&gt;Plugin Group&lt;/h3&gt;
&lt;p&gt;We could deploy this as is, but you would need to search around the admin panel to enable each of the 4 different plugins, not to mention these plugins have dependencies on each other and should not be used independently of one another. &amp;nbsp;We can use a [[api-documentation:IPluginGroup Plugin Type|IPluginGroup]]&amp;nbsp;to create a single point to enable or disable all related plugins at the same time to care of both of these issues.&lt;/p&gt;
&lt;p&gt;Here is the completed source for our Plugin Group:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksPluginGroup_2E00_cs"&gt;community.telligent.com/.../LinksPluginGroup_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Example_Widget" name="Example_Widget"&gt;&lt;/a&gt;Example Widget&lt;/h3&gt;
&lt;p&gt;We can now deploy the dll containing our Links Application to the community and enable the Links Application Plugin group. &amp;nbsp;We can use a widget to test that our application is working and our content can use a core service, in this case the Like service.&lt;/p&gt;
&lt;p&gt;The widget will list all the Links Applications. &amp;nbsp;For each application it will list all the Link Items and those items will each display a Like button.&lt;/p&gt;
&lt;p&gt;The velocity code for that widget would look like:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="velocity"&gt;#set($linkapps = $telligent_v1_links.List())

#foreach ($linkapp in $linkapps)
#beforeall
    &amp;lt;ul class=&amp;quot;content-list simple&amp;quot;&amp;gt;
#each
        &amp;lt;li class=&amp;quot;content-item simple&amp;quot;&amp;gt;
            &amp;lt;h4 style=&amp;quot;margin-bottom: 5px;&amp;quot;&amp;gt;$linkapp.Name&amp;lt;/h4&amp;gt;
            &amp;lt;div class=&amp;quot;description&amp;quot; style=&amp;quot;margin: 5px 0;&amp;quot;&amp;gt;$linkapp.Description&amp;lt;/div&amp;gt;
            
            #set($links = $telligent_v1_linkitem.List($linkapp.ApplicationId))
            
            #foreach ($link in $links)
		    #beforeall
		    	&amp;lt;ul class=&amp;quot;links&amp;quot;&amp;gt;
		    #each
    				&amp;lt;li class=&amp;quot;link-item&amp;quot; style=&amp;quot;margin-bottom: 5px;&amp;quot;&amp;gt;
        				#if ($core_v2_user.IsRegistered($core_v2_user.Accessing.Id))
        					#set ($likeFormat = &amp;#39;{toggle} &amp;lt;span class=&amp;quot;count&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;{count}&amp;lt;/span&amp;gt;&amp;#39;)
        				#else
        					#set ($likeFormat = &amp;#39;&amp;lt;span class=&amp;quot;count&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;{count}&amp;lt;/span&amp;gt;&amp;#39;)
        				#end    				

    				    &amp;lt;a href=&amp;quot;$link.Url&amp;quot;&amp;gt;$link.Name&amp;lt;/a&amp;gt; - $core_v2_ui.Like($link.ContentId, $link.ContentTypeId, &amp;quot;%{ Format = $likeFormat, IncludeTip = &amp;#39;true&amp;#39; }&amp;quot;)

    				    &amp;lt;div class=&amp;quot;description&amp;quot;&amp;gt;$link.Description&amp;lt;/div&amp;gt;
    				&amp;lt;/li&amp;gt;
		    #afterall
                &amp;lt;/ul&amp;gt;		    
		    #end
        &amp;lt;/li&amp;gt;
#afterall
    &amp;lt;/ul&amp;gt;
#end&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Once the widget is added to a page you should see the following:&lt;/p&gt;
&lt;p&gt;&lt;a href="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/4466.png"&gt;&lt;img alt=" " src="/resized-image/__size/640x480/__key/communityserver-wikis-components-files/00-00-00-12-83/4466.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a id="Downloadable_Source" name="Downloadable_Source"&gt;&lt;/a&gt;Downloadable&amp;nbsp;Source&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/Samples.Links.zip"&gt;community.telligent.com/.../Samples.Links.zip&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now that we have a base level application and content type, we can begin to add support for core services to our application. &amp;nbsp;Additional articles discussing &lt;a href="/training/w/developer90/52445.adding-core-service-support-to-content"&gt;Adding Core Service Support to Content&lt;/a&gt;&amp;nbsp;are available.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;

&lt;div style="font-size: 90%;"&gt;Tags: IContentType, IApplicationType&lt;/div&gt;
</description></item><item><title>Creating Custom Applications and Content</title><link>https://community.telligent.com/community/11/w/developer-training/65100/creating-custom-applications-and-content/revision/2</link><pubDate>Wed, 05 Aug 2020 15:08:59 GMT</pubDate><guid isPermaLink="false">9c708778-1984-4d1c-9853-406bc41713cb</guid><dc:creator>Former Member</dc:creator><comments>https://community.telligent.com/community/11/w/developer-training/65100/creating-custom-applications-and-content#comments</comments><description>Revision 2 posted to Developer Training by Former Member on 08/05/2020 15:08:59&lt;br /&gt;
&lt;p&gt;The platform&amp;nbsp;provides the ability to create your own types of content and applications.&lt;/p&gt;
&lt;p&gt;[toc]&lt;/p&gt;
&lt;h2&gt;&lt;a id="Why_create_custom_applications_and_content" name="Why_create_custom_applications_and_content"&gt;&lt;/a&gt;Why create custom applications and content?&lt;/h2&gt;
&lt;p&gt;If you are writing a new&amp;nbsp;application&amp;nbsp;or&amp;nbsp;have content (internal or external) that you want to interact with Verint Community&amp;#39;s core services, creating a custom content and application type within the community can be beneficial. &amp;nbsp;Content Types within the community can interact with core services. &amp;nbsp;Likes, Ratings, Comments, Moderation, Mentions and Hashtags are some of the services your content will have access to once registered with the community.&lt;/p&gt;
&lt;p&gt;There is a deeper discussion of how content and applications fit in the community platform in &lt;a href="/training/w/developer90/52676.the-content-model"&gt;The Content Model&lt;/a&gt; article.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Content_and_Content_Types" name="Content_and_Content_Types"&gt;&lt;/a&gt;Content and Content Types&lt;/h2&gt;
&lt;p&gt;There are two interfaces that are provided in the platform to identify types of content and individual content entities. &amp;nbsp;The [[api-documentation:IContentType Plugin Type|IContentType]]&amp;nbsp;interface is used to identify types of content and the [[api-documentation:IContent Plugin Supplementary Type|IContent]]&amp;nbsp;interface is used to represent the individual content entities. &amp;nbsp;Both of these interfaces are found in the Telligent.Evolution.Core.dll.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Applications_and_Application_Types" name="Applications_and_Application_Types"&gt;&lt;/a&gt;Applications and Application Types&lt;/h2&gt;
&lt;p&gt;Similar to content, the platform provides the [[api-documentation:IApplicationType Plugin Type|IApplicationType]] to identify a type of application and [[api-documentation:IApplication Plugin Supplementary Type|IApplication]] to represent an individual application entity. &amp;nbsp;These interfaces are also found in the&amp;nbsp;Telligent.Evolution.Core.dll.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Creating_an_Application_and_Content" name="Creating_an_Application_and_Content"&gt;&lt;/a&gt;Creating an Application and Content&lt;/h2&gt;
&lt;p&gt;For our example application, we will create a Links Application. &amp;nbsp;The Links Application will be a collection of links to websites. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s outline our entities.&lt;/p&gt;
&lt;h3&gt;&lt;a id="LinksApplication_Entity" name="LinksApplication_Entity"&gt;&lt;/a&gt;LinksApplication Entity&lt;/h3&gt;
&lt;p&gt;Our LinksApplication Entity will implement the IApplication interface and represent an instance of a Links Application.&lt;/p&gt;
&lt;p&gt;ApplicationTypeId is a unique id that represents a type of application in the community, you define this value. In the example, we have a static class where we define our Id, so it can be referenced from&amp;nbsp;multiple locations. ApplicationId is the unique Id for an individual application in the community. &amp;nbsp;We will provide this to the community as well.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Guid ApplicationId { get; set; }

public Guid ApplicationTypeId
{
    get { return ContentTypes.LinksApplicationId; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The Name and Description fields are not required by the IApplication interface, but allow us to store a raw version of the there values. &amp;nbsp;The HtmlName and HtmlDescription methods are then used to provide the output depending on the target. &amp;nbsp;These allow the output to be tailored to those targets, for instance if your target was an email you may not want to display images inline in your content. &amp;nbsp;Our example data just uses text for Name and Descriptions, there is no need to tailor our output to different targets, instead we will just return the text for all targets.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public string Name { get; set; }
public string Description { get; set; }

public string HtmlName(string target)
{
    return Name;
}

public string HtmlDescription(string target)
{
    return Description;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;For this example we won&amp;#39;t allow disabling the application, so the IsEnabled property will always return true. &amp;nbsp;We wont store our applications in different groups, instead they will all be located in the Site Root group so we will always&amp;nbsp;return the Site&amp;nbsp;group for the Application&amp;#39;s Container. &amp;nbsp;Our application won&amp;#39;t have a url to view it or an avatar associated with it, both AvatarUrl and the Url will just return null.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public bool IsEnabled
{
    get { return true; }
}

public IContainer Container
{
    get { return Apis.Get&amp;lt;IGroups&amp;gt;().Root; }
}

string IApplication.AvatarUrl
{
    get { return null; }
}

string IApplication.Url
{
    get { return null; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinksApplication entity source:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksApplication_2E00_cs"&gt;community.telligent.com/.../LinksApplication_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="LinksItem_Entity" name="LinksItem_Entity"&gt;&lt;/a&gt;LinksItem Entity&lt;/h3&gt;
&lt;p&gt;Our LinkItem&amp;nbsp;Entity will implement the IContent interface and represent a single link item in the Links Application.&lt;/p&gt;
&lt;p&gt;ContentTypeId&amp;nbsp;is a unique id that represents a type of content&amp;nbsp;in the community, you define this value when creating your content type. &amp;nbsp;The example uses the same static class that defines the ApplicationTypeId to define this Id. &amp;nbsp;ContentId&amp;nbsp;is the unique Id for an individual content item&amp;nbsp;in the community. &amp;nbsp;We will provide this to the community as well.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Guid ContentId { get; set; }

public Guid ContentTypeId
{
    get { return ContentTypes.LinksItemId; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Each piece of Content is related to an application in the community, &amp;nbsp;we have defined a property to store the ApplicationId for our content&amp;#39;s application. &amp;nbsp;We use this value to return an instance of our application when we implement the Application property on the IContent interface.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Guid ApplicationId { get; set; }

public IApplication Application
{
    get { return LinksData.GetApplication(ApplicationId); }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The Name and Description fields are not required by the IContent&amp;nbsp;interface, but allow use to store a raw version of the there values. &amp;nbsp;The HtmlName and HtmlDescription methods are then used to provide the output depending on the target. &amp;nbsp;These allow the output to be tailored to those targets, for instance if your target was an email you may not want to display images inline in your content.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public string Name { get; set; }
public string Description { get; set; }

public string HtmlName(string target)
{
    return Name;
}

public string HtmlDescription(string target)
{
    return Description;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Each link item has a Url and the IContent interface requires a Url, so we will use that property to store the Url and satisfy the interface.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public string Url { get; set; }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The CreatedDate, IsEnabled, AvatarUrl and CreatedByUserId properties are required by the interface but will be static or are not needed in this example, so we will implement those, but they don&amp;#39;t provide any additional value. &amp;nbsp;If this were a fully functional example that implemented core services or other features of the platform these values would become important to populate correctly.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public DateTime CreatedDate { get; set; }

public bool IsEnabled
{
    get { return true; }
}

string IContent.AvatarUrl
{
    get { return null; }
}

int? IContent.CreatedByUserId
{
    get { return null; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinkItem&amp;nbsp;entity source:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinkItem_2E00_cs"&gt;community.telligent.com/.../LinkItem_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next we will define our Application and Content Types that make use of our entities&amp;nbsp;to register those with the platform.&lt;/p&gt;
&lt;h3&gt;&lt;a id="LinksApplication_Application_Type" name="LinksApplication_Application_Type"&gt;&lt;/a&gt;LinksApplication Application Type&lt;/h3&gt;
&lt;p&gt;The [[api-documentation:IPlugin Plugin Type|IPlugin]]&amp;nbsp;and [[api-documentation:ITranslatablePlugin Plugin Type|ITranslatablePlugin]] interfaces are discussed in other articles, we will skip the explanation of those implementations and focus on the IApplicationType implementation.&lt;/p&gt;
&lt;p&gt;ApplicationTypeId is the same id that was used when defining our IApplication entity. &amp;nbsp;ApplicationName is the name of the application that will be displayed in the community. &amp;nbsp;The example uses a translation so the application name can be translated for each language the community supports. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid IApplicationType.ApplicationTypeId
{
    get { return ContentTypes.LinksApplicationId; ; }
}

string IApplicationType.ApplicationTypeName
{
    get { return _translations.GetLanguageResourceValue(&amp;quot;ApplicationTypeName&amp;quot;); }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The AttachChangeEvents method provides access to an [[api-documentation:IApplicationStateChanges Plugin Supplementary Type|IApplicationStateChanges]]&amp;nbsp;object. &amp;nbsp;This object is used by your application type to inform the platform of changes to your application. &amp;nbsp;For instance, when you application is deleted, informing the platform of the deletion allows the platform to&amp;nbsp;remove data associated with that application. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;void IApplicationType.AttachChangeEvents(IApplicationStateChanges stateChanges)
{
    _applicationState = stateChanges;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The ContainerTypes property should return all the types of containers that can hold this application. &amp;nbsp;In this case the only container is groups, so that Id is returned. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid[] IApplicationType.ContainerTypes
{
    get { return new Guid[] { Apis.Get&amp;lt;IGroups&amp;gt;().ContentTypeId }; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Lastly, the Get method should return an instance of the Application entity.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;IApplication IApplicationType.Get(Guid applicationId)
{
    return LinksData.GetApplication(applicationId);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinksApplicationType source:&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksApplicationType_2E00_cs"&gt;community.telligent.com/.../LinksApplicationType_2E00_cs&lt;/a&gt;&lt;/h3&gt;
&lt;h3&gt;&lt;a id="LinkItem_Content_Type" name="LinkItem_Content_Type"&gt;&lt;/a&gt;LinkItem Content Type&lt;/h3&gt;
&lt;p&gt;Again, the [[api-documentation:IPlugin Plugin Type|IPlugin]]&amp;nbsp;and [[api-documentation:ITranslatablePlugin Plugin Type|ITranslatablePlugin]] interfaces are discussed in other articles, we will skip the explanation of those implementations and focus on the IContentType&amp;nbsp;implementation.&lt;/p&gt;
&lt;p&gt;ContentTypeId&amp;nbsp;is the same id that was used when defining our IContent&amp;nbsp;entity. &amp;nbsp;ContentName&amp;nbsp;is the name of the content&amp;nbsp;that will be displayed in the community. &amp;nbsp;The example uses a translation so the content&amp;nbsp;name can be translated for each language the community supports. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid IContentType.ContentTypeId
{
    get { return ContentTypes.LinksItemId; }
}

string IContentType.ContentTypeName
{
    get { return _translations.GetLanguageResourceValue(&amp;quot;ContentTypeName&amp;quot;); }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The AttachChangeEvents method provides access to an [[api-documentation:IContentStateChanges Plugin Supplementary Type|IContentStateChanges]]&amp;nbsp;object. &amp;nbsp;This object is used by your content&amp;nbsp;type to inform the platform of changes to your content. &amp;nbsp;For instance, when you content&amp;nbsp;is deleted, informing the platform of the deletion allows the platform to&amp;nbsp;remove data associated with that content. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;void IContentType.AttachChangeEvents(IContentStateChanges stateChanges)
{
    _contentState = stateChanges;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The ApplicationTypes&amp;nbsp;property should return all the types of applications&amp;nbsp;that can hold this content. &amp;nbsp;In this case the only application&amp;nbsp;is our LinksApplication, so that Id is returned. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid[] IContentType.ApplicationTypes
{
    get { return new Guid[] { ContentTypes.LinksApplicationId }; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Finally the Get method should return an instance of the Content&amp;nbsp;entity.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;IContent IContentType.Get(Guid contentId)
{
    return LinksData.GetLink(contentId);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinkItemContentType entity source:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/1856_2E00_LinkItemContentType_2E00_cs"&gt;community.telligent.com/.../1856_2E00_LinkItemContentType_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The custom content and application plugins are now completed, but we can add some additional functionality to make this easier to use in a community site.&lt;/p&gt;
&lt;h3&gt;&lt;a id="Widget_Extensions" name="Widget_Extensions"&gt;&lt;/a&gt;Widget Extensions&lt;/h3&gt;
&lt;p&gt;As of now, we won&amp;#39;t be able to interact with our new application or content from a velocity widget, a couple custom [[api-documentation:IScriptedContentFragmentExtension Plugin Type|IScriptedContentFragmentExtension]]s can expose our data methods so they can be called from velocity. &amp;nbsp;We will add an extension that works with the LinksApplication called &lt;em&gt;telligent_v1_links&lt;/em&gt;&amp;nbsp;and an extension for the LinkItem methods called&amp;nbsp;&lt;em&gt;telligent_v1_linkitem.&amp;nbsp;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our extension will expose the LinksApplicationMethods class. &amp;nbsp;$telligent_v1_links.List() will return a list of all the links applications, while&amp;nbsp;telligent_v1_links.Get(Guid applicationId) will return a single links application.&lt;/p&gt;
&lt;p&gt;The source code for the &lt;em&gt;telligent_v1_links&lt;/em&gt;&amp;nbsp;extension:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksApplicationWidgetExtension_2E00_cs"&gt;community.telligent.com/.../LinksApplicationWidgetExtension_2E00_cs&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Similarly, we will use a&amp;nbsp;LinkItemMethods class to expose methods to List all LinkItems in a Link Application and another to Get a single LinkItem. &lt;em&gt;$telligent_v1_linkitem.List(Guid applicationId)&lt;/em&gt; will return the list, while &lt;em&gt;$telligent_v1_linkitem.Get(Guid contentId)&lt;/em&gt; will return a single instance of a LinkItem.&lt;/p&gt;
&lt;p&gt;The source code for the&amp;nbsp;&lt;em&gt;telligent_v1_linkitem &lt;/em&gt;extension:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinkItemWidgetExtension_2E00_cs"&gt;community.telligent.com/.../LinkItemWidgetExtension_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Plugin_Group" name="Plugin_Group"&gt;&lt;/a&gt;Plugin Group&lt;/h3&gt;
&lt;p&gt;We could deploy this as is, but you would need to search around the admin panel to enable each of the 4 different plugins, not to mention these plugins have dependencies on each other and should not be used independently of one another. &amp;nbsp;We can use a [[api-documentation:IPluginGroup Plugin Type|IPluginGroup]]&amp;nbsp;to create a single point to enable or disable all related plugins at the same time to care of both of these issues.&lt;/p&gt;
&lt;p&gt;Here is the completed source for our Plugin Group:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksPluginGroup_2E00_cs"&gt;community.telligent.com/.../LinksPluginGroup_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Example_Widget" name="Example_Widget"&gt;&lt;/a&gt;Example Widget&lt;/h3&gt;
&lt;p&gt;We can now deploy the dll containing our Links Application to the community and enable the Links Application Plugin group. &amp;nbsp;We can use a widget to test that our application is working and our content can use a core service, in this case the Like service.&lt;/p&gt;
&lt;p&gt;The widget will list all the Links Applications. &amp;nbsp;For each application it will list all the Link Items and those items will each display a Like button.&lt;/p&gt;
&lt;p&gt;The velocity code for that widget would look like:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="velocity"&gt;#set($linkapps = $telligent_v1_links.List())

#foreach ($linkapp in $linkapps)
#beforeall
    &amp;lt;ul class=&amp;quot;content-list simple&amp;quot;&amp;gt;
#each
        &amp;lt;li class=&amp;quot;content-item simple&amp;quot;&amp;gt;
            &amp;lt;h4 style=&amp;quot;margin-bottom: 5px;&amp;quot;&amp;gt;$linkapp.Name&amp;lt;/h4&amp;gt;
            &amp;lt;div class=&amp;quot;description&amp;quot; style=&amp;quot;margin: 5px 0;&amp;quot;&amp;gt;$linkapp.Description&amp;lt;/div&amp;gt;
            
            #set($links = $telligent_v1_linkitem.List($linkapp.ApplicationId))
            
            #foreach ($link in $links)
		    #beforeall
		    	&amp;lt;ul class=&amp;quot;links&amp;quot;&amp;gt;
		    #each
    				&amp;lt;li class=&amp;quot;link-item&amp;quot; style=&amp;quot;margin-bottom: 5px;&amp;quot;&amp;gt;
        				#if ($core_v2_user.IsRegistered($core_v2_user.Accessing.Id))
        					#set ($likeFormat = &amp;#39;{toggle} &amp;lt;span class=&amp;quot;count&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;{count}&amp;lt;/span&amp;gt;&amp;#39;)
        				#else
        					#set ($likeFormat = &amp;#39;&amp;lt;span class=&amp;quot;count&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;{count}&amp;lt;/span&amp;gt;&amp;#39;)
        				#end    				

    				    &amp;lt;a href=&amp;quot;$link.Url&amp;quot;&amp;gt;$link.Name&amp;lt;/a&amp;gt; - $core_v2_ui.Like($link.ContentId, $link.ContentTypeId, &amp;quot;%{ Format = $likeFormat, IncludeTip = &amp;#39;true&amp;#39; }&amp;quot;)

    				    &amp;lt;div class=&amp;quot;description&amp;quot;&amp;gt;$link.Description&amp;lt;/div&amp;gt;
    				&amp;lt;/li&amp;gt;
		    #afterall
                &amp;lt;/ul&amp;gt;		    
		    #end
        &amp;lt;/li&amp;gt;
#afterall
    &amp;lt;/ul&amp;gt;
#end&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Once the widget is added to a page you should see the following:&lt;/p&gt;
&lt;p&gt;&lt;a href="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/4466.png"&gt;&lt;img alt=" " src="/resized-image/__size/640x480/__key/communityserver-wikis-components-files/00-00-00-12-83/4466.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a id="Downloadable_Source" name="Downloadable_Source"&gt;&lt;/a&gt;Downloadable&amp;nbsp;Source&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/Samples.Links.zip"&gt;community.telligent.com/.../Samples.Links.zip&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now that we have a base level application and content type, we can begin to add support for core services to our application. &amp;nbsp;Additional articles discussing &lt;a href="/training/w/developer90/52445.adding-core-service-support-to-content"&gt;Adding Core Service Support to Content&lt;/a&gt;&amp;nbsp;are available.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;

&lt;div style="font-size: 90%;"&gt;Tags: IContentType, IApplicationType&lt;/div&gt;
</description></item><item><title>Creating Custom Applications and Content</title><link>https://community.telligent.com/community/11/w/developer-training/65100/creating-custom-applications-and-content/revision/1</link><pubDate>Thu, 13 Jun 2019 19:28:28 GMT</pubDate><guid isPermaLink="false">9c708778-1984-4d1c-9853-406bc41713cb</guid><dc:creator>Ben Tiedt</dc:creator><comments>https://community.telligent.com/community/11/w/developer-training/65100/creating-custom-applications-and-content#comments</comments><description>Revision 1 posted to Developer Training by Ben Tiedt on 06/13/2019 19:28:28&lt;br /&gt;
&lt;p&gt;The platform&amp;nbsp;provides the ability to create your own types of content and applications.&lt;/p&gt;
&lt;p&gt;[toc]&lt;/p&gt;
&lt;h2&gt;&lt;a id="Why_create_custom_applications_and_content" name="Why_create_custom_applications_and_content"&gt;&lt;/a&gt;Why create custom applications and content?&lt;/h2&gt;
&lt;p&gt;If you are writing a new&amp;nbsp;application&amp;nbsp;or&amp;nbsp;have content (internal or external) that you want to interact with Telligent Community&amp;#39;s core services, creating a custom content and application type within the community can be beneficial. &amp;nbsp;Content Types within the community can interact with core services. &amp;nbsp;Likes, Ratings, Comments, Moderation, Mentions and Hashtags are some of the services your content will have access to once registered with the community.&lt;/p&gt;
&lt;p&gt;There is a deeper discussion of how content and applications fit in the community platform in &lt;a href="/training/w/developer90/52676.the-content-model"&gt;The Content Model&lt;/a&gt; article.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Content_and_Content_Types" name="Content_and_Content_Types"&gt;&lt;/a&gt;Content and Content Types&lt;/h2&gt;
&lt;p&gt;There are two interfaces that are provided in the platform to identify types of content and individual content entities. &amp;nbsp;The [[api-documentation:IContentType Plugin Type|IContentType]]&amp;nbsp;interface is used to identify types of content and the [[api-documentation:IContent Plugin Supplementary Type|IContent]]&amp;nbsp;interface is used to represent the individual content entities. &amp;nbsp;Both of these interfaces are found in the Telligent.Evolution.Core.dll.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Applications_and_Application_Types" name="Applications_and_Application_Types"&gt;&lt;/a&gt;Applications and Application Types&lt;/h2&gt;
&lt;p&gt;Similar to content, the platform provides the [[api-documentation:IApplicationType Plugin Type|IApplicationType]] to identify a type of application and [[api-documentation:IApplication Plugin Supplementary Type|IApplication]] to represent an individual application entity. &amp;nbsp;These interfaces are also found in the&amp;nbsp;Telligent.Evolution.Core.dll.&lt;/p&gt;
&lt;h2&gt;&lt;a id="Creating_an_Application_and_Content" name="Creating_an_Application_and_Content"&gt;&lt;/a&gt;Creating an Application and Content&lt;/h2&gt;
&lt;p&gt;For our example application, we will create a Links Application. &amp;nbsp;The Links Application will be a collection of links to websites. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s outline our entities.&lt;/p&gt;
&lt;h3&gt;&lt;a id="LinksApplication_Entity" name="LinksApplication_Entity"&gt;&lt;/a&gt;LinksApplication Entity&lt;/h3&gt;
&lt;p&gt;Our LinksApplication Entity will implement the IApplication interface and represent an instance of a Links Application.&lt;/p&gt;
&lt;p&gt;ApplicationTypeId is a unique id that represents a type of application in the community, you define this value. In the example, we have a static class where we define our Id, so it can be referenced from&amp;nbsp;multiple locations. ApplicationId is the unique Id for an individual application in the community. &amp;nbsp;We will provide this to the community as well.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Guid ApplicationId { get; set; }

public Guid ApplicationTypeId
{
    get { return ContentTypes.LinksApplicationId; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The Name and Description fields are not required by the IApplication interface, but allow us to store a raw version of the there values. &amp;nbsp;The HtmlName and HtmlDescription methods are then used to provide the output depending on the target. &amp;nbsp;These allow the output to be tailored to those targets, for instance if your target was an email you may not want to display images inline in your content. &amp;nbsp;Our example data just uses text for Name and Descriptions, there is no need to tailor our output to different targets, instead we will just return the text for all targets.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public string Name { get; set; }
public string Description { get; set; }

public string HtmlName(string target)
{
    return Name;
}

public string HtmlDescription(string target)
{
    return Description;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;For this example we won&amp;#39;t allow disabling the application, so the IsEnabled property will always return true. &amp;nbsp;We wont store our applications in different groups, instead they will all be located in the Site Root group so we will always&amp;nbsp;return the Site&amp;nbsp;group for the Application&amp;#39;s Container. &amp;nbsp;Our application won&amp;#39;t have a url to view it or an avatar associated with it, both AvatarUrl and the Url will just return null.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public bool IsEnabled
{
    get { return true; }
}

public IContainer Container
{
    get { return Apis.Get&amp;lt;IGroups&amp;gt;().Root; }
}

string IApplication.AvatarUrl
{
    get { return null; }
}

string IApplication.Url
{
    get { return null; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinksApplication entity source:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksApplication_2E00_cs"&gt;community.telligent.com/.../LinksApplication_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="LinksItem_Entity" name="LinksItem_Entity"&gt;&lt;/a&gt;LinksItem Entity&lt;/h3&gt;
&lt;p&gt;Our LinkItem&amp;nbsp;Entity will implement the IContent interface and represent a single link item in the Links Application.&lt;/p&gt;
&lt;p&gt;ContentTypeId&amp;nbsp;is a unique id that represents a type of content&amp;nbsp;in the community, you define this value when creating your content type. &amp;nbsp;The example uses the same static class that defines the ApplicationTypeId to define this Id. &amp;nbsp;ContentId&amp;nbsp;is the unique Id for an individual content item&amp;nbsp;in the community. &amp;nbsp;We will provide this to the community as well.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Guid ContentId { get; set; }

public Guid ContentTypeId
{
    get { return ContentTypes.LinksItemId; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Each piece of Content is related to an application in the community, &amp;nbsp;we have defined a property to store the ApplicationId for our content&amp;#39;s application. &amp;nbsp;We use this value to return an instance of our application when we implement the Application property on the IContent interface.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public Guid ApplicationId { get; set; }

public IApplication Application
{
    get { return LinksData.GetApplication(ApplicationId); }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The Name and Description fields are not required by the IContent&amp;nbsp;interface, but allow use to store a raw version of the there values. &amp;nbsp;The HtmlName and HtmlDescription methods are then used to provide the output depending on the target. &amp;nbsp;These allow the output to be tailored to those targets, for instance if your target was an email you may not want to display images inline in your content.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public string Name { get; set; }
public string Description { get; set; }

public string HtmlName(string target)
{
    return Name;
}

public string HtmlDescription(string target)
{
    return Description;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Each link item has a Url and the IContent interface requires a Url, so we will use that property to store the Url and satisfy the interface.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public string Url { get; set; }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The CreatedDate, IsEnabled, AvatarUrl and CreatedByUserId properties are required by the interface but will be static or are not needed in this example, so we will implement those, but they don&amp;#39;t provide any additional value. &amp;nbsp;If this were a fully functional example that implemented core services or other features of the platform these values would become important to populate correctly.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;public DateTime CreatedDate { get; set; }

public bool IsEnabled
{
    get { return true; }
}

string IContent.AvatarUrl
{
    get { return null; }
}

int? IContent.CreatedByUserId
{
    get { return null; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinkItem&amp;nbsp;entity source:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinkItem_2E00_cs"&gt;community.telligent.com/.../LinkItem_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next we will define our Application and Content Types that make use of our entities&amp;nbsp;to register those with the platform.&lt;/p&gt;
&lt;h3&gt;&lt;a id="LinksApplication_Application_Type" name="LinksApplication_Application_Type"&gt;&lt;/a&gt;LinksApplication Application Type&lt;/h3&gt;
&lt;p&gt;The [[api-documentation:IPlugin Plugin Type|IPlugin]]&amp;nbsp;and [[api-documentation:ITranslatablePlugin Plugin Type|ITranslatablePlugin]] interfaces are discussed in other articles, we will skip the explanation of those implementations and focus on the IApplicationType implementation.&lt;/p&gt;
&lt;p&gt;ApplicationTypeId is the same id that was used when defining our IApplication entity. &amp;nbsp;ApplicationName is the name of the application that will be displayed in the community. &amp;nbsp;The example uses a translation so the application name can be translated for each language the community supports. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid IApplicationType.ApplicationTypeId
{
    get { return ContentTypes.LinksApplicationId; ; }
}

string IApplicationType.ApplicationTypeName
{
    get { return _translations.GetLanguageResourceValue(&amp;quot;ApplicationTypeName&amp;quot;); }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The AttachChangeEvents method provides access to an [[api-documentation:IApplicationStateChanges Plugin Supplementary Type|IApplicationStateChanges]]&amp;nbsp;object. &amp;nbsp;This object is used by your application type to inform the platform of changes to your application. &amp;nbsp;For instance, when you application is deleted, informing the platform of the deletion allows the platform to&amp;nbsp;remove data associated with that application. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;void IApplicationType.AttachChangeEvents(IApplicationStateChanges stateChanges)
{
    _applicationState = stateChanges;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The ContainerTypes property should return all the types of containers that can hold this application. &amp;nbsp;In this case the only container is groups, so that Id is returned. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid[] IApplicationType.ContainerTypes
{
    get { return new Guid[] { Apis.Get&amp;lt;IGroups&amp;gt;().ContentTypeId }; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Lastly, the Get method should return an instance of the Application entity.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;IApplication IApplicationType.Get(Guid applicationId)
{
    return LinksData.GetApplication(applicationId);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinksApplicationType source:&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksApplicationType_2E00_cs"&gt;community.telligent.com/.../LinksApplicationType_2E00_cs&lt;/a&gt;&lt;/h3&gt;
&lt;h3&gt;&lt;a id="LinkItem_Content_Type" name="LinkItem_Content_Type"&gt;&lt;/a&gt;LinkItem Content Type&lt;/h3&gt;
&lt;p&gt;Again, the [[api-documentation:IPlugin Plugin Type|IPlugin]]&amp;nbsp;and [[api-documentation:ITranslatablePlugin Plugin Type|ITranslatablePlugin]] interfaces are discussed in other articles, we will skip the explanation of those implementations and focus on the IContentType&amp;nbsp;implementation.&lt;/p&gt;
&lt;p&gt;ContentTypeId&amp;nbsp;is the same id that was used when defining our IContent&amp;nbsp;entity. &amp;nbsp;ContentName&amp;nbsp;is the name of the content&amp;nbsp;that will be displayed in the community. &amp;nbsp;The example uses a translation so the content&amp;nbsp;name can be translated for each language the community supports. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid IContentType.ContentTypeId
{
    get { return ContentTypes.LinksItemId; }
}

string IContentType.ContentTypeName
{
    get { return _translations.GetLanguageResourceValue(&amp;quot;ContentTypeName&amp;quot;); }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The AttachChangeEvents method provides access to an [[api-documentation:IContentStateChanges Plugin Supplementary Type|IContentStateChanges]]&amp;nbsp;object. &amp;nbsp;This object is used by your content&amp;nbsp;type to inform the platform of changes to your content. &amp;nbsp;For instance, when you content&amp;nbsp;is deleted, informing the platform of the deletion allows the platform to&amp;nbsp;remove data associated with that content. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;void IContentType.AttachChangeEvents(IContentStateChanges stateChanges)
{
    _contentState = stateChanges;
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The ApplicationTypes&amp;nbsp;property should return all the types of applications&amp;nbsp;that can hold this content. &amp;nbsp;In this case the only application&amp;nbsp;is our LinksApplication, so that Id is returned. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;Guid[] IContentType.ApplicationTypes
{
    get { return new Guid[] { ContentTypes.LinksApplicationId }; }
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Finally the Get method should return an instance of the Content&amp;nbsp;entity.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="csharp"&gt;IContent IContentType.Get(Guid contentId)
{
    return LinksData.GetLink(contentId);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the completed LinkItemContentType entity source:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/1856_2E00_LinkItemContentType_2E00_cs"&gt;community.telligent.com/.../1856_2E00_LinkItemContentType_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The custom content and application plugins are now completed, but we can add some additional functionality to make this easier to use in a community site.&lt;/p&gt;
&lt;h3&gt;&lt;a id="Widget_Extensions" name="Widget_Extensions"&gt;&lt;/a&gt;Widget Extensions&lt;/h3&gt;
&lt;p&gt;As of now, we won&amp;#39;t be able to interact with our new application or content from a velocity widget, a couple custom [[api-documentation:IScriptedContentFragmentExtension Plugin Type|IScriptedContentFragmentExtension]]s can expose our data methods so they can be called from velocity. &amp;nbsp;We will add an extension that works with the LinksApplication called &lt;em&gt;telligent_v1_links&lt;/em&gt;&amp;nbsp;and an extension for the LinkItem methods called&amp;nbsp;&lt;em&gt;telligent_v1_linkitem.&amp;nbsp;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our extension will expose the LinksApplicationMethods class. &amp;nbsp;$telligent_v1_links.List() will return a list of all the links applications, while&amp;nbsp;telligent_v1_links.Get(Guid applicationId) will return a single links application.&lt;/p&gt;
&lt;p&gt;The source code for the &lt;em&gt;telligent_v1_links&lt;/em&gt;&amp;nbsp;extension:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksApplicationWidgetExtension_2E00_cs"&gt;community.telligent.com/.../LinksApplicationWidgetExtension_2E00_cs&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Similarly, we will use a&amp;nbsp;LinkItemMethods class to expose methods to List all LinkItems in a Link Application and another to Get a single LinkItem. &lt;em&gt;$telligent_v1_linkitem.List(Guid applicationId)&lt;/em&gt; will return the list, while &lt;em&gt;$telligent_v1_linkitem.Get(Guid contentId)&lt;/em&gt; will return a single instance of a LinkItem.&lt;/p&gt;
&lt;p&gt;The source code for the&amp;nbsp;&lt;em&gt;telligent_v1_linkitem &lt;/em&gt;extension:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinkItemWidgetExtension_2E00_cs"&gt;community.telligent.com/.../LinkItemWidgetExtension_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Plugin_Group" name="Plugin_Group"&gt;&lt;/a&gt;Plugin Group&lt;/h3&gt;
&lt;p&gt;We could deploy this as is, but you would need to search around the admin panel to enable each of the 4 different plugins, not to mention these plugins have dependencies on each other and should not be used independently of one another. &amp;nbsp;We can use a [[api-documentation:IPluginGroup Plugin Type|IPluginGroup]]&amp;nbsp;to create a single point to enable or disable all related plugins at the same time to care of both of these issues.&lt;/p&gt;
&lt;p&gt;Here is the completed source for our Plugin Group:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/LinksPluginGroup_2E00_cs"&gt;community.telligent.com/.../LinksPluginGroup_2E00_cs&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a id="Example_Widget" name="Example_Widget"&gt;&lt;/a&gt;Example Widget&lt;/h3&gt;
&lt;p&gt;We can now deploy the dll containing our Links Application to the community and enable the Links Application Plugin group. &amp;nbsp;We can use a widget to test that our application is working and our content can use a core service, in this case the Like service.&lt;/p&gt;
&lt;p&gt;The widget will list all the Links Applications. &amp;nbsp;For each application it will list all the Link Items and those items will each display a Like button.&lt;/p&gt;
&lt;p&gt;The velocity code for that widget would look like:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="velocity"&gt;#set($linkapps = $telligent_v1_links.List())

#foreach ($linkapp in $linkapps)
#beforeall
    &amp;lt;ul class=&amp;quot;content-list simple&amp;quot;&amp;gt;
#each
        &amp;lt;li class=&amp;quot;content-item simple&amp;quot;&amp;gt;
            &amp;lt;h4 style=&amp;quot;margin-bottom: 5px;&amp;quot;&amp;gt;$linkapp.Name&amp;lt;/h4&amp;gt;
            &amp;lt;div class=&amp;quot;description&amp;quot; style=&amp;quot;margin: 5px 0;&amp;quot;&amp;gt;$linkapp.Description&amp;lt;/div&amp;gt;
            
            #set($links = $telligent_v1_linkitem.List($linkapp.ApplicationId))
            
            #foreach ($link in $links)
		    #beforeall
		    	&amp;lt;ul class=&amp;quot;links&amp;quot;&amp;gt;
		    #each
    				&amp;lt;li class=&amp;quot;link-item&amp;quot; style=&amp;quot;margin-bottom: 5px;&amp;quot;&amp;gt;
        				#if ($core_v2_user.IsRegistered($core_v2_user.Accessing.Id))
        					#set ($likeFormat = &amp;#39;{toggle} &amp;lt;span class=&amp;quot;count&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;{count}&amp;lt;/span&amp;gt;&amp;#39;)
        				#else
        					#set ($likeFormat = &amp;#39;&amp;lt;span class=&amp;quot;count&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;{count}&amp;lt;/span&amp;gt;&amp;#39;)
        				#end    				

    				    &amp;lt;a href=&amp;quot;$link.Url&amp;quot;&amp;gt;$link.Name&amp;lt;/a&amp;gt; - $core_v2_ui.Like($link.ContentId, $link.ContentTypeId, &amp;quot;%{ Format = $likeFormat, IncludeTip = &amp;#39;true&amp;#39; }&amp;quot;)

    				    &amp;lt;div class=&amp;quot;description&amp;quot;&amp;gt;$link.Description&amp;lt;/div&amp;gt;
    				&amp;lt;/li&amp;gt;
		    #afterall
                &amp;lt;/ul&amp;gt;		    
		    #end
        &amp;lt;/li&amp;gt;
#afterall
    &amp;lt;/ul&amp;gt;
#end&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Once the widget is added to a page you should see the following:&lt;/p&gt;
&lt;p&gt;&lt;a href="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/4466.png"&gt;&lt;img src="/resized-image/__size/640x480/__key/communityserver-wikis-components-files/00-00-00-12-83/4466.png" alt=" " /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a id="Downloadable_Source" name="Downloadable_Source"&gt;&lt;/a&gt;Downloadable&amp;nbsp;Source&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://community.telligent.com/cfs-file/__key/communityserver-wikis-components-files/00-00-00-12-83/Samples.Links.zip"&gt;community.telligent.com/.../Samples.Links.zip&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now that we have a base level application and content type, we can begin to add support for core services to our application. &amp;nbsp;Additional articles discussing &lt;a href="/training/w/developer90/52445.adding-core-service-support-to-content"&gt;Adding Core Service Support to Content&lt;/a&gt;&amp;nbsp;are available.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;

&lt;div style="font-size: 90%;"&gt;Tags: IContentType, IApplicationType&lt;/div&gt;
</description></item></channel></rss>