I'm trying to get the querystring that is in the browser,
an example /UserHome/UserProfile?username=dangercoder. I'm working in WebApi controller
from the following url i want to get "dangercoder" so I can use the dangercoder username in my AddPost method that is in my Web Api
what i've done so far in the method (the reciever id can be hardcoded but ofcourse i want it to be dangercoder username converted to an id.
[System.Web.Http.HttpPost]
public IHttpActionResult AddPost(Post post)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = User.Identity.Name;
post.SenderID = UserRepository.GetUserId(user);
// QueryString that returns username in the parameter below.
post.RecieverID = UserRepository.GetUserId();
PostRepository.AddNewPost(post);
return CreatedAtRoute("DefaultApi", new { id = post.ID }, post);
}
As far as I see, the view UserProfile contains HTML form with Post fields.
You may create hidden field SenderId in the form with user's ID.
Related
I use ASP.NET MVC 5.
I have an AccountController and a ChangePassword(string guid) action method with a HttpGet attribute.
This action gets a guid and shows change password view, for a specific user.
URL address in browser is for example:
https://localhost:3434/ChangePassword?guid=21725E33A1FD4FCE909770B8926FB294
When user enters a valid value, everything is OK.
But if the user enters an invalid value, I return a view (user) to show the view with entered value.
URL is changed to
https://localhost:3434/ChangePassword
and we lose the guid in the query string.
Is there any way to save the guid in the query string after post?
[HttpGet]
public ActionResult ChangePassword(string guid)
{
return View();
}
[HttpPost]
public ActionResult ChangePassword(clsUser user)
{
if (!ModelState.IsValid)
{
return View(user);
}
else
{
do something ....
}
}
I am trying to retrieve the current logged on user details in a Web API controller to create a user profile page.
I have got the method created but the user keeps returning null in the code was shown below. This works fine in my MVC controller but in Web API controller it throws an error.
[HttpGet]
public IActionResult userProfile()
{
if (ModelState.IsValid)
{
var user = _userManager.Users.First(x => x.Email == User.Identity.Name);
return Ok(new UserViewModel
{
Id = user.Id,
UserName = user.Email,
FirstName = user.FirstName,
LastName = user.LastName
});
}
else
{
return BadRequest(ModelState);
}
}
UPDATE
[HttpGet]
[Authorize(Roles = "Client, Administrator")]
public IActionResult userProfile()
{
string baseUrl = "https://localhost:5001";
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(baseUrl);
var contentType = new MediaTypeWithQualityHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(contentType);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", HttpContext.Session.GetString("token"));
UserViewModel userModel = new UserViewModel();
HttpResponseMessage response = client.GetAsync("https://localhost:5001/api/UserAPI").Result;
string stringData = response.Content.ReadAsStringAsync().Result;
userModel = JsonConvert.DeserializeObject<UserViewModel>(stringData);
return View(userModel);
}
Error Message:
System.InvalidOperationException: 'Sequence contains no elements
An API is stateless meaning that there is no concept of logged in users or sessions. This is because each request is unique, separate and holds all the information required to provide a response.
An API has no way of knowing who is sending a request, there can be 10k people all sending requests at the same time, so who exactly is "logged in"?
So, if you want to load a user profile then send the userID as a parameter, something like:
[HttpGet]
public IActionResult userProfile(string userEmail)
{
if ( !string.IsNullOrEmpty (userEmail) ) ..... etc etc
{
var user = _userManager.Users.First(x => x.Email == userEmail);
return Ok(new UserViewModel
{
Id = user.Id,
UserName = user.Email,
FirstName = user.FirstName,
LastName = user.LastName
});
}
}
As a side note, if you don't have any input parameters or the input is a primitive type such as string or int, then ModelState.IsValid won't do anything. Only use ModelState.IsValid if you have a model class populated with the right rules.
in my case I could actually replace the string with a class
public class UserProfileRetrieveModel
{
[Required]
public string UserEmail { get;set; }
}
then I can do :
[HttpGet]
public IActionResult userProfile(UserProfileRetrieveModel model)
{
if (ModelState.IsValid)
{
var user = _userManager.Users.First(x => x.Email == model.UserEmail);
//etc
}
else
{
return BadRequest(ModelState);
}
}
--- after question updated
so it looks like you have a client application and from that you call the API.
everything I said above still applies, simply populate the data you have before calling the API.
Example:
public IActionResult userProfile()
{
//removed code we don't care about
string userEmail = "";// get your user email here in the MVC controller
//populate it in the api url.
//you might need to URL encode it since it will contain dots and #
string apiUrl = "https://localhost:5001/api/UserAPI/{userEmail}";
HttpResponseMessage response = client.GetAsync(apiUrl).Result;
}
you don't need to work out anything in the API, just pass everything you need to the API, from the MVC controller.
Now, all this aside, you have massive async issues. that part needs work although it's not related to the question.
Im presuming you're on WebAPI 2.
Try the following:
var user = _userManager.GetUser(HttpContext.User);
or
var user = _userManager.FindById(User.Identity.GetUserId());
Instead of .First() change it to .FirstOrDefault()
From the error message It seems you are trying to retrieve an element from an empty sequence. So check whether you have the the data or not.And also try to use .FirstOrDefault().
I have two controllers Base and Login.
Base Controller:
public ActionResult start()
{
string action = Request.QueryString[WSFederationConstants.Parameters.Action];
}
Login Controller:
public ActionResult Login(string user,string password,string returnUrl)
{
if (FormsAuthentication.Authenticate(user, password))
{
if (string.IsNullOrEmpty(returnUrl) && Request.UrlReferrer != null)
returnUrl = Server.UrlEncode(Request.UrlReferrer.PathAndQuery);
return RedirectToAction("Start","Base", returnUrl });
}
return View();
}
After authentication is done it gets redirected to Start action in Base Controller as expected.
But the querystring doesnot fetch the value. When hovered over the querystring it shows length value but not the uri.
How to use the url sent from Login controller in Base Controller and fetch parameters from it?
You are actually returning a 302 to the client.
From the docs.
Returns an HTTP 302 response to the browser, which causes the browser
to make a GET request to the specified action.
When doing that the client will make another request with the url that you created. In your case something like youruri.org/Base/Start. Take a look at the network tab in your browser (F12 in Chrome).
What I think you want to do is:
return RedirectToAction
("Start", "Base", new { WSFederationConstants.Parameters.Action = returnUrl });
Assuming that WSFederationConstants.Parameters.Action is a constant. If WSFederationConstants.Parameters.Action returns the string fooUrl your action will return the following to the browser:
Location:/Base/Start?fooUrl=url
Status Code:302 Found
Another option is to actually pass the value to the controller:
public class BaseController: Controller
{
public ActionResult start(string myAction)
{
string localAction = myAction; //myAction is automatically populated.
}
}
And in your redirect:
return RedirectToAction
("Start", "Base", new { myAction = returnUrl });
Then the BaseController will automatically fetch the parameter, and you don't need to fetch it from the querystring.
Within my Home controller is the Index() action. Within Index() I return the a user object from the database using the currently authenticated user's ID:
return View(db.Users.Find(User.UserId));
That works properly and the URL is simply:
https://localhost:44301/
However elsewhere in the Home controller in a separate action I modify the current user and pass it back into the index view using:
return RedirectToAction("Index", user);
When I do this the URL becomes cluttered with a serialized version of the User model:
https://localhost:44301/Home/Index/4?Name=katrina&Administrator=True&PasswordEncodedHash=1000%3AqzWR8U6poGKshxHDsP%2B5yFhz5AZ01%2Fv1%3ASqCG0SliIpjX0M0jjkQqAf5aunTVS2gx&Tests=System.Collections.Generic.List%601%5BLearningManagementSystem.Models.Test%5D&UserTestAttempts=System.Collections.Generic.List%601%5BLearningManagementSystem.Models.UserTestAttempt%5D&Phones=System.Collections.Generic.List%601%5BLearningManagementSystem.Models.Phone%5D
I imagine I doing something dumb with the way I am redirecting the action however I cannot figure out how to fix this. I have tried adding a custom route but the "?Name=...." still gets appended to that.
(Edit) Code from that other action:
public ActionResult ToggleAdministrator()
{
if (Request.IsAuthenticated)
{
var user = db.Users.Find(User.UserId);
user.Administrator = !user.Administrator;
db.SaveChanges();
Response.Cookies.Add(cookie);
return RedirectToAction("Index", user);
}
return RedirectToAction("Index", (User)null);
}
I think you don't need to pass whole data while redirecting to some action using RedirectToAction.
Suppose you have an action Index in Home controller.
Public ActionResult Index(int id)
{
-- write the code here to fetch data based on that id
-- like
var user = db.Users.FirstOrDefault(x=>x.Id = id);
return View(user);
}
Now for this you just need to use redirect to action like below:
return RedirectToAction("Index", new { Id= 5 });
Note:
Never pass a complex type object in QueryString or in GET requests
I need authorization attribute to ensure that authenticated user can access in secure area to manage his and only his data.
I was thinking to retrieve httpContext.User.Identity.Name and to match that to retrieved username from the database.
Is this basically good (secure) approach? or it can be done with better secure on the mind?
So, my controller is decorated with custom attribute
[UserAccountAuthorizeAttribute]
public ActionResult Edit(string username)
{
return View();
}
and I'm overriding AuthorizeAttribute but in the debug mode got null value on following line
var rd = httpContext.Request.RequestContext.RouteData;
var username = rd.Values["username"]; // null
what can be aproblem ?
You shouldn't be putting the username in the querystring.
If you're using the built in ASP.NET Membership provider your action would look something like this.
[Authorize]
public ActionResult Edit()
{
var userId = (Guid)Membership.GetUser().ProviderUserKey;
var someService = new MyService();
var someData = someService.GetSomeDataByUserId(userId);
//...
}