1 namespace System.Web.Mvc {
3 using System.Diagnostics.CodeAnalysis;
4 using System.Globalization;
6 using System.Security.Principal;
9 using System.Web.Mvc.Resources;
10 using System.Web.Routing;
12 public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter {
14 private IActionInvoker _actionInvoker;
15 private ModelBinderDictionary _binders;
16 private RouteCollection _routeCollection;
17 private ITempDataProvider _tempDataProvider;
19 public IActionInvoker ActionInvoker {
21 if (_actionInvoker == null) {
22 _actionInvoker = CreateActionInvoker();
24 return _actionInvoker;
27 _actionInvoker = value;
31 [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Property is settable so that the dictionary can be provided for unit testing purposes.")]
32 protected internal ModelBinderDictionary Binders {
34 if (_binders == null) {
35 _binders = ModelBinders.Binders;
44 public HttpContextBase HttpContext {
46 return ControllerContext == null ? null : ControllerContext.HttpContext;
50 public ModelStateDictionary ModelState {
52 return ViewData.ModelState;
56 public HttpRequestBase Request {
58 return HttpContext == null ? null : HttpContext.Request;
62 public HttpResponseBase Response {
64 return HttpContext == null ? null : HttpContext.Response;
68 internal RouteCollection RouteCollection {
70 if (_routeCollection == null) {
71 _routeCollection = RouteTable.Routes;
73 return _routeCollection;
76 _routeCollection = value;
80 public RouteData RouteData {
82 return ControllerContext == null ? null : ControllerContext.RouteData;
86 public HttpServerUtilityBase Server {
88 return HttpContext == null ? null : HttpContext.Server;
92 public HttpSessionStateBase Session {
94 return HttpContext == null ? null : HttpContext.Session;
98 public ITempDataProvider TempDataProvider {
100 if (_tempDataProvider == null) {
101 _tempDataProvider = CreateTempDataProvider();
103 return _tempDataProvider;
106 _tempDataProvider = value;
110 public UrlHelper Url {
115 public IPrincipal User {
117 return HttpContext == null ? null : HttpContext.User;
121 [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "'Content' refers to ContentResult type; 'content' refers to ContentResult.Content property.")]
122 protected internal ContentResult Content(string content) {
123 return Content(content, null /* contentType */);
126 [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "'Content' refers to ContentResult type; 'content' refers to ContentResult.Content property.")]
127 protected internal ContentResult Content(string content, string contentType) {
128 return Content(content, contentType, null /* contentEncoding */);
131 [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "'Content' refers to ContentResult type; 'content' refers to ContentResult.Content property.")]
132 protected internal virtual ContentResult Content(string content, string contentType, Encoding contentEncoding) {
133 return new ContentResult {
135 ContentType = contentType,
136 ContentEncoding = contentEncoding
140 protected virtual IActionInvoker CreateActionInvoker() {
141 return new ControllerActionInvoker();
144 protected virtual ITempDataProvider CreateTempDataProvider() {
145 return new SessionStateTempDataProvider();
148 // The default invoker will never match methods defined on the Controller type, so
149 // the Dispose() method is not web-callable. However, in general, since implicitly-
150 // implemented interface methods are public, they are web-callable unless decorated with
152 public void Dispose() {
153 Dispose(true /* disposing */);
154 GC.SuppressFinalize(this);
157 protected virtual void Dispose(bool disposing) {
160 protected override void ExecuteCore() {
161 // If code in this method needs to be updated, please also check the BeginExecuteCore() and
162 // EndExecuteCore() methods of AsyncController to see if that code also must be updated.
164 PossiblyLoadTempData();
166 string actionName = RouteData.GetRequiredString("action");
167 if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
168 HandleUnknownAction(actionName);
172 PossiblySaveTempData();
176 protected internal FileContentResult File(byte[] fileContents, string contentType) {
177 return File(fileContents, contentType, null /* fileDownloadName */);
180 protected internal virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName) {
181 return new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName };
184 protected internal FileStreamResult File(Stream fileStream, string contentType) {
185 return File(fileStream, contentType, null /* fileDownloadName */);
188 protected internal virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName) {
189 return new FileStreamResult(fileStream, contentType) { FileDownloadName = fileDownloadName };
192 protected internal FilePathResult File(string fileName, string contentType) {
193 return File(fileName, contentType, null /* fileDownloadName */);
196 protected internal virtual FilePathResult File(string fileName, string contentType, string fileDownloadName) {
197 return new FilePathResult(fileName, contentType) { FileDownloadName = fileDownloadName };
200 protected virtual void HandleUnknownAction(string actionName) {
201 throw new HttpException(404, String.Format(CultureInfo.CurrentCulture,
202 MvcResources.Controller_UnknownAction, actionName, GetType().FullName));
205 protected internal HttpNotFoundResult HttpNotFound() {
206 return HttpNotFound(null);
209 protected internal virtual HttpNotFoundResult HttpNotFound(string statusDescription) {
210 return new HttpNotFoundResult(statusDescription);
213 protected internal virtual JavaScriptResult JavaScript(string script) {
214 return new JavaScriptResult { Script = script };
217 protected internal JsonResult Json(object data) {
218 return Json(data, null /* contentType */, null /* contentEncoding */, JsonRequestBehavior.DenyGet);
221 protected internal JsonResult Json(object data, string contentType) {
222 return Json(data, contentType, null /* contentEncoding */, JsonRequestBehavior.DenyGet);
225 protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding) {
226 return Json(data, contentType, contentEncoding, JsonRequestBehavior.DenyGet);
229 protected internal JsonResult Json(object data, JsonRequestBehavior behavior) {
230 return Json(data, null /* contentType */, null /* contentEncoding */, behavior);
233 protected internal JsonResult Json(object data, string contentType, JsonRequestBehavior behavior) {
234 return Json(data, contentType, null /* contentEncoding */, behavior);
237 protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior) {
238 return new JsonResult {
240 ContentType = contentType,
241 ContentEncoding = contentEncoding,
242 JsonRequestBehavior = behavior
246 protected override void Initialize(RequestContext requestContext) {
247 base.Initialize(requestContext);
248 Url = new UrlHelper(requestContext);
251 protected virtual void OnActionExecuting(ActionExecutingContext filterContext) {
254 protected virtual void OnActionExecuted(ActionExecutedContext filterContext) {
257 protected virtual void OnAuthorization(AuthorizationContext filterContext) {
260 protected virtual void OnException(ExceptionContext filterContext) {
263 protected virtual void OnResultExecuted(ResultExecutedContext filterContext) {
266 protected virtual void OnResultExecuting(ResultExecutingContext filterContext) {
269 protected internal PartialViewResult PartialView() {
270 return PartialView(null /* viewName */, null /* model */);
273 protected internal PartialViewResult PartialView(object model) {
274 return PartialView(null /* viewName */, model);
277 protected internal PartialViewResult PartialView(string viewName) {
278 return PartialView(viewName, null /* model */);
281 protected internal virtual PartialViewResult PartialView(string viewName, object model) {
283 ViewData.Model = model;
286 return new PartialViewResult {
293 internal void PossiblyLoadTempData() {
294 if (!ControllerContext.IsChildAction) {
295 TempData.Load(ControllerContext, TempDataProvider);
299 internal void PossiblySaveTempData() {
300 if (!ControllerContext.IsChildAction) {
301 TempData.Save(ControllerContext, TempDataProvider);
305 [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Response.Redirect() takes its URI as a string parameter.")]
306 protected internal virtual RedirectResult Redirect(string url) {
307 if (String.IsNullOrEmpty(url)) {
308 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "url");
311 return new RedirectResult(url);
314 [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Response.RedirectPermanent() takes its URI as a string parameter.")]
315 protected internal virtual RedirectResult RedirectPermanent(string url) {
316 if (String.IsNullOrEmpty(url)) {
317 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "url");
320 return new RedirectResult(url, permanent: true);
323 protected internal RedirectToRouteResult RedirectToAction(string actionName) {
324 return RedirectToAction(actionName, (RouteValueDictionary)null);
327 protected internal RedirectToRouteResult RedirectToAction(string actionName, object routeValues) {
328 return RedirectToAction(actionName, new RouteValueDictionary(routeValues));
331 protected internal RedirectToRouteResult RedirectToAction(string actionName, RouteValueDictionary routeValues) {
332 return RedirectToAction(actionName, null /* controllerName */, routeValues);
335 protected internal RedirectToRouteResult RedirectToAction(string actionName, string controllerName) {
336 return RedirectToAction(actionName, controllerName, (RouteValueDictionary)null);
339 protected internal RedirectToRouteResult RedirectToAction(string actionName, string controllerName, object routeValues) {
340 return RedirectToAction(actionName, controllerName, new RouteValueDictionary(routeValues));
343 protected internal virtual RedirectToRouteResult RedirectToAction(string actionName, string controllerName, RouteValueDictionary routeValues) {
344 RouteValueDictionary mergedRouteValues;
346 if (RouteData == null) {
347 mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, null, routeValues, includeImplicitMvcValues: true);
350 mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, RouteData.Values, routeValues, includeImplicitMvcValues: true);
353 return new RedirectToRouteResult(mergedRouteValues);
356 protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName) {
357 return RedirectToActionPermanent(actionName, (RouteValueDictionary)null);
360 protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, object routeValues) {
361 return RedirectToActionPermanent(actionName, new RouteValueDictionary(routeValues));
364 protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, RouteValueDictionary routeValues) {
365 return RedirectToActionPermanent(actionName, null /* controllerName */, routeValues);
368 protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, string controllerName) {
369 return RedirectToActionPermanent(actionName, controllerName, (RouteValueDictionary)null);
372 protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, string controllerName, object routeValues) {
373 return RedirectToActionPermanent(actionName, controllerName, new RouteValueDictionary(routeValues));
376 protected internal virtual RedirectToRouteResult RedirectToActionPermanent(string actionName, string controllerName, RouteValueDictionary routeValues) {
377 RouteValueDictionary implicitRouteValues = (RouteData != null) ? RouteData.Values : null;
379 RouteValueDictionary mergedRouteValues =
380 RouteValuesHelpers.MergeRouteValues(actionName, controllerName, implicitRouteValues, routeValues, includeImplicitMvcValues: true);
382 return new RedirectToRouteResult(null, mergedRouteValues, permanent: true);
385 protected internal RedirectToRouteResult RedirectToRoute(object routeValues) {
386 return RedirectToRoute(new RouteValueDictionary(routeValues));
389 protected internal RedirectToRouteResult RedirectToRoute(RouteValueDictionary routeValues) {
390 return RedirectToRoute(null /* routeName */, routeValues);
393 protected internal RedirectToRouteResult RedirectToRoute(string routeName) {
394 return RedirectToRoute(routeName, (RouteValueDictionary)null);
397 protected internal RedirectToRouteResult RedirectToRoute(string routeName, object routeValues) {
398 return RedirectToRoute(routeName, new RouteValueDictionary(routeValues));
401 protected internal virtual RedirectToRouteResult RedirectToRoute(string routeName, RouteValueDictionary routeValues) {
402 return new RedirectToRouteResult(routeName, RouteValuesHelpers.GetRouteValues(routeValues));
405 protected internal RedirectToRouteResult RedirectToRoutePermanent(object routeValues) {
406 return RedirectToRoutePermanent(new RouteValueDictionary(routeValues));
409 protected internal RedirectToRouteResult RedirectToRoutePermanent(RouteValueDictionary routeValues) {
410 return RedirectToRoutePermanent(null /* routeName */, routeValues);
413 protected internal RedirectToRouteResult RedirectToRoutePermanent(string routeName) {
414 return RedirectToRoutePermanent(routeName, (RouteValueDictionary)null);
417 protected internal RedirectToRouteResult RedirectToRoutePermanent(string routeName, object routeValues) {
418 return RedirectToRoutePermanent(routeName, new RouteValueDictionary(routeValues));
421 protected internal virtual RedirectToRouteResult RedirectToRoutePermanent(string routeName, RouteValueDictionary routeValues) {
422 return new RedirectToRouteResult(routeName, RouteValuesHelpers.GetRouteValues(routeValues), permanent: true);
425 protected internal bool TryUpdateModel<TModel>(TModel model) where TModel : class {
426 return TryUpdateModel(model, null, null, null, ValueProvider);
429 protected internal bool TryUpdateModel<TModel>(TModel model, string prefix) where TModel : class {
430 return TryUpdateModel(model, prefix, null, null, ValueProvider);
433 protected internal bool TryUpdateModel<TModel>(TModel model, string[] includeProperties) where TModel : class {
434 return TryUpdateModel(model, null, includeProperties, null, ValueProvider);
437 protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties) where TModel : class {
438 return TryUpdateModel(model, prefix, includeProperties, null, ValueProvider);
441 protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) where TModel : class {
442 return TryUpdateModel(model, prefix, includeProperties, excludeProperties, ValueProvider);
445 protected internal bool TryUpdateModel<TModel>(TModel model, IValueProvider valueProvider) where TModel : class {
446 return TryUpdateModel(model, null, null, null, valueProvider);
449 protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, IValueProvider valueProvider) where TModel : class {
450 return TryUpdateModel(model, prefix, null, null, valueProvider);
453 protected internal bool TryUpdateModel<TModel>(TModel model, string[] includeProperties, IValueProvider valueProvider) where TModel : class {
454 return TryUpdateModel(model, null, includeProperties, null, valueProvider);
457 protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, IValueProvider valueProvider) where TModel : class {
458 return TryUpdateModel(model, prefix, includeProperties, null, valueProvider);
461 protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel : class {
463 throw new ArgumentNullException("model");
465 if (valueProvider == null) {
466 throw new ArgumentNullException("valueProvider");
469 Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, includeProperties, excludeProperties);
470 IModelBinder binder = Binders.GetBinder(typeof(TModel));
472 ModelBindingContext bindingContext = new ModelBindingContext() {
473 ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(TModel)),
475 ModelState = ModelState,
476 PropertyFilter = propertyFilter,
477 ValueProvider = valueProvider
479 binder.BindModel(ControllerContext, bindingContext);
480 return ModelState.IsValid;
483 protected internal bool TryValidateModel(object model) {
484 return TryValidateModel(model, null /* prefix */);
487 protected internal bool TryValidateModel(object model, string prefix) {
489 throw new ArgumentNullException("model");
492 ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());
494 foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(metadata, ControllerContext).Validate(null)) {
495 ModelState.AddModelError(DefaultModelBinder.CreateSubPropertyName(prefix, validationResult.MemberName), validationResult.Message);
498 return ModelState.IsValid;
501 protected internal void UpdateModel<TModel>(TModel model) where TModel : class {
502 UpdateModel(model, null, null, null, ValueProvider);
505 protected internal void UpdateModel<TModel>(TModel model, string prefix) where TModel : class {
506 UpdateModel(model, prefix, null, null, ValueProvider);
509 protected internal void UpdateModel<TModel>(TModel model, string[] includeProperties) where TModel : class {
510 UpdateModel(model, null, includeProperties, null, ValueProvider);
513 protected internal void UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties) where TModel : class {
514 UpdateModel(model, prefix, includeProperties, null, ValueProvider);
517 protected internal void UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) where TModel : class {
518 UpdateModel(model, prefix, includeProperties, excludeProperties, ValueProvider);
521 protected internal void UpdateModel<TModel>(TModel model, IValueProvider valueProvider) where TModel : class {
522 UpdateModel(model, null, null, null, valueProvider);
525 protected internal void UpdateModel<TModel>(TModel model, string prefix, IValueProvider valueProvider) where TModel : class {
526 UpdateModel(model, prefix, null, null, valueProvider);
529 protected internal void UpdateModel<TModel>(TModel model, string[] includeProperties, IValueProvider valueProvider) where TModel : class {
530 UpdateModel(model, null, includeProperties, null, valueProvider);
533 protected internal void UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, IValueProvider valueProvider) where TModel : class {
534 UpdateModel(model, prefix, includeProperties, null, valueProvider);
537 protected internal void UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel : class {
538 bool success = TryUpdateModel(model, prefix, includeProperties, excludeProperties, valueProvider);
540 string message = String.Format(CultureInfo.CurrentCulture, MvcResources.Controller_UpdateModel_UpdateUnsuccessful,
541 typeof(TModel).FullName);
542 throw new InvalidOperationException(message);
546 protected internal void ValidateModel(object model) {
547 ValidateModel(model, null /* prefix */);
550 protected internal void ValidateModel(object model, string prefix) {
551 if (!TryValidateModel(model, prefix)) {
552 throw new InvalidOperationException(
554 CultureInfo.CurrentCulture,
555 MvcResources.Controller_Validate_ValidationFailed,
556 model.GetType().FullName
562 protected internal ViewResult View() {
563 return View(null /* viewName */, null /* masterName */, null /* model */);
566 protected internal ViewResult View(object model) {
567 return View(null /* viewName */, null /* masterName */, model);
570 protected internal ViewResult View(string viewName) {
571 return View(viewName, null /* masterName */, null /* model */);
574 protected internal ViewResult View(string viewName, string masterName) {
575 return View(viewName, masterName, null /* model */);
578 protected internal ViewResult View(string viewName, object model) {
579 return View(viewName, null /* masterName */, model);
582 protected internal virtual ViewResult View(string viewName, string masterName, object model) {
584 ViewData.Model = model;
587 return new ViewResult {
589 MasterName = masterName,
595 [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "The method name 'View' is a convenient shorthand for 'CreateViewResult'.")]
596 protected internal ViewResult View(IView view) {
597 return View(view, null /* model */);
600 [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "The method name 'View' is a convenient shorthand for 'CreateViewResult'.")]
601 protected internal virtual ViewResult View(IView view, object model) {
603 ViewData.Model = model;
606 return new ViewResult {
613 #region IActionFilter Members
614 void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext) {
615 OnActionExecuting(filterContext);
618 void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext) {
619 OnActionExecuted(filterContext);
623 #region IAuthorizationFilter Members
624 void IAuthorizationFilter.OnAuthorization(AuthorizationContext filterContext) {
625 OnAuthorization(filterContext);
629 #region IExceptionFilter Members
630 void IExceptionFilter.OnException(ExceptionContext filterContext) {
631 OnException(filterContext);
635 #region IResultFilter Members
636 void IResultFilter.OnResultExecuting(ResultExecutingContext filterContext) {
637 OnResultExecuting(filterContext);
640 void IResultFilter.OnResultExecuted(ResultExecutedContext filterContext) {
641 OnResultExecuted(filterContext);