Web.Mvc - Refactor UmbracoViewPage, UmbracoTemplatePage, support strongly-typed content
Conflicts: src/Umbraco.Web/Umbraco.Web.csproj
This commit is contained in:
435
src/Umbraco.Tests/Mvc/UmbracoViewPageTests.cs
Normal file
435
src/Umbraco.Tests/Mvc/UmbracoViewPageTests.cs
Normal file
@@ -0,0 +1,435 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using System.Xml;
|
||||
using NUnit.Framework;
|
||||
using umbraco.BusinessLogic;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Tests.PublishedContent;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Stubs;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.PublishedCache.XmlPublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Mvc
|
||||
{
|
||||
[TestFixture]
|
||||
public class UmbracoViewPageTests
|
||||
{
|
||||
#region RenderModel To ...
|
||||
|
||||
[Test]
|
||||
public void RenderModel_To_RenderModel()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel(content, CultureInfo.InvariantCulture);
|
||||
var view = new RenderModelTestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.AreSame(model, view.Model);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModel_ContentType1_To_ContentType1()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel(content, CultureInfo.InvariantCulture);
|
||||
var view = new ContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModel_ContentType2_To_ContentType1()
|
||||
{
|
||||
var content = new ContentType2(null);
|
||||
var model = new RenderModel(content, CultureInfo.InvariantCulture);
|
||||
var view = new ContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModel_ContentType1_To_ContentType2()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel(content, CultureInfo.InvariantCulture);
|
||||
var view = new ContentType2TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => view.SetViewDataX(viewData));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModel_ContentType1_To_RenderModelOf_ContentType1()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel(content, CultureInfo.InvariantCulture);
|
||||
var view = new RenderModelOfContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<RenderModel<ContentType1>>(view.Model);
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModel_ContentType2_To_RenderModelOf_ContentType1()
|
||||
{
|
||||
var content = new ContentType2(null);
|
||||
var model = new RenderModel(content, CultureInfo.InvariantCulture);
|
||||
var view = new RenderModelOfContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<RenderModel<ContentType1>>(view.Model);
|
||||
Assert.IsInstanceOf<ContentType2>(view.Model.Content);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModel_ContentType1_To_RenderModelOf_ContentType2()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel(content, CultureInfo.InvariantCulture);
|
||||
var view = new RenderModelOfContentType2TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
|
||||
Assert.Throws<InvalidCastException>(() => view.SetViewDataX(viewData));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RenderModelOf To ...
|
||||
|
||||
[Test]
|
||||
public void RenderModelOf_ContentType1_To_RenderModel()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel<ContentType1>(content, CultureInfo.InvariantCulture);
|
||||
var view = new RenderModelTestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.AreSame(model, view.Model);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModelOf_ContentType1_To_ContentType1()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel<ContentType1>(content, CultureInfo.InvariantCulture);
|
||||
var view = new ContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModelOf_ContentType2_To_ContentType1()
|
||||
{
|
||||
var content = new ContentType2(null);
|
||||
var model = new RenderModel<ContentType2>(content, CultureInfo.InvariantCulture);
|
||||
var view = new ContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModelOf_ContentType1_To_ContentType2()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel<ContentType1>(content, CultureInfo.InvariantCulture);
|
||||
var view = new ContentType2TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
Assert.Throws<InvalidCastException>(() => view.SetViewDataX(viewData));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType1()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel<ContentType1>(content, CultureInfo.InvariantCulture);
|
||||
var view = new RenderModelOfContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<RenderModel<ContentType1>>(view.Model);
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModelOf_ContentType2_To_RenderModelOf_ContentType1()
|
||||
{
|
||||
var content = new ContentType2(null);
|
||||
var model = new RenderModel<ContentType2>(content, CultureInfo.InvariantCulture);
|
||||
var view = new RenderModelOfContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<RenderModel<ContentType1>>(view.Model);
|
||||
Assert.IsInstanceOf<ContentType2>(view.Model.Content);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType2()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var model = new RenderModel<ContentType1>(content, CultureInfo.InvariantCulture);
|
||||
var view = new RenderModelOfContentType2TestPage();
|
||||
var viewData = new ViewDataDictionary(model);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
Assert.Throws<InvalidCastException>(() => view.SetViewDataX(viewData));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ContentType To ...
|
||||
|
||||
[Test]
|
||||
public void ContentType1_To_RenderModel()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var view = new RenderModelTestPage();
|
||||
var viewData = new ViewDataDictionary(content);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<RenderModel>(view.Model);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContentType1_To_RenderModelOf_ContentType1()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var view = new RenderModelOfContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(content);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<RenderModel<ContentType1>>(view.Model);
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContentType2_To_RenderModelOf_ContentType1()
|
||||
{
|
||||
var content = new ContentType2(null);
|
||||
var view = new RenderModelOfContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(content);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<RenderModel<ContentType1>>(view.Model);
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContentType1_To_RenderModelOf_ContentType2()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var view = new RenderModelOfContentType2TestPage();
|
||||
var viewData = new ViewDataDictionary(content);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
Assert.Throws<InvalidCastException>(() =>view.SetViewDataX(viewData));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContentType1_To_ContentType1()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var view = new ContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(content);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContentType1_To_ContentType2()
|
||||
{
|
||||
var content = new ContentType1(null);
|
||||
var view = new ContentType2TestPage();
|
||||
var viewData = new ViewDataDictionary(content);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
Assert.Throws<InvalidCastException>(() => view.SetViewDataX(viewData));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContentType2_To_ContentType1()
|
||||
{
|
||||
var content = new ContentType2(null);
|
||||
var view = new ContentType1TestPage();
|
||||
var viewData = new ViewDataDictionary(content);
|
||||
|
||||
view.ViewContext = GetViewContext();
|
||||
view.SetViewDataX(viewData);
|
||||
|
||||
Assert.IsInstanceOf<ContentType1>(view.Model);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Test elements
|
||||
|
||||
public class TestPage<TModel> : UmbracoViewPage<TModel>
|
||||
{
|
||||
public override void Execute()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetViewDataX(ViewDataDictionary viewData)
|
||||
{
|
||||
SetViewData(viewData);
|
||||
}
|
||||
}
|
||||
|
||||
public class RenderModelTestPage : TestPage<RenderModel>
|
||||
{ }
|
||||
|
||||
public class RenderModelOfContentType1TestPage : TestPage<RenderModel<ContentType1>>
|
||||
{ }
|
||||
|
||||
public class RenderModelOfContentType2TestPage : TestPage<RenderModel<ContentType2>>
|
||||
{ }
|
||||
|
||||
public class ContentType1TestPage : TestPage<ContentType1>
|
||||
{ }
|
||||
|
||||
public class ContentType2TestPage : TestPage<ContentType2>
|
||||
{ }
|
||||
|
||||
public class ContentType1 : PublishedContentWrapped
|
||||
{
|
||||
public ContentType1(IPublishedContent content) : base(content) {}
|
||||
}
|
||||
|
||||
public class ContentType2 : ContentType1
|
||||
{
|
||||
public ContentType2(IPublishedContent content) : base(content) { }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Test helpers
|
||||
|
||||
ViewContext GetViewContext()
|
||||
{
|
||||
var umbracoContext = GetUmbracoContext("/dang", 0);
|
||||
|
||||
var urlProvider = new UrlProvider(umbracoContext, new IUrlProvider[] { new DefaultUrlProvider() });
|
||||
var routingContext = new RoutingContext(
|
||||
umbracoContext,
|
||||
Enumerable.Empty<IContentFinder>(),
|
||||
new FakeLastChanceFinder(),
|
||||
urlProvider);
|
||||
umbracoContext.RoutingContext = routingContext;
|
||||
|
||||
var request = new PublishedContentRequest(new Uri("http://localhost/dang"), routingContext);
|
||||
request.Culture = CultureInfo.InvariantCulture;
|
||||
umbracoContext.PublishedContentRequest = request;
|
||||
|
||||
var context = new ViewContext();
|
||||
context.RouteData = new RouteData();
|
||||
context.RouteData.DataTokens.Add("umbraco-context", umbracoContext);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
protected UmbracoContext GetUmbracoContext(string url, int templateId, RouteData routeData = null, bool setSingleton = false)
|
||||
{
|
||||
var cache = new PublishedContentCache();
|
||||
|
||||
//cache.GetXmlDelegate = (context, preview) =>
|
||||
//{
|
||||
// var doc = new XmlDocument();
|
||||
// doc.LoadXml(GetXmlContent(templateId));
|
||||
// return doc;
|
||||
//};
|
||||
|
||||
//PublishedContentCache.UnitTesting = true;
|
||||
|
||||
// ApplicationContext.Current = new ApplicationContext(false) { IsReady = true };
|
||||
var appCtx = new ApplicationContext(false) { IsReady = true };
|
||||
|
||||
var ctx = new UmbracoContext(
|
||||
GetHttpContextFactory(url, routeData).HttpContext,
|
||||
appCtx,
|
||||
new PublishedCaches(cache, new PublishedMediaCache()));
|
||||
|
||||
//if (setSingleton)
|
||||
//{
|
||||
// UmbracoContext.Current = ctx;
|
||||
//}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
protected FakeHttpContextFactory GetHttpContextFactory(string url, RouteData routeData = null)
|
||||
{
|
||||
var factory = routeData != null
|
||||
? new FakeHttpContextFactory(url, routeData)
|
||||
: new FakeHttpContextFactory(url);
|
||||
|
||||
|
||||
//set the state helper
|
||||
StateHelper.HttpContext = factory.HttpContext;
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -145,6 +145,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="AttemptTests.cs" />
|
||||
<Compile Include="MockTests.cs" />
|
||||
<Compile Include="Mvc\UmbracoViewPageTests.cs" />
|
||||
<Compile Include="Persistence\Auditing\AuditTests.cs" />
|
||||
<Compile Include="BootManagers\CoreBootManagerTests.cs" />
|
||||
<Compile Include="BusinessLogic\DictionaryTest.cs" />
|
||||
|
||||
9
src/Umbraco.Web/Models/IRenderModel.cs
Normal file
9
src/Umbraco.Web/Models/IRenderModel.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public interface IRenderModel
|
||||
{
|
||||
IPublishedContent Content { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the model for the current rendering page in Umbraco
|
||||
/// </summary>
|
||||
public class RenderModel
|
||||
public class RenderModel : IRenderModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor specifying both the IPublishedContent and the CultureInfo
|
||||
@@ -16,7 +17,7 @@ namespace Umbraco.Web.Models
|
||||
/// <param name="culture"></param>
|
||||
public RenderModel(IPublishedContent content, CultureInfo culture)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
if (culture == null) throw new ArgumentNullException("culture");
|
||||
Content = content;
|
||||
CurrentCulture = culture;
|
||||
@@ -28,7 +29,7 @@ namespace Umbraco.Web.Models
|
||||
/// <param name="content"></param>
|
||||
public RenderModel(IPublishedContent content)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
if (UmbracoContext.Current == null)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot construct a RenderModel without specifying a CultureInfo when no UmbracoContext has been initialized");
|
||||
|
||||
36
src/Umbraco.Web/Models/RenderModelOfTContent.cs
Normal file
36
src/Umbraco.Web/Models/RenderModelOfTContent.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Globalization;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public class RenderModel<TContent> : RenderModel
|
||||
where TContent : class, IPublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor specifying both the IPublishedContent and the CultureInfo
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="culture"></param>
|
||||
public RenderModel(TContent content, CultureInfo culture)
|
||||
: base(content, culture)
|
||||
{
|
||||
Content = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to set the IPublishedContent and the CurrentCulture is set by the UmbracoContext
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
public RenderModel(TContent content)
|
||||
: base(content)
|
||||
{
|
||||
Content = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current IPublishedContent object
|
||||
/// </summary>
|
||||
public new TContent Content { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,4 @@
|
||||
using System;
|
||||
using StackExchange.Profiling;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Web.Mvc
|
||||
@@ -17,58 +8,19 @@ namespace Umbraco.Web.Mvc
|
||||
/// </summary>
|
||||
public abstract class UmbracoTemplatePage : UmbracoViewPage<RenderModel>
|
||||
{
|
||||
protected UmbracoTemplatePage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void InitializePage()
|
||||
{
|
||||
base.InitializePage();
|
||||
//set the model to the current node if it is not set, this is generally not the case
|
||||
if (Model != null)
|
||||
{
|
||||
////this.ViewData.Model = Model;
|
||||
//var backingItem = new DynamicBackingItem(Model.CurrentNode);
|
||||
var dynamicNode = new DynamicPublishedContent(Model.Content);
|
||||
CurrentPage = dynamicNode.AsDynamic();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetViewData(System.Web.Mvc.ViewDataDictionary viewData)
|
||||
{
|
||||
//Here we're going to check if the viewData's model is of IPublishedContent, this is basically just a helper for
|
||||
//syntax on the front-end so we can just pass in an IPublishedContent object to partial views that inherit from
|
||||
//UmbracoTemplatePage. Then we're going to manually contruct a RenderViewModel to pass back in to SetViewData
|
||||
if (viewData.Model is IPublishedContent)
|
||||
{
|
||||
//change the model to a RenderModel and auto set the culture
|
||||
viewData.Model = new RenderModel((IPublishedContent)viewData.Model, UmbracoContext.PublishedContentRequest.Culture);
|
||||
}
|
||||
|
||||
base.SetViewData(viewData);
|
||||
}
|
||||
private object _currentPage;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the a DynamicPublishedContent object
|
||||
/// Returns the content as a dynamic object
|
||||
/// </summary>
|
||||
public dynamic CurrentPage { get; private set; }
|
||||
|
||||
private UmbracoHelper _helper;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an UmbracoHelper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This ensures that the UmbracoHelper is constructed with the content model of this view
|
||||
/// </remarks>
|
||||
public override UmbracoHelper Umbraco
|
||||
public dynamic CurrentPage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _helper ?? (_helper = Model == null
|
||||
? new UmbracoHelper(UmbracoContext)
|
||||
: new UmbracoHelper(UmbracoContext, Model.Content));
|
||||
// it's invalid to create a DynamicPublishedContent around a null content anyway
|
||||
// fixme - should we return null or DynamicNull.Null?
|
||||
if (Model == null || Model.Content == null) return null;
|
||||
return _currentPage ?? (_currentPage = Model.Content.AsDynamic());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
src/Umbraco.Web/Mvc/UmbracoTemplatePageOfTContent.cs
Normal file
26
src/Umbraco.Web/Mvc/UmbracoTemplatePageOfTContent.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Web.Mvc
|
||||
{
|
||||
public abstract class UmbracoTemplatePage<TContent> : UmbracoViewPage<RenderModel<TContent>>
|
||||
where TContent : class, IPublishedContent
|
||||
{
|
||||
private object _currentPage;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the content as a dynamic object
|
||||
/// </summary>
|
||||
public dynamic CurrentPage
|
||||
{
|
||||
get
|
||||
{
|
||||
// it's invalid to create a DynamicPublishedContent around a null content anyway
|
||||
// fixme - should we return null or DynamicNull.Null?
|
||||
if (Model == null || Model.Content == null) return null;
|
||||
return _currentPage ?? (_currentPage = Model.Content.AsDynamic());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,188 +1,11 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.WebPages;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Web.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// The View that umbraco front-end views inherit from
|
||||
/// </summary>
|
||||
public abstract class UmbracoViewPage<T> : WebViewPage<T>
|
||||
{
|
||||
protected UmbracoViewPage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current UmbracoContext
|
||||
/// </summary>
|
||||
public UmbracoContext UmbracoContext
|
||||
{
|
||||
get
|
||||
{
|
||||
//we should always try to return the context from the data tokens just in case its a custom context and not
|
||||
//using the UmbracoContext.Current.
|
||||
//we will fallback to the singleton if necessary.
|
||||
if (ViewContext.RouteData.DataTokens.ContainsKey("umbraco-context"))
|
||||
{
|
||||
return (UmbracoContext)ViewContext.RouteData.DataTokens.GetRequiredObject("umbraco-context");
|
||||
}
|
||||
//next check if it is a child action and see if the parent has it set in data tokens
|
||||
if (ViewContext.IsChildAction)
|
||||
{
|
||||
if (ViewContext.ParentActionViewContext.RouteData.DataTokens.ContainsKey("umbraco-context"))
|
||||
{
|
||||
return (UmbracoContext)ViewContext.ParentActionViewContext.RouteData.DataTokens.GetRequiredObject("umbraco-context");
|
||||
}
|
||||
}
|
||||
|
||||
//lastly, we will use the singleton, the only reason this should ever happen is is someone is rendering a page that inherits from this
|
||||
//class and are rendering it outside of the normal Umbraco routing process. Very unlikely.
|
||||
return UmbracoContext.Current;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current ApplicationContext
|
||||
/// </summary>
|
||||
public ApplicationContext ApplicationContext
|
||||
{
|
||||
get { return UmbracoContext.Application; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current PublishedContentRequest
|
||||
/// </summary>
|
||||
internal PublishedContentRequest PublishedContentRequest
|
||||
{
|
||||
get
|
||||
{
|
||||
//we should always try to return the object from the data tokens just in case its a custom object and not
|
||||
//using the UmbracoContext.Current.
|
||||
//we will fallback to the singleton if necessary.
|
||||
if (ViewContext.RouteData.DataTokens.ContainsKey("umbraco-doc-request"))
|
||||
{
|
||||
return (PublishedContentRequest)ViewContext.RouteData.DataTokens.GetRequiredObject("umbraco-doc-request");
|
||||
}
|
||||
//next check if it is a child action and see if the parent has it set in data tokens
|
||||
if (ViewContext.IsChildAction)
|
||||
{
|
||||
if (ViewContext.ParentActionViewContext.RouteData.DataTokens.ContainsKey("umbraco-doc-request"))
|
||||
{
|
||||
return (PublishedContentRequest)ViewContext.ParentActionViewContext.RouteData.DataTokens.GetRequiredObject("umbraco-doc-request");
|
||||
}
|
||||
}
|
||||
|
||||
//lastly, we will use the singleton, the only reason this should ever happen is is someone is rendering a page that inherits from this
|
||||
//class and are rendering it outside of the normal Umbraco routing process. Very unlikely.
|
||||
return UmbracoContext.Current.PublishedContentRequest;
|
||||
}
|
||||
}
|
||||
|
||||
private UmbracoHelper _helper;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an UmbracoHelper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This constructs the UmbracoHelper with the content model of the page routed to
|
||||
/// </remarks>
|
||||
public virtual UmbracoHelper Umbraco
|
||||
{
|
||||
get { return _helper ?? (_helper = new UmbracoHelper(UmbracoContext)); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that the current view context is added to the route data tokens so we can extract it if we like
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this is required by mvc macro engines
|
||||
/// </remarks>
|
||||
protected override void InitializePage()
|
||||
{
|
||||
base.InitializePage();
|
||||
if (!ViewContext.IsChildAction)
|
||||
{
|
||||
if (!ViewContext.RouteData.DataTokens.ContainsKey(Constants.DataTokenCurrentViewContext))
|
||||
{
|
||||
ViewContext.RouteData.DataTokens.Add(Constants.DataTokenCurrentViewContext, this.ViewContext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will detect the end /body tag and insert the preview badge if in preview mode
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteLiteral(object value)
|
||||
{
|
||||
// filter / add preview banner
|
||||
if (Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value
|
||||
{
|
||||
if (UmbracoContext.Current.IsDebug || UmbracoContext.Current.InPreviewMode)
|
||||
{
|
||||
var text = value.ToString().ToLowerInvariant();
|
||||
var pos = text.IndexOf("</body>", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
if (pos > -1)
|
||||
{
|
||||
string markupToInject;
|
||||
|
||||
if (UmbracoContext.Current.InPreviewMode)
|
||||
{
|
||||
// creating previewBadge markup
|
||||
markupToInject =
|
||||
String.Format(UmbracoSettings.PreviewBadge,
|
||||
IOHelper.ResolveUrl(SystemDirectories.Umbraco),
|
||||
IOHelper.ResolveUrl(SystemDirectories.UmbracoClient),
|
||||
Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Path));
|
||||
}
|
||||
else
|
||||
{
|
||||
// creating mini-profiler markup
|
||||
markupToInject = Html.RenderProfiler().ToHtmlString();
|
||||
}
|
||||
|
||||
var sb = new StringBuilder(text);
|
||||
sb.Insert(pos, markupToInject);
|
||||
|
||||
base.WriteLiteral(sb.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.WriteLiteral(value);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public HelperResult RenderSection(string name, Func<dynamic, HelperResult> defaultContents)
|
||||
{
|
||||
return WebViewPageExtensions.RenderSection(this, name, defaultContents);
|
||||
}
|
||||
|
||||
public HelperResult RenderSection(string name, HelperResult defaultContents)
|
||||
{
|
||||
return WebViewPageExtensions.RenderSection(this, name, defaultContents);
|
||||
}
|
||||
|
||||
public HelperResult RenderSection(string name, string defaultContents)
|
||||
{
|
||||
return WebViewPageExtensions.RenderSection(this, name, defaultContents);
|
||||
}
|
||||
|
||||
public HelperResult RenderSection(string name, IHtmlString defaultContents)
|
||||
{
|
||||
return WebViewPageExtensions.RenderSection(this, name, defaultContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract class UmbracoViewPage : UmbracoViewPage<IPublishedContent>
|
||||
{ }
|
||||
}
|
||||
|
||||
282
src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs
Normal file
282
src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs
Normal file
@@ -0,0 +1,282 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.WebPages;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// The View that umbraco front-end views inherit from
|
||||
/// </summary>
|
||||
public abstract class UmbracoViewPage<TModel> : WebViewPage<TModel>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the current UmbracoContext
|
||||
/// </summary>
|
||||
public UmbracoContext UmbracoContext
|
||||
{
|
||||
get
|
||||
{
|
||||
//we should always try to return the context from the data tokens just in case its a custom context and not
|
||||
//using the UmbracoContext.Current.
|
||||
//we will fallback to the singleton if necessary.
|
||||
if (ViewContext.RouteData.DataTokens.ContainsKey("umbraco-context"))
|
||||
{
|
||||
return (UmbracoContext)ViewContext.RouteData.DataTokens.GetRequiredObject("umbraco-context");
|
||||
}
|
||||
//next check if it is a child action and see if the parent has it set in data tokens
|
||||
if (ViewContext.IsChildAction)
|
||||
{
|
||||
if (ViewContext.ParentActionViewContext.RouteData.DataTokens.ContainsKey("umbraco-context"))
|
||||
{
|
||||
return (UmbracoContext)ViewContext.ParentActionViewContext.RouteData.DataTokens.GetRequiredObject("umbraco-context");
|
||||
}
|
||||
}
|
||||
|
||||
//lastly, we will use the singleton, the only reason this should ever happen is is someone is rendering a page that inherits from this
|
||||
//class and are rendering it outside of the normal Umbraco routing process. Very unlikely.
|
||||
return UmbracoContext.Current;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current ApplicationContext
|
||||
/// </summary>
|
||||
public ApplicationContext ApplicationContext
|
||||
{
|
||||
get { return UmbracoContext.Application; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current PublishedContentRequest
|
||||
/// </summary>
|
||||
internal PublishedContentRequest PublishedContentRequest
|
||||
{
|
||||
get
|
||||
{
|
||||
//we should always try to return the object from the data tokens just in case its a custom object and not
|
||||
//using the UmbracoContext.Current.
|
||||
//we will fallback to the singleton if necessary.
|
||||
if (ViewContext.RouteData.DataTokens.ContainsKey("umbraco-doc-request"))
|
||||
{
|
||||
return (PublishedContentRequest)ViewContext.RouteData.DataTokens.GetRequiredObject("umbraco-doc-request");
|
||||
}
|
||||
//next check if it is a child action and see if the parent has it set in data tokens
|
||||
if (ViewContext.IsChildAction)
|
||||
{
|
||||
if (ViewContext.ParentActionViewContext.RouteData.DataTokens.ContainsKey("umbraco-doc-request"))
|
||||
{
|
||||
return (PublishedContentRequest)ViewContext.ParentActionViewContext.RouteData.DataTokens.GetRequiredObject("umbraco-doc-request");
|
||||
}
|
||||
}
|
||||
|
||||
//lastly, we will use the singleton, the only reason this should ever happen is is someone is rendering a page that inherits from this
|
||||
//class and are rendering it outside of the normal Umbraco routing process. Very unlikely.
|
||||
return UmbracoContext.Current.PublishedContentRequest;
|
||||
}
|
||||
}
|
||||
|
||||
private UmbracoHelper _helper;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an UmbracoHelper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This constructs the UmbracoHelper with the content model of the page routed to
|
||||
/// </remarks>
|
||||
public virtual UmbracoHelper Umbraco
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_helper == null)
|
||||
{
|
||||
var model = ViewData.Model;
|
||||
var content = model as IPublishedContent;
|
||||
if (content == null && model is IRenderModel)
|
||||
content = ((IRenderModel) model).Content;
|
||||
_helper = content == null
|
||||
? new UmbracoHelper(UmbracoContext)
|
||||
: new UmbracoHelper(UmbracoContext, content);
|
||||
}
|
||||
return _helper;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that the current view context is added to the route data tokens so we can extract it if we like
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this is required by mvc macro engines
|
||||
/// </remarks>
|
||||
protected override void InitializePage()
|
||||
{
|
||||
base.InitializePage();
|
||||
if (ViewContext.IsChildAction == false)
|
||||
{
|
||||
if (ViewContext.RouteData.DataTokens.ContainsKey(Constants.DataTokenCurrentViewContext) == false)
|
||||
{
|
||||
ViewContext.RouteData.DataTokens.Add(Constants.DataTokenCurrentViewContext, ViewContext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// maps model
|
||||
protected override void SetViewData(ViewDataDictionary viewData)
|
||||
{
|
||||
var source = viewData.Model;
|
||||
if (source == null)
|
||||
{
|
||||
base.SetViewData(viewData);
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceType = source.GetType();
|
||||
var targetType = typeof (TModel);
|
||||
|
||||
// it types already match, nothing to do
|
||||
if (sourceType.Inherits<TModel>()) // includes ==
|
||||
{
|
||||
base.SetViewData(viewData);
|
||||
return;
|
||||
}
|
||||
|
||||
// try to grab the content
|
||||
// if no content is found, return, nothing we can do
|
||||
var sourceContent = source as IPublishedContent;
|
||||
if (sourceContent == null && sourceType.Implements<IRenderModel>())
|
||||
{
|
||||
sourceContent = ((IRenderModel)source).Content;
|
||||
}
|
||||
if (sourceContent == null)
|
||||
{
|
||||
var attempt = source.TryConvertTo<IPublishedContent>();
|
||||
if (attempt.Success) sourceContent = attempt.Result;
|
||||
}
|
||||
|
||||
var ok = sourceContent != null;
|
||||
if (sourceContent != null)
|
||||
{
|
||||
// try to grab the culture
|
||||
// using context's culture by default
|
||||
var culture = UmbracoContext.PublishedContentRequest.Culture;
|
||||
var sourceRenderModel = source as RenderModel;
|
||||
if (sourceRenderModel != null)
|
||||
culture = sourceRenderModel.CurrentCulture;
|
||||
|
||||
// reassign the model depending on its type
|
||||
if (targetType.Implements<IPublishedContent>())
|
||||
{
|
||||
// it TModel implements IPublishedContent then use the content
|
||||
// provided that the content is of the proper type
|
||||
if ((sourceContent is TModel) == false)
|
||||
throw new InvalidCastException(string.Format("Cannot cast source content type {0} to view model type {1}.",
|
||||
sourceContent.GetType(), targetType));
|
||||
viewData.Model = sourceContent;
|
||||
}
|
||||
else if (targetType == typeof(RenderModel))
|
||||
{
|
||||
// if TModel is a basic RenderModel just create it
|
||||
viewData.Model = new RenderModel(sourceContent, culture);
|
||||
}
|
||||
else if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(RenderModel<>))
|
||||
{
|
||||
// if TModel is a strongly-typed RenderModel<> then create it
|
||||
// provided that the content is of the proper type
|
||||
var targetContentType = targetType.GetGenericArguments()[0];
|
||||
if ((sourceContent.GetType().Inherits(targetContentType)) == false)
|
||||
throw new InvalidCastException(string.Format("Cannot cast source content type {0} to view model content type {1}.",
|
||||
sourceContent.GetType(), targetContentType));
|
||||
viewData.Model = Activator.CreateInstance(targetType, sourceContent, culture);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok == false)
|
||||
{
|
||||
// last chance : try to convert
|
||||
var attempt = source.TryConvertTo<TModel>();
|
||||
if (attempt.Success) viewData.Model = attempt.Result;
|
||||
}
|
||||
|
||||
base.SetViewData(viewData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will detect the end /body tag and insert the preview badge if in preview mode
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public override void WriteLiteral(object value)
|
||||
{
|
||||
// filter / add preview banner
|
||||
if (Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value
|
||||
{
|
||||
if (UmbracoContext.Current.IsDebug || UmbracoContext.Current.InPreviewMode)
|
||||
{
|
||||
var text = value.ToString().ToLowerInvariant();
|
||||
var pos = text.IndexOf("</body>", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
if (pos > -1)
|
||||
{
|
||||
string markupToInject;
|
||||
|
||||
if (UmbracoContext.Current.InPreviewMode)
|
||||
{
|
||||
// creating previewBadge markup
|
||||
markupToInject =
|
||||
String.Format(UmbracoSettings.PreviewBadge,
|
||||
IOHelper.ResolveUrl(SystemDirectories.Umbraco),
|
||||
IOHelper.ResolveUrl(SystemDirectories.UmbracoClient),
|
||||
Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Path));
|
||||
}
|
||||
else
|
||||
{
|
||||
// creating mini-profiler markup
|
||||
markupToInject = Html.RenderProfiler().ToHtmlString();
|
||||
}
|
||||
|
||||
var sb = new StringBuilder(text);
|
||||
sb.Insert(pos, markupToInject);
|
||||
|
||||
base.WriteLiteral(sb.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.WriteLiteral(value);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public HelperResult RenderSection(string name, Func<dynamic, HelperResult> defaultContents)
|
||||
{
|
||||
return WebViewPageExtensions.RenderSection(this, name, defaultContents);
|
||||
}
|
||||
|
||||
public HelperResult RenderSection(string name, HelperResult defaultContents)
|
||||
{
|
||||
return WebViewPageExtensions.RenderSection(this, name, defaultContents);
|
||||
}
|
||||
|
||||
public HelperResult RenderSection(string name, string defaultContents)
|
||||
{
|
||||
return WebViewPageExtensions.RenderSection(this, name, defaultContents);
|
||||
}
|
||||
|
||||
public HelperResult RenderSection(string name, IHtmlString defaultContents)
|
||||
{
|
||||
return WebViewPageExtensions.RenderSection(this, name, defaultContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,6 +294,10 @@
|
||||
<Compile Include="Controllers\ProfileController.cs" />
|
||||
<Compile Include="Controllers\LoginStatusController.cs" />
|
||||
<Compile Include="Editors\MediaController.cs" />
|
||||
<Compile Include="Models\IRenderModel.cs" />
|
||||
<Compile Include="Models\RenderModelOfTContent.cs" />
|
||||
<Compile Include="Mvc\UmbracoTemplatePageOfTContent.cs" />
|
||||
<Compile Include="Mvc\UmbracoViewPage.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentSortOrder.cs" />
|
||||
<Compile Include="Controllers\RegisterController.cs" />
|
||||
<Compile Include="Models\ProfileModel.cs" />
|
||||
@@ -421,7 +425,7 @@
|
||||
<Compile Include="Mvc\UmbracoController.cs" />
|
||||
<Compile Include="Mvc\UmbracoControllerFactory.cs" />
|
||||
<Compile Include="Mvc\UmbracoMvcHandler.cs" />
|
||||
<Compile Include="Mvc\UmbracoViewPage.cs" />
|
||||
<Compile Include="Mvc\UmbracoViewPageOfTModel.cs" />
|
||||
<Compile Include="PublishedCache\IPublishedCache.cs" />
|
||||
<Compile Include="PublishedCache\IPublishedContentCache.cs" />
|
||||
<Compile Include="PublishedCache\IPublishedMediaCache.cs" />
|
||||
|
||||
Reference in New Issue
Block a user