Getting identity from another method in the same class - asp.net-mvc

Into class I get logged user like
public static GetUserById_Result GetUser(string userId)
{
GetUserById_Result user = new GetUserById_Result();
try
{
using (EF.SSMA oContext = new EF.SSMA())
{
user = oContext.GetUserById(userId).FirstOrDefault();
}
}
catch (Exception)
{
throw;
}
return user;
}
So it runs fine. But in the same class I want to acces user value into another method
public static List<GetUsers_Result> SelectAll()
{
List<GetUsers_Result> lstResult = new List<GetUsers_Result>();
try
{
using (EF.SSMA oContext = new EF.SSMA())
{
lstResult = oContext.GetUsers().Where().ToList();
}
}
catch (Exception ex)
{
throw ex;
}
return lstResult;
}
What I need to do to achieve that?, into controller is really simple I just do this:
var users = User.Identity.GetUserId();
GetUserById_Result currentUser = UserClass.GetUser(users);
var role = currentUser.BranchOfficeId;
But how can I acces it in the same class' I try to call GetUserId with
System.Web.HttpContext.Current.User.Identity.GetUserId();
but it just mark HttpContext in red and say "Cannot resolve symbol 'HttpContext'"
My target is to call only users who BranchOfficeId = user.BranchOfficeId
Help is very appreciated. Regards

If i understand your question well, make sure that you already installed the package Microsoft.Owin.Host.SystemWeb and add using System.Web, then use directely User.Identity.GetUserId()

The reason you can do this in the controller is because Controller has an HttpContext property, which has been created with the details of the current request, including the identity of the current user.
If you want to access the user from another class, you need to pass the user as an argument to your method. As an example:
using System.Security.Principal;
public class SomeClass
{
public void SomeMethod(IPrincipal user)
{
// Whatever you need
}
}
Then in your controller:
var someClass = new SomeClass();
someClass.SomeMethod(HttpContext.User);
However, if you're only interested in the user's name, then you can actually just pass a string instead:
public class SomeClass
{
public void SomeMethod(string username)
{
// Whatever you need
}
}
Then in your controller:
var someClass = new SomeClass();
someClass.SomeMethod(HttpContext.User.Identity.Name);

Related

How to mock HttpContext in ASP.NET Core [duplicate]

This question already has answers here:
Error trying to create Mock.Of<ControllerContext>() for ASP.Net Core 3.1 Unit Test
(2 answers)
Closed 1 year ago.
I'm trying to mock HttpContext to test my UsersController.
The UsersController inherit from
public abstract class ControllerBase
and HttpContext is a property of ControllerBase
public HttpContext HttpContext { get; }
and here is the method in the UsersContoller, which I want to test
public async Task<IActionResult> Register([FromBody] UserViewModel model)
{
_logger.LogDebug("Register new user");
var user = mapper.Map<User>(model);
user.Company.Active = false;
var result = await userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await userManager.AddToRoleAsync(user, Roles.NO_ACCESS);
//send confirmation email
string confirmationToken = userManager.GenerateEmailConfirmationTokenAsync(user).Result;
HostString hostString = HttpContext.Request.Host; //I need to mock httpcontext for this
this.mailSender.SendConfirmationMailAsync(user, hostString, confirmationToken);
return Ok();
}
else
{
_logger.LogInformation("User could not be registered Errors:");
result.Errors.ToList().ForEach(e => _logger.LogInformation(e.Description));
return BadRequest(result.Errors);
}
}
this is my BaseTestContoller, in which setup for tests is initialized
[SetUp]
public void Setup()
{
var dbContext = CreateDbContext();
CreateUserManager();
CreateMailSender(dbContext);
CreateMockImapper();
CreateMockIlogger();
usersController = new Mock<UsersController>(
userManagerMock.Object,
new CompanyService(dbContext),
mailSenderMock,
new Mock<IConfiguration>().Object,
iMapperMock.Object,
iLoggerFactoryMock.Object);
}
i've tried many options, but it wasn't successful therefor it would be nice if someone could help me.
Thanks in advance
UPDATE
usersController = new Mock<UsersController>(
userManagerMock.Object,
new CompanyService(dbContext),
mailSenderMock,
new Mock<IConfiguration>().Object,
iMapperMock.Object,
iLoggerFactoryMock.Object);
var conterllerContext = new ControllerContext() { HttpContext = new DefaultHttpContext() { } };
HostString host = new HostString("test.de");
conterllerContext.HttpContext.Request.Host = host;
usersController.Setup(c => c.HttpContext).Returns(conterllerContext.HttpContext);
Now i have a problem with setting up.
userController.setup returns this msg :
System.NotSupportedException : Unsupported expression: c => c.HttpContext
Non-overridable members (here: ControllerBase.get_HttpContext) may not be used in setup / verification expressions.
You can use ControllerContext to set the context to be DefaultHttpContext which you can modify to your needs.
var ctx = new ControllerContext() { HttpContext = new DefaultHttpContext()};
var tested = new MyCtrl();
tested.ControllerContext = ctx;
Can't you make a mock service for getting the host address (I am not really familiar with mock libraries).
Something like this:
class IHostService {
string GetHost();
}
public class HostService {
// create constructor with httpcontextaccessor
public string GetHost() {
return _httpContextAccessor.HttpContext.Request.Host;
}
}
public class MockHostService {
public string GetHost() {
return "test.de";
}
}
and in your mock class you can probably add this service just like you added mailSenderMock. And in your controller you use string host = _hostService.GetHost().

how validate data that is not send by Post method?

i have a static object in controller that will be fill in some level of registration forms.finally i want to validate this object by modelstate method but is not possible because that is not send by post method..i am searching a standard way to validate..
public class AccountController : Controller
{
private MyDb db = new MyDb();
private static Trainer trainer = new Trainer();
public Trainer InfoSave(Trainer info)
{
trainer.SchoolGrade = info.SchoolGrade;
trainer.SchoolMajor = info.SchoolMajor;
trainer.MajorId = info.Major.Id;
trainer.History = info.History;
trainer.Major = info.Major;
if (ModelState.IsValid)
return true;
else
return false;
}
You can use some Third party library for loosely couple the validation logic. I am using FluentValidation library. You can utilize it:
using FluentValidation;
public class TrainerValidator : AbstractValidator<Trainer> {
public TrainerValidator() {
RuleFor(c=> c.Name).NotNull().WithMessage("Name is required");
}
}
public class AccountController : Controller
{
private MyDb db = new MyDb();
private static Trainer trainer = new Trainer();
public Trainer InfoSave(Trainer info)
{
trainer.SchoolGrade = info.SchoolGrade;
trainer.SchoolMajor = info.SchoolMajor;
trainer.MajorId = info.Major.Id;
trainer.History = info.History;
trainer.Major = info.Major;
TrainerValidator validator = new TrainerValidator();
ValidationResult result = validator.Validate(trainer);
if (result.IsValid)
return true;
else
return false;
}
You can extend it based on your requirements. Here is the link for the same FluentValidation

Testing a method in MVC which makes calls to Repositories

I have a MVC method like so:
public ActionResult ChangeStatus(string productId, string statusToChange)
{
var productToChangeStatus = _updateProductRepository.GetUpdateProduct(productId);
if (statusToChange.ToLower() == ChangeStatusTo.Disable)
{
productToChangeStatus.Active = "false";
}
else
{
productToChangeStatus.Active = "true";
}
_updateProductsManager.UpsertProduct(productToChangeStatus);
return Json(new { success = true });
}
This method gets an existing product based on the 'productId', changes the 'Active' property on it based on the 'statusToChange' value, saves it back and returns a Json with success.
The test setup is like so:
private ProductController _controller;
private Mock<IUpdateProductRepository> _iProductRepository;
[TestInitialize]
public void TestSetup()
{
_iProductRepository = new Mock<IUpdateProductRepository>();
_controller = new ProductController(_iProductRepository.Object);
}
Wrote a test method like so:
[TestMethod]
public void Disable_A_Product_Which_Is_Currently_Enabled()
{
const string productId = "123";
var productBeforeStatusChange = new Product()
{
Active = "true",
Id = new Guid().ToString(),
Name = "TestProduct",
ProductId = "123"
};
var productAfterStatusChange = new Product()
{
Active = "false",
Id = new Guid().ToString(),
Name = "TestProduct",
ProductId = "123"
};
_iProductRepository.Setup(r => r.GetUpdateProduct(productId)).Returns(productBeforeStatusChange);
_iProductRepository.Setup(r => r.UpsertProduct(productBeforeStatusChange)).Returns(productAfterStatusChange);
var res = _controller.ChangeStatus("123", "disable") as JsonResult;
Assert.AreEqual("{ success = true }", res.Data.ToString());
}
The test fails with this error:
Object reference not set to an instant of the object.
On debugging I found that it fails inside the
if(...)
condition where the actual setting of the Active property is happening.
Since the productId that's being passed is not real a product object can't be retrieved for the code to work on.
I tried to use Mock but I think my usage is not correct.
So what I want to know is, how to test a method like this where a method that returns an ActionResult is in turn calling the repository to work with object(s).
Thanks in advance.
You seems to be missing setup for
_updateProductsManager.UpsertProduct()
The way you setup GetUpdateProduct() method you ought to setup UpsertProduct() on the mock instance.

Mocking SetPhoneNumberAsync in MVC 5

I am using Moq framework to mock objects in my project. I want to save the user profile which is calling UserManager.SetPhoneNUmberAsync of AspNet.Identity.
Here is my code:
public async Task<ActionResult> SaveProfile(DistributorViewModel distributorModel)
{
if (ModelState.IsValid)
{
string currentUserId = User.Identity.GetUserId();
distributorModel.UserDetailViewModel.ModifiedDate = System.DateTime.Now;
distributorModel.UserDetailViewModel.ModifiedBy =Guid.Parse( currentUserId);
var isUpdated = this.distributorService.Update(distributorModel.UserDetailViewModel);
IdentityResult result = await UserManager.SetPhoneNumberAsync(currentUserId, distributorModel.UserDetailViewModel.MobileNo);
if (result.Succeeded && isUpdated)
{
Flash.Success(Messages.ProfileUpdatedSuccessfully);
}
else
{
Flash.Error(Messages.ProfileUpdationError);
}
}
return RedirectToAction("Index", distributorModel);
}
Its throwing error on UserManager.SetPhoneNumberAsync.
How can I mock this method?
Something similar to this should work:
var manager = new Mock<UserManager<ApplicationUser>();
manager.Setup(m => m.SetPhoneNumberAsync(userId, "phoneNumber").ReturnsAsync(IdentityResult.Succeeded()).Verifiable();
You can also create class IdentityResultMock which inherited from IdentityResult. Than you can assign Successed property from IdentityResultMock because IdentityResult has protected constructor.
Please refer to my answer here.

Why does one Web API method work, whereas the other does not?

One of my Web API methods works perfectly, and the other not at all.
By works perfectly, I mean this:
The other one, though, doesn't seem to even know about itself. It answers the browser request with:
The code seems to be set up the same for both of them, so I don't know why one works like a charm and the other fails so thuddily.
The pertinent code is:
CONTROLLER
public class DepartmentsController : ApiController
{
private readonly IDepartmentRepository _deptsRepository;
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository is null");
}
_deptsRepository = deptsRepository;
}
[Route("api/Departments/Count")]
public int GetCountOfDepartmentRecords()
{
return _deptsRepository.Get();
}
[Route("api/Departments")]
public IEnumerable<Department> GetBatchOfDepartmentsByStartingID(int ID, int CountToFetch)
{
return _deptsRepository.Get(ID, CountToFetch);
}
REPOSITORY
public class DepartmentRepository : IDepartmentRepository
{
private readonly List<Department> departments = new List<Department>();
public DepartmentRepository()
{
using (var conn = new OleDbConnection(
#"Provider=Microsoft.ACE.OLEDB.12.0;User ID=Freebo;Password=RunningOnEmpty;Data Source=C:\CDBWin\DATA\CCRDAT42.MDB;Jet OLEDB:System database=C:\CDBWin\Data\nrbq.mdw"))
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT td_department_accounts.dept_no, IIF(ISNULL(t_accounts.name),'No Name provided',t_accounts.name) AS name FROM t_accounts INNER JOIN td_department_accounts ON t_accounts.account_no = td_department_accounts.account_no ORDER BY td_department_accounts.dept_no";
cmd.CommandType = CommandType.Text;
conn.Open();
int i = 1;
using (OleDbDataReader oleDbD8aReader = cmd.ExecuteReader())
{
while (oleDbD8aReader != null && oleDbD8aReader.Read())
{
int deptNum = oleDbD8aReader.GetInt16(0);
string deptName = oleDbD8aReader.GetString(1);
Add(new Department { Id = i, AccountId = deptNum, Name = deptName });
i++;
}
}
}
}
}
public int Get()
{
return departments.Count;
}
private Department Get(int ID) // called by Delete()
{
return departments.First(d => d.Id == ID);
}
If entering:
http://shannon2:28642/api/Departments/Count
in the browser works to execute the Controller's GetCountOfDepartmentRecords() method, why does entering:
http://localhost:28642/api/Departments/5/6
(or:
http://localhost:28642/api/Departments/1/5
etc) not work to execute the Controller's GetBatchOfDepartmentsByStartingID() method?
Your route is missing its parameters.
[Route("api/Departments/{ID:int}/{CountToFetch:int}")]
This question looks similar to your other question below:
Why is my Web API call returning "No action was found on the controller 'DPlatypus' that matches the request"?
If you are expecting the values to come from a non-query string part of a url, you need to define them in the route template. So, it should be
[Route("api/Departments/{id}/{countToFetch}")]
Following is a good article to read about routing and action selection in Web API:
http://www.asp.net/web-api/overview/web-api-routing-and-actions

Resources