Image not loading as intended ASP.NET MVC - asp.net

I have a view model in which I have declared a few variables in a class for example picture, name, description and so forth. The picture variable contains the url for the various images which are stored locally in the project file. I then display those variables in my view but for some reason the image would not load...After inspecting the element using chrome dev tools the image url is correct but the actual image isn't loading correctly and it throws a 404 error in the browser for the images, could someone please explain to me why this would be happening and maybe just point me in the right direction.
ViewModel code:
public class MyViewModel : Product
{
private string _Picture;
private string _Name;
private string _Description;
public MyViewModel(string picture, string name, string description, int price, int quantity) : base(price, quantity)
{
_Picture = picture;
_Name = name;
_Description = description;
}
public string Picture
{
get { return _Picture; }
set { _Picture = value; }
}
public string Name
{
get { return _Name; }
set { _Name = value; }
}
public string Description
{
get { return _Description; }
set { _Description = value; }
}
}
Controller code:
public class MyController : Controller
{
public ActionResult Index()
{
List<MyViewModel> data = GetData();
return View(data);
}
private List<MyViewModel> GetData()
{
List<MyViewModel> data = new List<MyViewModel>();
MyViewModel data1 = new MyViewModel("~/Images/image.png", "Name", "Description", 200, 0);
data.Add(data1);
return data;
}
}
View code:
#model List<MyProject.ViewModels.MyViewModel>
#{
ViewBag.Title = "Data";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container">
<div class="row">
#foreach (var data in Model)
{
<div class="col-md">
<div class="card text-white bg-dark" style="width: 18rem;">
<img class="card-img-top" src="#data.Picture" alt="#data.Name">
<div class="card-body">
<h5 class="card-title">#data.Name</h5>
<p class="card-text">#data.Description</p>
<p class="card-text">Price: #data.Price</p>
<label for="customRange3">Select Quantity:</label>
<form>
<input type="range" class="custom-range quantitySlider" name="amountRange1" min="0" max="5" value="#data.Quantity" step="1" id="quantity" oninput="this.form.amountInput1.value=this.value" />
<input type="button" class="btn btn-outline-success" value="Add to Cart" /><input type="text" class="form-control bg-light quantityInput" name="amountInput1" value="0" readonly />
</form>
</div>
</div>
</div>
}
</div>
</div>
The ouput:
Inspecting the element in chrome dev tools:

Try this in your view:
<img class="card-img-top" src="#Url.Content(data.Picture)" alt="#data.Name">

Another option is to change
MyViewModel data1 = new MyViewModel("~/Images/image.png", "Name", "Description", 200, 0);
to:
MyViewModel data1 = new MyViewModel(#"/Images/image.png", "Name", "Description", 200, 0);

Related

How to fix Invalid OperationException: Multiple constructors accepting all given argument types have been found in type 'System.Collections.Generic

I have seen variations to this question asked. But none of the answers seem to help me.
When trying to view a list of roles in my view after hitting the AddOrRemoveUsers button(see picture)
I get the following error message.
I cant find where the multiple constructors error seem to be. Am I missing something.
#page
#using ThreeTierAdvisementApp.Areas.Identity.Pages.Account.Administration
#using ThreeTierAdvisementApp.Data
#model List<UserRole>
<form method="post">
<div class="card">
<div class="card-header">
<h2>Add or remove users from this role</h2>
</div>
<div class="card-body">
#for(int i = 0; i<Model.Count; i++){
<div class="form-check m-1">
<input asp-for="#Model[i].IsSelected" class="form-check-input" />
<label class="form-check-label">
#Model[i].UserName
</label>
</div>
}
</div>
<div class="card-footer">
<input type="submit" value="Update" class="btn btn-primary"
style="width:auto" />
<a asp-action="EditRole" asp-route-id="UserId"
class="btn btn-primary" style="width:auto">Cancel</a>
</div>
</div>
</form>
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ThreeTierAdvisementApp.Data;
namespace ThreeTierAdvisementApp.Areas.Identity.Pages.Account.Administration
{
public class EditUsersInRoleModel : PageModel
{
private readonly RoleManager<IdentityRole> _roleManager;
private readonly UserManager<DefaultUser> _userManager;
public EditUsersInRoleModel(RoleManager<IdentityRole> roleManager, UserManager<DefaultUser> userManager)
{
_roleManager = roleManager;
_userManager = userManager;
}
[BindProperty]
public UserRole RoleView { get; set; }
public async Task<IActionResult> OnGet(string roleId)
{
RoleView = new UserRole { UserId = roleId };
var role = await _roleManager.FindByIdAsync(roleId);
if (role == null)
{
return NotFound();
}
var model = new List<UserRole>();
foreach (var user in _userManager.Users)
{
var userRoleViewModel = new UserRole
{
UserId = user.Id,
UserName = user.UserName,
};
if (await _userManager.IsInRoleAsync(user, role.Name))
{
userRoleViewModel.IsSelected = true;
}
else
{
userRoleViewModel.IsSelected = false;
}
model.Add(userRoleViewModel);
}
return Page();
}
}
}
using Microsoft.AspNetCore.Identity;
using System.Security.Principal;
namespace ThreeTierAdvisementApp.Data
{
public class UserRole
{
public string UserId { get; set; }
public string UserName { get; set; }
public bool IsSelected { get; set; }
}
}
I am using asp.net 6 Razor page pattern but all the examples online are using the MVC pattern. Would appreciate some feedback on how to handle this.

I am getting null value in the server side from CheckBox in asp.net MVC

When I check the box, it shows it has a false value in the server side model but in the ajax call getting values it shows null values.
In the model class:
[Display(Name = "Is Buyer")]
public bool IsBuyer { get; set; }
In the Razor Page:
<div class="row g-my-4">
<div class="col-md-10 g-pl-0">
<div class="row">
<div class="col-md-1"> </div>
<div class="col-md-7 g-pl-0 g-pr-0" id="IsBuyer">
<label>
#Html.CheckBoxFor(m=>m.IsBuyer)
#*#Html.CheckBoxFor(model => model.IsBuyer, new { id = "CheckBuyer" })*#
#*#Html.CheckBox("IsBuyer")*#
Buyer
</label>
</div>
</div>
</div>
</div>
I tried to use everything but nothing is working.
Getting data values to use ajax call
Here you can see the IsBuyer attribute is null = empty, and here on the server side it's getting false value however I have checked every check box but that's what I am getting back
Try to use usual BeginForm() block and post data like below:
#model Models.ViewModel
#using (Html.BeginForm())
{
<div class="form-group row">
<p>#Html.LabelFor(l => Model.IsBuyer) </p>
#Html.CheckBoxFor(r => Model.IsBuyer)
</div>
<input id="Button" type="submit" value="Save" />
}
In the controller code:
public IActionResult IndexTest()
{
var model = new ViewModel() { IsBuyer = true };
return View(model);
}
[HttpPost]
public IActionResult IndexTest(ViewModel data)
{
if (ModelState.IsValid)
{
// your code here...
}
return RedirectToAction("IndexTest", data);
}
// View data model class
public class ViewModel
{
[Display(Name = "Is Buyer")]
public bool IsBuyer { get; set; }
// Additional propereties is defined here...
}

Passing List<T> Model to a Controller in ASP.NET Core

I have a form in my web application for evaluation and it has several questions and each question, several answers which should be chosen by user (radio buttons).
My model looks like:
public class EvaluationQuestionModel
{
public int Id { get; set; }
public string Title { get; set; }
public List<EvaluationAnswerModel> Answers { get; set; }
public int SelectedAnswer { get; set; }
}
(and my Answers model:
public class EvaluationAnswerModel
{
public string Title { get; set; }
public int Grade { get; set; }
}
)
And my view looks like:
#model List<EvaluationQuestionModel>
<form asp-controller="EvaluationQuestions" asp-action="SubmitSurvey">
#for (int i = 0; i < Model.Count(); i++)
{
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-12">
<label>#Model[i].Title</label>
</div>
<div class="col-lg-12 col-md-12 col-sm-12 col-12">
#for (int j = 0; j < Model[i].Answers.Count; j++)
{
<div class="form-check form-check-inline">
<input class="form-check-input" asp-for="#Model[i].SelectedAnswer" name="#Model[i].Id" type="radio" value="#Model[i].Answers[j].Grade">
<label asp-for="#Model[i].Answers[j].Title" class="form-check-label">#Model[i].Answers[j].Title</label>
</div>
}
</div>
</div>
<hr />
}
<div class="row no-block d-flex justify-content-center">
<input type="submit" value="Submit">
</div>
</form>
I can't seem to find a way to pass the model to my controller. I want to have the answer for each question, I wonder if anyone can help me out.
//UPDATE
I actually solved it with two modifications:
binding the input like this: [#i].SelectedAnswer instead of #Model[i].SelectedAnswer
using the 'name' property instead of 'asp-for'
If you want pass your formdata to backend, your data format in your request should be like below:
[{Id:1,SelectedAnswer:1},{Id:2,SelectedAnswer:2},{Id:3,SelectedAnswer:3}]
Then you can get list model by FromForm, like
public async Task<IActionResult> SubmitSurvey([FromForm] List<EvaluationQuestionModel> data){}
Tips
You need make sure your properties in http request as same as model in backend, it will works fine.
I create a sample code you provided and test it, I saw the data.
My Solution
I can foreach IFormCollection, then convert them to list.
[HttpPost]
public async Task<IActionResult> SubmitSurvey(IFormCollection formCollection)
{
List<EvaluationQuestionModel> data = new List<EvaluationQuestionModel>();
foreach (var item in formCollection)
{
if (item.Key != "__RequestVerificationToken")
{
EvaluationQuestionModel e = new EvaluationQuestionModel();
e.Id = int.Parse(item.Key);
e.SelectedAnswer = int.Parse(item.Value);
data.Add(e);
}
}
return Ok(data);
}
Then you can get the data in backend.

Dynamic Property and Child Model Not Binding

I want to build dynamic form using Blazor.
Here is my sample component.
#page "/customform"
#using System.Dynamic
#using System.Text.Json
#inject IJSRuntime JSRuntime;
<div class="card m-3">
<h4 class="card-header">Blazor WebAssembly Form Validation Example</h4>
<div class="card-body">
<EditForm EditContext="#editContext"
OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator></DataAnnotationsValidator>
#foreach (var field in Model.Fields)
{
<div class="form-group">
<label>#field.Name</label>
<input #bind-value="field.Value" class="form-control" />
<ValidationMessage For="(()=> field.Value)" />
<ValidationMessage For="(()=> field.Name)" />
<ValidationMessage For="(()=> field)" />
</div>
}
<div class="form-group">
<label>Address</label>
<input #bind-value="Model.Address" class="form-control" />
<ValidationMessage For="()=> Model.Address" />
</div>
<div class="form-group">
<label>Child</label>
<input #bind-value="Model.ChildModel.ChildName" class="form-control" />
<ValidationMessage For="()=> Model.ChildModel.ChildName" />
</div>
<div class="text-left">
<button class="btn btn-primary" type="submit">Submit</button>
</div>
</EditForm>
</div>
</div>
#code{
private SampleModel Model = new SampleModel();
private EditContext editContext;
private ValidationMessageStore _messageStore;
protected override void OnInitialized()
{
editContext = new EditContext(Model);
editContext.OnValidationRequested += ValidationRequested;
_messageStore = new ValidationMessageStore(editContext);
}
private void HandleValidSubmit(EditContext context)
{
var modelJson = JsonSerializer.Serialize(context.Model, new JsonSerializerOptions { WriteIndented = true });
JSRuntime.InvokeVoidAsync("alert", $"SUCCESS!! :-)\n\n{modelJson}");
}
async void ValidationRequested(object sender, ValidationRequestedEventArgs args)
{
_messageStore.Add(editContext.Field("FirstName"), "Test");
_messageStore.Add(editContext.Field("Address"), "Invalid Address");
_messageStore.Add(editContext.Field("ChildModel.ChildName"), "Invalid Child Name");
editContext.NotifyValidationStateChanged();
}
public class SampleModel
{
public string Address { get; set; }
public ChildModel ChildModel { get; set; }
public List<Field> Fields { get; set; }
public SampleModel()
{
this.ChildModel = new ChildModel();
this.Fields = new List<Field>();
this.Fields.Add(new Field()
{
Name = "FirstName",
Value = "",
ControlType = ControlType.Input
});
this.Fields.Add(new Field()
{
Name = "LastName",
Value = "",
ControlType = ControlType.Input
});
}
}
public class ChildModel
{
public string ChildName { get; set; }
}
public enum ControlType
{
Input
}
public class Field
{
public string Value { get; set; }
public string Name { get; set; }
public string DisplayName { get; set; }
public ControlType ControlType { get; set; }
}
}
Currently I am facing too many issues.
If I use For lookup instead of For each it is not working
ChildModel seems to be bind but its validation is not working
Dynamically generated based on Fields collection control does not display validation.
Only address in SimpleModel display validation.
Is there any suggestion or help around this ?
Your profile suggests you know what you're doing, so I'll keep this succinct.
Your for loop needs to look something like this. Set a local "index" variable within the loop to link the controls to. If you don't they point to the last value of i - in this case 2 which is out of range! The razor code is converted to a cs file by the razor builder. You can see the c# file generated in the obj folder structure - obj\Debug\net5.0\Razor\Pages. Note, the linkage of the Validation Message
#for(var i = 0; i < Model.Fields.Count; i++)
{
var index = i;
<div class="form-group">
<label>#Model.Fields[index].Name</label>
<input #bind-value="Model.Fields[index].Value" class="form-control" />
<ValidationMessage For="(()=> Model.Fields[index].Value)" />
</div>
}
Now the message validation store. Here's my rewritten ValidationRequested. Note I'm creating a FieldIdentifier which is the correct way to do it. "Address" works because it's a property of EditContext.Model. If a ValidationMessage doesn't display the message you anticipate, then it's either not being generated, or it's FieldIdentifier doesn't match the field the ValidationMessage is For. This should get you going in whatever project you're involved in - if not add a comment for clarification :-).
void ValidationRequested(object sender, ValidationRequestedEventArgs args)
{
_messageStore.Clear();
_messageStore.Add(new FieldIdentifier(Model.Fields[0], "Value"), "FirstName Validation Message");
_messageStore.Add(new FieldIdentifier(Model.Fields[1], "Value"), "Surname Validation Message");
_messageStore.Add(editContext.Field("FirstName"), "Test");
_messageStore.Add(editContext.Field("Address"), "Invalid Address");
_messageStore.Add(editContext.Field("ChildModel.ChildName"), "Invalid Child Name");
editContext.NotifyValidationStateChanged();
}
If you interested in Validation and want something more that the basic out-of-the-box validation, there's a couple of my articles that might give you info Validation Form State Control or there's a version of Fluent Validation by Chris Sainty out there if you search.

Add Roles to User using checkboxes

I am developing a Razor application and I need the Admin to assign or update roles of the Users. I am using a checkbox to carry out this action. So far, I have been able to populate the view to show the users and their respective roles ticked in the checkbox, but I haven't been able to update their roles, as anytime a checkbox is ticked to add a role, it doesn't add the role to the user. I think this line is the culprit: var selectedRoles = model.Where(x => x.Selected).Select(y => y.RoleName);.
This is the Model:
public class ManageUserRolesViewModel
{
public string RoleId { get; set; }
public string RoleName { get; set; }
public bool Selected { get; set; }
}
This is the Page:
<form method="post">
<div class="card">
<div class="card-header">
<h2>Manage User Roles</h2>
Add / Remove Roles for #Model.UserID
</div>
<div class="card-body">
#foreach (var x in Model.UserRoles)
{
<div class="form-check m-1">
<input type="hidden" asp-for="#x.RoleId" />
<input type="hidden" asp-for="#x.RoleName" />
<input asp-for="#x.Selected" class="form-check-input" />
<label class="form-check-label" asp-for="#x.Selected">
#x.RoleName
</label>
</div>
}
<div asp-validation-summary="All" class="text-danger"></div>
</div>
<div class="card-footer">
<input type="submit" value="Update" class="btn btn-primary" style="width:auto" />
<a asp-page="/Account/UserManagement/UserList" class="btn btn-primary" style="width:auto">Cancel</a>
</div>
</div>
</form>
This is the Page Model:
public class ManageModel : PageModel
{
private readonly RoleManager<IdentityRole> _roleManager;
private readonly BankAssesmentApplicationIdentityDbContext _db;
private readonly UserManager<IdentityUser> _userManager;
public ManageModel(
RoleManager<IdentityRole> roleManager,
UserManager<IdentityUser> userManager,
BankAssesmentApplicationIdentityDbContext db)
{
_db = db;
_userManager = userManager;
_roleManager = roleManager;
}
public IList<ManageUserRolesViewModel> UserRoles = new List<ManageUserRolesViewModel>();
public string UserID { get; set; }
public async Task<IActionResult> OnPostAsync(List<ManageUserRolesViewModel> model, string userId)
{
UserID = userId;
if (ModelState.IsValid)
{
IdentityUser user = await _userManager.FindByNameAsync(userId);
if (user == null)
{
return Page();
}
var roles = await _userManager.GetRolesAsync(user);
var result = await _userManager.RemoveFromRolesAsync(user, roles);
if (!result.Succeeded)
{
ModelState.AddModelError("", "Cannot remove user existing roles");
return Page();
}
var selectedRoles = model.Where(x => x.Selected).Select(y => y.RoleName);
await _userManager.AddToRolesAsync(user, selectedRoles);
if (!result.Succeeded)
{
ModelState.AddModelError("", "Cannot add selected roles to user");
return Page();
}
return RedirectToPage("/Account/UserManagement/UserList");
}
return Page();
}
public async Task<IActionResult> OnGetAsync(string userId)
{
UserID = userId;
var user = await _userManager.FindByEmailAsync(userId);
if (user == null)
{
return Page();
}
var model = new List<ManageUserRolesViewModel>();
foreach (var role in _roleManager.Roles.ToList())
{
ManageUserRolesViewModel roles = new ManageUserRolesViewModel
{
RoleId = role.Id,
RoleName = role.Name,
};
UserRoles.Add(roles);
if (await _userManager.IsInRoleAsync(user, role.Name))
{
roles.Selected = true;
}
else
{
roles.Selected = false;
}
model.Add(roles);
}
return Page();
}
}
Firsly,you need know that for each property of the complex type, model binding looks through the sources for the name pattern prefix.property_name. If nothing is found, it looks for just property_name without the prefix.Your backend wants to receive a list model,so what you pass should be [index].PropertyName.But what you did will result in serveral inputs with the same name,the model binding system could not match the value for the list.
Then you need know that asp-for="#x.Selected" will generate the value for checkbox,but it will not change the value when you change the checkbox state,you need create a click event to change the value:
<input asp-for="#x.Selected" onclick="$(this).val(this.checked ? true : false)"/>
What you need change like below:
<form method="post">
<div class="card">
<div class="card-header">
<h2>Manage User Roles</h2>
Add / Remove Roles for #Model.UserID
</div>
<div class="card-body">
#*Begin change*#
#{ int i = 0;}
#foreach (var x in Model.UserRoles)
{
<div class="form-check m-1">
<input type="hidden" asp-for="#x.RoleId" name="[#i].RoleId"/>
<input type="hidden" asp-for="#x.RoleName" name="[#i].RoleName"/>
<input asp-for="#x.Selected" name="[#i].Selected" class="form-check-input" onclick="$(this).val(this.checked ? true : false)"/>
<label class="form-check-label" asp-for="#x.Selected">
#x.RoleName
</label>
</div>
i++;
}
#*End change*#
<div asp-validation-summary="All" class="text-danger"></div>
</div>
<div class="card-footer">
<input type="submit" value="Update" class="btn btn-primary" style="width:auto" />
<a asp-page="/Account/UserManagement/UserList" class="btn btn-primary" style="width:auto">Cancel</a>
</div>
</div>
</form>
Result:
#user:3843256 have a look at this sample it works ok, the only difference is you are using for each, that means bind does not take place, change to counter based index binding
Checkbox list binding

Resources