0

I am making an Aspnetcore project for a client but facing a problem while getting the user/visitor registered and getting the current logged in visitor.

I have made the modal - Visitor.cs below:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;

namespace API.Entities
{
    public class Visitor : IdentityUser
    {
       [Required, MaxLength(200)]
       public string Name { get; set; } 

       [NotMapped]
       public IFormFile ProfilePhoto { get; set; }
       public string Token { get; set; }

    }
}

similaly my loginDTO and registerDTO are as follows-

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

namespace API.DTOs
{
    public class RegisterDTO
    {
       [Required, MaxLength(200)]
       public string Name { get; set; } 
       public string UserName { get; set; }
       public string Email { get; set; }

       [NotMapped]
       public IFormFile ProfilePhoto { get; set; }

       public string Password { get; set; }

    }
}

loginDTO -

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace API.DTOs
{
    public class LoginDTO
    {
       [Required, MaxLength(200)]
       public string UserName { get; set; }
       public string Password { get; set; }
    }
}

finally i am returning the new VisitorDTO to the client on the successful log in of the user -

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

namespace API.DTOs
{
    public class VisitorDTO
    {
       public string Name { get; set; } 
       public string Email { get; set; }

       public string Token { get; set; }

       
       public string ProfilePhoto { get; set; }

    }
}

In order to register the user I am creating the new instance of the Visitor which is effectively taking its data from the registerDTO modal. It is indeed working fine as so do the loginUser() - method, but after logged in I want to get a currentUser which will return the VisitorDTO to the client's browser.

On testing the functionality of the post and get methods for register and login respectively on swagger , they both are working fine as expected. But the currentUser (httpGet) is throwing a 500 error as

 "title": "Value cannot be null. (Parameter 'userName')",
  "status": 500,
  "detail": "   at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)\n   at API.Controllers.VisitorController.GetCurrentVisitor() in /Users/himanshu/SnakeLadder/API/Controllers/VisitorController.cs:line 74\n   at lambda_method258(Closure , Object )\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()\n--- End of stack trace from previous location ---\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)\n   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)\n   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)\n   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)\n   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)\n   at API.Middleware.customMiddleware.InvokeAsync(HttpContext context) in /Users/himanshu/SnakeLadder/API/Middleware/customMiddleware.cs:line 28"
}

and here is my VisitorController.cs class

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using API.Data;
using API.DTOs;
using API.Entities;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.Diagnostics;

namespace API.Controllers
{
    public class VisitorController : BaseAPIController
    {
        private readonly UserManager<Visitor> _userManager;
        private readonly GameContext _gameContext;
        public VisitorController(GameContext gameContext, UserManager<Visitor> userManager)
        {
            _userManager = userManager;
            _gameContext = gameContext;
            
        }

//register visitor
[HttpPost("register")]
public async Task<IActionResult> RegisterUser([FromForm]RegisterDTO registerDTO){
var photoUrl = await SaveProfile(registerDTO.ProfilePhoto);
var registeredVisitor = new Visitor {
Name = registerDTO.Name,
UserName = registerDTO.UserName,
ProfilePhoto = registerDTO.ProfilePhoto,
Email = registerDTO.Email,
Token = ""
};

var result = await _userManager.CreateAsync(registeredVisitor, registerDTO.Password);

if (!result.Succeeded) {
    foreach(var Error in result.Errors)
    {
        ModelState.AddModelError(Error.Code, Error.Description);
    }
    return ValidationProblem();
}
await _userManager.AddToRoleAsync(registeredVisitor, "Member");
return Ok($"User {registeredVisitor.Name} is successfully registered to the server. Thank You : )");
}

[HttpPost("loginUser")]
public async Task<ActionResult<VisitorDTO>> LoginUser(LoginDTO loginDTO){
    var loggedinUser = await _userManager.FindByNameAsync(loginDTO.UserName);
    if (loggedinUser == null || !await _userManager.CheckPasswordAsync(loggedinUser, loginDTO.Password)) {
return Unauthorized(new ProblemDetails{
    Title = "Unauthorized",
    Status = 401,
    Detail = "Your Username or Password is incorrect! Please try again..."
});
}

    return new VisitorDTO{
        Email = loggedinUser.Email,
        Name = loggedinUser.Name,
        Token = "",
        ProfilePhoto = await SaveProfile(loggedinUser.ProfilePhoto),
    };
}


[HttpGet("currentVisitor")]
public async Task<ActionResult<VisitorDTO>> GetCurrentVisitor() {
var visitorName = await _userManager.FindByNameAsync(User.Identity.Name);
Console.WriteLine(visitorName);
if(visitorName == null) return BadRequest(new ProblemDetails{Title = "Username cannot be found!"});

return new VisitorDTO{
    Email = visitorName.Email,
    ProfilePhoto = await SaveProfile(visitorName.ProfilePhoto),
    Token = visitorName.Token,
    Name = visitorName.Name,
};
/*var uploadedFile = await SaveProfile(visitor.ProfilePhoto);
if(uploadedFile.Length > 0){*/
/*}else{
    return BadRequest(new ProblemDetails{
        Title= "400 - Bad Request",
        Status = 400,
        Detail = "Problem While Uploading Profile Picture to the Server."
    });*/
}

[NonAction]
public  async Task<string> SaveProfile(IFormFile imageFile){
string fileName = null;
if (imageFile != null) {
    string uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "Uploads");
    //this is encoded file
    fileName = "Created" + DateTime.Now.ToString("yymmddhhmmss") + "+" + Guid.NewGuid().ToString() + "_" + Path.GetExtension(imageFile.FileName);
    string filePATH = Path.Combine(uploadsFolder, fileName);
    using(var fileStream = new FileStream(filePATH, FileMode.Create)){
        await imageFile.CopyToAsync(fileStream);
    }}  
return fileName;
}

private byte[] ReadImage(IFormFile file)
{
    using (var target = new MemoryStream())
    {
        file.CopyTo(target);
        return target.ToArray();
    }
}
}}

into the HttpGet("CurrentUser") I am not getting the loggedIN user's data as I wanted.

I have already migrated the data to the database into my storeContext.cs class

halfer
  • 19,824
  • 17
  • 99
  • 186
Himanshu Sharma
  • 315
  • 2
  • 9
  • 1
    Put breakpoint on _userManager.FindByNameAsync(User.Identity.Name); and see if User.Identity actually exists and not null. – AliK Sep 01 '22 at 11:30
  • yeah it is displaying as null on debugger. But I don't know why it is showing as null even if my database do contain the username inside it for that user. – Himanshu Sharma Sep 01 '22 at 12:54
  • 1
    You need to see sample code about authorization as you are not performing a login so user context will be empty. I suggest reading tutorials about authorisation in .net. – AliK Sep 01 '22 at 17:25
  • 1
    @HimanshuSharma, your `HttpGet("CurrentUser")` call is not authorized so you don't get current user in the httpcontext. – CodingMytra Sep 02 '22 at 05:40

0 Answers0