(Sorry if my english sucks a little)
I'm trying to call an api method from a mvc controller but the mvc seems unable to find the method. I set the route in the mvc controller as
[Route("[controller]")]
and in the api controller as
[Route("api/[controller]")]
In the startup.cs file i added this command to enable default route
app.UseMvcWithDefaultRoute();
Mvc controller code:
[HttpGet]
public async Task<ActionResult> GetAll()
{
IEnumerable<Utente> utenti = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:57279/");
var Res = await client.GetAsync("api/utente/GetAll");
if (Res.IsSuccessStatusCode)
{
var readTask = Res.Content.ReadAsAsync<IList<Utente>>();
utenti = readTask.Result;
}
else
{
utenti = Enumerable.Empty<Utente>();
ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
}
}
return View(utenti);
}
Api code:
[HttpGet]
public IHttpActionResult GetAll()
{
IList<Utente> utenti = null;
using (_utenteContext)
{
utenti = _utenteContext.Utenti.Select(u => new Utente()
{
id = u.id,
user = u.user,
password = u.password
}).ToList<Utente>();
}
if (utenti.Count == 0)
{
return NotFound();
}
return Ok(utenti);
}
The problem might be that I'm following an old example for both mvc and api controllers in same project, but I'd like if you guys could help me with it.
In the:
var Res = await client.GetAsync("api/utente/GetAll");
I always get {StatusCode: 404, ReasonPhrase: 'Not Found',...} no matter the changes I make to the code.
EDIT:
Whole Api Controller (I was trying also with a POST method but it doesn't work either)
using AdrianWebApi.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace AdrianWebApi.Controllers.api
{
[Route("api/[controller]")]
public class UtenteController : ApiController
{
private readonly UtenteContext _utenteContext;
public UtenteController(UtenteContext context)
{
_utenteContext = context;
}
[HttpGet]
public IHttpActionResult GetAll()
{
IList<Utente> utenti = null;
using (_utenteContext)
{
utenti = _utenteContext.Utenti.Select(u => new Utente()
{
id = u.id,
user = u.user,
password = u.password
}).ToList<Utente>();
}
if (utenti.Count == 0)
{
return NotFound();
}
return Ok(utenti);
}
[HttpPost]
public IHttpActionResult PostNewUtente(Utente utente)
{
if (!ModelState.IsValid)
return BadRequest("Not a valid model");
using (_utenteContext)
{
_utenteContext.Utenti.Add(new Utente()
{
id = utente.id,
user = utente.user,
password = utente.password
});
_utenteContext.SaveChanges();
}
return Ok();
}
}
}
EDIT 2
Startup class if it's useful:
using AdrianWebApi.Models;
using AdrianWebApi.Models.DataManager;
using AdrianWebApi.Models.Repository;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace AdrianWebApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<UtenteContext>(options =>{options.UseMySQL("server=localhost;database=dbutenti;User ID=root;password=root;");});
services.AddScoped<IDataRepository<Utente>, DataManager>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvcWithDefaultRoute();
}
}
}
EDIT 3 Post method MVC if someone is interested, working, at least for me:
[Route("Add")]
[System.Web.Http.HttpPost]
public ActionResult Add([FromForm]Utente utente)
{
if (utente.password == null)
{
return View();
}
else
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:57279/api/");
//HTTP POST
var postTask = client.PostAsJsonAsync<Utente>("utente", utente);
postTask.Wait();
var result = postTask.Result;
if (result.IsSuccessStatusCode)
{
return RedirectToAction("GetAll");
}
}
ModelState.AddModelError(string.Empty, "Server Error. Please contact administrator.");
return View(utente);
}
}
Try commenting out your controller and replacing it with this code below, then go to api/utente/ and see if you get a result. If you do then replace what you need with your code.
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace AdrianWebApi.Controllers.api
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "Test 1", " Test 2" };
}
}
}
Related
I need to get token when I register, but it gives me an error
Hello everyone.
I got that error when I was trying to register to my project on Postman:
https://anotepad.com/note/read/tgrka47d
(System.InvalidOperationException: An exception was thrown while attempting to evaluate the LINQ query parameter expression 'value(DataAccess.Concrete.EntityFramework.EfUserDal+<>c__DisplayClass0_0).user.Id'. See the inner exception for more information.)
My UserManager is here:
`
using System.Collections.Generic;
using Business.Abstract;
using Core.Entities.Concrete;
using DataAccess.Abstract;
namespace Business.Concrete
{
public class UserManager : IUserService
{
IUserDal _userDal;
public UserManager(IUserDal userDal)
{
_userDal = userDal;
}
public List<OperationClaim> GetClaims(User user)
{
return _userDal.GetClaims(user);
}
public void Add(User user)
{
_userDal.Add(user);
}
public User GetByMail(string email)
{
return _userDal.Get(u => u.Email == email);
}
}
}
`
My AuthManager is here:
`
using Business.Abstract;
using Business.Constants;
using Core.Entities.Concrete;
using Core.Utilities.Results;
using Core.Utilities.Security.Hashing;
using Core.Utilities.Security.JWT;
using Entities.DTOs;
namespace Business.Concrete
{
public class AuthManager : IAuthService
{
private IUserService _userService;
private ITokenHelper _tokenHelper;
public AuthManager(IUserService userService, ITokenHelper tokenHelper)
{
_userService = userService;
_tokenHelper = tokenHelper;
}
public IDataResult<User> Register(UserForRegisterDto userForRegisterDto, string password)
{
byte[] passwordHash, passwordSalt;
HashingHelper.CreatePasswordHash(password, out passwordHash, out passwordSalt);
var user = new User
{
Email = userForRegisterDto.Email,
FirstName = userForRegisterDto.FirstName,
LastName = userForRegisterDto.LastName,
PasswordHash = passwordHash,
PasswordSalt = passwordSalt,
Status = true
};
_userService.Add(user);
return new SuccessDataResult<User>(user, Messages.UserRegistered);
}
public IDataResult<User> Login(UserForLoginDto userForLoginDto)
{
var userToCheck = _userService.GetByMail(userForLoginDto.Email);
if (userToCheck == null)
{
return new ErrorDataResult<User>(Messages.UserNotFound);
}
if (!HashingHelper.VerifyPasswordHash(userForLoginDto.Password, userToCheck.PasswordHash, userToCheck.PasswordSalt))
{
return new ErrorDataResult<User>(Messages.PasswordError);
}
return new SuccessDataResult<User>(userToCheck, Messages.SuccessfulLogin);
}
public IResult UserExists(string email)
{
if (_userService.GetByMail(email) != null)
{
return new ErrorResult(Messages.UserAlreadyExists);
}
return new SuccessResult();
}
public IDataResult<AccessToken> CreateAccessToken(User user)
{
var claims = _userService.GetClaims(user);
var accessToken = _tokenHelper.CreateToken(user, claims);
return new SuccessDataResult<AccessToken>(accessToken, Messages.AccessTokenCreated);
}
}
}
`
My AuthController is here:
`
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Business.Abstract;
using Entities.DTOs;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace WebAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AuthController : Controller
{
private IAuthService _authService;
public AuthController(IAuthService authService)
{
_authService = authService;
}
[HttpPost("login")]
public ActionResult Login(UserForLoginDto userForLoginDto)
{
var userToLogin = _authService.Login(userForLoginDto);
if (!userToLogin.Success)
{
return BadRequest(userToLogin.Message);
}
var result = _authService.CreateAccessToken(userToLogin.Data);
if (result.Success)
{
return Ok(result.Data);
}
return BadRequest(result.Message);
}
[HttpPost("register")]
public ActionResult Register(UserForRegisterDto userForRegisterDto)
{
var userExists = _authService.UserExists(userForRegisterDto.Email);
if (!userExists.Success)
{
return BadRequest(userExists.Message);
}
var registerResult = _authService.Register(userForRegisterDto,userForRegisterDto.Password);
var result = _authService.CreateAccessToken(registerResult.Data);
if (result.Success)
{
return Ok(result.Data);
}
return BadRequest(result.Message);
}
}
}
`
My EfUserDal is here:
`
using System.Collections.Generic;
using Core.DataAccess.EntityFramework;
using Core.Entities.Concrete;
using DataAccess.Abstract;
using System.Linq;
namespace DataAccess.Concrete.EntityFramework
{
public class EfUserDal : EfEntityRepositoryBase<User,CarRentalContext>,IUserDal
{
public List<OperationClaim> GetClaims(User user)
{
using (CarRentalContext context = new CarRentalContext())
{
var result = from operationClaim in context.OperationClaims
join userOperationClaim in context.UserOperationClaims
on operationClaim.Id equals userOperationClaim.OperationClaimId
where userOperationClaim.UserId == user.Id
select new OperationClaim {Id = operationClaim.Id, Name = operationClaim.Name};
return result.ToList();
}
}
}
}
`
I need to get a token when I register. How can I fix this?
You picked up the wrong lines from your stacktrace to focus on.
It states the following in the inner exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at DataAccess.Concrete.EntityFramework.EfUserDal.GetClaims(User user) in /home/mert/Desktop/Project/ReCapProject/DataAccess/Concrete/EntityFramework/EfUserDal.cs:line 20
Which means you have a variable on line 20 in your EfUserDal which does not have a value at runtime.
Since the next line mentions ToList, I'm guessing result is null after evaluating the query. Use debugging to see what value each variable in your query is getting before it's evaluated. Probably one of them is null
I'm trying to create an ActionFilter that will read the Accept-Language header and find if it matches any value in locale and if it does not match, use the a default value which is "en".
First of all, this is my handler:
using MediatR;
using Microsoft.EntityFrameworkCore;
using Subscription.Domain.Common;
using Subscription.Domain.Exceptions;
using Subscription.Infrastructure.Configuration;
using System.Net;
namespace Subscription.API.Application.Package.Queries.Get
{
public class GetHandler : IRequestHandler<GetRequest, EntityResponseModel>
{
private readonly SubscriptionContext _context;
private readonly IHttpContextAccessor _httpContext;
public GetHandler(SubscriptionContext context, IHttpContextAccessor httpContext)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_httpContext = httpContext;
}
public async Task<EntityResponseModel> Handle(GetRequest request, CancellationToken cancellationToken)
{
var lang = _httpContext.HttpContext.Request.Headers["Accept-Language"].ToString();
var packages = await _context.Packages.Where(x => !x.IsDeleted)
.Select(x => new GetResponseModel()
{
Id = x.Id,
BrandId = x.BrandId,
StartAt = x.StartAt,
IconUrl = x.IconUrl,
ImageUrl = x.ImageUrl,
CreatedAt = x.CreatedDate,
Title = x.PackageTranslations.FirstOrDefault(pt => pt.PackageId == x.Id && pt.Locale.Equals(lang)).Title,
Description = x.PackageTranslations.FirstOrDefault(pt => pt.PackageId == x.Id && pt.Locale.Equals(lang)).Description
}).ToListAsync();
if (!packages.Any())
{
throw new DomainException(HttpStatusCode.NotFound, "No record found.");
}
return new EntityResponseModel()
{
Data = packages
};
}
}
}
And this is the controller:
using Microsoft.AspNetCore.Mvc;
using MediatR;
using Subscription.API.Application.Package.Queries.Get;
using Subscription.API.Application.Bundle.Queries.GetById;
using Subscription.API.Filters;
namespace Subscription.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PackagesController : ControllerBase
{
private readonly IMediator _mediator;
public PackagesController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet]
[ValidateHeaders]
public async Task<ActionResult> GetAll()
{
var response = await _mediator.Send(new GetRequest() { });
return Ok(response);
}
}
}
This the filter class:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Subscription.API.Filters
{
public class ValidateHeaders : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var headers = context.HttpContext.Request.Headers;
// need to do something here
}
}
}
So, basically what I need is to create a filter that:
Check the Accept-Language header if it have a value that matches locale
If it does not have a value that matches it, return string with the default value which is "en"
Any idea what I should do?
You can do this in 2 different ways;
Action Filter
Middleware
1.Action Filter
If you use this action filter, you have to write this attribute on each endpoint.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace Subscription.API.Filters
{
public class ValidateHeaders : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var languageHeader = context.HttpContext.Request.Headers.AcceptLanguage;
if (string.IsNullOrWhiteSpace(languageHeader))
context.HttpContext.Request.Headers.AcceptLanguage = "en";
}
}
}
2.Middleware
If you write it as middleware, it will be enough to place this middleware in the first place in the request pipeline.
public class ValidateHeadersMiddleware
{
private readonly RequestDelegate _next;
public ValidateHeadersMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var languageHeader = context.Request.Headers.AcceptLanguage;
if (string.IsNullOrWhiteSpace(languageHeader))
context.Request.Headers.AcceptLanguage = "en";
//Continue processing
if (_next != null)
await _next.Invoke(context);
}
}
This will effect all requests.
public static class MiddlewareExtension
{
public static IApplicationBuilder UseHeaderValidation(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ValidateHeadersMiddleware>();
}
}
In the Configure method in Startup.cs or minimal api configuration in Program.cs, use this middleware;
...
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHeaderValidation();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
...
I've done this before with MVC5 using User.Identity.GetUserId() but that doesn't seem to work here.
The User.Identity doesn't have the GetUserId() method.
I am using Microsoft.AspNet.Identity.
Update in ASP.NET Core Version >= 2.0
In the Controller:
public class YourControllerNameController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public YourControllerNameController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task<IActionResult> YourMethodName()
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier) // will give the user's userId
var userName = User.FindFirstValue(ClaimTypes.Name) // will give the user's userName
// For ASP.NET Core <= 3.1
ApplicationUser applicationUser = await _userManager.GetUserAsync(User);
string userEmail = applicationUser?.Email; // will give the user's Email
// For ASP.NET Core >= 5.0
var userEmail = User.FindFirstValue(ClaimTypes.Email) // will give the user's Email
}
}
In some other class:
public class OtherClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
public OtherClass(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void YourMethodName()
{
var userId = _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
}
}
Then you should register IHttpContextAccessor in the Startup class as follows:
public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Or you can also register as follows
services.AddHttpContextAccessor();
}
For more readability write extension methods as follows:
public static class ClaimsPrincipalExtensions
{
public static T GetLoggedInUserId<T>(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
if (typeof(T) == typeof(string))
{
return (T)Convert.ChangeType(loggedInUserId, typeof(T));
}
else if (typeof(T) == typeof(int) || typeof(T) == typeof(long))
{
return loggedInUserId != null ? (T)Convert.ChangeType(loggedInUserId, typeof(T)) : (T)Convert.ChangeType(0, typeof(T));
}
else
{
throw new Exception("Invalid type provided");
}
}
public static string GetLoggedInUserName(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
return principal.FindFirstValue(ClaimTypes.Name);
}
public static string GetLoggedInUserEmail(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
return principal.FindFirstValue(ClaimTypes.Email);
}
}
Then use as follows:
public class YourControllerNameController : Controller
{
public IActionResult YourMethodName()
{
var userId = User.GetLoggedInUserId<string>(); // Specify the type of your UserId;
var userName = User.GetLoggedInUserName();
var userEmail = User.GetLoggedInUserEmail();
}
}
public class OtherClass
{
private readonly IHttpContextAccessor _httpContextAccessor;
public OtherClass(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void YourMethodName()
{
var userId = _httpContextAccessor.HttpContext.User.GetLoggedInUserId<string>(); // Specify the type of your UserId;
}
}
Until ASP.NET Core 1.0 RC1 :
It's User.GetUserId() from System.Security.Claims namespace.
Since ASP.NET Core 1.0 RC2 :
You now have to use UserManager.
You can create a method to get the current user :
private Task<ApplicationUser> GetCurrentUserAsync() => _userManager.GetUserAsync(HttpContext.User);
And get user information with the object :
var user = await GetCurrentUserAsync();
var userId = user?.Id;
string mail = user?.Email;
Note :
You can do it without using a method writing single lines like this string mail = (await _userManager.GetUserAsync(HttpContext.User))?.Email, but it doesn't respect the single responsibility principle. It's better to isolate the way you get the user because if someday you decide to change your user management system, like use another solution than Identity, it will get painful since you have to review your entire code.
you can get it in your controller:
using System.Security.Claims;
var userId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
or write an extension method like before .Core v1.0
using System;
using System.Security.Claims;
namespace Shared.Web.MvcExtensions
{
public static class ClaimsPrincipalExtensions
{
public static string GetUserId(this ClaimsPrincipal principal)
{
if (principal == null)
throw new ArgumentNullException(nameof(principal));
return principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
}
}
}
and get wherever user ClaimsPrincipal is available :
using Microsoft.AspNetCore.Mvc;
using Shared.Web.MvcExtensions;
namespace Web.Site.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return Content(this.User.GetUserId());
}
}
}
I included using System.Security.Claims and I could access the GetUserId() extension method
NB: I had the using Microsoft.AspNet.Identity already but couldn't get the extension method. So I guess both of them have to be used in conjunction with one another
using Microsoft.AspNet.Identity;
using System.Security.Claims;
EDIT:
This answer is now outdated. Look at Soren's or Adrien's answer for a dated way of achieving this in CORE 1.0
For .NET Core 2.0 Only The following is required to fetch the UserID of the logged-in User in a Controller class:
var userId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
or
var userId = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
e.g.
contact.OwnerID = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
As stated somewhere in this post, the GetUserId() method has been moved to the UserManager.
private readonly UserManager<ApplicationUser> _userManager;
public YourController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public IActionResult MyAction()
{
var userId = _userManager.GetUserId(HttpContext.User);
var model = GetSomeModelByUserId(userId);
return View(model);
}
If you started an empty project you might need to add the UserManger to your services in startup.cs. Otherwise this should already be the case.
you have to import Microsoft.AspNetCore.Identity & System.Security.Claims
// to get current user ID
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
// to get current user info
var user = await _userManager.FindByIdAsync(userId);
For ASP.NET Core 2.0, Entity Framework Core 2.0, AspNetCore.Identity 2.0 api (https://github.com/kkagill/ContosoUniversity-Backend):
The Id was changed to User.Identity.Name
[Authorize, HttpGet("Profile")]
public async Task<IActionResult> GetProfile()
{
var user = await _userManager.FindByIdAsync(User.Identity.Name);
return Json(new
{
IsAuthenticated = User.Identity.IsAuthenticated,
Id = User.Identity.Name,
Name = $"{user.FirstName} {user.LastName}",
Type = User.Identity.AuthenticationType,
});
}
Response:
In .net core 3.1 (and other more recent versions), you can use:
private readonly UserManager<IdentityUser> _userManager;
public ExampleController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
Then:
string userId = _userManager.GetUserId(User);
Or async:
var user = await _userManager.GetUserAsync(User);
var userId = user.Id;
At this point, I'm trying to figure out why you'd use one over the other. I know the general benefits of async, but see both of these used frequently. Please post some comments if anyone knows.
For ASP.NET 5.0, I have an extension method as follow:
using System;
using System.ComponentModel;
using System.Security.Claims;
namespace YOUR_PROJECT.Presentation.WebUI.Extensions
{
public static class ClaimsPrincipalExtensions
{
public static TId GetId<TId>(this ClaimsPrincipal principal)
{
if (principal == null || principal.Identity == null ||
!principal.Identity.IsAuthenticated)
{
throw new ArgumentNullException(nameof(principal));
}
var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier);
if (typeof(TId) == typeof(string) ||
typeof(TId) == typeof(int) ||
typeof(TId) == typeof(long) ||
typeof(TId) == typeof(Guid))
{
var converter = TypeDescriptor.GetConverter(typeof(TId));
return (TId)converter.ConvertFromInvariantString(loggedInUserId);
}
throw new InvalidOperationException("The user id type is invalid.");
}
public static Guid GetId(this ClaimsPrincipal principal)
{
return principal.GetId<Guid>();
}
}
}
So you can use it like:
using Microsoft.AspNetCore.Mvc;
using YOUR_PROJECT.Presentation.WebUI.Extensions;
namespace YOUR_PROJECT.Presentation.WebUI.Controllers
{
public class YourController :Controller
{
public IActionResult YourMethod()
{
// If it's Guid
var userId = User.GetId();
// Or
// var userId = User.GetId<int>();
return View();
}
}
}
in the APiController
User.FindFirst(ClaimTypes.NameIdentifier).Value
Something like this you will get the claims
Although Adrien's answer is correct, you can do this all in single line. No need for extra function or mess.
It works I checked it in ASP.NET Core 1.0
var user = await _userManager.GetUserAsync(HttpContext.User);
then you can get other properties of the variable like user.Email. I hope this helps someone.
For getting current user id in razor views, we can inject UserManager in the view like this:
#inject Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> _userManager
#{ string userId = _userManager.GetUserId(User); }
I hope you find it useful.
User.Identity.GetUserId();
does not exist in asp.net identity core 2.0. in this regard, i have managed in different way. i have created a common class for use whole application, because of getting user information.
create a common class PCommon & interface IPCommon
adding reference using System.Security.Claims
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Common.Web.Helper
{
public class PCommon: IPCommon
{
private readonly IHttpContextAccessor _context;
public PayraCommon(IHttpContextAccessor context)
{
_context = context;
}
public int GetUserId()
{
return Convert.ToInt16(_context.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier));
}
public string GetUserName()
{
return _context.HttpContext.User.Identity.Name;
}
}
public interface IPCommon
{
int GetUserId();
string GetUserName();
}
}
Here the implementation of common class
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging;
using Pay.DataManager.Concreate;
using Pay.DataManager.Helper;
using Pay.DataManager.Models;
using Pay.Web.Helper;
using Pay.Web.Models.GeneralViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Pay.Controllers
{
[Authorize]
public class BankController : Controller
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger _logger;
private readonly IPCommon _iPCommon;
public BankController(IUnitOfWork unitOfWork, IPCommon IPCommon, ILogger logger = null)
{
_unitOfWork = unitOfWork;
_iPCommon = IPCommon;
if (logger != null) { _logger = logger; }
}
public ActionResult Create()
{
BankViewModel _bank = new BankViewModel();
CountryLoad(_bank);
return View();
}
[HttpPost, ActionName("Create")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Insert(BankViewModel bankVM)
{
if (!ModelState.IsValid)
{
CountryLoad(bankVM);
//TempData["show-message"] = Notification.Show(CommonMessage.RequiredFieldError("bank"), "Warning", type: ToastType.Warning);
return View(bankVM);
}
try
{
bankVM.EntryBy = _iPCommon.GetUserId();
var userName = _iPCommon.GetUserName()();
//_unitOfWork.BankRepo.Add(ModelAdapter.ModelMap(new Bank(), bankVM));
//_unitOfWork.Save();
// TempData["show-message"] = Notification.Show(CommonMessage.SaveMessage(), "Success", type: ToastType.Success);
}
catch (Exception ex)
{
// TempData["show-message"] = Notification.Show(CommonMessage.SaveErrorMessage("bank"), "Error", type: ToastType.Error);
}
return RedirectToAction(nameof(Index));
}
}
}
get userId and name in insert action
_iPCommon.GetUserId();
Thanks,
Maksud
TLDR:
In the Controler add:
using System.Security.Claims;
and then you can use:
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
endof TLDR;
Just an easy way in dot net 6 to test how to get the userID and test it in the default Blazor WebAssembly Core Hosted:
I added a String in WeatherForecast class named userId
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string userId { get; set; } = "nope";
}
Then in the WeatherForecastController
I add
using System.Security.Claims;
In the GET method I set WeatherForecast.userId to User.FindFirstValue(ClaimTypes.NameIdentifier):
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)],
userId = User.FindFirstValue(ClaimTypes.NameIdentifier)
})
.ToArray();
}
And finally in the FetchData.razor I modify the table to:
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
<th>User Id</th>
</tr>
</thead>
<tbody>
#foreach (var forecast in forecasts)
{
<tr>
<td>#forecast.Date.ToShortDateString()</td>
<td>#forecast.TemperatureC</td>
<td>#forecast.TemperatureF</td>
<td>#forecast.Summary</td>
<td>#forecast.userId</td>
</tr>
}
</tbody>
</table>
And then finally I get:
I hope it helps because in net core 6 sometimes it's quite difficult to find the answers
If you are using JWT tokens this code works:
User.FindFirstValue("sub");
use can use
string userid = User.FindFirst("id").Value;
for some reason NameIdentifier now retrieve the username (.net core 2.2)
Make sure that you have enable windows authentication. If you have anonymous authentication enabled you may be getting a null string.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1&tabs=visual-studio
I know there are many answers posted already, but maybe it will help someone as it did for me.
I mixed two solutions into one, and I am able to get the logged-in User and its Data.
I was using DotNet 5.
Following code, help to get the logged-in User.
var user = await _userManager.FindByNameAsync(HttpContext.User.Identity.Name);
I used the following package for _userManager
using Microsoft.AspNetCore.Identity;
And for HttpContext, I inherit my Controller from ControllerBase, and for ControllerBase Class I was using the following package
using Microsoft.AspNetCore.Mvc;
As an administrator working on other people's profile and you need to get the Id of the profile you are working on, you can use a ViewBag to capture the Id e.g ViewBag.UserId = userId; while userId is the string Parameter of the method you are working on.
[HttpGet]
public async Task<IActionResult> ManageUserRoles(string userId)
{
ViewBag.UserId = userId;
var user = await userManager.FindByIdAsync(userId);
if (user == null)
{
ViewBag.ErrorMessage = $"User with Id = {userId} cannot be found";
return View("NotFound");
}
var model = new List<UserRolesViewModel>();
foreach (var role in roleManager.Roles)
{
var userRolesViewModel = new UserRolesViewModel
{
RoleId = role.Id,
RoleName = role.Name
};
if (await userManager.IsInRoleAsync(user, role.Name))
{
userRolesViewModel.IsSelected = true;
}
else
{
userRolesViewModel.IsSelected = false;
}
model.Add(userRolesViewModel);
}
return View(model);
}
If you want this in ASP.NET MVC Controller, use
using Microsoft.AspNet.Identity;
User.Identity.GetUserId();
You need to add using statement because GetUserId() won't be there without it.
I been trying for days to resolve localization in my ASP.NET Core 3.1 Car Sales project....it copmprises only one controller and three resource files. Default language is Serbian, the other two, german and english. Resx files are located in Resources folder within the project(Resource.resx,Resource.en-Us.resx,Resource.de-DE.resx. After debugging project, there's no visible mistake were displayenter image description hereed.
AutomobilController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using CarSales.Models;
using System.IO;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Localization;
using Microsoft.AspNetCore.Localization;
namespace CarSales.Controllers
{
public class AutomobilController : Controller
{
public IStringLocalizer<Resource> localizer;
private readonly AutomobilContext db;
public AutomobilController(AutomobilContext context, IStringLocalizer<Resource> localizer)
{
db = context;
this.localizer = localizer;
}
public IActionResult SetCulture(string culture,string sourceUrl)
{
Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName,CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) } );
return Redirect(sourceUrl);
}
public FileContentResult CitajAutomobil(int? Id)
{
if (Id == null)
{
return null;
}
Automobil auto = db.Automobili.Find(Id);
if (Id == null)
{
return null;
}
return File(auto.Fotografija, auto.TipFajla);
}
// GET: Automobil
public async Task<IActionResult> Index()
{
ViewBag.teststring = localizer["Detalji"];
return View(await db.Automobili.ToListAsync());
}
// GET: Automobil/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var automobil = await db.Automobili
.FirstOrDefaultAsync(m => m.Id == id);
if (automobil == null)
{
return NotFound();
}
return View(automobil);
}
// GET: Automobil/Create
public IActionResult Create()
{
return View();
}
public IActionResult ONama()
{
return View();
}
public IActionResult Kontakt()
{
return View();
}
// POST: Automobil/Create
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Fotografija,TipFajla,Marka,Model,Godiste,ZapreminaMotora,Snaga,Gorivo,Karoserija,Opis,Cena,Kontakt")] Automobil automobil, IFormFile OdabraniAutomobil)
{
if (OdabraniAutomobil == null)
{
ModelState.AddModelError("Fotografija", "Niste odabrali sliku");
}
if (ModelState.IsValid)
{
try
{
using (MemoryStream ms = new MemoryStream())
{
await OdabraniAutomobil.CopyToAsync(ms);
automobil.Fotografija = ms.ToArray();
}
automobil.TipFajla = OdabraniAutomobil.ContentType;
db.Add(automobil);
await db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch (Exception)
{
ViewBag.Greska = "Greska pri cuvanju slike Automobila";
}
}
return View(automobil);
}
// GET: Automobil/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var automobil = await db.Automobili.FindAsync(id);
if (automobil == null)
{
return NotFound();
}
return View(automobil);
}
// POST: Automobil/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Fotografija,TipFajla,Marka,Model,Godiste,ZapreminaMotora,Snaga,Gorivo,Karoserija,Opis,Cena,Kontakt")] Automobil automobil)
{
if (id != automobil.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
db.Update(automobil);
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!AutomobilExists(automobil.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(automobil);
}
// GET: Automobil/Delete/5
[Authorize]
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var automobil = await db.Automobili
.FirstOrDefaultAsync(m => m.Id == id);
if (automobil == null)
{
return NotFound();
}
return View(automobil);
}
// POST: Automobil/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var automobil = await db.Automobili.FindAsync(id);
db.Automobili.Remove(automobil);
await db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool AutomobilExists(int id)
{
return db.Automobili.Any(e => e.Id == id);
}
}
}
Startup.cs
using CarSales.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CarSales.Models;
using System.Globalization;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
namespace CarSales
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<AutomobilContext>(opcije => opcije.UseSqlServer(Configuration.GetConnectionString("DatabaseConnection")));
services.AddLocalization(opts => opts.ResourcesPath = "Resources");
services.AddMvc().AddDataAnnotationsLocalization(opts => { opts.DataAnnotationLocalizerProvider = (type, factory) => factory.Create(typeof(Resource)); }).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddRazorPages();
services.Configure<RequestLocalizationOptions>(
opts =>
{
var supported = new\[\]
{
new CultureInfo("en"),
new CultureInfo("sr"),
new CultureInfo("de-DE")
};
opts.DefaultRequestCulture = new RequestCulture(culture: "sr", uiCulture: "sr");
opts.SupportedCultures = supported;
opts.SupportedUICultures = supported;
}
);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseRequestLocalization();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Automobil}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
}][2]
Any help would be much appreciated...
InvalidOperationException: Unable to resolve service for type 'Echelon.Data.IAssignmentRepository' while attempting to activate 'Echelon.Controllers.SessionController'.
I keep getting this Error whenever I try to login or click something
in my navbar, I'm confused as to why it's erroring out, can someone
please help? This started when I got email verification working, then
whenever I try to login or click anything I get the error?
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Echelon.Models.SessionViewModels;
using Echelon.Classes;
using Microsoft.AspNetCore.Identity;
using Echelon.Models;
using Echelon.Data;
namespace Echelon.Controllers
{
public class SessionController : Controller
{
StoredProcedure storedProcedure = new StoredProcedure();
private IAssignmentRepository repository;
private readonly AssignmentDbContext _context;
public SessionController(IAssignmentRepository repo, AssignmentDbContext context)
{
repository = repo;
_context = context;
}
[Authorize]
public IActionResult Home()
{
return View();
}
public IActionResult Courses()
{
var Courses = storedProcedure.getCourseNames(User.Identity.Name);
var CoursesView = new CoursesViewModel();
foreach (var Course in Courses.ToList())
{
Course course = new Course();
course.CourseName = Course;
CoursesView.Courses.Add(course);
}
return View(CoursesView);
}
public IActionResult CreateCourse()
{
return View();
}
[HttpPost]
public IActionResult CreateCourse(CreateCourseModel course)
{
if (ModelState.IsValid)
{
storedProcedure.addCourse(User.Identity.Name, course.CourseName, course.CourseDesc, course.StartDate, course.EndDate);
return RedirectToAction("Courses");
}
else
{
return View();
}
}
public IActionResult Assignments(string courseName)
{
var assignments = storedProcedure.getAssignments(User.Identity.Name, courseName);
var AssignmentsView = new AssignmentsViewModel { CourseName = courseName };
foreach (var Assignment in assignments.ToList())
{
AssignmentsView.Assignments.Add(Assignment);
}
return View(AssignmentsView);
}
public IActionResult CreateAssignment(string courseName)
{
CreateAssignment assignmentModel = new CreateAssignment();
assignmentModel.CourseName = courseName;
assignmentModel.UserName = User.Identity.Name;
return View(assignmentModel);
}
[HttpPost]
public async Task<IActionResult> CreateAssignment([Bind("AssignmentID,UserName,CourseName,AssignmentName,AssignmentDescription,TotalPoints,DueDate")] CreateAssignment assignment)
{
if (ModelState.IsValid)
{
_context.Add(assignment);
try
{
await _context.SaveChangesAsync();
}
catch (Exception ex)
{
return View(assignment);
}
//return View(assignment);
return RedirectToAction("Assignments", "Session", new { courseName = assignment.CourseName });
}
else
return View(assignment);
}
public IActionResult Students(string courseName)
{
var students = storedProcedure.getStudents(User.Identity.Name, courseName);
var studentsView = new StudentsViewModel();
foreach (var student in students.ToList())
{
Student Student = new Student();
Student.StudentFName = student.StudentFName;
Student.StudentLName = student.StudentLName;
Student.CourseName = student.CourseName;
studentsView.Students.Add(Student);
}
return View(studentsView);
}
public IActionResult AllStudents()
{
var students = storedProcedure.getAllStudents(User.Identity.Name);
var studentsView = new AllStudentsViewModel();
foreach (var student in students.ToList())
studentsView.Students.Add(student);
return View(studentsView);
}
public IActionResult Attendance()
{
return View();
}
}
}
You usually get that error when you are trying to use an implementation of an interface, but you have not registered the concrete implementation you want to use with the framework.
If you are using the default dependency injection framework used by asp.net core, you should register it in the ConfigureServices method in Startup.cs class
services.AddTransient<IAssignmentRepository , AssignmentRepository>();
where AssignmentRepository is a your concrete class where you are implementing the IAssignmentRepository interface.
public interface IAssignmentRepository
{
IEnumerable<CreateAssignment> Assignments { get; }
}
public class AssignmentRepository : IAssignmentRepository
{
public IEnumerable<CreateAssignment> Assignments
{
get
{
return new List<CreateAssignment>()
{
new CreateAssignment(),
new CreateAssignment()
};
}
}
}
Here i just hard coded the Assignments property to return 2 CreateAssignment objects. But i guess you probably will be reading it from database and return it.
Now when a new request comes for your controller action method, the framework will create a new object of SessionController and pass an object of AssignmentRepository to the constructor of SessionController
If you are not familiar with the dependency injection concept, i strongly suggest you to spend 16 minutes to read the excellent documentation on learn.microsoft.com before trying to write any further code.
Introduction to Dependency Injection in ASP.NET Core