C# System.InvalidOperationException DisplayClass0_0 error while getting token - c#

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

Related

How to assign an object, for example, the owner's car [duplicate]

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.

.NET Core Mediatr Usage not all code paths return a value

In my API, I am trying to use MediatR; so in my controller code, I wrote:
[HttpPost("AdminLogin")
public async Task<ActionResult<Admin>> GetContractById(Admin admin)
{
var response = await _mediator.Send(new UserLoginRequest(admin));
if (response.HasError)
{
return BadRequest(response);
}
return Ok(response);
}
Then in my UserLoginRequest.cs I wrote this code:
using MediatR;
using SinavAlemiPanel.Domain.Models;
using SinavAlemiPanel.Infrastructure.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SinavAlemiPanel.Application.Requests.UserRequests
{
public class UserLoginRequest :IRequest<BaseResponse<Admin>>
{
private Admin admin;
public UserLoginRequest(Admin admin)
{
this.admin = admin;
}
public Admin UserCredentials { get; set; }
}
public sealed class UserLoginRequestHandlers : IRequestHandler<UserLoginRequest, BaseResponse<Admin>>
{
private readonly IUserService _userService;
public UserLoginRequestHandlers(IUserService userService)
{
_userService = userService;
}
public async Task<BaseResponse<Admin>> Handle(UserLoginRequest request, CancellationToken cancellationToken)
{
await Task.Run(() =>
{
return _userService.Login(request.UserCredentials);
});
}
}
}
And in my service I have:
using Dapper;
using SinavAlemiPanel.Domain.Models;
using SinavAlemiPanel.Infrastructure.Interfaces;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace SinavAlemiPanel.Infrastructure.Services
{
public class UserService : IUserService
{
private readonly IBaseService _baseService;
private readonly DBConnection _db;
public UserService(IBaseService baseService)
{
_baseService = baseService;
}
public Admin Login(Admin admin)
{
Admin result = new Admin();
var dynamicParams = new DynamicParameters();
var conn = _baseService.GetConnection(_db.GetConnString());
try
{
dynamicParams.Add("#username", admin.Username, DbType.String, ParameterDirection.Input);
dynamicParams.Add("#pass", admin.Password, DbType.String, ParameterDirection.Input);
result = SqlMapper.Query<Admin>(conn, "dbo.SP_Admin_Login #username, #pass", dynamicParams).SingleOrDefault();
conn.Close();
if (result != null && result.Id > 0)
{
result.Accesses = (result != null && result.Id > 0) ? Accesses(result.Id) : new List<Access>();
}
return result;
}
catch(Exception ex)
{
return result;
}
}
public List<Access> Accesses(int refAdmin)
{
List<Access> result = new List<Access>();
var dynamicParams = new DynamicParameters();
var conn = _baseService.GetConnection(_db.GetConnString());
try
{
dynamicParams.Add("#refAdmin", refAdmin, DbType.Int32, ParameterDirection.Input);
result = SqlMapper.Query<Access>(conn, "dbo.SP_Admin_Accesses #refAdmin", dynamicParams).ToList();
conn.Close();
return result;
}
catch (Exception e)
{
return result;
}
}
}
}
My problem is that the code doesn't accept in request handle, I get this error:
Error CS0161
'UserLoginRequestHandlers.Handle(UserLoginRequest, CancellationToken)': not all code paths return a value
I am new in C# so I couldn't detect the error. How can I solve this issue?
Thanks in advance
You are missing a return statement in the Handle method, but adding it alone won't fix the compilation you need to translate Admin returned by _userService.Login to BaseResponse<Admin>. Also since _userService.Login is a sync method - no need for Task.Run and assync-await - use Task.FromResult instead. Something like this (assiming the existence of corresponding BaseResponse ctor):
public Task<BaseResponse<Admin>> Handle(UserLoginRequest request, CancellationToken cancellationToken)
{
var admin = _userService.Login(request.UserCredentials);
return Task.FromResult(new BaseResponse<Admin>(admin)); // no need for Task.Run and async-await cause Login is synchronous method
}
The another approach is to create your service as async:
public async Task<Admin> Login(Admin admin)
And you need a corresponding constructor in your BaseResponse class:
public async Task<BaseResponse<Admin>> Handle(UserLoginRequest request, CancellationToken cancellationToken)
{
Admin admin = await _userService.Login(request.UserCredentials);
return new BaseResponse<Admin>(admin);
}
BaseResponse example:
public class BaseResponse<T>
{
private T Response;
public BaseResponse(T response)
{
Response = response;
}
}

passing a user input variable to another file

Im needing assistance on how to take a user input from a login page, check the Database for the username, and if it exist in the DB, pass it to another file that will pull the information pertaining to that username from the cosmosDB.
Below is the loginPage code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ToDoItems.Core.Pages
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class LoginPage : ContentPage
{
public LoginPage()
{
InitializeComponent();
}
async void SignInProcedure(object sender, EventArgs e)
{
User user = new User(Entry_Username.Text, Entry_Password.Text);
if (user.CheckInformation())
{
//await Navigation.PushModalAsync(new CosmosDBService(Entry_Username.Text));
await Navigation.PushAsync(new ToDoItemsPage());
}
else
{
DisplayAlert("Login", "Login Failed", "Okay");
}
}
}
}
And Im trying to, first check the cosmosDB for the user name, then pass the username if it exist to the cosmosDBservice file to get the information associated with the username:
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using System;
using System.Data;
using System.Diagnostics;
using Microsoft.Azure.Documents.Linq;
using Xamarin.Forms;
using ToDoItems.Core.Pages;
namespace ToDoItems.Core
{
public class CosmosDBService
{
static string queryname;
public CosmosDBService(string logname)
{
// store the parameter for use later;
queryname = logname;
}
static DocumentClient docClient = null;
static readonly string databaseName = "Tasks";
static readonly string collectionName = "Items";
static async Task<bool> Initialize()
{
if (docClient != null)
return true;
try
{
docClient = new DocumentClient(new Uri(APIKeys.CosmosEndpointUrl), APIKeys.CosmosAuthKey);
// Create the database - this can also be done through the portal
await docClient.CreateDatabaseIfNotExistsAsync(new Database { Id = databaseName });
// Create the collection - make sure to specify the RUs - has pricing implications
// This can also be done through the portal
await docClient.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(databaseName),
new DocumentCollection { Id = collectionName },
new RequestOptions { OfferThroughput = 400 }
);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
docClient = null;
return false;
}
return true;
}
// <GetToDoItems>
/// <summary>
/// </summary>
/// <returns></returns>
///
public async static Task<List<ToDoItem>> GetToDoItems()
{
var todos = new List<ToDoItem>();
if (!await Initialize())
return todos;
var todoQuery = docClient.CreateDocumentQuery<ToDoItem>(
UriFactory.CreateDocumentCollectionUri(databaseName, collectionName),
new FeedOptions { MaxItemCount = -1, EnableCrossPartitionQuery = true })
.Where(name => name.Name == queryname)
.AsDocumentQuery();
while (todoQuery.HasMoreResults)
{
var queryResults = await todoQuery.ExecuteNextAsync<ToDoItem>();
todos.AddRange(queryResults);
}
return todos;
}
// </GetToDoItems>
you are already passing the username to the constructor of CosmosDBService
public void CosmosDBService(string user)
{
...
}
you need to create a class variable to store it
string username;
public void CosmosDBService(string user)
{
// store the parameter for use later
username = user;
...
}
then in your query use that class variable
public async static Task<List<ToDoItem>> GetToDoItems()
{
...
.Where(name => name.Name == username)
...
}

Why HttpContext is null?

I've just read more than one and I don't find any solution for my problem.
I've create WebApi + MVC and Unit Test project with FrameWork 4.5.
I have this HomeController.cs with this method:
using Net.Personal.Authentication.FormAuthentication;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
namespace FormAuthenticationProva.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Title = "Home Page";
var guidAccount = "xxxxxxxx-xxxx-xxxx-xxxx-422632e0bd95";
var userData = new CookieUserData(guidAccount) { GuidAccount = guidAccount };
HttpContextBase httpContextBase = this.HttpContext;
AuthenticationProvider _authProvider = new AuthenticationProvider(httpContextBase.ApplicationInstance.Context);
_authProvider.CheckAuthorizationForUrl("http://pippo");
return View();
}
}
}
And the HomeControllerTest.cs with this code:
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FormAuthenticationProva.Controllers;
using Moq;
using System.Web;
using System.Collections.Specialized;
using System.Web.Routing;
namespace FormAuthenticationProva.Tests.Controllers
{
[TestClass]
public class HomeControllerTest
{
[TestMethod]
public void Index()
{ // Disposizione
var formData = new NameValueCollection { { "id", "test" } };
var request = new Mock<HttpRequestBase>();
request.SetupGet(r => r.Form).Returns(formData);
var context = new Mock<HttpContextBase>();
context.SetupGet(c => c.Request).Returns(request.Object);
var controller = new HomeController();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
// Azione
ViewResult result = controller.Index() as ViewResult;
// Asserzione
Assert.IsNotNull(result);
Assert.AreEqual("Home Page", result.ViewBag.Title);
}
}
}
And the AuthenticationProvider.cs class is here:
/* AuthenticationProvider.cs code */
using System;
using System.Security.Principal;
using System.Threading;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Security;
namespace Net.Personal.Authentication.FormAuthentication
{
public class AuthenticationProvider : IFormsAuthentication
{
public AuthContextConfiguration AuthContextConfiguration { get; set; }
public AuthenticationProvider() {}
public AuthenticationProvider(HttpContext context , AuthContextConfiguration authContextConfiguration = null)
{
AuthContextConfiguration = AuthContextConfiguration ?? new AuthContextConfiguration(context);
}
private void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
public void SignIn(string userName, bool createPersistentCookie)
{
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
}
public void SignIn(string userName, bool createPersistentCookie, ICookieUserData userData)
{
this.SetAuthCookie<ICookieUserData>(userName, true, userData);
HttpContext.Current.Cache.Insert(userName, userData);
}
public int SetAuthCookie<T>( string name, bool rememberMe, T userData)
{
/// In order to pickup the settings from config, we create a default cookie and use its values to create a
/// new one.
if (string.IsNullOrEmpty(((ICookieUserData)userData).Name)) ((ICookieUserData)userData).Name = name;
var cookie = FormsAuthentication.GetAuthCookie(name, rememberMe);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration,
ticket.IsPersistent, new JavaScriptSerializer().Serialize(userData), ticket.CookiePath);
var encTicket = FormsAuthentication.Encrypt(newTicket);
/// Use existing cookie. Could create new one but would have to copy settings over...
cookie.Value = encTicket;
HttpContext.Current.Response.Cookies.Add(cookie);
return encTicket.Length;
}
public void SignOut()
{
FormsAuthentication.SignOut();
}
public bool IsAuthorized()
{
return HttpContext.Current.User != null &&
HttpContext.Current.User.Identity != null &&
HttpContext.Current.User.Identity.IsAuthenticated;
}
public void SetUserOnApplication_AuthenticateRequest<T>(HttpContext context)
{
PrincipalUser principal = null;
ICookieUserData userData = null;
// Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = context.Request.Cookies[cookieName];
if (null == authCookie)
{
// There is no authentication cookie.
return;
}
var nameIdentity = HttpContext.Current.User.Identity.Name;
if(string.IsNullOrEmpty(nameIdentity)) {
return;
}
if(HttpContext.Current.Cache[nameIdentity] ==null) {
FormsAuthenticationTicket authTicket = null;
try {
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex) {
// Log exception details (omitted for simplicity)
return;
}
if (null == authTicket) {
// Cookie failed to decrypt.
return;
}
userData = (ICookieUserData)new JavaScriptSerializer().Deserialize<T>(authTicket.UserData);
// When the ticket was created, the UserData property was assigned a
// pipe delimited string of role names.
string[] roles = authTicket.UserData.Split('|');
// Create an Identity object
//FormsIdentity id = new FormsIdentity(authTicket);
// This principal will flow throughout the request.
//PrincipalUser principal = new PrincipalUser(id, roles);
} else {
userData = (ICookieUserData)HttpContext.Current.Cache[nameIdentity];
}
principal = new PrincipalUser(userData);
// Attach the new principal object to the current HttpContext object
context.User = principal;
}
public void CheckAuthorization()
{
if (!this.IsAuthorized()) throw new Exception("Access not allowed");
}
public void CheckAuthorizationForUrl(string url)
{
AuthContextConfiguration.CheckAuthorizationForUrl(url);
if (AuthContextConfiguration.CheckRequiredAuth() && !this.IsAuthorized()) throw new Exception("Access not allowed");
}
}
public class PrincipalUser : IPrincipal
{
private ICookieUserData _userData;
private GenericIdentity _identity;
public PrincipalUser(ICookieUserData userData)
{
_identity = new GenericIdentity(userData.Name);
_userData = userData;
}
public IIdentity Identity
{
get
{
return _identity;
}
}
public ICookieUserData UserData
{
get
{
return _userData;
}
}
public bool IsInRole(string role)
{
return _userData.Role.Contains(role);
}
}
public interface ICookieUserData
{
string Name { get; set; }
string Role { get; set; }
}
}
And now the problem is when I debug from [TestMethod] and I go into method with debugging (F10) and putted breakpoint in the method in HomeController.cs I see this System.Web.HttpContext.Current is every time null! What's the problem? I use Moq.
System.Web.HttpContext.Current is populated by IIS which is not present/active during unit testing. Hence null. Do not tightly couple your code to HttpContext for that very reason. Instead encapsulate that behind abstractions that can be mocked when testing in isolation.
Bad design aside, for your specific design you are trying to access a static dependency external to the controller. If faking the controller's context as demonstrated in your current test, then access the controller's context instead of calling the static context.
//... code removed for brevity
var _authProvider = new AuthenticationProvider(this.HttpContext);
//... code removed for brevity
With that out of the way, the design of the controller should be refactored to explicitly depend on abstractions instead of concretions.
for example, here is an abstraction for the provider
public interface IAuthenticationProvider : IFormsAuthentication {
void CheckAuthorizationForUrl(string url);
//...other members
}
public class AuthenticationProvider : IAuthenticationProvider {
//...
}
The controller should explicitly depend on this via constructor injection
public class HomeController : Controller {
private readonly IAuthenticationProvider authProvider;
public HomeController(IAuthenticationProvider authProvider) {
this.authProvider = authProvider;
}
public ActionResult Index() {
ViewBag.Title = "Home Page";
var guidAccount = "xxxxxxxx-xxxx-xxxx-xxxx-422632e0bd95";
var userData = new CookieUserData(guidAccount) { GuidAccount = guidAccount };
authProvider.CheckAuthorizationForUrl("http://pippo");
return View();
}
}
The IAuthenticationProvider implementation should be configured to be injected into the controller at run time using the framework's DependencyResolver if using dependency injection, but can now be replaced when testing the controller in isolation so as not to be coupled to framework implementation concerns.
[TestClass]
public class HomeControllerTest {
[TestMethod]
public void Index(){
// Disposizione
var authMock = new Mock<IAuthenticationProvider>();
var controller = new HomeController(authMock.Object);
// Azione
ViewResult result = controller.Index() as ViewResult;
// Asserzione
Assert.IsNotNull(result);
Assert.AreEqual("Home Page", result.ViewBag.Title);
}
}
I will scope my answer only to System.Web.HttpContext.Current.
It is set automatically by IIS.
In order to use it you could use Microsoft fakes (https://learn.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes).
The article above explains how to implement it. You would then have access to Current without getting null error.

C# MVC controller breaks on Login

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

Categories

Resources