how validate data that is not send by Post method? - asp.net-mvc

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

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().

create user in migration Up() using Identity Framework

I have added a migration to create a user but the code hangs when it hits userRepo.Create(...) and within this method at _userManager.Create(...)
using (UserRepository userRepo = new UserRepository())
{
User adminUser = new User() { IsActive = true, UserName =
"admin#testing.com", CompanyId = 1, Password =
"admintesting" };
adminUser.Role = new Models.Security.Role() { Id = 2 };
userRepo.Create(adminUser);
}
Create method is below
public IdentityResult Create(Model.User user)
{
var userEntity = Mapper.Map<Entity.Security.User>(user);
_dbContext.Set<Entity.Security.User>().Add(userEntity);
var result = _userManager.Create(userEntity, userEntity.Password);
DetachAllEntities();
return result;
}
_dbContext is inherited from IdentityDbContext and instantiated accordingly
UserManager<Entity.Security.User, int> _userManager = new UserManager<Entity.Security.User, int>(new UserStore<Entity.Security.User, Entity.Security.Role, int, Entity.Security.UserLogin, Entity.Security.UserRole, Entity.Security.UserClaim>(_dbContext));
The equivalent async method works elsewhere in the application but I would like the non-async for the migration sake. Any help is highly appreciated.

Getting identity from another method in the same class

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);

The neat and simple way for multiple models in a view

What can be simplest way for having rendered in a view information from multiple models. I use ViewModel in some scenarios (in particular when models are not related directly), but now I want to made a kind of dashboard for the current user. So apart from AspNetUsers model I have for example several models (e.g. Orders, OperationJournal, Jobs etc.) that in terms of entity have each a foreign key on UserID.
I made a ViewModel such:
namespace JobShop.Models
{
class QuickProfileVM
{
public IEnumerable<Jobs> Jobs { get; set; }
public IEnumerable<AspNetUsers> AspNetUsers { get; set; }
public IEnumerable<CreditJournal> CreditJournal { get; set; }
public IEnumerable<CandidateReview> CandidateReview { get; set; }
}
}
(since the base models that I need, are done by EF they have all about relations between entities) but it seems to me that is not enough. I am not able to view both the current user profile (so one record) and it's details (more than one record and more than one model).
I have try with Partial View, both with own controller or with actions in Dashboard View controller.
As an example an ActionResult that now I play with:
public ActionResult QuickProfile()
{
var QuickProfile = new QuickProfileVM();
var AspNetUsers = new AspNetUsers();
if (User.Identity.IsAuthenticated)
{
var CurrentUser = User.Identity.GetUserId();//UserManager.FindById(User.Identity.GetUserId());
var TheUser = db.AspNetUsers.Where(u => u.Id == CurrentUser)
.Select(u => new
{
ID = u.Id,
Email = u.Email,
PhoneNumber = u.PhoneNumber,
Companyname = u.Companyname,
Address = u.Address,
ZIP = u.ZIP,
City = u.City,
Country = u.Country,
Website = u.Website,
Facebook = u.Facebook,
Twitter = u.Twitter,
GooglePlus = u.GooglePlus,
Dribble = u.Dribble,
BirthDate = u.BirthDate,
Username = u.UserName,
Surrname = u.Surname,
Name = u.Name,
Role = u.Role,
ThumbURL = u.ThumbURL,
CreditBalance = u.CreditBalance
}).Single();
var TheJournal = db.CreditJournal.Where(tj => tj.UseBy == CurrentUser)
.Select(tj => new
{
IdJournal = tj.IdJournal,
Operation = tj.Operation,
CvID = tj.CvID,
JobID = tj.JobID,
CreditConsumed = tj.CreditConsumed,
UseDate = tj.UseDate,
UseBy = tj.UseBy
}).ToList();
//similar for Jobs and CandidateReview
//
var UserId = TheUser.ID;
var username = TheUser.Username;
var role = TheUser.Role;
var InitialCredit = TheUser.CreditBalance;
AspNetUsers.UserName = TheUser.Username;
AspNetUsers.Companyname = TheUser.Companyname;
AspNetUsers.Surname = TheUser.Surrname;
AspNetUsers.Name = TheUser.Name;
AspNetUsers.ThumbURL = TheUser.ThumbURL;
AspNetUsers.CreditBalance = InitialCredit;
//I put this to ilustrates what I have accesible for example
//about CreditJournal: only methods, not properties
QuickProfile.CreditJournal.AsEnumerable();
var id = CurrentUser;
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
AspNetUsers aspNetUsers = db.AspNetUsers.Find(id);
if (aspNetUsers == null)
{
return HttpNotFound();
}
}
return View(AspNetUsers);
//Disbled since at this stage is not usefull
//return View(QuickProfile);
//return View();
}
I suggest you consider using Html.RenderAction in your view. For example, say your main dashboard is this:
#{
ViewBag.Title = "title";
}
<h2>Multiple Models</h2>
#{ Html.RenderAction("GetData", "Foo"); }
You can use Html.RenderAction to call FooController.GetData()
public class FooController : Controller
{
public ActionResult GetData()
{
var viewModel = new FooViewModel();
viewModel.TimeStamp = DateTime.UtcNow;
return View(viewModel);
}
}
So rather than having one viewmodel with lots of other viewmodels attached as properties, you can split up the rendering of the dashboard view.
Overall this should makes things easier for you - I've used this approach in the past and have found it reduces complexity.

User.Identity.Name in Web Api Controller

I went through the answer to some of the already existing questions and none of the answers are working for me.
In the ProfileController, I invoke the WebApi Controller as follows:
public ViewResult Index()
{
var client = new HttpClient();
var webApiUrl = ConfigurationManager.AppSettings["WebApiURL"];
var response = client.GetAsync(string.Format("{0}{1}", webApiUrl, "//api/ProfileWeb")).Result;
var profile = response.Content.ReadAsAsync<Profile>().Result;
if (profile != null)
{
_profileModel.Id = profile.Id;
_profileModel.FirstName = profile.FirstName;
_profileModel.LastName = profile.LastName;
_profileModel.PhoneNumber = profile.PhoneNumber;
_profileModel.EmailAddress = profile.EmailAddress;
}
return this.View(_profileModel);
}
In the Api Contoller, I get the userName as follows:
public class ProfileWebController : ApiController
{
private IReminderDb _db;
public ProfileWebController(IReminderDb db)
{
_db = db;
}
public object Get()
{
string userName = User.Identity.Name; // <-- Not working..
var profile = _db.GetProfile(userName);
return profile;
}
}
Inside the web api controller, I am not able to get the User.Identity.Name that is in the ProfileContoller. According to some other answers where I have tried Thread.CurrentPrincipal but still the User.Identity.Name is coming out as null in web api controller.
What am I missing?

Resources