ASP.NET Core 6 MVC how use #model in both shared layout and view - razor

I have an ASP.NET Core 6 project where I want to have a cart in my navbar by taking a dbcontext into a model dynamic and then looping through it to get some values, however I got in to the problem where I use a model called TblOrderItem inside the view and I want to use the model dynamic in my shared layout, but I get the error
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Dynamic.ExpandoObject', but this ViewDataDictionary instance requires a model item of type 'xxx.DataDB.TblOrderItem'.
I want to have this in my layout view:
#model dynamic
And this in my index:
#model xxx.TblOrderItem
Thanks in advance!
Best regards Max

You can put the value you get into a List, and then use ##model IEnumerable<xxxxx.Models.xxx> on the View, like this:
Controller:
public class TestController : Controller
{
public IActionResult Index()
{
Test test = new Test();
test.id = 1;
test.name = "test";
test.address = "address";
List<Test> tests = new List<Test>();
tests.Add(test);
return View(tests);
}
}
Model:
public class Test
{
public int id { get; set; }
public string name { get; set; }
public string address { get; set; }
}
View:
#model IEnumerable<WebApplication220.Models.Test>
#foreach (var item in Model)
{
<div>#item.id</div>
<div>#item.name</div>
<div>#item.address</div>
}
Result:

Related

ASP.net core 3.1: Serializing a list in model and deserializing in JavaScript

I'm trying to get a list of objects from the model and use it in JavaScript. What is the best method of serializing the List in the Model and deserializing it in the JavaScript code so I can loop through the list in JS? I should be able to save the list in a JavaScript variable.
Model List:
public List<Post> postsList { get; set; }
If you can provide the specific code that would be perfect.
In MVC it is done in a straightforward way (using strongly-typed view or just ViewBag).
Let's assume u have 2 models - FooViewModel:
public class FooViewModel
{
public int FooId { get; set; }
public List<BarViewModel> Bars { get; } = new List<BarViewModel>();
}
and BarViewModel:
public class BarViewModel
{
public int BarId { get; set; }
public string BarName { get; set; }
public string BarTitle { get; set; }
public int IdFooViewModel { get; set; }
}
Default HomeController have been changed a little bit:
public IActionResult Index()
{
var vm = new FooViewModel
{
FooId = 1,
Bars =
{
new BarViewModel {BarId = 1, BarName = "First Bar", BarTitle = "I am here!", IdFooViewModel = 1},
new BarViewModel {BarId = 2, BarName = "Second Bar", BarTitle = "Me too!", IdFooViewModel = 1}
}
};
return View(vm);
}
On a razor backend we construct a javascript object:
#{
ViewData["Title"] = "Home Page";
}
#using System.Collections.Specialized
#using System.Text.Json
#model FooViewModel
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Index works!</p>
</div>
#section Scripts {
<script>
var vm = window.viewModel = JSON.parse('#Html.Raw(JsonSerializer.Serialize(Model))');
console.dir(vm);
</script>
}
Please, notice #Html.Raw tag helper is used reasonably - razor does html-encoding, which corrupts quotation marks of json data. That's why we get rid of html-encoding. But this can be security critical - your client should trust your backend.
Then, client side does deserialize long string literal to get data.

Properties with different names null when posting to MVC Controller but not WebApi Controller

I have a model called Purchase with various properties:
public class Purchase
{
[JsonProperty(PropertyName = "amount", NullValueHandling = NullValueHandling.Ignore)]
public int Amount
{
get;
set;
}
[JsonProperty(PropertyName = "currency_code", NullValueHandling = NullValueHandling.Ignore)]
public string CurrencyCode
{
get;
set;
}
}
The JSON is:
{
amount: 3000,
currency_code: "USD"
}
The controller is:
[AllowAnonymous]
public class ProtoController : Controller
{
private readonly IPurchaseManagerFactorySelector purchaseManagerFactorySelector = null;
public ProtoController(IPurchaseManagerFactorySelector purchaseManagerFactorySelector)
{
this.purchaseManagerFactorySelector = purchaseManagerFactorySelector;
}
[Route("opt/proto/index/{identifier}")]
[HttpGet]
public async Task<ActionResult> Index(string identifier)
{
return View();
}
[Route("opt/proto/index/{identifier}")]
[HttpPost]
public async Task<ActionResult> Index(string identifier, Request.Purchase purchase)
{
IPurchaseManager purchaseManager = purchaseManagerFactorySelector.GetFactory(identifier);
return View();
}
}
When the JSON is posted to an ApiController all the properties are populated correctly, however when the same JSON is posted to a Controller only Amount is populated - CurrencyCode is null. I briefly added a new property called Currency_Code and that was populated, it seems like the JsonProperty attribute is being ignore under MVC? I added the DataMember attribute, however that didn't have any effect so I removed it. Json.Net is being used, however I don't understand what the difference is?
I'd remove the Request.Purchase from the arguments and try the [FromBody] attribute for parameter binding.
If all you're changing is the Controller inheritence from Controller to ApiController than I'm not sure but it sounds like your message headers.
If you make the call in Chrome and use the inspect tools you should be able to inspect the headers in each call you make and see what's being populated

Is Identity Core 2 IdentityRole missing defintions for Users?

Am I missing something or has the definition for Users been removed from IdentityRole in Identity Core 2?
I am using asp.net core 2 and I need to calculate the number of users per role. This worked just fine in Core 1 with the following standard code
public class ApplicationRoleController : Controller
{
private readonly RoleManager<ApplicationRole> roleManager;
public ApplicationRoleController(RoleManager<ApplicationRole> roleManager)
{
this.roleManager = roleManager;
}
[HttpGet]
public IActionResult Index()
{
List<ApplicationRoleListViewModel> model = new List<ApplicationRoleListViewModel>();
model = roleManager.Roles.Select(r => new
{
RoleName = r.Name,
Id = r.Id,
Description = r.Description,
NumberOfUsers = r.Users.Count
}).ToList()
.Select(r => new ApplicationRoleListViewModel
{
RoleName = r.RoleName,
Id = r.Id,
Description = r.Description,
NumberOfUsers = r.NumberOfUsers
}).ToList();
return View(model);
}
In My application using Core 2, the line NumberOfUsers = r.Users.Count, where r is derived from the class ApplicationRole with the error that "ApplicationRole does not contain a definition for Users" The ApplicationRole inherits from IdentityRole.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using System;
public class ApplicationRole : IdentityRole
{
public string Description { get; set; }
public DateTime CreatedDate { get; set; }
public string IPAddress { get; set; }
}
You can use this
var admins = _userManager.GetUsersInRoleAsync("Admin").Result;
var number = admins.Count;
The issue with Core 2 apparently is that they forgo the navigation properties in
AspNetUsers AspNetUserRoles AspNetRoles. No idea why. Its very frustrating to be honest. Supposedly you can re-implement them, but so far I had no luck. I am here trying to find a way to list all users with all their roles.
I think the above code is what you need tho.
Also _userManager is imported as such in a controller
private readonly UserManager<ApplicationUser> _userManager;
public MyControllerController(DBContext context, UserManager<ApplicationUser> userManager)
{
this.context = context;
_userManager = userManager; ;
}

MVC4 : Interface object in Model

I'm quite new about MVC. I have the following Model classes:
public class Store
{
public PriceList PriceListInfo { get; set; }
public IStore storeData;
}
public class PriceList
{
public int id { get; set; }
public string codice { get; set; }
}
public interface IStore
{
[...]
}
public class Silo2Store : IStore
{
public int S2 { get; set; }
public int S3 { get; set; }
}
And i want use this model in my view:
#model Store
#Html.TextBoxFor(model => ((Silo2Store)Model.storeData).S3)
The corresponding Controller method is:
public ActionResult Customer()
{
using (Store t = (Store)Session["Store"])
{
if (t.PriceListInfo == null)
{
t.PriceListInfo = new PriceList();
}
t.PriceListInfo.codice = "XXX";
return View(t);
}
}
And I'd like to retrieve the model in my Controller:
[HttpPost]
public ActionResult Customer(Store modelStore)
{
var test = ((Silo2Store)Model.storeData).S3;
}
but Model.storeData attribute isn't initialized in my view, it's null. Then, I can't retrieve the value in my controller.
Should I change my model in anyway?
You have to define your own model binder for IStore.
Taken from this article on MSDN Magazine about MVC Model Binding:
For example, even though the Microsoft .NET Framework provides excellent support for object-oriented principles, the DefaultModelBinder offers no support for binding to abstract base classes and interfaces.

How to bind DbContext from Model to View

I'm new to MVC and have this simple Problem (I think).
I have a DbContext
public class UsersContext : DbContext
{
public UsersContext() : base("Share_DB") {}
public DbSet<ItemDB> Items { get; set; }
}
which contains a list of items with id and Title:
[Table("Items")]
public class ItemDB
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Title { get; set; }
}
and I want to bind a list with all the itemes in the Database table to the model. However I can't figure out how to do that.
In the View (cshtml file) I guess I have define which model I have to use ( #model XXX.Models.ItemModel ) then Display it with something like:
<ul>
#foreach (XXX.Models.ItemModel.ItemDB item in #Items)
{
<li>#item.Title</li>
}
</ul>
However it can't find the #Items property is not found. How do I write this?
The way MVC works is when you return a view in your controller, whatever gets passed to View() ends up as the Model property. In other words:
public ActionResult Index()
{
return View("Hello World");
}
Will pass the string "Hello World" to your View. Then at the top of your Index.cshtml file, you need to declare the model type:
#model string
And usage becomes:
<div>#Model</div>
In your case, you just need to pass your list of Items to the view, and tell it to expect the right type of model:
public ActionResult Index()
{
using (var db = new UsersContext())
{
var items = db.Items.ToList();
return View(items);
}
}
and then in your view:
#model IEnumerable<ItemDB>
and you can use it as:
#foreach (var item in Model)
{
<div>#item.Title</item>
}