0

I'm trying something new and that would be using ASP.NET Core as my backend while using Angular for the frontend. While the backend was a breeze to configure, the frontend haven't been as close. When I try running the application, I receive the following errors in teh console:

> integrafechado@0.0.0 prestart
> node aspnetcore-https


> integrafechado@0.0.0 start
> run-script-os


> integrafechado@0.0.0 start:windows
> ng serve --port 44488 --ssl --ssl-cert "%APPDATA%\ASP.NET\https\%npm_package_name%.pem" --ssl-key "%APPDATA%\ASP.NET\https\%npm_package_name%.key"


Initial Chunk Files   | Names         |  Raw Size
vendor.js             | vendor        |   3.03 MB |
styles.css, styles.js | styles        | 440.48 kB |
polyfills.js          | polyfills     | 434.76 kB |
main.js               | main          | 181.56 kB |
runtime.js            | runtime       |   6.53 kB |

                      | Initial Total |   4.07 MB

Build at: 2023-06-12T15:15:32.894Z - Hash: bdb0de9435970ca7 - Time: 2757ms

Error: src/api-authorization/login/login.component.html:6:13 - error NG8002: Can't bind to 'formGroup' since it isn't a known property of 'form'.

6             [formGroup]="loginForm"
              ~~~~~~~~~~~~~~~~~~~~~~~

  src/api-authorization/login/login.component.ts:16:15
    16  templateUrl: "./login.component.html",
                     ~~~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component LoginComponent.


Error: src/api-authorization/login/login.component.html:6:26 - error TS2339: Property 'loginForm' does not exist on type 'LoginComponent'.

6             [formGroup]="loginForm"
                           ~~~~~~~~~

  src/api-authorization/login/login.component.ts:16:15
    16  templateUrl: "./login.component.html",
                     ~~~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component LoginComponent.


Error: src/api-authorization/login/login.component.html:7:25 - error TS2341: Property 'login' is private and only accessible within class 'LoginComponent'.

7             (ngSubmit)="login(loginForm.value)"
                          ~~~~~

  src/api-authorization/login/login.component.ts:16:15
    16  templateUrl: "./login.component.html",
                     ~~~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component LoginComponent.


Error: src/api-authorization/login/login.component.html:7:31 - error TS2339: Property 'loginForm' does not exist on type 'LoginComponent'.

7             (ngSubmit)="login(loginForm.value)"
                                ~~~~~~~~~

  src/api-authorization/login/login.component.ts:16:15
    16  templateUrl: "./login.component.html",
                     ~~~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component LoginComponent.


Error: src/api-authorization/login/login.component.html:69:1 - error NG8001: 'app-footer' is not a known element:
1. If 'app-footer' is an Angular component, then verify that it is part of this module.
2. If 'app-footer' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.

69 <app-footer></app-footer>
   ~~~~~~~~~~~~

  src/api-authorization/login/login.component.ts:16:15
    16  templateUrl: "./login.component.html",
                     ~~~~~~~~~~~~~~~~~~~~~~~~
    Error occurs in the template of component LoginComponent.




** Angular Live Development Server is listening on localhost:44488, open your browser on https://localhost:44488/ **


× Failed to compile.

Here's the login.component.html file:

<div class="login-container">
  <div id="container-main" class="login-container-main">
    <label id="login-label" for="login-form" class="login-text">Login</label>
    <div id="container-form" class="login-container-form">
      <form id="login-form"
            [formGroup]="loginForm"
            (ngSubmit)="login(loginForm.value)"
            name="login-form"
            target="self"
            enctype="application/x-www-form-urlencoded"
            class="login-form">
        <div class="login-container-labels">
          <div id="email-label-div" class="login-container1">
            <label id="email-label" for="email-input" class="login-text1">
              E-mail
            </label>
          </div>
          <div id="senha-label-div" class="login-container2">
            <label id="password-label" for="password-input" class="login-text2">
              Senha
            </label>
          </div>
          <div id="register-div" class="login-container3">
            <label id="noregister-label"
                   for="register-button"
                   class="login-text3">
              Não tem conta?
            </label>
            <button id="register-button"
                    name="register-button"
                    type="button"
                    class="login-button Link button">
              Registrar
            </button>
          </div>
        </div>
        <div class="login-container-inputs">
          <div id="email-input-div" class="login-container4">
            <input formControlName="email"
                   type="email"
                   id="email-input"
                   required
                   autofocus
                   placeholder="exemplo@exemplo.com"
                   class="input" />
          </div>
          <div id="senha-input-div" class="login-container5">
            <input formControlName="password"
                   type="password"
                   id="password-input"
                   required
                   minlength="8"
                   placeholder="Sua senha"
                   class="input" />
          </div>
          <div id="login-div" class="login-container6">
            <button type="submit" class="login-button1 button">
              <span class="login-text4">
                <span class="login-text5">Logar</span>
                <br />
              </span>
            </button>
          </div>
        </div>
      </form>
    </div>
  </div>
</div>
<app-footer></app-footer>

login.module.ts:

import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FooterComponent } from "./footer.component";
@NgModule({
    declarations: [
        FooterComponent
    ],
    imports: [
        CommonModule
    ],
    exports: [
        FooterComponent
    ]
})
export class FooterModule { }

login.component.ts:

/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-useless-escape */
/* eslint-disable no-case-declarations */
import { Component, OnInit } from "@angular/core";
import { AuthorizeService, AuthenticationResultStatus } from "../authorize.service";
import { ActivatedRoute, Router } from "@angular/router";
import { BehaviorSubject } from "rxjs";
import { LoginActions, QueryParameterNames, ApplicationPaths, ReturnUrlType } from "../api-authorization.constants";

// The main responsibility of this component is to handle the user's login process.
// This is the starting point for the login process. Any component that needs to authenticate
// a user can simply perform a redirect to this component with a returnUrl query parameter and
// let the component perform the login and return back to the return url.
@Component({
    selector: "app-login",
    templateUrl: "./login.component.html",
    styleUrls: ["./login.component.css"]
})
export class LoginComponent implements OnInit {
    public message = new BehaviorSubject<string | null | undefined>(null);

    constructor(
    private authorizeService: AuthorizeService,
    private activatedRoute: ActivatedRoute,
    private router: Router) { }

    async ngOnInit() {
        const action = this.activatedRoute.snapshot.url[1];
        switch (action.path) {
        case LoginActions.Login:
            await this.login(this.getReturnUrl());
            break;
        case LoginActions.LoginCallback:
            await this.processLoginCallback();
            break;
        case LoginActions.LoginFailed:
            const message = this.activatedRoute.snapshot.queryParamMap.get(QueryParameterNames.Message);
            this.message.next(message);
            break;
        case LoginActions.Profile:
            this.redirectToProfile();
            break;
        case LoginActions.Register:
            this.redirectToRegister();
            break;
        default:
            throw new Error(`Invalid action '${action}'`);
        }
    }


    private async login(returnUrl: string): Promise<void> {
        const state: INavigationState = { returnUrl };
        const result = await this.authorizeService.signIn(state);
        this.message.next(undefined);
        switch (result.status) {
        case AuthenticationResultStatus.Redirect:
            break;
        case AuthenticationResultStatus.Success:
            await this.navigateToReturnUrl(returnUrl);
            break;
        case AuthenticationResultStatus.Fail:
            await this.router.navigate(ApplicationPaths.LoginFailedPathComponents, {
                queryParams: { [QueryParameterNames.Message]: result.message }
            });
            break;
        default:
            throw new Error(`Invalid status result ${(result as any).status}.`);
        }
    }

    private async processLoginCallback(): Promise<void> {
        const url = window.location.href;
        const result = await this.authorizeService.completeSignIn(url);
        switch (result.status) {
        case AuthenticationResultStatus.Redirect:
            // There should not be any redirects as completeSignIn never redirects.
            throw new Error("Should not redirect.");
        case AuthenticationResultStatus.Success:
            await this.navigateToReturnUrl(this.getReturnUrl(result.state));
            break;
        case AuthenticationResultStatus.Fail:
            this.message.next(result.message);
            break;
        }
    }

    private redirectToRegister(): any {
        this.redirectToApiAuthorizationPath(
            `${ApplicationPaths.IdentityRegisterPath}?returnUrl=${encodeURI("/" + ApplicationPaths.Login)}`);
    }

    private redirectToProfile(): void {
        this.redirectToApiAuthorizationPath(ApplicationPaths.IdentityManagePath);
    }

    private async navigateToReturnUrl(returnUrl: string) {
        // It's important that we do a replace here so that we remove the callback uri with the
        // fragment containing the tokens from the browser history.
        await this.router.navigateByUrl(returnUrl, {
            replaceUrl: true
        });
    }

    private getReturnUrl(state?: INavigationState): string {
        const fromQuery = (this.activatedRoute.snapshot.queryParams as INavigationState).returnUrl;
        // If the url is coming from the query string, check that is either
        // a relative url or an absolute url
        if (fromQuery &&
      !(fromQuery.startsWith(`${window.location.origin}/`) ||
        /\/[^\/].*/.test(fromQuery))) {
            // This is an extra check to prevent open redirects.
            throw new Error("Invalid return url. The return url needs to have the same origin as the current page.");
        }
        return (state && state.returnUrl) ||
      fromQuery ||
      ApplicationPaths.DefaultLoginRedirectPath;
    }

    private redirectToApiAuthorizationPath(apiAuthorizationPath: string) {
        // It's important that we do a replace here so that when the user hits the back arrow on the
        // browser they get sent back to where it was on the app instead of to an endpoint on this
        // component.
        const redirectUrl = `${window.location.origin}/${apiAuthorizationPath}`;
        window.location.replace(redirectUrl);
    }
}

interface INavigationState {
  [ReturnUrlType]: string;
}

and finally, footer.module.ts:

import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FooterComponent } from "./footer.component";
@NgModule({
    declarations: [
        FooterComponent
    ],
    imports: [
        CommonModule
    ],
    exports: [
        FooterComponent
    ]
})
export class FooterModule { }

I'm not completely sure about what is right or wrong, VS2022 creates the new project with the base for authentication in a folder called api-authorization, but I tried using Angular's forms, although ASP.NET Core handles authentication with the middlewares. As far as I've seen, you have to create the login template for the application. Is there a simpler way to use the created login html? I'd be happy to provide more details if needed

  • [Does the answer useful to you?](https://stackoverflow.com/a/39152110/7687666) You need using this `import { FormsModule, ReactiveFormsModule } from '@angular/forms';`. – Jason Pan Jun 14 '23 at 07:24
  • I tried that too and it didn't work, I also tried moving that import around and it didn't work either. I'd still get the errors that were supposed to go away with that import. – Mat Crisanto Jun 14 '23 at 14:21
  • If this is brand new project, you could share the repo for us. If not, please hide your sensitive info and business logic code, then share the sample project which can reproduce the issue for us. Then we could help you better. – Jason Pan Jun 15 '23 at 02:45
  • I didn't find out what the problem really was, but starting a new project and simply copying what I already had worked fine, only difference is that at first I started an ASP.NET Core 7 project and now it's an ASP.NET Core 6 project. – Mat Crisanto Jun 15 '23 at 11:21
  • I don’t think .net6 is the root cause,have try to create a new .net6 project? But the good news is you can solve the issue. – Jason Pan Jun 15 '23 at 13:20
  • I don't think it is either, I've maybe deleted something by accident, anyway, thank you for the help :) – Mat Crisanto Jun 15 '23 at 13:51

1 Answers1

0

As I've told Jason in the question comments, starting a new project with .net6 instead of .net7 solved it, but I've a feeling I might've deleted something by accident, so the version of.net makes no difference here. Now it works.