Frage

Goal: To create a re-usable drop down menu that lists my website's administrators, managers and agents. These types of users are defined by the .NET Simplemembership webpages_Roles and webpages_UsersInRoles tables.

So Far: I have a UserProfile table in my database which has 25 columns. I have a corresponding domain model of the same name which is accessed from my UsersContext() EF.

The drop down menu only needs to list the User's FirstName, LastName and UserId so instead of working with the complete domain model, I created the following ViewModel:

namespace MyModels.Models.ViewModels
{
    public class AdminsAndAgentsListVM
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int UserId { get; set; }
    }
}

I then added the following to my Account controller (notice I'm not working with partial view yet):

public ActionResult AdminsAndAgentsList()
{
   UsersContext _db = new UsersContext(); //provides me access to UserProfiles data
   var admins = Roles.GetUsersInRole("Admin"); //gets users with this role

   var viewModel = _db.UserProfiles
       .Where(x => admins.Contains(x.UserName)); //Selects users who match UserName list
    return View(viewModel);
}

I then scaffold a list view and base it on the strongly typed ViewModel:

    @model IEnumerable<MyModels.Models.ViewModels.AdminsAndAgentsListVM>

@{
    ViewBag.Title = "AdminsAndAgentsList";
}

<h2>AdminsAndAgentsList</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.FirstName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.LastName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.UserId)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.FirstName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.LastName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.UserId)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
            @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
            @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
        </td>
    </tr>
}

</table>

I do a successful build and when I run the web page I get the following error:

The model item passed into the dictionary is of type'System.Data.Entity.Infrastructure.DbQuery1[My.Models.UserProfile]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[My.Models.ViewModels.AdminsAndAgentsListVM]'.

If I recreate the view but strongly type it agains the UserProfile, it works fine. So how to re work this so I can strongly type against my ViewModel instead? Please provide examples if possible. I am new to C# and MVC and really benefit from the seeing the code first hand. Much appreciate the help!

EDIT ----------------------------- Here is the object for the UserProfile:

public class UsersContext : DbContext
{
    public UsersContext()
        : base("DefaultConnection")

    {
    }

    public DbSet<UserProfile> UserProfiles { get; set; }
}

[Table("UserProfile")]
public class UserProfile
{

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string UserName { get; set; }

    [Required]
    [ReadOnly(true)]
    [DisplayName("SubscriberID")]
    public int? SubscriberId { get; set; } //Foreign key

    [StringLength(50, ErrorMessage = "The {0} must be at least {2} characters long.")]
    [Display(Name = "First Name")]
    public string FirstName { get; set; }

    [StringLength(50, ErrorMessage = "The {0} must be at least {2} characters long.")]
    [Display(Name = "Last Name")]
    public string LastName { get; set; }

    //public DateTime DOB { get; set; }
    [DataType(DataType.Date)]
    public DateTime? DOB { get; set; } //This allows null

    public bool? Gender { get; set; }

    [Required]
    [MaxLength(250)]
    [EmailAddress]
    public string Email { get; set; }

    [MaxLength(250)]
    [EmailAddress]
    [NotEqualTo("Email", ErrorMessage = "Alt Email and Email cannot be the same.")]
    public string AltEmail { get; set; }

    [MaxLength(250)]
    [EmailAddress]
    public string FormEmail { get; set; }

    public Address Address { get; set; }

    [MaxLength(20)]
    public string Telephone { get; set; }

    [MaxLength(20)]
    public string Mobile { get; set; }

    [Required]
    [DataType(DataType.Date)]
    public DateTime DateAdded { get; set; }

    [DataType(DataType.DateTime)]
    public DateTime? LastLoginDate { get; set; }

    public bool? OffersOptIn { get; set; } //any offers we may have with us or partners

    public bool? NewsOptIn { get; set; } //newsletter

    public bool? SubscriptionOptIn { get; set; } //account, technical, renewal notices, pp invoices, pp receipts

    public bool? OrderOptIn { get; set; } //orders - workflow notices

    [DataType(DataType.DateTime)]
    public DateTime? LastUpdatedAccountDate { get; set; } //Last time user updated contact info
}
War es hilfreich?

Lösung

Try this. It will cast your query into your view model.

var viewModel = _db.UserProfiles
       .Where(x => admins.Contains(x.UserName))
       .Select(x => new AdminsAndAgentsListVM { 
                        FirstName = x.FirstName,
                        LastName = x.LastName,
                        UserId = x.UserId});

Andere Tipps

You're passing the view your query, not your model.

Execute the query as you have it

var query = _db.UserProfiles
           .Where(x => admins.Contains(x.UserName));

Then instantiate and populate your view model

var viewModels = new List<AdminsAndAgentsListVM>();
foreach (var item in query)
{
var viewModel = new AdminsAndAgentsListVM();
     viewodel.FirstName = item.FirstName;
     viewodel.LastName = item.LastName;
     viewodel.UserId = item.UserId;
viewModels.Add(viewModel);
}



  return View(viewModels);

This assumes, of course, that a UserProfile and AdminsAndAgentsListVM have matching properties.

Change your return line to:

return View(viewModel.AsEnumerable());

You aren't selecting your ViewModel. You need to do a Select(x => new AdminsAndAgentsListVM on your query. I would also do ToList() on there.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top