/// <summary> /// Maps a navigation parameters to target action parameter. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="bindingContext">The binding context.</param> /// <returns> /// The value that will be supplied to the action. /// </returns> public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var requestParameter = bindingContext.RouteValues.FirstOrDefault(x => string.Equals(x.Key, bindingContext.TargetParameterName, StringComparison.InvariantCultureIgnoreCase)); if (requestParameter.Key == null) { TraceSources.MagellanSource.TraceError("DefaultModelBinder could not find a parameter '{0}' for the action method '{1}' in the list of navigation parameters.", controllerContext.ActionName, bindingContext.TargetParameterName); throw new ArgumentException(string.Format("The action '{0}' on controller '{1}' requires a parameter named '{2}', which was not supplied.", controllerContext.ActionName, controllerContext.Controller.GetType().FullName, bindingContext.TargetParameterName)); } var source = requestParameter.Value; if (source == null) { TraceSources.MagellanSource.TraceWarning("The parameter '{0}' which was supplied to action '{1}' was null, but the parameter is declared as type '{2}', which is a value type. DefaultModelBinder is creating a new default instance of the type instead.", bindingContext.TargetParameterName, controllerContext.ActionName, bindingContext.TargetParameterType ); return bindingContext.TargetParameterType.IsValueType ? Activator.CreateInstance(bindingContext.TargetParameterType) : null; } if (bindingContext.TargetParameterType.IsAssignableFrom(source.GetType())) { return source; } return Convert.ChangeType(source, bindingContext.TargetParameterType, CultureInfo.InvariantCulture); }
/// <summary> /// Initializes a new instance of the <see cref="ChildWindowViewEngineResult"/> class. /// </summary> /// <param name="viewActivator">The view activator.</param> /// <param name="type">The type.</param> /// <param name="options">The options.</param> /// <param name="controllerContext">The controller context.</param> public ChildWindowViewEngineResult(IViewActivator viewActivator, Type type, ViewResultOptions options, ControllerContext controllerContext) : base(controllerContext, options) { _viewActivator = viewActivator; _type = type; _options = options; }
private static MethodInfo SelectBestActionMethod(ControllerContext controllerContext, string actionName) { var type = controllerContext.Controller.GetType(); var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); var candidateMethods = methods.Where(x => HasMatchingSignature(x, actionName)).ToList(); if (candidateMethods.Count == 1) { var result = candidateMethods.First(); TraceSources.MagellanSource.TraceVerbose("DefaultActionInvoker found the action '{0}' as method '{1}'", actionName, result); return result; } if (candidateMethods.Count > 1) { var result = candidateMethods .OrderBy(x => x.GetParameters().Length) .LastOrDefault( candidate => candidate.GetParameters().Select(x => x.Name) .HasSameItemsRegardlessOfSortOrder(controllerContext.Request.RouteValues.Select(x => x.Key)) ); TraceSources.MagellanSource.TraceVerbose("DefaultActionInvoker found multiple methods for the action '{0}'. The method selected was '{1}'.", actionName, result); return result; } TraceSources.MagellanSource.TraceError("DefaultActionInvoker could not find a method for the action '{0}'.", actionName); return null; }
/// <summary> /// When implemented in a derived class, allows the derived class to restrict the criteria used to select potential types. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="options">The view parameters.</param> /// <param name="viewName">Name of the view.</param> /// <param name="candidates">The list of candidate types.</param> /// <returns></returns> protected override IEnumerable<Type> FilterCandidateTypes(ControllerContext controllerContext, ViewResultOptions options, string viewName, IEnumerable<Type> candidates) { if (options.GetRegionName() != null || options.GetRegion() != null) { return candidates.Where(type => typeof (UIElement).IsAssignableFrom(type)); } return new Type[0]; }
/// <summary> /// When implemented in a derived class, resolves an action by the given name on the controller. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="actionName">Name of the action.</param> /// <returns> /// An implementation of <see cref="IActionDescriptor"/>, or null if no action could be found. /// </returns> protected override IActionDescriptor FindAction(ControllerContext controllerContext, string actionName) { Guard.ArgumentNotNull(controllerContext, "controllerContext"); Guard.ArgumentNotNullOrEmpty(actionName, "actionName"); var method = SelectBestActionMethod(controllerContext, actionName); return method == null ? null : new DelegateActionDescriptor(method, controllerContext.Controller); }
/// <summary> /// When implemented in a derived class, performs the bulk of the action rendering. /// </summary> /// <param name="controllerContext">The controller context.</param> protected override void ExecuteInternal(ControllerContext controllerContext) { TraceSources.MagellanSource.TraceInformation("The StartProcessResult is launching the process '{0}'.", startInfo.FileName); StartedProcess = Process.Start(startInfo); if (waitForExit) { TraceSources.MagellanSource.TraceInformation("The StartProcessResult is waiting for the process '{0}' to exit.", startInfo.FileName); StartedProcess.WaitForExit(); } }
/// <summary> /// When implemented in a derived class, performs the bulk of the action rendering. /// </summary> /// <param name="controllerContext">The controller context.</param> protected override void ExecuteInternal(ControllerContext controllerContext) { TraceSources.MagellanSource.TraceVerbose("The RedirectResult is navigating to the request '{0}'.", NewRequest); var dispatcher = controllerContext.Request.Navigator.Dispatcher; dispatcher.Dispatch( delegate { controllerContext.Request.Navigator.Navigate(NewRequest); }); }
/// <summary> /// Given a controller and the start of a namespace, generates a set of combinations where views /// may be kept. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="baseNamespace">The base namespace.</param> /// <param name="viewName">Name of the view.</param> /// <returns> /// A collection of possible view namespaces. /// </returns> public virtual IEnumerable<string> GetNamespaces(ControllerContext controllerContext, string baseNamespace, string viewName) { return new[] { baseNamespace + ".Views." + controllerContext.ControllerName, baseNamespace + ".Views." + viewName, baseNamespace + ".Views." + controllerContext.ControllerName + "." + viewName, baseNamespace + ".Views", baseNamespace + "." + controllerContext.ControllerName, baseNamespace }; }
/// <summary> /// When implemented in a derived class, performs the bulk of the action rendering. /// </summary> /// <param name="controllerContext">The controller context.</param> protected override void ExecuteInternal(ControllerContext controllerContext) { TraceSources.MagellanSource.TraceInformation("BackResult is rendering for request '{0}'. RemoveFromJournal is {1}", controllerContext.Request, removeFromJournal); var dispatcher = controllerContext.Request.Navigator.Dispatcher; dispatcher.Dispatch( delegate { var navigationService = controllerContext.Request.Navigator; navigationService.GoBack(removeFromJournal); }); }
/// <summary> /// Executes the action result. /// </summary> /// <param name="controllerContext"></param> protected override void ExecuteInternal(ControllerContext controllerContext) { Guard.ArgumentNotNull(controllerContext, "controllerContext"); var viewName = this.viewName ?? controllerContext.ActionName; ViewEngineResult = viewEngines.FindView(controllerContext, Options, viewName); if (ViewEngineResult.Success) { ViewEngineResult.Render(); } else { throw new ViewNotFoundException(controllerContext.ControllerName, controllerContext.ActionName, viewName, ViewEngineResult.SearchLocations); } }
/// <summary> /// When implemented in a derived class, finds all pre and post <see cref="IResultFilter">result filters</see> that apply to the given action. /// </summary> /// <param name="action">The action.</param> /// <param name="controllerContext">The controller context.</param> /// <param name="actionName">Name of the action.</param> /// <returns></returns> protected override IEnumerable<IResultFilter> FindResultFilters(IActionDescriptor action, ControllerContext controllerContext, string actionName) { Guard.ArgumentNotNull(action, "action"); Guard.ArgumentNotNull(controllerContext, "controllerContext"); Guard.ArgumentNotNullOrEmpty(actionName, "actionName"); Guard.ArgumentIsOfType(action, typeof(DelegateActionDescriptor), "action"); var delegateDescriptor = (DelegateActionDescriptor)action; var attributeSources = new ICustomAttributeProvider[] { delegateDescriptor.Method, controllerContext.Controller.GetType() }; var filters = attributeSources.SelectMany(x => x.GetCustomAttributes(true)).Select(x => x as IResultFilter).Where(x => x != null).ToList(); TraceSources.MagellanSource.TraceVerbose("DefaultActionInvoker found the following result filters for action '{0}': '{1}'.", actionName, string.Join(", ", filters.Select(x => x.GetType().Name).ToArray()) ); return filters; }
/// <summary> /// Executes the action on the specified controller. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="actionName">Name of the action.</param> /// <param name="modelBinders">The model binders.</param> public override void ExecuteAction(ControllerContext controllerContext, string actionName, ModelBinderDictionary modelBinders) { var dispatcher = controllerContext.Request.Navigator.Dispatcher; ThreadPool.QueueUserWorkItem( delegate { Thread.CurrentThread.Name = string.Format("Navigation request: {0}", controllerContext.Request); try { ExecuteBase(controllerContext, actionName, modelBinders); } catch (Exception ex) { var rethrower = new Rethrower( string.Format("An exception occurred when attempting to asynchronously execute the request '{0}'. {1}", controllerContext.Request, ex.Message), ex); dispatcher.Dispatch(rethrower.RethrowOnDispatchThread); } }); }
protected ViewEngineResult FindViewForController(string controllerName, string viewName, object viewParameters) { var controllerType = Project.Assembly.GetType(controllerName, true); var controllerShortName = Path.GetExtension(controllerName.Replace("Controller", "")).Substring(1); var context = new ControllerContext(Activator.CreateInstance(controllerType) as IController, new ResolvedNavigationRequest( new Uri("magellan://foobar"), "foobar", true, new Mock<INavigator>().Object, new Mock<IRoute>().Object, new RouteValueDictionary(new{controller = controllerShortName, action = "x"}), new List<INavigationProgressListener>() ), ViewEngines.CreateDefaults()); var viewEngine = _viewEngineCreator(); return viewEngine.FindView(context, new ViewResultOptions(viewParameters), viewName); }
/// <summary> /// Executes the action on the controller using the parameters and model binders in the current request. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="modelBinders">The model binders.</param> /// <returns> /// The <see cref="ActionResult"/> returned by the controller action. /// </returns> public ActionResult Execute(ControllerContext controllerContext, ModelBinderDictionary modelBinders) { var arguments = new List<object>(); foreach (var parameterInfo in method.GetParameters()) { var bindingContext = new ModelBindingContext(parameterInfo.Name, Method, parameterInfo.ParameterType, controllerContext.Request.RouteValues); var binder = modelBinders.GetBinder(parameterInfo.ParameterType); var argument = binder.BindModel(controllerContext.Request, bindingContext); arguments.Add(argument); } try { var wrapper = DelegateInvoker.CreateInvoker(controller, method); return (ActionResult) wrapper.Call(arguments.ToArray()); } catch (Exception ex) { TraceSources.MagellanSource.TraceError(ex, "The action '{0}' on controller '{1} threw an exception.", controllerContext.ActionName, controllerContext.ActionName); throw; } }
private ActionResult ExecuteAction(ControllerContext controllerContext, ModelBinderDictionary modelBinders, string actionName, IActionDescriptor actionDescriptor) { var filters = FindActionFilters(actionDescriptor, controllerContext, actionName); var result = ExecutePreActionFilters(controllerContext, modelBinders, filters); // If one of the filters gave us a result, we can short-circuit calling the action and skip ahead if (result != null) return result; controllerContext.Request.ReportProgress(new ExecutingActionNavigationEvent()); try { // Invoke the action on the controller result = actionDescriptor.Execute(controllerContext, modelBinders); } catch (Exception ex) { // Give post-filters a chance to suppress or handle the exception var errorFilterResult = ExecutePostActionFilters(controllerContext, result, ex, filters); if (errorFilterResult.ExceptionHandled || errorFilterResult.Exception == null) return errorFilterResult.Result; if (ex == errorFilterResult.Exception) throw; throw errorFilterResult.Exception; } // Give post-filters a chance rewrite the result var filterResult = ExecutePostActionFilters(controllerContext, result, null, filters); if (filterResult.ExceptionHandled || filterResult.Exception == null) return filterResult.Result; throw filterResult.Exception; }
/// <summary> /// Executes the action on the specified controller. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="actionName">Name of the action.</param> /// <param name="modelBinders">The model binders.</param> public virtual void ExecuteAction(ControllerContext controllerContext, string actionName, ModelBinderDictionary modelBinders) { try { Guard.ArgumentNotNull(controllerContext, "controllerContext"); Guard.ArgumentNotNull(modelBinders, "modelBinders"); Guard.ArgumentNotNullOrEmpty(actionName, "actionName"); controllerContext.Request.ReportProgress(new ResolvingActionNavigationEvent()); var actionDescriptor = FindAction(controllerContext, actionName); if (actionDescriptor == null) { throw new ActionNotFoundException(string.Format("An action by the name '{0}' could not be found on the controller '{1}'. In general, actions should be public instance methods, and should return ActionResult or a derived type. Please ensure the action exists, has a valid signature and the name is spelled correctly.", actionName, controllerContext.Controller.GetType())); } var actionResult = ExecuteAction(controllerContext, modelBinders, actionName, actionDescriptor); ExecuteResult(actionDescriptor, controllerContext, actionName, actionResult); } finally { controllerContext.Dispose(); TraceSources.MagellanSource.TraceInformation("Request completed: '{0}'.", controllerContext.Request); } }
private IEnumerable<Type> FindTypesNamed(ControllerContext controllerContext, IEnumerable<string> names) { var types = GetAllTypesFromAllAssemblies(controllerContext); return names.SelectMany(name => types.Where(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase))); }
private IEnumerable<string> CreateShortlistOfNamespacesInWhichToSearch(ControllerContext controllerContext, string view) { var current = controllerContext.Controller.GetType().Namespace; while (current != null && current.Trim().Length > 0) { foreach (var alternative in NamespaceConvention.GetNamespaces(controllerContext, current, view)) yield return alternative; var lastDot = current.LastIndexOf('.'); if (lastDot < 0) break; current = current.Substring(0, lastDot); } yield return null; }
/// <summary> /// Initializes a new instance of the <see cref="ResultExecutingContext"/> class. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="result">The result.</param> public ResultExecutingContext(ControllerContext controllerContext, ActionResult result) { Result = result; this.controllerContext = controllerContext; }
/// <summary> /// When implemented in a derived class, finds all pre and post <see cref="IResultFilter">result filters</see> that apply to the given action. /// </summary> /// <param name="action">The action.</param> /// <param name="controllerContext">The controller context.</param> /// <param name="actionName">Name of the action.</param> /// <returns></returns> protected abstract IEnumerable<IResultFilter> FindResultFilters(IActionDescriptor action, ControllerContext controllerContext, string actionName);
/// <summary> /// Invokes all post-request filters after the controller has been invoked. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="result">The result.</param> /// <param name="ex">The ex.</param> /// <param name="filters">The filters.</param> /// <returns></returns> protected virtual ActionExecutedContext ExecutePostActionFilters(ControllerContext controllerContext, ActionResult result, Exception ex, IEnumerable<IActionFilter> filters) { controllerContext.Request.ReportProgress(new PostActionFiltersNavigationEvent()); var executedContext = new ActionExecutedContext(controllerContext, result, ex); foreach (var filter in filters) { filter.OnActionExecuted(executedContext); } return executedContext; }
private IEnumerable<Type> GetAllTypesFromAllAssemblies(ControllerContext controllerContext) { var assembly = controllerContext.Controller.GetType().Assembly; return assembly.GetTypes().Union( additionalViewAssemblies.SelectMany(x => x.GetTypes()) ); }
/// <summary> /// Attempts to find the view, or returns information about the locations that were searched. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="options">The view parameters.</param> /// <param name="view">The view.</param> /// <returns> /// A <see cref="ViewEngineResult"/> containing the resolved view or information about the locations that were searched. /// </returns> public ViewEngineResult FindView(ControllerContext controllerContext, ViewResultOptions options, string view) { if (!ShouldHandle(controllerContext, options, view)) { return new ViewEngineResult(false, new string[0]); } var possibleViewNames = NamingConvention.GetAlternativeNames(controllerContext, view); var allTypes = FindTypesNamed(controllerContext, possibleViewNames); var candidateTypes = FilterCandidateTypes(controllerContext, options, view, allTypes); var namespaces = CreateShortlistOfNamespacesInWhichToSearch(controllerContext, view); var match = namespaces.Select(ns => FindFirstTypeInNamespace(candidateTypes, ns)).Where(x => x != null).FirstOrDefault(); if (match != null) { return CreateViewResult(controllerContext, options, match); } // Make a list of all search examples used above to create a friendly error message var searchAttempts = namespaces.SelectMany(ns => possibleViewNames.Select(name => string.IsNullOrEmpty(ns) ? string.Format("{0}", name) : string.Format("{0}.{1}", ns, name) )); TraceSources.MagellanSource.TraceInformation("The {0} could not find the view '{1}'. The following locations were searched: \r\n{2}", GetType().FullName, view, string.Join("\r\n- ", searchAttempts.ToArray())); return new ViewEngineResult(false, searchAttempts); }
/// <summary> /// When implemented in a derived class, allows the derived class to restrict the criteria used to select potential types. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="options">The view parameters.</param> /// <param name="viewName">Name of the view.</param> /// <param name="candidates">The list of candidate types.</param> /// <returns></returns> protected abstract IEnumerable<Type> FilterCandidateTypes(ControllerContext controllerContext, ViewResultOptions options, string viewName, IEnumerable<Type> candidates);
/// <summary> /// When implemented in a derived class, indicated whether this view engine should even attempt to /// locate views and handle the request. If this method returns false, no reflection will be /// performed. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="options">The view parameters.</param> /// <param name="viewName">Name of the view.</param> /// <returns></returns> protected virtual bool ShouldHandle(ControllerContext controllerContext, ViewResultOptions options, string viewName) { return true; }
/// <summary> /// When implemented in a derived class, resolves an action by the given name on the controller. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="actionName">Name of the action.</param> /// <returns>An implementation of <see cref="IActionDescriptor"/>, or null if no action could be found.</returns> protected abstract IActionDescriptor FindAction(ControllerContext controllerContext, string actionName);
/// <summary> /// Creates the view result for the specified view type. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="options">The view parameters.</param> /// <param name="type">The type.</param> /// <returns></returns> protected abstract ViewEngineResult CreateViewResult(ControllerContext controllerContext, ViewResultOptions options, Type type);
/// <summary> /// Invokes all pre-result filters, before the result has been invoked. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="result">The result.</param> /// <param name="resultFilters">The result filters.</param> /// <returns></returns> protected virtual ResultExecutingContext ExecutePreResultFilters(ControllerContext controllerContext, ActionResult result, IEnumerable<IResultFilter> resultFilters) { controllerContext.Request.ReportProgress(new PreResultFiltersNavigationEvent()); var context = new ResultExecutingContext(controllerContext, result); foreach (var filter in resultFilters) { filter.OnResultExecuting(context); if (context.Cancel) { return context; } } return context; }
/// <summary> /// Initializes a new instance of the <see cref="ResultExecutedContext"/> class. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="result">The result.</param> /// <param name="exception">An exception that may have been thrown.</param> public ResultExecutedContext(ControllerContext controllerContext, ActionResult result, Exception exception) { this.result = result; Exception = exception; this.controllerContext = controllerContext; }
/// <summary> /// Invokes all pre-request filters, before the controller has been invoked. /// </summary> /// <param name="controllerContext">The controller context.</param> /// <param name="modelBinders">The model binders.</param> /// <param name="filters">The filters.</param> /// <returns></returns> protected virtual ActionResult ExecutePreActionFilters(ControllerContext controllerContext, ModelBinderDictionary modelBinders, IEnumerable<IActionFilter> filters) { controllerContext.Request.ReportProgress(new PreActionFiltersNavigationEvent()); var context = new ActionExecutingContext(controllerContext, modelBinders); foreach (var filter in filters) { filter.OnActionExecuting(context); if (context.OverrideResult != null) { return context.OverrideResult; } } return null; }