question

kobosh-5924 avatar image
0 Votes"
kobosh-5924 asked cooldadtx answered

Model Derived from Identity Error

I created .net core (5) app with authentication. Now I wanted to manage created database. I added model derived from Identity.IdentityUser to use it in scaffolding view. I added migration and updated database. When I run app I get:

InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List`1[Microsoft.AspNetCore.Identity.IdentityUser]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.List`1[ContactManager.Models.UserModel]'.

Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary.EnsureCompatible(object value)
My controller:

public class UsersController : Controller
{
private ApplicationDbContext db;
public UsersController(ApplicationDbContext _db)
{
db = _db;
}
// GET: UsersController
public async Task< ActionResult> Index()
{
var result = await db.Users.ToListAsync();
return View(result );
}
.................
................
}

My Model:

public class UserModel:Microsoft.AspNetCore.Identity.IdentityUser
{

}
My view

@model List<ContactManager.Models.UserModel>

@{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>Index</h1>

<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
User Name
</th>
<th>
Email
</th>

<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>


<td>
<a asp-action="Edit" asp-route-id="@ item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@ item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@ item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>



dotnet-entity-framework-core
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

cooldadtx avatar image
0 Votes"
cooldadtx answered

The issue is a type mismatch between what your controller action is passing to the view and what the view is expecting.

var result = await db.Users.ToListAsync();
return View(result );


result is of type List<IdentityUser> because that is what ToListAsync will return. However in your view you are using this

@model List<ContactManager.Models.UserModel>


That means the view is expecting UserModel. Since you are passing a different type to the view it is raising the exception. To work around this the correct solution is to convert the IdentityUser instances to UserModel before passing that to the view. Unfortunately your existing model is not going to work. You are deriving from IdentityUser but you won't be able to create instances of that type nor can you magically associate them with a new UserModel instance. Instead you should accept (generally in the constructor or by using object initializer syntax) the IdentityUser you want to have the model represent. Convert each of the users before passing that on to the view.

public class UserModel
{
   //In general you should have a default constructor for models otherwise you run into binding issues
   public UserModel() { }

   //Converts a user to a model
   public UserModel ( IdentityUser user ) {
       //Set whatever properties you need
       UserName= user.UserName;
       Email  = user.Email;
   }

   //Expose whatever properties your view will need, just making some up here
   public string UserName { get; set; }
   public string Email { get; set; }
}

//Do the conversion from user to model
var result = await db.Users.ToListAsync();
var models = result.Select(x => new UserModel(x));
return View(models);
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.