2

I have configured my application to send a confirmation Email to the user after registration. After the registration is completed the user will see a page that is saying you need to confirm you Email:

<div *ngIf="!emailConfirmed">
  <p> Please activate your account by clicking the relevant link in your Email </p>
</div>

<div *ngIf="emailConfirmed">
  <p>
   Your Email is now confirmed, please click the below button to Log-In.
  </p>
  <a class="btn btn-md btn-success btn-color" [routerLink]="['/login']">
    Sign In
  </a>
</div>

And emailConfirmed is just a simple variable that I have defined in the emailConfirmed's typescript relevant file:

export class EmailConfirmed {
  public emailConfirmed: boolean;
}

After the user clicks on the link in his/her Email, his/her account will be verified and then the application will be redirected to the ConfirmEmail page again using the below code:

[HttpGet]
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
public async Task<IActionResult> ConfirmEmail(string userId = "", string code = "")
{
    //....
    IdentityResult result = await UserManager.ConfirmEmailAsync(userId, code);
    if (result.Succeeded)
    {
        return Redirect("http://localhost:5000/emailconfirmed");
    }
}

Now the question is: I don't know how can I set the emailConfirmed variable of EmailConfirmed component to true from WEB API and in the return Redirect line, in order the user see the second message this time? Also I doubt that I have chosen the best way to redirect the application to an Angular route using the return Redirect("http://localhost:5000/emailconfirmed"); line.

3 Answers3

2

@ManojChoudhari is right. You can't route like this!

First it should be a "HttpPost". Return a response and then redirect on the clientside using router. Here is a little example. This does not take into account the separation of concerns!

Serverside

Models

public class UserRequest {
    public string UserId { get; set; }
    public string Code { get; set; }
}

public class EMailConfirmationResponse {
    public boolean EmailConfirmed { get; set; }
}

Controller

...
[HttpPost]
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
public async Task<IHttpActionResult> ConfirmEmail(UserRequest user)
{
    var result = await UserManager.ConfirmEmailAsync(user.UserId, user.Code)
    if (result.Succeeded)
    {
        return Ok(new EMailConfirmationResponse { EmailConfirmed = true });
    }
    else
    {
        return BadRequest("An error occurred confirming the given email-address.");
    }
}
...

Clientside

import { Component } from "@angular/core";
import { Router } from "@angular/router";
import { HttpClient } from "@angular/common/http";
@Component({
    selector: "your",
    templateUrl: "./your.component.html"
})
export class YourAngularComponent {
    constructor(
        private _router: Router,
        private _http: Http
    ) {

... 
    // put this into your method
    const httpOptions = { headers: new HttpHeaders({'Content-Type':  'application/json', 'Authorization': 'my-auth-token'}) };
    this.http
        .post("webapiurl", { userId: "TheUserId", code: "TheUserCode" }, httpOptions)
        .subscribe((response) => {
            const emailConfirmationResponse = response.json();
            if(emailConfirmationResponse.emailConfirmed) {
                this._router.navigate(["emailconfirmed"]);
            }
        }, (err: HttpErrorResponse) => {
            // do some error handling here:
            console.log(err.error);
            console.log(err.name);
            console.log(err.message);
            console.log(err.status);
        }
    );
...
Pierre
  • 794
  • 5
  • 15
  • Thanks. Could you please show me also the client-side part? What I need to do in the client? –  May 02 '19 at 09:44
  • thanks @Pierre. I was about to type this same example. Thanks for adding it. – Manoj Choudhari May 02 '19 at 09:46
  • 1
    So you mean I should change the CallbackURL that I send as an Email to user to point to an angular route instead and then I call an HttpPost from angular component to my API to enable the confirm property and then use the result? –  May 02 '19 at 18:06
1

One thing you need to understand is - the Angular routes are only available on client side. You will not be able to redirect user to angular template from server side.

The option you have probably is to return some flag from web API. This flag should be unique and then angular should redirect user to other page.

Your API Code should be:

[HttpGet]
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
public async Task<IActionResult> ConfirmEmail(string userId = "", string code = "")
{
    //....
    IdentityResult result = await UserManager.ConfirmEmailAsync(userId, code);
    if (result.Succeeded)
    {
        return Ok();
    }
    else
    {
        return BadRequest("An error occurred confirming the given email-address.");
    }
}

In your client side typescript you can add below code:

//// result = call web api and take result
//// if result is 200 OK then
this.router.navigate(['/your-path'])

Hope this helps.

Manoj Choudhari
  • 5,277
  • 2
  • 26
  • 37
  • Thanks. Would you please show me an example of how can I do this? I am new to Angular and don't have any idea what I need to do to achieve what you said. –  May 02 '19 at 08:59
  • @J.P - does this [link](https://stackoverflow.com/questions/38791267/using-angular-route-in-webapi-application) help ? – Manoj Choudhari May 02 '19 at 09:05
  • No. I checked the link but I think It is different from mine. –  May 02 '19 at 09:08
  • I need to find a way to set the `emailConfirmed` to true after Email is confirmed. –  May 02 '19 at 09:10
  • Did you try making ajax call and returning bool from web api ? on client side, then you can direct to new page using angular route to other page. – Manoj Choudhari May 02 '19 at 09:13
  • I don't know how can I implement what you are saying. I am sure that there is something very simple to set this variable, but as I am new to Angular I don't have really an idea. –  May 02 '19 at 09:16
  • The problem is I haven't called the API from client, I have called it when the user clicks on the link in his/her Email. –  May 02 '19 at 10:12
  • Then you will have to redirect user to special page, from their you can redirect to email confirmed successfully page. – Manoj Choudhari May 02 '19 at 10:20
  • you should use return Redirect(url.ToString()); where url.Tostring() should be your public facing URL and you can send some query string to tell that email was successfully verified. That page can then use typescript code to redirect to appropriate angular route. – Manoj Choudhari May 02 '19 at 10:22
  • I have already redirected the user with `return Redirect("http://localhost:5000/emailconfirmed");`. Do you mean a different url? Can you show what's your mean? –  May 02 '19 at 10:49
0

I guess directly from webapi you can't redirect. use Api response and then in angular redirect to another page or domain.

Muni Chittem
  • 988
  • 9
  • 17