After I added some logic to the server side, I don't get the result on the client side. I tested my server with postman and I'm getting the response via postman, but not with my react app, so I think it's a client side issue, and I don't know what I'm missing.
const getData= async () => {
const { history } = props;
const response = await fetch('member/data');
if (response.status === 401) {
history.push('/unauthorized');
setUser({ ...user, loggedIn: false })
} else {
const data = JSON.parse(await response.text());
console.log(data)// prints nothing to cosole
setLoading(false);
setData(data.allUsers);
}
}
useEffect( () => {
getData().catch(console.error);
}, []);
I don't see any errors in the console, and nothing is printed to it
Server side before change:
public IActionResult Get()
{
return Ok(new {_usersRepository.GetAll().ToList()});
}
Server side after change:
public async Task<IActionResult> Get()
{
//getting user id from token...
return Ok(new {await context.Users.Include(x => x.Enrolled).SingleOrDefaultAsync(x => x.Id==id)});
}
Related
I have three function in .Net web api in .Net 6.
First:
[HttpPost("name/{name}")]
public async Task<ActionResult<Book>> PostOrder(string name, Book book)
{
try
{
var id = _context.Order.Where(el => el.User == name).Select(el => el.OrderID).FirstOrDefault();
if (id > 0)
{
book.OrderID = id;
_context.Book.Update(book);
await _context.SaveChangesAsync();
return book;
}
else
{
Order o = new()
{
User = name
};
_context.Order.Add(o);
await _context.SaveChangesAsync();
id = _context.Order.Where(el => el.User == name).Select(el => el.OrderID).FirstOrDefault();
book.OrderID = id;
_context.Book.Update(book);
await _context.SaveChangesAsync();
return book;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return NotFound();
}
}
Second and third
[HttpPut("{id}")]
public async Task<IActionResult> PutUser(int id, User user)
{
if (id != user.id)
{
return BadRequest();
}
_context.Entry(user).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!UserExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Users
[HttpPost]
public async Task<ActionResult<User>> PostUser(User user)
{
_context.User.Add(user);
await _context.SaveChangesAsync();
return CreatedAtAction("GetUser", new { id = user.id }, user);
}
And I use to communication Angular:
First:
addToOrder(user: string, book: Book): Observable<Book> {
const url = `${this.orderUrl}/name/${user}`;
return this.http.post<Book>(this.orderUrl, book, this.httpOptions).pipe(
tap(_ => this.log(`added book to order for ${user}`)),
catchError(this.handleError<Book>('addToOrder'))
);
}
Second and third:
updateUser(user: User): Observable<any> {
const url = `${this.usersUrl}/${user.id}`;
return this.http.put(url, user, this.httpOptions).pipe(
tap(_ => this.log(`updated users id=${user.id}`)),
catchError(this.handleError<any>('updateUser'))
);
}
addUser(user: User): Observable<User> {
return this.http.post<User>(this.usersUrl, user, this.httpOptions).pipe(
tap((newUser: User) => this.log(`added user w/ id=${newUser.id}`)),
catchError(this.handleError<User>('addUser'))
);
}
And first no working. No communicating with .Net, where is wrong data? I can't find any. Mayby parameters is incorect. But I do not see. Any other function working, I have responde and in debug the server is requested but on first request no. Only in POSTMAN or SWAGGER.
I have in orders on Angular:
getOrder(user: string): Observable<Book[]> {
const url = `${this.orderUrl}/name/${user}`;
return this.http.get<Book[]>(url)
.pipe(
tap(_ => this.log(`fetched order for name=${user}`)),
catchError(this.handleError<Book[]>('getBooks', []))
);
}
Is working to.
When I try to use Postman or Swagger I see responde.
P.S when I coppy address on debug from:
const url = `${this.orderUrl}/name/${user}`;
And try in postman added Book in JSON:
{
"bookID": 4,
"title": "string2",
"author": "strin2g",
"isbn": "stri2ng"
}
I have responde.
By default POST method parameters must all be in the request body (FromBody).
GET method parameters must all be in the request query (FromUri).
To change this behavior, you need to add Parameters Bindings.
.net Parameter Binding docs
Changes
[HttpPost("name/{name}")]
public async Task<ActionResult<Book>> PostOrder(
[FromUri] string name,
[FromBody] Book book)
{
// CODE
}
Ok. I have a answer. I havae a:
const url = `${this.orderUrl}/name/${user}`;
return this.http.post<Book>(this.orderUrl, book, this.httpOptions)
But must be:
const url = `${this.orderUrl}/name/${user}`;
return this.http.post<Book>(url, book, this.httpOptions)
Sory for problem. I didn't notice it.
I have the below method in my user controller:
[HttpPost]
public async Task<ActionResult<bool>> Create(User user)
{
var userCreated = userService.register(user); // returns true or false
if (userCreated)
{
return Ok();
}
else
{
return BadRequest("Could not create user.");
}
}
This method should then be captured in my angular calling the service:
onSubmit(user: User): void {
this.userService.registerUser(user).subscribe((response) => {
console.warn(response);
});
}
The register URL method:
registerUser(user: User): Observable <boolean> {
const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) };
return this.http.post<boolean>(environment.userUrl, user, httpOptions);
}
Unfortunately, the console writes null. Am I missing out anything? I want to capture whether the status is OK or BadRequest.
In your controller you are missing to return the value of your response:
[HttpPost]
public async Task<ActionResult<bool>> Create(User user)
{
var userCreated = userService.register(user); // returns true or false
if (userCreated)
{
return Ok(userCreated); // <= HERE
}
else
{
return BadRequest("Could not create user.");
}
}
After changing the above, you should be OK.
A small tip is that you don't need to add HttpOptions on every request in Angular.
The HttpClient is doing that for you:
registerUser(user: User): Observable<boolean> {
return this.http.post<boolean>(environment.userUrl, user);
}
PS: Ok() in C# means that you are returning a response with code 200.
On the other hand, a BadRequest() will result a 400 error code and will be caught as error inside subscription. In your case I thing that the code in the back end should be like this:
[HttpPost]
public async Task<ActionResult<bool>> Create(User user)
{
var userCreated = userService.register(user); // returns true or false
return Ok(userCreated);
}
I am using Angular 9 (localhost:4200) and WebAPI with dotnet Core 3.1 (localhost:5000). During user registration I pass user data from Client to Server and then in Register method I send him an email to verify. After user clicks the link it redirects him to localhost:5000 to VerifyEmail method.
How to create a link in Registration function so the code could hit the client function first and then confirm verification on server?
Or there is better way to confirm email with Angular/dotnet core WebApi?
Client Side:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { User } from '../_models/user';
import { environment } from '../../environments/environment';
#Injectable({
providedIn: 'root'
})
export class AuthService {
baseUrl = environment.apiUrl + 'auth/';
constructor(private http: HttpClient) {}
register(user: User) {
return this.http.post(this.baseUrl + 'register', user);
}
}
verifyEmail(data: any) { // not used
return this.http.post(this.baseUrl + 'VerifyEmail', data);
}
Server Side:
[HttpPost("register")]
public async Task<IActionResult> Register(UserForRegisterDto userForRegisterDto)
{
var code = string.Empty;
var userToCreate = _mapper.Map<User>(userForRegisterDto);
try
{
var userExists = await _userManager.FindByNameAsync(userToCreate.UserName);
if (userExists == null)
{
var result = await _userManager.CreateAsync(userToCreate, userForRegisterDto.Password);
code = await _userManager.GenerateEmailConfirmationTokenAsync(userToCreate);
if (result.Succeeded)
{
//some code
}
}
else
{
var emailConfirmed = await _userManager.IsEmailConfirmedAsync(userExists);
code = await _userManager.GenerateEmailConfirmationTokenAsync(userExists);
if (emailConfirmed)
{
return Ok();
}
}
var link = Url.Action(nameof(VerifyEmail), "Auth", new { userId = userToCreate.Id, code }, Request.Scheme, Request.Host.ToString());
await _emailService.SendAsync("test#test.com", "email verify", $"Verify Email", true);
}
catch (Exception ex)
{
throw;
}
return Ok();
}
public async Task<IActionResult> VerifyEmail(string userId, string code)
{
if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(code))
{
return BadRequest();
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return BadRequest();
}
if (user.EmailConfirmed)
{
//return Ok();
}
var result = await _userManager.ConfirmEmailAsync(user, code);
if (result.Succeeded)
{
return Ok();
}
return BadRequest();
}
Thank you in advance for any help and your time!
I'd create a new angular component that resolves to /verify-email route and from there called AuthService
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'email-verification',
template: '<h1>{{status}}</h1>',
styleUrls: [ './email-verification.component.css' ]
})
export class EmailVerificationComponent implements OnInit {
status: string = "Verifying...";
constructor(private authService: AuthService){}
ngOnInit() {
this.authService.verifyEmail().subscribe(_ => this.status = "Email verified!");
//redirect to another component
}
}
Iam getting a 401 unauthorized error while authorizing an user to consume an api on .net core and angular 7 application.
My angular service has a function :-
getUserProfile() {
var tokenHeader = new HttpHeaders({'Authorization':'Bearer ' + localStorage.getItem('token')});
console.log(tokenHeader)
return this.http.get('/api/ApplicationUser/UserProfile', { headers: tokenHeader});
}
on tokenHeader I am sending the user jwt token.
My api is
[HttpGet]
[Authorize]
[Route("UserProfile")]
//'api/userProfile'
public async Task<Object> GetUserProfile()
{
string userId = User.Claims.First(c => c.Type == "UserID").Value;
var user = await _userManager.FindByIdAsync(userId);
return new { user.fullName, user.Email, user.UserName };
}
I have tried some answers from other questions but nothing helps.
Any helps appreciated.
Your code should be like this
const httpOptions = {
headers: new HttpHeaders({
'Authorization': `Bearer ${localStorage.getItem('token')}`
})
};
return this.http.get('/api/ApplicationUser/UserProfile', httpOptions);
Also make sure you have this line in your controller
[Authorize(AuthenticationSchemes = "Bearer")]
Can you share your request from network tab.
Also I recommend to use interceptors for make it global
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
private isRefreshing = false;
private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
constructor(public authService: AuthService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.authService.getJwtToken()) {
request = this.addToken(request, this.authService.getJwtToken());
}
return next.handle(request).pipe(catchError(error => {
if (error instanceof HttpErrorResponse && error.status === 401) {
return this.handle401Error(request, next);
} else {
return throwError(error);
}
}));
}
private addToken(request: HttpRequest<any>, token: string) {
return request.clone({
setHeaders: {
'Authorization': `Bearer ${token}`
}
});
}
private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshing) {
this.isRefreshing = true;
this.refreshTokenSubject.next(null);
return this.authService.refreshToken().pipe(
switchMap((token: any) => {
this.isRefreshing = false;
this.refreshTokenSubject.next(token.jwt);
return next.handle(this.addToken(request, token.jwt));
}));
} else {
return this.refreshTokenSubject.pipe(
filter(token => token != null),
take(1),
switchMap(jwt => {
return next.handle(this.addToken(request, jwt));
}));
}
}
}
Full example https://github.com/bartosz-io/jwt-auth-angular/blob/master/src/app/auth/token.interceptor.ts
I am connecting to the Quickbooks api, download the employees inforamtion and saving it to my local database. I am using angularjs, webapi to accomplish this. I am getting the following error when I am saving the info to database. I do see all the functions have async and await. Can some body please help me why I am getting this error.
Error :
Server Error in '/' Application.An asynchronous module or handler completed while an asynchronous operation was still pending.
Problem is happening in the below pasted piece of code:
var candidate = await CandidateLoginBL.AddCandidateByEmployeeAsync(new CandidateLoginBO()
{
FirstName = e.GivenName,
MiddleName = e.MiddleName,
LastName = e.FamilyName
});
}
});
The full flow is as follows :
js :
QuickbookModule.factory('QuickbookService', ['$http', function ($http) {
return {
getQuickbooksSync: function () {
return $http({
url: '/api/QuickbookService/syncQuickbooks',
method: 'GET',
params: { IdCompany: sessionStorage.CID }
});
}
API Controller :
[HttpGet]
[Route("syncQuickbooks")]
public async Task<IHttpActionResult> syncQuickbooks(int IdCompany)
{
var result = await QuickbooksBL.FullQuickbooksSync(IdCompany);
return Ok(result);
}
QuickbooksBL :
public static async Task<List<IncompleteEmp>> FullQuickbooksSync(int IdCompany)
{return await SyncronizeEmps(IdCompany); }
public static async Task<List<IncompleteEmp>> SyncronizeEmps(int companyId)
{
......
List<EmployeeBO> empList = new List<EmployeeBO>();
await AddToHumanEfits(companyId, inQBEmpsInfo); ....
}
return IncompleteEmps;
}
public static async Task AddToHumanEfits(int companyId, List<EmployeeQbOnlineBO> qbEmpsList)
{
....
qbEmpsList.ForEach(async e =>
{
// Add a record into Candidate Login.
var candidate = await CandidateLoginBL.AddCandidateByEmployeeAsync(new CandidateLoginBO()
{
FirstName = e.GivenName,
MiddleName = e.MiddleName,
LastName = e.FamilyName });
}
});
}
CandidateContactBL :
public static async Task<CandidateLoginBO> AddCandidateByEmployeeAsync(CandidateLoginBO model)
{
return await CandidateLoginDAL.AddCandidateByEmployeeAsync(model);
}
CandidateContactDAL :
public static async Task<CandidateLoginBO> AddCandidateByEmployeeAsync(CandidateLoginBO model)
{
CandidateLoginBO candidate = new CandidateLoginBO();
candidate = await GetByUserNameAsync(new CandidateLoginBO() { Email = model.Email }); candidate = await AddEmployeeAsync(model);
return candidate;
}
This kind of error is commonly caused by async void. And I see one right here:
qbEmpsList.ForEach(async e =>
{
...
});
You'd probably want to make this into a regular foreach:
foreach (var e in qbEmpsList)
{
...
}