Skip to content
This repository was archived by the owner on Apr 8, 2020. It is now read-only.

Angular-CLI-Based-Template: Appropriate way to return HTTP Status Code #1423

Closed
naveedahmed1 opened this issue Dec 8, 2017 · 6 comments
Closed

Comments

@naveedahmed1
Copy link

naveedahmed1 commented Dec 8, 2017

@SteveSandersonMS with new Angular CLI based template what is the most appropriate way to return proper HTTP Response Code for example 404 for page not found?

For Angular part we can do something like this https://stackoverflow.com/a/46790709/2755616 but how would we grab and handle the status code passed from Angular in .Net with this new template.

@naveedahmed1
Copy link
Author

@SteveSandersonMS I tried adding the below controller but it doesn't seem to work:

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.NodeServices;
using Microsoft.AspNetCore.SpaServices.Prerendering;
using System.Net;
using System.Threading.Tasks;

namespace Mustakbil.Controllers
{
    public class HomeController : Controller
    {
        public async Task<IActionResult> Index([FromServices] INodeServices nodeServices, [FromServices] IHostingEnvironment hostEnv)
        {
            var applicationBasePath = hostEnv.ContentRootPath;
            var requestFeature = Request.HttpContext.Features.Get<IHttpRequestFeature>();
            var unencodedPathAndQuery = requestFeature.RawTarget;
            var unencodedAbsoluteUrl = $"{Request.Scheme}://{Request.Host}{unencodedPathAndQuery}";

            System.Threading.CancellationTokenSource cancelSource = new System.Threading.CancellationTokenSource();
            System.Threading.CancellationToken cancelToken = cancelSource.Token;

            var prerenderResult = await Prerenderer.RenderToString(
                      "/",
                      nodeServices,
                      cancelToken,
                      new JavaScriptModuleExport(applicationBasePath + "/ClientApp/dist-server/main.bundle.js"),
                      unencodedAbsoluteUrl,
                      unencodedPathAndQuery,
                      null,
                      30000,
                      Request.PathBase.ToString()
                  );

            ViewData["html"] = prerenderResult.Html;
            int statusCode = (int)prerenderResult.Globals["statusCode"];

            Response.StatusCode = statusCode > 0 ? statusCode : (int)HttpStatusCode.OK;

            return View();
        }
    }
}

@chrisvfabio
Copy link

@naveedahmed1

I also needed to render the html via a Controller for converting it into a pdf for a specific endpoint. I got it working by using ngAspnetCoreEngine in main.server:

ngAspnetCoreEngine requires a request object to be passed in, so need to add it to the customDataParameter:

HomeController.cs

var prerenderResult = await Prerenderer.RenderToString(
  "/",
  nodeServices,
  cancelToken,
  new JavaScriptModuleExport(applicationBasePath + "/ClientApp/dist-server/main.bundle.js"),
  unencodedAbsoluteUrl,
  unencodedPathAndQuery,
  new Dictionary<string, object>{ { "request", Request.AbstractRequestInfo()} },
  0,
  Request.PathBase.ToString());

main.server.ts

export default createServerRenderer(params => {
  const { AppServerModule, AppServerModuleNgFactory, LAZY_MODULE_MAP } = (module as any).exports;

  // Platform-server provider configuration
  const setupOptions: IEngineOptions = {
    appSelector: '<app-root></app-root>',
    ngModule: AppServerModuleNgFactory ? AppServerModuleNgFactory : AppServerModule,
    request: params,
    providers: [
      provideModuleMap(LAZY_MODULE_MAP),
      { provide: APP_BASE_HREF, useValue: params.baseUrl },
      { provide: 'BASE_URL', useValue: params.origin + params.baseUrl },
    ]
  };

  return ngAspnetCoreEngine(setupOptions).then(response => {
    return ({
      html: response.html,
      globals: response.globals
    });
  });
});

This was based off @MarkPieszak template. I don't know of any other way to fetch the prerendered html on the server. I also had to add a [Route("")] to the HomeController to bypass the spa routing.

@SteveSandersonMS
Copy link
Member

This was a missing feature in the new SpaServices.Extensions package. Now implemented in 8ded472 and will be included in the next preview release and/or the final release.

@naveedahmed1
Copy link
Author

naveedahmed1 commented Dec 12, 2017

Very quick, You're awesome @SteveSandersonMS . Can you please also guide what changes would be needed in main.server? Especially if the status code is coming from a service.

Would appreciate if you could please answer this over here https://stackoverflow.com/questions/47760100/angular-5-using-value-from-a-service-in-createserverrenderer

Thanks @chrisvfabio with 8ded472 it should be simple.

@naveedahmed1
Copy link
Author

@SteveSandersonMS can you please update documentation about this feature?

Please also share the status of the template, when do you plan to release it?

@naveedahmed1
Copy link
Author

Can anyone please review this approach to return status code, and share feedback:

https://stackoverflow.com/a/50937983/2755616

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants