Пример #1
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);
            }
        }
Пример #2
0
        public async Task ProcessRequestCore(DotvvmRequestContext context)
        {
            if (context.OwinContext.Request.Method != "GET" && context.OwinContext.Request.Method != "POST")
            {
                // unknown HTTP method
                context.OwinContext.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                throw new DotvvmHttpException("Only GET and POST methods are supported!");
            }
            if (context.OwinContext.Request.Headers["X-PostbackType"] == "StaticCommand")
            {
                ProcessStaticCommandRequest(context);
                return;
            }
            var isPostBack = DetermineIsPostBack(context.OwinContext);

            context.IsPostBack = isPostBack;
            context.ChangeCurrentCulture(context.Configuration.DefaultCulture);

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

            page.SetValue(Internal.RequestContextProperty, context);

            // run the preinit phase in the page
            DotvvmControlCollection.InvokePageLifeCycleEventRecursive(page, LifeCycleEventType.PreInit);

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

            // get action filters
            var globalFilters    = context.Configuration.Runtime.GlobalFilters.ToList();
            var viewModelFilters = context.ViewModel.GetType().GetCustomAttributes <ActionFilterAttribute>(true).ToList();

            // run OnViewModelCreated on action filters
            foreach (var filter in globalFilters.Concat(viewModelFilters))
            {
                filter.OnViewModelCreated(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.OwinContext.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 = actionInfo.Binding.ActionFilters == null?globalFilters.Concat(viewModelFilters).ToArray() :
                                            globalFilters.Concat(viewModelFilters).Concat(actionInfo.Binding.ActionFilters).ToArray();

                    // run OnCommandExecuting on action filters
                    foreach (var filter in methodFilters)
                    {
                        filter.OnCommandExecuting(context, actionInfo);
                    }

                    Exception commandException = null;
                    try
                    {
                        var result = actionInfo.Action();
                        if (result is Task)
                        {
                            await(Task) result;
                        }
                    }
                    catch (Exception ex)
                    {
                        if (ex is TargetInvocationException)
                        {
                            ex = ex.InnerException;
                        }
                        if (ex is DotvvmInterruptRequestExecutionException)
                        {
                            throw new DotvvmInterruptRequestExecutionException("The request execution was interrupted in the command!", ex);
                        }
                        commandException = ex;
                    }

                    // run OnCommandExecuted on action filters
                    foreach (var filter in methodFilters)
                    {
                        filter.OnCommandExecuted(context, actionInfo, commandException);
                    }

                    if (commandException != null && !context.IsCommandExceptionHandled)
                    {
                        throw new Exception("Unhandled exception occured in the command!", commandException);
                    }
                }
            }

            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 globalFilters.Concat(viewModelFilters))
            {
                filter.OnResponseRendering(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);
            }
        }
Пример #3
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;
            }
        }