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); }
protected override async Task OnPageExceptionAsync(IDotvvmRequestContext context, Exception exception) { if (exception is ObjectNotFoundException) { context.HttpContext.Response.StatusCode = 404; context.InterruptRequest(); } await base.OnPageExceptionAsync(context, exception); }
internal static async Task InterruptRequestAsync(this IDotvvmRequestContext context, HttpStatusCode statusCode, string?message = null) { context.HttpContext.Response.StatusCode = (int)statusCode; if (!string.IsNullOrEmpty(message)) { await context.HttpContext.Response.WriteAsync(message !); } context.InterruptRequest(); }
/// <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); } }
/// <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; } }
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); }