1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2 
3 using System.Diagnostics.CodeAnalysis;
4 using System.Globalization;
5 using System.IO;
6 using System.Security.Principal;
7 using System.Text;
8 using System.Web.Mvc.Async;
9 using System.Web.Mvc.Properties;
10 using System.Web.Profile;
11 using System.Web.Routing;
12 
13 namespace System.Web.Mvc
14 {
15     [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Class complexity dictated by public surface area")]
16     public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer
17     {
18         private static readonly object _executeTag = new object();
19         private static readonly object _executeCoreTag = new object();
20 
21         private readonly AsyncManager _asyncManager = new AsyncManager();
22         private IActionInvoker _actionInvoker;
23         private ModelBinderDictionary _binders;
24         private RouteCollection _routeCollection;
25         private ITempDataProvider _tempDataProvider;
26         private ViewEngineCollection _viewEngineCollection;
27 
28         private IDependencyResolver _resolver;
29 
30         // By default, use the global resolver with caching.
31         // Or we can override to supply this instance with its own cache.
32         internal IDependencyResolver Resolver
33         {
34             get { return _resolver ?? DependencyResolver.CurrentCache; }
35             set { _resolver = value; }
36         }
37 
38         public AsyncManager AsyncManager
39         {
40             get { return _asyncManager; }
41         }
42 
43         /// <summary>
44         /// This is for backwards compat. MVC 4.0 starts allowing Controller to support asynchronous patterns.
45         /// This means ExecuteCore doesn't get called on derived classes. Derived classes can override this
46         /// flag and set to true if they still need ExecuteCore to be called.
47         /// </summary>
48         protected virtual bool DisableAsyncSupport
49         {
50             get { return false; }
51         }
52 
53         public IActionInvoker ActionInvoker
54         {
55             get
56             {
57                 if (_actionInvoker == null)
58                 {
59                     _actionInvoker = CreateActionInvoker();
60                 }
61                 return _actionInvoker;
62             }
63             set { _actionInvoker = value; }
64         }
65 
66         [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Property is settable so that the dictionary can be provided for unit testing purposes.")]
67         protected internal ModelBinderDictionary Binders
68         {
69             get
70             {
71                 if (_binders == null)
72                 {
73                     _binders = ModelBinders.Binders;
74                 }
75                 return _binders;
76             }
77             set { _binders = value; }
78         }
79 
80         public HttpContextBase HttpContext
81         {
82             get { return ControllerContext == null ? null : ControllerContext.HttpContext; }
83         }
84 
85         public ModelStateDictionary ModelState
86         {
87             get { return ViewData.ModelState; }
88         }
89 
90         public ProfileBase Profile
91         {
92             get { return HttpContext == null ? null : HttpContext.Profile; }
93         }
94 
95         public HttpRequestBase Request
96         {
97             get { return HttpContext == null ? null : HttpContext.Request; }
98         }
99 
100         public HttpResponseBase Response
101         {
102             get { return HttpContext == null ? null : HttpContext.Response; }
103         }
104 
105         internal RouteCollection RouteCollection
106         {
107             get
108             {
109                 if (_routeCollection == null)
110                 {
111                     _routeCollection = RouteTable.Routes;
112                 }
113                 return _routeCollection;
114             }
115             set { _routeCollection = value; }
116         }
117 
118         public RouteData RouteData
119         {
120             get { return ControllerContext == null ? null : ControllerContext.RouteData; }
121         }
122 
123         public HttpServerUtilityBase Server
124         {
125             get { return HttpContext == null ? null : HttpContext.Server; }
126         }
127 
128         public HttpSessionStateBase Session
129         {
130             get { return HttpContext == null ? null : HttpContext.Session; }
131         }
132 
133         public ITempDataProvider TempDataProvider
134         {
135             get
136             {
137                 if (_tempDataProvider == null)
138                 {
139                     _tempDataProvider = CreateTempDataProvider();
140                 }
141                 return _tempDataProvider;
142             }
143             set { _tempDataProvider = value; }
144         }
145 
146         public UrlHelper Url { get; set; }
147 
148         public IPrincipal User
149         {
150             get { return HttpContext == null ? null : HttpContext.User; }
151         }
152 
153         [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This entire type is meant to be mutable.")]
154         public ViewEngineCollection ViewEngineCollection
155         {
156             get { return _viewEngineCollection ?? ViewEngines.Engines; }
157             set { _viewEngineCollection = value; }
158         }
159 
160         [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "'Content' refers to ContentResult type; 'content' refers to ContentResult.Content property.")]
Content(string content)161         protected internal ContentResult Content(string content)
162         {
163             return Content(content, null /* contentType */);
164         }
165 
166         [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "'Content' refers to ContentResult type; 'content' refers to ContentResult.Content property.")]
Content(string content, string contentType)167         protected internal ContentResult Content(string content, string contentType)
168         {
169             return Content(content, contentType, null /* contentEncoding */);
170         }
171 
172         [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "'Content' refers to ContentResult type; 'content' refers to ContentResult.Content property.")]
Content(string content, string contentType, Encoding contentEncoding)173         protected internal virtual ContentResult Content(string content, string contentType, Encoding contentEncoding)
174         {
175             return new ContentResult
176             {
177                 Content = content,
178                 ContentType = contentType,
179                 ContentEncoding = contentEncoding
180             };
181         }
182 
CreateActionInvoker()183         protected virtual IActionInvoker CreateActionInvoker()
184         {
185             // Controller supports asynchronous operations by default.
186             return Resolver.GetService<IAsyncActionInvoker>() ?? Resolver.GetService<IActionInvoker>() ?? new AsyncControllerActionInvoker();
187         }
188 
CreateTempDataProvider()189         protected virtual ITempDataProvider CreateTempDataProvider()
190         {
191             return Resolver.GetService<ITempDataProvider>() ?? new SessionStateTempDataProvider();
192         }
193 
194         // The default invoker will never match methods defined on the Controller type, so
195         // the Dispose() method is not web-callable.  However, in general, since implicitly-
196         // implemented interface methods are public, they are web-callable unless decorated with
197         // [NonAction].
Dispose()198         public void Dispose()
199         {
200             Dispose(true /* disposing */);
201             GC.SuppressFinalize(this);
202         }
203 
Dispose(bool disposing)204         protected virtual void Dispose(bool disposing)
205         {
206         }
207 
ExecuteCore()208         protected override void ExecuteCore()
209         {
210             // If code in this method needs to be updated, please also check the BeginExecuteCore() and
211             // EndExecuteCore() methods of AsyncController to see if that code also must be updated.
212 
213             PossiblyLoadTempData();
214             try
215             {
216                 string actionName = RouteData.GetRequiredString("action");
217                 if (!ActionInvoker.InvokeAction(ControllerContext, actionName))
218                 {
219                     HandleUnknownAction(actionName);
220                 }
221             }
222             finally
223             {
224                 PossiblySaveTempData();
225             }
226         }
227 
File(byte[] fileContents, string contentType)228         protected internal FileContentResult File(byte[] fileContents, string contentType)
229         {
230             return File(fileContents, contentType, null /* fileDownloadName */);
231         }
232 
File(byte[] fileContents, string contentType, string fileDownloadName)233         protected internal virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName)
234         {
235             return new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName };
236         }
237 
File(Stream fileStream, string contentType)238         protected internal FileStreamResult File(Stream fileStream, string contentType)
239         {
240             return File(fileStream, contentType, null /* fileDownloadName */);
241         }
242 
File(Stream fileStream, string contentType, string fileDownloadName)243         protected internal virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName)
244         {
245             return new FileStreamResult(fileStream, contentType) { FileDownloadName = fileDownloadName };
246         }
247 
File(string fileName, string contentType)248         protected internal FilePathResult File(string fileName, string contentType)
249         {
250             return File(fileName, contentType, null /* fileDownloadName */);
251         }
252 
File(string fileName, string contentType, string fileDownloadName)253         protected internal virtual FilePathResult File(string fileName, string contentType, string fileDownloadName)
254         {
255             return new FilePathResult(fileName, contentType) { FileDownloadName = fileDownloadName };
256         }
257 
HandleUnknownAction(string actionName)258         protected virtual void HandleUnknownAction(string actionName)
259         {
260             throw new HttpException(404, String.Format(CultureInfo.CurrentCulture,
261                                                        MvcResources.Controller_UnknownAction, actionName, GetType().FullName));
262         }
263 
HttpNotFound()264         protected internal HttpNotFoundResult HttpNotFound()
265         {
266             return HttpNotFound(null);
267         }
268 
HttpNotFound(string statusDescription)269         protected internal virtual HttpNotFoundResult HttpNotFound(string statusDescription)
270         {
271             return new HttpNotFoundResult(statusDescription);
272         }
273 
JavaScript(string script)274         protected internal virtual JavaScriptResult JavaScript(string script)
275         {
276             return new JavaScriptResult { Script = script };
277         }
278 
Json(object data)279         protected internal JsonResult Json(object data)
280         {
281             return Json(data, null /* contentType */, null /* contentEncoding */, JsonRequestBehavior.DenyGet);
282         }
283 
Json(object data, string contentType)284         protected internal JsonResult Json(object data, string contentType)
285         {
286             return Json(data, contentType, null /* contentEncoding */, JsonRequestBehavior.DenyGet);
287         }
288 
Json(object data, string contentType, Encoding contentEncoding)289         protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding)
290         {
291             return Json(data, contentType, contentEncoding, JsonRequestBehavior.DenyGet);
292         }
293 
Json(object data, JsonRequestBehavior behavior)294         protected internal JsonResult Json(object data, JsonRequestBehavior behavior)
295         {
296             return Json(data, null /* contentType */, null /* contentEncoding */, behavior);
297         }
298 
Json(object data, string contentType, JsonRequestBehavior behavior)299         protected internal JsonResult Json(object data, string contentType, JsonRequestBehavior behavior)
300         {
301             return Json(data, contentType, null /* contentEncoding */, behavior);
302         }
303 
Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)304         protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
305         {
306             return new JsonResult
307             {
308                 Data = data,
309                 ContentType = contentType,
310                 ContentEncoding = contentEncoding,
311                 JsonRequestBehavior = behavior
312             };
313         }
314 
Initialize(RequestContext requestContext)315         protected override void Initialize(RequestContext requestContext)
316         {
317             base.Initialize(requestContext);
318             Url = new UrlHelper(requestContext);
319         }
320 
OnActionExecuting(ActionExecutingContext filterContext)321         protected virtual void OnActionExecuting(ActionExecutingContext filterContext)
322         {
323         }
324 
OnActionExecuted(ActionExecutedContext filterContext)325         protected virtual void OnActionExecuted(ActionExecutedContext filterContext)
326         {
327         }
328 
OnAuthorization(AuthorizationContext filterContext)329         protected virtual void OnAuthorization(AuthorizationContext filterContext)
330         {
331         }
332 
OnException(ExceptionContext filterContext)333         protected virtual void OnException(ExceptionContext filterContext)
334         {
335         }
336 
OnResultExecuted(ResultExecutedContext filterContext)337         protected virtual void OnResultExecuted(ResultExecutedContext filterContext)
338         {
339         }
340 
OnResultExecuting(ResultExecutingContext filterContext)341         protected virtual void OnResultExecuting(ResultExecutingContext filterContext)
342         {
343         }
344 
PartialView()345         protected internal PartialViewResult PartialView()
346         {
347             return PartialView(null /* viewName */, null /* model */);
348         }
349 
PartialView(object model)350         protected internal PartialViewResult PartialView(object model)
351         {
352             return PartialView(null /* viewName */, model);
353         }
354 
PartialView(string viewName)355         protected internal PartialViewResult PartialView(string viewName)
356         {
357             return PartialView(viewName, null /* model */);
358         }
359 
PartialView(string viewName, object model)360         protected internal virtual PartialViewResult PartialView(string viewName, object model)
361         {
362             if (model != null)
363             {
364                 ViewData.Model = model;
365             }
366 
367             return new PartialViewResult
368             {
369                 ViewName = viewName,
370                 ViewData = ViewData,
371                 TempData = TempData,
372                 ViewEngineCollection = ViewEngineCollection
373             };
374         }
375 
PossiblyLoadTempData()376         internal void PossiblyLoadTempData()
377         {
378             if (!ControllerContext.IsChildAction)
379             {
380                 TempData.Load(ControllerContext, TempDataProvider);
381             }
382         }
383 
PossiblySaveTempData()384         internal void PossiblySaveTempData()
385         {
386             if (!ControllerContext.IsChildAction)
387             {
388                 TempData.Save(ControllerContext, TempDataProvider);
389             }
390         }
391 
392         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Response.Redirect() takes its URI as a string parameter.")]
Redirect(string url)393         protected internal virtual RedirectResult Redirect(string url)
394         {
395             if (String.IsNullOrEmpty(url))
396             {
397                 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "url");
398             }
399 
400             return new RedirectResult(url);
401         }
402 
403         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Response.RedirectPermanent() takes its URI as a string parameter.")]
RedirectPermanent(string url)404         protected internal virtual RedirectResult RedirectPermanent(string url)
405         {
406             if (String.IsNullOrEmpty(url))
407             {
408                 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "url");
409             }
410 
411             return new RedirectResult(url, permanent: true);
412         }
413 
RedirectToAction(string actionName)414         protected internal RedirectToRouteResult RedirectToAction(string actionName)
415         {
416             return RedirectToAction(actionName, (RouteValueDictionary)null);
417         }
418 
RedirectToAction(string actionName, object routeValues)419         protected internal RedirectToRouteResult RedirectToAction(string actionName, object routeValues)
420         {
421             return RedirectToAction(actionName, new RouteValueDictionary(routeValues));
422         }
423 
RedirectToAction(string actionName, RouteValueDictionary routeValues)424         protected internal RedirectToRouteResult RedirectToAction(string actionName, RouteValueDictionary routeValues)
425         {
426             return RedirectToAction(actionName, null /* controllerName */, routeValues);
427         }
428 
RedirectToAction(string actionName, string controllerName)429         protected internal RedirectToRouteResult RedirectToAction(string actionName, string controllerName)
430         {
431             return RedirectToAction(actionName, controllerName, (RouteValueDictionary)null);
432         }
433 
RedirectToAction(string actionName, string controllerName, object routeValues)434         protected internal RedirectToRouteResult RedirectToAction(string actionName, string controllerName, object routeValues)
435         {
436             return RedirectToAction(actionName, controllerName, new RouteValueDictionary(routeValues));
437         }
438 
RedirectToAction(string actionName, string controllerName, RouteValueDictionary routeValues)439         protected internal virtual RedirectToRouteResult RedirectToAction(string actionName, string controllerName, RouteValueDictionary routeValues)
440         {
441             RouteValueDictionary mergedRouteValues;
442 
443             if (RouteData == null)
444             {
445                 mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, null, routeValues, includeImplicitMvcValues: true);
446             }
447             else
448             {
449                 mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, RouteData.Values, routeValues, includeImplicitMvcValues: true);
450             }
451 
452             return new RedirectToRouteResult(mergedRouteValues);
453         }
454 
RedirectToActionPermanent(string actionName)455         protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName)
456         {
457             return RedirectToActionPermanent(actionName, (RouteValueDictionary)null);
458         }
459 
RedirectToActionPermanent(string actionName, object routeValues)460         protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, object routeValues)
461         {
462             return RedirectToActionPermanent(actionName, new RouteValueDictionary(routeValues));
463         }
464 
RedirectToActionPermanent(string actionName, RouteValueDictionary routeValues)465         protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, RouteValueDictionary routeValues)
466         {
467             return RedirectToActionPermanent(actionName, null /* controllerName */, routeValues);
468         }
469 
RedirectToActionPermanent(string actionName, string controllerName)470         protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, string controllerName)
471         {
472             return RedirectToActionPermanent(actionName, controllerName, (RouteValueDictionary)null);
473         }
474 
RedirectToActionPermanent(string actionName, string controllerName, object routeValues)475         protected internal RedirectToRouteResult RedirectToActionPermanent(string actionName, string controllerName, object routeValues)
476         {
477             return RedirectToActionPermanent(actionName, controllerName, new RouteValueDictionary(routeValues));
478         }
479 
RedirectToActionPermanent(string actionName, string controllerName, RouteValueDictionary routeValues)480         protected internal virtual RedirectToRouteResult RedirectToActionPermanent(string actionName, string controllerName, RouteValueDictionary routeValues)
481         {
482             RouteValueDictionary implicitRouteValues = (RouteData != null) ? RouteData.Values : null;
483 
484             RouteValueDictionary mergedRouteValues =
485                 RouteValuesHelpers.MergeRouteValues(actionName, controllerName, implicitRouteValues, routeValues, includeImplicitMvcValues: true);
486 
487             return new RedirectToRouteResult(null, mergedRouteValues, permanent: true);
488         }
489 
RedirectToRoute(object routeValues)490         protected internal RedirectToRouteResult RedirectToRoute(object routeValues)
491         {
492             return RedirectToRoute(new RouteValueDictionary(routeValues));
493         }
494 
RedirectToRoute(RouteValueDictionary routeValues)495         protected internal RedirectToRouteResult RedirectToRoute(RouteValueDictionary routeValues)
496         {
497             return RedirectToRoute(null /* routeName */, routeValues);
498         }
499 
RedirectToRoute(string routeName)500         protected internal RedirectToRouteResult RedirectToRoute(string routeName)
501         {
502             return RedirectToRoute(routeName, (RouteValueDictionary)null);
503         }
504 
RedirectToRoute(string routeName, object routeValues)505         protected internal RedirectToRouteResult RedirectToRoute(string routeName, object routeValues)
506         {
507             return RedirectToRoute(routeName, new RouteValueDictionary(routeValues));
508         }
509 
RedirectToRoute(string routeName, RouteValueDictionary routeValues)510         protected internal virtual RedirectToRouteResult RedirectToRoute(string routeName, RouteValueDictionary routeValues)
511         {
512             return new RedirectToRouteResult(routeName, RouteValuesHelpers.GetRouteValues(routeValues));
513         }
514 
RedirectToRoutePermanent(object routeValues)515         protected internal RedirectToRouteResult RedirectToRoutePermanent(object routeValues)
516         {
517             return RedirectToRoutePermanent(new RouteValueDictionary(routeValues));
518         }
519 
RedirectToRoutePermanent(RouteValueDictionary routeValues)520         protected internal RedirectToRouteResult RedirectToRoutePermanent(RouteValueDictionary routeValues)
521         {
522             return RedirectToRoutePermanent(null /* routeName */, routeValues);
523         }
524 
RedirectToRoutePermanent(string routeName)525         protected internal RedirectToRouteResult RedirectToRoutePermanent(string routeName)
526         {
527             return RedirectToRoutePermanent(routeName, (RouteValueDictionary)null);
528         }
529 
RedirectToRoutePermanent(string routeName, object routeValues)530         protected internal RedirectToRouteResult RedirectToRoutePermanent(string routeName, object routeValues)
531         {
532             return RedirectToRoutePermanent(routeName, new RouteValueDictionary(routeValues));
533         }
534 
RedirectToRoutePermanent(string routeName, RouteValueDictionary routeValues)535         protected internal virtual RedirectToRouteResult RedirectToRoutePermanent(string routeName, RouteValueDictionary routeValues)
536         {
537             return new RedirectToRouteResult(routeName, RouteValuesHelpers.GetRouteValues(routeValues), permanent: true);
538         }
539 
540         protected internal bool TryUpdateModel<TModel>(TModel model) where TModel : class
541         {
542             return TryUpdateModel(model, null, null, null, ValueProvider);
543         }
544 
545         protected internal bool TryUpdateModel<TModel>(TModel model, string prefix) where TModel : class
546         {
547             return TryUpdateModel(model, prefix, null, null, ValueProvider);
548         }
549 
550         protected internal bool TryUpdateModel<TModel>(TModel model, string[] includeProperties) where TModel : class
551         {
552             return TryUpdateModel(model, null, includeProperties, null, ValueProvider);
553         }
554 
555         protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties) where TModel : class
556         {
557             return TryUpdateModel(model, prefix, includeProperties, null, ValueProvider);
558         }
559 
560         protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) where TModel : class
561         {
562             return TryUpdateModel(model, prefix, includeProperties, excludeProperties, ValueProvider);
563         }
564 
565         protected internal bool TryUpdateModel<TModel>(TModel model, IValueProvider valueProvider) where TModel : class
566         {
567             return TryUpdateModel(model, null, null, null, valueProvider);
568         }
569 
570         protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, IValueProvider valueProvider) where TModel : class
571         {
572             return TryUpdateModel(model, prefix, null, null, valueProvider);
573         }
574 
575         protected internal bool TryUpdateModel<TModel>(TModel model, string[] includeProperties, IValueProvider valueProvider) where TModel : class
576         {
577             return TryUpdateModel(model, null, includeProperties, null, valueProvider);
578         }
579 
580         protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, IValueProvider valueProvider) where TModel : class
581         {
582             return TryUpdateModel(model, prefix, includeProperties, null, valueProvider);
583         }
584 
585         protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel : class
586         {
587             if (model == null)
588             {
589                 throw new ArgumentNullException("model");
590             }
591             if (valueProvider == null)
592             {
593                 throw new ArgumentNullException("valueProvider");
594             }
595 
596             Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, includeProperties, excludeProperties);
597             IModelBinder binder = Binders.GetBinder(typeof(TModel));
598 
599             ModelBindingContext bindingContext = new ModelBindingContext()
600             {
601                 ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(TModel)),
602                 ModelName = prefix,
603                 ModelState = ModelState,
604                 PropertyFilter = propertyFilter,
605                 ValueProvider = valueProvider
606             };
binder.BindModel(ControllerContext, bindingContext)607             binder.BindModel(ControllerContext, bindingContext);
608             return ModelState.IsValid;
609         }
610 
TryValidateModel(object model)611         protected internal bool TryValidateModel(object model)
612         {
613             return TryValidateModel(model, null /* prefix */);
614         }
615 
TryValidateModel(object model, string prefix)616         protected internal bool TryValidateModel(object model, string prefix)
617         {
618             if (model == null)
619             {
620                 throw new ArgumentNullException("model");
621             }
622 
623             ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());
624 
625             foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(metadata, ControllerContext).Validate(null))
626             {
627                 ModelState.AddModelError(DefaultModelBinder.CreateSubPropertyName(prefix, validationResult.MemberName), validationResult.Message);
628             }
629 
630             return ModelState.IsValid;
631         }
632 
633         protected internal void UpdateModel<TModel>(TModel model) where TModel : class
634         {
UpdateModel(model, null, null, null, ValueProvider)635             UpdateModel(model, null, null, null, ValueProvider);
636         }
637 
638         protected internal void UpdateModel<TModel>(TModel model, string prefix) where TModel : class
639         {
UpdateModel(model, prefix, null, null, ValueProvider)640             UpdateModel(model, prefix, null, null, ValueProvider);
641         }
642 
643         protected internal void UpdateModel<TModel>(TModel model, string[] includeProperties) where TModel : class
644         {
UpdateModel(model, null, includeProperties, null, ValueProvider)645             UpdateModel(model, null, includeProperties, null, ValueProvider);
646         }
647 
648         protected internal void UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties) where TModel : class
649         {
UpdateModel(model, prefix, includeProperties, null, ValueProvider)650             UpdateModel(model, prefix, includeProperties, null, ValueProvider);
651         }
652 
653         protected internal void UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) where TModel : class
654         {
UpdateModel(model, prefix, includeProperties, excludeProperties, ValueProvider)655             UpdateModel(model, prefix, includeProperties, excludeProperties, ValueProvider);
656         }
657 
658         protected internal void UpdateModel<TModel>(TModel model, IValueProvider valueProvider) where TModel : class
659         {
UpdateModel(model, null, null, null, valueProvider)660             UpdateModel(model, null, null, null, valueProvider);
661         }
662 
663         protected internal void UpdateModel<TModel>(TModel model, string prefix, IValueProvider valueProvider) where TModel : class
664         {
UpdateModel(model, prefix, null, null, valueProvider)665             UpdateModel(model, prefix, null, null, valueProvider);
666         }
667 
668         protected internal void UpdateModel<TModel>(TModel model, string[] includeProperties, IValueProvider valueProvider) where TModel : class
669         {
UpdateModel(model, null, includeProperties, null, valueProvider)670             UpdateModel(model, null, includeProperties, null, valueProvider);
671         }
672 
673         protected internal void UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, IValueProvider valueProvider) where TModel : class
674         {
UpdateModel(model, prefix, includeProperties, null, valueProvider)675             UpdateModel(model, prefix, includeProperties, null, valueProvider);
676         }
677 
678         protected internal void UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel : class
679         {
680             bool success = TryUpdateModel(model, prefix, includeProperties, excludeProperties, valueProvider);
681             if (!success)
682             {
683                 string message = String.Format(CultureInfo.CurrentCulture, MvcResources.Controller_UpdateModel_UpdateUnsuccessful,
684                                                typeof(TModel).FullName);
685                 throw new InvalidOperationException(message);
686             }
687         }
688 
ValidateModel(object model)689         protected internal void ValidateModel(object model)
690         {
691             ValidateModel(model, null /* prefix */);
692         }
693 
ValidateModel(object model, string prefix)694         protected internal void ValidateModel(object model, string prefix)
695         {
696             if (!TryValidateModel(model, prefix))
697             {
698                 throw new InvalidOperationException(
699                     String.Format(
700                         CultureInfo.CurrentCulture,
701                         MvcResources.Controller_Validate_ValidationFailed,
702                         model.GetType().FullName));
703             }
704         }
705 
View()706         protected internal ViewResult View()
707         {
708             return View(viewName: null, masterName: null, model: null);
709         }
710 
View(object model)711         protected internal ViewResult View(object model)
712         {
713             return View(null /* viewName */, null /* masterName */, model);
714         }
715 
View(string viewName)716         protected internal ViewResult View(string viewName)
717         {
718             return View(viewName, masterName: null, model: null);
719         }
720 
View(string viewName, string masterName)721         protected internal ViewResult View(string viewName, string masterName)
722         {
723             return View(viewName, masterName, null /* model */);
724         }
725 
View(string viewName, object model)726         protected internal ViewResult View(string viewName, object model)
727         {
728             return View(viewName, null /* masterName */, model);
729         }
730 
View(string viewName, string masterName, object model)731         protected internal virtual ViewResult View(string viewName, string masterName, object model)
732         {
733             if (model != null)
734             {
735                 ViewData.Model = model;
736             }
737 
738             return new ViewResult
739             {
740                 ViewName = viewName,
741                 MasterName = masterName,
742                 ViewData = ViewData,
743                 TempData = TempData,
744                 ViewEngineCollection = ViewEngineCollection
745             };
746         }
747 
748         [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "The method name 'View' is a convenient shorthand for 'CreateViewResult'.")]
View(IView view)749         protected internal ViewResult View(IView view)
750         {
751             return View(view, null /* model */);
752         }
753 
754         [SuppressMessage("Microsoft.Naming", "CA1719:ParameterNamesShouldNotMatchMemberNames", MessageId = "0#", Justification = "The method name 'View' is a convenient shorthand for 'CreateViewResult'.")]
View(IView view, object model)755         protected internal virtual ViewResult View(IView view, object model)
756         {
757             if (model != null)
758             {
759                 ViewData.Model = model;
760             }
761 
762             return new ViewResult
763             {
764                 View = view,
765                 ViewData = ViewData,
766                 TempData = TempData
767             };
768         }
769 
IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)770         IAsyncResult IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
771         {
772             return BeginExecute(requestContext, callback, state);
773         }
774 
IAsyncController.EndExecute(IAsyncResult asyncResult)775         void IAsyncController.EndExecute(IAsyncResult asyncResult)
776         {
777             EndExecute(asyncResult);
778         }
779 
BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)780         protected virtual IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
781         {
782             if (DisableAsyncSupport)
783             {
784                 // For backwards compat, we can disallow async support and just chain to the sync Execute() function.
785                 Action action = () =>
786                 {
787                     Execute(requestContext);
788                 };
789 
790                 return AsyncResultWrapper.BeginSynchronous(callback, state, action, _executeTag);
791             }
792             else
793             {
794                 if (requestContext == null)
795                 {
796                     throw new ArgumentNullException("requestContext");
797                 }
798 
799                 // Support Asynchronous behavior.
800                 // Execute/ExecuteCore are no longer called.
801 
802                 VerifyExecuteCalledOnce();
803                 Initialize(requestContext);
804                 return AsyncResultWrapper.Begin(callback, state, BeginExecuteCore, EndExecuteCore, _executeTag);
805             }
806         }
807 
BeginExecuteCore(AsyncCallback callback, object state)808         protected virtual IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
809         {
810             // If code in this method needs to be updated, please also check the ExecuteCore() method
811             // of Controller to see if that code also must be updated.
812             PossiblyLoadTempData();
813             try
814             {
815                 string actionName = RouteData.GetRequiredString("action");
816                 IActionInvoker invoker = ActionInvoker;
817                 IAsyncActionInvoker asyncInvoker = invoker as IAsyncActionInvoker;
818                 if (asyncInvoker != null)
819                 {
820                     // asynchronous invocation
821                     BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState)
822                     {
823                         return asyncInvoker.BeginInvokeAction(ControllerContext, actionName, asyncCallback, asyncState);
824                     };
825 
826                     EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult)
827                     {
828                         if (!asyncInvoker.EndInvokeAction(asyncResult))
829                         {
830                             HandleUnknownAction(actionName);
831                         }
832                     };
833 
834                     return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, _executeCoreTag);
835                 }
836                 else
837                 {
838                     // synchronous invocation
839                     Action action = () =>
840                     {
841                         if (!invoker.InvokeAction(ControllerContext, actionName))
842                         {
843                             HandleUnknownAction(actionName);
844                         }
845                     };
846                     return AsyncResultWrapper.BeginSynchronous(callback, state, action, _executeCoreTag);
847                 }
848             }
849             catch
850             {
851                 PossiblySaveTempData();
852                 throw;
853             }
854         }
855 
EndExecute(IAsyncResult asyncResult)856         protected virtual void EndExecute(IAsyncResult asyncResult)
857         {
858             AsyncResultWrapper.End(asyncResult, _executeTag);
859         }
860 
EndExecuteCore(IAsyncResult asyncResult)861         protected virtual void EndExecuteCore(IAsyncResult asyncResult)
862         {
863             // If code in this method needs to be updated, please also check the ExecuteCore() method
864             // of Controller to see if that code also must be updated.
865 
866             try
867             {
868                 AsyncResultWrapper.End(asyncResult, _executeCoreTag);
869             }
870             finally
871             {
872                 PossiblySaveTempData();
873             }
874         }
875 
876         #region IActionFilter Members
877 
IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)878         void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
879         {
880             OnActionExecuting(filterContext);
881         }
882 
IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)883         void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
884         {
885             OnActionExecuted(filterContext);
886         }
887 
888         #endregion
889 
890         #region IAuthorizationFilter Members
891 
IAuthorizationFilter.OnAuthorization(AuthorizationContext filterContext)892         void IAuthorizationFilter.OnAuthorization(AuthorizationContext filterContext)
893         {
894             OnAuthorization(filterContext);
895         }
896 
897         #endregion
898 
899         #region IExceptionFilter Members
900 
IExceptionFilter.OnException(ExceptionContext filterContext)901         void IExceptionFilter.OnException(ExceptionContext filterContext)
902         {
903             OnException(filterContext);
904         }
905 
906         #endregion
907 
908         #region IResultFilter Members
909 
IResultFilter.OnResultExecuting(ResultExecutingContext filterContext)910         void IResultFilter.OnResultExecuting(ResultExecutingContext filterContext)
911         {
912             OnResultExecuting(filterContext);
913         }
914 
IResultFilter.OnResultExecuted(ResultExecutedContext filterContext)915         void IResultFilter.OnResultExecuted(ResultExecutedContext filterContext)
916         {
917             OnResultExecuted(filterContext);
918         }
919 
920         #endregion
921     }
922 }
923