예제 #1
0
        public async Task <bool> Handle(IDotvvmRequestContext context)
        {
            var requestTracer = context.Services.GetRequiredService <AggregateRequestTracer>();

            await requestTracer.TraceEvent(RequestTracingConstants.BeginRequest, context);

            IDictionary <string, object> parameters;
            var route = FindMatchingRoute(context.Configuration.RouteTable, context, out parameters);

            //check if route exists
            if (route == null)
            {
                return(false);
            }

            context.Route      = route;
            context.Parameters = parameters;

            var presenter = context.Presenter = route.GetPresenter(context.Services);
            var filters   =
                ActionFilterHelper.GetActionFilters <IPageActionFilter>(presenter.GetType().GetTypeInfo())
                .Concat(context.Configuration.Runtime.GlobalFilters.OfType <IPageActionFilter>());

            try
            {
                foreach (var f in filters)
                {
                    await f.OnPageLoadingAsync(context);
                }
                await presenter.ProcessRequest(context);

                foreach (var f in filters)
                {
                    await f.OnPageLoadedAsync(context);
                }
            }
            catch (DotvvmInterruptRequestExecutionException) { } // the response has already been generated, do nothing
            catch (DotvvmHttpException) { throw; }
            catch (Exception exception)
            {
                foreach (var f in filters)
                {
                    await f.OnPageExceptionAsync(context, exception);

                    if (context.IsPageExceptionHandled)
                    {
                        context.InterruptRequest();
                    }
                }
                await requestTracer.EndRequest(context, exception);

                throw;
            }

            await requestTracer.EndRequest(context);

            return(true);
        }
예제 #2
0
        public async Task ProcessStaticCommandRequest(IDotvvmRequestContext context)
        {
            JObject postData;

            using (var jsonReader = new JsonTextReader(new StreamReader(context.HttpContext.Request.Body)))
            {
                postData = JObject.Load(jsonReader);
            }
            // validate csrf token
            context.CsrfToken = postData["$csrfToken"].Value <string>();
            CsrfProtector.VerifyToken(context, context.CsrfToken);

            var command    = postData["command"].Value <string>();
            var arguments  = postData["args"] as JArray;
            var lastDot    = command.LastIndexOf('.');
            var typeName   = command.Remove(lastDot);
            var methodName = command.Substring(lastDot + 1);
            var methodInfo = Type.GetType(typeName).GetMethod(methodName);

            if (!methodInfo.IsDefined(typeof(AllowStaticCommandAttribute)))
            {
                throw new DotvvmHttpException($"This method cannot be called from the static command. If you need to call this method, add the '{nameof(AllowStaticCommandAttribute)}' to the method.");
            }
            var target          = methodInfo.IsStatic ? null : arguments[0].ToObject(methodInfo.DeclaringType);
            var methodArguments =
                arguments.Skip(methodInfo.IsStatic ? 0 : 1)
                .Zip(methodInfo.GetParameters(), (arg, parameter) => arg.ToObject(parameter.ParameterType))
                .ToArray();
            var actionInfo = new ActionInfo
            {
                IsControlCommand = false,
                Action           = () => methodInfo.Invoke(target, methodArguments)
            };
            var filters = context.Configuration.Runtime.GlobalFilters.OfType <ICommandActionFilter>()
                          .Concat(ActionFilterHelper.GetActionFilters <ICommandActionFilter>(methodInfo))
                          .ToArray();

            var result = await ExecuteCommand(actionInfo, context, filters);

            using (var writer = new StreamWriter(context.HttpContext.Response.Body))
            {
                var json = ViewModelSerializer.BuildStaticCommandResponse(context, result);
                writer.WriteLine(json);
            }
        }
예제 #3
0
        public async Task ProcessStaticCommandRequest(IDotvvmRequestContext context)
        {
            try
            {
                JObject postData;
                using (var jsonReader = new JsonTextReader(new StreamReader(context.HttpContext.Request.Body)))
                {
                    postData = JObject.Load(jsonReader);
                }

                // validate csrf token
                context.CsrfToken = postData["$csrfToken"].Value <string>();
                CsrfProtector.VerifyToken(context, context.CsrfToken);

                var command       = postData["command"].Value <string>();
                var arguments     = postData["args"] as JArray;
                var executionPlan =
                    StaticCommandBindingCompiler.DecryptJson(Convert.FromBase64String(command), context.Services.GetService <IViewModelProtector>())
                    .Apply(StaticCommandBindingCompiler.DeserializePlan);

                var actionInfo = new ActionInfo {
                    IsControlCommand = false,
                    Action           = () => { return(ExecuteStaticCommandPlan(executionPlan, new Queue <JToken>(arguments), context)); }
                };
                var filters = context.Configuration.Runtime.GlobalFilters.OfType <ICommandActionFilter>()
                              .Concat(executionPlan.GetAllMethods().SelectMany(m => ActionFilterHelper.GetActionFilters <ICommandActionFilter>(m)))
                              .ToArray();

                var result = await ExecuteCommand(actionInfo, context, filters);

                await OutputRenderer.WriteStaticCommandResponse(context,
                                                                ViewModelSerializer.BuildStaticCommandResponse(context, result));
            }
            finally
            {
                StaticCommandServiceLoader.DisposeStaticCommandServices(context);
            }
        }
예제 #4
0
        /// <summary>
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task ProcessRequestCore(IDotvvmRequestContext context)
        {
            var requestTracer = context.Services.GetRequiredService <AggregateRequestTracer>();

            if (context.HttpContext.Request.Method != "GET" && context.HttpContext.Request.Method != "POST")
            {
                // unknown HTTP method
                context.HttpContext.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                throw new DotvvmHttpException("Only GET and POST methods are supported!");
            }
            if (context.HttpContext.Request.Headers["X-PostbackType"] == "StaticCommand")
            {
                await ProcessStaticCommandRequest(context);

                await requestTracer.TraceEvent(RequestTracingConstants.StaticCommandExecuted, context);

                return;
            }
            var isPostBack = context.IsPostBack = DetermineIsPostBack(context.HttpContext);

            // build the page view
            var page = DotvvmViewBuilder.BuildView(context);

            page.SetValue(Internal.RequestContextProperty, context);
            context.View = page;
            await requestTracer.TraceEvent(RequestTracingConstants.ViewInitialized, context);

            // locate and create the view model
            context.ViewModel = ViewModelLoader.InitializeViewModel(context, page);

            // get action filters
            var viewModelFilters = ActionFilterHelper.GetActionFilters <IViewModelActionFilter>(context.ViewModel.GetType().GetTypeInfo())
                                   .Concat(context.Configuration.Runtime.GlobalFilters.OfType <IViewModelActionFilter>());

            var requestFilters = ActionFilterHelper.GetActionFilters <IPageActionFilter>(context.ViewModel.GetType().GetTypeInfo())
                                 .Concat(context.Configuration.Runtime.GlobalFilters.OfType <IPageActionFilter>());

            foreach (var f in requestFilters)
            {
                await f.OnPageInitializedAsync(context);
            }
            try
            {
                // run the preinit phase in the page
                DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.PreInit);
                page.DataContext = context.ViewModel;

                // run OnViewModelCreated on action filters
                foreach (var filter in viewModelFilters)
                {
                    await filter.OnViewModelCreatedAsync(context);
                }
                await requestTracer.TraceEvent(RequestTracingConstants.ViewModelCreated, context);

                // perform parameter binding
                if (context.ViewModel is DotvvmViewModelBase dotvvmViewModelBase)
                {
                    dotvvmViewModelBase.ExecuteOnViewModelRecursive(v => ViewModelParameterBinder.BindParameters(context, v));
                }
                else
                {
                    ViewModelParameterBinder.BindParameters(context, context.ViewModel);
                }

                // init the view model lifecycle
                if (context.ViewModel is IDotvvmViewModel viewModel)
                {
                    viewModel.Context = context;
                    ChildViewModelsCache.SetViewModelClientPath(viewModel, ChildViewModelsCache.RootViewModelPath);
                    await viewModel.Init();
                }

                // run the init phase in the page
                DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.Init);
                await requestTracer.TraceEvent(RequestTracingConstants.InitCompleted, context);

                object commandResult = null;

                if (!isPostBack)
                {
                    // perform standard get
                    if (context.ViewModel is IDotvvmViewModel)
                    {
                        await((IDotvvmViewModel)context.ViewModel).Load();
                    }

                    // run the load phase in the page
                    DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.Load);
                    await requestTracer.TraceEvent(RequestTracingConstants.LoadCompleted, context);
                }
                else
                {
                    // perform the postback
                    string postData;
                    using (var sr = new StreamReader(context.HttpContext.Request.Body))
                    {
                        postData = await sr.ReadToEndAsync();
                    }
                    ViewModelSerializer.PopulateViewModel(context, postData);

                    // run OnViewModelDeserialized on action filters
                    foreach (var filter in viewModelFilters)
                    {
                        await filter.OnViewModelDeserializedAsync(context);
                    }
                    await requestTracer.TraceEvent(RequestTracingConstants.ViewModelDeserialized, context);

                    // validate CSRF token
                    try
                    {
                        CsrfProtector.VerifyToken(context, context.CsrfToken);
                    }
                    catch (SecurityException exc)
                    {
                        await context.InterruptRequestAsync(HttpStatusCode.BadRequest, exc.Message);
                    }

                    if (context.ViewModel is IDotvvmViewModel)
                    {
                        await((IDotvvmViewModel)context.ViewModel).Load();
                    }

                    // run the load phase in the page
                    DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.Load);
                    await requestTracer.TraceEvent(RequestTracingConstants.LoadCompleted, context);

                    // invoke the postback command
                    var actionInfo = ViewModelSerializer.ResolveCommand(context, page);

                    // get filters
                    var methodFilters = context.Configuration.Runtime.GlobalFilters.OfType <ICommandActionFilter>()
                                        .Concat(ActionFilterHelper.GetActionFilters <ICommandActionFilter>(context.ViewModel.GetType().GetTypeInfo()));
                    if (actionInfo.Binding.GetProperty <ActionFiltersBindingProperty>(ErrorHandlingMode.ReturnNull) is ActionFiltersBindingProperty filters)
                    {
                        methodFilters = methodFilters.Concat(filters.Filters.OfType <ICommandActionFilter>());
                    }

                    commandResult = await ExecuteCommand(actionInfo, context, methodFilters);

                    await requestTracer.TraceEvent(RequestTracingConstants.CommandExecuted, context);
                }

                if (context.ViewModel is IDotvvmViewModel)
                {
                    await((IDotvvmViewModel)context.ViewModel).PreRender();
                }

                // run the prerender phase in the page
                DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.PreRender);

                // run the prerender complete phase in the page
                DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.PreRenderComplete);
                await requestTracer.TraceEvent(RequestTracingConstants.PreRenderCompleted, context);

                // generate CSRF token if required
                if (string.IsNullOrEmpty(context.CsrfToken))
                {
                    context.CsrfToken = CsrfProtector.GenerateToken(context);
                }

                // run OnViewModelSerializing on action filters
                foreach (var filter in viewModelFilters)
                {
                    await filter.OnViewModelSerializingAsync(context);
                }
                await requestTracer.TraceEvent(RequestTracingConstants.ViewModelSerialized, context);

                // render the output
                ViewModelSerializer.BuildViewModel(context);
                if (commandResult != null)
                {
                    context.ViewModelJson["commandResult"] = JToken.FromObject(commandResult);
                }
                if (!context.IsInPartialRenderingMode)
                {
                    // standard get
                    await OutputRenderer.WriteHtmlResponse(context, page);
                }
                else
                {
                    // postback or SPA content
                    var postBackUpdates = OutputRenderer.RenderPostbackUpdatedControls(context, page);
                    ViewModelSerializer.AddPostBackUpdatedControls(context, postBackUpdates);
                    await OutputRenderer.WriteViewModelResponse(context, page);
                }
                await requestTracer.TraceEvent(RequestTracingConstants.OutputRendered, context);

                foreach (var f in requestFilters)
                {
                    await f.OnPageRenderedAsync(context);
                }
            }
            catch (DotvvmInterruptRequestExecutionException) { throw; }
            catch (DotvvmHttpException) { throw; }
            catch (Exception ex)
            {
                // run OnPageException on action filters
                foreach (var filter in requestFilters)
                {
                    await filter.OnPageExceptionAsync(context, ex);

                    if (context.IsPageExceptionHandled)
                    {
                        context.InterruptRequest();
                    }
                }

                throw;
            }
            finally
            {
                if (context.ViewModel != null)
                {
                    ViewModelLoader.DisposeViewModel(context.ViewModel);
                }
                StaticCommandServiceLoader.DisposeStaticCommandServices(context);
            }
        }
예제 #5
0
        /// <summary>
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task ProcessRequestCore(IDotvvmRequestContext context)
        {
            if (context.HttpContext.Request.Method != "GET" && context.HttpContext.Request.Method != "POST")
            {
                // unknown HTTP method
                context.HttpContext.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                throw new DotvvmHttpException("Only GET and POST methods are supported!");
            }
            if (context.HttpContext.Request.Headers["X-PostbackType"] == "StaticCommand")
            {
                await ProcessStaticCommandRequest(context);

                return;
            }
            var isPostBack = context.IsPostBack = DetermineIsPostBack(context.HttpContext);

            // build the page view
            var page = DotvvmViewBuilder.BuildView(context);

            page.SetValue(Internal.RequestContextProperty, context);
            context.View = page;

            // locate and create the view model
            context.ViewModel = ViewModelLoader.InitializeViewModel(context, page);

            // get action filters
            var viewModelFilters = ActionFilterHelper.GetActionFilters <IViewModelActionFilter>(context.ViewModel.GetType().GetTypeInfo());

            viewModelFilters.AddRange(context.Configuration.Runtime.GlobalFilters.OfType <IViewModelActionFilter>());
            var requestFilters = ActionFilterHelper.GetActionFilters <IRequestActionFilter>(context.ViewModel.GetType().GetTypeInfo());

            foreach (var f in requestFilters)
            {
                await f.OnPageLoadingAsync(context);
            }

            try
            {
                // run the preinit phase in the page
                DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.PreInit);
                page.DataContext = context.ViewModel;

                // run OnViewModelCreated on action filters
                foreach (var filter in viewModelFilters)
                {
                    await filter.OnViewModelCreatedAsync(context);
                }

                // init the view model lifecycle
                if (context.ViewModel is IDotvvmViewModel)
                {
                    ((IDotvvmViewModel)context.ViewModel).Context = context;
                    await((IDotvvmViewModel)context.ViewModel).Init();
                }

                // run the init phase in the page
                DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.Init);

                if (!isPostBack)
                {
                    // perform standard get
                    if (context.ViewModel is IDotvvmViewModel)
                    {
                        await((IDotvvmViewModel)context.ViewModel).Load();
                    }

                    // run the load phase in the page
                    DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.Load);
                }
                else
                {
                    // perform the postback
                    string postData;
                    using (var sr = new StreamReader(context.HttpContext.Request.Body))
                    {
                        postData = await sr.ReadToEndAsync();
                    }
                    ViewModelSerializer.PopulateViewModel(context, postData);

                    // validate CSRF token
                    CsrfProtector.VerifyToken(context, context.CsrfToken);

                    if (context.ViewModel is IDotvvmViewModel)
                    {
                        await((IDotvvmViewModel)context.ViewModel).Load();
                    }

                    // validate CSRF token
                    CsrfProtector.VerifyToken(context, context.CsrfToken);

                    // run the load phase in the page
                    DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.Load);

                    // invoke the postback command
                    ActionInfo actionInfo;
                    ViewModelSerializer.ResolveCommand(context, page, postData, out actionInfo);

                    if (actionInfo != null)
                    {
                        // get filters
                        var methodFilters = context.Configuration.Runtime.GlobalFilters.OfType <ICommandActionFilter>()
                                            .Concat(ActionFilterHelper.GetActionFilters <ICommandActionFilter>(context.ViewModel.GetType().GetTypeInfo()));
                        if (actionInfo.Binding.ActionFilters != null)
                        {
                            methodFilters = methodFilters.Concat(actionInfo.Binding.ActionFilters.OfType <ICommandActionFilter>());
                        }

                        await ExecuteCommand(actionInfo, context, methodFilters);
                    }
                }

                if (context.ViewModel is IDotvvmViewModel)
                {
                    await((IDotvvmViewModel)context.ViewModel).PreRender();
                }

                // run the prerender phase in the page
                DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.PreRender);

                // run the prerender complete phase in the page
                DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.PreRenderComplete);

                // generate CSRF token if required
                if (string.IsNullOrEmpty(context.CsrfToken))
                {
                    context.CsrfToken = CsrfProtector.GenerateToken(context);
                }

                // run OnResponseRendering on action filters
                foreach (var filter in viewModelFilters)
                {
                    await filter.OnResponseRenderingAsync(context);
                }

                // render the output
                ViewModelSerializer.BuildViewModel(context);
                if (!context.IsInPartialRenderingMode)
                {
                    // standard get
                    await OutputRenderer.WriteHtmlResponse(context, page);
                }
                else
                {
                    // postback or SPA content
                    OutputRenderer.RenderPostbackUpdatedControls(context, page);
                    ViewModelSerializer.AddPostBackUpdatedControls(context);
                    await OutputRenderer.WriteViewModelResponse(context, page);
                }

                if (context.ViewModel != null)
                {
                    ViewModelLoader.DisposeViewModel(context.ViewModel);
                }

                foreach (var f in requestFilters)
                {
                    await f.OnPageLoadedAsync(context);
                }
            }
            catch (DotvvmInterruptRequestExecutionException) { throw; }
            catch (DotvvmHttpException) { throw; }
            catch (Exception ex)
            {
                // run OnPageException on action filters
                foreach (var filter in requestFilters)
                {
                    await filter.OnPageExceptionAsync(context, ex);

                    if (context.IsPageExceptionHandled)
                    {
                        context.InterruptRequest();
                    }
                }
                throw;
            }
        }
예제 #6
0
        public async Task <bool> Handle(IDotvvmRequestContext context)
        {
            // attempt to translate Googlebot hashbang espaced fragment URL to a plain URL string.
            string url;

            if (!TryParseGooglebotHashbangEscapedFragment(context.HttpContext.Request.QueryString, out url))
            {
                url = context.HttpContext.Request.Path.Value;
            }
            url = url.Trim('/');

            // remove SPA identifier from the URL
            if (url.StartsWith(HostingConstants.SpaUrlIdentifier, StringComparison.Ordinal))
            {
                url = url.Substring(HostingConstants.SpaUrlIdentifier.Length).Trim('/');
            }


            // find the route
            IDictionary <string, object> parameters = null;
            var route = context.Configuration.RouteTable.FirstOrDefault(r => r.IsMatch(url, out parameters));

            //check if route exists
            if (route == null)
            {
                return(false);
            }

            context.Route      = route;
            context.Parameters = parameters;

            var presenter = context.Presenter = route.GetPresenter();
            var filters   = ActionFilterHelper.GetActionFilters <IRequestActionFilter>(presenter.GetType().GetTypeInfo());

            filters.AddRange(context.Configuration.Runtime.GlobalFilters.OfType <IRequestActionFilter>());
            try
            {
                foreach (var f in filters)
                {
                    await f.OnPageLoadingAsync(context);
                }
                await presenter.ProcessRequest(context);

                foreach (var f in filters)
                {
                    await f.OnPageLoadedAsync(context);
                }
            }
            catch (DotvvmInterruptRequestExecutionException) { } // the response has already been generated, do nothing
            catch (DotvvmHttpException) { throw; }
            catch (Exception exception)
            {
                foreach (var f in filters)
                {
                    await f.OnPageExceptionAsync(context, exception);

                    if (context.IsPageExceptionHandled)
                    {
                        context.InterruptRequest();
                    }
                }
                throw;
            }
            return(true);
        }