U4-10822 - refactor view models binding error handling
This commit is contained in:
@@ -41,14 +41,14 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
[Test]
|
||||
public void BindModel_Null_Source_Returns_Null()
|
||||
{
|
||||
Assert.IsNull(RenderModelBinder.BindModel(null, typeof(MyContent), CultureInfo.CurrentCulture));
|
||||
Assert.IsNull(RenderModelBinder.Instance.BindModel(null, typeof(MyContent), CultureInfo.CurrentCulture));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BindModel_Returns_If_Same_Type()
|
||||
{
|
||||
var content = new MyContent(Mock.Of<IPublishedContent>());
|
||||
var bound = RenderModelBinder.BindModel(content, typeof (IPublishedContent), CultureInfo.CurrentCulture);
|
||||
var bound = RenderModelBinder.Instance.BindModel(content, typeof (IPublishedContent), CultureInfo.CurrentCulture);
|
||||
Assert.AreSame(content, bound);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
{
|
||||
var content = new MyContent(Mock.Of<IPublishedContent>());
|
||||
var renderModel = new RenderModel(content, CultureInfo.CurrentCulture);
|
||||
var bound = RenderModelBinder.BindModel(renderModel, typeof(IPublishedContent), CultureInfo.CurrentCulture);
|
||||
var bound = RenderModelBinder.Instance.BindModel(renderModel, typeof(IPublishedContent), CultureInfo.CurrentCulture);
|
||||
Assert.AreSame(content, bound);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
public void BindModel_IPublishedContent_To_RenderModel()
|
||||
{
|
||||
var content = new MyContent(Mock.Of<IPublishedContent>());
|
||||
var bound = (IRenderModel)RenderModelBinder.BindModel(content, typeof(RenderModel), CultureInfo.CurrentCulture);
|
||||
var bound = (IRenderModel)RenderModelBinder.Instance.BindModel(content, typeof(RenderModel), CultureInfo.CurrentCulture);
|
||||
Assert.AreSame(content, bound.Content);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
public void BindModel_IPublishedContent_To_Generic_RenderModel()
|
||||
{
|
||||
var content = new MyContent(Mock.Of<IPublishedContent>());
|
||||
var bound = (IRenderModel)RenderModelBinder.BindModel(content, typeof(RenderModel<MyContent>), CultureInfo.CurrentCulture);
|
||||
var bound = (IRenderModel)RenderModelBinder.Instance.BindModel(content, typeof(RenderModel<MyContent>), CultureInfo.CurrentCulture);
|
||||
Assert.AreSame(content, bound.Content);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
@@ -13,8 +12,10 @@ namespace Umbraco.Web.Mvc
|
||||
/// <summary>
|
||||
/// Allows for Model Binding any IPublishedContent or IRenderModel
|
||||
/// </summary>
|
||||
public class RenderModelBinder : DefaultModelBinder, IModelBinder, IModelBinderProvider
|
||||
public class RenderModelBinder : DefaultModelBinder, IModelBinderProvider
|
||||
{
|
||||
public static RenderModelBinder Instance = new RenderModelBinder();
|
||||
|
||||
/// <summary>
|
||||
/// Binds the model to a value by using the specified controller context and binding context.
|
||||
/// </summary>
|
||||
@@ -66,7 +67,7 @@ namespace Umbraco.Web.Mvc
|
||||
// to
|
||||
// { RenderModel, RenderModel<TContent>, IPublishedContent }
|
||||
//
|
||||
public static object BindModel(object source, Type modelType, CultureInfo culture)
|
||||
public object BindModel(object source, Type modelType, CultureInfo culture)
|
||||
{
|
||||
// null model, return
|
||||
if (source == null) return null;
|
||||
@@ -132,10 +133,30 @@ namespace Umbraco.Web.Mvc
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void ThrowModelBindingException(bool sourceContent, bool modelContent, Type sourceType, Type modelType)
|
||||
public class ModelBindingArgs : EventArgs
|
||||
{
|
||||
public ModelBindingArgs(Type sourceType, Type modelType, StringBuilder message)
|
||||
{
|
||||
SourceType = sourceType;
|
||||
ModelType = modelType;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public bool SourceIsContent;
|
||||
public bool ViewModelIsContent;
|
||||
public Type SourceType { get; set; }
|
||||
public Type ModelType { get; set; }
|
||||
public StringBuilder Message { get; private set; }
|
||||
public bool Restart { get; set; }
|
||||
}
|
||||
|
||||
public static event EventHandler<ModelBindingArgs> ModelBindingException;
|
||||
|
||||
private void ThrowModelBindingException(bool sourceContent, bool modelContent, Type sourceType, Type modelType)
|
||||
{
|
||||
var msg = new StringBuilder();
|
||||
|
||||
|
||||
// prepare message
|
||||
msg.Append("Cannot bind source");
|
||||
if (sourceContent) msg.Append(" content");
|
||||
msg.Append(" type ");
|
||||
@@ -145,29 +166,25 @@ namespace Umbraco.Web.Mvc
|
||||
msg.Append(" type ");
|
||||
msg.Append(modelType.FullName);
|
||||
msg.Append(".");
|
||||
|
||||
// raise event, to give model factories a chance at reporting
|
||||
// the error with more details, and optionally request that
|
||||
// the application restarts.
|
||||
|
||||
// compare FullName for the time being because when upgrading ModelsBuilder,
|
||||
// Umbraco does not know about the new attribute type - later on, can compare
|
||||
// on type directly (ie after v7.4.2).
|
||||
var sourceAttr = sourceType.Assembly.CustomAttributes.FirstOrDefault(x =>
|
||||
x.AttributeType.FullName == "Umbraco.ModelsBuilder.PureLiveAssemblyAttribute");
|
||||
var modelAttr = modelType.Assembly.CustomAttributes.FirstOrDefault(x =>
|
||||
x.AttributeType.FullName == "Umbraco.ModelsBuilder.PureLiveAssemblyAttribute");
|
||||
var args = new ModelBindingArgs(sourceType, modelType, msg);
|
||||
if (ModelBindingException != null)
|
||||
ModelBindingException(this, args);
|
||||
|
||||
// bah.. names are App_Web_all.generated.cs.8f9494c4.jjuvxz55 so they ARE different, fuck!
|
||||
// we cannot compare purely on type.FullName 'cos we might be trying to map Sub to Main = fails!
|
||||
if (sourceAttr != null && modelAttr != null
|
||||
&& sourceType.Assembly.GetName().Version.Revision != modelType.Assembly.GetName().Version.Revision)
|
||||
if (args.Restart)
|
||||
{
|
||||
msg.Append(" Types come from two PureLive assemblies with different versions,");
|
||||
msg.Append(" this usually indicates that the application is in an unstable state.");
|
||||
msg.Append(" The application is restarting now, reload the page and it should work.");
|
||||
var context = HttpContext.Current;
|
||||
if (context == null)
|
||||
AppDomain.Unload(AppDomain.CurrentDomain);
|
||||
else
|
||||
ApplicationContext.Current.RestartApplicationPool(new HttpContextWrapper(context));
|
||||
}
|
||||
msg.Append(" The application is restarting now.");
|
||||
|
||||
var context = HttpContext.Current;
|
||||
if (context == null)
|
||||
AppDomain.Unload(AppDomain.CurrentDomain);
|
||||
else
|
||||
ApplicationContext.Current.RestartApplicationPool(new HttpContextWrapper(context));
|
||||
}
|
||||
|
||||
throw new ModelBindingException(msg.ToString());
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace Umbraco.Web.Mvc
|
||||
// bind the model (use context culture as default, if available)
|
||||
if (UmbracoContext.PublishedContentRequest != null && UmbracoContext.PublishedContentRequest.Culture != null)
|
||||
culture = UmbracoContext.PublishedContentRequest.Culture;
|
||||
viewData.Model = RenderModelBinder.BindModel(viewDataModel, typeof (TModel), culture);
|
||||
viewData.Model = RenderModelBinder.Instance.BindModel(viewDataModel, typeof (TModel), culture);
|
||||
|
||||
// set the view data
|
||||
base.SetViewData(viewData);
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Umbraco.Web
|
||||
ViewEngines.Engines.Add(new PluginViewEngine());
|
||||
|
||||
//set model binder
|
||||
ModelBinderProviders.BinderProviders.Add(new RenderModelBinder()); // is a provider
|
||||
ModelBinderProviders.BinderProviders.Add(RenderModelBinder.Instance); // is a provider
|
||||
|
||||
////add the profiling action filter
|
||||
//GlobalFilters.Filters.Add(new ProfilingActionFilter());
|
||||
|
||||
Reference in New Issue
Block a user