Represents a context for tracking Widget execution.
        /// <summary>
        /// Invokes a widget synchronously.
        /// </summary>
        /// <param name="writer">The target text writer.</param>
        /// <param name="descriptor">The widget descriptor.</param>
        /// <param name="values">The set of values to provide to the widget.</param>
        private void InvokeCore(TextWriter writer, WidgetDescriptor descriptor, object values = null)
        {
            var context = new WidgetContext(descriptor, new RouteValueDictionary(values), _viewContext, writer);
            var invoker = _invokerFactory.CreateInstance(context);

            invoker.Invoke(context);
        }
        /// <summary>
        /// Finds a synchronous method to execute.
        /// </summary>
        /// <param name="context">The widget context.</param>
        /// <param name="widgetType">The widget type.</param>
        /// <returns>The synchronous method.</returns>
        public static MethodInfo FindSyncMethod(WidgetContext context, TypeInfo widgetType)
        {
            string httpMethod = ResolveHttpMethod(context);
            string state = string.Empty; // Resolve a widget state?
            MethodInfo method = null;

            for (int i = 0; i < SyncMethodNames.Length; i++)
            {
                string name = string.Format(SyncMethodNames[i], state, httpMethod);
                method = GetMethod(name, widgetType);
                if (method != null)
                {
                    break;
                }
            }

            if (method == null)
            {
                return null;
            }

            if (method.ReturnType == typeof(void))
            {
                throw new InvalidOperationException($"Sync method '{method.Name}' should return a value.");
            }

            if (method.ReturnType.IsAssignableFrom(typeof(Task)))
            {
                throw new InvalidOperationException($"Sync method '{method.Name}' cannot return a task.");
            }

            return method;
        }
        /// <inheritdoc />
        public async Task ExecuteAsync(WidgetContext context)
        {
            var viewEngine = ViewEngine ?? ResolveViewEngine(context);
            var viewData = ViewData ?? context.ViewData;
            bool isNullOrEmptyViewName = string.IsNullOrEmpty(ViewName);

            string state = null; // TODO: Resolve from value provider?

            string qualifiedViewName;
            if (!isNullOrEmptyViewName && (ViewName[0] == '~' || ViewName[0] == '/'))
            {
                qualifiedViewName = ViewName;
            }
            else
            {
                qualifiedViewName = string.Format(ViewPath, context.WidgetDescriptor.ShortName, isNullOrEmptyViewName ? (state ?? DefaultViewName) : ViewName);
            }

            var view = FindView(context.ViewContext, viewEngine, qualifiedViewName);
            var childViewContext = new ViewContext(
                context.ViewContext,
                view,
                viewData,
                context.Writer);

            using (view as IDisposable)
            {
                await view.RenderAsync(childViewContext);
            }
        }
        /// <summary>
        /// Finds an asynchronous method to execute.
        /// </summary>
        /// <param name="context">The widget context.</param>
        /// <param name="widgetType">The widget type.</param>
        /// <returns>The asynchronous method.</returns>
        public static MethodInfo FindAsyncMethod(WidgetContext context, TypeInfo widgetType)
        {
            string httpMethod = ResolveHttpMethod(context);
            string state = string.Empty; // Resolve a widget state?
            MethodInfo method = null;

            for (int i = 0; i < AsyncMethodNames.Length; i++)
            {
                string name = string.Format(AsyncMethodNames[i], state, httpMethod);
                method = GetMethod(name, widgetType);
                if (method != null)
                {
                    break;
                }
            }

            if (method == null)
            {
                return null;
            }

            if (!method.ReturnType.GetTypeInfo().IsGenericType
                || method.ReturnType.GetGenericTypeDefinition() != typeof(Task<>))
            {
                throw new InvalidOperationException($"Async method '{method.Name}' must return a task.");
            }

            return method;
        }
        /// <inheritdoc />
        public virtual void Activate(object widget, WidgetContext context)
        {
            var propertiesToActivate = _injectActions.GetOrAdd(widget.GetType(), _getPropertiesToActivate);

            for (int i = 0; i < propertiesToActivate.Length; i++)
            {
                var activateInfo = propertiesToActivate[i];
                activateInfo.Activate(widget, context);
            }
        }
        /// <inheritdoc />
        public virtual void Activate(object widget, WidgetContext context)
        {
            var propertiesToActivate = _injectActions.GetOrAdd(widget.GetType(), _getPropertiesToActivate);

            for (int i = 0; i < propertiesToActivate.Length; i++)
            {
                var activateInfo = propertiesToActivate[i];
                activateInfo.Activate(widget, context);
            }
        }
Exemple #7
0
        /// <summary>
        /// Creates a widget instance.
        /// </summary>
        /// <param name="context">The widget context.</param>
        /// <returns>The wiget instance.</returns>
        private object CreateWidget(WidgetContext context)
        {
            var services = context.ViewContext.HttpContext.RequestServices;
            var widget   = _typeActivatorCache.CreateInstance <object>(
                services,
                context.WidgetDescriptor.Type);

            _widgetActivator.Activate(widget, context);

            return(widget);
        }
Exemple #8
0
        /// <summary>
        /// Invokes an asynchronous method.
        /// </summary>
        /// <param name="method">The method to invoke.</param>
        /// <param name="context">The widget context.</param>
        /// <returns>The widget result.</returns>
        private async Task <IWidgetResult> InvokeAsyncCore(MethodInfo method, WidgetContext context)
        {
            var widget = CreateWidget(context);

            var arguments = await GetArgumentsAsync(context, method, context.Values);

            var result = await ControllerActionExecutor.ExecuteAsync(method, widget, arguments);

            var widgetResult = CoerceToWidgetResult(result);

            return(widgetResult);
        }
Exemple #9
0
        /// <inheritdocs />
        public async Task <IDictionary <string, object> > BindArgumentsAsync(WidgetContext context, MethodInfo method, IDictionary <string, object> values)
        {
            var bindingContext = new OperationBindingContext
            {
                HttpContext       = context.ViewContext.HttpContext,
                InputFormatters   = _options.InputFormatters,
                MetadataProvider  = _modelMetadataProvider,
                ModelBinder       = new CompositeModelBinder(_options.ModelBinders),
                ValidatorProvider = new CompositeModelValidatorProvider(_options.ModelValidatorProviders),
                ValueProvider     = await CompositeValueProvider.CreateAsync(_options.ValueProviderFactories, new ValueProviderFactoryContext(context.ViewContext.HttpContext, context.ViewContext.RouteData.Values))
            };

            var arguments  = new Dictionary <string, object>(StringComparer.Ordinal);
            var parameters = method.GetParameters();

            foreach (var parameter in parameters)
            {
                if (values.ContainsKey(parameter.Name))
                {
                    arguments.Add(parameter.Name, values[parameter.Name]);
                }
                else
                {
                    var attribute   = parameter.GetCustomAttributes().OfType <IBindingSourceMetadata>().FirstOrDefault();
                    var bindingInfo = new BindingInfo()
                    {
                        BindingSource = attribute?.BindingSource
                    };

                    var metadata            = _modelMetadataProvider.GetMetadataForType(parameter.ParameterType);
                    var modelBindingContext = ModelBindingContext.CreateBindingContext(
                        bindingContext,
                        context.ModelState,
                        metadata,
                        bindingInfo,
                        parameter.Name);

                    var result = await bindingContext.ModelBinder.BindModelAsync(modelBindingContext);

                    if (result.IsModelSet)
                    {
                        _objectModelValidator.Validate(bindingContext.ValidatorProvider, context.ModelState, modelBindingContext.ValidationState, result.Key, result.Model);
                        arguments.Add(parameter.Name, result.Model);
                    }
                    else
                    {
                        arguments.Add(parameter.Name, Activator.CreateInstance(parameter.ParameterType));
                    }
                }
            }

            return(arguments);
        }
        /// <inheritdocs />
        public async Task<IDictionary<string, object>> BindArgumentsAsync(WidgetContext context, MethodInfo method, IDictionary<string, object> values)
        {
            var bindingContext = new OperationBindingContext
            {
                HttpContext = context.ViewContext.HttpContext,
                InputFormatters = _options.InputFormatters,
                MetadataProvider = _modelMetadataProvider,
                ModelBinder = new CompositeModelBinder(_options.ModelBinders),
                ValidatorProvider = new CompositeModelValidatorProvider(_options.ModelValidatorProviders),
                ValueProvider = await CompositeValueProvider.CreateAsync(_options.ValueProviderFactories, new ValueProviderFactoryContext(context.ViewContext.HttpContext, context.ViewContext.RouteData.Values))
            };

            var arguments = new Dictionary<string, object>(StringComparer.Ordinal);
            var parameters = method.GetParameters();

            foreach (var parameter in parameters)
            {
                if (values.ContainsKey(parameter.Name))
                {
                    arguments.Add(parameter.Name, values[parameter.Name]);
                }
                else
                {
                    var attribute = parameter.GetCustomAttributes().OfType<IBindingSourceMetadata>().FirstOrDefault();
                    var bindingInfo = new BindingInfo()
                    {
                        BindingSource = attribute?.BindingSource
                    };

                    var metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterType);
                    var modelBindingContext = ModelBindingContext.CreateBindingContext(
                        bindingContext,
                        context.ModelState,
                        metadata,
                        bindingInfo,
                        parameter.Name);

                    var result = await bindingContext.ModelBinder.BindModelAsync(modelBindingContext);
                    if (result.IsModelSet)
                    {
                        _objectModelValidator.Validate(bindingContext.ValidatorProvider, context.ModelState, modelBindingContext.ValidationState, result.Key, result.Model);
                        arguments.Add(parameter.Name, result.Model);
                    }
                    else
                    {
                        arguments.Add(parameter.Name, Activator.CreateInstance(parameter.ParameterType));
                    }
                }
            }

            return arguments;
        }
Exemple #11
0
        /// <inheritdoc />
        public void Invoke(WidgetContext context)
        {
            var method = WidgetMethodSelector.FindSyncMethod(context, context.WidgetDescriptor.Type.GetTypeInfo());

            if (method == null)
            {
                throw new InvalidOperationException("Cannot find an appropriate method.");
            }

            var result = InvokeSyncCore(method, context);

            result.Execute(context);
        }
        /// <inheritdoc />
        public void Invoke(WidgetContext context)
        {
            var method = WidgetMethodSelector.FindSyncMethod(context, context.WidgetDescriptor.Type.GetTypeInfo());

            if (method == null)
            {
                throw new InvalidOperationException("Cannot find an appropriate method.");
            }

            var result = InvokeSyncCore(method, context);

            result.Execute(context);
        }
        /// <inheritdoc />
        public void Execute(WidgetContext context)
        {
            var serializerSettings = _serializerSettings;
            if (serializerSettings == null)
            {
                serializerSettings = context.ViewContext.HttpContext.RequestServices.GetRequiredService<IOptions<MvcJsonOptions>>().Value.SerializerSettings;
            }

            using (var jsonWriter = new JsonTextWriter(context.Writer))
            {
                jsonWriter.CloseOutput = false;

                var jsonSerializer = JsonSerializer.Create(serializerSettings);
                jsonSerializer.Serialize(jsonWriter, Value);
            }
        }
Exemple #14
0
        /// <summary>
        /// Invokes a synchronous method.
        /// </summary>
        /// <param name="method">The method to invoke.</param>
        /// <param name="context">The widget context.</param>
        /// <returns>The widget result.</returns>
        private IWidgetResult InvokeSyncCore(MethodInfo method, WidgetContext context)
        {
            var    widget = CreateWidget(context);
            object result = null;

            var arguments = GetArgumentsAsync(context, method, context.Values).GetAwaiter().GetResult();

            try
            {
                result = method.Invoke(widget, arguments);
                var widgetResult = CoerceToWidgetResult(result);

                return(widgetResult);
            }
            catch (TargetInvocationException ex)
            {
                var exceptionInfo = ExceptionDispatchInfo.Capture(ex.InnerException);
                exceptionInfo.Throw();

                return(null); // Unreachable
            }
        }
        /// <inheritdoc />
        public async Task InvokeAsync(WidgetContext context)
        {
            IWidgetResult result;
            var asyncMethod = WidgetMethodSelector.FindAsyncMethod(context, context.WidgetDescriptor.Type.GetTypeInfo());

            if (asyncMethod == null)
            {
                var syncMethod = WidgetMethodSelector.FindSyncMethod(context, context.WidgetDescriptor.Type.GetTypeInfo());

                if (syncMethod == null)
                {
                    throw new InvalidOperationException("Cannot find an appropriate method.");
                }

                result = InvokeSyncCore(syncMethod, context);
            }
            else
            {
                result = await InvokeAsyncCore(asyncMethod, context);
            }

            await result.ExecuteAsync(context);
        }
Exemple #16
0
        /// <inheritdoc />
        public async Task InvokeAsync(WidgetContext context)
        {
            IWidgetResult result;
            var           asyncMethod = WidgetMethodSelector.FindAsyncMethod(context, context.WidgetDescriptor.Type.GetTypeInfo());

            if (asyncMethod == null)
            {
                var syncMethod = WidgetMethodSelector.FindSyncMethod(context, context.WidgetDescriptor.Type.GetTypeInfo());

                if (syncMethod == null)
                {
                    throw new InvalidOperationException("Cannot find an appropriate method.");
                }

                result = InvokeSyncCore(syncMethod, context);
            }
            else
            {
                result = await InvokeAsyncCore(asyncMethod, context);
            }

            await result.ExecuteAsync(context);
        }
 /// <inheritdoc />
 public IWidgetInvoker CreateInstance(WidgetContext context)
 {
     return new DefaultWidgetInvoker(_typeActivatorCache, _widgetActivator, _argumentBinder);
 }
 /// <summary>
 /// Resolves the view engine.
 /// </summary>
 /// <param name="context">The widget context.</param>
 /// <returns>The view engine.</returns>
 private static IViewEngine ResolveViewEngine(WidgetContext context)
 {
     return context.ViewContext.HttpContext.RequestServices.GetRequiredService<ICompositeViewEngine>();
 }
        /// <summary>
        /// Invokes a widget synchronously.
        /// </summary>
        /// <param name="writer">The target text writer.</param>
        /// <param name="descriptor">The widget descriptor.</param>
        /// <param name="values">The set of values to provide to the widget.</param>
        private void InvokeCore(TextWriter writer, WidgetDescriptor descriptor, object values = null)
        {
            var context = new WidgetContext(descriptor, new RouteValueDictionary(values), _viewContext, writer);
            var invoker = _invokerFactory.CreateInstance(context);

            invoker.Invoke(context);
        }
        /// <inheritdoc />
        public void Execute(WidgetContext context)
        {
            var task = ExecuteAsync(context);

            task.GetAwaiter().GetResult();
        }
 /// <summary>
 /// Gets the arguments for the target method. 
 /// </summary>
 /// <remarks>
 /// The argument binder will provide a mixed-result of values from the provided dictionary, and those from model binding.
 /// </remarks>
 /// <param name="context">The widget context.</param>
 /// <param name="method">The target method.</param>
 /// <param name="values">The set of provided values.</param>
 /// <returns>The bound arguments.</returns>
 private async Task<object[]> GetArgumentsAsync(WidgetContext context, MethodInfo method, RouteValueDictionary values)
 {
     var arguments = await _argumentBinder.BindArgumentsAsync(context, method, values);
     return arguments.Values.ToArray();
 }
        /// <summary>
        /// Resolves the HTTP method used to discover which action to execute.
        /// </summary>
        /// <param name="context">The widget context.</param>
        /// <returns>The HTTP method.</returns>
        private static string ResolveHttpMethod(WidgetContext context)
        {
            string httpMethod = context.ViewContext?.HttpContext?.Request?.Method;
            if (string.Equals(httpMethod, "get", StringComparison.OrdinalIgnoreCase))
            {
                httpMethod = "Get";
            }
            else
            {
                httpMethod = "Post";
            }

            if (httpMethod == "Post" && !string.IsNullOrEmpty(context.WidgetId))
            {
                // MA - We only want to use Post if we are the active widget.
                // TODO - This needs to come from the value provider.
                var form = context.ViewContext?.HttpContext?.Request?.Form;
                if (!string.Equals(context.WidgetId, form[WidgetConventions.WidgetTarget], StringComparison.CurrentCultureIgnoreCase))
                {
                    httpMethod = "Get";
                }
            }

            return httpMethod;
        }
 /// <inheritdoc />
 public Task ExecuteAsync(WidgetContext context)
 {
     Execute(context);
     return Task.FromResult(true);
 }
        /// <summary>
        /// Invokes an asynchronous method.
        /// </summary>
        /// <param name="method">The method to invoke.</param>
        /// <param name="context">The widget context.</param>
        /// <returns>The widget result.</returns>
        private async Task<IWidgetResult> InvokeAsyncCore(MethodInfo method, WidgetContext context)
        {
            var widget = CreateWidget(context);

            var arguments = await GetArgumentsAsync(context, method, context.Values);

            var result = await ControllerActionExecutor.ExecuteAsync(method, widget, arguments);
            var widgetResult = CoerceToWidgetResult(result);
            return widgetResult;
        }
        /// <summary>
        /// Invokes a synchronous method.
        /// </summary>
        /// <param name="method">The method to invoke.</param>
        /// <param name="context">The widget context.</param>
        /// <returns>The widget result.</returns>
        private IWidgetResult InvokeSyncCore(MethodInfo method, WidgetContext context)
        {
            var widget = CreateWidget(context);
            object result = null;

            var arguments = GetArgumentsAsync(context, method, context.Values).GetAwaiter().GetResult();

            try
            {
                result = method.Invoke(widget, arguments);
                var widgetResult = CoerceToWidgetResult(result);

                return widgetResult;
            }
            catch (TargetInvocationException ex)
            {
                var exceptionInfo = ExceptionDispatchInfo.Capture(ex.InnerException);
                exceptionInfo.Throw();

                return null; // Unreachable
            }
        }
 /// <inheritdoc />
 public void Execute(WidgetContext context)
 {
     context.Writer.Write(EncodedContent.ToString());
 }
 /// <inheritdoc />
 public Task ExecuteAsync(WidgetContext context)
 {
     return context.Writer.WriteAsync(EncodedContent.ToString());
 }
 /// <inheritdoc />
 public IWidgetInvoker CreateInstance(WidgetContext context)
 {
     return(new DefaultWidgetInvoker(_typeActivatorCache, _widgetActivator, _argumentBinder));
 }
        /// <summary>
        /// Creates a widget instance.
        /// </summary>
        /// <param name="context">The widget context.</param>
        /// <returns>The wiget instance.</returns>
        private object CreateWidget(WidgetContext context)
        {
            var services = context.ViewContext.HttpContext.RequestServices;
            var widget = _typeActivatorCache.CreateInstance<object>(
                services,
                context.WidgetDescriptor.Type);
            _widgetActivator.Activate(widget, context);

            return widget;
        }
Exemple #30
0
        /// <summary>
        /// Gets the arguments for the target method.
        /// </summary>
        /// <remarks>
        /// The argument binder will provide a mixed-result of values from the provided dictionary, and those from model binding.
        /// </remarks>
        /// <param name="context">The widget context.</param>
        /// <param name="method">The target method.</param>
        /// <param name="values">The set of provided values.</param>
        /// <returns>The bound arguments.</returns>
        private async Task <object[]> GetArgumentsAsync(WidgetContext context, MethodInfo method, RouteValueDictionary values)
        {
            var arguments = await _argumentBinder.BindArgumentsAsync(context, method, values);

            return(arguments.Values.ToArray());
        }