71 lines
3.5 KiB
C#
71 lines
3.5 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq.Expressions;
|
|||
|
|
|
|||
|
|
namespace Umbraco.Core.Models.PublishedContent
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// Implements a strongly typed content model factory
|
|||
|
|
/// </summary>
|
|||
|
|
internal class PublishedContentModelFactoryImpl : IPublishedContentModelFactory
|
|||
|
|
{
|
|||
|
|
//private readonly Dictionary<string, ConstructorInfo> _constructors
|
|||
|
|
// = new Dictionary<string, ConstructorInfo>();
|
|||
|
|
|
|||
|
|
private readonly Dictionary<string, Func<IPublishedContent, IPublishedContent>> _constructors
|
|||
|
|
= new Dictionary<string, Func<IPublishedContent, IPublishedContent>>();
|
|||
|
|
|
|||
|
|
public PublishedContentModelFactoryImpl()
|
|||
|
|
{
|
|||
|
|
var types = PluginManager.Current.ResolveTypes<PublishedContentModel>();
|
|||
|
|
var ctorArgTypes = new[] { typeof(IPublishedContent) };
|
|||
|
|
|
|||
|
|
foreach (var type in types)
|
|||
|
|
{
|
|||
|
|
if (type.Inherits<PublishedContentModel>() == false)
|
|||
|
|
throw new InvalidOperationException(string.Format("Type {0} is marked with PublishedContentModel attribute but does not inherit from PublishedContentExtended.", type.FullName));
|
|||
|
|
var constructor = type.GetConstructor(ctorArgTypes);
|
|||
|
|
if (constructor == null)
|
|||
|
|
throw new InvalidOperationException(string.Format("Type {0} is missing a public constructor with one argument of type IPublishedContent.", type.FullName));
|
|||
|
|
var attribute = type.GetCustomAttribute<PublishedContentModelAttribute>(false);
|
|||
|
|
var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias;
|
|||
|
|
typeName = typeName.ToLowerInvariant();
|
|||
|
|
|
|||
|
|
if (_constructors.ContainsKey(typeName))
|
|||
|
|
throw new InvalidOperationException(string.Format("More that one type want to be a model for content type {0}.", typeName));
|
|||
|
|
|
|||
|
|
// should work everywhere, potentially slow?
|
|||
|
|
//_constructors[typeName] = constructor;
|
|||
|
|
|
|||
|
|
// note: would it be even faster with a dynamic method?
|
|||
|
|
// here http://stackoverflow.com/questions/16363838/how-do-you-call-a-constructor-via-an-expression-tree-on-an-existing-object
|
|||
|
|
// but MediumTrust issue?
|
|||
|
|
|
|||
|
|
// fixme - must make sure that works in medium trust
|
|||
|
|
// read http://boxbinary.com/2011/10/how-to-run-a-unit-test-in-medium-trust-with-nunitpart-three-umbraco-framework-testing/
|
|||
|
|
var exprArg = Expression.Parameter(typeof(IPublishedContent), "content");
|
|||
|
|
var exprNew = Expression.New(constructor, exprArg);
|
|||
|
|
var expr = Expression.Lambda<Func<IPublishedContent, IPublishedContent>>(exprNew, exprArg);
|
|||
|
|
var func = expr.Compile();
|
|||
|
|
_constructors[typeName] = func;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public IPublishedContent CreateModel(IPublishedContent content)
|
|||
|
|
{
|
|||
|
|
// be case-insensitive
|
|||
|
|
var contentTypeAlias = content.DocumentTypeAlias.ToLowerInvariant();
|
|||
|
|
|
|||
|
|
//ConstructorInfo constructor;
|
|||
|
|
//return _constructors.TryGetValue(contentTypeAlias, out constructor)
|
|||
|
|
// ? (IPublishedContent) constructor.Invoke(new object[] { content })
|
|||
|
|
// : content;
|
|||
|
|
|
|||
|
|
Func<IPublishedContent, IPublishedContent> constructor;
|
|||
|
|
return _constructors.TryGetValue(contentTypeAlias, out constructor)
|
|||
|
|
? constructor(content)
|
|||
|
|
: content;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|