/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This software is subject to the Microsoft Public License (Ms-PL).
* A copy of the license can be found in the license.htm file included
* in this distribution.
*
* You must not remove this notice, or any other, from this software.
*
* ***************************************************************************/
namespace System.Web.Mvc{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc.Html;
// Though many of the properties on ControllerContext and its subclassed types are virtual, there are still sealed
// properties (like ControllerContext.RequestContext, ActionExecutingContext.Result, etc.). If these properties
// were virtual, a mocking framework might override them with incorrect behavior (property getters would return
// null, property setters would be no-ops). By sealing these properties, we are forcing them to have the default
// "get or store a value" semantics that they were intended to have.
public class ControllerContext {
private HttpContextBase _httpContext;
private RequestContext _requestContext;
private RouteData _routeData;
internal const string PARENT_ACTION_VIEWCONTEXT = "ParentActionViewContext";
// parameterless constructor used for mocking
public ControllerContext() {
}
// copy constructor - allows for subclassed types to take an existing ControllerContext as a parameter
// and we'll automatically set the appropriate properties
[SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors",
Justification = "The virtual property setters are only to support mocking frameworks, in which case this constructor shouldn't be called anyway.")]
protected ControllerContext(ControllerContext controllerContext) {
if (controllerContext == null) {
throw new ArgumentNullException("controllerContext");
}
Controller = controllerContext.Controller;
RequestContext = controllerContext.RequestContext;
}
public ControllerContext(HttpContextBase httpContext, RouteData routeData, ControllerBase controller)
: this(new RequestContext(httpContext, routeData), controller) {
}
[SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors",
Justification = "The virtual property setters are only to support mocking frameworks, in which case this constructor shouldn't be called anyway.")]
public ControllerContext(RequestContext requestContext, ControllerBase controller) {
if (requestContext == null) {
throw new ArgumentNullException("requestContext");
}
if (controller == null) {
throw new ArgumentNullException("controller");
}
RequestContext = requestContext;
Controller = controller;
}
public virtual ControllerBase Controller {
get;
set;
}
public virtual HttpContextBase HttpContext {
get {
if (_httpContext == null) {
_httpContext = (_requestContext != null) ? _requestContext.HttpContext : new EmptyHttpContext();
}
return _httpContext;
}
set {
_httpContext = value;
}
}
public virtual bool IsChildAction {
get {
RouteData routeData = RouteData;
if (routeData == null) {
return false;
}
return routeData.DataTokens.ContainsKey(PARENT_ACTION_VIEWCONTEXT);
}
}
public ViewContext ParentActionViewContext {
get {
return RouteData.DataTokens[PARENT_ACTION_VIEWCONTEXT] as ViewContext;
}
}
public RequestContext RequestContext {
get {
if (_requestContext == null) {
// still need explicit calls to constructors since the property getters are virtual and might return null
HttpContextBase httpContext = HttpContext ?? new EmptyHttpContext();
RouteData routeData = RouteData ?? new RouteData();
_requestContext = new RequestContext(httpContext, routeData);
}
return _requestContext;
}
set {
_requestContext = value;
}
}
public virtual RouteData RouteData {
get {
if (_routeData == null) {
_routeData = (_requestContext != null) ? _requestContext.RouteData : new RouteData();
}
return _routeData;
}
set {
_routeData = value;
}
}
private sealed class EmptyHttpContext : HttpContextBase {
}
}
}
|